随笔
Claude Code 源码解读 02:问题先怎样进入 Context
拆解用户输入从 submitMessage 到 processUserInput、附件聚合和 transcript 写入的路径,说明“看对问题”比直接行动更重要。
Context 不是“把资料都塞给模型”,而是一次用户请求进入模型前的装配线。
快速了解
- Context 的核心不是信息越多越好,而是模型调用前先把规则、状态、附件和用户消息分层放好。
submitMessage()更像总装层,不只是把 prompt 传给模型。- CLAUDE.md、git status、image、IDE selection、memory 都不是同一种上下文,不能混写成主线。
- 用户消息先写 transcript,是后续 resume 和审计的基础。
如果只想快速理解,可以先读这一节;如果要看源码机制,再往下看“主线与场景插入分类”和机制图。
设问与回应
| 设问 | 回应 |
|---|---|
submitMessage() 到底负责了哪些装配工作? | submitMessage() 不是把 prompt 转交给模型,而是一次 turn 的总装入口:模型配置、工具环境、权限上下文、memory prompt、Hook、附件、transcript 都在这里进入同一条链路。 |
fetchSystemPromptParts() 里的 system prompt、userContext、systemContext 分别承担什么? | system prompt 更像底层行为约束,userContext 承接项目和用户侧上下文,systemContext 则补运行环境和系统状态。三者都进入模型前缀,但来源、可信度和变化频率不同。 |
processUserInput() 是普通文本处理,还是协议归一化? | processUserInput() 不是普通字符串处理,而是协议归一化。普通文本、slash command、bash mode、图片、附件和 Hook 输出,最后都要变成后续 query loop 能消费的消息结构。 |
getAttachmentMessages() 为什么既是主线入口,又是场景增强聚合点? | getAttachmentMessages() 是主线入口,因为每个 turn 都可能需要附件聚合;它也是场景增强聚合点,因为 IDE selection、image、memory、任务上下文等内容只在特定条件下进入。 |
主线与场景插入分类
| 机制/模块 | 分类 | 我保留的判断 |
|---|---|---|
QueryEngine.submitMessage() | 主线功能 | 会话 turn 的入口,把输入、工具环境、权限上下文和模型请求串起来 |
fetchSystemPromptParts() | 主线功能 | 构造 API 前缀上下文,决定模型请求前的基础提示 |
processUserInput() | 主线功能 | 把用户输入归一化为 Message,是进入模型前的协议边界 |
getAttachmentMessages() | 主线 + 场景插入聚合点 | 附件聚合是主线,但 image、IDE、memory、任务上下文按条件启用 |
getUserContext() 中的 CLAUDE.md | 场景插入 | 依赖文件存在、环境变量、bare mode 等条件 |
recordTranscript before model call | 可观测/恢复支撑 | 用户消息先落盘,保证 API 中断后仍能 resume |
源码链路拆解
submitMessage() 是总装层。它先决定模型、thinking config、MCP / tools / agents、memory prompt、输入处理上下文、Hook、附件和 transcript 的进入顺序。processUserInput() 做的是协议归一化。普通文本、slash command、bash mode、图片、附件、UserPromptSubmit Hook,最后都要落到 UserMessage + AttachmentMessages。
从 Codex 差异拆解 Context 输入治理
Context 构建能力越强,越需要判断哪些内容是当前 turn 的高密度输入,哪些只是场景噪声。拿 Codex 做对比时,问题不应该停在“谁能塞更多上下文”,而要拆成几层:项目规则、运行状态、用户附件、工具反馈、异步预取和历史摘要是否拥有不同来源、不同新鲜度和不同进入时机。
这样看,Context 的核心不是扩大输入窗口,而是输入治理。Claude Code 把 submitMessage()、processUserInput()、system/user/system context、attachments、memory 和 transcript 前置写入组织成一条装配线;Codex compact 失败问题也可以从这里反问:动态运行反馈是否应该和长期项目规则混在一起,摘要失败是否会污染后续任务,异步材料进入模型前是否有清晰边界。这个对比带来的设计理解是:优秀 agent harness 的 Context 层应该先把输入变成可分层、可追溯、可裁剪的协议对象,再交给模型推理。