系列文章目录
【 LangChain v1.2 入门系列教程】【一】开篇入门 | 从零开始,跑通你的第一个 AI Agent
【 LangChain v1.2 入门系列教程】【二】消息类型与提示词工程
【 LangChain v1.2 入门系列教程】【三】工具(Tools)开发,让 Agent 连接外部世界
【 LangChain v1.2 入门系列教程】【四】结构化输出,让 Agent 返回可预测的结构
【 LangChain v1.2 入门系列教程】【五】记忆管理,让 Agent 记住对话
【 LangChain v1.2 入门系列教程】【六】流式输出, 让 Agent 告别“想好了再说”
文章目录
- 系列文章目录
- 前言
- 一、 LangChain 的 4 种核心消息类型
- 1. 手动构建消息列表
- 2. llm.invoke() 传入消息历史
- 3.agent.invoke()传入消息历史
- 4.ToolMessage 的传递
- 二、提示词模板(ChatPromptTemplate)
- 1. 基础用法(方式一)
- 2. 基础用法(方式二)
- 3. 基础用法(方式三)
- 4. 基础用法(方式四)
- 5、进阶用法(MessagesPlaceholder)
- 三、系统提示(System Prompt)
- 1. 系统提示词的设计原则
- 四、 总结
前言
在上一篇中,我们完成了环境搭建并跑通了第一个 AI Agent 。本文将带你深入 LangChain v1.2 的消息机制(Messages),并学习如何用提示词模板(Prompt Templates)像搭积木一样构建稳定、可控的对话。
一、 LangChain 的 4 种核心消息类型
LangChain 使用结构化的消息对象来与聊天模型交互,每种消息对应对话中的一个角色:
| 消息类型 | 角色 | 作用 |
|---|---|---|
| SystemMessage | 系统消息 | 给 AI 设定 “人设” 和规则(比如 “你是一个资深博客专家”),通常放在对话开头。 |
| HumanMessage | 用户消息 | 用户说的话,就是直接发给 AI 的提问或指令 |
| AIMessage | AI 消息 | AI 回复的话 |
| ToolMessage | 工具消息 | 当 AI 调用某个工具(如上一篇中 get_weather)后,工具返回的结果 |
1. 手动构建消息列表
有时候我们需要手动维护把各类历史消息按顺序传回给模型,作为上下文参考。例如:
importosfromdotenvimportload_dotenvfromlangchain.messagesimportAIMessage,HumanMessage,SystemMessagefromlangchain_openaiimportChatOpenAI load_dotenv()# api_key从硅基流动后台获取API_KEY=os.getenv("API_KEY")#实例化模型llm=ChatOpenAI(model="Qwen/Qwen3-8B",# 模型名称base_url="https://api.siliconflow.cn/v1",# 硅基流动的 API 地址api_key=API_KEY,# 你的-api-key)#手动构建对话历史messages=[SystemMessage(content="你是一位翻译专家,将中文翻译成英文。"),HumanMessage(content="你好,世界"),AIMessage(content="hello, world"),HumanMessage(content="我正在写博客"),#当前问题]#调用模型response=llm.invoke(messages)print(response.content)#输出:I'm writing a blog说明:我们最初通过系统消息定义ai的角色是一名"翻译专家“,回答规则是把输入的中文翻译成英文,第一轮用户提问“你好,世界”,ai翻译后回答“hello,world”。第二轮用户提问“我正在写博客”,ai翻译后回答“I’m writing a blog”。从该示例中我们能深刻体会SystemMessage(系统消息)的作用。
2. llm.invoke() 传入消息历史
LangChain v1.2 我们使用 llm.invoke() 方法传入消息历史获取大模型回复,入参有2种类型,除了上面示例展示的List[BaseMessage]形式外,它还支持字典格式List[dict],例如:
messages=[{"role":"system","content":"你是一位翻译专家,将中文翻译成英文。"},{"role":"user","content":"你好,世界"},{"role":"assistant","content":"hell,word"},{"role":"user","content":"我正在写博客"},]# 调用模型response=llm.invoke(messages)print(response.content)# 输出:I'm writing a blog注意:用户消息也兼容如下写法:{“role”: “human”,“content”: “你好,世界”}
3.agent.invoke()传入消息历史
当你使用 create_agent() 创建 Agent, invoke() 方法通常要求传入一个字典,其中必须包含一个 “messages” 键,其值为消息列表(支持List[BaseMessage]或List[dict]格式),例如:
importosfromdotenvimportload_dotenvfromlangchain.agentsimportcreate_agentfromlangchain.messagesimportAIMessage,HumanMessage,SystemMessagefromlangchain_openaiimportChatOpenAI load_dotenv()# api_key从硅基流动后台获取API_KEY=os.getenv("API_KEY")# 实例化模型llm=ChatOpenAI(model="Qwen/Qwen3-8B",# 模型名称base_url="https://api.siliconflow.cn/v1",# 硅基流动的 API 地址api_key=API_KEY,# 你的-api-key)# 创建Agentagent=create_agent(model=llm)# 手动构建对话历史messages=[SystemMessage(content="你是一位翻译专家,将中文翻译成英文。"),HumanMessage(content="你好,世界"),AIMessage(content="hell,word"),HumanMessage(content="我正在写博客"),]# 调用模型response=agent.invoke({"messages":messages})print(response["messages"][-1].content)# 输出:I'm writing a blog从上述示例可以发现agent .invoke() 跟 llm.invoke()返回值不一样,它是个字典包含“messages”字段,打印下“messages”数据:
print(response["messages"])打印数据如下:
[SystemMessage(content='你是一位翻译专家,将中文翻译成英文。',additional_kwargs={},response_metadata={},id='9c5700dd-62b4-4e4c-9e03-21d42b307f24'),HumanMessage(content='你好,世界',additional_kwargs={},response_metadata={},id='893b5d7f-4555-4d0f-af15-2ad4bb428351'),AIMessage(content='hell,word',additional_kwargs={},response_metadata={},id='2da1c10d-f2b8-4422-aa5f-3e967abaf704',tool_calls=[],invalid_tool_calls=[]),HumanMessage(content='我正在写博客',additional_kwargs={},response_metadata={},id='973de492-98f3-4f2c-97e6-d69c3a076937'),AIMessage(content="I'm writing a blog.",additional_kwargs={'refusal':None},response_metadata={'token_usage':{'completion_tokens':6,'prompt_tokens':48,'total_tokens':54,'completion_tokens_details':{'accepted_prediction_tokens':None,'audio_tokens':None,'reasoning_tokens':0,'rejected_prediction_tokens':None},'prompt_tokens_details':None},'model_provider':'openai','model_name':'Qwen/Qwen3-8B','system_fingerprint':'','id':'019d207edbd5da788a852a998ba5082e','finish_reason':'stop','logprobs':None},id='lc_run--019d207e-db57-7e13-8cb9-e3e4bb6787c6-0',tool_calls=[],invalid_tool_calls=[],usage_metadata={'input_tokens':48,'output_tokens':6,'total_tokens':54,'input_token_details':{},'output_token_details':{'reasoning':0}})]可以发现这是完整的消息列表,它由你传入的原始 messages 加上 AI 新生成的消息(可能还有工具调用产生的消息)合并而成。
response[“messages”][-1] 就是列表中的最后一条消息。在大多数简单场景下,它恰好是 AI 针对最后一个用户输入生成的新回复,类型为 AIMessage,其 content 属性即为回复文本。
4.ToolMessage 的传递
当 AI 调用了工具,我们需要将工具执行结果以 ToolMessage 形式传回给模型。ToolMessage 除了 content,还必须有 tool_call_id,以关联对应的工具调用。
fromlangchain_core.messagesimportToolMessage# 假设模型调用 get_weather 工具,并生成了一个 tool_call_idtool_call_id="call_123"# 构造工具返回的消息tool_message=ToolMessage(content="厦门的天气是晴朗,20°C",tool_call_id=tool_call_id)# 将 tool_message 添加到消息列表中,继续对话messages.append(tool_message)# 然后再次调用模型response=llm.invoke(messages)二、提示词模板(ChatPromptTemplate)
手动构建消息列表虽然直观,但不够灵活。LangChain 提供ChatPromptTemplate 允许你定义消息模板,动态注入变量,重复使用模版。
1. 基础用法(方式一)
ChatPromptTemplate.from_template().format_messages() #单角色消息fromlangchain_core.promptsimportChatPromptTemplate# 提示词模版prompt_template=ChatPromptTemplate.from_template("你是{role}专家,请用{style}风格回答问题,问题:{question}")# 格式化提示词message=prompt_template.format_messages(role="文学",style="幽默",question="讲个故事")# 调用模型response=llm.invoke(message)print(response.content)2. 基础用法(方式二)
ChatPromptTemplate.from_template() +链式调用 #单角色消息fromlangchain_core.output_parsersimportStrOutputParser# 提示词模版prompt_template=ChatPromptTemplate.from_template("你是{role}专家,请用{style}风格回答问题,问题:{question}")#链式调用chain=prompt_template|llm|StrOutputParser()#StrOutputParser:输出解析器:提取纯文本内容# 调用模型content=chain.invoke({"role":"文学","style":"幽默","question":"讲个故事"})print(content)ps:| 语法是一种类似 Unix 管道的链式操作符,用于将前一个组件的输出直接作为后一个组件的输入,从而串联起提示词模板、模型和输出解析器等组件,形成一条可执行的处理链
3. 基础用法(方式三)
ChatPromptTemplate.from_messages().format_messages() #多角色消息# 提示词模版prompt_template=ChatPromptTemplate.from_messages([("system","你是一个专业的翻译官,把{input_language}翻译成{output_language}。"),#系统消息("human","{question}"),#用户消息])#格式化消息messages=prompt_template.format_messages(input_language="中文",output_language="英文",question="你好,世界")# 调用模型response=llm.invoke(messages)print(response.content)#Hello, world.4. 基础用法(方式四)
ChatPromptTemplate.from_messages() +链式调用 #多角色消息# 提示词模版prompt_template=ChatPromptTemplate.from_messages([("system","你是一个专业的翻译官,把{input_language}翻译成{output_language}。"),#系统消息("human","{question}"),#人类消息])chain=(prompt_template|llm|StrOutputParser())# StrOutputParser:输出解析器:提取纯文本内容# 调用模型content=chain.invoke({"input_language":"中文","output_language":"英文","question":"你好,世界"})print(content)#hellow,world.5、进阶用法(MessagesPlaceholder)
当需要插入不确定数量的历史消息时(如多轮对话),使用 MessagesPlaceholder动态插入消息列表
fromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholder#构建占位符消息模版prompt_template=ChatPromptTemplate.from_messages([("system","你是一个友好的客服助手。"),MessagesPlaceholder(variable_name="chat_history"),# 这里会插入任意多条历史消息("human","{question}")#当前用户问题])# 对话历史history_messages=[AIMessage(content="您好!请问有什么可以帮您?"),HumanMessage(content="我想查一下订单状态。")]chain=prompt_template|llm|StrOutputParser()content=chain.invoke({"chat_history":history_messages,"question":"我的订单号是12345"})print(content)#您的订单处于待发货状态三、系统提示(System Prompt)
在LangChain v1.2中推荐使用create_agent() 创建智能体方式来调用大模型,通过system_prompt参数非常方便设置系统提示(SystemMessage系统消息),例如:
#创建agentagent=create_agent(model=llm,system_prompt="你是一位翻译专家,将中文翻译成英文"#系统提示词)#调用模型response=agent.invoke({"messages":[HumanMessage('你叫什么名字?')]})print(response['messages'][-1].content)#What's your name?1. 系统提示词的设计原则
系统提示词是影响 AI 行为最直接、成本最低的方式。好的系统提示词设计时遵循:
(1)角色定义清晰:
system_prompt=""" 你是一位精通 Python 性能优化的资深工程师,擅长识别代码中的瓶颈并给出量化改进建议。 """(2)强制输出格式
system_prompt="""你必须严格按照以下JSON格式回复: { "thinking": "思考过程", "answer": "最终答案", "confidence": 0-1之间的数字 } 只输出JSON,不要其他内容。"""(3)制定规则
system_prompt=""" 你必须遵守以下规则: 1. 只使用 Markdown 格式回复。 2. 每条建议前必须加上「⚠️ 风险」或「💡 建议」。 3. 禁止输出任何未经测试的代码片段。 4. 禁止使用「可能」「大概」等模糊词汇。 """(4)设定清晰边界
system_prompt=""" 你是一个医疗信息摘要助手。 - 如果你遇到用户描述的疑似急症(如胸痛、呼吸困难),必须回答:“请立即就医,我无法提供诊断。” - 对于其他健康问题,你可以总结信息,但不得给出具体治疗建议。 """(5)提供示例
system_prompt=""" 你是一个数学解题助手,输出格式:先列出关键步骤,再给出最终答案。 示例: 用户:2 + 3 × 4 助手: 步骤: 1. 先算乘法:3 × 4 = 12 2. 再算加法:2 + 12 = 14 最终答案:14 """四、 总结
通过本文,我们从 LangChain 的消息体系入手,逐步掌握了以下核心技能:
理解四种消息角色:SystemMessage、HumanMessage、AIMessage、ToolMessage,并学会手动构建消息列表,让 AI 在对话中“记住”上下文。
灵活调用模型:无论是直接使用 llm.invoke() 传入消息列表,还是通过 agent.invoke() 传入字典格式的消息,都能轻松实现多轮对话。
告别硬编码:借助 ChatPromptTemplate 和 MessagesPlaceholder,我们可以像搭积木一样动态构建提示词模板,支持变量注入、历史占位,让代码更优雅、更易维护。
用好系统提示词:明确了角色定义、输出格式、边界约束等五大设计原则,并通过示例展示了如何写出“指令明确”的优质提示词。
当你掌握了消息与提示词这两大基石,LangChain 的大门才算真正向你敞开。在下一篇文章中,我们将深入 工具调用(Tool Calling),敬请期待!