1. 为什么要在 Coding Agent 外面再套一层决策层
1.1 从两个真实痛点说起
先说一个我踩过的坑。去年有一段时间,我同时用两个 Coding Agent 处理日常开发任务:一个负责偏工程化的重构和脚本生成,另一个负责偏探索性的代码理解和方案推演。用着用着就发现一个很尴尬的问题——每次遇到一个任务,我得先自己判断"这个活该丢给谁"。判断本身不费劲,但判断的过程会打断心流,而且我经常判断错:明明是个需要长上下文推理的活,我丢给了擅长快速改文件的那个,结果来回改了三轮才收敛。
第二个坑更隐蔽。Coding Agent 本身是有"决策能力"的,但它的决策是任务内决策——给定一个 prompt,它决定先读哪个文件、先改哪一行、要不要跑测试。它缺的是任务前决策——这个任务到底该不该现在做、该用哪种模式做、该带多少上下文进去。这两层决策混在一起,导致 Agent 经常在错误的层面上使劲。
"Jev 接入 Claude Code 与 Codex"这件事,本质上就是解决这两个坑:在 Coding Agent 之上加一层快速决策能力,让"选谁做、怎么做、带什么进去"这三件事在进入 Agent 之前就被快速定下来。Jev 在这里扮演的是决策层的角色,Claude Code 和 Codex 是被调度的执行层。
1.2 这层决策能力到底解决什么问题
我把这层能力要解决的问题拆成三类,你可以对照自己的场景看看中了几条:
- 路由问题:同一个需求,不同 Agent 的擅长区间不一样。有的擅长在已有代码库里做精准修改,有的擅长从零生成一段独立逻辑,有的擅长读大量文件后给出结论。人工路由慢且不稳定。
- 上下文问题:Agent 的表现极度依赖喂进去的上下文。喂多了它抓不住重点,喂少了它瞎猜。快速决策层要能在进入 Agent 前,把上下文裁剪到"刚好够用"。
- 收敛问题:一个任务要不要拆成多轮、每轮的验收标准是什么、什么时候该停下来问人。这些如果全交给 Agent 自己判断,很容易陷入"改—测—再改"的循环。
注意:这层决策能力不是要替代 Agent 的推理,而是把"元决策"从 Agent 内部抽出来,放到一个更快、更可控、更便宜的地方。这是整个方案的核心设计哲学,后面所有细节都围绕它展开。
1.3 适合谁来参考这套思路
如果你符合下面任意一条,这篇内容对你会比较有用:
- 日常已经在用至少一个 Coding Agent,但觉得"每次都要自己想怎么用"很累;
- 团队里多人共用 Agent,希望有一套统一的调度规则而不是各凭手感;
- 想给 Agent 加一层轻量的前置处理,但不想引入重型编排框架;
- 对"决策层"这个概念感兴趣,想看看在 Coding 场景里具体怎么落地。
如果你只是偶尔用 Agent 写个一次性脚本,那这套东西可能有点重,可以先收藏,等任务复杂度上来了再回来看。
2. 整体架构设计:决策层与执行层怎么分工
2.1 三层结构:输入归一化、快速决策、执行分发
我把整个链路拆成三层,从上到下依次是:
- 输入归一化层:把用户五花八门的输入(一句话需求、一段报错、一个文件路径、一段伪代码)统一成结构化任务描述。
- 快速决策层(Jev 所在层):基于结构化任务描述,输出一个决策结果,包含目标 Agent、上下文清单、执行模式、验收标准。
- 执行分发层:把决策结果翻译成对应 Agent 能接受的调用形式,分别对接 Claude Code 和 Codex。
这个分层的意义在于每一层都可以独立替换。比如你以后想接入第三个 Agent,只需要在执行分发层加一个适配器,决策层的逻辑完全不用动。反过来,你想换一套决策规则,执行层也感知不到。
2.2 为什么决策层要"快"
标题里"快速决策"这四个字不是修辞,是硬约束。原因有三个:
- 决策层在关键路径上:它挡在用户和 Agent 之间,它慢一秒,整个交互就慢一秒。Agent 本身执行可能要几十秒,但决策层如果也要几秒,用户体感就是"卡"。
- 决策层要便宜:如果决策层本身也调用一个大模型做推理,那成本就翻倍了。快速决策层应该尽量用规则、轻量分类、缓存命中来完成大部分判断。
- 决策层要可解释:Agent 内部怎么想的你很难干预,但决策层必须能说清楚"为什么选了这个 Agent"。否则出了问题你没法调。
基于这三点,我在设计时定了一个原则:能用规则解决的绝不上模型,能用缓存命中的绝不重新计算,只有真正模糊的情况才走轻量推理。这个原则后面会反复出现。
2.3 决策结果的数据结构
决策层的输出我定义成一个固定结构,这样执行层才好对接。字段大致如下:
| 字段 | 含义 | 示例 |
|---|---|---|
| target | 目标执行器 | claude-code / codex |
| mode | 执行模式 | patch / generate / explore |
| context | 上下文清单 | 文件路径列表、片段范围 |
| acceptance | 验收标准 | 测试通过、编译通过、人工确认 |
| max_rounds | 最大轮次 | 3 |
| fallback | 兜底策略 | 换 Agent 重试 / 直接问人 |
这个结构看起来简单,但每个字段背后都有一堆取舍。比如mode为什么只有三种而不是更细?因为模式太细会导致决策层判断负担变重,三种是"够用且好判断"的平衡点。max_rounds为什么要有?因为不加这个,Agent 很容易无限循环。
2.4 与直接调用 Agent 的对比
为了说清楚这层决策的价值,我做个对比:
| 维度 | 直接调用 Agent | 加决策层 |
|---|---|---|
| 路由 | 人工判断 | 自动判断 |
| 上下文 | 人工挑选 | 自动裁剪 |
| 成本 | 单次调用 | 决策开销 + 单次调用 |
| 可解释性 | 弱 | 强(决策可记录) |
| 扩展性 | 换 Agent 要改习惯 | 加适配器即可 |
可以看到,加决策层唯一的代价是"决策开销",而这个开销通过规则化和缓存可以压到很低。收益是可解释性和扩展性,这两点在长期使用中价值很大。
3. 核心细节解析:决策层到底怎么判断
3.1 任务分类:先分清"改"和"造"
决策层第一步是把任务分成两大类:改已有代码和造新代码。这个判断看似简单,但它是后续所有决策的基础。
我的判断规则是这样的:
- 如果输入里包含明确的文件路径、函数名、报错信息,且这些指向的是已有代码库里的东西,归为"改"。
- 如果输入是"帮我写一个 XXX"、"实现一个 XXX 功能"且没有指向具体文件,归为"造"。
- 如果两者都有,比如"在 XXX 文件里加一个 YYY 功能",归为"改",因为主体是在已有结构里动刀。
为什么这个分类重要?因为"改"和"造"对 Agent 的要求完全不同。"改"要求 Agent 能精准理解现有代码的约束,"造"要求 Agent 能快速产出可运行的结构。Claude Code 和 Codex 在这两件事上的表现差异,是路由决策的主要依据。
3.2 上下文裁剪:给多少才刚好
上下文裁剪是决策层里最容易被低估的一环。我见过太多人直接把整个仓库丢给 Agent,然后抱怨 Agent 抓不住重点。实际上,Agent 的注意力是有限的,喂太多等于没喂。
我的裁剪策略分三步:
- 锚点定位:从输入里提取锚点,比如报错的文件名、函数名、行号。锚点是裁剪的起点。
- 扩散范围:从锚点向外扩散,扩散范围取决于任务类型。"改"任务扩散到调用方和被调用方,"造"任务扩散到同类实现作为参考。
- 预算控制:给上下文设一个 token 预算,超了就按相关性排序截断。
这里有个经验值可以参考:对于"改"任务,上下文控制在 2000 到 8000 token 之间通常比较合适;对于"造"任务,参考实现的上下文控制在 3000 token 以内,剩下的留给生成。这个数字不是绝对的,但可以作为起点。
提示:裁剪的时候宁可少给一点,让 Agent 主动去读,也不要一次给太多。Agent 主动读文件的过程本身就是在建立理解,这个理解比被动接收上下文更扎实。
3.3 模式选择:patch、generate、explore 的适用边界
三种模式的边界我总结如下:
- patch 模式:适用于明确的局部修改。特征是改动范围可预期、验收标准明确(比如测试通过)。这种模式要求 Agent 输出 diff 而不是完整文件,减少出错面。
- generate 模式:适用于从零生成或大范围重写。特征是现有代码参考价值低、需要 Agent 自由发挥。这种模式允许 Agent 输出完整文件。
- explore 模式:适用于"我还不确定要改什么"的情况。特征是任务描述模糊、需要先理解再动手。这种模式让 Agent 先输出分析报告,人确认后再进入 patch 或 generate。
模式选错的代价很大。我试过把本该 explore 的任务当成 patch 丢进去,结果 Agent 在没理解全局的情况下改了一堆文件,最后全回滚了。所以决策层在模式判断上要保守一点:拿不准的时候,先 explore。
3.4 验收标准:怎么定义"做完了"
验收标准是决策层里最容易被忽略但最重要的一环。没有验收标准,Agent 就不知道什么时候该停,人也不知道该不该接受结果。
我的验收标准分四级:
| 级别 | 标准 | 适用场景 |
|---|---|---|
| L1 | 编译/语法通过 | 任何代码改动的最低要求 |
| L2 | 相关测试通过 | 有测试覆盖的模块 |
| L3 | 新增测试通过 | 新增功能 |
| L4 | 人工确认 | 涉及设计决策的改动 |
决策层要根据任务类型自动选一个级别。比如纯格式化改动 L1 就够,新增功能至少要 L3。这个级别会写进决策结果,执行层据此判断是否继续。
4. 实操过程:从零搭起这套决策链路
4.1 环境准备与依赖梳理
先说环境。这套东西对运行环境要求不高,核心依赖就几样:
- 一个能跑脚本的运行时(我用的是 Python,你也可以用 Node);
- 两个 Agent 的调用入口(Claude Code 和 Codex 各自的命令行或 API);
- 一个轻量的规则引擎(其实用配置文件加 if-else 就够,不用上重型框架);
- 一个缓存层(本地文件缓存即可,不用上 Redis)。
我特意把依赖压到最低,因为决策层本身应该是"透明"的,依赖越多越容易出问题。你如果只是想验证思路,甚至可以先不接真实 Agent,用 mock 把决策链路跑通再说。
4.2 输入归一化的实现
输入归一化这一步,我写了一个简单的解析器,把输入映射成结构化任务。核心逻辑如下:
def normalize(raw_input): task = { "raw": raw_input, "anchors": extract_anchors(raw_input), # 文件路径、函数名、报错 "intent": classify_intent(raw_input), # fix / create / explore "scope": estimate_scope(raw_input), # local / module / repo } return taskextract_anchors用正则匹配文件路径和常见报错格式,classify_intent用关键词加简单规则,estimate_scope根据锚点数量和是否提到"全局""重构"这类词来判断。
这里有个细节:不要在这一步做太重的 NLP。归一化的目标是"够用",不是"完美"。我一开始想用模型做意图分类,后来发现规则能覆盖 80% 的情况,剩下 20% 走兜底就行,没必要为了 20% 把整条链路拖慢。
4.3 决策规则的编写与优先级
决策规则我用一个有序列表来组织,从上到下匹配,命中即停。大致长这样:
- 如果 intent 是 explore,直接选 explore 模式,目标 Agent 选擅长长上下文理解的那个。
- 如果 intent 是 fix 且 scope 是 local,选 patch 模式,目标 Agent 选擅长精准修改的那个。
- 如果 intent 是 create 且 scope 是 module,选 generate 模式。
- 如果 scope 是 repo,无论 intent 是什么,先降级为 explore,因为大范围改动风险太高。
- 兜底:选 explore 模式,让 Agent 先给分析。
这个顺序很重要。风险高的规则要排在前面,比如第 4 条"大范围改动降级",必须早于具体的 fix/create 判断,否则会被后面的规则覆盖掉。
4.4 对接 Claude Code 与 Codex 的适配层
适配层的职责是把决策结果翻译成各 Agent 能接受的调用。两个 Agent 的接口形态不一样,所以适配层要分别处理。
对接 Claude Code 时,我主要用它处理 patch 和 explore 模式,因为它在理解现有代码结构上比较稳。调用时把 context 清单转成它认识的路径参数,把 acceptance 转成它执行后要跑的验证命令。
对接 Codex 时,我主要用它处理 generate 模式,因为它在从零产出结构上比较快。调用时把 context 作为参考片段传入,把 max_rounds 作为它的重试上限。
适配层的关键是把决策结果里的抽象字段翻译成具体参数。这一步不要偷懒,翻译逻辑要写清楚,否则出了问题你根本不知道是决策错了还是翻译错了。
4.5 缓存与命中策略
缓存是让决策层"快"起来的关键。我缓存两类东西:
- 任务指纹到决策结果的映射:把归一化后的任务算一个指纹,命中就直接返回上次的决策。
- 锚点到上下文的映射:同一个文件同一个函数,裁剪出来的上下文基本一样,可以复用。
缓存失效策略我用的是"文件修改时间 + 任务指纹"双条件。文件没改、任务一样,缓存就有效。实测下来,重复任务的决策耗时能从几百毫秒降到几毫秒。
注意:缓存不要缓存"决策过程",只缓存"决策结果"。过程缓存会导致你调试时看到的是旧逻辑,很容易误判。
5. 常见问题与排查技巧实录
5.1 决策层选错 Agent 怎么办
这是最常见的问题。表现是:任务丢给了 A,A 做了一半卡住,换 B 才做完。排查思路是回看决策记录,看是哪条规则命中了、为什么命中。
我遇到过的典型原因是锚点提取失败。比如输入里写的是"那个处理用户登录的地方",没有具体文件名,锚点提取为空,决策层只能走兜底规则。解决办法是在归一化层加一个"模糊锚点"处理:如果提取不到精确锚点,就用关键词去代码库里搜,搜到候选再让用户确认。
5.2 上下文给多了导致 Agent 跑偏
表现是:Agent 读了一堆无关文件,然后在一个不相关的地方改了东西。排查时看决策结果里的 context 清单,如果清单长度明显超过预算,就是裁剪没生效。
原因通常是扩散范围设太大。我的经验是:扩散范围默认只扩一跳,也就是只包含直接调用方和被调用方,不要递归扩散。需要更多上下文时,让 Agent 自己主动去读,而不是一次性喂给它。
5.3 验收标准太松导致反复返工
表现是:Agent 说做完了,你一测发现没做完。排查时看决策结果里的 acceptance 级别,如果任务明显需要 L3 但决策给了 L1,就是级别判断错了。
修正方法是在决策规则里加一条:只要任务涉及新增逻辑,acceptance 至少 L3。这条规则能挡掉大部分"假完成"。
5.4 常见问题速查表
| 现象 | 可能原因 | 排查动作 | 解决方向 |
|---|---|---|---|
| 选错 Agent | 锚点提取失败 | 看决策记录 | 加模糊锚点处理 |
| Agent 跑偏 | 上下文超预算 | 看 context 清单 | 缩小扩散范围 |
| 反复返工 | 验收标准太松 | 看 acceptance 级别 | 提高级别下限 |
| 决策变慢 | 缓存未命中 | 看缓存命中率 | 优化指纹算法 |
| 无限循环 | max_rounds 缺失 | 看决策结果 | 补默认轮次上限 |
5.5 几个我踩过的坑
第一个坑是决策层和 Agent 抢活干。我一开始在决策层里也做了一点代码分析,结果和 Agent 的分析重复了,还互相矛盾。后来我把决策层的分析严格限制在"路由所需的最小信息",剩下的全交给 Agent。
第二个坑是规则越加越多。每遇到一个边界情况就加一条规则,加到三十多条的时候,规则之间开始互相干扰,维护成本爆炸。后来我改成"规则分层":核心规则不超过十条,边界情况走兜底加人工确认。
第三个坑是忽略决策日志。一开始我没记决策日志,出了问题只能靠回忆。后来加了结构化日志,每次决策记下命中的规则、输入指纹、输出结果,排查效率提升非常明显。
6. 这套方案还能怎么扩展
6.1 接入更多执行器
决策层的 target 字段现在是二选一,扩展成多选很自然。只要在执行分发层加适配器,决策规则里加对应的路由条件就行。我建议扩展时保持"每个执行器有明确的擅长区间"这个原则,不要为了接入而接入。
6.2 决策规则的自动化调优
现在规则是手写的,未来可以根据决策日志做统计:哪些规则命中后经常需要人工纠正,哪些规则几乎不命中。前者要改,后者可以删。这一步不需要多复杂,一个简单的统计脚本就能给出方向。
6.3 把决策层做成可观测的服务
如果团队多人共用,可以把决策层做成一个轻量服务,暴露一个决策接口,记录所有决策日志。这样团队能看到"最近哪些任务路由错了",形成反馈闭环。这一步的收益在多人场景下才明显,个人用可以先不做。
6.4 一个我个人的小技巧
最后分享一个我在实际使用中总结的小技巧:给决策层加一个"干跑"模式。也就是只输出决策结果,不真正调用 Agent。这样你在调整规则时,可以快速验证"如果按新规则,这个任务会被路由到哪",而不用真的跑一遍 Agent。这个模式帮我省了大量调试时间,强烈建议你也加上。
这套东西我用了几个月,最大的体会是:决策层的价值不在于它多聪明,而在于它把"怎么用 Agent"这件事从人的脑子里搬到了代码里。搬出来之后,它就可记录、可调优、可复用了。至于具体用哪个 Agent、哪条规则,反而是次要的,因为那些都可以慢慢调。