系统篇

12|Codex、Claude Code、Copilot:从公开事实到可诊断运行链

系统篇约 6.3 千字1 组分步图解
本章目录

本章预备知识

源码阅读先跟对象流向,不先背类名。把一个输出项怎样变成工具调用、怎样携带调用ID、怎样进入执行注册表画清;闭源产品只描述已公开的边界。

本章各题列出所需基础。可先完成相应基础课,也可通过自检确认掌握程度。

进入深读前的小检查:用“已注册→可发现→已暴露→可授权→执行成功”逐级排查工具为何没用上,而不是看到配置文件就宣布生效。

术语带虚线时可点击速查。公式中的字母先看定义;不要用猜缩写替代推导。

三个产品不是同一套实现,也不是同一个界面的三个模型选项。本章对Codex使用固定源码快照,对Claude Code和Copilot使用公开产品文档;不声称知道闭源提示、全部调度策略或未公开服务端实现。

沿着对象与状态理解本章

比较编码产品时,先使用同一条公开的可诊断链:上下文组成、模型提议、宿主执行、结果回填、状态恢复。闭源产品未公开的内部机制保持未知;教学泳道不是对三款产品逐行源码的共同断言。

下方图解的固定输入在“输入与适用条件”中声明。它用于解释本章机制,不与本章其他独立例子的数值暗中接续。

动态图解 · F22

把一个Agent任务拆成真正发生的几轮

同一句用户任务,为什么可能调用模型不止一次?

LLM生成下一步提议,宿主执行获准的动作,把结果再交给LLM。这是外层任务循环;每次模型调用内部还要经历逐Token生成。外层的一轮工具行动不等于内部生成一个Token,两种“循环”不能混用。

调用标识把某次工具请求与其结果连接的ID。
工具结果程序实际执行后返回的内容。
上下文本轮明确交给模型的信息,而非整个电脑状态。

输入与适用条件:构造的只读教学任务:文件config.txt含timeout=30。泳道展示职责边界,不声称调用了真实商业API;数据和动作顺序固定。

1 / 8 · 1. 用户任务:读config.txt中的timeout

第1步,共8步

窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。

把一个Agent任务拆成真正发生的几轮:1. 用户任务:读config.txt中的timeout用户宿主LLM文件工具用户任务:读config.txt中的timeout模型请求:任务+read_file工具定义模型输出:call_id=c1,path=config.txt宿主校验后读取文件工具结果:timeout=30下一轮输入:原任务+调用+结果模型回答:配置的timeout为30宿主显示回答;任务结束

模型尚未看到磁盘文件。先区分用户给的任务与环境真实内容。

未读取

默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。

为什么需要

模型可以借助工具获得新证据,而不把一切都塞入参数。

怎样实现

按请求、校验、执行、结果回填、继续决策组织循环。

可能的代价与误解

忘记回填工具结果会让模型重复请求;把输出文本当执行证明会误报完成。

如何判断是否做对

对照每轮模型输入和工具日志,确认结果与call_id匹配。

Q045|Codex源码里,工具从模型可见到真正分派经过哪些对象?压缩又怎样替换历史?

核心回答

在本书检查的Codex提交ce0323f2f2d3b25e82806cd555237da3db4e1897中,ToolRouter区分注册表、模型可见schema与不同暴露方式;响应项先转成ToolCall,再包装ToolInvocation交给registry分派。压缩路径则构造新的历史、重建上下文并替换当前历史,不只是清空聊天文本。这是该快照的局部源码观察,不保证所有版本或托管产品相同。[CODEX-SRC]

先看真实字段,而不是凭名称猜架构

codex-rs/core/src/tools/router.rs包含registry、model_visible_specs、tool_mode、code_mode_tool_names和can_manage_children等字段。它们的分离直接说明“工具已注册”不等于“模型本轮能直接看见”。

exposes_tool检查标准化名称是否通过code mode映射、直接/命名空间schema暴露,或在存在tool search能力时能作为deferred工具找到。has_terminal_controls需要同时暴露启动与继续交互终端的两个工具;子Agent管理能力也根据相关工具集合计算。这里的“可达”仍不是对每次具体参数的最终授权。

调用转换路径可以按下列顺序阅读:

ResponseItem
  → build_tool_call
  → ToolCall {tool_name, call_id, payload, ...}
  → dispatch_tool_call_with_state
  → dispatch_tool_call_with_code_mode_result_inner
  → ToolInvocation {session, step_context, cancellation_token, tracker, ...}
  → registry.dispatch_any_with_state

build_tool_call对FunctionCall、客户端执行的ToolSearchCall、CustomToolCall分支处理,其余项可返回None。这说明普通文本与工具调用不是靠扫描自然语言里的函数名区分。参数解析错误也有返回模型的错误通道。真正handler、权限或沙箱检查需继续追踪registry和对应工具实现;只读router不能宣称已经审计全部执行安全。

压缩路径在compact.rs中克隆历史、准备模型输入、处理流完成或错误;成功后收集用户消息与摘要,构建压缩历史,重建world-state相关上下文,再调用replace_compacted_history并重算Token使用。源码还区分响应不完整、上下文超限、取消等错误,不能把所有失败都当普通重试。

运行示例 · Q045

从工具注册到真正dispatch,逐道看它能否到达

输入与条件。以本书记录的Codex固定提交ce0323f2f2d3b25e82806cd555237da3db4e1897为背景,设工具x已经进入注册表。

步骤与对象内部动作中间结果 / 新状态
1注册registry中存在x这只证明执行实现可被找到,不证明本轮模型能看见。
2暴露核对model_visible_specs、延后发现或code-mode路径隐藏工具不能仅凭注册成功就判定可用。
3模型输出响应项是可识别的FunctionCall或相应CustomToolCallbuild_tool_call把它转换成内部ToolCall。
4分派构建携带call_id、payload、session和step_context的ToolInvocation送到registry的dispatch路径。
5诊断注册计数增加但本轮调用仍不出现先检查暴露计划和实际请求,不急着归因于模型“不愿用”。

把过程连起来。注册、可发现、可见、可调用和执行成功是不同状态,应逐道观察。

边界与反例。源码讲解限已存档固定提交与路径,不声称当前所有Codex版本一致;权限等完整链路还需阅读相邻实现。

依据与适用范围:[CODEX]。示例输入和场景由本书明确设定。

追问:为什么固定commit比引用main路径重要?

主分支会变化,函数移动和行为改变会让行号失效。固定快照能让读者核对同一段代码。本书只用上述快照证明局部结构,不把它称为永远最新;更新产品时应重新定位调用链和测试。

追问:看到代码有retry,就能断言工具一定幂等吗?

不能。这里有模型流重试、压缩重试和工具执行等不同层。是否重复副作用取决于执行记录、handler和远端接口。源码阅读必须沿数据与副作用路径走,不能根据一个函数里的backoff推导全系统保证。

追问:为什么不逐字复制完整源码作为教程?

完整源码会淹没核心路径,且读者可能误把某版内部类型当稳定API。本书给出真实符号、路径、固定版本及中文控制流解释,原理与教学实现分开。需要编译该仓库时应使用其依赖与测试环境,本文没有声称完成源码编译或全量审计。

Q046|Claude Code怎样获得项目上下文?Subagent为什么不等于主Agent的完全复制?

核心回答

公开文档将Claude Code描述为围绕模型、工具和反馈运行的Agent,支持项目指令、技能、子Agent和上下文管理。子Agent可使用独立上下文与配置,主Agent通常接收其结果而非全部内部过程。具体内建提示和服务端细节未完整公开。[CLAUDE][SUBAGENTS][CLAUDEMEM]

用诊断视角展开一轮工作

当你打开仓库并提问,应分别检查工作目录是否正确、哪些项目指令被发现、技能是否相关、工具和权限是否可用、模型实际读取了哪些文件。这些检查是通用诊断方法,不是断言内部每个字段的精确顺序。

对于“分析某模块”子任务,主Agent可以传递目标与范围,子Agent在自己的工具/权限配置下读代码,返回根因、证据与建议。独立上下文减少主线程被长日志占满,但也形成信息瓶颈:子Agent若只说“没有问题”,主Agent无法知道检查了哪个版本、什么范围和什么测试。

项目指令适合稳定约束;自动记忆或持久笔记适合跨会话可用信息;当前任务进度则需要具体证据与状态。三者不能全部塞进一份越来越长的文件。长会话的工具输出清理或压缩可以减少上下文负担,但仍可能丢失细节,因此关键证据最好可重新定位。[CONTEXT]

运行示例 · Q046

子Agent只收到摘要,为什么它不知道主Agent的限制

输入与条件。主任务有约束“只读,不修改文件”。父Agent委派“调查配置问题”,子Agent拥有独立上下文。

步骤与对象内部动作中间结果 / 新状态
1父上下文用户原话明确禁止修改限制在父会话可见。
2委派消息只写“调查配置问题”不能假设子会话自动包含整段原历史。
3最小交接追加只读范围、具体问题、仓库版本和证据路径不必复制无关长对话。
4工具限制宿主对子任务只提供只读能力自然语言要求与工具权限共同约束。
5返回整合子Agent提供发现、证据和未解决问题父Agent仍负责用户整体目标。

把过程连起来。独立上下文节省父上下文成本,同时也需要有意识地传递必要约束。

边界与反例。这是独立子Agent模式的风险示例,不断言任何当前产品的默认继承字段;配置必须按公开文档与实际请求核查。

依据与适用范围:[CLAUDE-SUB] [CLAUDE]。示例输入和场景由本书明确设定。

追问:主Agent能用的MCP,子Agent一定能用吗?

不能作为跨产品、跨配置的普遍假设。要检查子Agent工具配置、权限模式、实际发现结果和运行日志。文件权限、MCP连接、模型可见schema是不同层;主线程已授权一次也未必意味着所有子Agent在所有上下文下继承同样能力。

追问:CLAUDE.md越长越能保证行为吗?

长指令可能互相冲突或淹没重点,也占用输入。应保留全局稳定规则,把局部专业流程放到按需内容,把事实放回可查询来源。自然语言规则是模型输入,不是确定性执行器;高风险限制仍需要真实权限和验证。

追问:无法看到内部Prompt,还能深入理解吗?

可以理解公开架构、接口语义、工具行为、上下文观察与可复现实验,但应停止在证据边界。通过控制变量测试某个配置是否改善任务是有效工程研究;从一次行为猜出“它内部一定用了某种隐藏路由”则不是事实。

Q047|Copilot的IDE、CLI、云端Agent为什么必须分开看?

核心回答

Copilot包含不同使用表面,工具、上下文来源、自定义Agent、权限和执行环境不应混为一谈。CLI的自定义Agent文档描述了基于配置的专用行为与工具集合;同名能力在IDE或云端可能有不同支持范围。[COPILOT][COPILOTSKILL]

从一次“Task Agent没加载Skill”逐层排查

先确定具体入口与版本:IDE聊天、CLI、后台编码任务还是其他表面。再看技能文件是否在该表面支持的发现位置,元数据是否有效,任务描述是否足以触发,是否实际读到了技能正文。最后检查技能要求的工具是否在这个Agent中暴露并允许使用。

故障可能出在发现:文件路径不被扫描;也可能出在选择:描述太泛或不匹配;也可能出在执行:技能读了但其依赖工具不可用。仅看到最终代码缺少某个模式,并不能证明Skill完全没加载。应看读取和执行证据,而不是让模型自报“我用了”。

仓库指令、路径特定指令、skill、custom agent和MCP各负责不同层。把同一大段规则复制到所有位置,可能暂时增加触发概率,也可能产生重复与冲突。更好的做法是先查目标表面的职责,再设计最小充分配置。

运行示例 · Q047

同一份仓库指令,在IDE、CLI与云任务里为什么可能不同

输入与条件。本地工作区有未提交的 rules.md;远程分支仍是旧版本。用户在IDE、本地CLI和云端任务分别运行相同问题。

步骤与对象内部动作中间结果 / 新状态
1IDE可能接入当前工作区与选中内容需要确认实际提供哪些缓冲区内容。
2CLI通常围绕当前目录和工具读到的文件读取范围、配置路径不能只凭IDE里看见什么来推定。
3云任务若从远程分支创建环境本地未提交修改不会自然出现。
4对账分别记录产品表面、仓库commit、工作树与指令来源先统一环境,再比较模型能力。
5反例云任务“没遵守新规则”原因可能是根本没取得该文件,而不是模型不会遵循。

把过程连起来。比较Agent产品前先比较它们拿到的版本、上下文入口与权限。

边界与反例。具体加载规则依产品表面和版本而定;本例展示一般分布式工作区差异,不伪造内部Prompt。

依据与适用范围:[COPILOT]。示例输入和场景由本书明确设定。

追问:为什么同一仓库同一句Prompt在IDE和CLI表现不同?

上下文来源可能不同,例如当前编辑器选择、未保存缓冲区、工作目录或可用工具;模型、默认指令、历史和权限也可能不同。比较时要控制这些变量,不能直接把差异归为某个产品“更懂业务”。

追问:自定义Agent声明了工具,模型就一定使用它吗?

声明通常是暴露/允许条件之一,而非强制调用程序。模型仍会根据任务判断。需要必然执行的验证可用确定性工作流或适当hook,而不是依赖描述里反复写“必须”。强制机制也应与风险相称。

追问:怎样做三产品公平对照?

同一任务、同一仓库快照、相同可见证据、相近预算、可比权限,分别记录结果与成本。无法控制的模型和托管环境差异明确列出。比较真实完成率而非只看一次演示或输出长度;也不要把不同表面的能力拼成一个不存在的“统一Copilot”。

Q048|怎样把“产品不好用”的抱怨转成可定位的问题?

核心回答

把失败分解为信息未发现、信息未加载、信息未利用、动作未执行、执行状态未知、验证不足和错误交付。逐层寻找首个偏离预期的证据,而不是在最后一层盲改Prompt。

一个可操作的诊断树

用户说“让它保留API兼容,它还是改了接口”。第一步确认原始约束进入了本轮有效上下文;若在旧会话且已压缩,检查压缩结果是否保留。第二步确认模型读取了调用方与兼容测试;若没读,应改善检索。第三步看计划/补丁是否明确识别兼容风险;若识别了但错误实现,需要实现和验证。第四步看测试是否覆盖旧调用;若只有新功能测试,绿灯不能排除回归。

同样,“没有用MCP”先看连接,再看发现,再看模型可见,再看调用意图,最后看实际执行拒绝。“Token太高”先看冗余上下文、工具返回量、重复失败和多Agent交接,不应一开始降低模型推理能力。

每个诊断结论都要带能反驳自己的检查。如果认为是检索问题,给定正确证据后任务仍失败,就要继续查模型/执行层;如果认为多Agent带来质量,单Agent在同预算下相同成功率,就需重新考虑编排价值。

运行示例 · Q048

找不到技能:用四个可观察事实逐步排除

输入与条件。症状:任务未使用某技能。可拿到配置、发现列表、本轮输入和执行日志。

步骤与对象内部动作中间结果 / 新状态
1查安装文件实际存在且格式可解析不存在时修安装,不能分析模型路由。
2查发现技能元数据是否出现在候选列表目录扫描或作用域不对时修发现链路。
3查输入本轮是否收到相关描述或显式指定未进入输入时不能说模型“忽略”。
4查执行技能已读但内部工具被禁用问题是能力或授权,不是技能未选择。
5最后才评测语义完整证据说明可见且可用但稳定误选用边界任务对比描述,不一开始增加更多规则。

把过程连起来。沿实际运行链找第一个缺失环节,比同时改模型、描述和权限更容易得到可靠结论。

边界与反例。流程是诊断方法,不要求为所有简单任务保留大量敏感原始Prompt;日志可做必要脱敏。

依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。

追问:什么是可重复的最小失败例?

保留导致故障的最少任务说明、仓库片段、配置和操作步骤,同时不删除关键边界。把不相关大仓库缩成小fixture能加快回归,但要确认缩小后仍复现同一机制,而不是制造另一个玩具问题。

追问:为什么不能凭一条trace推算系统成功率?

Trace解释一次运行发生什么,不提供任务分布上的概率。机制诊断与统计评估互补:前者找根因,后者判断改动是否普遍有效。单次成功可作为案例,不是总体收益证明。

追问:哪些地方不值得继续优化?

没有具体失败、没有可测收益、增加长期维护负担的机制要谨慎。若简单直接执行已稳定满足目标,再加一层路由和审查可能只增加成本。深入系统的最终目的,是知道哪里该改、哪里不该改,而不是把每层都做复杂。

记录保存在本机浏览器。

输入关键词即可检索。

↑ ↓ 选择 Enter 打开Esc 关闭 · 仅本地搜索

阅读设置

阅读设置仅保存在本机浏览器,不上传任何数据。