1. 为什么要在 Coding Agent 外面再套一层决策层
1.1 从两个真实场景说起
先聊两个我最近半年反复遇到的场景。
第一个场景:我在一个中型前端项目里用 Coding Agent 做重构,任务是把一个用了三年的状态管理方案迁移到新的架构上。Agent 拿到任务之后,第一步就开始读文件,读了两百多个文件,然后开始改,改到一半发现某个核心模块的依赖关系它没理解对,于是回滚,重新读,重新改。整个过程消耗了大量上下文窗口和时间,最后交付的结果还带着三处隐蔽的循环依赖。
第二个场景:我在一个数据处理脚本里让 Agent 帮我加一个边界条件判断。这个任务其实很小,但 Agent 依然走了完整的"读文件—分析—规划—执行—验证"流程,花了将近两分钟才给出一个五行代码的修改。
这两个场景指向同一个问题:Coding Agent 的决策粒度和任务粒度不匹配。大任务它容易迷路,小任务它又过度规划。而 Jev 这个项目要解决的,就是在 Agent 和具体任务之间插入一层轻量的快速决策能力,让 Agent 在动手之前先判断"这件事该用什么策略做"。
1.2 Jev 到底是什么
Jev 是一个面向 Coding Agent 的决策路由层。它本身不做代码生成,也不做文件读写,它做的事情是在任务进入 Claude Code 或 Codex 这类 Coding Agent 之前,先对任务做一次快速分类和策略匹配,然后决定:
- 这个任务应该用哪种执行模式(直接改、先规划再改、先探索再改、还是拆成子任务)
- 需要加载哪些上下文(全量文件、局部文件、还是只需要接口签名)
- 用哪个 Agent 后端更合适(Claude Code 擅长长上下文推理,Codex 擅长精确代码补全)
- 是否需要人工确认节点
你可以把它理解成一个"任务分诊台"。病人(任务)来了,先分诊,再决定去哪个科室、做什么检查,而不是直接推进手术室。
1.3 为什么不是直接调 Agent API
有人可能会问:Claude Code 和 Codex 本身就有任务理解能力,为什么还要在外面套一层?
这个问题我一开始也想过。实测下来,直接调 Agent API 有三个绕不过去的坎:
第一,Agent 的规划成本很高。每次让 Agent 自己判断"该怎么做",它都要消耗 token 做推理。对于高频的小任务,这个开销累积起来很可观。Jev 的做法是用轻量规则加小模型做前置判断,把大部分简单任务的决策成本压到接近零。
第二,Agent 的决策不可控。同一个任务,你今天问它和明天问它,它可能给出不同的执行策略。在团队协作场景里,这种不确定性会带来很大的沟通成本。Jev 把决策逻辑显式化,策略可配置、可审计、可复现。
第三,多 Agent 协作需要统一入口。当你同时用 Claude Code 和 Codex 的时候,如果没有一层统一的路由,每个 Agent 各自为政,上下文不共享,任务边界不清晰。Jev 提供了一个统一的决策入口,让不同 Agent 各司其职。
提示:Jev 不是要替代 Agent 的推理能力,而是把"策略选择"这件事从 Agent 的推理循环里抽出来,让 Agent 专注于它最擅长的事情——在给定策略下执行具体操作。
2. Jev 的核心架构与决策模型拆解
2.1 三层结构:路由层、策略层、执行层
Jev 的架构可以拆成三层,我用一个实际的任务流来串讲。
假设你提交了一个任务:"把用户模块的密码加密方式从 MD5 换成 bcrypt,并更新所有相关测试。"
路由层先接手。它做的是任务分类:这是一个"代码修改 + 测试更新"的复合任务,涉及安全敏感操作,影响范围中等。路由层输出一个任务标签:refactor + security + medium-scope。
策略层根据标签匹配策略。安全相关的重构任务,策略库里对应的规则是:必须先做影响面分析,必须加载所有调用方文件,必须生成变更清单供人工确认,执行阶段用 Claude Code 做推理、用 Codex 做具体代码替换。
执行层按照策略生成执行计划,分派给对应的 Agent,并在关键节点插入确认点。
这三层的职责边界很清晰:路由层只做分类不做决策,策略层只做匹配不做执行,执行层只做操作不做判断。这种分离带来的好处是,每一层都可以独立替换和测试。
2.2 决策模型:规则优先,模型兜底
Jev 的决策模型采用"规则优先,模型兜底"的策略。这个选择背后有明确的工程考量。
规则引擎处理的是高频、明确的任务模式。比如:
| 任务特征 | 匹配规则 | 执行策略 |
|---|---|---|
| 单文件、少于50行改动 | 微任务规则 | 直接执行,跳过规划 |
| 涉及配置文件修改 | 配置规则 | 先备份,再修改,后验证 |
| 跨三个以上模块 | 大范围规则 | 强制拆分子任务 |
| 包含"测试""test"关键词 | 测试规则 | 先跑现有测试,再改代码 |
| 安全相关关键词 | 安全规则 | 强制人工确认节点 |
规则覆盖不到的任务,才交给小模型做分类。小模型只做分类不做规划,输出的是任务标签,不是执行步骤。这样既控制了成本,又保证了覆盖率。
实测下来,在一个中等规模的代码库里,规则引擎能覆盖大约七成的日常任务,剩下三成走模型分类。模型分类的延迟在几百毫秒级别,对整体体验影响很小。
2.3 与 Claude Code 和 Codex 的接入方式
Jev 接入这两个 Agent 的方式不太一样,因为它们的接口特性和擅长领域不同。
接入 Claude Code走的是会话式接口。Jev 把策略层生成的执行计划作为系统提示的一部分注入会话,Claude Code 在会话中按照计划执行。Jev 会在会话的关键节点监听输出,判断是否需要触发确认或回滚。
接入 Codex走的是补全式接口。Jev 把任务拆成具体的代码修改点,每个修改点作为一个独立的补全请求发给 Codex。这种方式适合精确的、局部的代码替换,不适合需要全局推理的任务。
两者的分工原则是:需要理解大范围上下文、做架构级判断的任务走 Claude Code;需要精确修改、局部替换的任务走 Codex。Jev 的策略层会根据任务标签自动选择后端,也支持手动指定。
注意:接入层需要处理两个 Agent 的上下文格式差异。Claude Code 的会话上下文是累积的,Codex 的补全上下文是每次独立的。Jev 在中间做了一层上下文适配,把累积上下文按需裁剪后传给 Codex,避免上下文污染。
3. 快速决策能力的实现细节
3.1 任务特征提取:从自然语言到结构化标签
决策的第一步是把自然语言任务描述转成结构化特征。Jev 提取的特征维度包括:
- 操作类型:新增、修改、删除、重构、查询
- 影响范围:单文件、单模块、跨模块、全局
- 风险等级:普通、敏感(安全、数据、配置)、高危(删除、迁移)
- 任务复杂度:微任务(单点修改)、小任务(单文件多改)、中任务(多文件)、大任务(跨模块)
- 验证需求:是否需要测试、是否需要人工确认
特征提取用的是关键词匹配加轻量语义分析。关键词匹配负责快速命中,语义分析负责处理同义表达。比如"把 A 换成 B"和"用 B 替代 A"会被归到同一类操作。
这里有个实操心得:特征提取的准确率不需要追求百分之百。我一开始想把准确率做到九成以上,后来发现投入产出比很低。实际上,只要把高风险任务识别准确,普通任务的误判成本很低,因为 Agent 本身有一定的纠错能力。
3.2 策略匹配:决策树的构建与调优
策略匹配的核心是一棵决策树。树的每个节点是一个特征判断,叶子节点是执行策略。
构建这棵树的时候,我踩过几个坑:
第一个坑是树太深。一开始我把所有特征都串起来判断,树有七八层,结果就是匹配逻辑复杂、维护困难、调试痛苦。后来改成扁平化设计,先按风险等级分三大支,每支下面再按影响范围分,最多三层。
第二个坑是策略太细。我一开始定义了二十多种执行策略,后来发现很多策略之间的差异很小,合并之后只剩八种核心策略。策略数量减少之后,匹配准确率和可维护性都提升了。
第三个坑是缺少兜底。决策树必须有兜底分支,当所有特征都不匹配时,走默认策略:先探索再执行,并插入人工确认节点。这个兜底策略救了我很多次。
调优的方法论是:先跑一批真实任务,记录每个任务的决策路径和最终结果,找出误判的案例,分析是特征提取的问题还是策略匹配的问题,然后针对性调整。这个过程需要迭代几轮,但每轮都能明显提升准确率。
3.3 上下文加载策略:按需加载而非全量加载
上下文加载是影响 Agent 表现的关键因素。加载太少,Agent 理解不充分;加载太多,上下文窗口被占满,推理质量下降。
Jev 的上下文加载策略分三档:
最小加载:只加载目标文件本身。适用于微任务和单文件修改。
局部加载:加载目标文件加直接依赖文件。适用于单模块内的修改。
扩展加载:加载目标文件、直接依赖、间接依赖、以及相关测试文件。适用于跨模块修改和重构任务。
加载策略由决策树根据任务特征自动选择。这里有个细节:扩展加载不是一次性把所有文件塞进去,而是分批加载,每批加载后让 Agent 判断是否还需要更多上下文。这样可以避免一次性加载过多无关文件。
实测数据:在一个约五万行的代码库里,最小加载平均加载三个文件,局部加载平均加载十二个文件,扩展加载平均加载三十五个文件。扩展加载的 token 消耗是最小加载的十倍左右,但只在真正需要的时候才触发。
4. 实操过程:从零搭建 Jev 决策层
4.1 环境准备与依赖安装
Jev 本身是一个轻量的服务,运行环境要求不高。我用的是 Python 3.11,主要依赖三个库:用于规则匹配的rule-engine,用于轻量分类的onnxruntime,以及用于接入 Agent 的 HTTP 客户端库。
安装步骤:
python -m venv jev-env source jev-env/bin/activate pip install rule-engine onnxruntime httpx pyyaml配置文件用 YAML 管理,主要分三块:规则配置、策略配置、Agent 接入配置。规则配置定义特征提取的关键词和模式,策略配置定义决策树的结构,Agent 接入配置定义两个后端的连接参数。
提示:轻量分类模型建议用蒸馏后的小模型,参数量控制在几千万级别。我用的是一个经过任务分类微调的小模型,推理延迟在两百毫秒以内,准确率能满足分类需求。
4.2 规则引擎的配置与调试
规则配置是 Jev 的核心配置。每条规则包含匹配条件、优先级、以及对应的任务标签。
一个典型的规则配置长这样:
rules: - name: security_refactor priority: 100 conditions: keywords: ["密码", "加密", "密钥", "token", "认证"] operations: ["修改", "重构", "替换"] labels: risk: high category: security require_confirmation: true - name: micro_task priority: 50 conditions: scope: "single_file" line_change: "<50" labels: complexity: micro skip_planning: true调试规则的时候,我建议先用一批历史任务做回放测试。把过去一个月里 Agent 处理过的任务拿出来,跑一遍规则引擎,看标签是否合理。这个过程能发现大部分规则冲突和遗漏。
规则冲突的处理原则是:高优先级规则覆盖低优先级规则,同优先级规则按配置顺序匹配。我一般把安全相关规则设为最高优先级,确保它们不会被其他规则覆盖。
4.3 决策树的实现与策略注入
决策树的实现我用的是配置驱动的方式,树结构写在 YAML 里,代码只负责遍历。
decision_tree: root: feature: risk branches: high: feature: scope branches: global: strategy: full_analysis_with_confirmation module: strategy: module_analysis_with_confirmation normal: feature: complexity branches: micro: strategy: direct_execute small: strategy: plan_then_execute medium: strategy: explore_plan_execute large: strategy: decompose_and_execute策略注入的方式是把策略转成 Agent 能理解的提示词。比如direct_execute策略会转成:"直接执行以下修改,不需要额外规划,修改后简要说明改动内容。"而explore_plan_execute会转成:"先探索相关文件,理解现有实现,然后给出修改计划,确认后再执行。"
策略提示词的措辞很关键。我试过很多版本,最后发现简洁明确的指令效果最好。太长的提示词反而会让 Agent 困惑。
4.4 接入 Claude Code 的完整流程
接入 Claude Code 的流程分四步:
第一步,建立会话。Jev 通过 HTTP 接口创建一个新会话,把策略提示词作为系统消息注入。
第二步,注入上下文。根据上下文加载策略,把相关文件内容分批注入会话。每批注入后,Jev 会检查会话的 token 使用量,接近阈值时停止注入。
第三步,提交任务。把用户的任务描述提交到会话,等待 Agent 响应。
第四步,监听与干预。Jev 持续监听 Agent 的输出,在关键节点(如准备执行删除操作、准备修改安全相关代码)触发确认请求。如果用户拒绝,Jev 会向会话发送中断信号并回滚。
这里有个实操细节:Claude Code 的会话有超时限制,长时间不活动会断开。Jev 在会话空闲时发送心跳保持连接,避免任务执行到一半会话失效。
4.5 接入 Codex 的完整流程
接入 Codex 的流程相对简单,因为它是无状态的补全接口。
第一步,任务拆解。Jev 把任务拆成具体的代码修改点,每个修改点包含目标文件、修改位置、修改意图。
第二步,构造补全请求。每个修改点构造一个补全请求,请求里包含目标文件的局部上下文和修改意图描述。
第三步,发送请求并收集结果。并发发送多个补全请求,收集返回的代码片段。
第四步,应用修改并验证。把返回的代码片段应用到目标文件,然后跑验证(语法检查、测试)。
Codex 的补全结果需要做后处理,因为补全接口返回的是代码片段,不保证与目标文件的格式一致。Jev 做了一层格式化适配,确保应用后的代码风格统一。
注意:Codex 的补全请求对上下文长度有限制,构造请求时需要裁剪上下文。裁剪原则是保留目标位置前后的完整语法块,去掉无关的注释和空行。
5. 常见问题与排查技巧实录
5.1 决策误判的排查思路
决策误判是最常见的问题。排查的时候,我一般按这个顺序走:
先看特征提取。把任务描述和提取出的特征对照,看是否有特征漏提或错提。常见的是关键词覆盖不全,比如"优化"这个词没有归到"修改"类操作里。
再看规则匹配。如果特征提取没问题,就看规则匹配。常见的是规则优先级设置不当,导致低优先级规则覆盖了高优先级规则。
最后看策略执行。如果前两步都没问题,那就是策略本身不适合这个任务。这时候需要调整策略定义,或者增加新的策略分支。
我整理了一个排查速查表:
| 现象 | 可能原因 | 排查方法 | 解决方式 |
|---|---|---|---|
| 简单任务走了复杂流程 | 复杂度特征提取错误 | 检查任务描述中的行数、文件数信息 | 补充复杂度特征提取规则 |
| 高风险任务没触发确认 | 风险关键词未命中 | 检查风险关键词库 | 补充关键词或调整优先级 |
| 上下文加载过多 | 影响范围判断过宽 | 检查依赖分析逻辑 | 收紧依赖分析深度 |
| Agent 执行偏离策略 | 策略提示词不清晰 | 检查注入的提示词 | 简化提示词,明确指令 |
| 会话中途断开 | 心跳机制失效 | 检查心跳配置 | 调整心跳间隔 |
5.2 上下文污染的避免与清理
上下文污染是另一个高频问题。表现是 Agent 在后续任务中引用了前面任务的无关信息,导致决策偏差。
避免上下文污染的核心原则是:任务隔离。每个独立任务用独立的会话或独立的补全上下文,不共享历史。
对于 Claude Code 的会话式接口,Jev 在任务完成后主动关闭会话,下一个任务创建新会话。对于需要连续对话的场景,Jev 会在会话中插入明确的任务边界标记,提醒 Agent 区分不同任务。
清理策略上,我建议定期清理会话缓存和上下文缓存。缓存过期时间设置为任务完成后十分钟,避免缓存无限增长。
5.3 多 Agent 协作时的任务边界划分
多 Agent 协作最容易出问题的地方是任务边界模糊。两个 Agent 同时修改同一个文件,或者一个 Agent 的修改依赖另一个 Agent 还没完成的修改。
Jev 的处理方式是串行化有依赖的任务,并行化无依赖的任务。具体做法:
- 任务提交时,Jev 分析任务之间的文件依赖关系
- 有文件重叠的任务进入同一个串行队列
- 无文件重叠的任务进入并行队列
- 每个任务完成后,Jev 更新文件状态,通知依赖它的任务
这个机制实现起来不复杂,但效果很明显。我实测下来,任务冲突率从最初的百分之十五降到了百分之二以下。
5.4 性能调优的几个关键参数
Jev 的性能调优主要围绕三个参数:
规则匹配的超时时间。默认设置是五十毫秒。规则数量多的时候,匹配时间会上升。如果超时,Jev 会跳过规则引擎直接走模型分类。这个参数需要根据规则数量调整,规则超过两百条时建议放宽到一百毫秒。
模型分类的批处理大小。当多个任务同时到达时,Jev 会把它们攒成一批做分类。批处理大小默认是八,调大能提升吞吐但增加延迟。根据实际任务到达速率调整,一般保持在四到十六之间。
上下文加载的 token 阈值。这个阈值决定什么时候停止加载上下文。默认是模型上下文窗口的百分之七十。调低能留更多空间给推理,但可能导致上下文不足。我一般设置在百分之六十到七十之间。
提示:这三个参数没有万能值,需要根据实际代码库规模、任务类型分布、Agent 响应速度来调。建议先用默认值跑一周,收集数据后再调。
6. 实际效果与经验总结
6.1 在一个中型项目上的实测数据
我在一个约八万行的后端项目上跑了三周的 Jev,对比之前直接调 Agent 的情况,几个关键指标的变化:
| 指标 | 直接调 Agent | 接入 Jev 后 | 变化 |
|---|---|---|---|
| 平均任务完成时间 | 4分20秒 | 2分50秒 | 下降35% |
| 任务一次通过率 | 68% | 84% | 提升16个百分点 |
| 高风险任务确认覆盖率 | 无 | 100% | 从无到有 |
| 上下文 token 消耗 | 基准 | 下降约40% | 显著下降 |
| 任务冲突率 | 15% | 2% | 大幅下降 |
这些数据是在特定项目上跑出来的,不同项目会有差异。但趋势是一致的:决策层带来的收益主要体现在减少无效探索、降低上下文消耗、提升任务可控性上。
6.2 我踩过的三个大坑
第一个坑是过度设计。我一开始想把 Jev 做成一个通用的任务编排系统,支持各种复杂的任务依赖和条件分支。结果就是配置复杂到我自己都不想用。后来砍掉了大量功能,只保留最核心的决策路由,反而好用多了。
第二个坑是忽视兜底。有段时间我太相信规则引擎,把兜底策略去掉了。结果遇到规则覆盖不到的任务时,Jev 直接报错,整个流程卡住。兜底策略是必须的,而且兜底策略要足够保守。
第三个坑是策略提示词写得太长。我一开始觉得提示词越详细越好,把策略的每个细节都写进去。结果 Agent 被过长的提示词干扰,反而抓不住重点。后来把提示词精简到三句话以内,效果明显提升。
6.3 后续可以扩展的方向
Jev 目前是一个相对轻量的决策层,后续有几个方向可以扩展。
策略学习。目前策略是人工配置的,后续可以基于历史任务的执行结果自动调整策略。比如某个策略在特定任务类型上表现不好,系统自动降低它的优先级。
多模型路由。目前只接入了两个 Agent 后端,后续可以接入更多。不同后端擅长不同任务,路由层可以根据任务特征选择最合适的后端。
决策可解释性。目前决策过程对用户是黑盒的,后续可以输出决策依据,让用户理解为什么某个任务走了某个策略。这对调试和信任建立都有帮助。
与 CI 流程集成。把 Jev 接入持续集成流程,让代码提交自动触发决策和 Agent 执行,实现更自动化的开发流程。
我个人在实际操作中的体会是,决策层的价值不在于它有多智能,而在于它把不确定性收敛到了可控范围内。Agent 的能力很强,但强能力需要好的调度才能发挥出来。Jev 做的就是调度这件事,让每个任务在合适的策略下、由合适的 Agent、在合适的上下文里执行。这个思路不仅适用于 Coding Agent,任何需要多步骤决策的自动化场景都可以参考。