LangChain Messages 篇章学习笔记 — 模型交互的输入输出单元
本文基于 LangChain 官方文档 Messages 章节学习整理,梳理消息对象的结构、四种消息类型、多种传参格式与多轮对话机制,适合 AI Agent 开发入门者理解模型交互的数据载体。
一、Message 是什么
Message 是 LangChain 中从模型获取上下文的基础工具(fundamental utility)。Model 是基础单元,而 Message 反映了模型的输入和输出。它携带 content(内容)和 metadata(元数据),用于与 AI 交流。
Message 是一个对象(object),包含以下核心字段:
| 字段 | 说明 | 示例 |
|---|---|---|
| role | 消息类型(角色) | system / user / assistant / tool |
| content | 消息内容 | 文本、图片、音频、文档等 |
| metadata | 可选元数据 | message id、token usage 等 |
LangChain 提供了标准的 Message 模型类别,可以在所有模型提供商中工作,确保一致性行为,不管你用的是哪个模型。
二、基础使用
2.1 创建 Message 对象
最简单的方式是直接创建 Message 实体,然后把它们放到 invoke / stream / batch 里调用。
fromlangchain.messagesimportSystemMessage,HumanMessage# SystemMessage:给模型定义角色、背景、风格SystemMessage(content="你是一个专业的 Python 翻译助手")# HumanMessage:用户的问题HumanMessage(content="Translate: I love programming.")2.2 三种传参方式
方式一:Text Prompts(字符串简写)
调用时直接传入字符串,LangChain 自动包装为 HumanMessage。
response=llm.invoke("什么是递归?")# 等价于 llm.invoke(HumanMessage(content="什么是递归?"))方式二:Message Prompts(消息对象列表)
创建一个 list,放入各种 Message 对象。适用于多轮对话和 system instruction。
fromlangchain.messagesimportSystemMessage,HumanMessage,AIMessage messages=[SystemMessage(content="你是英文到法文翻译助手"),HumanMessage(content="Translate: I love programming."),AIMessage(content="J'adore la programmation."),# 上一轮 AI 的回答HumanMessage(content="Translate: I love building applications."),]response=llm.invoke(messages)多轮对话的关键:把 AI 之前说的内容(AIMessage)放回消息列表,让 AI 有了短暂的记忆能力。你说一句、AI 说一句,再把 AI 说的内容传回去,形成多轮对话。
方式三:Dictionary Format(字典格式)
用字典构建消息,OpenAI 兼容最简洁的写法。
messages=[{"role":"system","content":"你是翻译助手"},{"role":"user","content":"Translate: I love programming."},{"role":"assistant","content":"J'adore la programmation."},{"role":"user","content":"Translate: I love building applications."},]response=llm.invoke(messages)Q:字典格式里的 role 和 content 是规定好的吗?能随便传吗?
A:不能随便传。role 只能是
system/user/assistant/tool这 4 个固定值,这是 OpenAI API 规范,所有兼容端点(包括百炼)都遵循。content 是你自己传的内容字符串。字典格式只是对象格式的简写,底层 LangChain 自动转成对应对象。
| 字典 role | LangChain 对象 | 作用 |
|---|---|---|
"system" | SystemMessage | 定义模型角色 |
"user" | HumanMessage | 用户输入 |
"assistant" | AIMessage | 模型输出 |
"tool" | ToolMessage | 工具返回结果 |
三、四种 Message 类型详解
3.1 SystemMessage — 角色定义
告诉模型行为并提供交互上下文,给模型定角色、提供背景。
SystemMessage(content="你是一个专业的 Python 翻译助手,只回答翻译结果")用途:
- 设置语调(正式/幽默/简洁)
- 定义模型角色(翻译助手/代码专家/数据分析师)
- 为 response 建立指导规则
- 给模型一个"性格"和"回答风格"
3.2 HumanMessage — 用户输入
代表用户 input 和 interaction,是用户与模型交互的开始。
HumanMessage(content="什么是装饰器?")多模态内容:HumanMessage 的 content 不仅可以是文本,还可以包含 audio、图片、files 等多模态内容。
HumanMessage 的字段:
| 字段 | 是否必填 | 类型 | 用途 |
|---|---|---|---|
content | 必填 | str 或 list | 消息内容(文本/图片/音频) |
name | 选填 | str | 多用户场景区分发言者 |
id | 选填 | str | 消息唯一标识,用于追踪/删除 |
Q:content、name、id 是规定好的还是自己创建的?
A:字段名是 LangChain 预定义的(不能改),值是你自己传的。类比 Java:就像一个 HumanMessage 类有三个属性,字段名是类定义好的,但属性值是你 new 的时候传的。
3.3 AIMessage — 模型输出
代表大语言模型返回的生成内容,包括信息、工具调用(tool_calls)和元数据等。
# 普通回答AIMessage(content="递归是一种函数调用自身的编程思想...")# 带工具调用的回答AIMessage(content="",tool_calls=[{"id":"call_001","name":"get_weather","args":{"city":"杭州"},}])Q:AIMessage 是动态的,下轮问答时需要先提取 content 再传进去吗?
A:不需要手动提取,直接把整个 AIMessage 对象追加到消息列表就行。
# ✅ 正确:直接追加 AIMessage 对象messages=[SystemMessage("你是助手"),HumanMessage("你好")]resp=llm.invoke(messages)messages.append(resp)# AIMessage 直接追加messages.append(HumanMessage("那明天呢?"))resp2=llm.invoke(messages)# 模型能看到完整多轮对话底层原理:模型 API 本身就接受
assistant角色的消息。在 Agent 中,这个"追加消息→调用模型→再追加"的循环是 Agent 框架自动做的,你不需要手写循环。
3.4 ToolMessage — 工具返回结果
Agent 可以使用工具调用,ToolMessage 用于把工具执行结果回传给模型。
ToolMessage(content="晴,25度",tool_call_id="call_001",# 必须与 AIMessage.tool_calls[i]["id"] 严格对应name="get_weather",)Q:ToolMessage 里的工具返回信息是放在 AIMessage 里面吗?
A:不是!ToolMessage 是独立的消息类型,和 AIMessage 是并列关系。
完整流程:
1. 模型返回 AIMessage(带 tool_calls) → "我想调用 get_weather(杭州)" 2. 你执行工具,得到结果 → "晴,25度" 3. 你把结果包成 ToolMessage 放回消息列表 → ToolMessage("晴,25度") 4. 再次调用模型,模型看到 ToolMessage → 生成最终回答
为什么 tool_call_id 必须对应?因为一次对话中模型可能同时调多个工具,模型靠 id 知道哪个 ToolMessage 对应哪个 tool_call:
AIMessage 的 tool_calls: ├── {id: "call_001", name: "get_weather", args: {city: "杭州"}} └── {id: "call_002", name: "get_time", args: {}} ToolMessage(tool_call_id="call_001", content="晴,25度") ← 对应 weather ToolMessage(tool_call_id="call_002", content="14:30") ← 对应 time四、多轮对话的消息流转
用户提问 模型回答 │ │ ▼ ▼ HumanMessage("你好") → AIMessage("你好!有什么帮你的?") │ │ └──── 都追加到 messages 列表 ────┘ │ ▼ HumanMessage("那明天呢?") → AIMessage("明天有什么需要帮忙的?") │ │ └──── 继续追加 ─────────────┘手动多轮对话(理解原理用,实际用 Agent 自动处理):
messages=[SystemMessage(content="你是助手")]forroundinrange(3):user_input=input("你:")messages.append(HumanMessage(user_input))resp=llm.invoke(messages)messages.append(resp)# AIMessage 直接追加print(f"AI:{resp.content}")五、三种传参格式对比
| 格式 | 代码 | 适合场景 |
|---|---|---|
| 字符串简写 | llm.invoke("你好") | 单次快速问答 |
| 消息对象列表 | [SystemMessage(...), HumanMessage(...)] | 多轮对话、需要附加 id/name、类型安全 |
| 字典格式 | [{"role": "user", "content": "..."}] | OpenAI 兼容最简洁、从 API 文档快速移植 |
选择建议:
- 学习/调试:消息对象列表(类型明确,IDE 补全好)
- 快速验证:字符串简写
- 生产环境:字典格式(简洁,易序列化)
六、总结
| 概念 | 一句话理解 |
|---|---|
| Message | 模型交互的输入输出单元,携带 role + content + metadata |
| SystemMessage | 角色定义,给模型设定背景和风格 |
| HumanMessage | 用户输入,可含多模态内容 |
| AIMessage | 模型输出,可带 tool_calls(工具调用意图) |
| ToolMessage | 工具返回结果,tool_call_id 必须与 AIMessage 对应 |
| 字符串简写 | 最简调用,自动包装为 HumanMessage |
| 消息对象列表 | 多轮对话标配,类型安全 |
| 字典格式 | OpenAI 兼容最简写,role 固定 4 值 |
| 多轮对话 | 把 AIMessage 直接追加回列表,模型即有"记忆" |
核心认知:Message 是模型交互的"信封",role 标识谁说的,content 是说的内容。四种 Message 类型对应对话中的四个角色,ToolMessage 是工具调用闭环的关键一环。