如果你也被下面这个场景折磨过,那你大概能秒懂这篇文章想解决什么问题:一个 Coding Agent 在某个中等规模页面功能上已经跑了二十多分钟。它先是翻遍了全仓库找类似实现,然后犹豫要不要引入一个状态管理库,接着又花了好几步去重构一个跟需求无关的模块,最后提交了一个你自己看了都想摔键盘的版本。
这不是模型不够聪明,这是典型的 agent 决策失控。模型每一步都写得很好,但整体方向却在无限发散。我在做模拟项目 X 的日常开发时反复遇到这类问题,后来干脆在 Claude Code 和 Codex 外面套了一层轻量决策编排模块,名字就叫 Jev。这篇文章会把 Jev 的设计思路、接入方式、踩坑经验完整记录下来——核心目标是给 Coding Agent 加一层快速决策能力,让它在正确的时间选对引擎、在跑偏之前及时止损。
1. 为什么 Coding Agent 需要一层"快速决策"——先看痛点
1.1 模型没变笨,是方向感丢了
我有个很明确的观点:现在大家抱怨 Coding Agent 不行,绝大多数情况不是模型能力不行,而是 agent 在错误的决策路径上走得太远。
拿一个很常见的需求举例:"给用户详情接口加一层基于缓存的读写优化"。如果没有决策层,agent 的典型行为是:
- 先搜索全仓库里有没有现成的缓存工具类;
- 发现没有,开始翻官方文档,琢磨要不要引入第三方缓存库;
- 又顺手打开当前接口的实现,觉得入口函数命名不够好,于是开始"顺手"重构;
- 中途跑一次测试,结果失败,又花三步去排查测试环境问题;
- 最后确实加了缓存,但同时也交回来十几个与本次需求无关的文件改动。
这个过程里每一步单独看都合理,合在一起就是灾难。问题出在哪?出在每一步的"局部最优决策"没有服务于全局目标。模型并不知道哪些探索是必要的,它只能靠上下文里的信息来决定下一步动作。如果没有一层机制在关键节点快速收敛方向,它就很容易陷入无限探索的循环。
我见过最夸张的一次,是某个 agent 为了给一个老接口加参数,竟然把隔壁两个服务的数据流都梳理了一遍,美其名曰"评估影响范围"。实际上那部分代码和需求毫无关系,纯粹是上下文里出现了相关字样,它就顺着读下去了。
1.2 慢决策带来的连锁反应
慢不只是"晚几分钟出结果"的问题,它会把三个问题一起放大:token 消耗、上下文污染、错误累积。
token 消耗是最容易感知的。一个中型任务让 agent 自由探索,动辄烧掉几十万 token,很多还是烧在无关代码阅读上。上下文污染更隐蔽:agent 一旦读了几段无关代码,这些内容就会残留在大脑里,后续每一步判断都被这些噪声干扰。最直接的体现是,它写着写着突然开始用另一个模块的命名风格,或者引用一个根本不相关的工具类。
错误累积则是雪崩式的。第一次小误判导致一个无关文件被修改,第二次误判就会在"这个文件已经被动过"的前提下继续扩大改动。等开发者回头看 diff,整个变更集里真正有价值的改动可能只占三分之一,剩下的都是 agent 在错误方向上制造的历史包袱。
我在模拟项目 X 里做过一次统计:无决策层时,一个 agent 完成改版任务平均要执行 12 到 18 步,其中 30% 到 40% 属于探索性、低产出步骤。这个现象不是某一个模型独有的,我分别用 Claude Code 和 Codex 跑过同一组任务,都有类似表现,只是具体形式不太一样。
1.3 Jev 的定位:不是新模型,是纪律层
所以 Jev 从一开始就不是"更聪明的模型",而是夹在任务与模型之间的一层纪律。它不写代码,它管节奏和边界。
需要回答的问题不是"这行代码怎么写",而是:
- 这个任务属于什么类型,该用哪个引擎;
- 当前这个方向值不值得继续投入;
- 预算还剩多少,要不要降级;
- 什么时候必须叫停,哪怕会中断看起来很顺的推进。
我把 Jev 比作一个贴身项目经理:它不一定比工程师更懂技术,但它负责盯着时间、范围、人力这三件事。模型负责生成能力,Jev 负责收敛能力。两者配合,Coding Agent 才既跑得快又不跑偏。
2. Jev 决策层的整体设计与工作流
2.1 决策层要回答的四个问题
设计 Jev 时,我把所有需要做的决策收敛成了四个问题。几乎所有坑都能归到这四个问题里:
- 做什么:任务本身是否清晰?模糊需求要先拆解,不能裸着丢给模型。
- 谁来干:选 Claude Code 还是 Codex,未来可能就是选 A 工具还是 B 工具。
- 怎么干:允许改哪些路径、禁止动哪些路径、用什么测试来验证。
- 何时停:什么时候该继续,什么时候该切换,什么时候该止损。
这四个问题对应 Jev 里的四个模块:预检器、路由表、预算控制器、健康监测器。模块之间通过一个统一的任务上下文对象通信,这个对象贯穿任务生命周期,相当于 agent 的"共享记忆"。
2.2 接入两个引擎时的架构形态
Jev 在架构上分三层。
最上面是入口层,接收开发者的任务请求,无论通过命令行还是 IDE 插件接入都行。中间是决策层,也就是 Jev 本体,它不直接碰任何模型。最下面是执行层,里面有两个适配器:Claude Code 适配器和 Codex 适配器。
决策层和执行层之间用一套"引擎无关协议"通信。所谓协议,就是我定义的一个统一接口:输入侧是任务描述、仓库快照和一组约束条件,输出侧是事件流。适配器负责把协议翻译成各个引擎听得懂的话,再把引擎的实时输出转换回统一事件流。
这样做最大的好处是:Jev 的核心逻辑完全不感知对面是 Claude Code 还是 Codex。换引擎时只需要新写一个适配器,决策层、预算控制、健康监测这些公共能力完全不用动。当时决定这么搞,就是不想把路由逻辑跟两套 SDK 的细节绑死,否则每改一次都要同步改两边,迟早把人逼疯。
2.3 核心模块拆解
预检器的职责是任务启动前做一次快速体检。它会扫描任务描述、涉及的文件路径范围、仓库里相关模块的规模,然后输出一个复杂度评分。这个评分决定了后续的预算大小和路由策略。
路由表根据复杂度评分和任务特征做引擎选择。初始规则很简单:大范围重构类任务优先 Claude Code,多方案探索验证类任务优先 Codex,小改动直接走最快路径不绕弯。具体规则后面专门讲。
预算控制器为每个任务分配 token 预算、步数预算和时间预算。预算不是死的,任务推进过程中会根据实际完成度动态调整。比如任务预期 10 步完成,但跑到第 7 步时只完成了一小部分,Jev 会预警而不是盲目加预算。
健康监测器是 Jev 最关键的模块。它盯的不是代码质量,而是"agent 是否在空转"。判断标准很直接:连续 N 步没有文件修改、没有触发测试、没有输出有信息量的工具调用结论,就判定为空转,触发干预。
3. 接入 Claude Code 与 Codex:接口与协议层的实现细节
3.1 为什么不能直接分别调用两边 SDK
很多人第一反应是:接入两个引擎,直接各自调 SDK 不就行了?可以,但你会被两个问题折磨。
第一是接口风格差异巨大。Claude Code 偏向本地终端 agent 的交互方式,工具调用、文件编辑、命令执行是主要动作,它习惯在你当前的工作区里做事情。Codex 偏向云端沙箱的批处理方式,强调隔离环境里的多步任务执行,跑完之后交回一个变更集。如果你在 Jev 里直接对着两套 SDK 写逻辑,路由、预算、健康检查这些公共能力就得写两遍,每改一个参数都要同步两边。
第二是难以统一做交叉判断。Jev 的价值在于把两个引擎的事件放在同一套语义下分析。如果两边事件格式都不一样,健康监测器看到的东西就完全是两码事,没法做横向对比。
所以我在底层定义了一套统一协议,用 TypeScript 描述大概是这样:
type EngineTask = { id: string; instruction: string; repoSnapshot: string; allowedPaths: string[]; forbiddenPaths: string[]; budget: { maxTokens: number; maxSteps: number; maxSeconds: number; }; }; type EngineEvent = | { type: "step_started"; stepIndex: number } | { type: "tool_called"; tool: string; args: unknown } | { type: "file_modified"; path: string; diffStats: { added: number; removed: number } } | { type: "test_triggered"; command: string; result: "pass" | "fail" } | { type: "task_aborted"; reason: string };输入侧统一了任务描述、仓库快照和约束条件,输出侧统一了事件流。两个适配器只做一件事:翻译。Claude Code 适配器把协议翻译成终端 agent 的任务提示,Codex 适配器把协议翻译成云端沙箱的执行指令。
3.2 两个适配器的具体适配点
具体到实现,两个适配器的差别比想象中大。
Claude Code 适配器要做三件事:把统一任务包转换成适合终端 agent 的任务提示;监听它的步骤事件、工具调用事件和文件变更事件;在任务包里附带一份"战术约束文件",相当于给它一段系统级的边界说明,明确哪些事绝对不做。
Codex 适配器就麻烦一点:需要先把仓库快照同步到云端沙箱环境;它的输入输出天然更结构化,任务定义和验收条件都可以直接写清楚;跑完一轮之后返回完整变更集,Jev 轮询拿到变更集再转换回统一事件流。
有一个差异特别值得提醒:Claude Code 对当前分支上的存量修改有感知,它会尊重你已有的未提交改动;Codex 的沙箱是干净环境,存量修改必须显式打包成 patch 传进去,否则它完全不知道这回事。这个差异在我接入第一天就坑了一次——我最初以为两边对工作区状态的理解一致,结果 Codex 跑出来的方案直接忽略了我本地一堆未提交的改动。
但核心逻辑还是要落在统一协议里。协议稳了,其他小差异都能通过适配器消化掉。
3.3 路由策略:什么时候选谁
路由不能搞玄学,我总结了几条很直白的规则:
- 任务描述里出现"重构、迁移、拆分、大范围修改"这类信号,且涉及文件数量较多,优先 Claude Code。它处理长上下文和既有代码结构的能力更强,适合在一坨旧代码里做手术。
- 任务描述接近"搜索答案、对比方案、验证某个假设",优先 Codex。这类任务交给隔离沙箱跑更安全、更干净,不会把当前工作区搞得一团糟。
- 非常明确的小改动,比如改一个配置项、加一个字段,直接交给一个引擎快速完成,压根不需要决策层做太多判断。
这里有个重要的设计原则:路由的目的不是"选最好的引擎",而是"减少来回切换和重复建上下文的成本"。模型切换的成本非常高,一个新引擎没有你前面积累的上下文,等于把所有工作重做一遍。所以路由宁可保守一点,也不要频繁换人。
4. "快速决策"的真正难点:延迟预算与降级策略
4.1 决策本身也有成本
文章标题里有个关键词是"快速决策能力",这里的"快速"不是形容词,是硬指标。
如果 Jev 的每个决策都要去调一次完整大模型,整个流程会变得更慢,决策层反而成为新瓶颈。我做过一次很蠢的尝试:让 Jev 在每个工具调用之后都问一遍"下一步怎么走",结果单任务耗时翻了将近一倍,token 消耗也暴涨。
这次尝试直接确立了 Jev 的第一原则:能用规则决策,就绝不调模型。规则决策的成本在毫秒级,而且可解释、可调试。比如判断"是否在小文件上做单行修改",直接看 diff 统计就够了,完全不需要模型出场。用最大型的工具解决最小的问题,听着很爽,实际上是在烧钱买延迟。
4.2 四级决策降级策略
Jev 的决策分四级,按成本从低到高排列:
Level 0 纯规则决策。用关键词、文件路径统计、diff 规模这类硬信号直接输出结论。耗时一般小于 5 毫秒,用于大多数确定性判断。
Level 1 小型模型预判。需要做意图分类、任务类型识别这类模糊判断时,用轻量模型跑一次。耗时在几百毫秒级别,输出不是一个终局,而是一个带置信度的候选推荐。
Level 2 完整 LLM 评审。这是真正烧预算的决策,只在关键节点触发:比如要不要切换引擎、要不要终止任务、要不要修改预算。这种决策会带上完整任务上下文去问大模型,耗时从两三秒到十几秒不等。
Level 3 人工介入。当连续两次 Level 2 的决策置信度都低于阈值,或者预算已经耗尽,Jev 会把现场整理成一份结构化报告,交给开发者做最终判断。这一步不追求自动化,只追求输得明明白白。
每个决策器输出结论时同时输出一个 confidence 分数。置信度低时,Jev 会自动升一级决策方式再做一次交叉确认,而不是直接采信低质量的结论。
4.3 延迟预算与超时控制
我给自己定的延迟预算很简单:普通任务的全流程决策总耗时不超过 2 秒,复杂重构任务不超过 15 秒。预算的含义就是"决策层额外占用的时间",这个时间必须从任务总时长里省回来,否则没有意义。
为了严格执行预算,每个 Level 2 决策器都挂了超时器。超过 10 秒没返回,Jev 直接采信 Level 1 的结果继续跑,决策绝对不能阻塞执行。超时会自动记录到决策日志里,事后复盘能看到底是哪个节点老超时。
这个思路有点像高并发系统里的熔断机制:决策服务再重要,也不能拖垮主流程。宁可给一次次优判断,也好过让整个 agent 停在原地干等。很多人在设计 agent 框架时忽略了这一点,总是追求"每一步都最优",结果每一步都慢,整体体验反而最差。
5. 实测效果与关键调优:从"能用"到"好用"
5.1 接入前后的对比数据
坦白说,这类数据在不同仓库、不同模型版本下波动很大,我不建议把我下面这组数字当标准答案,只当参考。这是我们在模拟项目 X 上连续两周、共 40 个真实开发任务里统计的中位数:
| 指标 | 裸跑(无决策层) | 接入 Jev 后 |
|---|---|---|
| 单任务总耗时 | 18.6 分钟 | 9.4 分钟 |
| 无效探索步骤占比 | 35% | 12% |
| token 消耗(中等规模任务) | 约 22 万 | 约 11.5 万 |
| 一次通过率(不返工) | 55% | 72% |
| 需要人工干预的任务占比 | 30% | 18% |
数字好看的原因不只是"决策变快",更关键的是 Jev 砍掉了大量无意义探索,让每一步都花在刀刃上。尤其是无效探索步骤从 35% 砍到 12%,这一项直接带动了 token 和耗时的同步下降。
5.2 踩坑记录:误判、来回切换、过度压缩
过程不可能一帆风顺,挑三个印象最深的坑说。
坑一:用文件数量衡量复杂度,严重误判。最初预检器把"涉及文件数量"当复杂度核心指标。结果遇到一个"单文件三千行、早该拆没拆"的老模块,预检器给了一个低复杂度,直接走了小改动快速路径。跑起来才发现改造量远超预期,预算和引擎全都不对。修复方案是加入文件内部的信号:TODO 数量、魔法值密度、重复代码块占比、导入关系复杂度,综合起来评分,不能只看文件个数。
坑二:频繁切换引擎反而更慢。我一开始在每一步都做路由,看起来很智能,实际是灾难。典型的场景是:Claude Code 已经构建了丰富上下文,刚准备发力,Jev 看到新文件出现就切到 Codex,Codex 需要重新同步整个仓库、重建上下文,一次完整的任务启动成本就被白白浪费掉。修复方案是引入切换冷却期:一个引擎至少要跑完当前里程碑,或者累计 6 步以上,才被允许切换。
坑三:上下文压缩过度,agent 开始自由发挥。为了省 token,我把历史记录压成摘要,压到一定程度后 agent 忘了需求原文,开始按自己的理解扩张改动范围。这比没压缩还可怕,因为它连自己最初的出发点都丢了。修复方案是划出两个不可压缩区:需求原文区和已作出决策的结论区。这两块内容永久保留完整信息,其他过程细节才允许压缩。
5.3 三个值得抄的参数
如果你也想做一个类似的决策层,我建议优先抄这三个参数:
- 空转判定阈值:连续 3 步没有 file_modified 或 test_triggered 事件,就判定为空转,立刻让 agent 输出一段解释,再由 Jev 决定继续、切换还是终止。
- 切换冷却期:默认 6 步。冷却期内除非出现测试全红或者明确的安全风险,否则不换引擎。
- 预算收尾模式:剩余预算低于 15% 时,Jev 强制把任务从"继续探索"切成"整理产物并提交"。这保证了任务没做完时也能留下一个能看、能跑、能回滚的半成品,而不是所有成果都烂在 agent 的上下文里。
这三个参数每个单独拿出来都不复杂,但组合在一起就形成了完整的止损机制。空转判定保证了"不白跑",切换冷却保证了"不白切",收尾模式保证了"不白烧"。
6. 从"双引擎决策"到"多工具编排":扩展思路与个人体会
6.1 Jev 还能管什么
Claude Code 和 Codex 只是我接入的第一批执行引擎。统一协议稳定之后,Jev 的决策能力可以往外扩展很多。
一个是多仓库任务拆解。大型改动横跨多个仓库时,Jev 可以先用 Level 2 决策做一次全局拆解,把子任务分发给不同引擎并行执行,再统一汇总和验证。这个场景下,决策层的价值比单仓库场景更明显,因为跨仓库的上下文断裂问题更严重。
另一个是接入更多工具信号。比如把测试框架的失败结果直接喂给健康监测器,看 agent 是不是在同一个测试上反复碰壁;把 lint 结果作为文件修改质量的实时反馈;把编译错误频率作为任务难度的动态指标。这些信号都是现成的、结构化的,接入成本很低,但能显著提升决策的判断质量。
如果再接上持续集成反馈,决策层甚至可以往自动化运维大脑的方向走:什么时候该跑验证、什么时候该降级到人工、什么时候该直接回滚,它都能提前给出判断方向。
6.2 我在实测中的几点体会
做完这个接入项目,我最大感受是:给 Coding Agent 加决策能力,本质上是给开发流程加一套止损纪律。
模型没有边界感,再聪明的模型也会在局部最优里越走越远。Jev 的价值不在于每次都做出最聪明的选择,而在于它会主动叫停、主动切换、主动降级。宁可让 agent 少走几步冤枉路,也好过让它闷头狂奔到最后交出一个不可用的结果。
另一个经验是:决策层的日志比决策本身更值钱。Jev 会把每次路由、每次干预都写成结构化日志,比如:
{ "taskId": "demo-task-2311", "ts": "2025-06-12T14:32:18.021Z", "decisionType": "engine_route", "level": 1, "confidence": 0.82, "conclusion": "route_to_claude", "signals": { "task_type": "refactor", "file_count": 14, "complexity_score": 7.2 } }复盘的时候,你能清清楚楚看到 agent 在哪个节点开始跑偏。这些数据比任何抽象建议都更有用。我现在已经养成了习惯:每次任务结束先翻决策日志,而不是只看最终 diff。
6.3 后面打算怎么做
目前 Jev 还只覆盖"任务启动前"和"任务执行中"两段决策。下一件事是把决策日志做成可回放的事件流,这样任务失败后可以精确看到 agent 从哪一步开始偏离目标,再针对这个节点做专项约束。这个回放能力我目前只能靠人工翻日志实现,还没有完全自动化。
另一个方向是把预算控制从"按任务分配"升级成"按收益动态分配"。同样 100 个 token 的预算,投入在验证假设上的收益更高,那决策层就该给探索性步骤让路,而不是平均分配。这个模型还在打磨,等稳定了我再单独写一篇。至于最后会不会把 Jev 整理成一个独立开源项目,我倾向于会,但还需要一段时间把现有的内部逻辑和协议文档化,毕竟现在它身上还带着很多模拟项目 X 的特化逻辑。