【零基础入门 LLM 开发 · Day 13】:LangChain 的对话记忆------Message 对象版
和 Day 6 是什么关系?
原理一模一样:还是那个"历史列表 + 全量发送"的套路。区别只是------
- Day 6(原生 SDK):历史是字典列表
[{"role": "user", ...}, ...] - 今天(LangChain):历史是对象列表
[HumanMessage(...), AIMessage(...), ...]
框架没变魔术,只是给了你更体面的写法。
完整代码
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
load_dotenv()
llm = ChatOpenAI(
model=os.getenv("YUMC_MODEL_NAME"),
api_key=os.getenv("YUMC_MODEL_API_KEY"),
base_url=os.getenv("YUMC_MODEL_BASE_URL"),
)
# 历史列表:用 SystemMessage 开场定人设
history = [SystemMessage(content="你是一个友好的AI助手,请记住用户告诉你的所有事情。")]
def chat(user_input):
# 1. 把用户的新问题加到历史中
history.append(HumanMessage(content=user_input))
# 2. 把整个历史发给大模型
response = llm.invoke(history)
# 3. 把大模型的回复也加到历史中
history.append(AIMessage(content=response.content))
return response.content
print("-----多轮对话测试-----")
print("你:", "我叫小明,我最喜欢吃火锅。")
print("AI:", chat("我叫小明,我最喜欢吃火锅。"))
print("你:", "你还记得我叫什么名字嘛?我最爱吃什么?")
print("AI:", chat("你还记得我叫什么名字嘛?我最爱吃什么?"))
三种消息对象对照表
| LangChain 对象 | 等价的原生字典 | 谁在说话 |
|---|---|---|
SystemMessage |
{"role": "system", ...} |
导演(人设/规矩) |
HumanMessage |
{"role": "user", ...} |
用户 |
AIMessage |
{"role": "assistant", ...} |
AI |
llm.invoke() 既接受字符串(单轮快速调用),也接受消息列表(多轮记忆),今天用的是后者。
这次代码比 Day 6 好在哪?
- 封装成
chat()函数:记忆逻辑收进一个函数,调用方不用关心实现细节; - 类型化的消息对象 :
HumanMessage(content=...)比{"role": "user", "content": ...}少打字、有补全、拼错角色名会立刻报错(字典写错 role 只会静默失败); - 为后续铺路:Day 14 的链式调用、Day 17 的 Agent 消息管理,都基于这套对象体系。
运行效果
-----多轮对话测试-----
你: 我叫小明,我最喜欢吃火锅。
AI: 你好小明!火锅爱好者你好呀,你最喜欢哪种锅底呢?
你: 你还记得我叫什么名字嘛?我最爱吃什么?
AI: 当然记得,你叫小明,你最喜欢吃火锅。
今日踩坑点
- 漏了第 3 步 append AIMessage:Day 6 的老坑,换了框架照样栽。症状:AI 只记得你说的,不记得自己答过的。
history是全局变量:练习阶段无所谓;真实项目里每个用户/每个会话要独立一份历史(或交给 LangGraph 的 checkpointer 这类组件管理)。- 把字符串直接 append 进历史 :
history.append("你好")会报错,历史里只能放消息对象。
今日小练习
- 必做:把
chat()改造成while True交互循环(参考 Day 6 的 quit 逻辑),并结合 Day 12 的.stream()做流式回复。 - 进阶:写一个
trim_history(max_rounds=5)函数,保留 SystemMessage + 最近 5 轮,控制历史长度。
明日预告
Day 14:让 AI 的输出从"人话"变成"机器能用的 JSON"------结构化输出,提测数据提取、API 联动的第一步。这里埋着本系列最大的一个语法坑。
附录:完整练习代码
memoryTest.py
python
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
load_dotenv()
llm = ChatOpenAI(
model=os.getenv("YUMC_MODEL_NAME"),
api_key=os.getenv("YUMC_MODEL_API_KEY"),
base_url=os.getenv("YUMC_MODEL_BASE_URL"),
)
history = [SystemMessage(content="你是一个友好的AI助手,请记住用户告诉你的所有事情。")]
def chat(user_input):
# 1.把用户的新问题加到历史中
history.append(HumanMessage(content=user_input))
# 2.把整个历史发给大模型
response = llm.invoke(history)
# 3. 把大模型的回复也加到历史中
history.append(AIMessage(content=response.content))
return response.content
print("-----多轮对话测试-----")
print("你:", "我叫小明,我最喜欢吃火锅。")
print("AI:", chat("我叫小明,我最喜欢吃火锅。"))
print("你:", "你还记得我叫什么名字嘛?我最爱吃什么?")
print("AI:", chat("你还记得我叫什么名字嘛?我最爱吃什么?"))