现在位置: 首页 > LangChain 教程 > 正文

LangChain Messages API 参考

在 LangChain 中,无论是普通聊天、Agent 工具调用、多轮对话,还是图片、音频等多模态输入,都离不开 Messages(消息)。

Messages 是 LangChain 与聊天模型交互的基础数据结构,用于区分系统指令、用户输入、AI 回复和工具执行结果。

例如:

SystemMessage → 告诉模型应该如何回答
HumanMessage  → 用户提出问题
AIMessage     → 模型生成回答或工具调用
ToolMessage   → 工具返回执行结果

本章节基于 LangChain 1.x,整理常用消息类型、ContentBlock 多模态结构、ToolCall、消息转换、历史裁剪以及在 Agent 中的实际用法。


一、LangChain 消息类型速查

LangChain 的消息对象通常继承自 BaseMessage。

常用消息如下:

消息类型对应角色type 属性主要用途
HumanMessageuserhuman用户输入
AIMessageassistantai模型回复及工具调用请求
SystemMessagesystemsystem系统指令
ToolMessagetooltool工具执行结果
AIMessageChunkassistantAIMessageChunk模型流式输出片段
RemoveMessage无普通对话角色remove请求删除状态中的消息
ChatMessage自定义角色chat自定义消息角色

这里需要区分两个概念:

  • role:模型 API 通常使用的角色,例如 user、assistant、system、tool。
  • type:LangChain 消息对象自身的类型标识,例如 human、ai、tool。

因此,HumanMessage 的 type 是 human,而不等于模型 API 中的 user。

另外,AIMessageChunk 虽然代表助手的流式回复,但其 Python 对象的 type 是 AIMessageChunk。


二、创建基本消息

可以从 langchain.messages 导入常见消息类。

实例:创建消息对象

实例

from langchain.messages import (
    SystemMessage,
    HumanMessage,
    AIMessage,
    ToolMessage
)

system = SystemMessage(content="你是 Python 编程助手。")
human = HumanMessage(content="什么是 Python?")
ai = AIMessage(content="Python 是一种通用编程语言。")

tool = ToolMessage(
    content="计算结果:42",
    tool_call_id="call_001",
    name="calculator"
)

for message in [system, human, ai, tool]:
    print(message.type, message.content)

输出:

system 你是 Python 编程助手。
human 什么是 Python?
ai Python 是一种通用编程语言。
tool 计算结果:42

注意,这里的 ToolMessage 是一个单独创建的示例对象。

真正发送给模型时,ToolMessage 应当与此前 AIMessage 中对应的工具调用请求配对,不能随意插入一个没有上下文的工具结果。


三、消息对象的常用属性

BaseMessage 提供了一些通用属性。

属性说明
content消息原始内容,可以是字符串或内容块列表
content_blocks标准化后的多模态 ContentBlock 列表
typeLangChain 消息类型
id消息 ID,可能为空
name可选的消息名称
additional_kwargs服务商相关的额外数据
response_metadata响应元数据,例如模型名称或其他统计信息

实例:读取消息属性

实例

from langchain.messages import HumanMessage

message = HumanMessage(
    content="介绍 Python 列表。",
    id="user-msg-001",
    name="student"
)

print("类型:", message.type)
print("内容:", message.content)
print("消息 ID:", message.id)
print("名称:", message.name)
print("标准内容块:", message.content_blocks)

如果 content 是普通字符串,LangChain 也可以将其表示为标准文本内容块。

注意:消息 ID 不一定由模型服务商返回。实际需要稳定标识时,可以在应用层为消息分配 ID。


四、HumanMessage:用户消息

HumanMessage 用于表示用户输入。

既可以包含普通文字,也可以在模型支持的情况下包含图片、文件等多模态内容。

实例:普通用户消息

实例

from langchain.messages import HumanMessage

message = HumanMessage(content="Python 字典是什么?")

print(message.type)
print(message.content)

输出:

human
Python 字典是什么?

在调用 Chat Model 或 Agent 时,通常不需要手动创建 HumanMessage,也可以直接使用 role 字典。


五、SystemMessage:系统指令

SystemMessage 用于向模型提供角色设定、行为规则和其他高优先级指令。

实例

实例

from langchain.messages import SystemMessage, HumanMessage

messages = [
    SystemMessage(content="你是编程老师,请使用简洁中文回答。"),
    HumanMessage(content="解释 Python 循环语句。")
]

消息通常按照对话顺序排列。

如果使用 create_agent(),更常见的方式是通过 system_prompt 设置系统指令。

agent = create_agent(
    model="deepseek:deepseek-chat",
    tools=[],
    system_prompt="你是 Python 编程老师。"
)

不建议把不可信文档内容直接转换为 SystemMessage,因为这会提高外部数据在提示词中的权限。


六、AIMessage:模型回复

AIMessage 表示模型生成的响应。

除了文字,还可能包含工具调用、Token 使用量和模型元数据。

主要属性

属性作用
content模型内容
tool_calls有效工具调用列表
invalid_tool_calls无法正常解析的工具调用
usage_metadataToken 使用量
response_metadata模型响应元数据
id消息标识

实例:查看 AIMessage

实例

from dotenv import load_dotenv
from langchain.chat_models import init_chat_model

load_dotenv()

model = init_chat_model("deepseek:deepseek-chat")
response = model.invoke("你好")

print("回答:", response.content)
print("类型:", response.type)
print("工具调用:", response.tool_calls)
print("Token 使用量:", response.usage_metadata)
print("响应元数据:", response.response_metadata)

如果服务商返回 Token 数据,usage_metadata 可能包含:

{
    "input_tokens": 12,
    "output_tokens": 20,
    "total_tokens": 32
}

这里是示例格式,并非真实调用结果。

不同提供商对 Token 用量、额外元数据和内容块的支持可能有所不同。


七、ToolCall:模型请求调用工具

ToolCall 用于表示模型希望调用某个工具。

通常可以通过:

AIMessage.tool_calls

读取。

一个工具调用常见的字段包括:

字段说明
name工具名称
args工具参数字典
id工具调用 ID
type工具调用类型标识

实例:创建工具调用消息

实例

from langchain.messages import AIMessage

ai = AIMessage(
    content="",
    tool_calls=[
        {
            "name": "get_weather",
            "args": {"city": "杭州"},
            "id": "call_weather_001",
            "type": "tool_call"
        }
    ]
)

for call in ai.tool_calls:
    print("工具:", call["name"])
    print("参数:", call["args"])
    print("调用 ID:", call["id"])

重要:创建 AIMessage.tool_calls 不会自动执行工具。

如果直接使用 Chat Model,需要应用程序执行工具,再将结果作为 ToolMessage 返回给模型。

而使用 create_agent() 时,LangChain 可以自动管理常见的工具调用循环。


八、ToolMessage:工具执行结果

ToolMessage 用于表示工具执行后返回的结果。

其中最重要的属性是:

tool_call_id

它必须对应先前 AIMessage 中某个 ToolCall 的 ID。

常用属性

属性说明
content提供给模型的工具结果
tool_call_id对应的工具调用 ID
name工具名称,可选
status执行状态,如 success、error
artifact不必直接发送给模型的附加数据

实例:工具请求和结果配对

实例

from langchain.messages import AIMessage, ToolMessage

ai = AIMessage(
    content="",
    tool_calls=[{
        "name": "get_weather",
        "args": {"city": "杭州"},
        "id": "call_001",
        "type": "tool_call"
    }]
)

tool_result = ToolMessage(
    content="杭州模拟天气:晴,25°C",
    tool_call_id="call_001",
    name="get_weather",
    status="success"
)

messages = [ai, tool_result]

print(ai.tool_calls[0]["id"])
print(tool_result.tool_call_id)

两个 ID 必须一致:

call_001
call_001

如果模型一次提出多个工具调用,就需要根据提供商的协议为每个调用提供正确的工具响应。

不要在一个尚未响应完所有工具调用的消息序列中,随意插入无关用户消息。


九、完整工具调用消息序列

下面展示一次有效的模型工具调用交互。

HumanMessage
    ↓
AIMessage(tool_calls)
    ↓
ToolMessage
    ↓
AIMessage(最终回答)

实例:手动执行工具

完整实例

from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage, ToolMessage
from langchain.tools import tool

load_dotenv()

@tool
def get_weather(city: str) -> str:
    """查询城市模拟天气。"""
    return f"{city}:模拟晴,25°C"

model = init_chat_model("deepseek:deepseek-chat")
model_with_tools = model.bind_tools([get_weather])

messages = [HumanMessage(content="请用工具查询杭州的模拟天气。")]

ai = model_with_tools.invoke(messages)
messages.append(ai)

for call in ai.tool_calls:
    if call["name"] == "get_weather":
        result = get_weather.invoke(call["args"])
        messages.append(ToolMessage(
            content=result,
            tool_call_id=call["id"],
            name="get_weather"
        ))

if ai.tool_calls:
    final = model_with_tools.invoke(messages)
    print("最终回答:", final.content)
else:
    print("模型未请求工具:", ai.content)

这里演示了工具调用的三个关键步骤:

  1. 模型生成包含 tool_calls 的 AIMessage。
  2. 应用根据调用参数执行工具,并返回对应的 ToolMessage。
  3. 将工具执行结果放回消息历史,再调用模型生成回答。

这个示例只处理一轮工具调用。如果模型再次返回 tool_calls,还需要继续执行循环。

生产环境建议使用 create_agent() 管理工具循环、执行次数限制和异常处理。


十、AIMessageChunk:流式消息

调用模型的 stream() 方法时,通常会逐步返回 AIMessageChunk。

它表示模型输出的一个增量片段。

例如:

Chunk 1:Python
Chunk 2: 是一种
Chunk 3: 编程语言。

实际 Chunk 不一定与单个 Token 一一对应。

实例:读取流式消息

实例

from langchain.chat_models import init_chat_model

model = init_chat_model("deepseek:deepseek-chat")

for chunk in model.stream("简单介绍 Python。"):
    if isinstance(chunk.content, str):
        print(chunk.content, end="", flush=True)

print()

AIMessageChunk 可以具有以下字段:

  • content:文本或其他内容增量。
  • tool_call_chunks:工具调用参数的流式片段。
  • usage_metadata:可用时的 Token 信息。
  • chunk_position:某些流中的片段位置标记。

需要注意,AIMessageChunk 的 type 通常是:

AIMessageChunk

并非 AIMessage 的 ai。


十一、合并流式消息 Chunk

如果不仅希望逐步打印文本,还想获得完整消息对象,可以将多个 AIMessageChunk 合并。

实例:合并消息增量

实例

from langchain.messages import AIMessageChunk

chunks = [
    AIMessageChunk(content="Python"),
    AIMessageChunk(content=" 是一种"),
    AIMessageChunk(content=" 编程语言。")
]

merged = chunks[0]

for chunk in chunks[1:]:
    merged = merged + chunk

print(merged.content)

输出:

Python 是一种 编程语言。

这里使用 + 合并消息片段。

实际流式工具调用中,工具名称和参数也可能分批返回,需要按照 LangChain 的 Chunk 合并规则进行处理,而不是直接把所有工具参数片段当成完整 JSON。


十二、ContentBlock:标准化多模态内容

LangChain 1.x 提供了标准化的 ContentBlock 结构,用于描述文本、图片、音频、视频和文件等不同内容。

模型消息不一定只有一个字符串,还可能包含多个内容块。

例如:

HumanMessage
    |
    ├── TextContentBlock
    └── ImageContentBlock

常见 ContentBlock 类型:

类型type 标识用途
TextContentBlocktext普通消息文本
PlainTextContentBlocktext-plainTXT、Markdown 等纯文本文件数据
ImageContentBlockimage图片
AudioContentBlockaudio音频
VideoContentBlockvideo视频
FileContentBlockfilePDF、Word 等文件数据
ReasoningContentBlockreasoning模型接口公开返回的推理相关内容
NonStandardContentBlocknon_standard未标准化的服务商专用内容

此外,还有 ToolCall、ServerToolCall、ServerToolResult 等与工具调用相关的标准结构。

注意:ContentBlock 是统一的数据表示格式,并不代表所有模型都支持所有模态。是否可以发送图片、音频、PDF 或视频,仍需检查具体模型和提供商集成。


十三、TextContentBlock 与 PlainTextContentBlock 的区别

这两个名字比较相似,但用途不同。

TextContentBlock

表示普通消息正文,例如:

{
    "type": "text",
    "text": "请解释 Python 列表"
}

PlainTextContentBlock

用于表示纯文本文件数据,例如 Markdown、TXT 文件内容。

{
    "type": "text-plain",
    "mime_type": "text/plain",
    "text": "# Python 教程\n变量用于保存数据"
}

一般聊天使用普通字符串或 TextContentBlock 就足够了,不必把每段普通文字都封装成 PlainTextContentBlock。

实例:创建标准文本内容块

实例

from langchain.messages import HumanMessage
from langchain_core.messages.content import create_text_block

message = HumanMessage(
    content=[create_text_block("什么是 Python?")]
)

print(message.content_blocks)

create_text_block() 可以自动创建符合标准格式的文本内容块。


十四、图片输入 ImageContentBlock

如果使用支持图片理解的模型,可以在 HumanMessage 中添加图片内容块。

例如:

实例:图片消息结构

from langchain.messages import HumanMessage
from langchain_core.messages.content import create_text_block, create_image_block

message = HumanMessage(content=[
    create_text_block("请描述这张图片。"),
    create_image_block(
        url="https://example.com/sample.png",
        mime_type="image/png"
    )
])

for block in message.content_blocks:
    print(block["type"])

输出:

text
image

这里的 URL 仅用于演示数据结构,不保证存在对应图片。

图片内容可以根据模型接口要求使用 URL、Base64 数据或其他受支持的文件引用方式。

注意:使用 deepseek-chat 等聊天模型时,不应假定其支持图片输入。需要选择明确支持视觉能力的模型。


十五、音频、视频与文件内容块

标准化 ContentBlock 还覆盖以下类型:

内容类型常见数据形式应用场景
AudioContentBlock音频数据、文件引用等语音转写、语音理解
VideoContentBlock视频数据或帧信息视频内容分析
FileContentBlockURL、Base64、文件 IDPDF 和其他文档输入
PlainTextContentBlock文本内容或文件引用TXT、Markdown 文档

对于不属于图片、音频或普通文本的文件,可以使用 FileContentBlock 表示。

但文件输入功能在不同模型间差异较大。

例如,某些模型支持直接读取 PDF;另一些模型则需要开发者先用 Document Loader 提取文本,再将文本放入消息中。

因此,不能只因为 LangChain 支持 FileContentBlock,就认为任意聊天模型都能直接分析 PDF。


十六、content 与 content_blocks

在 LangChain 消息对象中,两个字段容易混淆:

属性用途
content消息的原始或服务商相关内容表示
content_blocksLangChain 标准化后的内容块

例如:

实例

from langchain.messages import AIMessage

message = AIMessage(content="你好,我是 Python 助手。")

print("原始内容:", message.content)
print("标准内容块:", message.content_blocks)

如果只是显示普通文本,通常直接读取 content 即可。

如果需要统一处理来自不同服务商的多模态数据,可以考虑使用 content_blocks。

注意:不要假设所有 content 都是字符串。多模态模型可能返回内容块列表。


十七、RemoveMessage:删除消息

RemoveMessage 用于在支持消息删除的状态管理中移除指定消息。

它并不是普通用户聊天消息。

例如,LangGraph 的 messages 状态字段通常使用 add_messages Reducer。

如果需要删除某条已有消息,可以返回对应的 RemoveMessage。

实例:删除指定消息

实例

from langchain.messages import HumanMessage, AIMessage, RemoveMessage
from langgraph.graph.message import add_messages

messages = [
    HumanMessage(content="旧问题", id="msg-001"),
    AIMessage(content="旧回答", id="msg-002")
]

updated = add_messages(
    messages,
    [RemoveMessage(id="msg-001")]
)

for msg in updated:
    print(msg.id, msg.content)

输出:

msg-002 旧回答

这里是通过 add_messages Reducer 删除消息,而不是通过普通 Python 列表自动实现删除。

注意:RemoveMessage 应与支持该语义的 Reducer 配合使用。对于不包含对应 ID 的消息,删除操作可能失败。

正式 Agent 还要注意消息依赖关系,例如不要只删除工具调用的 AIMessage,却保留依赖它的 ToolMessage。


十八、消息历史为什么不能直接截取?

很多初学者会这样截取历史:

messages = messages[-10:]

对于普通文本对话,这种方式有时可以工作。

但对包含工具调用的 Agent,可能产生无效的消息序列。

例如:

AIMessage(tool_calls=[...])
ToolMessage(tool_call_id="call_001")

如果恰好把 AIMessage 删除,只保留 ToolMessage,那么工具结果就失去了对应的调用请求。

因此,裁剪 Agent 历史时,应特别注意消息的合法顺序。

对于复杂的多轮工具调用,通常更适合使用 LangChain Middleware 或专门的对话压缩策略。


十九、trim_messages():裁剪消息历史

LangChain 提供 trim_messages(),可以根据指定预算裁剪消息列表。

它支持按 Token 数量或使用自定义计数方式控制长度。

主要参数

参数默认值说明
messages必填待裁剪的消息列表
max_tokens必填Token 或指定计数预算
token_counter必填模型、计数函数或 approximate
strategylast保留最前面或最后面的消息
allow_partialFalse是否允许保留部分消息
start_onNone限制裁剪后起始消息类型
end_onNone限制裁剪后结束消息类型
include_systemFalse是否保留第一条 SystemMessage
text_splitterNone部分裁剪时使用的文本切分器

实例:保留最近对话

实例

from langchain.messages import (
    SystemMessage,
    HumanMessage,
    AIMessage,
    trim_messages
)

messages = [
    SystemMessage(content="你是 Python 助手。"),
    HumanMessage(content="什么是列表?"),
    AIMessage(content="列表可以存储多个元素。"),
    HumanMessage(content="什么是字典?"),
    AIMessage(content="字典使用键值对存储数据。"),
    HumanMessage(content="列表和字典有什么区别?")
]

trimmed = trim_messages(
    messages,
    max_tokens=80,
    strategy="last",
    token_counter="approximate",
    include_system=True,
    start_on="human",
    end_on=("human", "tool")
)

for msg in trimmed:
    print(msg.type, msg.content)

这里的 token_counter="approximate" 使用近似 Token 计数,适合需要快速估算上下文长度的场景。

它不保证与具体模型服务商的实际 Token 计费数量完全一致。

示例中的最终保留消息数量取决于实际计数结果。


二十、按消息数量裁剪

如果只是想保留固定数量的消息,也可以传入:

token_counter=len

这时 max_tokens 实际上代表消息数量预算,而不是模型 Token 数。

实例

实例

trimmed = trim_messages(
    messages,
    max_tokens=4,
    strategy="last",
    token_counter=len,
    include_system=True,
    start_on="human"
)

for msg in trimmed:
    print(msg.type, msg.content)

这种方式比较简单,但无法反映不同消息的实际 Token 长度。

例如一条 5000 字的消息与一条只有"你好"的消息,按消息数量计数时都算一条。

建议:生产环境中的上下文控制,应优先结合实际 Token 预算,而不是只依赖消息数量。


二十一、filter_messages():筛选消息

如果只想提取某类消息,可以使用 filter_messages()。

例如只查看用户消息。

实例:筛选 HumanMessage

实例

from langchain.messages import filter_messages

messages = [
    HumanMessage(content="你好"),
    AIMessage(content="你好!"),
    HumanMessage(content="介绍 Python"),
    AIMessage(content="Python 是一种编程语言")
]

users = filter_messages(
    messages,
    include_types="human"
)

for msg in users:
    print(msg.content)

输出:

你好
介绍 Python

还可以按照消息 ID、名称或消息类型进行筛选。

例如:

filter_messages(messages, exclude_types="system")

用于排除 SystemMessage。


二十二、convert_to_messages():转换消息格式

LangChain 可以使用多种方式表达聊天消息。

例如:

("user", "你好")

{"role": "user", "content": "你好"}

HumanMessage(content="你好")

convert_to_messages() 可以将支持的消息表示转换成消息对象。

实例

实例

from langchain.messages import convert_to_messages

raw_messages = [
    ("system", "你是 Python 助手。"),
    {"role": "user", "content": "你好"},
    ("assistant", "你好!")
]

messages = convert_to_messages(raw_messages)

for msg in messages:
    print(type(msg).__name__, msg.content)

输出:

SystemMessage 你是 Python 助手。
HumanMessage 你好
AIMessage 你好!

这在需要兼容不同历史消息格式时非常实用。


二十三、merge_message_runs():合并连续消息

如果消息列表中连续存在多条相同类型的消息,可以使用 merge_message_runs() 合并。

实例

实例

from langchain.messages import merge_message_runs

messages = [
    HumanMessage(content="请介绍 Python。"),
    HumanMessage(content="要求适合零基础。"),
    AIMessage(content="Python 是一种编程语言。")
]

merged = merge_message_runs(messages)

for msg in merged:
    print(msg.type, msg.content)

这个函数可以合并相邻的同类消息。

但需要注意:

  • 只处理可合并的连续消息。
  • 并不是所有类型的消息都适合合并。
  • ToolMessage 通常不会被合并,因为它具有独立的 tool_call_id。

因此,不要用合并函数随意修改尚未完成的工具调用消息序列。


二十四、MessageLikeRepresentation:快捷消息格式

LangChain 在许多模型和 Agent API 中支持多种消息输入格式。

常见写法:

格式示例
字符串"你好"
消息对象HumanMessage(content="你好")
元组("user", "你好")
字典{"role": "user", "content": "你好"}

例如,直接调用 Chat Model:

model.invoke("你好")

或者:

model.invoke([
    ("system", "你是助手"),
    ("user", "你好")
])

调用 Agent:

agent.invoke({
    "messages": [
        {"role": "user", "content": "你好"}
    ]
})

对于简单开发,使用字典或元组比较方便。

如果需要直接读取和处理 message.id、tool_calls、metadata 等属性,使用明确的消息对象通常更方便。


二十五、LangChain Messages 与对话记忆

Agent 多轮对话中的消息历史通常保存在 State 中。

例如:

{
    "messages": [
        HumanMessage(content="我正在学 Python"),
        AIMessage(content="好的"),
        HumanMessage(content="推荐学习路线")
    ]
}

LangGraph 默认的 messages 状态通常通过 add_messages Reducer 管理更新。

这意味着:

  • 新的消息通常会被追加。
  • 具有相同 ID 的消息可以替换已有消息。
  • RemoveMessage 可以请求删除指定消息。

但仅仅创建 messages 列表,并不意味着 Agent 可以跨程序重启自动记住历史。

要实现多轮记忆,需要根据应用情况使用 Checkpointer。

如果需要长期保存用户偏好,还可以进一步配合 Store。


二十六、完整实例:Messages API 综合使用

下面通过一个可以直接运行的示例,演示消息创建、属性读取、工具调用格式、消息筛选以及消息裁剪。

文件名:messages_api_demo.py

安装:

pip install -U langchain langchain-core

本示例全部使用本地模拟消息,不需要 API Key。

完整实例

from langchain.messages import (
    SystemMessage,
    HumanMessage,
    AIMessage,
    AIMessageChunk,
    ToolMessage,
    RemoveMessage,
    trim_messages,
    filter_messages,
    convert_to_messages
)
from langgraph.graph.message import add_messages

# ========== 1. 基本消息 ==========

messages = [
    SystemMessage(content="你是 Python 助手。", id="sys-001"),
    HumanMessage(content="你好", id="user-001"),
    AIMessage(content="你好!", id="ai-001"),
    HumanMessage(content="介绍 Python 列表。", id="user-002"),
    AIMessage(content="列表可以保存多个元素。", id="ai-002")
]

print("=== 基本消息 ===")
for msg in messages:
    print(msg.type, msg.content)

# ========== 2. ToolCall + ToolMessage ==========

tool_request = AIMessage(
    content="",
    id="ai-tool-001",
    tool_calls=[{
        "name": "get_weather",
        "args": {"city": "杭州"},
        "id": "call-001",
        "type": "tool_call"
    }]
)

tool_result = ToolMessage(
    content="杭州模拟天气:晴,25°C",
    tool_call_id="call-001",
    name="get_weather",
    id="tool-msg-001"
)

print("\n=== 工具调用 ===")
print(tool_request.tool_calls)
print(tool_result.tool_call_id)

# ========== 3. 流式消息合并 ==========

chunk1 = AIMessageChunk(content="Python")
chunk2 = AIMessageChunk(content=" 很容易入门。")

merged = chunk1 + chunk2
print("\n=== Chunk 合并 ===")
print(merged.content)

# ========== 4. 消息裁剪 ==========

trimmed = trim_messages(
    messages,
    max_tokens=4,
    strategy="last",
    token_counter=len,
    include_system=True,
    start_on="human"
)

print("\n=== 裁剪结果 ===")
for msg in trimmed:
    print(msg.type, msg.content)

# ========== 5. 消息筛选 ==========

users = filter_messages(messages, include_types="human")
print("\n=== 用户消息 ===")
for msg in users:
    print(msg.content)

# ========== 6. 消息转换 ==========

converted = convert_to_messages([
    ("user", "什么是字典?"),
    ("assistant", "字典通过键值对保存数据。")
])

print("\n=== 格式转换 ===")
for msg in converted:
    print(type(msg).__name__, msg.content)

# ========== 7. 消息删除 ==========

updated = add_messages(
    messages,
    [RemoveMessage(id="user-001")]
)

print("\n=== 删除消息后 ===")
for msg in updated:
    print(msg.id, msg.content)

此程序不调用模型,因此无需联网即可测试上述消息对象和辅助函数。

对于具体的裁剪结果,应以当前安装的 LangChain 版本和配置为准。


二十七、常见问题

1、HumanMessage 和 role=user 有什么区别?

HumanMessage 是 LangChain 消息对象,user 是聊天模型 API 中的角色名称。

2、AIMessage 的 type 是 assistant 吗?

不是。AIMessage 的 type 通常是 ai,assistant 是对应的对话角色。

3、AIMessageChunk 的 type 是 ai 吗?

不是。Python 的 AIMessageChunk 使用自己的类型标识 AIMessageChunk。

4、ToolCall 和 ToolMessage 有什么区别?

ToolCall 是模型的工具调用请求;ToolMessage 是工具实际执行后的返回消息。

5、为什么 ToolMessage 需要 tool_call_id?

因为模型可能同时请求多个工具,需要通过 ID 将调用结果与原始请求对应。

6、bind_tools() 会自动创建 ToolMessage 吗?

不会。bind_tools() 主要让模型具备生成工具调用请求的能力,实际工具执行通常由应用代码或 Agent 处理。

7、content 一定是字符串吗?

不一定。多模态消息可能包含内容块列表。

8、TextContentBlock 和 PlainTextContentBlock 有什么区别?

前者用于普通文本,后者主要用于 TXT、Markdown 等纯文本文件数据。

9、ImageContentBlock 能用于任何 Chat Model 吗?

不能。模型必须支持图片输入,并且提供商集成能够处理对应内容格式。

10、AIMessageChunk 一定是一个 Token 吗?

不是。Chunk 表示流式增量,可能包含一个或多个 Token 的内容。

11、如何合并多个 AIMessageChunk?

可以使用 + 操作符,将同一条消息的多个 Chunk 聚合。

12、为什么 trim_messages() 之后工具调用报错?

可能因为裁剪破坏了 AIMessage.tool_calls 与对应 ToolMessage 的关系,需要保留有效消息序列。

13、token_counter=len 表示按 Token 计数吗?

不是。它表示按消息数量计数。

14、RemoveMessage 会直接删除 Python 列表元素吗?

不会。它需要通过支持删除语义的消息 Reducer 处理。

15、如何只获取用户消息?

可以使用 filter_messages(messages, include_types="human")。

16、如何把字典转换为消息对象?

可以使用 convert_to_messages()。

17、Chat Model 和 Agent 使用的消息类型相同吗?

通常共享 LangChain Messages 体系,但 Agent 还会结合工具消息、状态更新和 Checkpointer 管理完整执行流程。

18、Messages 可以保存用户长期偏好吗?

消息历史可以提供会话上下文,但跨会话长期偏好更适合使用 Store 或业务数据库保存。


总结

Messages API 是 LangChain 1.x 的核心基础之一。

本章节介绍了:

  • HumanMessage:用户消息。
  • AIMessage:模型回复。
  • SystemMessage:系统指令。
  • ToolMessage:工具执行结果。
  • AIMessageChunk:流式消息增量。
  • ToolCall:模型工具调用请求。
  • RemoveMessage:删除状态消息。
  • TextContentBlock:普通文本。
  • ImageContentBlock、AudioContentBlock 等:多模态数据。
  • content_blocks:标准化内容块。
  • trim_messages():裁剪消息历史。
  • filter_messages():筛选消息。
  • convert_to_messages():转换消息格式。
  • merge_message_runs():合并连续消息。

最基本的聊天消息结构:

messages = [
    SystemMessage(content="你是助手"),
    HumanMessage(content="你好"),
    AIMessage(content="你好!")
]

工具调用的基本结构:

HumanMessage
      ↓
AIMessage(tool_calls)
      ↓
ToolMessage(tool_call_id)
      ↓
AIMessage(最终回答)

核心原则:LangChain Messages 不只是聊天文本容器,还承担角色区分、工具调用关联、流式增量、多模态内容表示和状态更新等任务。

理解消息结构后,才能更准确地使用 Agent、Middleware、Checkpointer、Streaming 和 Human-in-the-Loop。

参考文档