一个完整的AI聊天机器人记忆管理解决方案,包含4种压缩策略和完整的性能测试数据
本项目实现了一个生产级的AI聊天机器人记忆系统,解决了对话历史管理中的核心问题:
- ✅ 如何高效存储对话历史
- ✅ 如何在Token限制下保留关键信息
- ✅ 如何平衡速度、成本和信息保留
核心特性:
- 🚀 4种压缩策略(滑动窗口、LLM摘要、混合策略、Token动态)
- 📊 完整的性能测试和对比数据
- 🎯 真实场景的最佳实践建议
- 💡 反直觉的发现和工程智慧
通过大量测试,我们发现了一些反直觉的结果:
短对话(5轮,126 tokens):
- 原始:126 tokens
- LLM摘要后:303 tokens(增加141%!)❌
结论:只有≥30轮时,LLM摘要才有正收益
滑动窗口(最简单):
✅ Token最少(145)
✅ 速度最快(0.00ms)
✅ 成本最低($0)
✅ 最可靠
LLM摘要(最智能):
❌ Token最多(597)
❌ 速度最慢(11,663ms)
❌ 成本最高($0.0001/次)
结论:80%场景用最简单的方案就够了
| 策略 | Token | 速度 | 成本 | 信息保留 |
|---|---|---|---|---|
| 滑动窗口 | ⭐最少 | ⭐最快 | ⭐$0 | ❌0% |
| LLM摘要 | ❌最多 | ❌最慢 | ❌最贵 | ⭐100% |
| 混合策略 | 中等 | 视情况 | 中等 | ⭐100% |
| Token动态 | 较少 | ⭐很快 | ⭐$0 | 依赖预算 |
核心教训:Trade-off无处不在,选择适合场景的策略。
memory-chatbot/
├── src/
│ ├── llm/
│ │ ├── base.py # LLM基类接口
│ │ └── deepseek.py # DeepSeek实现
│ ├── memory/
│ │ ├── short_term.py # 短期记忆(Deque实现)
│ │ └── compressor.py # 4种压缩策略
│ └── chatbot.py # 完整聊天机器人
├── tests/
│ ├── test_data.py # 测试数据生成
│ ├── test_short_term.py # 短期记忆测试
│ ├── test_sliding_window.py # 滑动窗口测试
│ ├── test_llm_summary.py # LLM摘要测试
│ ├── test_hybrid.py # 混合策略测试
│ └── test_token_based.py # Token动态测试
├── .env.example # 环境变量示例
├── requirements.txt # 项目依赖
└── README.md # 项目说明
# 克隆项目
git clone https://github.com/yourusername/memory-chatbot.git
cd memory-chatbot
# 安装依赖
pip install -r requirements.txt# 复制环境变量模板
cp .env.example .env
# 编辑 .env,填入你的API密钥
DEEPSEEK_API_KEY=your_api_key_here# 测试滑动窗口策略
python tests/test_sliding_window.py
# 测试LLM摘要策略
python tests/test_llm_summary.py
# 测试混合策略
python tests/test_hybrid.py
# 测试Token动态策略
python tests/test_token_based.py| 策略 | Token | 压缩率 | 速度 | 成本 | 信息保留 |
|---|---|---|---|---|---|
| 滑动窗口 | 145 | 74% | 0.00ms | $0 | 0% |
| Token动态 | 193 | 66% | 0.53ms | $0 | 依赖预算 |
| LLM摘要 | 597 | -7% | 13,446ms | $0.0001 | 100% |
| 混合策略 | 604 | -8% | 11,663ms | $0.0001 | 100% |
| 策略 | 保留率 | 详情 |
|---|---|---|
| 滑动窗口 | 0% | 全部丢失 ❌ |
| LLM摘要 | 100% | 全部保留 ✅ |
| 混合策略 | 100% | 全部保留 ✅ |
| Token动态(预算200) | 100% | 全部保留 ✅ |
from src.memory.compressor import SlidingWindowCompressor
# 创建压缩器
compressor = SlidingWindowCompressor(keep_turns=5)
# 压缩对话历史
compressed = compressor.compress(messages)
print(f"压缩前: {len(messages)}条")
print(f"压缩后: {len(compressed)}条")from src.memory.compressor import HybridCompressor
from src.llm.deepseek import DeepSeekLLM
# 初始化LLM
llm = DeepSeekLLM()
# 创建混合策略压缩器
compressor = HybridCompressor(
llm,
threshold_turns=10, # 10轮以下用滑动窗口
keep_recent_turns=5 # 保留最近5轮
)
# 自动选择最优策略压缩
compressed = compressor.compress(messages)from src.memory.compressor import TokenBasedCompressor
from src.llm.deepseek import DeepSeekLLM
llm = DeepSeekLLM()
# 创建Token动态压缩器
compressor = TokenBasedCompressor(
llm.count_tokens,
max_tokens=200 # 精确控制在200 tokens
)
compressed = compressor.compress(messages)
# 验证Token数
actual_tokens = sum(llm.count_tokens(m['content']) for m in compressed)
print(f"目标: 200 tokens")
print(f"实际: {actual_tokens} tokens")
print(f"误差: {abs(actual_tokens - 200)} tokens")对话长度≤10轮?
├─ 是 → 【滑动窗口】
│ 理由:简单、快速、零成本
│
└─ 否 → 需要保留用户信息?
├─ 否 → 【滑动窗口】
│ 理由:Token效率最高
│
└─ 是 → 有Token预算限制?
├─ 有 → 【Token动态】
│ 理由:精确控制预算
│
└─ 无 → 【混合策略】
理由:自动适应,体验最好
| 场景 | 推荐策略 | 理由 |
|---|---|---|
| FAQ机器人 | 滑动窗口 | 对话短,速度最重要 |
| 客服助手 | 混合策略 | 自动适应,体验好 |
| 心理咨询 | LLM摘要 | 必须记住所有信息 |
| API网关 | Token动态 | 精确控制Token限制 |
| 免费产品 | 滑动窗口 | 零成本,可扩展 |
| VIP服务 | 混合策略 | 用户体验优先 |
原理: 固定保留最近N轮对话
def compress(self, messages):
if len(messages) <= self.keep_messages:
return messages
return messages[-self.keep_messages:]优点:
- 速度:0.00ms(极快)
- 成本:$0
- Token:最少(145)
- 代码:3行核心代码
缺点:
- 丢失所有早期信息
- 不智能
原理: 用LLM智能摘要历史,保留最近N轮完整对话
def compress(self, messages):
if len(messages) <= self.keep_recent_messages:
return messages
# 分割历史和最近消息
history = messages[:-self.keep_recent_messages]
recent = messages[-self.keep_recent_messages:]
# LLM摘要历史
summary = self._summarize(history)
# 组合
return [{"role": "system", "content": summary}] + recent优点:
- 信息保留:100%
- 智能提取关键信息
缺点:
- 短对话负优化(Token增加141%)
- 速度慢(11,663ms)
- 有成本($0.0001/次)
原理: 短对话用滑动窗口,长对话用LLM摘要
def compress(self, messages):
turn_count = len(messages) // 2
if turn_count <= self.threshold_turns:
return self.sliding_window.compress(messages)
else:
return self.llm_summary.compress(messages)优点:
- 短对话:保持滑动窗口速度
- 长对话:保留用户信息
- 自动适应
缺点:
- 长对话Token多4倍
- 阈值需要调优
原理: 精确控制在Token预算内
def compress(self, messages):
total_tokens = sum(self.token_counter(m['content']) for m in messages)
if total_tokens <= self.max_tokens:
return messages
# 从最早开始删除
compressed = messages[:]
current_tokens = total_tokens
while compressed and current_tokens > self.max_tokens:
removed = compressed.pop(0)
current_tokens -= self.token_counter(removed['content'])
return compressed优点:
- 精确控制(误差<5%)
- 速度快(0.53ms)
- 零成本
缺点:
- 可能比滑动窗口多用Token
- 信息保留依赖预算设置
完整的实现细节、性能测试、反直觉发现,请阅读:
掘金文章: AI聊天机器人记忆系统:从零到生产环境(完整实战)
文章目录:
- 背景和动机
- 短期记忆实现(Deque vs List)
- 四种压缩策略详解
- 滑动窗口
- LLM摘要
- 混合策略
- Token动态
- 性能测试中的意外发现
- 最佳实践和建议
欢迎提交Issue和Pull Request!
MIT License
Tom - @你的GitHub用户名
格思教育 AI工程师
感谢所有提供反馈和建议的朋友!
如果这个项目对你有帮助,请给个Star ⭐️