LangChain Message介绍

57 阅读4分钟

在 LangChain 中,消息(Messages)是构建聊天模型输入和输出的核心单元。LangChain 将不同角色的对话内容标准化为特定的类,以便于在不同的 LLM 供应商(如 OpenAI、Anthropic、Claude)之间切换。

1. Message消息类型与继承关系

所有的消息类都继承自 BaseMessage 基类。这个基类定义了所有消息共有的属性:content(内容)、name(可选,发送者名称)和 additional_kwargs(特定供应商的额外参数)。

继承关系图解:

类名继承自代表角色说明
SystemMessageBaseMessageSystem设置 AI 的行为、性格或约束条件,通常放在对话首位。
HumanMessageBaseMessageUser代表用户的输入,可以是文本、图片或其他多模态数据。
AIMessageBaseMessageAssistantAI 生成的响应。包含文本内容、工具调用(tool_calls)等。
ToolMessageBaseMessageTool传递工具执行结果回模型的消息。必须包含 tool_call_id
FunctionMessageBaseMessageFunction旧版函数调用结果(已逐渐被 ToolMessage取代)。
ChatMessageBaseMessage自定义允许手动指定任意 role字符串的通用消息类。

2. 各消息类型详细介绍与用法

SystemMessage (系统消息)

用于“洗脑”或初始化。它告诉模型:“你是一个专业的翻译官”或“你说话必须带海盗口音”。

  • 用法SystemMessage(content="你是一个金融分析师,只回答财经问题。")

HumanMessage (人类消息)

用户的指令或提问。

  • 用法HumanMessage(content="今天的黄金价格是多少?")
  • 多模态支持:它也可以接收列表形式的 content,用于传递图片: HumanMessage(content=[{"type": "text", "text": "..."}, {"type": "image_url", ...}])

AIMessage (AI 消息)

模型返回的对象。它除了 content,最重要的属性是 tool_calls。当模型决定调用工具时,content 可能为空,而 tool_calls 会包含具体的函数名和参数。

  • 用法:通常由模型 model.invoke() 产生,但也可以手动构建: AIMessage(content="好的,我为您查询一下。", tool_calls=[...])

ToolMessage (工具消息)

这是闭环的关键。模型发出 tool_calls 后,你运行本地代码得到结果,必须用 ToolMessage 把结果传回。

  • 用法ToolMessage(content="250元/克", tool_call_id="call_abc123")
  • 核心要求:必须匹配 AI 消息中对应的 id

3. 代码示例:一个完整的对话流

from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage, AnyMessage

messages = [
    SystemMessage(content="你是一个智能助手。"),
    HumanMessage(content="查询北京天气"),
    # 模拟模型返回结果,决定调用工具
    AIMessage(content="", tool_calls=[{"name": "get_weather", "args": {"city": "北京"}, "id": "123"}]),
    # 模拟工具返回结果
    ToolMessage(content="晴,25度", tool_call_id="123"),
    # 模型根据工具结果给出最终回答
    AIMessage(content="北京今天天气晴朗,气温 25 度。")
]

# AnyMessage 涵盖了这两种具体类型
def process_chat(msg: AnyMessage):
    print(msg.content) # BaseMessage 共有属性

    if isinstance(msg, AIMessage):
        # 只有标注为 AnyMessage 或 AIMessage,IDE 才会在这里提示 .tool_calls
        print(msg.tool_calls)

# 它可以接收任何子类
process_chat(HumanMessage(content="你好"))
process_chat(AIMessage(content="我好"))

4. AnyMessage

AnyMessage 并不是一个普通的 类(Class) ,而是一个 类型别名(Type Alias)

简单来说,AnyMessage 就是所有具体消息类型的 合集(Union)

4.1. 继承与包含关系

在 Python 的 typing 体系中,它们的逻辑关系如下:

  • BaseMessage 是所有消息类的 祖先基类
  • HumanMessage, AIMessage, SystemMessage, ToolMessage 等都 继承(Inherit)BaseMessage

AnyMessage 是一个 Union 类型,python中的定义为:

AnyMessage = Annotated[    Annotated[AIMessage, Tag(tag="ai")]
    | Annotated[HumanMessage, Tag(tag="human")]
    | Annotated[ChatMessage, Tag(tag="chat")]
    | Annotated[SystemMessage, Tag(tag="system")]
    | Annotated[FunctionMessage, Tag(tag="function")]
    | Annotated[ToolMessage, Tag(tag="tool")]
    | Annotated[AIMessageChunk, Tag(tag="AIMessageChunk")]
    | Annotated[HumanMessageChunk, Tag(tag="HumanMessageChunk")]
    | Annotated[ChatMessageChunk, Tag(tag="ChatMessageChunk")]
    | Annotated[SystemMessageChunk, Tag(tag="SystemMessageChunk")]
    | Annotated[FunctionMessageChunk, Tag(tag="FunctionMessageChunk")]
    | Annotated[ToolMessageChunk, Tag(tag="ToolMessageChunk")],
    Field(discriminator=Discriminator(_get_type)),
]
"""A type representing any defined `Message` or `MessageChunk` type."""

这里边还有MessageChunk类型,就不详细介绍了,有兴趣可以问下大模型

4.2. 为什么要用 AnyMessage?

在 LangGraph 或复杂的 Chain 中,我们经常需要处理“一个包含各种消息的列表”。

  • 如果标注为 list[BaseMessage]:类型检查器只知道里面是基础消息,当你访问 AIMessage 特有的 tool_calls 属性时,IDE 可能会报警告,因为它不确定 BaseMessage 是否有这个属性。
  • 如果标注为 list[AnyMessage]:这是 类型安全 的做法。它告诉 IDE 和编译器:“这个列表里的对象一定是这几种具体消息类型之一”。这样当你进行类型判断(如 if isinstance(msg, AIMessage))时,IDE 能提供精准的代码补全。

4.3. 在代码中的表现

from langchain_core.messages import AnyMessage, HumanMessage, AIMessage

# AnyMessage 涵盖了这两种具体类型
def process_chat(msg: AnyMessage):
    print(msg.content) # BaseMessage 共有属性

    if isinstance(msg, AIMessage):
        # 只有标注为 AnyMessage 或 AIMessage,IDE 才会在这里提示 .tool_calls
        print(msg.tool_calls)

# 它可以接收任何子类
process_chat(HumanMessage(content="你好"))
process_chat(AIMessage(content="我好"))