多轮对话 + 工具调用时,厂商 API 要求消息顺序与字段严格:assistant 声明 tool_calls 后必须跟对应 tool 角色结果,且 id 一一匹配。漏一条或顺序错乱,下一轮直接 400。Messages 类型把各 role 收成 Pydantic 对象,便于在 invoke 前校验与调试。
段末注释:BaseMessage = LangChain 对话单元的基类;Tool Calling = 模型通过结构化字段请求执行外部工具。
1. 一句话定位
| 维度 | 内容 |
|---|---|
| 角色 | 能力层对话数据结构:统一 role、content、tool 元数据 |
| 输入 → 输出 | 应用层组装 list[BaseMessage] → 传入 ChatModel |
| 典型调用入口 | HumanMessage(...)、AIMessage(tool_calls=...)、ToolMessage(...) |
| 与 LangGraph | 图 state 中 messages 常为 Annotated[list, add_messages];类型仍用本篇 |
2. 实现逻辑
带工具的一轮完整结构:
1 | 1. [SystemMessage, HumanMessage("查北京天气")] |
字段级变形:
1 | tool_calls[0].id = "call_abc" |
3. 原理说明
3.1 常见消息类型
均继承 langchain_core.messages.BaseMessage。content 可为 str 或多模态 list[block]。
BaseMessage(抽象数据类)
功能:对话轮次的统一载体。
数据结构公共字段:content(必填);additional_kwargs: dict = {};response_metadata: dict = {};id: str | None = None。
最小维度:至少 content(工具轮次 AI 可为 "")。
SystemMessage(数据类)
功能:系统指令,通常放列表首位。type="system"。
最小维度:content ≥1 字符才有语义。
HumanMessage(数据类)
功能:用户输入。type="human"。最小 1 条即可构成一次提问。
AIMessage(数据类)
功能:模型回复。type="ai"。
| 字段 | 类型 | 默认值 | 最小维度 |
|---|---|---|---|
content |
str / list | 必填 | 工具轮次可为 "" |
tool_calls |
list | [] |
0=纯文本;并行工具 ≥1 |
invalid_tool_calls |
list | [] |
解析失败时非空 |
ToolMessage(数据类)
功能:把工具执行结果回填给模型。type="tool"。
| 字段 | 类型 | 默认值 | 最小维度 |
|---|---|---|---|
content |
str | 必填 | 建议非空;异常时可写错误文本 |
tool_call_id |
str | 必填 | 非空,必须等于对应 tool_calls[].id |
name |
str / None | None |
可选 |
1 | ToolMessage(content="晴,18°C", tool_call_id=ai.tool_calls[0]["id"]) |
3.2 tool_calls 结构
AIMessage.tool_calls(字段,list[dict])
功能:模型发起的工具调用。与 OpenAI tool_calls 对齐。
| 键 | 类型 | 默认值 | 最小维度 |
|---|---|---|---|
name |
str | 必填 | 非空,须为已 bind 的工具名 |
args |
dict | 必填 | 无参工具 {};键名对齐 schema |
id |
str | 必填 | 非空;回填 ToolMessage 必须相同 |
type |
str | "tool_call" |
— |
最小一次调用 = {name, args, id} 三键。执行后必须用 相同 id 回填。
1 | call = ai.tool_calls[0] |
3.3 多 tool 并行
一条 AIMessage 可含 len(tool_calls) ≥ 2。对应 等量 ToolMessage(id 各自匹配),再一次性 invoke(history + [ai, *tool_msgs])。
最小并行:2 条 tool_calls + 2 条 ToolMessage。
3.4 与 dict 互转
message_to_dict(message)(函数)
功能:Message → 可 JSON 序列化的 dict。无默认参数。最小输入:1 条 BaseMessage。
messages_from_dict(dicts)(函数)
功能:list[dict] → list[BaseMessage]。
最小维度:dicts len≥1(空列表返回 []);每项须含 type 与 data。
1 | from langchain_core.messages import message_to_dict, messages_from_dict |
生产仍推荐 typed Message,减少字段拼写错误。
4. 最小可运行示例
1 | pip install -U langchain-openai |
1 | from langchain_openai import ChatOpenAI |
重要配置参数
| 参数(API 名) | 类型 / 默认值 | 功能说明 | 作用与影响 | 参考起点 | 配置指导 |
|---|---|---|---|---|---|
content |
str / list,必填 | 本轮对模型可见的正文或多模态块 | 工具轮次 ai.content 可为空;过长费 token | 纯文本 | 引用资料时只塞需要的片段 |
tool_calls |
list,AIMessage,默认 [] |
模型发起的待执行工具调用列表 | 非空则必须回填等量 ToolMessage | 含 id/name/args | args 须可 JSON 序列化 |
tool_call_id |
str,ToolMessage 必填 | 把工具结果绑回哪一次 tool_call | 不一致则厂商 API 拒绝整轮 | 与 tool_calls[].id 相同 |
从 ai.tool_calls[i]["id"] 原样拷 |
name |
str,ToolMessage 可选 | 标明这条结果来自哪个工具 | 便于日志;部分厂商可选 | 与 tool_calls[].name 一致 |
调试时建议填 |
additional_kwargs |
dict,默认 {} |
厂商扩展字段容器 | 业务代码少写;集成包内部用 | 少用 | 不要塞业务 payload |
id |
str,消息级可选 | 单条消息的唯一标识 | 持久化/去重用;缺省由框架生成 | 可选 | 存库时建议设 |
5. 易踩坑
- ToolMessage 缺 tool_call_id 或 id 不匹配:OpenAI/Anthropic 均报错,且错误信息有时只提 “tool”。
- 在 tool 结果未齐时就 invoke:多个 tool_calls 只回填一个 ToolMessage,上下文非法。
- 把 ToolMessage 放在 AIMessage 之前:顺序须保持 user → assistant(tool_calls) → tool(s) → assistant。
小结
- 对话在 LangChain 里是
list[BaseMessage],工具场景扩展 AIMessage.tool_calls + ToolMessage。 - tool_call_id 是工具链最容易错的一字段。
- System 通常首位;多 tool 须 全部回填 再继续 model。
- 持久化可用 dict 互转,运行时优先 typed Message。