多轮对话的 messages 数组演变
本文档展示 3 轮对话 中 messages 数组的完整演变过程。
场景设定
- 第 1 轮: 用户"你好" → AI 回复
- 第 2 轮: 用户"读取 README.md" → AI 调用工具 → AI 回复
- 第 3 轮: 用户"谢谢" → AI 回复
第 1 轮对话
用户输入
你好
发送给 LLM 的 messages(第 1 轮)
[
{
"role": "system",
"content": "# 核心身份\n\n你的名字是\"小C\",运行在 CountBot框架内的专用智能助手...(完整系统提示词)"
},
{
"role": "user",
"content": "你好"
}
]
LLM 响应
{
"role": "assistant",
"content": "你好!很高兴见到你!有什么我可以帮助你的吗?"
}
保存到数据库
-- messages 表
INSERT INTO messages (session_id, role, content, created_at) VALUES
('550e8400-e29b-41d4-a716-446655440000', 'user', '你好', '2024-01-15 10:30:00'),
('550e8400-e29b-41d4-a716-446655440000', 'assistant', '你好!很高兴见到你!有什么我可以帮助你的吗?', '2024-01-15 10:30:02');
第 2 轮对话
用户输入
读取 README.md 文件
获取历史消息
# backend/api/chat.py - send_message()
context = await session_manager.get_history_with_summary(
session_id=request.session_id,
limit=None if max_history == -1 else max_history
)
返回的 context:
[
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好!很高兴见到你!有什么我可以帮助你的吗?"}
]
发送给 LLM 的 messages(第 2 轮 - 第 1 次调用)
[
{
"role": "system",
"content": "# 核心身份\n\n你的名字是\"小C\"...(完整系统提示词)"
},
{
"role": "user",
"content": "你好"
},
{
"role": "assistant",
"content": "你好!很高兴见到你!有什么我可以帮助你的吗?"
},
{
"role": "user",
"content": "读取 README.md 文件"
}
]
LLM 响应(包含 tool_calls)
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "read_file",
"arguments": "{\"path\":\"README.md\",\"show_line_numbers\":true}"
}
}
]
}
执行工具
# backend/modules/tools/registry.py - execute()
result = await self.tools.execute(
tool_name="read_file",
arguments={"path": "README.md", "show_line_numbers": True}
)
工具结果:
[File: README.md | Lines: 150]
1| # CountBot
2|
3| CountBot 是一个基于 LLM 的智能助手框架。
4|
5| ## 功能特性
6|
7| - 多模型支持(OpenAI、Claude、国产大模型)
8| - 工具调用系统
9| - 记忆管理
10| - 技能系统
... (省略后续内容)
发送给 LLM 的 messages(第 2 轮 - 第 2 次调用)
[
{
"role": "system",
"content": "# 核心身份\n\n你的名字是\"小C\"...(完整系统提示词)"
},
{
"role": "user",
"content": "你好"
},
{
"role": "assistant",
"content": "你好!很高兴见到你!有什么我可以帮助你的吗?"
},
{
"role": "user",
"content": "读取 README.md 文件"
},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "read_file",
"arguments": "{\"path\":\"README.md\",\"show_line_numbers\":true}"
}
}
]
},
{
"role": "tool",
"tool_call_id": "call_abc123",
"name": "read_file",
"content": "[File: README.md | Lines: 150]\n 1| # CountBot\n 2| \n 3| CountBot 是一个基于 LLM 的智能助手框架..."
}
]
LLM 最终响应
{
"role": "assistant",
"content": "我已经读取了 README.md 文件。这是 CountBot 项目的说明文档,主要介绍了以下内容:\n\n1. **功能特性**:\n - 多模型支持(OpenAI、Claude、国产大模型)\n - 工具调用系统\n - 记忆管理\n - 技能系统\n - 多渠道接入(Web、钉钉、Telegram)\n\n2. **快速开始**:提供了安装和运行命令\n\n3. **配置说明**:需要编辑 config.yaml 文件\n\n需要我详细解释某个部分吗?"
}
保存到数据库
-- messages 表
INSERT INTO messages (session_id, role, content, created_at) VALUES
('550e8400-e29b-41d4-a716-446655440000', 'user', '读取 README.md 文件', '2024-01-15 10:31:00'),
('550e8400-e29b-41d4-a716-446655440000', 'assistant', '我已经读取了 README.md 文件。这是 CountBot 项目的说明文档...', '2024-01-15 10:31:05');
-- tool_conversations 表
INSERT INTO tool_conversations (id, session_id, tool_name, arguments, result, duration_ms, timestamp, user_message, message_id) VALUES
('tc_789xyz', '550e8400-e29b-41d4-a716-446655440000', 'read_file', '{"path":"README.md","show_line_numbers":true}', '[File: README.md | Lines: 150]...', 45, '2024-01-15 10:31:02', '读取 README.md 文件', 4);
第 3 轮对话
用户输入
谢谢
获取历史消息
context = await session_manager.get_history_with_summary(
session_id=request.session_id,
limit=None if max_history == -1 else max_history
)
返回的 context:
[
{"role": "user", "content": "你好"},
{"role": "assistant", "content": "你好!很高兴见到你!有什么我可以帮助你的吗?"},
{"role": "user", "content": "读取 README.md 文件"},
{"role": "assistant", "content": "我已经读取了 README.md 文件。这是 CountBot 项目的说明文档..."}
]
注意: 工具调用的 assistant 和 tool 消息不会保存到数据库,只保存最终的用户消息和 AI 回复。
发送给 LLM 的 messages(第 3 轮)
[
{
"role": "system",
"content": "# 核心身份\n\n你的名字是\"小C\"...(完整系统提示词)"
},
{
"role": "user",
"content": "你好"
},
{
"role": "assistant",
"content": "你好!很高兴见到你!有什么我可以帮助你的吗?"
},
{
"role": "user",
"content": "读取 README.md 文件"
},
{
"role": "assistant",
"content": "我已经读取了 README.md 文件。这是 CountBot 项目的说明文档,主要介绍了以下内容:\n\n1. **功能特性**:\n - 多模型支持(OpenAI、Claude、国产大模型)\n - 工具调用系统\n - 记忆管理\n - 技能系统\n - 多渠道接入(Web、钉钉、Telegram)\n\n2. **快速开始**:提供了安装和运行命令\n\n3. **配置说明**:需要编辑 config.yaml 文件\n\n需要我详细解释某个部分吗?"
},
{
"role": "user",
"content": "谢谢"
}
]
LLM 响应
{
"role": "assistant",
"content": "不客气!如果你在使用 CountBot 的过程中遇到任何问题,或者需要进一步的帮助,随时告诉我。祝你使用愉快!😊"
}
保存到数据库
-- messages 表
INSERT INTO messages (session_id, role, content, created_at) VALUES
('550e8400-e29b-41d4-a716-446655440000', 'user', '谢谢', '2024-01-15 10:32:00'),
('550e8400-e29b-41d4-a716-446655440000', 'assistant', '不客气!如果你在使用 CountBot 的过程中遇到任何问题...', '2024-01-15 10:32:01');
历史消息限制
配置
# config.yaml
persona:
max_history_messages: 50 # 最多保留 50 条历史消息,-1 表示不限制
滚动窗口机制
当历史消息超过 max_history_messages 时,会触发滚动窗口截断:
# backend/api/chat.py - send_message()
if max_history > 0:
await session_manager.summarize_overflow(
session_id=request.session_id,
max_history=max_history,
provider=agent_loop.provider,
model=agent_loop.model,
memory_store=_overflow_memory,
)
滚动窗口流程
- 检测溢出: 如果消息数 > max_history,触发总结
- 总结旧消息: 将最旧的消息(超出窗口的部分)总结为记忆条目
- 写入记忆: 保存到
MEMORY.md文件 - 删除旧消息: 从数据库删除已总结的消息
- 保留窗口: 只保留最近的 max_history 条消息
总结提示词
# backend/modules/agent/prompts.py - OVERFLOW_SUMMARY_PROMPT
OVERFLOW_SUMMARY_PROMPT = """你是一个对话总结器。以下是一段即将被截断的旧对话历史,请将其中有长期价值的信息总结为简洁的记忆条目。
要求:
1. 输出格式: 一行文本,多个事项用中文分号(;)分隔
2. 只记录有长期价值的事实信息
3. 不要记录闲聊、一次性查询结果
4. 每个事项必须包含具体信息
5. 如果对话没有值得长期记录的信息,输出: 无需记录
对话内容:
{messages}
输出(一行,事项用;分隔):"""
示例
假设 max_history=50,当前有 55 条消息:
# 消息 1-5(最旧的 5 条)会被总结
old_messages = [
{"role": "user", "content": "我的邮箱是 user@example.com"},
{"role": "assistant", "content": "好的,我记住了你的邮箱是 user@example.com"},
{"role": "user", "content": "我喜欢用 Python 开发"},
{"role": "assistant", "content": "了解,你偏好使用 Python"},
{"role": "user", "content": "今天天气怎么样"},
]
# LLM 总结为记忆条目
summary = "用户邮箱: user@example.com;偏好编程语言: Python"
# 写入 MEMORY.md
# 2024-01-15|web-chat|用户邮箱: user@example.com;偏好编程语言: Python
# 删除消息 1-5,保留消息 6-55
会话总结注入
手动创建会话总结
PUT /api/chat/sessions/550e8400-e29b-41d4-a716-446655440000/summary HTTP/1.1
Content-Type: application/json
{
"summary": "这是一个关于 CountBot 项目开发的会话。用户正在学习如何使用工具系统。"
}
总结注入到系统提示词
# backend/modules/agent/context.py - build_messages()
if session_summary:
system_prompt += f"\n\n## Current Session Context\n{session_summary}"
生成的系统提示词(末尾追加):
## Current Session Context
这是一个关于 CountBot 项目开发的会话。用户正在学习如何使用工具系统。
发送给 LLM 的 messages(包含会话总结)
[
{
"role": "system",
"content": "# 核心身份\n\n你的名字是\"小C\"...(完整系统提示词)\n\n## Current Session Context\n这是一个关于 CountBot 项目开发的会话。用户正在学习如何使用工具系统。"
},
{
"role": "user",
"content": "你好"
},
{
"role": "assistant",
"content": "你好!很高兴见到你!有什么我可以帮助你的吗?"
},
{
"role": "user",
"content": "