news 2026/8/7 11:04:13

LangChain 进阶:深度解析模型调用中的消息结构与多轮对话管理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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导入这些类:

Python

from langchain_core.messages import AIMessage, HumanMessage, SystemMessage

2.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 请求参数。

Python

user_input = input(">> 用户:") human_message = HumanMessage(content=user_input)

2.3 AIMessage:捕获模型的产出

AIMessage是调用model.invoke()后返回的对象。它包含了模型生成的文本。

单轮对话中,我们通常只关心AIMessage.content。 但在多轮对话中,整个AIMessage对象(或至少其内容)必须被保存下来,并在下一次发起请求时,连同新的HumanMessage一起发送给模型。

多轮对话原理解析图:

如图所示,多轮对话本质上是不断滚雪球式地将历史消息列表发送给模型。模型本身是不具备记忆功能的(Stateless),记忆是由程序员通过维护这个列表来实现的。

3. 实战案例:构建带角色的命令行客服

光说不练假把式。我们结合SystemMessagetemperature参数,来实现一个真实的客服场景。

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:单次对话助手

Python

import 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( model='Pro/zai-org/GLM-5', model_provider='openai', api_key=os.getenv('SILICONFLOW_API_KEY'), base_url=os.getenv('SILICONFLOW_BASE_URL'), temperature=0.5 ) messages = [ SystemMessage(content="你是一个傲娇的机器人助手,虽然会回答用户问题,但语气要显得不情愿。"), HumanMessage(content="帮我解释一下什么是量子力学。"), ] response = model.invoke(messages) print(response.content)

运行测试:观察模型是否使用了机器人语气,以及当你询问“什么是量子力学”时,它是否会根据 System 规则回复你。下面是我的运行结果。

3.2.2:多轮对话助手

4. 上下文管理优化:限制历史消息数量

上面的代码虽然实现了多轮对话,但存在一个致命缺陷:消息列表会无限增长

随着对话的进行:

  1. 成本飙升:大模型的计费通常基于 Token 数量(输入+输出)。历史越长,每次请求的 Token 数越多。

  2. 速度变慢:模型处理长上下文需要更长的时间。

  3. 甚至报错:每个模型都有上下文窗口限制(e.g., 8K, 32K, 128K Token)。一旦超过限制,请求就会失败。

  4. 干扰严重:过久的、无关的历史消息可能会干扰模型对当前问题的判断。

因此,在实际工程中,我们必须进行上下文管理。最简单直接的方法是:只保留最近 N 轮对话

4.1 实战:保留历史的助手

我们可以利用 Python list 的切片功能轻松实现这一点。通常一轮对话包含一门HumanMessage和一个AIMessage,如果我们想保留最近 3 轮对话,就需要保留最近 6 条消息。

同时,SystemMessage 通常不能被切掉,它必须始终处于列表的第一位。

Python

# ... (前面的初始化代码同上) ... # 这里我们要维护一个“滑动窗口”的思想 def get_messages_for_model(all_messages, limit=6): """ 确保 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(content=user_input)) # 4. 获取修剪后的消息列表用于发送 messages_to_send = get_messages_for_model(messages, limit=6) 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_name="chat_history"), # 这里用来动态插入历史消息 ("human", "{question}"), ])

配合 LangChain 的RunnableWithMessageHistory(将在内存管理章节讲解),可以实现完全自动化的历史消息维护和修剪,无需手动写 Python code 去管理 list。

6. 总结

掌握消息结构是迈向 LangChain 高级开发的第一步。请务必牢记以下几点:

  1. 三剑客:SystemMessage定人设,HumanMessage传意图,AIMessage捕产出。

  2. 多轮对话本质:是状态的维护,是不断把完整的历史消息(雪球)发送给模型。

  3. Temperature:决定模型严谨程度的关键按钮。客服用低温,创意用高温。

  4. 上下文管理:现实项目中必须限制历史长度,兼顾成本、速度和模型注意力。

如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、关注。在下一篇文章中,我们将深入探讨 LangChain 的另一个核心概念:PromptTemplate(提示词模板),教你如何像写代码一样解耦和管理复杂的提示词。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/7 11:03:35

5个实用技巧:让你的普通鼠标在macOS上超越触控板体验

5个实用技巧&#xff1a;让你的普通鼠标在macOS上超越触控板体验 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix Mac Mouse Fix是一款强大的开源…

作者头像 李华
网站建设 2026/8/7 11:02:26

ADC设备全解析:从核心原理到选型设计实战指南

1. 项目概述&#xff1a;ADC设备到底是什么&#xff1f; 如果你在电子、通信或者自动化领域工作&#xff0c;那么“ADC设备”这个词你肯定不陌生。但说实话&#xff0c;对于很多刚入行的朋友&#xff0c;或者跨领域协作的同事来说&#xff0c;它可能就是个模糊的缩写&#xff0…

作者头像 李华
网站建设 2026/8/7 11:02:26

MySQL表字段批量修改实战与优化指南

1. MySQL表字段批量修改的必要性与场景分析 在数据库运维和开发过程中&#xff0c;我们经常遇到需要批量修改表字段的情况。比如最近接手一个老项目&#xff0c;发现用户表里有十几个字段命名不规范&#xff08;user_name vs username&#xff09;&#xff0c;还有字段类型不统…

作者头像 李华
网站建设 2026/8/7 10:59:30

中小企业如何评估企业网站建设可行性分析:从零开始的深度思考与避坑指南

在这个数字化浪潮汹涌的时代,很多老板和创业者的第一反应是:“我要做个网站。” 好像只要有了个网站,生意就稳了,形象就高档了,客户就找上门了。但现实往往是残酷的,很多网站建好后,变成了互联网的“孤岛”,既没有流量,也没有转化,最后只能吃灰。为什么会出现这种情况…

作者头像 李华
网站建设 2026/8/7 10:59:17

CH32F20x MCU电气特性与接口时序实战:从参数解析到信号完整性设计

1. 项目概述&#xff1a;为什么需要深挖MCU的电气与时序&#xff1f; 拿到一颗新的MCU&#xff0c;尤其是像沁恒的CH32F205/207/203这类主打高性价比和高集成度的ARM Cortex-M3内核芯片&#xff0c;很多工程师的第一反应可能是直接打开库函数&#xff0c;对照着例程点灯、调通串…

作者头像 李华