Prompts 与 LCEL:提示词工程 + 结构化输出

    |     2026年8月18日   |   AI大模型应用, LangChain框架   |     0 条评论   |    5

上篇你把 Messages 协议吃透了——System / Human / AI / Tool,图文也能塞进 Human。但每轮手写消息列表又臭又长。这篇讲 Prompt 模板LCEL 管道,以及怎样用数据类型拿到结构化输出


小明烦透了「复制粘贴人设」

小明写了三个小功能:解释概念、改写用户问题、生成概念卡片。每个文件都这样开头:

SystemMessage(content="你是简洁的助教。用中文回答,控制在 80 字以内。")
HumanMessage(content="请解释概念:LCEL")

改人设要改三处;用户输入带空格还得自己 .strip();要前端表格字段时,他又让模型「输出 JSON」,然后 json.loads——模型偶尔多一句废话,解析直接炸。

他去找老张:”Messages 我会拼了,有没有模板 + 管道?结构化能不能别手写解析?”

老张说:”有。提示词工程 + LCEL:人设进模板,变量进占位符,| 串成链;要字段就先定义数据类型,再 with_structured_output。”


什么是 Prompts、LCEL、结构化输出

老张在白板上分三块:

1) System Prompt
   创建 Agent 时可 system_prompt= 一次设定
   不必每轮在 Messages 里重复贴

2) 提示词工程(Prompt Engineering)
   优化 System / 指令,让输出更理想
   - 设定角色与详细指令
   - Few-shot:给几个输入→输出样例
   - 结构化输出:别只靠「请输出 JSON」

3) LCEL
   ChatPromptTemplate | model | parser
   链上同样有 invoke / stream

比喻:

  • 手写 Messages = 每次点菜都把店规念一遍
  • ChatPromptTemplate = 把店规印在菜单模板上,只填 {topic}
  • LCEL | = 传菜流水线:填单 → 厨师 → 装盘
  • 结构化输出 = 不要散文诗,直接按表格字段出菜

在 LangChain 里做结构化,往往不必自己在提示词里描述 JSON 形状,而是设定好一个数据类型

方式 你写什么 得到什么
手写 Messages 每轮 System+Human AIMessage 文本
Prompt 模板 ("system",...) + {var} 填变量后变 Messages
LCEL 链 prompt | model | parser 常为 str 或继续往后接
with_structured_output Pydantic / schema 对象字段,可直接读

小明:”和 Agent 的 system_prompt 啥关系?”

“同一件事的两种挂法:链用模板里的 system 句;Agent 用 create_agent(..., system_prompt=...)。都是人设,只是入口不同。”


代码拆解:模板 → 管道 → 结构化

1. ChatPromptTemplate + LCEL

from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from llm import get_chat_model


def build_explain_chain():
  """模板 → 模型 → 字符串。"""
  model = get_chat_model(temperature=0.4)

  prompt = ChatPromptTemplate.from_messages(
    [
      ("system", "你是简洁的助教。用中文回答,控制在 80 字以内。"),
      ("human", "请解释概念:{topic}"),
    ]
  )

  return prompt | model | StrOutputParser()

三步:

  1. 模板 —— ("system", ...) / ("human", "{topic}"),元组写法对应上篇的消息角色
  2. 管道 —— prompt | model | StrOutputParser():填变量 → 调模型 → 只要 .content 字符串
  3. 调用 —— 传入字典,不是裸字符串:”
chain = build_explain_chain()
print(chain.invoke({"topic": "LCEL 管道 |"}))

流式同样挂在链上:

for chunk in chain.stream({"topic": "PromptTemplate"}):
  print(chunk, end="", flush=True)

“学习目标对上了:解释编排层定位;写出带变量的 ChatPromptTemplate;跑通链上 invoke 与 stream。”

2. Runnable 预处理再进 Prompt

def build_rewrite_chain():
  model = get_chat_model(temperature=0.2)
  prompt = ChatPromptTemplate.from_messages(
    [
      ("system", "把用户输入改写成更清晰的中文问题,不要回答问题。不超过 40 字。"),
      ("human", "{raw}"),
    ]
  )

  return (
    RunnablePassthrough.assign(raw=RunnableLambda(lambda x: x["raw"].strip()))
    | prompt
    | model
    | StrOutputParser()
  )

“System 写死行为:只改写、不回答、限长——这就是提示词工程里的「详细指令」。
assign + strip 把脏输入洗干净,再进模板。Messages、Runnable、Prompt 在一条链里碰头。”

3. 结构化输出:先定义类型

schemas.py

from pydantic import BaseModel, Field


class ConceptCard(BaseModel):
  name: str = Field(description="概念名称")
  one_liner: str = Field(description="一句话解释")
  when_to_use: str = Field(description="适用场景")

llm.py

def get_structured_model(schema: Type[BaseModel], *, temperature: float = 0):
  """返回 with_structured_output 后的模型。"""
  return get_chat_model(temperature=temperature).with_structured_output(schema)

main.py 演示 C:

def demo_structured_output() -> None:
  card = get_structured_model(ConceptCard).invoke(
    "请用结构化字段解释:LangChain 的 Runnable 是什么。"
  )
  print(card.model_dump_json(indent=2, ensure_ascii=False))

用法心智:

  1. 封装要输出的数据 —— Pydantic 模型 + Field 描述
  2. with_structured_output(schema) —— 模型按 schema 吐对象
  3. 读字段 —— card.name / card.one_liner,或 model_dump_json

注释写得很清楚:底层可能走 tool / JSON mode,比「纯文本再 json.loads」稳。教学上仍可学 Output Parser;生产优先 with_structured_output

Agent 路线还会见到 response['structured_response']——那是创建 Agent 时挂输出格式后的字段名。

4. Agent 上的 System Prompt(对照)

上篇系列 已出现过:

agent = create_agent(
  get_chat_model(temperature=0),
  tools=TOOLS,
  system_prompt="你是助手。需要查天气或做加法时必须调用工具,不要编造。",
)

“链:人设在 ChatPromptTemplate 的 system 句。
Agent:人设在 system_prompt=
Few-shot:可在模板里多几轮 ("human", ...), ("ai", ...) 样例——本篇先掌握模板变量 + 结构化,Few-shot 作提示词工程菜单项记住即可。”

小明复述:”模板填变量;竖线组流水线;要表格就先写 Pydantic。”


总结

老张说:”第五篇只办一件事——用模板和类型,取代复制粘贴与脆弱 JSON。”

“三个核心理解:

  1. ChatPromptTemplate —— 人设与指令进模板,变量用 {占位符}
  2. LCEL —— prompt | model | parser,链上 invoke / stream
  3. 结构化输出 —— 先定义数据类型,再 with_structured_output,直接读字段”

LangChain 支线进度:

… → Messages 与多模态
    ↓
Prompts / LCEL / 结构化输出(本篇)
    ↓
Tools 与 Tool Agent → Memory → AI私厨…

小明说:”下一篇该系统看 Tools 了——@tool、多工具、和 Agent 循环怎么工程化。”

“对。下一篇:Tools 与 Tool Agent。”

提示词工程不是玄学堆形容词;是把人设、样例、输出形状写进可复用的模板与类型里。LCEL 让这些零件变成管道。

转载请注明来源:Prompts 与 LCEL:提示词工程 + 结构化输出
本文链接地址:https://ai.zhousir.top/?p=3821
回复 取消