多轮对话系统 - 构建有记忆的 AI 助手

系列文章: System Prompt 实战指南(2/6)
难度: ⭐⭐
预计阅读时间: 20 分钟


一、真实案例引入

1.1 场景:企业内部 IT 支持助手

某科技公司有 500 名员工,IT 部门每天要处理大量重复性问题:

  • "我的 VPN 连不上了"
  • "忘记了邮箱密码怎么办"
  • "新电脑如何配置开发环境"

现状痛点:

  • IT 人员疲于应对重复问题
  • 员工等待时间长(平均 30 分钟)
  • 非工作时间无人响应

解决方案: 构建一个 AI IT 支持助手 (PS: 当然如果用运维Agent来解决此类问题会更加合适)

1.2 用户需求分析

核心需求:

  1. 记住上下文:用户不想重复说明问题
  2. 多轮澄清:AI 能主动追问细节
  3. 角色一致:整个对话保持专业、友好的 IT 专家形象
  4. 成本可控: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:优化版(加入上下文管理)

改进点:

  1. 滑动窗口:只保留最近 N 轮对话
  2. 对话摘要:压缩历史信息
  3. 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

核心特性:

  1. ✅ 智能摘要:自动压缩历史对话
  2. ✅ 分层记忆:短期(最近对话)+ 长期(摘要)
  3. ✅ 会话持久化:可保存和恢复
  4. ✅ 异常处理:网络错误、API 限流
  5. ✅ 监控指标: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 优化技巧

  1. 压缩 System Prompt

    • 删除冗余说明
    • 使用简洁的语言
    • 避免重复的示例
  2. 智能截断历史

    • 保留关键信息(问题描述、解决方案)
    • 删除寒暄、重复内容
  3. 使用摘要

    • 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% 成本


七、关键要点总结

  1. 上下文管理是核心

    • 选择合适的策略(固定窗口 vs 滑动窗口 vs 智能摘要)
    • 根据对话长度动态调整
  2. Prompt Caching 是必备

    • 2 次调用即回本
    • 节省 90% 的 System Prompt 成本
  3. 角色一致性需要设计

    • 详细的人设描述
    • Few-shot 示例
    • 定期强化
  4. 生产环境要考虑全面

    • 异常处理
    • 会话持久化
    • 监控指标
  5. 成本优化有方法

    • 智能摘要
    • 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

posted @ 2026-05-08 13:51  拉耶维奇  阅读(95)  评论(0)    收藏  举报