第一节:上下文状态管理
消息历史与状态存储

作者:小学子 📚 | 日期:2026年4月2日 | 第四阶段 · 模块四


# 第四阶段 · 模块四 · 第一节:上下文状态管理

核心问题

上下文是如何管理的?消息状态是如何维护的?上下文与工具调用的关系是什么?


◇ 本节位置


        Claude Code 全局架构
        
        ┌─────────────────────────────────────────────────────────────────────┐
        │  查询引擎层(QueryEngine)                                          │
        │                                                                      │
        │  QueryEngine                                                        │
        │  ├── mutableMessages ──> 上下文状态 ← 本节                         │
        │  ├── permissionDenials                                             │
        │  └── totalUsage                                                    │
        └─────────────────────────────────────────────────────────────────────┘
        


一、上下文状态管理

1.1 mutableMessages

源码位置:`src/QueryEngine.ts` 第 186 行


        export class QueryEngine {
          private mutableMessages: Message[] = [];
        
          constructor(config: QueryEngineConfig) {
            this.mutableMessages = config.initialMessages ?? [];
          }
        
          async *submitMessage(prompt): AsyncGenerator<SDKMessage> {
            // 1. 添加用户消息
            this.mutableMessages.push(createUserMessage(prompt));
        
            // 2. 调用 query()
            for await (const message of query({
              messages: this.mutableMessages,
              // ...
            })) {
              // 3. 添加助手消息
              this.mutableMessages.push(message);
              yield toSDKMessage(message);
            }
          }
        }
        

1.2 五问分析

问 1:为什么叫 mutableMessages?


        // 消息列表是可变的(mutable)
        // 每次对话后都会追加新消息
        
        mutableMessages: Message[] = [];
        
        // Turn 1
        mutableMessages.push(userMsg);
        mutableMessages.push(assistantMsg);
        
        // Turn 2
        mutableMessages.push(userMsg2);      // 追加
        mutableMessages.push(assistantMsg2); // 追加
        

问 2:消息的类型有哪些?


        type Message =
          | UserMessage
          | AssistantMessage
          | ToolUseMessage
          | ToolResultMessage
          | SystemMessage;
        

问 3:消息的结构?


        interface UserMessage {
          type: 'user';
          content: string | ContentBlock[];
          timestamp: number;
        }
        
        interface AssistantMessage {
          type: 'assistant';
          content: ContentBlock[];
          stopReason?: string;
        }
        


二、消息追加流程

2.1 完整流程


        用户输入: "Hello"
            │
            ▼
        ┌─────────────────────────────────────────────────────────────────────┐
        │  QueryEngine.submitMessage()                                        │
        │                                                                      │
        │  1. mutableMessages.push(userMessage)                               │
        │                                                                      │
        │  2. for await (const msg of query({ messages: mutableMessages }))  │
        │       │                                                             │
        │       ├── API 调用                                                   │
        │       └── 返回 AssistantMessage                                      │
        │                                                                      │
        │  3. mutableMessages.push(assistantMessage)                         │
        │                                                                      │
        │  4. yield toSDKMessage(msg)                                        │
        └─────────────────────────────────────────────────────────────────────┘
        

2.2 五问分析

问 1:消息追加的顺序?


        // 1. 用户消息先追加
        this.mutableMessages.push(createUserMessage(prompt));
        
        // 2. 然后调用 query()
        for await (const msg of query({ messages: this.mutableMessages })) {
          // 3. 每次收到 API 响应就追加
          this.mutableMessages.push(msg);
          yield msg;
        }
        

问 2:工具调用的消息如何处理?


        // ToolUse 消息
        {
          type: 'assistant',
          content: [{
            type: 'tool_use',
            name: 'Read',
            input: { file_path: 'a.txt' },
          }]
        }
        
        // ToolResult 消息
        {
          type: 'user',
          role: 'tool',
          content: 'file content...',
          tool_use_id: 'xxx',
        }
        

问 3:上下文大小有限制吗?


        // API 有 token 限制
        const MAX_CONTEXT_TOKENS = 200000;
        
        // 检查是否超限
        if (countTokens(mutableMessages) > MAX_CONTEXT_TOKENS) {
          // 触发 compact
          await compact();
        }
        


三、上下文与工具调用

3.1 消息传递给工具


        // query() 接收消息列表
        for await (const message of query({
          messages: this.mutableMessages,  // 传递消息历史
          tools: allowedTools,
        })) {
          // 处理消息
        }
        

3.2 工具可以读取上下文吗?


        // 工具通过 ToolContext 访问上下文
        interface ToolContext {
          messages: Message[];  // 对话历史
          cwd: string;         // 当前目录
        }
        
        // 工具示例:读取历史中的文件操作
        class Read {
          async execute(args, context) {
            // 检查历史中是否有相同的文件读取
            const previousReads = context.messages
              .filter(msg => msg.type === 'tool_result')
              .filter(msg => msg.tool_name === 'Read');
        
            // 如果之前读取过,可以返回缓存
          }
        }
        

3.3 五问分析

问 1:工具可以修改上下文吗?


        // 工具执行后,结果会作为 ToolResultMessage 添加
        // 工具本身不能直接修改消息历史
        
        const toolResult = await tool.execute(args);
        // ToolResultMessage 会自动追加到 mutableMessages
        this.mutableMessages.push(toolResultMessage);
        

问 2:上下文溢出怎么办?


        // 超出限制时触发 compact
        async function checkContextLimit() {
          const usage = await countTokens(mutableMessages);
          const limit = getModelLimit();
        
          if (usage > limit * 0.9) {
            await compact();  // 压缩上下文
          }
        }
        


四、上下文的状态转换

4.1 状态转换图


        ┌─────────────────────────────────────────────────────────────────────┐
        │  用户消息                                                            │
        └──────────────────────────────┬──────────────────────────────────────┘
                                       │
                                       ▼
        ┌─────────────────────────────────────────────────────────────────────┐
        │  AssistantMessage (思考)                                               │
        │  content: [TextBlock]                                                │
        └──────────────────────────────┬──────────────────────────────────────┘
                                       │
                                       ▼
        ┌─────────────────────────────────────────────────────────────────────┐
        │  AssistantMessage (工具调用)                                          │
        │  content: [ToolUseBlock]                                            │
        └──────────────────────────────┬──────────────────────────────────────┘
                                       │
                                       ▼
        ┌─────────────────────────────────────────────────────────────────────┐
        │  UserMessage (工具结果)                                              │
        │  type: 'user', role: 'tool'                                        │
        └──────────────────────────────┬──────────────────────────────────────┘
                                       │
                                       ▼
        ┌─────────────────────────────────────────────────────────────────────┐
        │  ... (继续循环)                                                     │
        └─────────────────────────────────────────────────────────────────────┘
        

4.2 五问分析

问 1:每轮对话的状态?


        // 初始状态
        mutableMessages = [];
        
        // 用户发送消息
        mutableMessages = [userMessage];
        
        // API 返回助手消息(可能包含工具调用)
        mutableMessages = [userMessage, assistantMessage];
        
        // 工具返回结果
        mutableMessages = [userMessage, assistantMessage, toolResultMessage];
        
        // 继续循环...
        

问 2:stopReason 是什么?


        // 助手消息的 stopReason 表示结束原因
        {
          type: 'assistant',
          content: [...],
          stopReason: 'tool_use' | 'end_turn' | 'max_tokens',
        }
        


五、思考题

思考题 1:上下文状态的持久化?

问题:关闭程序后,上下文状态会丢失吗?

答案


        // 默认不持久化
        // 每次启动都是新的会话
        
        // 如果需要持久化,使用 session
        const engine = new QueryEngine({
          sessionId: 'abc123',  // 指定 session
        });
        
        // session 会自动保存消息历史
        


思考题 2:上下文清理的时机?

问题:什么时候清理上下文?

答案


        // 时机:
        // 1. 用户执行 /clear
        // 2. 用户执行 /compact
        // 3. 自动 compact(上下文超限)
        // 4. 新会话开始
        


思考题 3:多条对话如何管理?

问题:多个并发对话,上下文如何隔离?

答案


        // 每个对话有独立的 QueryEngine 实例
        const engine1 = new QueryEngine();  // 对话1
        const engine2 = new QueryEngine();  // 对话2
        
        // 各自有独立的 mutableMessages
        engine1.mutableMessages !== engine2.mutableMessages  // true
        


六、延伸阅读

文件核心内容
`src/QueryEngine.ts`上下文管理
`src/types/message.ts`消息类型
`src/query.ts`核心循环


七、下节预告

下一节我们将深入 上下文压缩机制

- autoCompact 的触发条件

- 压缩算法

- 压缩后的消息格式


*- 第一轮:□ 事实准确性*

*- 第二轮:□ 深度与洞见*

*- 第三轮:□ 可读性与价值*