当前位置: 首页 > news >正文

LangChain 系列之 Messages:为什么大模型对话不是简单字符串?

大模型对话不是“字符串输入、字符串输出”这么简单。真正进入模型上下文的,是一组带角色、内容和元数据的消息列表。

1. Messages 是大模型对话的骨架

很多人刚学 LangChain,会把模型调用理解成:我给模型一段文本,模型返回一段文本。这个理解不能说错,但它只适合最简单的 Demo。真实的大模型应用,尤其是智能客服、知识库问答、Agent 工具调用、多轮对话,绝对不能只靠一大段字符串拼接。

LangChain 官方文档把 Messages 定义为模型上下文的基本单位。一个 Message 不只是内容,它还包含 role、content、metadata。role 表示谁说的,content 表示说了什么,metadata 用来记录消息 ID、token 用量、模型响应信息等。也就是说,一条消息本身就是一个结构化对象。

为什么这件事重要?因为大模型要理解对话,首先要知道“谁在说话”。系统规则、用户问题、模型回复、工具结果,如果全部揉成一段字符串,模型就需要自己猜边界;而 Messages 直接把边界标出来,模型理解上下文会更稳定。

普通字符串和 Messages 列表的区别

你可以把 Messages 理解成一次会议纪要:不是只记录一句话,而是记录谁说的、什么时候说的、说的内容是什么、这句话和后续动作有什么关系。

2. 为什么不能一直用字符串拼接?

小项目里,用字符串拼接确实能跑起来。例如把系统提示词、用户问题、历史对话全部拼成一段 prompt,然后丢给模型。但是项目稍微复杂一点,问题马上出现。

第一,角色混乱。系统规则、用户提问、模型历史回复和工具结果都混在一起,模型可能分不清哪些是必须遵守的规则,哪些只是用户随口说的话。

第二,多轮对话容易乱。用户第一轮说“我想退款”,第二轮说“订单号 123”,第三轮说“那多久能到账”。如果没有消息角色和顺序管理,你只能不断拼字符串,越拼越乱,成本也越来越高。

第三,工具调用不好接。Agent 场景里,模型可能先请求调用订单查询工具,工具返回结果后,模型再生成最终答案。这个过程需要 AIMessage 和 ToolMessage 精确对应,普通字符串很难优雅表达。

第四,线上问题难排查。生产系统需要知道每一轮输入输出、token 用量、工具调用 ID、模型响应元数据。字符串只有一大段文本,排查时很难定位问题发生在哪里。

问题

字符串拼接的风险

Messages 的优势

角色边界

系统规则、用户问题、模型回复混在一起

每条消息都有明确 role

多轮上下文

越拼越长,越拼越乱

消息按顺序保存,可裁剪、摘要、持久化

工具调用

工具请求和结果难对应

AIMessage.tool_calls 与 ToolMessage.tool_call_id 可关联

可观测

只能看到最终 prompt

可以记录 message_id、token、response_metadata

多模态

文本拼接难承载图片、音频、文件

content 可以承载多种内容块

3. LangChain 的 Message 到底长什么样?

LangChain 里的 Message 可以先用三个字段理解:

字段

含义

例子

role

这句话是谁说的

system / user / assistant / tool

content

消息内容,可以是文本,也可以是多模态内容块

“你是一个客服助手” / 图片 / 文件

metadata

额外信息,用于追踪和工程化治理

id、token 用量、模型响应信息、工具调用信息

最简单的写法可以是这样:

from langchain.chat_models import init_chat_model
from langchain.messages import SystemMessage, HumanMessage
model = init_chat_model("gpt-5-nano")
messages = [
SystemMessage("你是一个专业、谨慎的技术文章助手。"),
HumanMessage("帮我解释 LangChain 的 Messages 是什么。"),
]
response = model.invoke(messages)
print(response.text)

你也可以用更接近 OpenAI Chat Completions 的字典格式:

messages = [
{"role": "system", "content": "你是一个技术文章助手"},
{"role": "user", "content": "解释一下 LangChain Messages"},
]
response = model.invoke(messages)

两种写法背后的思想是一样的:把一次对话拆成多条有角色的消息,而不是拼成一坨字符串。

4. 四类核心消息:System、Human、AI、Tool

4.1 SystemMessage:给模型定规矩

SystemMessage 是模型行为的“底层规则”。它通常放在消息列表最前面,用来告诉模型:你是谁、要怎么回答、有什么边界、哪些事情不能做。

比如智能客服里,SystemMessage 可以写:你是金融客服助手,必须基于知识库和订单系统回答;涉及退款、借款、改手机号等高风险操作时,只能引导用户走官方流程,不能直接替用户操作。

SystemMessage 的价值不是让回答看起来更好,而是把业务规则前置,让模型在整个对话中始终被规则约束。

SystemMessage("""
你是一个企业知识库问答助手。
回答必须基于已检索到的资料。
如果资料中没有答案,要明确说不知道,不能编造。
""")

4.2 HumanMessage:承载用户输入

HumanMessage 代表用户输入。它可以是纯文本,也可以包含图片、音频、文件等多模态内容。对智能客服来说,它就是用户说的每一句话;对文档问答来说,它就是用户的问题;对多模态应用来说,它还可能包含截图、合同图片、商品图。

从工程角度看,HumanMessage 最好不要只存 content,还要记录 user_id、session_id、message_id、时间戳等信息,方便后续排查。

4.3 AIMessage:承载模型输出

AIMessage 是模型返回的消息。它不一定只有最终答案,还可能包含 tool_calls,也就是模型认为自己需要调用某个工具。

比如用户问“帮我查订单 123 到哪了”,模型可能不会直接回答,而是在 AIMessage 里发起 query_order_status 这个工具调用请求。等工具返回结果后,模型再生成最终回复。

AIMessage 里通常还会带 usage_metadata、response_metadata 等信息。这些信息对成本统计、性能分析、线上排查很重要。

4.4 ToolMessage:把工具结果送回模型

ToolMessage 是 Agent 工具调用链路里的关键角色。模型发起工具调用后,业务系统真正执行工具,比如查数据库、查订单、查天气、查股票行情。执行结果不能随便拼进 prompt,而是应该作为 ToolMessage 回传给模型。

ToolMessage 需要和 AIMessage 里的 tool_call_id 对齐。这样模型就能知道:这个工具结果对应的是刚才哪一次工具请求。

5. 多轮对话为什么必须用 Messages?

单轮问答里,Messages 的优势可能不明显。但是一旦进入多轮对话,Messages 就非常关键。

多轮对话不是“当前问题 + 历史文本”这么简单。模型需要知道:第一句是谁说的,第二句是谁回答的,第三句是不是工具返回的结果,第四句是不是用户在追问。消息顺序和消息角色一起构成了对话状态。

LangChain 官方文档也明确提到,message prompts 适合管理多轮对话、处理多模态内容、包含系统指令。也就是说,只要你要做真正的聊天应用,就应该进入 Messages 的世界。

举个客服场景:

messages = [
SystemMessage("你是金融客服助手,回答必须合规。"),
HumanMessage("我想提前还款。"),
AIMessage("可以,请提供贷款编号。"),
HumanMessage("编号是 LN2026。"),
ToolMessage(
content="查询结果:用户可提前还款,手续费 0 元。",
tool_call_id="call_loan_query_001",
name="query_loan_plan"
),
]

这段消息历史比一坨字符串清晰得多。模型能看到:用户想提前还款,模型曾经追问贷款编号,工具已经查出可提前还款,最后就可以基于工具结果生成准确回复。

6. Message content:不只是文本,还可以是多模态内容

早期很多人把大模型应用理解成文本问答,但现在模型已经越来越多模态。用户可能上传图片、合同截图、PDF、音频,模型也可能返回带引用、推理块、工具调用块的内容。

LangChain 的 Message content 是比较灵活的:既可以是字符串,也可以是内容块列表。官方文档提到,content 可以承载文本、图片、音频、文档等内容,同时还支持不同模型提供商的原生结构。

这意味着 Messages 不只是聊天记录,更像是一种统一上下文容器。它把用户输入、模型输出、工具结果、多模态内容和元数据都放进同一套结构里。

7. Message metadata:线上排查靠它救命

很多教程只讲 role 和 content,但企业级项目一定要重视 metadata。因为线上出现问题时,你不能只看最终回答,还要知道模型到底看到了什么、用了多少 token、有没有调用工具、调用哪个工具、工具结果是什么。

AIMessage 里常见的 usage_metadata 可以记录输入 token、输出 token、总 token;response_metadata 可以记录模型供应商返回的响应信息。HumanMessage 也可以带 name、id 等字段,用于标识不同用户或不同消息。

如果你做智能客服、股票分析助手、企业知识库系统,建议从第一天就把消息结构化落库。否则等线上回答错了,你只能翻日志猜问题,很痛苦。

字段

建议是否落库

用途

request_id

必须

一次请求的唯一编号,方便串联完整链路

session_id

必须

区分不同会话,支持多轮对话

role

必须

区分 system、human、ai、tool

content

必须

消息正文或工具结果

message_id

建议

单条消息追踪

tool_call_id

工具场景必须

把工具请求和工具结果对应起来

usage_metadata

强烈建议

统计 token 和成本

response_metadata

建议

排查模型供应商响应问题

8. 在 Java + Python 架构里,Messages 应该怎么设计?

如果你的主系统是 Spring Boot,AI 能力放在 Python FastAPI 服务里,建议 Java 负责业务身份和会话管理,Python 负责构造 LangChain Messages 并调用模型。

Java 侧不要只给 Python 传一个 prompt 字符串,而应该传结构化请求。例如用户 ID、会话 ID、业务场景、用户问题、历史消息、检索结果、工具权限等。Python AI 服务再把这些内容组装成 SystemMessage、HumanMessage、AIMessage、ToolMessage。

这样做有三个好处:第一,Java 仍然掌握权限和业务边界;第二,Python 可以灵活使用 LangChain 生态;第三,后续接 LangGraph、Memory、LangSmith、评测系统时,不需要推倒重来。

# Java 主服务传给 Python AI 服务的请求示例
{
"request_id": "req_20260613_001",
"session_id": "s_10086",
"user_id": "u_123",
"scene": "customer_service",
"question": "我的订单 123 到哪了?",
"history": [
{"role": "human", "content": "我想查订单"},
{"role": "ai", "content": "请提供订单号"}
],
"allowed_tools": ["query_order_status"]
}

# Python AI 服务中构造 LangChain Messages
messages = [
SystemMessage("你是客服助手,只能调用授权工具回答。"),
HumanMessage("我想查订单"),
AIMessage("请提供订单号"),
HumanMessage("我的订单 123 到哪了?"),
]
response = agent.invoke({"messages": messages})

9. 常见错误:很多 LangChain 项目都栽在这里

错误做法

为什么有问题

正确做法

把全部历史对话拼成一个字符串

角色边界丢失,越拼越乱

用 messages 列表保存多轮对话

把工具结果直接拼到用户问题后面

模型分不清这是工具结果还是用户输入

用 ToolMessage 回填工具结果

SystemMessage 写得太随意

业务规则不稳定,模型容易跑偏

把角色、边界、输出要求写清楚

不记录 usage_metadata

上线后无法统计成本

保存 token 用量和模型响应信息

无脑保留全部历史消息

上下文变长,成本增加,效果下降

结合 Memory、摘要、窗口裁剪

忽略 tool_call_id

多工具调用时结果容易错配

工具请求和结果必须一一对应

10. 总结:Messages 是后面所有高级能力的地基

这章看起来只是在讲消息类型,但它其实是 LangChain 后续所有高级能力的地基。Prompt Template 要生成消息,Chat Model 要消费消息,Memory 要保存和裁剪消息,Tools 要通过 AIMessage 和 ToolMessage 交互,Agent 要围绕消息不断循环,LangGraph 也会把消息作为状态的一部分来流转。

所以,学 LangChain 不要只记 API。你真正要理解的是:大模型应用的上下文,不是一段随便拼出来的字符串,而是一组可组织、可追踪、可扩展、可治理的消息。

记住一句话:Messages 是大模型应用里的“对话账本”。每一条消息都要知道是谁说的、说了什么、和后续动作有什么关系。


内容来源:LangChain 系列之 Messages:为什么大模型对话不是简单字符串?:功能变化与行业影响解析_热闻岛

http://www.rkmt.cn/news/1521349.html

相关文章:

  • 2026金华驾校教练选择指南:本地老牌、耐心教学与实战派谁更值得托付? - 优质品牌商家
  • 2026-06-14:切换打开灯泡。用go语言,给定一个整数数组 bulbs,数组中每个元素都在 1 到 100 之间。共有 100 个电灯泡,编号从 1 到 100,初始时全部处于关闭状态。 依次遍
  • 告别虚拟机!用DOSBox在Win11上搭建汇编开发环境(附Masm文件配置)
  • 实战指南:如何构建企业级开源即时通讯系统OpenIM
  • 法考讲义网盘|讲义|资料已整理
  • STM32CubeIDE实战:手把手教你将正点原子LCD驱动移植到F103精英板(附完整代码)
  • ArcGIS Pro弹出窗口图片显示:三种方法保姆级对比,别再只会用HTML了
  • YOLOv5到v8怎么选?我用同一份快递数据集做了个全面对比测试(附mAP/F1-Score详细数据)
  • 无人机虚拟仿真备赛:从SF600航线规划到安全飞行的全流程细节复盘
  • ollama v0.30.8 最新更新解读:修复启动提供方选择错误,提示词缓存更稳,MLX 推理与递归模型全面增强
  • 2026年西南钢模板租赁市场现状与供应商能力评测:谁更值得合作? - 优质品牌商家
  • 多模态仇恨内容检测:xDORA框架与FAISS检索实践
  • 九江报名 CPPM 注册采购经理哪家靠谱?机构选择避坑指南 - 众智商学院课程中心
  • 2026年知名的警示柱反光膜/工程级反光膜深度厂家推荐 - 品牌宣传支持者
  • 你的显卡在吃灰吗?解锁Ansys Speos隐藏性能:GPU计算与实时预览全攻略
  • 量子计算中的Dynamical Lie Algebra与图结构分析
  • 别再只用kl-f8了!Diffusion VAE选型指南:从kl-f4到ft-MSE,哪个更适合你的SD模型?
  • 保姆级教程:用C语言和gSOAP从零实现一个ONVIF客户端(附完整源码)
  • LangChain 系列:Structured Output结构化输出与源码解析
  • 2026年热门的秦皇岛全屋整装装修/秦皇岛一站式整装装修/秦皇岛装修/秦皇岛全屋定制装修优选服务公司 - 品牌宣传支持者
  • 2026年高端婚介服务深度观察:成都、长沙主流机构多维对比分析 - 优质品牌商家
  • Windows/Mac双平台实测:Upscayl这6个AI放大模型到底怎么选?附批量处理与压缩设置技巧
  • 保姆级教程:用mavcmd命令行一键搞定PX4无人机指点飞行(附IMU频率设置)
  • 别再傻傻分不清!嵌入式开发选RTOS,SMP和AMP到底哪个更适合你的多核SOC?
  • 从Airflow到Kafka:拆解OpenMetadata与DataHub的元数据‘搬运’哲学
  • 装机小白必看:DDR4内存条怎么选?从频率、时序到颗粒,一篇讲透避坑要点
  • 2026年知名的机架钣金加工/自动化框架钣金加工/苏州铝型材框架钣金加工/钢平台钣金加工厂家选择推荐 - 行业平台推荐
  • ProCAST结果数据搬运工:温度场、应力场导出为PATRAN格式的完整避坑指南
  • 2026年高端熔体静电纺丝设备/对喷静电纺丝设备/山东纳米静电纺丝设备/山东纳米纤维静电纺丝设备优质厂家推荐榜 - 品牌宣传支持者
  • yt-dlp-gui:终极免费视频下载神器,三步搞定YouTube视频下载