做 Agent 的人都绕不开一个灵魂拷问:循环里的每一步判断,到底该谁说了算?我见过太多项目,一上来就把所有判断都丢给 LLM——状态要不要切换,参数合不合法,结果要不要重试,甚至循环要不要停,全都让大模型拍板。结果呢?贵、慢、还经常给出前后矛盾的回答。Jev 决策模型的核心主张就一句话:Agent 循环里大约 80% 的判断,根本不应该交给 LLM。这篇文章会把 Jev 模型的原理拆开讲透,解释为什么控制流里的高频判断必须用确定性的规则和代码完成,以及那剩下的 20% 创造性判断在什么时候、用什么方式交给 LLM 才最划算。无论你是在搭 Agent 框架、写知识库工具,还是被循环失控、token 超支、行为不可复现这些问题折磨,这篇都值得看完。
1. Jev 决策模型是什么:一个循环被拆成三段之后
1.1 Jev 的三个字母到底指什么
Jev 不是某个公司的闭源黑盒,也不是什么新鲜的神秘算法,它是一套关于 Agent 循环控制权的设计约定。整个模型的核心可以拆成三个动作:Judge(判断)、Execute(执行)、Verify(验证)。任何一轮 Agent 循环,本质上都是在反复走这三个动作。
- Judge:根据当前状态决定下一步做什么。是继续调用工具,还是收集到的信息已经足够生成最终答案。
- Execute:执行被选中的动作。可能是调用函数、读数据库、查知识库、写文件,也可能是让 LLM 生成一段文本。
- Verify:确认执行结果是否合法、是否符合预期、是否满足终止条件。不合法就回退重试,合法才进入下一轮。
这三段拆开之后,一个重要的现象浮出水面:真正需要“智能”的只有 Judge 里的一小部分,Execute 是机械动作,Verify 更是纯粹的规则检查。大部分团队把三件事全塞给 LLM,相当于让一个擅长写作文的同学去同时干会计的活——能干,但贵得要命,还老算错。
1.2 为什么 Agent 必须依赖循环,而不是一次调用搞定
很多人第一次接触 Agent 时都会问:我直接写一个超长 prompt,让 LLM 一次性把任务做完不就行了?为什么非得搞循环?答案是:一次调用解决不了多步骤任务。
举个例子,让 Agent 从公开网页抓取一批产品价格,然后按要求生成对比表。一次调用的话,LLM 要么瞎编数据,要么中途忘了格式要求。多步骤任务天然需要观察→决策→行动→再观察的闭环。循环的价值在于:每一步都可以把最新的中间结果纳入考量,错了可以及时纠正,而不是祈祷一次生成就完美。
但循环也带来了新的问题:循环里的判断次数会爆炸。一个 20 轮的 Agent 任务,每轮至少 2~3 次判断(要不要继续、结果行不行),单任务就是 60 次判断。如果全走 LLM,成本和延迟都不可控。Jev 模型就是用来回答“这些判断里哪些该走 LLM”这个问题的。
1.3 循环里的三类判断:结构性、经验性与创造性
我在实践中习惯把 Agent 循环里的判断分成三类,Jev 模型的分配原则也是从这里出发的:
| 判断类型 | 典型问题 | 特征 |
|---|---|---|
| 结构性判断 | 参数是否为空、返回码是否为 0、JSON 字段是否存在、循环次数是否超限 | 有明确对错,可被规则描述 |
| 经验性判断 | 重试几次?超时阈值设多少?置信度低于多少回退? | 有统计规律,可用阈值和策略表描述 |
| 创造性判断 | 这段用户意图到底是什么?两个方案哪个更好?当前信息是否足以回答? | 无标准答案,需要语义理解 |
Jev 模型的分配原则非常朴素:结构性判断 100% 用代码,经验性判断 90% 用配置和规则,只有创造性判断才轮到 LLM。粗略算下来,循环里的判断超过 80% 都属于前两类,这就是标题里“80% 的判断不该交给 LLM”的由来。
2. 为什么 80% 的判断不该交给 LLM:四个算得清的账
2.1 成本账:一次 LLM 判断的价格是规则判断的几万倍
先算一笔最简单的账。假设一个 Agent 循环里,每轮需要判断“当前输出是否合法”。用规则判断(比如检查 JSON 能不能 parse、字段是否存在),成本是 CPU 微秒级,几乎等于零。用 LLM 判断,哪怕用最便宜的模型,一次也要消耗几百 token,按市场价大约是 0.001~0.01 美元,延迟还得加几百毫秒。
按单任务 20 轮、每轮 3 次判断计算:全走 LLM 的话,单任务判断成本 0.06~0.6 美元;如果其中 80% 换成规则,成本直接降到原来的五分之一以下。跑 1000 个任务,省下的钱足够买一台不错的开发机。这还没算 LLM 判断偶尔出错导致的重跑成本——规则判断错了马上能定位,LLM 判断错了可能要整个循环回滚,那个代价是几何级数放大的。
2.2 可靠性账:概率输出支撑不起确定性控制流
这是我最看重的一点。Agent 循环本质上是确定性控制流——步骤 1 做完必须走步骤 2,状态 A 不满足条件就不能切到状态 B。但 LLM 的输出是概率性的:同一个 prompt,温度调到 0 也不是 100% 稳定,换版本、换随机种子都可能输出不同。
如果在循环里用 LLM 判断“这个 JSON 是否合法”“这个参数是否越界”,你会遇到没法调试的噩梦:同一个输入,上一轮判断通过,下一轮判断失败,但代码和数据都没变。你没法断言,没法复现,没法写单元测试。而这些问题在 Jev 模型里根本不会出现——因为所有结构性判断都被下沉到了规则层,规则是确定性的,输入相同必然输出相同,出问题就是一个 stack trace。
2.3 延迟账:循环的吞吐量被最慢的环节卡死
循环有个特点:每一轮都是串行的。上一轮的判断结果直接决定下一轮的动作,没办法并行。这意味着整个循环的实际耗时等于所有环节耗时之和,任何一个环节慢,整个任务就被拖慢。
规则判断 50 毫秒以内能完成,LLM 判断再怎么也要 300~500 毫秒起。一个 20 轮的循环,如果每轮有 3 次判断全走 LLM,光判断就占去 18~30 秒。把其中 80% 换成规则后,判断总耗时缩到大约 3 秒。在需要实时响应的场景里(比如让 Agent 操作当前的沙盒环境),这个差距就是“能用”和“不能用”的区别。
还记得热搜词里那个“javascript学习手册七:js循环语句”吗?道理是相通的——循环里最耗时的语句决定了整体性能。只是在前端,你优化的是一个循环体内的计算;在 Agent 里,你优化的是每轮循环里最贵的那个 LLM 调用。
2.4 可观测性账:黑箱判断没法给循环做审计
Agent 在生产环境跑起来之后,你一定会遇到这种场景:某个任务做了一半卡住了,或者结果明显不对,但排查起来极其痛苦。如果循环里的判断都是 LLM 做的,你面对的就是一堆 prompt 日志和模型输出,很难回答“当时为什么决定走这条路”。
规则判断就完全不同。每一次判断都可以打日志、埋指标、出断言。循环走到哪一步、哪个条件没满足、为什么走了重试分支,一目了然。Jev 模型在架构上保证了决策链路的可审计性:你随时能说出眼下循环的状态是哪条规则推进的,而不是“大模型觉得应该这样”。
这也解释了为什么很多 Agent 框架(包括热搜里的 pi agent、hermes agent)在成熟之后,都会把越来越多的判断逻辑从“让模型想”改成“代码说了算”——不是为了省那点钱,而是为了让系统变成人能维护的系统。
2.5 那 80% 到底具体指什么:一张判断分类对照表
说了这么多,不如给一张具体的对照表,假设你正在写一个“文档整理 Agent”,它要从一批文件里提取信息、去重、汇总、输出报告。循环里会遇到的判断基本就是这些:
| 循环环节 | 判断内容 | 推荐层级 | 实现方式 |
|---|---|---|---|
| 读文件阶段 | 文件是否存在、是否为支持格式、大小是否超限 | 结构性 | 文件系统 API + 格式校验 |
| 提取阶段 | 提取结果是否为空、字段是否完整、JSON 是否合法 | 结构性 | 解析器 + schema 校验 |
| 去重阶段 | 相似度是否超过阈值、是否该合并 | 经验性 | 相似度算法 + 阈值配置 |
| 汇总阶段 | 已有信息是否足够回答用户问题 | 创造性 | LLM(20% 的归属) |
| 输出阶段 | 报告格式是否符合要求、字数范围是否达标 | 结构性 | 正则 + 长度判断 |
| 全局控制 | 循环是否超过最大轮数、token 是否超预算 | 结构性 | 计数器 + 预算检查 |
数一下就会发现,真正需要 LLM 的只有“信息是否足够”这一类开放性语义判断,其余全是规则能搞定的。这 20% 才是 LLM 的用武之地:用它的语义理解能力去做那些没有标准答案的裁决。
3. Jev 决策模型的实操落地:从伪代码到可跑的结构
3.1 最小可用的 Jev 循环骨架
理论说完了,直接上代码。下面这个骨架是我在用 TypeScript 写小 Agent 时沉淀下来的,你可以直接改造成任何语言。它最核心的地方在于:Judge 被拆成了 rule_judge 和 llm_judge 两层,先跑规则,规则判不了才走 LLM。
type AgentState = { step: number; data: any; errors: string[]; done: boolean; }; const MAX_STEPS = 20; async function runAgent(initialData: any) { let state: AgentState = { step: 0, data: initialData, errors: [], done: false, }; while (!state.done && state.step < MAX_STEPS) { state.step++; // 1. Judge —— 先规则后模型 const ruleDecision = ruleJudge(state); if (ruleDecision.action === "stop") { state.done = true; break; } let action: string = ruleDecision.action; if (ruleDecision.needsLLM) { action = await llmJudge(state); // 只有规则层判断不了时才进来 } // 2. Execute const execResult = await executeAction(action, state.data); // 3. Verify const verifyResult = verifyStep(execResult); if (!verifyResult.ok) { state.errors.push(verifyResult.message); if (state.errors.length >= 3) { console.error("连续失败,循环终止"); break; } continue; // 回到 Judge,尝试重试或换一条路 } state.data = execResult.output; } if (state.step >= MAX_STEPS) { console.warn("达到最大步数,强制结束"); } return state; }这里有个很容易被忽略的点:verifyStep是一票否决的。执行结果不合法,后续任何判断都失去意义,所以必须先验证再进下一轮。很多 Agent 项目把验证也丢给 LLM,等发现结果不对时已经污染了后续所有轮次的状态,排查起来非常痛苦。
3.2 决策路由表:20% 与 80% 的分界线怎么画
Jev 模型的落地核心是一张决策路由表。不要指望在代码里到处写 if-else,那会很快变成一团乱麻。正确的做法是把所有判断项集中定义成一张表,每项包含判断名称、判断层级(rule/llm)、判断逻辑(函数引用或 prompt 模板)、失败时的兜底策略。
const decisionRouter = [ { id: "check_input_valid", level: "rule", logic: (s: AgentState) => s.data != null && typeof s.data === "object", fallback: "stop_with_error", }, { id: "check_json_schema", level: "rule", logic: (s: AgentState) => validateSchema(s.data), fallback: "retry_parse", }, { id: "check_info_sufficient", level: "llm", // 这一条才走模型 logic: "判断当前收集的信息是否足以回答用户问题,不足则列出缺失项", fallback: "continue_collect", }, { id: "check_format_ok", level: "rule", logic: (s: AgentState) => /^[A-Z][a-z]+:/.test(s.data.output), fallback: "reformat_output", }, ];这张表的价值不只是清晰,它还能让你方便地做动态调整。前期对一个判断拿不准时,可以先走 LLM;等积累了几百条真实样本后,总结出规则模式,再把它降级成 rule。我自己的经验是:一个判断从 LLM 降级到规则后,成本基本归零,而且系统稳定性显著提升,所以我会刻意推动这个降级过程。
3.3 三层校验:参数级、状态级、结果级分别查什么
Verify 这一步很容易被草草带过,但它恰恰是 Jev 模型里最体现工程水准的地方。我把校验拆成三层,每一层管的事情不一样:
- 参数级校验(执行前):动作的参数是否合法。比如要调用一个读取文件的函数,就要先检查文件路径非空、文件存在、大小不超过阈值。这一层可以在 Execute 之前拦截大量低级错误。
- 状态级校验(执行中):当前状态是否允许执行这个动作。比如“文件还没读完,就不能进入去重阶段”。这本质上是 Agent 内部的有限状态机约束。
- 结果级校验(执行后):执行结果是否符合预期。包括返回码、字段完整性、数据格式、业务规则约束。
三层校验全部写成纯函数,不涉及任何 LLM 调用。这样带来的直接好处是:单元测试覆盖率可以做得非常高。我在项目里就把这三层校验函数全部单独测,跑一次测试只要几十毫秒。对比一下,如果校验靠 LLM,你根本没法写有效的测试——因为同一个输入可能有时通过有时不通过。
3.4 循环终止与逃生机制:死循环、token 超支和沙盒卡死
Jev 模型还有一个容易被忽略但极其重要的部分:循环的逃生机制。循环在 Agent 里失控的概率远比你想象的高,最常见的三种情况是:
- 死循环:某一步反复失败但始终不满足终止条件,while 循环空转到超时。
- token 超支:LLM 调用过多,单个任务的 token 消耗超出预算。
- 沙盒卡死:Agent 操控的沙盒环境异常,执行结果迟迟不返回。
针对这三种情况,我建议在循环骨架里设置三道防线:
| 防线 | 配置项 | 触发行为 |
|---|---|---|
| 最大循环步数 | max_steps: 20 | 打印警告并按当前结果收尾 |
| token 预算 | token_budget: 50000 | 停止新增 LLM 调用,改用规则兜底 |
| 看门狗超时 | watchdog_timeout: 120s | 强制中断当前执行并标记失败 |
这里我想特别提一下“token 预算”的触发行为。很多人以为 token 超了就直接失败重来,但 Jev 模型的做法更聪明:token 预算耗尽后,自动切换到降级模式——所有后续判断一律走规则,LLM 只在绝对必要的时候调用一次,产生一个粗糙但完整的输出。这就像一个集团里的预算审批制度:钱快花完了,所有采购都要走严格审批,而不能说“预算不够就停业”。
不要小看这个设计。在生产环境里,Agent 任务的数据量是波动的,一个平时 20 轮能跑完的任务,碰到一份异常文档可能膨胀到 40 轮。没有逃生机制,任务就挂了;有了它,至少还能输出一个“部分完成+失败原因”的结果,让上层决定是否重试。
4. 常见问题与排查技巧实录
4.1 LLM 判断抖动导致循环震荡怎么办
这是把 20% 判断交给 LLM 后最先遇到的头疼问题。现象是:循环在同一个决策点反复摇摆,这轮判断“信息不足,继续收集”,下一轮同样的数据判断“信息够了,可以结束”,再下一轮又变回“不足”。任务就在这个决策点附近来回震荡,直到撞上最大步数。
这个问题的根源在于 LLM 是概率输出,而且 prompt 里的语义边界本身就有模糊地带。我的排查思路是这样:
- 先把
llm_judge的输入输出全部加日志,确认它传来的上下文是否一致。 - 在决策点前面加一个状态去重:如果该决策点已经遇到过完全相同的输入状态,直接复用上一次的结果,不再调用 LLM。
- 给 LLM 判断加一个短期记忆:记录最近两次的判断结果,如果出现 A→B→A 的震荡,默认采纳“更保守”的那个(比如“继续收集”),并标记这是一个需要人工介入的边界情况。
最后一步是最有用的。因为震荡本身就是模型对边界感到困惑的信号,与其赌它下一次的输出,不如用规则强制稳定下来。
4.2 规则越写越复杂,代码膨胀成意大利面怎么办
Jev 模型的一个常见副作用是:规则判断的逻辑越来越多,ruleJudge函数从几十行膨胀到几千行,最后没人敢动。这个问题的本质是把路由逻辑和业务逻辑混在了一起。
我的建议是分三步治理:
- 路由与执行分离:
ruleJudge只负责查决策路由表,找对规则,不负责实现规则细节;每条规则单独一个文件,单独测试。 - 规则按业务模块分组:比如文件校验、数据清洗、格式输出各一组,模块之间不互相调用,只通过状态对象交换数据。
- 定期做规则降级审查:每两周看一次日志,找出高频走 LLM 的决策点,尝试把它的特征归纳成规则。每降级一条,代码会变多一点,但系统会变稳一大截。
我用这个流程治理过一个写了 3000 行判断逻辑的老项目,拆分之后每块都不到 300 行,测试反而更完善了。规则代码膨胀不是 Jev 模型的缺点,缺少结构才是。
4.3 循环异常终止或半途退出,怎么定位是哪个环节的问题
有一次我在本地跑一个 Agent,任务执行到一半突然停了,没有任何报错,日志最后一行停在某个工具调用之后。排查了很久才发现,是结果级校验里有个 JSON 字段的 schema 定义错了,校验函数静默返回 false,触发连续失败计数达到 3 次直接终止。
这个案例暴露了一个 Jev 实现里的常见缺陷:失败计数用了一个全局计数器,没有区分失败类型。文件读取失败和校验失败是不同性质的失败,前者可能是临时网络问题,重试有价值;后者是确定性问题,重试一万次也没用。
改进办法是给每种失败类型单独计数,并配置不同的重试策略。我把这个技巧整理成一张简单的排查表:
| 失败类型 | 典型表现 | 重试策略 |
|---|---|---|
| 临时性错误(网络超时) | 偶发,重试后成功 | 指数退避重试,上限 3 次 |
| 确定性错误(校验失败) | 每次必现,不随重试改变 | 不重试,直接回退状态 |
| 资源性错误(token 超支) | 任务越长越容易触发 | 触发降级模式,不做完整重试 |
| 逻辑性错误(状态机非法) | 某状态下调用了不该调用的动作 | 立即终止,标记需要人工审查 |
4.4 token 监控怎么做:从“事后看账单”变成“事前熔断”
都说 Agent 烧 token,但真正把 token 监控做成“实时熔断”的项目很少。大多数人的做法是跑完任务后看一眼账单,发现贵了再去优化 prompt——这已经晚了。
我在项目里维护一个全局的 token 计数器,在每次 LLM 调用前先检查预算。预算按比例分区:前 60% 正常用,60%~80% 开始跳过非必要的 LLM 判断(比如那些“信息是否充分”之外的可有可无的判断),超过 80% 直接切降级模式,只保留最核心的一次调用。
这行逻辑不复杂,但效果显著——至少没有哪个任务会因为 token 超支而彻底失败。有一次一个异常数据批量任务把 token 消耗推到了预算的 90%,系统自动把后续判断全切成了规则,最后任务在降级模式下多跑了几十秒完成了,而不是报错重来。事后我检查了两小时,真正因为没有 LLM 判断而牺牲掉的质量,只在最边缘的两个条目上,完全在可接受范围内。
提示:token 预算的判断本身也是“80% 判断不该交给 LLM”的典型例子——这种计数、比较、熔断的逻辑,用代码就是一行,用 LLM 反而不可靠还贵。
5. 一些更深的体会:Jev 模型的适用范围与边界
这套模型并不神秘,它的本质就是重新划分了 Agent 内部的“权力边界”。权力清晰之后,系统自然变得可控。但我也要泼一盆冷水:Jev 模型不是万能的,以下场景它的收益会打折扣:
- 纯探索型任务:比如让 Agent 去“头脑风暴”十个营销文案,循环本身的意义不大,谈不上 80/20 分配。
- 单次交互场景:不需要循环,一次 LLM 调用完事,Jev 没有用武之地。
- 规则无法描述的高动态环境:如果任务里的每一步都需要对开放世界做语义理解,规则层能覆盖的部分会非常有限。
反过来说,凡是流程固定、步骤可枚举、有明确成败标准的任务,比如批量文档处理、数据清洗、网页操作、代码生成后自动验证,Jev 模型都能带来立竿见影的效果。这类任务也是目前生产环境里对 Agent 需求最大的领域。
我自己在把一个“信息收集 Agent”改造成 Jev 结构之后,最直观的感受是:以前出了问题,我拿着一堆对话日志无从下手;现在出了问题,我知道去看哪个决策路由项、哪层校验函数、哪条失败计数。这种“系统重新变得可运维”的感觉,比单纯省下的钱和 token 更让人踏实。如果你手头正有一个循环跑得不太顺的 Agent,不妨先把里头的判断列一张表,标出哪些是非走 LLM 不可的,然后你就会发现——原来 80% 的判断,规则早就能搞定。