news 2026/7/23 3:20:54

LangChain 实战第 2 章:搞懂消息结构,写出会“记住对话“的客服助手

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LangChain 实战第 2 章:搞懂消息结构,写出会“记住对话“的客服助手

LangChain 实战第 2 章:搞懂消息结构,写出会"记住对话"的客服助手

📌 这是系列第 2 篇。上一篇我们已经搭好 Python 环境、配好 DeepSeek、跑通了第一次模型调用。这一篇往上走一步:学会用消息结构和模型聊天,并做出一个能连续对话的命令行客服。

一、本章目标

学完这一章,你应该能够:

  • 理解模型调用里role(角色)是什么
  • system消息控制"助手是谁"
  • human消息把用户问题传给模型
  • ai回复存起来,形成多轮对话
  • 设置最常用的模型参数temperature
  • 亲手实现一个带上下文的命令行客服助手

二、为什么不能只传字符串?

上一章我们是这样调用的:

response = model.invoke("请用一句话介绍 LangChain 的作用")

这样能跑,但在真实项目里不够灵活。因为实际场景我们经常要同时告诉模型:

  • 你是什么角色(客服?讲师?翻译?)
  • 回答要遵守什么规则(语气、长度、格式)
  • 用户现在问了什么
  • 前面已经聊过什么

把这些信息全塞进一个字符串里,既难维护又容易出错。更好的办法,是把它们拆成结构化的消息传给模型。

三、三种消息角色:system / human / ai

大模型对话里有三类最常出现的消息:

角色作用
system设置模型的角色、规则和回答风格
human用户的输入
ai模型的回复
  • SystemMessage(系统消息):开发者设定——AI 是谁、能干啥、不能干啥、用什么语气、输出什么格式。
  • HumanMessage(用户消息):普通人的提问、需求、问题。
  • AIMessage(AI 回复):大模型返回的内容。

在 LangChain 里,这三个类是这样导入的:

from langchain_core.messages import AIMessage, HumanMessage, SystemMessage

拼一组消息也很直观:

messages = [ SystemMessage(content="你是一名客服助手,回答要礼貌、简洁。"), HumanMessage(content="我的订单什么时候发货?"), ]

💡 记住这个组合:system 定规则,human 提问题,ai 记回答。后面所有对话都建立在它之上。

四、SystemMessage:给 AI 定身份和规矩

SystemMessage相当于在对话最开头,给 AI 立好"永久人设":

  • 在一轮对话最前面发给模型
  • 优先级高于用户的所有提问HumanMessage
  • 整轮对话全程生效

它对应 OpenAI 接口里的role: "system"。常见用途有:

  • 限定角色(你是电商客服 / Python 讲师)
  • 限定语气(礼貌、专业、口语化)
  • 限定回答长度
  • 限定输出格式(JSON、分点、不超过 N 字)
  • 限定不能回答的范围

示例:

SystemMessage(content="你是一名 Python 讲师,回答要适合初学者。")

⚠️ 新手建议:第一阶段的 system 规则别写太长太复杂。规则一多,模型反而可能执行不稳定。先把"角色 + 一句要求"写清楚就够用了。

五、HumanMessage:把用户的话传进去

HumanMessage表示用户输入,也就是"用户说了什么"。

HumanMessage(content="我想查询订单物流")

真实项目里,用户输入通常来自这些地方:

  • 命令行输入
  • Web 页面的输入框
  • App 的聊天框
  • 后端 API 的请求参数

本章先用命令行输入来演示,最容易看懂原理。

六、AIMessage:模型的回复,也是下一轮的"记忆"

AIMessage表示模型回复。它不只是"拿到答案就完事"——在多轮对话里,必须把模型回复也加进历史消息,否则模型根本不知道之前聊过什么。

messages.append(AIMessage(content=response.content))

加上这一行后,下一次调用模型时,它就能"看到"自己上一次的回答,对话才连得起来。

七、案例一:一句话定好客服人设

system消息控制模型角色。创建01_customer_service.py

import os from dotenv import load_dotenv from langchain.chat_models import init_chat_model from langchain_core.messages import HumanMessage, SystemMessage load_dotenv() model = init_chat_model( model="deepseek-v4-flash", model_provider="openai", api_key=os.getenv("DEEPSEEK_API_KEY"), base_url=os.getenv("DEEPSEEK_BASE_URL"), temperature=0.5, ) messages = [ SystemMessage( content=( "你是一名电商客服助手。" "回答要礼貌、简洁。" "如果用户没有提供订单号,就提醒用户提供订单号。" ) ), HumanMessage(content="我的快递怎么还没到?"), ] response = model.invoke(messages) print(response.content)

运行:

python 01_customer_service.py

重点观察两点:模型是否用了客服语气?是否提醒你提供订单号?

八、模型参数 temperature:控制"稳重"还是"脑洞"

temperature是最常用、也最该先搞懂的模型参数。它控制输出的随机性、创造性、幻觉程度,取值范围0 ~ 2

  • 越接近0:输出固定、严谨、重复度高,几乎不瞎编;
  • 越接近2:脑洞大、自由发挥,容易编造不存在的内容。
取值区间特点适合场景
= 0完全确定性,同输入同输出代码生成、RAG 知识库问答、数据提取、订单查询、数学计算
0.1 ~ 0.4轻微随机,逻辑稳、极少幻觉客服问答、RAG、文档解析、结构化提取、规范代码
0.5 ~ 0.8创意与逻辑平衡文案、总结、普通聊天
≥ 1.0高创造性,易虚构写故事、诗歌、创意文案

设置方式就是把temperature传给init_chat_model

model = init_chat_model( model="deepseek-v4-flash", model_provider="openai", api_key=os.getenv("DEEPSEEK_API_KEY"), base_url=os.getenv("DEEPSEEK_BASE_URL"), temperature=0.3, )

💡 经验值:问答 / 客服 / 知识库temperature调低(0.1~0.4);文案 / 创意 / 改写可以调高(0.7~1.0)。第一阶段先把temperature用熟就够了,别一上来追一堆参数。

九、案例二:能连续对话的命令行客服

上面案例每次都只问一句话。真实客服要能"接着聊"。核心思路:把每一轮的用户提问和模型回复都存进messages列表

创建02_chat_with_history.py

import os from dotenv import load_dotenv from langchain.chat_models import init_chat_model from langchain_core.messages import SystemMessage, HumanMessage, AIMessage load_dotenv() model = init_chat_model( base_url=os.getenv("DEEPSEEK_BASE_URL"), api_key=os.getenv("DEEPSEEK_API_KEY"), model="deepseek-v4-flash", temperature=0.5, model_provider="openai" ) messages = [ SystemMessage(content="你是一个快递客服,回答问题要有礼貌,假如对方没有提供单号,请让其先提供快递单号") ] while True: question = input("用户:") if question == "exit": break messages.append(HumanMessage(content=question)) response = model.invoke(messages) print("客服的回答:" + response.content) messages.append(AIMessage(content=response.content))

运行:

python 02_chat_with_history.py

可以这样测试:

用户:我要查物流 用户:订单号是 A10086 用户:那我可以申请退款吗?

因为程序把历史消息都保留了,模型能看到前面的对话,所以第三问它才知道你在说"刚才那个订单"。

十、多轮对话的坑:历史不能无限堆

保存历史消息很有用,但不能无限制地一直存。原因很现实:

  • 消息越多,每次请求花的钱越多
  • 上下文太长,模型处理速度变慢
  • 超过模型上下文上限会直接报错
  • 太早的消息可能干扰当前回答

本章先用"保存全部历史"这种最简单的方式。后面会专门讲怎么控制上下文长度。

十一、案例三:只保留最近几轮

为了避免历史无限增长,可以只保留最近几条消息。创建03_chat_with_limited_history.py

import os from dotenv import load_dotenv from langchain.chat_models import init_chat_model from langchain_core.messages import SystemMessage, HumanMessage, AIMessage load_dotenv() model = init_chat_model( base_url=os.getenv("DEEPSEEK_BASE_URL"), api_key=os.getenv("DEEPSEEK_API_KEY"), model="deepseek-v4-flash", temperature=0.5, model_provider="openai" ) system = SystemMessage(content="你是一个快递客服,回答问题要有礼貌,假如对方没有提供单号,请让其先提供快递单号") history = [] while True: question = input("用户:") if question.lower() == "exit": break history.append(HumanMessage(content=question)) print("history 的长度是:" + str(len(history))) messages = [system] + history[-6:] response = model.invoke(messages) print("客服的回答:" + response.content) history.append(AIMessage(content=response.content))

关键在这一行:

messages = [system] + history[-6:]

history[-6:]表示只取最后 6 条历史消息。因为一轮对话通常包含"用户消息 + AI 回复"两条,所以 6 条 ≈ 最近 3 轮对话。

📘 顺手复习一下 list 切片(后面会经常用):

# lst[start:end:step],索引从 0 开始 a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(a[:4]) # [0, 1, 2, 3] print(a[3:]) # [3, 4, 5, 6, 7, 8, 9] print(a[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 倒序 print(a[::2]) # [0, 2, 4, 6, 8] 隔一个取 print(a[-1]) # 9 最后一位 print(a[-6:]) # [4, 5, 6, 7, 8, 9] 最后六个

十二、进阶预告:用模板更优雅地插历史

本章我们是手动拼消息的:

messages = [system_message] + history[-6:]

这种写法直观,适合先理解原理。等学到ChatPromptTemplate,可以用MessagesPlaceholder在模板里预留历史消息的位置,更省心:

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder prompt_template = ChatPromptTemplate.from_messages( [ ("system", "你是一名电商客服助手,回答要礼貌、简洁。"), MessagesPlaceholder(variable_name="history"), ("human", "{question}"), ] )

其中:

  • history用来接收以前的HumanMessageAIMessage
  • question表示用户当前的问题

本章只要知道"有这种更方便的写法"就行,完整用法下一章讲 Prompt 模板时展开。

十三、本章重点(速记)

  • 模型调用既可以传字符串,也可以传消息列表
  • SystemMessage设置角色和规则
  • HumanMessage表示用户输入
  • AIMessage表示模型回复
  • 多轮对话必须保存历史消息
  • 历史消息不能无限增长(用history[-6:]截断)
  • temperature影响回答的稳定性和创造性

十四、常见问题

Q1:为什么模型没严格按 system 规则回答?大模型不是传统if/else程序。system 规则能提高"按要求回答"的概率,但不保证 100% 执行。如果要求很重要,后续可以配合:更清晰的 Prompt、结构化输出、程序校验、后处理逻辑来兜底。

Q2:为什么多轮对话越来越慢?因为每次请求都把历史消息一起发给了模型。历史越长,请求内容越多、越慢。解决办法就是限制历史数量,例如history[-6:]

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

没有完美的系统:辩证法视角下的计算机架构演进与实践论

可用的系统,并且这种系统也需要随着现实情况的变化,而调整乃至于重构其自身。所以,整个系统不能看成是绝对稳定的,系统的架构会随着各种各样内外部条件的变化而不断演进,其总有着发生变化的趋势。由此可见,…

作者头像 李华
网站建设 2026/7/23 3:18:23

粉笔刷题App 与华图在线题库对比:客观评测与选型参考

引言:公考刷题工具的选型逻辑 公考报名人数持续走高。根据国家公务员局公布的数据,2024 年国考报名人数突破 300 万,平均竞争比约 77:1,部分热门岗位竞争比更高。在这样高强度的竞争环境下,刷题几乎是每一位考生的必修…

作者头像 李华
网站建设 2026/7/23 3:15:35

Grok AI助手:从代码审查到架构设计的全方位开发效率提升指南

最近在AI圈里有个很有意思的现象:大家都在讨论大模型的能力边界,但真正能让人眼前一亮的实用工具却不多。直到看到Elon Musk对Grok的评价——"可靠的多面手",这个描述让我开始重新审视这个AI助手到底能做什么。很多人可能以为Grok只…

作者头像 李华
网站建设 2026/7/23 3:15:33

Qwen3.8模型代码生成与长文档处理技术解析

上周,当国内开发者社区还在讨论如何优化开源模型部署流程时,一条消息迅速传开:月之暗面与阿里巴巴联手发布了新一代模型。这个合作之所以引起广泛关注,不仅因为两家公司的技术背景,更因为它在多项关键指标上表现出的能…

作者头像 李华
网站建设 2026/7/23 3:15:08

计算机毕业设计之基于SpringBoot的社区论坛系统的设计与实现

近些年来,随着科技的飞速发展,互联网的普及逐渐延伸到各行各业中,给人们生活带来了十分的便利,社区论坛系统利用计算机网络实现信息化管理,使整个社区论坛系统的发展和服务水平有显著提升。本文拟采用Eclipse开发工具&…

作者头像 李华
网站建设 2026/7/23 3:14:58

Spring Boot 3 + Vue 3 + MySQL 动漫推荐管理系统源码前后端分离实战

一、项目简介 动漫推荐管理系统是一套基于 Spring Boot 3 Vue 3 的前后端分离系统,提供动漫浏览、播放、收藏、评论及个性化推荐功能。系统包含普通用户端与管理员端两个角色,普通用户可浏览番剧、观看剧集、收藏动漫、发表评论、查看观看历史&#xf…

作者头像 李华