LangChain 入门系列 · 第 2 章
第02章 模型调用与消息结构
目录
- 1. 本章目标
- 2. 为什么需要消息结构
- 3. 常见消息角色
- 4. system 消息
- 5. human 消息
- 6. ai 消息
- 7. 案例一:客服角色助手
- 8. 模型参数
- 9. 案例二:带上下文的命令行客服助手
- 10. 多轮对话的注意事项
- 11. 案例三:限制历史消息数量
- 12. 多轮对话的后续写法
- 13. 本章重点
- 14. 常见问题
1. 本章目标
上一章我们完成了 LangChain 环境搭建,并使用 DeepSeek 模型完成了第一次调用。
本章继续学习模型调用中最常用的内容:消息结构。
学完本章后,你应该能够:
- 理解模型调用中的
role - 使用
system消息控制助手角色 - 使用
human消息传递用户问题 - 保存 AI 回复并形成多轮对话
- 设置常用模型参数
- 实现一个带上下文的命令行客服助手
2. 为什么需要消息结构
上一章中,我们直接传入了字符串:
response=model.invoke("请用一句话介绍 LangChain 的作用")这种写法可以运行,但在真实项目中不够灵活。
因为我们经常需要告诉模型:
- 你是什么角色
- 回答要遵守什么规则
- 用户问了什么问题
- 前面聊过什么内容
这时就需要使用消息结构。
3. 常见消息角色
大模型对话中常见 3 类消息:
| 角色 | 作用 |
|---|---|
system | 设置模型角色、规则和回答风格 |
human | 用户输入 |
ai | 模型回复 |
- SystemMessage(系统消息):开发者设定 —— AI 是谁、能干啥、不能干啥、输出格式、语气、专业规则。
- HumanMessage(用户消息):普通人提问、需求、问题。
- AIMessage(AI 回复):大模型返回的内容。
LangChain 中常用的消息类:
fromlangchain_core.messagesimportAIMessage,HumanMessage,SystemMessage示例:
messages=[SystemMessage(content="你是一名客服助手,回答要礼貌、简洁。"),HumanMessage(content="我的订单什么时候发货?"),]response=model.invoke(messages)print(response.content)4. system 消息
SystemMessage= 给 AI 定好永久身份、规则、行事标准。
在一轮对话最开头发给模型,优先级高于用户所有提问(HumanMessage),全程生效。
对应 OpenAI 接口里role: "system"。
SystemMessage用来设定助手的角色和规则。例如:
SystemMessage(content="你是一名 Python 讲师,回答要适合初学者。")常见用途:
- 限定角色
- 限定语气
- 限定回答长度
- 限定输出要求
- 限定不能回答的范围
第一阶段不用写特别复杂的 system 规则。规则太多,模型反而可能执行不稳定。
5. human 消息
HumanMessage表示用户输入。
HumanMessage(content="我的订单什么时候发货?")实际项目中,用户输入通常来自:
- 命令行输入
- Web 页面输入框
- App 聊天框
- API 请求参数
本章先用命令行输入演示。
6. ai 消息
AIMessage表示模型回复。
AIMessage(content="您的订单预计 24 小时内发货,请提供订单号以便查询。")在多轮对话中,需要把模型回复加入历史消息:
messages=[SystemMessage(content="你是一名客服助手,回答要礼貌、简洁。"),HumanMessage(content="我的订单什么时候发货?"),AIMessage(content="请提供您的订单号,我帮您查询发货状态。"),HumanMessage(content="订单号是 123456。"),]这样下一次调用模型时,模型就能看到之前的回答。
7. 案例一:客服角色助手
本案例使用system消息控制模型角色。
创建01_customer_service.py:
fromlangchain_openaiimportChatOpenAIfromlangchain_core.messagesimportSystemMessage,HumanMessage# 初始化模型(上一章已配置好 DeepSeek,此处用环境变量管理 Key 更规范)importos model=ChatOpenAI(model="deepseek-chat",api_key=os.getenv("DEEPSEEK_API_KEY"),base_url="https://api.deepseek.com/v1",)# 用 system 消息设定客服角色messages=[SystemMessage(content="你是一名电商客服助手,回答要礼貌、简洁,并提醒用户提供订单号。"),HumanMessage(content="我的订单什么时候发货?"),]response=model.invoke(messages)print(response.content)运行:
python 01_customer_service.py这个案例重点观察:
- 模型是否使用客服语气
- 模型是否提醒用户提供订单号
8. 模型参数
模型调用时可以设置一些常用参数。
| 参数 | 作用 |
|---|---|
temperature | 控制回答随机性 |
temperature 温度参数详解
1. 核心作用
temperature控制大模型输出的随机性、创造性、幻觉程度,取值范围:0 ~ 2
- 越接近 0:输出固定、严谨、重复度高,几乎不瞎编;
- 越接近 2:脑洞大、自由发挥、容易编造不存在内容。
2. 分段取值对应场景
temperature = 0:完全确定性,相同输入每次返回一模一样的答案。
适用:代码生成、RAG 知识库问答、数据提取、订单查询、数学计算,杜绝 AI 瞎编。temperature = 0.1 ~ 0.4:轻微随机,逻辑稳定,极少幻觉,偶尔措辞略有差别,内容不会乱编。
最适合场景:客服问答、RAG、文档解析、结构化信息提取、写规范代码。temperature = 0.5 ~ 0.8:平衡创意与逻辑,适合文案、总结、普通聊天。temperature ≥ 1.0:高创造性,适合写故事、诗歌、创意文案,容易出现虚构内容。
示例:
model=ChatOpenAI(model="deepseek-chat",temperature=0.3,# 客服场景:低随机、少幻觉)建议:
- 问答、客服、知识库:
temperature可以低一些 - 文案、创意、改写:
temperature可以高一些
不要在第一阶段追求太多参数。先掌握
temperature就够用了。
9. 案例二:带上下文的命令行客服助手
本案例实现一个可以连续对话的客服助手。
创建02_chat_with_history.py:
fromlangchain_openaiimportChatOpenAIfromlangchain_core.messagesimportSystemMessage,HumanMessage,AIMessageimportos model=ChatOpenAI(model="deepseek-chat",api_key=os.getenv("DEEPSEEK_API_KEY"),base_url="https://api.deepseek.com/v1",)# 系统设定,全程生效;后续消息不断追加到列表中messages=[SystemMessage(content="你是一名电商客服助手,回答要礼貌、简洁。"),]print("客服助手已启动,输入 exit 退出")whileTrue:user_input=input("你:")ifuser_input.lower()=="exit":breakmessages.append(HumanMessage(content=user_input))response=model.invoke(messages)reply=response.contentprint("客服:",reply)# 把 AI 回复也加入历史,下一次调用模型就能看到前面的对话messages.append(AIMessage(content=reply))运行:
python 02_chat_with_history.py可以按下面方式测试:
你:我的订单到哪了? 客服:请提供您的订单号,我帮您查询物流状态。 你:订单号 123456 客服:订单 123456 已发货,预计明天送达。因为程序保存了历史消息,所以模型能看到前面的对话内容。
10. 多轮对话的注意事项
保存历史消息很有用,但不能无限保存。
原因:
- 消息越多,请求成本越高
- 上下文太长,模型处理速度会变慢
- 超过模型上下文限制后可能报错
- 很早之前的消息可能干扰当前回答
本章先使用最简单的方式保存所有历史。
后续课程会再讲如何控制上下文长度。
11. 案例三:限制历史消息数量
为了避免历史消息无限增长,可以只保留最近几轮对话。
创建03_chat_with_limited_history.py:
fromlangchain_openaiimportChatOpenAIfromlangchain_core.messagesimportSystemMessage,HumanMessage,AIMessageimportos model=ChatOpenAI(model="deepseek-chat",api_key=os.getenv("DEEPSEEK_API_KEY"),base_url="https://api.deepseek.com/v1",)history=[SystemMessage(content="你是一名电商客服助手,回答要礼貌、简洁。"),]print("客服助手已启动(仅保留最近 3 轮对话),输入 exit 退出")whileTrue:user_input=input("你:")ifuser_input.lower()=="exit":breakhistory.append(HumanMessage(content=user_input))response=model.invoke(history)reply=response.contentprint("客服:",reply)history.append(AIMessage(content=reply))# 只保留最近 6 条消息history=history[-6:]这里的:
history=history[-6:]表示只保留最近 6 条历史消息。
通常一轮对话包含:
- 用户消息
- AI 回复
所以 6 条消息大约是最近 3 轮对话。
复习:list 的切片用法
list[-n:]取末尾 n 个元素。
12. 多轮对话的后续写法
本章通过下面的方式手动组织消息:
messages=[SystemMessage(content="..."),HumanMessage(content="..."),AIMessage(content="..."),]这种写法简单直观,适合先理解多轮对话的基本原理。
后面学习ChatPromptTemplate时,还可以使用:
fromlangchain_core.promptsimportChatPromptTemplate prompt=ChatPromptTemplate.from_messages([("system","你是一名客服助手,回答要礼貌、简洁。"),("placeholder","{history}"),# 历史消息占位("human","{question}"),# 当前问题占位])chain=prompt|model response=chain.invoke({"history":[HumanMessage(content="..."),AIMessage(content="...")],"question":"我的订单到哪了?",})在 Prompt 模板中预留历史消息的位置。其中:
history用来接收以前的HumanMessage和AIMessagequestion表示用户当前的问题
本章只需要知道它可以更方便地插入历史消息,具体用法和完整案例会在下一章 Prompt 模板中讲。
13. 本章重点
本章最重要的是掌握:
- 模型调用可以传字符串,也可以传消息列表
SystemMessage用来设置角色和规则HumanMessage表示用户输入AIMessage表示模型回复- 多轮对话需要保存历史消息
- 历史消息不能无限增长
temperature可以影响回答稳定性
14. 常见问题
14.1 为什么模型没有严格按 system 规则回答
大模型不是传统程序。
System 规则能提高模型按要求回答的概率,但不能保证百分百执行。
如果要求很重要,后续可以结合:
- 更清晰的 Prompt
- 结构化输出
- 程序校验
- 后处理逻辑
14.2 为什么多轮对话越来越慢
因为每次请求都带上了历史消息。
历史越长,请求内容越多。
可以限制历史消息数量,例如:
# 只保留最近 6 条(约 3 轮)消息history=history[-6:]✍️ 如有问题,欢迎在评论区交流。