Prompt 与 Chains

面试官:「用 LangChain 怎么调用 LLM?」

你:「很简单,就是用 `|` 管道符把 Prompt Template 和 Model 连起来...」

面试官:「那多个 Chain 怎么串联?」

你:「用 `RunnableSequence`...」

面试官:「输出怎么解析成结构化数据?」

🤔 这个问题问得深!LCEL 不只是 `|` 那么简单,它背后是一套完整的可运行对象体系。

2.1 Prompt 基础概念

Prompt(提示词)是我们与 LLM 沟通的桥梁。一个好的 Prompt 可以显著提升模型的输出质量。

💡 Prompt 的核心要素

要素 作用 示例
指令(Instruction) 告诉模型要做什么 "翻译以下文本"
上下文(Context) 提供必要的背景信息 "这是一封商务邮件"
输入数据(Input) 模型需要处理的内容 "Hello, how are you?"
输出格式(Format) 指定期望的输出形式 "用中文回答"
图 2-1:Prompt 组成结构
指令 Instruction 上下文 Context 输入 Input 格式 Format 示例 Prompt: "你是一位专业的英文翻译。请将以下中文翻译成英文:今天天气真好用简洁的语言输出。" 指令 上下文 输入 格式

2.1.1 为什么需要 Prompt Templates?

在应用中,我们通常需要多次调用 LLM,每次调用可能只有少量参数不同。如果每次都写完整的 Prompt,会导致代码重复、难以优化、容易出错。Prompt Template 就是为了解决这些问题。

2.2 Prompt Templates 详解

2.2.1 字符串 Prompt Template

python string_prompt_template.py
from langchain_core.prompts import PromptTemplate

template = PromptTemplate.from_template(
    "请将以下中文翻译成{target_language}:{text}"
)

prompt = template.invoke({
    "target_language": "英文",
    "text": "你好,世界"
})
print(prompt.to_string())

2.2.2 Few-Shot 提示模板

python few_shot_template.py
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate

examples = [
    {"word": "开心", "antonym": "伤心"},
    {"word": "高大", "antonym": "矮小"},
]

example_prompt = PromptTemplate.from_template("词语: {word}
反义词: {antonym}")

prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="请给出下列词语的反义词:",
    suffix="词语: {input}
反义词:",
    input_variables=["input"]
)

result = prompt.invoke({"input": "快速"})
print(result.to_string())
💡 Few-Shot 的优势

Few-shot 比 zero-shot(不给示例)效果更好,但示例不宜过多,通常 3-5 个就够了。

2.3 Chat Prompt 模板

对于 Chat Model,我们需要使用专门的 Chat Prompt 模板。

2.3.1 消息类型

消息类型 角色 用途
SystemMessage system 设定 AI 的角色和行为
HumanMessage user 用户输入
AIMessage assistant AI 的回复

2.3.2 创建 Chat Prompt 模板

python chat_prompt_template.py
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一位专业的{subject}老师。"),
    ("human", "请解释:{concept}"),
])

messages = prompt.invoke({
    "subject": "物理学",
    "concept": "量子纠缠"
})
print(messages.to_messages())

2.3.3 MessagesPlaceholder 动态消息

python messages_placeholder.py
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个乐于助人的助手。"),
    MessagesPlaceholder("chat_history", optional=True),
    ("human", "{user_input}"),
])

result = prompt.invoke({
    "chat_history": [HumanMessage(content="我叫张三"), AIMessage(content="你好!")],
    "user_input": "我叫什么名字?"
})

2.4 输出解析器

输出解析器(Output Parser)可以将 LLM 文本输出解析成结构化数据。

解析器 用途 输出格式
StrOutputParser 直接输出字符串 str
JsonOutputParser 输出 JSON dict
PydanticOutputParser 基于 Pydantic 模型 自定义结构

2.4.1 JsonOutputParser 使用

python json_output_parser.py
from langchain_core.output_parsers import JsonOutputParser
from pydantic import BaseModel, Field

class Joke(BaseModel):
    setup: str = Field(description="笑话的铺垫")
    punchline: str = Field(description="笑话的笑点")

parser = JsonOutputParser(pydantic_object=Joke)
chain = prompt | llm | parser
result = chain.invoke({"topic": "程序员"})
print(result)
⚠️ 注意事项

输出解析器依赖模型正确遵循格式指令。对于复杂结构,建议添加重试逻辑。

2.5 Chain 链式调用

Chain(链)是 LangChain 的核心概念,它将多个组件串联起来。

2.5.1 LCEL 基础语法

LCEL 提供了直观的 | 管道操作符:

图 2-4:LCEL 管道操作符
Component A | Component B | Component C = Chain

2.5.2 构建一个简单链

python llm_chain.py
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个翻译助手。"),
    ("human", "翻译成{target_lang}:{sentence}")
])
parser = StrOutputParser()

chain = prompt | llm | parser
result = chain.invoke({"target_lang": "日语", "sentence": "你好"})
print(result)
💡 提示

流式调用(stream)对于需要实时显示输出的场景特别有用。

2.6 顺序链与路由链

2.6.1 顺序链 SequentialChain

当链的输出需要作为下一个链的输入时,使用顺序链:

python sequential_chain.py
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

translate_chain = (
    ChatPromptTemplate.from_template("翻译成英文:{text}") | llm | StrOutputParser()
)

summarize_chain = (
    ChatPromptTemplate.from_template("一句话总结:{text}") | llm | StrOutputParser()
)

final_chain = {"translation": translate_chain} | summarize_chain
result = final_chain.invoke({"text": "今天天气真好"})
print(result)

2.6.2 路由链 RouterChain

python router_chain.py
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

translate_chain = (ChatPromptTemplate.from_template("翻译:{text}") | llm | StrOutputParser())
qa_chain = (ChatPromptTemplate.from_template("问答:{text}") | llm | StrOutputParser())

router = ChatPromptTemplate.from_template("选择:translate 或 qa
输入:{text}") | llm | StrOutputParser()

def route(text):
    choice = router.invoke({"text": text}).strip().lower()
    if "translate" in choice:
        return translate_chain.invoke({"text": text})
    return qa_chain.invoke({"text": text})

2.7 本章小结

📝 关键概念回顾

概念 说明 代码示例
PromptTemplate 字符串模板,支持变量 from_template("翻译成{target}:{text}")
ChatPromptTemplate 消息列表模板 from_messages([("system", "..."), ("human", "...")])
OutputParser 解析模型输出 JsonOutputParser, StrOutputParser
LCEL 链式调用语法 prompt | llm | parser
  • Prompt Template:通过变量复用提示词
  • Chat Prompt:使用 System/Human/AI 消息角色
  • Output Parser:将文本解析为结构化数据
  • LCEL:使用 | 操作符组合组件
  • 顺序链:处理多步骤工作流
  • 路由链:根据输入动态选择处理路径
🚀 接下来学什么?

在下一章中,我们将学习 Agents 与 Memory