Chat Model 的本质
在 LangChain 的语境中,Chat Model 是与 LLM 交互的标准接口。与早期的文本补全接口(输入一段文字、输出续写文字)不同,Chat Model 基于 对话消息列表(Message List)进行交互:输入是一组带角色标签的消息,输出是模型的回复消息。
这种设计更贴近现代 LLM API(如 OpenAI Chat Completions、Anthropic Messages API),并且天然支持多轮对话上下文的传递。
接入主流 Chat Models
OpenAI GPT 系列
from langchain_openai import ChatOpenAI
# 基本配置
model = ChatOpenAI(
model="gpt-4o", # 或 "gpt-4o-mini"
temperature=0.7, # 创造性,0~2,建议 0~1
max_tokens=1024, # 最大输出 token 数
timeout=60, # 请求超时(秒)
max_retries=3, # 自动重试次数
)
# 直接调用(传入消息列表)
from langchain_core.messages import HumanMessage, SystemMessage
response = model.invoke([
SystemMessage(content="你是一位专业的 Python 导师,用简洁的语言解答问题。"),
HumanMessage(content="解释什么是生成器(generator)"),
])
print(response.content) # AIMessage.content
print(response.usage_metadata) # token 用量统计
Anthropic Claude 系列
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-opus-4-5", # 或 "claude-haiku-3-5"
temperature=0,
max_tokens=2048,
)
response = model.invoke([
HumanMessage(content="用中文解释 LangChain 的 LCEL 是什么")
])
print(response.content)
模型参数调优技巧
temperature 参数
- 0:确定性输出,适合代码生成、数学计算
- 0.3~0.7:平衡创意与准确性,适合问答
- 0.8~1.0:更有创意,适合文案创作
- 大于 1.0 较少使用,输出可能不稳定
streaming 流式输出
- 设置
streaming=True或调用.stream() - 逐 token 返回,改善用户体验
- 适合聊天界面、长文本生成
- 配合 LCEL 管道自动传播流式
PromptTemplate:模板化提示词
PromptTemplate 是将字符串模板与变量结合的工具。它让提示词可以复用,通过占位符动态插入不同的输入内容。
ChatPromptTemplate(最常用)
from langchain_core.prompts import ChatPromptTemplate
# 方式一:from_messages(推荐)
prompt = ChatPromptTemplate.from_messages([
("system", "你是一位专业的{language}开发者,用简洁的中文回答问题。"),
("human", "帮我解释:{question}"),
])
# 格式化:传入变量
messages = prompt.format_messages(
language="Python",
question="什么是装饰器?"
)
print(messages)
# [SystemMessage(content='你是一位专业的Python开发者...'),
# HumanMessage(content='帮我解释:什么是装饰器?')]
# 或者直接在 LCEL 管道中使用(推荐)
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
model = ChatOpenAI(model="gpt-4o-mini")
chain = prompt | model | StrOutputParser()
result = chain.invoke({
"language": "Python",
"question": "什么是装饰器?"
})
print(result) # 直接得到字符串
PromptTemplate(纯文本)
from langchain_core.prompts import PromptTemplate
# 用于需要纯字符串格式的场景
template = PromptTemplate.from_template(
"将以下内容翻译成{language}:\n\n{text}"
)
formatted = template.format(language="日语", text="Hello World")
print(formatted) # 将以下内容翻译成日语:\n\nHello World
MessagePlaceholder:注入历史消息
MessagePlaceholder 是 ChatPromptTemplate 中的特殊占位符,用于在模板中插入一段动态的消息列表,最常见的用途是注入多轮对话历史。
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage
prompt = ChatPromptTemplate.from_messages([
("system", "你是一位 AI 助手,用友好的语气回答用户问题。"),
MessagesPlaceholder(variable_name="history"), # 注入对话历史
("human", "{input}"),
])
# 模拟带历史的调用
history = [
HumanMessage(content="我叫小明"),
AIMessage(content="你好,小明!很高兴认识你。"),
]
messages = prompt.format_messages(
history=history,
input="你还记得我叫什么名字吗?"
)
model = ChatOpenAI(model="gpt-4o-mini")
response = model.invoke(messages)
print(response.content) # 模型会记住 "小明"
MessagesPlaceholder 的优势在于:它可以接受任意长度的消息列表,并且与 LCEL 管道无缝集成。当与 RunnableWithMessageHistory(第5章)结合时,历史消息会自动从存储中加载并注入到这个占位符中。
Few-shot 提示工程
Few-shot Prompting(少样本提示)是指在提示词中给模型提供少量示例,让模型学习输出格式和风格,而不需要微调模型。这是提升模型输出质量最有效的技巧之一。
from langchain_core.prompts import (
ChatPromptTemplate, FewShotChatMessagePromptTemplate
)
# 定义示例
examples = [
{
"input": "2 + 2",
"output": "计算结果:4\n运算过程:直接加法"
},
{
"input": "15 * 4",
"output": "计算结果:60\n运算过程:15 乘以 4"
},
]
# 定义每个示例的格式
example_prompt = ChatPromptTemplate.from_messages([
("human", "{input}"),
("ai", "{output}"),
])
# Few-shot 提示模板
few_shot_prompt = FewShotChatMessagePromptTemplate(
examples=examples,
example_prompt=example_prompt,
)
# 最终完整提示
final_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个数学计算助手,按照示例的格式回答。"),
few_shot_prompt,
("human", "{input}"),
])
chain = final_prompt | model | StrOutputParser()
print(chain.invoke({"input": "7 * 8"}))
Few-shot 的选择策略
当示例数量较多时,可以使用 SemanticSimilarityExampleSelector 根据输入的语义相似性动态选择最相关的示例:
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma
selector = SemanticSimilarityExampleSelector.from_examples(
examples=examples, # 全部示例
embeddings=OpenAIEmbeddings(),
vectorstore_cls=Chroma,
k=3, # 每次选最相关的 3 个
)
# 根据当前输入动态选择示例
selected = selector.select_examples({"input": "如何用 Python 排序列表?"})
print(selected)
partial_variables:预填充模板变量
有时候某些变量在运行时是固定的(比如当前日期),可以使用 partial 预填充,避免每次调用都传入:
from datetime import datetime
from langchain_core.prompts import ChatPromptTemplate
def get_current_date():
return datetime.now().strftime("%Y年%m月%d日")
prompt = ChatPromptTemplate.from_messages([
("system", "今天是{date},你是一位时事分析师。"),
("human", "{question}"),
]).partial(date=get_current_date) # 预填充 date 变量
# 调用时只需传入 question
chain = prompt | model | StrOutputParser()
result = chain.invoke({"question": "今日有什么重要新闻?"})
Prompt 调试技巧
在开发阶段,经常需要查看实际发送给模型的完整消息。几个实用技巧:
# 技巧1:直接调用 format_messages 查看渲染结果
messages = prompt.format_messages(language="Python", question="装饰器")
for m in messages:
print(type(m).__name__, ":", m.content[:100])
# 技巧2:在 LCEL 管道中插入调试步骤
from langchain_core.runnables import RunnableLambda
def debug_print(x):
print("[DEBUG]", x)
return x
chain = prompt | RunnableLambda(debug_print) | model | StrOutputParser()
# 技巧3:开启 LangSmith 追踪(最全面,第9章详述)
# LANGCHAIN_TRACING_V2=true 环境变量开启后,所有调用自动追踪
直接用 f-string 拼接提示词虽然快速,但无法与 LCEL 管道集成,不支持流式输出,也无法在 LangSmith 中正确追踪变量注入情况。养成使用 ChatPromptTemplate 的习惯,会带来长期的可维护性收益。
本章小结
- Chat Model 基于消息列表(System/Human/AI/Tool Message)进行交互
ChatOpenAI、ChatAnthropic等通过统一的 Runnable 接口调用,可互换ChatPromptTemplate.from_messages()是构建提示词的标准方式MessagesPlaceholder用于在模板中动态插入对话历史- Few-shot 通过示例引导模型输出格式,语义选择器可动态匹配最相关示例
partial()可预填充固定变量,简化调用接口