本节聚焦 LangChain 1.0 的 Model 与 Prompt:模型参数如何影响输出、消息如何组织上下文、Prompt 模板如何复用,以及怎样让模型返回可校验的结构化结果。
1. 初始化模型
python
import os
from langchain.chat_models import init_chat_model
model = init_chat_model(
"Qwen/Qwen3-8B",
model_provider="openai",
base_url=os.getenv("OPENAI_BASE_URL"),
api_key=os.getenv("OPENAI_API_KEY"),
temperature=0.2,
max_tokens=1024,
timeout=30,
max_retries=2,
)
常用参数:
| 参数 | 作用 | 建议 |
|---|---|---|
temperature |
控制随机性 | 抽取/分类设低,创作适当提高 |
max_tokens |
限制最大输出长度 | 结合任务与成本设置 |
timeout |
单次请求超时 | 避免无限等待 |
max_retries |
临时错误重试次数 | 配合指数退避使用 |
stop |
遇到指定文本停止 | 适合固定格式输出 |
参数不能替代 Prompt。低温度只能让结果更稳定,不能自动让指令更清晰。
2. 消息模型
Chat Model 接收的是消息序列,而不是一整段无角色文本。
python
from langchain_core.messages import (
SystemMessage,
HumanMessage,
AIMessage,
)
messages = [
SystemMessage(content="你是一名专业的旅游顾问。"),
HumanMessage(content="推荐两家适合商务出行的柏林酒店。"),
]
response = model.invoke(messages)
print(response.content)
SystemMessage:设定角色、规则和边界;HumanMessage:用户输入;AIMessage:模型回答,也可能包含 Tool Call;ToolMessage:工具执行后返回给模型的结果。
3. Prompt 模板
当提示词需要反复使用时,不应手工拼接字符串,而应使用 ChatPromptTemplate。
python
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
(
"system",
"你是一名{domain}专家。请使用{style}风格回答,"
"不知道时明确说明,不要编造。",
),
("human", "{question}"),
])
messages = prompt.invoke({
"domain": "Python",
"style": "简洁且包含代码示例",
"question": "解释上下文管理器",
})
response = model.invoke(messages)
print(response.content)
模板变量由 {变量名} 声明,调用时必须提供所有必填变量。
4. 在模板中加入历史消息
python
from langchain_core.prompts import (
ChatPromptTemplate,
MessagesPlaceholder,
)
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一名中文技术助手。"),
MessagesPlaceholder(variable_name="history"),
("human", "{question}"),
])
history = [
HumanMessage(content="我正在学习 LangChain。"),
AIMessage(content="好的,我会结合 LangChain 示例回答。"),
]
messages = chat_prompt.invoke({
"history": history,
"question": "Agent 的状态保存在哪里?",
})
MessagesPlaceholder 会原样插入消息列表,避免把多轮对话压成一段普通字符串。
5. 组合 Prompt、Model 与解析器
LangChain 的 Runnable 可以使用管道运算符组合:
python
from langchain_core.output_parsers import StrOutputParser
chain = prompt | model | StrOutputParser()
answer = chain.invoke({
"domain": "LangChain",
"style": "分点说明",
"question": "什么是 Runnable?",
})
print(answer)
这里的执行顺序是:
text
变量字典 → PromptValue → AIMessage → 字符串
6. 批量、异步与流式处理
python
inputs = [
{
"domain": "AI",
"style": "一句话",
"question": "解释 RAG",
},
{
"domain": "AI",
"style": "一句话",
"question": "解释 Agent",
},
]
results = chain.batch(inputs)
python
result = await chain.ainvoke(inputs[0])
python
for chunk in chain.stream(inputs[0]):
print(chunk, end="", flush=True)
7. 结构化输出
自由文本适合给人阅读,程序消费时应使用结构化输出。
python
from pydantic import BaseModel, Field
class ReviewAspect(BaseModel):
name: str = Field(description="评价维度")
score: float = Field(ge=0, le=5, description="0~5 分")
comment: str = Field(description="该维度的简短说明")
class ProductReview(BaseModel):
overall_sentiment: str = Field(
description="positive、neutral 或 negative"
)
overall_score: float = Field(ge=0, le=5)
aspects: list[ReviewAspect]
structured_model = model.with_structured_output(ProductReview)
result = structured_model.invoke(
"""分析以下评论:
手机拍照清晰,续航也不错,但充电速度偏慢。
"""
)
print(result.model_dump())
Pydantic 同时完成四件事:
- 描述目标字段;
- 约束数据类型;
- 校验数值范围;
- 将返回结果转为 Python 对象。
8. Prompt 设计检查表
- 角色是谁;
- 需要完成什么目标;
- 有哪些输入数据;
- 可以使用哪些知识,不能做什么;
- 输出格式是什么;
- 资料不足时如何处理;
- 是否需要给出来源、步骤或置信度。
9. 常见问题
9.1 模板变量报错
检查 Prompt 中所有 {name} 是否都在 invoke() 参数中提供。需要输出字面量大括号时,应写成 {``{ 和 }}。
9.2 JSON 解析失败
不要只在 Prompt 中说"返回 JSON";优先使用 with_structured_output(),并为字段增加类型和说明。
9.3 结果不稳定
先明确任务、边界和输出格式,再降低 temperature。必要时加入少量高质量示例。
9.4 上下文越来越长
不要无限追加历史消息。后续可以使用消息裁剪、自动摘要和 Checkpointer 控制上下文。
10. 本节小结
一个稳定的模型功能需要同时控制三层:模型参数决定生成特性,Prompt 决定任务边界,结构化输出决定结果能否被程序可靠消费。