LangChain 进阶:深度解析模型调用中的消息结构与多轮对话管理 在上一篇文章中我们完成了 LangChain 环境的搭建并成功实现了对 DeepSeek 模型的第一次调用。当时我们使用的是最简单的方式直接向模型传递一个字符串。虽然这种方式可以让模型运转但在构建真实的 AI 应用如智能客服、Chatbot时它显得捉襟见肘。我们往往需要更精细地控制模型的行为设定角色告诉 AI“你是谁”是严谨的律师还是幽默的导游。制定规则规定哪些能说哪些不能说回答的格式是什么。维护上下文让 AI 记得几分钟前用户说了什么实现真正的“对话”。要实现这些功能我们就必须深入理解 LangChain 的消息结构Message Structure。本篇文章将带你掌握模型调用中最核心的三个消息角色学习如何控制模型性格并手把手教你实现一个带历史记忆的命令行对话助手。1. 为什么字符串输入还不够在 REST API 的原生调用中我们通常需要构建复杂的 JSON 对象。LangChain 对此进行了抽象引入了消息Messages的概念。使用消息结构而非纯文本核心优势在于语义化控制和状态管理。模型需要知道哪部分内容是开发者的指令哪部分是用户的提问哪部分是它自己之前的回答。2. 核心消息角色详解在 LangChain以及大多数主流大模型 API中对话被抽象为一个消息列表。最常用的有三类消息角色 (Role)LangChain 类描述SystemSystemMessage系统消息。由开发者预设用于定义 AI 的身份、行为准则、输出格式、语气等。它是对话的基调优先级最高。HumanHumanMessage用户消息。真实的终端用户输入的提问或需求。AIAIMessageAI 回复。模型生成的文本内容。在多轮对话中需要将其捕获并重新塞回消息列表。我们可以从langchain_core.messages导入这些类Pythonfrom langchain_core.messages import AIMessage, HumanMessage, SystemMessage2.1 SystemMessage铸造 AI 的灵魂SystemMessage是你给大模型下达的“底层指令”。它通常在对话的最开始发送一次并在整个会话中持续生效取决于模型的上下文窗口和注意力机制。对应的 OpenAI API 角色是role: system。常见用途限定角色“你是一名专业的 Python 架构师。”限定语气“你的回答必须幽默、风趣多用表情包。”限定规则“如果用户询问价格请引导其联系销售不要直接报价。”限定输出“所有回答必须是标准的 JSON 格式。”代码示例Python# 设定一个傲娇的 AI 助手 messages [ SystemMessage(content你是一个傲娇的机器人助手虽然会回答用户问题但语气要显得不情愿。), HumanMessage(content帮我解释一下什么是量子力学。), ] # 模型可能会回复哼真麻烦连这个都不懂...然后开始解释提示在使用初期无需构建极其复杂的 System Prompt。规则过多反而可能导致模型执行不稳定或产生冲突。2.2 HumanMessage传递用户意图HumanMessage代表用户的输入。在实际项目中它可能来自命令行 (input())、Web 前端的输入框、App 的聊天界面或者 API 请求参数。Pythonuser_input input( 用户) human_message HumanMessage(contentuser_input)2.3 AIMessage捕获模型的产出AIMessage是调用model.invoke()后返回的对象。它包含了模型生成的文本。在单轮对话中我们通常只关心AIMessage.content。 但在多轮对话中整个AIMessage对象或至少其内容必须被保存下来并在下一次发起请求时连同新的HumanMessage一起发送给模型。多轮对话原理解析图如图所示多轮对话本质上是不断滚雪球式地将历史消息列表发送给模型。模型本身是不具备记忆功能的Stateless记忆是由程序员通过维护这个列表来实现的。3. 实战案例构建带角色的命令行客服光说不练假把式。我们结合SystemMessage和temperature参数来实现一个真实的客服场景。3.1 引入模型参数Temperature在调用模型时temperature温度是一个非常关键的参数。它控制着模型输出的随机性和创造性。Temperature 0完全确定性。相同输入永远返回相同输出。适合代码生成、数学计算、知识库问答RAG。Temperature ≈ 0.1 - 0.4严谨、逻辑稳定、极少幻觉。适合商务客服、金融报表解析。Temperature ≈ 0.7 - 1.0平衡创意与逻辑。适合通用聊天、邮件撰写、文案摘要。Temperature 1.0脑洞大开、容易瞎编。适合写故事、写诗、创意激荡。对于客服场景我们需要稳定、礼貌严禁瞎编因此应设置较低的温度。3.2 实战基础客服助手 (01_customer_service.py)3.2.1单次对话助手Pythonimport os from dotenv import load_dotenv from langchain.chat_models import init_chat_model from langchain_core.messages import SystemMessage, HumanMessage load_dotenv() model init_chat_model( modelPro/zai-org/GLM-5, model_provideropenai, api_keyos.getenv(SILICONFLOW_API_KEY), base_urlos.getenv(SILICONFLOW_BASE_URL), temperature0.5 ) messages [ SystemMessage(content你是一个傲娇的机器人助手虽然会回答用户问题但语气要显得不情愿。), HumanMessage(content帮我解释一下什么是量子力学。), ] response model.invoke(messages) print(response.content)运行测试观察模型是否使用了机器人语气以及当你询问“什么是量子力学”时它是否会根据 System 规则回复你。下面是我的运行结果。3.2.2多轮对话助手4. 上下文管理优化限制历史消息数量上面的代码虽然实现了多轮对话但存在一个致命缺陷消息列表会无限增长。随着对话的进行成本飙升大模型的计费通常基于 Token 数量输入输出。历史越长每次请求的 Token 数越多。速度变慢模型处理长上下文需要更长的时间。甚至报错每个模型都有上下文窗口限制e.g., 8K, 32K, 128K Token。一旦超过限制请求就会失败。干扰严重过久的、无关的历史消息可能会干扰模型对当前问题的判断。因此在实际工程中我们必须进行上下文管理。最简单直接的方法是只保留最近 N 轮对话。4.1 实战保留历史的助手我们可以利用 Python list 的切片功能轻松实现这一点。通常一轮对话包含一门HumanMessage和一个AIMessage如果我们想保留最近 3 轮对话就需要保留最近 6 条消息。同时SystemMessage 通常不能被切掉它必须始终处于列表的第一位。Python# ... (前面的初始化代码同上) ... # 这里我们要维护一个“滑动窗口”的思想 def get_messages_for_model(all_messages, limit6): 确保 SystemMessage 始终在首位并取最近 limit 条 Human/AI 消息 if len(all_messages) 1: # 只有 SystemMessage return all_messages system_msg all_messages[0] # 取最近的 limit 条消息 (注意不包括索引 0 的 system message) recent_msgs all_messages[1:][-limit:] return [system_msg] recent_msgs # ... (在 while 循环中) ... # 3. 将用户输入封装为 HumanMessage messages.append(HumanMessage(contentuser_input)) # 4. 获取修剪后的消息列表用于发送 messages_to_send get_messages_for_model(messages, limit6) try: # 5. 调用模型时传入修剪后的列表 response model.invoke(messages_to_send) # 6. 打印 AI 回复并将 AI 回复也加入完整的历史 print(f 客服: {response.content}) messages.append(response) # 完整的历史还是要存的方便查看或持久化 # ...5. 展望更好的多轮对话写法本篇文章中我们手动维护了一个 list并手动进行append和切片。这是理解原理的最佳方式。但在 LangChain 的高级用法中通常不建议这样手动操作。下一章在讲解ChatPromptTemplate提示词模板时我们会介绍更优雅的写法例如使用MessagesPlaceholder在模板中预留历史消息的位置Python# 示意代码下一章详述 prompt ChatPromptTemplate.from_messages([ (system, 你是一个专业的地理学家。), MessagesPlaceholder(variable_namechat_history), # 这里用来动态插入历史消息 (human, {question}), ])配合 LangChain 的RunnableWithMessageHistory将在内存管理章节讲解可以实现完全自动化的历史消息维护和修剪无需手动写 Python code 去管理 list。6. 总结掌握消息结构是迈向 LangChain 高级开发的第一步。请务必牢记以下几点三剑客SystemMessage定人设HumanMessage传意图AIMessage捕产出。多轮对话本质是状态的维护是不断把完整的历史消息雪球发送给模型。Temperature决定模型严谨程度的关键按钮。客服用低温创意用高温。上下文管理现实项目中必须限制历史长度兼顾成本、速度和模型注意力。如果你觉得这篇文章对你有帮助欢迎点赞、收藏、关注。在下一篇文章中我们将深入探讨 LangChain 的另一个核心概念PromptTemplate提示词模板教你如何像写代码一样解耦和管理复杂的提示词。