# 03 - Messages: 消息类型与对话管理
# 核心要点(只讲难点)
# 初始化模型
from init_model import get_chat_model
chat_model = get_chat_model()
# 角色 字典格式 对象格式 用途
# System {"role": "system", ...} SystemMessage(...) 系统提示
# User {"role": "user", ...} HumanMessage(...) 用户输入
# Assistant {"role": "assistant", ...} AIMessage(...) AI 回复
# 推荐:直接用字典,简洁!
def demo1():
message = [
{"role": "system", "content": "你是一个专业的编程导师,擅长解释复杂概念。"},
{"role": "user", "content": "什么是列表?"},
]
# ❌ 不推荐(太啰嗦)
from langchain_core.messages import SystemMessage, HumanMessage
messages = [SystemMessage(content="你是助手"), HumanMessage(content="你好")]
# 2. 对话历史管理(核心难点)
# 🔴 关键规则
# 每次调用必须传递完整的对话历史!
def demo2():
# 第一次
r1 = chat_model.invoke("我叫张三")
# 第二次(没传历史)
r2 = chat_model.invoke("我叫什么?") # AI 不记得!
# ✅ 正确做法
def demo3():
conversation = []
conversation.append({"role": "user", "content": "我叫张三"})
r1 = chat_model.invoke(conversation)
conversation.append({"role": "assistant", "content": r1.content})
# 第二次(传递完整历史)
conversation.append({"role": "user", "content": "我叫什么?"})
r2 = chat_model.invoke(conversation) # AI 记得!
# 3. 对话历史优化(避免太长)
# 🔴 问题
# 对话历史会越来越长,消耗大量 tokens 和成本。
# ✅ 解决方案
# 只保留最近 N 轮对话:
def keep_recent_messages(messages, max_pairs=2):
"""
保留最近的 N 轮对话
max_pairs: 保留的对话轮数(每轮 = user + assistant)
"""
if not messages:
return []
# 1. 处理 System 消息:通常只保留第一条作为系统指令
# 如果你的业务逻辑需要保留所有 system 消息,可以改回原来的列表推导式
system_msg = next((m for m in messages if m.get("role") == "system"), None)
# 2. 提取纯对话流 (排除 system)
conversation = [m for m in messages if m.get("role") != "system"]
if not conversation:
return [system_msg] if system_msg else []
# 3. 智能截取最近对话
# 我们需要保留最多 max_pairs 轮。
# 一轮定义为:User -> Assistant
# 特殊情况:最后一条如果是 User,也要保留(即使没有对应的 Assistant)
recent_conversation = []
pairs_found = 0
# 从后往前遍历,每次找到 User 就添加它和对应的 Assistant(如果有)
i = len(conversation) - 1
while i >= 0 and pairs_found < max_pairs:
current_msg = conversation[i]
# 如果是 Assistant 消息
if current_msg.get("role") == "assistant":
# 尝试找前一条是否为 User
if i > 0 and conversation[i - 1].get("role") == "user":
# 找到完整的一对
recent_conversation.insert(0, conversation[i - 1])
recent_conversation.insert(1, current_msg)
pairs_found += 1
i -= 2
else:
# 孤立的 Assistant 消息(异常情况),单独保留或跳过?
# 这里选择保留它以防丢失上下文,但不计入完整轮数
recent_conversation.insert(0, current_msg)
i -= 1
else:
# 如果是 User 消息
# 情况 A: 它是最后一条消息(当前正在提问),必须保留
# 情况 B: 它是某轮的开始,但后面没有 Assistant(数据损坏),保留
# 只要还没凑够 max_pairs,且这是剩下的最后一条 User,就保留
if pairs_found < max_pairs:
recent_conversation.insert(0, current_msg)
i -= 1
# 4. 组装结果
result = []
if system_msg:
result.append(system_msg)
result.extend(recent_conversation)
return result
conversation_history = [
{"role": "system", "content": "你是一个助手"},
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好!有什么事吗?"},
{"role": "user", "content": "今天天气如何"},
{"role": "assistant", "content": "天气不错"},
{"role": "user", "content": "那明天呢?"}, # 当前最新的问题,尚未回答
]
# 使用
optimized = keep_recent_messages(conversation_history, max_pairs=5)
response = chat_model.invoke(optimized)
# 核心总结
# 要点 说明
# 格式 用字典,不用消息对象
# 历史 每次必须传递完整历史
# 保存 必须保存 AI 的回复
# 优化 只保留最近 N 轮
# System 总是保留 system 消息