同一段「用户问天气」可以是 str、{"role":"user"} 或 HumanMessage。混用到工具轮次时,漏 tool_call_id 或把流式 AIMessageChunk 当完整 AIMessage 再 invoke,厂商 API 直接 400。LangChain 用 langchain_core.messages 把角色收成带 type 判别器的对象;下游(ChatModel、Parser、工具循环、图状态)按 类 而不是按字符串猜测。
段末注释:BaseMessage = 对话单元基类;MessageChunk = 流式增量,可用
+合并成完整消息。
社区方案:只用官方 langchain_core.messages 类型(Messages 概念)。不要自造 role dict 长期跑生产。风险:FunctionMessage / ChatMessage 仍可 import,但新工具协议与多数 partner 包已不保证。

1. 一句话定位
| 维度 | 内容 |
|---|---|
| 角色 | 能力层 对话类型系统:角色、字段、序列化判别器 |
| 输入 → 输出 | 构造 BaseMessage 子类 → ChatModel.invoke 吃 list[BaseMessage],吐 AIMessage |
| 典型调用入口 | HumanMessage / AIMessage / ToolMessage;stream 得 AIMessageChunk |
| 与 LangGraph | 图 state 的 messages 仍是这些类;RemoveMessage 只给 reducer,不给模型 |
2. 实现逻辑
一次调用里类型怎么分流:
1 | 1. 应用组装 list[BaseMessage](或 str → 内部包成 HumanMessage) |
字段级变形:
1 | str "北京天气?" → HumanMessage(type="human") |
3. 原理说明
3.1 类型总表
AnyMessage 是带 type 判别器的联合类型,反序列化靠它。运行时你真正 new 的是下表各类。
| 类 | type |
进 ChatModel.invoke | 谁产出 | 新代码是否用 |
|---|---|---|---|---|
SystemMessage |
system |
是,通常首位 | 应用 | 是 |
HumanMessage |
human |
是;invoke(str) 的落点 |
用户/应用 | 是 |
AIMessage |
ai |
是(作为历史) | 模型,或手写历史 | 是 |
ToolMessage |
tool |
是,须紧跟对应 AI(tool_calls) | 应用执行工具后 | 是 |
FunctionMessage |
function |
旧 function calling | 旧工具循环 | 否,改 ToolMessage |
ChatMessage |
chat |
视集成;需自带 role |
应用 | 仅非标准角色 |
AIMessageChunk 等 |
AIMessageChunk 等 |
应先 + 合并 |
stream / astream |
流式 UI |
RemoveMessage |
remove |
否 | 应用 | 仅图状态删除 |
BaseMessage(抽象数据类)
功能:所有消息的公共载体。
默认值:additional_kwargs={}、response_metadata={}、name=None、id=None。
最小维度:子类必须带 content(RemoveMessage 强制 "")。
| 字段 | 类型 | 默认值 | 最小维度 |
|---|---|---|---|
content |
str / list | 必填 | 文本 ≥0 字符;多模态为 list len≥1 |
type |
str | 子类 Literal | 序列化判别器,勿手改 |
name |
str / None | None |
可选;Human 标识用户、Tool 标识工具 |
id |
str / None | None |
Remove 必填;其余建议有 |
additional_kwargs |
dict | {} |
厂商扩展,业务少写 |
response_metadata |
dict | {} |
模型名、logprobs 等 |
1 | from langchain_core.messages import HumanMessage |
3.2 对话角色类(数据差)
SystemMessage(数据类)
功能:系统指令,给模型定角色与约束。
数据结构:公共字段 + type="system"。无 tool_calls。
最小维度:content ≥1 字符才有语义。多数厂商允许 0~1 条;多条时有的合并、有的只认第一条。
1 | from langchain_core.messages import SystemMessage |
HumanMessage(数据类)
功能:用户输入,可含多模态 content 块。
最小维度:一次提问至少 1 条;invoke("hi") 等价 invoke([HumanMessage("hi")])。name 用于区分多用户,厂商可能忽略。
1 | from langchain_core.messages import HumanMessage |
AIMessage(数据类)
功能:模型输出(也可手写进历史当「模型说过」)。唯一带 tool_calls / usage_metadata 的常用类型。
| 字段 | 类型 | 默认值 | 最小维度 |
|---|---|---|---|
content |
str / list | 必填 | 纯工具轮次可为 "" / [] |
tool_calls |
list | [] |
0=纯文本;≥1 必须回填 ToolMessage |
invalid_tool_calls |
list | [] |
schema 解析失败时非空 |
usage_metadata |
dict / None | None |
有则含 input/output/total_tokens |
1 | from langchain_core.messages import AIMessage |
ToolMessage(数据类)
功能:把一次工具执行结果回填给模型。type="tool"。
| 字段 | 类型 | 默认值 | 最小维度 |
|---|---|---|---|
content |
str | 必填 | 建议非空;失败写错误文本 |
tool_call_id |
str | 必填 | 非空,等于对应 tool_calls[].id |
name |
str / None | None |
建议填工具名 |
artifact |
Any / None | None |
不发给模型,给应用下游(如 doc_id) |
status |
str,视版本 | 成功态 | "error" 时仍要带 id |
1 | from langchain_core.messages import ToolMessage |
FunctionMessage(数据类,legacy)
功能:旧 OpenAI function calling(role=function)。有 name,没有 tool_call_id。
最小维度:content + name 均必填。新代码一律 ToolMessage。
1 | from langchain_core.messages import FunctionMessage |
ChatMessage(数据类)
功能:任意 role: str 的通用消息。type="chat"。
最小维度:role 非空 + content。多数 ChatOpenAI / Anthropic 集成只认标准四角色,自定义 role 可能被丢或 400。
1 | from langchain_core.messages import ChatMessage |
3.3 Chunk 与 RemoveMessage
AIMessageChunk / HumanMessageChunk / SystemMessageChunk / ToolMessageChunk / ChatMessageChunk / FunctionMessageChunk(数据类)
功能:对应完整类型的流式切片。字段与父类同形,content 常为短 str。
默认值:空 content="" 的心跳 chunk 可能出现。
最小维度:一次 stream 至少 1 个 chunk。合并:full = c1 if full is None else full + c。
1 | full = None |
RemoveMessage(数据类)
功能:声明「删掉 id 等于某值的消息」。type="remove"。
数据结构:id: str 必填;content 强制 "",传入非空会 ValueError。
最小维度:仅 id。下游是 LangGraph add_messages reducer,不是 Chat Completions。
1 | from langchain_core.messages import RemoveMessage |
3.4 下游调用区别
同一 list 里类型不同,下游走不同分支。
| 下游 | 认哪些类型 | 数据怎么用 | 用错会怎样 |
|---|---|---|---|
ChatModel.invoke |
System / Human / AI / Tool(+ 少数 Chat) | 映射为厂商 role;Anthropic 常把 System 抽到 顶层 system=,messages 里只留 user/assistant/tool |
Tool 缺 id → 400;Remove/未合并 Chunk → 非法 payload |
ChatModel.invoke(str) |
无显式类型 | 内部 只 包成 1 条 HumanMessage,没有 System | 需要系统指令时必须走 list |
bind_tools 后再 invoke |
同上 + 返回 AIMessage.tool_calls | 有 tool_calls 时下游应执行工具,不要当最终答案 | 把 AI 当终态会丢掉工具 |
model.stream / astream |
产出 AIMessageChunk |
逐块 content;应用层 + 合并 |
把单个 Chunk 当完整 AI 再回填会丢 tool_calls 后半段 |
StrOutputParser |
AIMessage / Chunk | 取 content;list block 则拼文本 |
喂 ToolMessage 得到工具原文,不是模型总结 |
JsonOutputParser |
AIMessage(完整 content) | json.loads(content) |
Chunk 半包 JSON 必炸 |
| 工具循环 / ToolNode | 读最后一条 AIMessage.tool_calls,写出 ToolMessage | 一条 tool_call 对应一条 ToolMessage | FunctionMessage 顶替 ToolMessage:新 OpenAI 兼容端拒收 |
| MessageHistory.add_message | 任意 BaseMessage | 原样追加 | 不存 Tool 则下轮工具上下文断裂 |
LangGraph add_messages |
含 RemoveMessage | Remove 按 id 删除,其余 append/去重 | 把 Remove 塞进 ChatModel.invoke 无对应 role |
厂商 role 对照(对话类):
| LangChain 类 | OpenAI role |
Anthropic | 备注 |
|---|---|---|---|
| SystemMessage | system |
常升格为请求级 system |
不要插在对话中间当「旁白」 |
| HumanMessage | user |
user |
多模态主要挂这里 |
| AIMessage | assistant |
assistant |
唯一合法的模型回复容器 |
| ToolMessage | tool |
tool |
必须带 tool_call_id |
| FunctionMessage | function |
基本不支持 | 旧协议 |
| ChatMessage | 你写的 role |
不保证 | 避免 |
合法顺序(工具轮):[System?, Human, AI(tool_calls), Tool×N, (Human\|AI)...]。Tool 不得出现在对应 AI 之前。
4. 最小可运行示例
验证于 langchain-core + 本地 Ollama。需 ollama serve 且已 ollama pull qwen3.5:9b。异步:await model.ainvoke(msgs),参数与同步一致。
1 | pip install -U langchain-core langchain-openai |
1 | from langchain_openai import ChatOpenAI |
RemoveMessage / FunctionMessage 不要塞进上面的 model.invoke。生产异步用 astream,chunk 类型相同。
重要配置参数
| 参数(API 名) | 类型 / 默认值 | 功能说明 | 作用与影响 | 参考起点 | 配置指导 |
|---|---|---|---|---|---|
content |
str / list,必填 | 发给模型或展示给用户的载荷 | 过长费 token;工具轮 AI 可空 | 纯 str | 多模态用 list block |
type |
str,子类固定 | 序列化判别器,决定反序列化成哪一类 | 手改会导致 messages_from_dict 失败 |
勿赋值 | 靠选对类 |
tool_calls |
list,仅 AIMessage,默认 [] |
模型发起的工具调用 | 非空则下游必须回填 ToolMessage | name/args/id | 不要写到 Human/System 上 |
tool_call_id |
str,仅 ToolMessage,必填 | 把结果绑回哪一次 tool_call | 错/缺 → 厂商 400 | 与 tool_calls[].id 相同 |
原样拷贝 |
artifact |
Any,ToolMessage,默认 None | 给应用的旁路数据,不进模型上下文 | 可放 doc_id 而不涨 prompt | 检索工具 | 模型可见的只放 content |
name |
str / None | Human 标用户;Tool/Function 标工具名 | Function 上必填;Human 上视厂商 | 可选 | 新工具链优先 ToolMessage.name |
role |
str,仅 ChatMessage | 自定义厂商角色名 | 非标准值多数集成不映射 | 避免 | 能用专用类就不用 ChatMessage |
id |
str / None | 消息主键;RemoveMessage 用它指定删除目标 | 无 id 则图上无法 Remove | 持久化时设 | 模型返回的 id 请保留 |
5. 易踩坑
FunctionMessage冒充ToolMessage:新 OpenAI 兼容端(含 Ollama/v1)要role=tool+tool_call_id。- 未合并的
AIMessageChunk再invoke:后半段tool_calls可能还在后续 chunk 里。 RemoveMessage丢进 ChatModel:没有role=remove;只给add_messages这类 reducer。invoke("问句")以为能带 System:字符串捷径只有 Human,系统指令必须显式SystemMessage。
小结
- 对话类四件套:System / Human / AI / Tool;新代码不要
FunctionMessage。 - 数据差在独有字段:
tool_calls、tool_call_id、artifact、role、Remove 的强制空content。 - 下游差:ChatModel 映射 role;stream 出 Chunk;Parser 吃 AI content;图 reducer 才吃 Remove。
- 最易踩:id 对不上、Chunk 当完整消息、Remove 发给模型。