TellWorldAI 世界档案
问档案English

首页›实践›实践

实践

LangChain 消息类型

讲清 LangChain 的消息对象:System、Human、AI、Tool 四种消息各做什么,内容块和多模态输入怎么写,流式输出怎么拼接,以及对话历史怎么保存和恢复。

这篇适合谁,读完能做到什么

适合已经会用 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 许可证发布。

来源

  1. 1
    MessagesLangChain docs (MIT)

引用本页: LangChain 消息类型. TellWorld, https://www.tellworld.net/zh/practice/practice-langchain-messages. 更新于 2026-11-14

相关动态