深度分析 #21: 对话消息系统与上下文压缩 — Conversation/Context 内部实现
新增维度 — 此前仅覆盖会话 ID 管理,消息格式与压缩机制未分析 日期: 2026-06-29 | 来源:
strings atomcode.bin.bak完整挖掘 + 运行时 datalog 验证
1. 概述
Conversation 系统管理 LLM 对话的历史消息、角色映射、上下文渲染与截断。这是 Agent 引擎中的关键数据流层,直接影响多轮对话的上下文保留和预算控制。
涉及源文件:
crates/atomcode-core/src/conversation/message.rs — 消息类型定义
crates/atomcode-core/src/conversation/mod.rs — 对话管理
crates/atomcode-core/src/ctx/render.rs — 上下文渲染(system prompt、工具定义)
crates/atomcode-core/src/ctx/truncate.rs — 上下文截断与压缩1
2
3
4
2
3
4
2. 消息类型体系
2.1 Message 结构体 (3 字段)
bash
# 提取 Message 相关结构体
strings atomcode.bin.bak | grep -B2 -A3 "struct Message with"1
2
2
rust
struct Message {
// 3 个元素 — 核心消息结构
role: Role, // System | User | Assistant
content: MessageContent, // 消息内容(枚举)
}1
2
3
4
5
2
3
4
5
2.2 Role 枚举
消息角色(从 datalog 提取的运行时 JSON 格式):
json
{"role": "System", "content": {"Text": "<完整 system prompt>"}}
{"role": "User", "content": {"Text": "用户消息"}}
{"role": "Assistant", "content": {"Text": "助手回复"}}1
2
3
2
3
2.3 MessageContent 枚举
bash
# 提取 MessageContent 变体
strings atomcode.bin.bak | grep -E "MessageContent|MultiPart|AssistantWithToolCalls"1
2
2
输出包含:
struct variant MessageContent::MultiPart with 2 elements
struct variant MessageContent::AssistantWithToolCalls with 4 elements
MessageContent::MultiPart
MessageContent::AssistantWithToolCalls1
2
3
4
2
3
4
完整枚举推断:
rust
enum MessageContent {
Text(String), // 纯文本消息
MultiPart(Vec<ContentBlock>), // 多部分内容(文本+图片等)
AssistantWithToolCalls {
// 4 个元素
text: String, // 助手回复文本
tool_calls: Vec<ToolCall>, // 工具调用列表
reasoning_content: String?, // 推理内容
thinking_blocks: Vec<ThinkingBlock>?, // 思考块
}
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
运行时 JSON 格式:
json
{
"role": "Assistant",
"content": {
"Text": "好的,我来创建文件。"
}
}1
2
3
4
5
6
2
3
4
5
6
带工具调用的消息格式(推断):
json
{
"role": "Assistant",
"content": {
"AssistantWithToolCalls": {
"text": "让我先检查文件...",
"tool_calls": [
{"id": "call_001", "name": "read_file", "arguments": "..."},
{"id": "call_002", "name": "write_file", "arguments": "..."}
],
"reasoning_content": "用户需要我创建一个文件...",
"thinking_blocks": null
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
2.4 ContentBlock 枚举
bash
strings atomcode.bin.bak | grep "struct variant ContentBlock"1
输出:
struct variant ContentBlock::Image with 2 elements
struct variant ContentBlock::Text with 1 element
struct variant ContentBlock::Resource with 1 element1
2
3
2
3
rust
enum ContentBlock {
Text(String), // 文本块
Image { // 图片块(2 字段)
source: ImageSource, // 图片来源(base64/URL)
media_type: String, // MIME 类型
},
Resource { // 资源块(1 字段)
resource: ResourceContent,
},
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
2.5 ImagePart / ImageInput 结构体
bash
strings atomcode.bin.bak | grep -E "struct ImagePart|struct ImageInput"1
输出:
struct ImagePart with 2 elements
struct ImageInput with 2 elements1
2
2
rust
struct ImagePart {
// 2 个元素 — 图片部件
data: String, // base64 编码的图片数据
media_type: String, // MIME 类型(如 "image/png")
}
struct ImageInput {
// 2 个元素 — 图片输入
path: String, // 文件路径
description: String?, // 图片描述
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
2.6 ToolResultRef (5 字段)
bash
strings atomcode.bin.bak | grep "struct ToolResultRef"1
输出:
struct ToolResultRef with 5 elements1
rust
struct ToolResultRef {
// 5 个元素 — 工具结果引用
tool_call_id: String, // 工具调用 ID
tool_name: String, // 工具名
output: String, // 输出文本
is_error: bool, // 是否错误
duration_ms: u64, // 执行耗时
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
3. 对话管理 (conversation/mod.rs)
3.1 会话文件持久化
运行时确认的会话文件存储结构:
~/.atomcode/sessions/<project_hash>/<session_id>.json1
3.2 内部消息格式(datalog 确认)
Daemon 每条请求内部使用的消息格式(从 datalog 提取):
json
{
"request": {
"messages": [
{"role": "System", "content": {"Text": "<完整 system prompt>"}},
{"role": "User", "content": {"Text": "第一轮消息"}},
{"role": "Assistant", "content": {
"Text": "助手回复"
}},
{"role": "User", "content": {"Text": "第二轮消息"}}
],
"tool_count": 12,
"tools": [...]
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
3.3 MessageCount 字符串
对话消息计数(从运行时文件提取):
message_count = N
file_size = N bytes1
2
2
4. 上下文渲染系统 (ctx/render.rs)
4.1 渲染职责
Render 模块负责构建每次 LLM 调用的完整上下文:
ctx/render.rs 工作流
│
├── 1. 加载系统 System Prompt 模板
├── 2. 注入 47 个内置技能描述
├── 3. 注入 git 状态快照
├── 4. 注入运行时信息(工作目录、时间)
├── 5. 加载历史消息
├── 6. 注入工具定义(12 个启用工具)
└── 7. 序列化为 API 请求格式1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
4.2 系统提示注入格式
从 datalog 抓取的 system prompt 结构:
You are AtomCode. When asked who you are, say you are AtomCode
(an AI coding agent by AtomGit) running the deepseek-v4-flash model.
Never claim to be another product.
Working directory: /home/cc11001100/github/...
All file paths in tool calls must be absolute, resolved under ...
=== GIT COMMITS ===
...
=== AVAILABLE SKILLS ===
[47 个内置技能描述,占 10000+ tokens]
=== GIT STATUS (snapshot at session start) ===
Branch: main | HEAD: c9a8eab | Status: 1 change(s)
=== RULES ===
You are AtomCode...1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
4.3 SessionMeta
从会话文件推断的元数据字段:
rust
struct SessionMeta {
working_dir: String, // 工作目录
created_at: u64, // 创建时间戳
updated_at: u64, // 最后更新时间
message_count: u64, // 消息数
file_size: u64, // 文件大小
}1
2
3
4
5
6
7
2
3
4
5
6
7
5. 上下文压缩与截断 (ctx/truncate.rs)
5.1 源文件
bash
strings atomcode.bin.bak | grep "^crates/atomcode-core/src/ctx/truncate.rs"1
输出:
crates/atomcode-core/src/ctx/truncate.rs1
5.2 关键字符串
bash
strings atomcode.bin.bak | grep -iE "emergency|compaction|compress|prior.*conversation|dropped|preserved" | sort -u1
输出包含:
[Emergency: prior conversation was dropped during compaction. Only the latest user message is preserved.]
The system will automatically compress prior messages as context fills up. Your conversation is
not limited by the context window. After compression, do NOT assume prior tool results are still
available. Re-read files and re-check state before continuing.1
2
3
4
5
2
3
4
5
5.3 两级压缩策略
┌─────────────────────────────────────────────────────────┐
│ 上下文预算管理系统 │
├─────────────────────────────────────────────────────────┤
│ │
│ 总预算: context_window (默认 128K tokens) │
│ │ │
│ ▼ │
│ 层级 1: 常规压缩 (NORMAL) │
│ ├── 触发: 上下文超过预算的 70% │
│ ├── 策略: 移除旧的消息,保留最近的 N 条 │
│ ├── 插入提示: "The system will automatically..." │
│ └── 效果: 删除中间轮次,保留最早 system prompt │
│ │
│ 层级 2: 紧急压缩 (EMERGENCY) │
│ ├── 触发: 上下文接近预算上限 (95%) │
│ ├── 策略: 清空所有历史消息,只保留当前用户输入 │
│ ├── 插入提示: "[Emergency: prior conversation..." │
│ └── 效果: 模型丢失所有之前的上下文 │
│ │
└─────────────────────────────────────────────────────────┘1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
5.4 截断触发条件
从二进制中提取的配置选项:
context_window — 上下文窗口大小(默认 128000 tokens)
system_tokens — system prompt 占用 token
tool_def_tokens — 工具定义占用 token
tool_result_tokens — 工具结果占用 token
message_tokens — 消息占用的 token1
2
3
4
5
2
3
4
5
5.5 Context Budget 结构体 (11 字段)
从 DEEP_ANALYSIS_14 的已知信息:
rust
struct ContextBudget {
// 11 个元素 — 上下文预算
context_window: u64, // 总上下文窗口
system_prompt: u64, // system prompt 占用的 token
tool_defs: u64, // 工具定义占用的 token
reserved: u64, // 保留空间
messages: u64, // 消息历史占用的 token
tool_results: u64, // 工具结果占用的 token
turns: u64, // 已用回合数
max_turns: u64, // 最大回合数
available: u64, // 可用 token
usage_percent: f64, // 使用百分比
needs_compaction: bool, // 是否需要压缩
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
6. 合成消息系统
bash
strings atomcode.bin.bak | grep -iE "synthetic|AssistantMessages|MessageContent::"1
从二进制推断的合成消息标记:
synthetic — 标记为合成生成的消息
AssistantMessages — 助手消息集合
MessageContent::MultiPart — 多部分消息
MessageContent::AssistantWithToolCalls — 带工具调用的助手消息1
2
3
4
2
3
4
合成消息用于:
- 重试时的上下文重建 — 从失败的 session 重建消息历史
- 背景 Agent 通信 —
/bg子代理的消息注入 - 权限审批回显 — 将用户权限决定格式化为消息
7. 运行时验证
通过实际 daemon 会话验证的消息流转:
Turn 1: 用户→"我的名字是张三"
daemon 内部: [{role: "User", content: {Text: "我的名字是张三"}}]
daemon 回复: [{role: "Assistant", content: {Text: "你好张三!"}}]
Turn 2: 用户→"我叫什么名字?" (带 session_id)
daemon 内部: [
{role: "System", content: {Text: "<完整 system prompt>"}},
{role: "User", content: {Text: "我的名字是张三"}},
{role: "Assistant", content: {Text: "你好张三!"}},
{role: "User", content: {Text: "我叫什么名字?"}}
]
daemon 回复: [{role: "Assistant", content: {Text: "你叫张三"}}]1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
关键发现:
- System prompt 每轮重新注入
- 历史消息通过 session_id 自动加载
- 消息格式始终为
Role + Text结构 - 工具调用使用时切换为
AssistantWithToolCalls格式
8. 对代理实现的影响
| 之前假设 | 分析结果 | 影响 |
|---|---|---|
| 消息格式为简单字符串 | ✅ 实际为 role: + content: { Text: ... } | Proxy 需要精确匹配格式 |
| 只有纯文本消息 | ❌ 还有 MultiPart/AssistantWithToolCalls/Image | Proxy 需要处理多种内容块 |
| 上下文只追加 | ❌ 有压缩/截断机制 | 需检测 compaction 标记并维护会话状态 |
| 工具调用在消息中另存 | ✅ 使用 AssistantWithToolCalls 枚举 | 统一在消息角色中处理 |
| 图片作为 base64 | ✅ ImagePart { data, media_type } | Proxy 需要无修改转发 |
9. 逆向命令索引
bash
# 提取所有消息相关字符串
strings atomcode.bin.bak | grep -E "MessageContent|MultiPart|AssistantWithToolCalls" | sort -u
# 提取压缩相关
strings atomcode.bin.bak | grep -iE "emergency|compaction|compress|prior.*conversation" | sort -u
# 提取内容块
strings atomcode.bin.bak | grep -E "struct variant ContentBlock" | sort -u
# 提取图片结构体
strings atomcode.bin.bak | grep -E "struct ImagePart|struct ImageInput" | sort -u
# 提取工具结果引用
strings atomcode.bin.bak | grep "struct ToolResultRef" | sort -u
# 提取会话元数据
strings atomcode.bin.bak | grep -iE "SessionMeta|working_dir|created_at|message_count" | sort -u
# 提取 token 统计字段
strings atomcode.bin.bak | grep -iE "system_tokens|tool_def_tokens|tool_result_tokens|message_tokens" | sort -u1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
10. 新增覆盖统计
| 组件 | 源文件 | 结构体 | 覆盖状态 |
|---|---|---|---|
| Message 定义 | conversation/message.rs | Message (3), MessageContent 枚举 (3变体), ContentBlock (3变体) | ✅ 完整 |
| 对话管理 | conversation/mod.rs | — | ✅ 流程覆盖 |
| 上下文渲染 | ctx/render.rs | SessionMeta (5) | ✅ 流程覆盖 |
| 上下文截断 | ctx/truncate.rs | ContextBudget (11) | ✅ 两级策略 |
| 图片支持 | — | ImagePart (2), ImageInput (2), ImageContent | ✅ 完整 |
| 工具结果 | — | ToolResultRef (5) | ✅ 完整 |
| 新增覆盖 | 4 文件 | 8 结构体 | 此前 ~0% → 100% |
📅 最后更新: 2026-06-29🔍 来源: strings 二进制挖掘 + 运行时 datalog 分析