多轮对话系统 - 构建有记忆的 AI 助手
系列文章: System Prompt 实战指南(2/6)
难度: ⭐⭐
预计阅读时间: 20 分钟
一、真实案例引入
1.1 场景:企业内部 IT 支持助手
某科技公司有 500 名员工,IT 部门每天要处理大量重复性问题:
- "我的 VPN 连不上了"
- "忘记了邮箱密码怎么办"
- "新电脑如何配置开发环境"
现状痛点:
- IT 人员疲于应对重复问题
- 员工等待时间长(平均 30 分钟)
- 非工作时间无人响应
解决方案: 构建一个 AI IT 支持助手 (PS: 当然如果用运维Agent来解决此类问题会更加合适)
1.2 用户需求分析
核心需求:
- 记住上下文:用户不想重复说明问题
- 多轮澄清:AI 能主动追问细节
- 角色一致:整个对话保持专业、友好的 IT 专家形象
- 成本可控:Token 消耗不能无限增长
典型对话流程:
用户: 我的 VPN 连不上
AI: 请问您使用的是 Windows 还是 Mac?
用户: Windows
AI: 好的。请问您看到什么错误提示?
用户: 显示"连接超时"
AI: 明白了。这通常是网络配置问题。请按以下步骤操作...
二、问题分析与需求拆解
2.1 核心挑战 1:上下文管理
问题: 如何让 AI "记住"之前的对话?
技术难点:
- 对话历史如何组织?(全部保留 vs 选择性保留)
- 历史对话占用大量 Token,成本快速增长
- 上下文窗口有限(200K tokens),长对话可能超限
解决思路:
- 滑动窗口:只保留最近 N 轮对话
- 智能摘要:压缩历史信息
- 分层记忆:短期记忆 + 长期摘要
2.2 核心挑战 2:角色一致性
问题: 如何确保 AI 在多轮对话中保持同一人设?
常见问题:
- 第 1 轮:专业、正式
- 第 5 轮:突然变得随意、口语化
- 第 10 轮:忘记了自己是 IT 专家
解决思路:
- System Prompt 中明确角色定义
- 使用 Few-shot 示例强化人设
- 定期在对话中"提醒" AI 角色
2.3 核心挑战 3:对话流控制
问题: AI 何时追问?何时给出答案?何时结束对话?
决策点:
- 信息不足 → 追问
- 信息充分 → 给出解决方案
- 问题解决 → 礼貌结束
解决思路:
- System Prompt 中定义对话策略
- 使用结构化输出(如 JSON)标记对话状态
2.4 核心挑战 4:Token 成本控制
问题: 对话越长,Token 消耗越大,成本如何控制?
成本分析:
第 1 轮: System Prompt (500) + User (50) + Assistant (100) = 650 tokens
第 2 轮: System Prompt (500) + 历史 (150) + User (50) + Assistant (100) = 800 tokens
第 10 轮: System Prompt (500) + 历史 (1500) + User (50) + Assistant (100) = 2150 tokens
解决思路:
- Prompt Caching:缓存 System Prompt
- 历史压缩:摘要或删除不重要的轮次
- 智能截断:保留关键信息,删除冗余内容
三、解决方案演进
V1:最简单的多轮对话(10分钟实现)
设计思路: 直接拼接所有历史消息
System Prompt:
SYSTEM_PROMPT_V1 = """
你是一名 IT 支持专家,帮助公司员工解决技术问题。
## 你的特点
- 专业、耐心、友好
- 善于引导用户提供必要信息
- 给出清晰的步骤指导
## 工作流程
1. 理解用户问题
2. 如果信息不足,追问细节
3. 给出解决方案
4. 确认问题是否解决
"""
代码实现:
import anthropic
import os
from dotenv import load_dotenv
load_dotenv()
client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
class SimpleITAssistant:
def __init__(self):
self.messages = [] # 存储所有历史消息
def chat(self, user_input):
# 添加用户消息
self.messages.append({
"role": "user",
"content": user_input
})
# 调用 API
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
system=SYSTEM_PROMPT_V1,
messages=self.messages
)
# 添加 AI 回复到历史
assistant_message = response.content[0].text
self.messages.append({
"role": "assistant",
"content": assistant_message
})
return assistant_message
# 使用示例
assistant = SimpleITAssistant()
print("用户: 我的 VPN 连不上")
print(f"AI: {assistant.chat('我的 VPN 连不上')}\n")
print("用户: Windows 系统")
print(f"AI: {assistant.chat('Windows 系统')}\n")
print("用户: 显示连接超时")
print(f"AI: {assistant.chat('显示连接超时')}\n")
运行效果:
用户: 我的 VPN 连不上
AI: 您好!我来帮您解决 VPN 连接问题。请问您使用的是什么操作系统?Windows 还是 Mac?
用户: Windows 系统
AI: 好的,Windows 系统。请问您看到什么错误提示吗?
用户: 显示连接超时
AI: 明白了。连接超时通常是网络配置问题。请按以下步骤操作:
1. 检查网络连接是否正常
2. 打开 VPN 客户端,点击"设置"...
优点:
- ✅ 实现简单,代码不到 30 行
- ✅ 能记住上下文,对话连贯
- ✅ 角色基本稳定
缺点:
- ❌ Token 消耗线性增长(每轮对话都包含全部历史)
- ❌ 长对话后可能超出上下文窗口
- ❌ 没有成本优化机制
- ❌ 角色偶尔会"跑偏"
V2:优化版(加入上下文管理)
改进点:
- 滑动窗口:只保留最近 N 轮对话
- 对话摘要:压缩历史信息
- Prompt Caching:缓存 System Prompt
System Prompt 改进:
SYSTEM_PROMPT_V2 = """
你是一名 IT 支持专家,帮助公司员工解决技术问题。
## 你的特点
- 专业、耐心、友好
- 善于引导用户提供必要信息
- 给出清晰的步骤指导
## 对话策略
- 每次回答前,先回顾用户已提供的信息
- 如果信息不足,明确指出缺少什么,然后追问
- 给出解决方案时,使用编号列表,步骤清晰
- 问题解决后,询问"还有其他问题吗?"
## 输出格式
使用以下结构回答:
**理解:** [总结用户问题和已知信息]
**回答:** [你的回答或追问]
**下一步:** [引导用户下一步操作]
"""
代码实现:
完整代码见 code/v2_optimized.py
效果对比:
| 轮次 | V1 Token 消耗 | V2 Token 消耗 | 节省 |
|---|---|---|---|
| 第 1 轮 | 650 | 650 | 0% |
| 第 5 轮 | 1,200 | 800 | 33% |
| 第 10 轮 | 2,150 | 900 | 58% |
| 第 20 轮 | 4,000 | 950 | 76% |
改进效果:
- ✅ Token 消耗可控(不再线性增长)
- ✅ 使用 Prompt Caching,成本降低 90%
- ✅ 对话结构更清晰
- ✅ 角色更稳定
仍存在的问题:
- ❌ 删除旧对话可能丢失关键信息
- ❌ 没有智能摘要机制
- ❌ 缺少异常处理
- ❌ 没有会话持久化
V3:生产级方案
完整代码见 code/v3_production.py
核心特性:
- ✅ 智能摘要:自动压缩历史对话
- ✅ 分层记忆:短期(最近对话)+ 长期(摘要)
- ✅ 会话持久化:可保存和恢复
- ✅ 异常处理:网络错误、API 限流
- ✅ 监控指标:Token、成本、缓存命中率
四、关键技术点深度剖析
4.1 上下文窗口策略对比
| 策略 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 固定窗口 | 实现简单,Token 可控 | 可能丢失关键信息 | 短对话(<10轮) |
| 滑动窗口 | 保持对话完整性 | 仍可能丢失早期信息 | 中等对话(10-20轮) |
| 智能摘要 | 保留关键信息,Token 可控 | 需要额外 API 调用 | 长对话(>20轮) |
4.2 角色一致性技巧
技巧 1:详细的人设描述
- 包含背景、性格、说话风格
- 使用具体的例子而非抽象描述
技巧 2:Few-shot 示例
- 在 System Prompt 中提供 2-3 个示例对话
- 展示期望的回答风格
技巧 3:定期"提醒"
- 在摘要中重申角色身份
- 每隔几轮对话强化人设
4.3 对话流控制模式
模式 1:状态机
states = ["收集信息", "诊断问题", "提供方案", "验证结果"]
模式 2:结构化输出
{
"stage": "collecting_info",
"next_question": "请问您使用的操作系统?",
"confidence": 0.3
}
五、生产环境注意事项
5.1 并发会话管理
- 每个用户独立的会话 ID
- 使用 Redis 等缓存存储会话状态
- 设置会话超时(如 30 分钟无活动自动清理)
5.2 异常情况处理
- API 限流:实现重试机制(指数退避)
- 网络超时:设置合理的超时时间
- 用户辱骂:检测并礼貌引导
5.3 监控指标
- Token 消耗趋势
- 平均对话轮次
- 问题解决率
- 用户满意度
六、性能优化与成本控制
6.1 Prompt Caching 最佳实践
何时使用:
- System Prompt > 1024 tokens
- 短时间内多次调用(< 5 分钟)
- 内容相对固定
成本对比:
无缓存:$0.003/1K tokens
缓存创建:$0.00375/1K tokens(+25%)
缓存读取:$0.0003/1K tokens(-90%)
投资回报:
- 第 1 次调用:多花 25%
- 第 2 次及以后:节省 90%
- 2 次调用即回本
6.2 Token 优化技巧
-
压缩 System Prompt
- 删除冗余说明
- 使用简洁的语言
- 避免重复的示例
-
智能截断历史
- 保留关键信息(问题描述、解决方案)
- 删除寒暄、重复内容
-
使用摘要
- 10 轮对话 → 1 条摘要(节省 80% Token)
6.3 成本分析
案例:1000 个用户,每人平均 10 轮对话
| 方案 | 平均 Token/轮 | 总 Token | 成本 |
|---|---|---|---|
| V1(无优化) | 1,500 | 15M | $45 |
| V2(滑动窗口) | 900 | 9M | $27 |
| V3(智能摘要+缓存) | 600 | 6M | $12 |
节省: V3 比 V1 节省 73% 成本
七、关键要点总结
-
上下文管理是核心
- 选择合适的策略(固定窗口 vs 滑动窗口 vs 智能摘要)
- 根据对话长度动态调整
-
Prompt Caching 是必备
- 2 次调用即回本
- 节省 90% 的 System Prompt 成本
-
角色一致性需要设计
- 详细的人设描述
- Few-shot 示例
- 定期强化
-
生产环境要考虑全面
- 异常处理
- 会话持久化
- 监控指标
-
成本优化有方法
- 智能摘要
- Token 压缩
- 缓存策略
附录:完整代码
所有代码示例位于 code/ 目录:
v1_simple.py- V1 简单实现v2_optimized.py- V2 优化版v3_production.py- V3 生产级utils.py- 工具函数
下一篇预告: 《内容创作系统 - 打造你的 AI 写作伙伴》
我们将探讨如何控制 AI 的写作风格、实现结构化输出、平衡创意与约束。敬请期待!
本文是《System Prompt 实战指南》系列的第 2 篇(共 6 篇)
发布日期:2026-05-08

浙公网安备 33010602011771号