这篇适合谁,读完能做到什么
适合已经会用 LangChain 的聊天模型、想弄清消息对象怎么组织的开发者。读完你应该能分清 System、Human、AI、Tool 四种消息,知道什么时候用字符串、什么时候用消息列表,能把图片输入写成内容块,并会把流式输出拼成完整消息,把对话历史存下来再恢复。
消息是什么
消息是 LangChain 里模型上下文的基本单位。模型的输入和输出都是消息,每条消息包含三部分:角色(role)、内容(content)和可选的元数据,元数据包括响应信息、消息 ID 和 token 用量[1]。LangChain 提供了一套标准的消息类型,在各家模型上行为一致[1]。
字符串还是消息列表
只发一个独立的请求、不需要保留上下文时,用字符串就够了。字符串适合最简单的生成任务[1]。
需要多轮对话、传入多模态内容或者设定系统指令时,就用消息列表,列表里放的是消息对象[1]。消息也可以直接用 OpenAI chat completions 的格式,以字典的形式写[1]。下面是一个带系统指令的例子:
from langchain.messages import SystemMessage, HumanMessage, AIMessage
messages = [
SystemMessage("You are a poetry expert"),
HumanMessage("Write a haiku about spring"),
AIMessage("Cherry blossoms bloom...")
]
response = model.invoke(messages)invoke() 收到一个字符串时,等于只包了一条 HumanMessage[1]。
四种消息各做什么
SystemMessage 是模型的初始指令,用来定下语气、角色和回答的准则[1]。
HumanMessage 代表用户的输入,可以包含文本、图片、音频、文件等多模态内容[1]。它还有一个 name 字段,但各家厂商的处理不同:有的用它区分用户,有的直接忽略。要确认的话,查对应厂商的参考文档[1]。
AIMessage 是一次模型调用的输出,里面可以带多模态数据、工具调用和厂商特有的元数据[1]。它的常用字段包括 text、content、content_blocks、tool_calls、id、usage_metadata 和 response_metadata[1]。厂商返回了 token 数时,这些数字会放在 usage_metadata 里[1]。
有时需要手工构造一个 AIMessage 插入历史,比如把之前的回答补进对话里。因为不同厂商对消息类型的权重理解不同,这样做有时会有帮助[1]。
ToolMessage 把单次工具执行的结果交回模型。它的 tool_call_id 必须和 AIMessage 里对应工具调用的 ID 一致[1]。ToolMessage 还有一个 artifact 字段,放的是不发给模型、只供程序读取的数据,比如原始结果或调试信息[1]。
工具调用在消息里怎么体现
模型发起工具调用时,调用会出现在 AIMessage 的 tool_calls 里,每个调用都有名称、参数和 ID[1]。读取方式如下:
for tool_call in response.tool_calls:
print(f"Tool: {tool_call['name']}")
print(f"Args: {tool_call['args']}")
print(f"ID: {tool_call['id']}")流式输出怎么拼成一条消息
流式输出时,模型逐个返回 AIMessageChunk。这些块可以加在一起,还原成完整的消息对象[1]。下面的代码把每个块收集起来,并用 + 拼接:
chunks = []
full_message = None
for chunk in model.stream("Hi"):
chunks.append(chunk)
print(chunk.text)
full_message = chunk if full_message is None else full_message + chunk内容块与多模态输入
content 可以是字符串,也可以是厂商原生格式的内容块列表,或者 LangChain 标准的内容块列表[1]。content_blocks 属性会把 content 惰性地解析成一种标准、有类型的表示,在各家厂商之间通用[1]。
初始化消息时指定 content_blocks,content 同样会被填充,但接口是有类型的,写起来更安全[1]:
human_message = HumanMessage(content_blocks=[
{"type": "text", "text": "Hello, how are you?"},
{"type": "image", "url": "https://example.com/image.jpg"},
])图片输入可以来自 URL,也可以是带 mime_type 的 base64 数据,或者是厂商托管的文件 ID[1]。下面是 URL 形式的图片消息:
message = {
"role": "user",
"content": [
{"type": "text", "text": "Describe the content of this image."},
{"type": "image", "url": "https://example.com/path/to/image.jpg"},
]
}内容块的顶层可以加额外的键,也可以放进 extras 里。有的厂商需要额外字段,例如 OpenAI 处理 PDF 时需要文件名[1]。
如果希望在 LangChain 之外的应用里直接读取标准内容块,可以在聊天模型上设置 output_version="v1",或者把环境变量 LC_OUTPUT_VERSION 设为 v1,这样标准内容块会保存在消息内容里[1]。
对话历史怎么保存和恢复
消息可以序列化成普通对象存起来,再反序列化回消息实例,适合持久化对话历史、下次接着聊[1]。但要注意,load() 会实例化 Python 对象,反序列化时可能产生副作用,所以绝不要对来自不可信或未经认证来源的数据调用它[1]。
限制与常见问题
- 聊天模型的交互通常是无状态的,每次调用都要把需要的消息一起传进去[1]。
- 多轮智能体会积累很长的消息历史。LangSmith 会记录每一轮、每个工具结果和每次模型响应,方便回看完整对话[1]。
- 同一个
name字段在不同厂商上效果不同,跨厂商使用前要先查清楚[1]。
下一步
想了解每个厂商的消息细节,可以查看对应集成的参考文档[1]。
本文改编自 LangChain 官方文档中的「Messages」页面[1],原文以 MIT 许可证发布。
来源
- 1MessagesLangChain docs (MIT)
引用本页: LangChain 消息类型. TellWorld, https://www.tellworld.net/zh/practice/practice-langchain-messages. 更新于 2026-11-14