Skip to content

运行时行为验证 #2: 多轮对话格式与会话管理

🆕 本章通过实际 daemon 运行时行为验证补全
日期: 2026-06-25 | Daemon: v4.25.5 | Model: deepseek-v4-flash


1. 背景

此前静态分析发现了 ChatRequestsession_id 字段和 _format_messages_for_daemon() 函数,但从未验证多轮对话是否能正确保留上下文。这是代理实现中最关键的行为。


2. 多轮对话测试

2.1 测试设置

Turn 1: 发送会话第一句,捕获 daemon 返回的 session_id
Turn 2: 使用该 session_id 发送后续问题,验证上下文保留

2.2 第一轮: 设置上下文

请求:

json
POST /chat
{
  "message": "我的名字是张三"
}

响应 (done event):

json
{"type":"done","tokens":6282,"tool_calls":0,"session_id":"68ef5b9d-4287-40d2-ac36-3e9c4dc35961"}

完整 SSE 序列:

reasoning (fragments)
text: "你好,张三!很高兴认识你。我是 AtomCode..."
tokens: {prompt: 6193, completion: 89, total: 6282}
done: {tokens: 6282, session_id: "68ef5b9d-..."}

2.3 第二轮: 验证上下文

请求:

json
POST /chat
{
  "message": "我叫什么名字?记住之前的对话,我说过。",
  "session_id": "68ef5b9d-4287-40d2-ac36-3e9c4dc35961"
}

响应:

reasoning → text: "你叫 **张三**" → tokens → done

✅ 上下文保留成功! Daemon 正确记住了上一轮对话中设置的上下文。

2.4 关于 session_id 的关键发现

特性发现
用户提供的 session_id 被忽略如果提供自定义 session_id(如 test-multi-xxx),daemon 仍然分配新的 UUID
必须使用 daemon 返回的 session_id只有 done 事件中的 session_id 才能用于后续对话
session_id 在 done 事件中返回{"type":"done","session_id":"68ef5b9d-..."}
跨轮 token 增量第二轮 prompt 仍为 6193(说明上下文被正确加载)

3. 对话格式分析

3.1 系统提示注入

通过 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...

关键点:

  • 每次 LLM 调用都注入 完整的 47 个技能描述 (~6000-8000 tokens)
  • 含当前 git branch/status/diff 快照
  • 每轮 prompt token 稳定在 ~6193,说明 system prompt 长度固定

3.2 消息格式

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": [...]
  }
}

3.3 session 文件持久化

Daemon 内部管理会话持久化,每轮对话完成后写入磁盘:

~/.atomcode/sessions/<project_hash>/<session_id>.json

4. 对代理实现的影响

之前假设运行时验证结果影响
用户自定义 session_id 会生效❌ 被忽略Proxy 必须使用 daemon 返回的 session_id
_format_messages_for_daemon() 的格式正确✅ 确认消息格式为 [System]\n...\n[User]\n...\n[Assistant]\n...
context_window 在 multi-turn 中变化✅ prompt 稳定在 6193System prompt 占主导(47 个技能)
会话过期时间未验证(需等待 30 分钟)默认 idle timeout 30 分钟

4.1 代理中的会话复用逻辑

python
# 代理中的正确逻辑:
async def chat_stream(messages, system_prompt=None):
    # 生成会话键(基于消息摘要)
    conv_key = sha256(messages + system_prompt)
    
    # 查找已有会话
    if conv_key in session_cache:
        session_id = session_cache[conv_key]
    else:
        session_id = None  # 新会话
    
    # 调用 daemon,传入 session_id
    result = await daemon_client.chat_stream(
        message=last_message,
        session_id=session_id
    )
    
    # 保存 daemon 返回的 session_id
    new_session_id = result["session_id"]
    session_cache[conv_key] = new_session_id

5. 注意点

  1. session_id 完全由 daemon 管理,用户请求中传入的 session_id 不会生效
  2. 每轮对话 token 消耗稳定,因为 system prompt 每次都重新注入
  3. 同 session_id 的后续请求会加载完整历史消息
  4. daemon 不检查 session_id 的合法性——传入不存在的 session_id 会创建新会话

📅 最后更新: 2026-06-25🔍 验证方法: 实际 daemon 运行时多轮对话抓包

逆向命令索引

bash
# 测试多轮会话
curl -s -X POST http://localhost:13456/chat \
  -H "Authorization: Bearer $(cat ~/.atomcode/auth.toml | grep access_token | cut -d'"' -f2)" \
  -H "Content-Type: application/json" \
  -d '{"message":"第一轮"}' 2>&1 | grep "session_id" | head -1

基于 VitePress 构建 · AtomCode v4.25.3 逆向工程分析文档