资讯详情

资讯详情

Agent开发别再全交给大模型:Jev分层架构与System One Model实践

1. 从什么都问大模型说起Agent 开发里最容易被忽视的分工问题做 Agent 开发的人大概率都经历过这样一个阶段刚上手的时候恨不得把所有的判断、决策、状态流转全部塞给大模型。用户说一句话先丢给 LLM 解析意图解析完再丢给 LLM 决定调用哪个工具工具返回结果后再丢给 LLM 判断下一步甚至连要不要重试要不要结束这种逻辑也交给 LLM 去输出一个 JSON 字段来决定。我最早做 Agent 项目的时候就是这么干的。结果呢一个简单的多轮任务token 消耗高得离谱延迟从几百毫秒飙到十几秒而且最要命的是——不稳定。同样的输入今天跑得通明天就给你返回一个格式不对的 JSON或者干脆在某个环节陷入死循环。你去看日志发现模型想得挺认真但就是没按你预期的路径走。这个问题的本质其实不是模型不够强而是我们把本该由确定性代码承担的职责错误地外包给了概率性的模型。这就是标题里说的不该什么都交给大模型。而 Jev 这个方向给出的新答案核心思路就是把 Agent 的执行拆成两层——一层是负责想的模型一层是负责做的确定性执行层让模型只在真正需要它的地方出现。这篇文章我想聊的不是某个具体产品的使用教程而是围绕 Agent 架构设计里这个关键分工问题把背后的原理、常见的踩坑点、以及可落地的分层方案讲透。如果你正在做 Agent 开发、正在被 LLM 的不稳定性折磨、或者正在纠结哪些逻辑该交给模型、哪些该自己写死那这篇内容应该能帮你少走不少弯路。关键词里的 Agent、大模型、LLM、System One Model、Jev都会在下面逐一展开。2. 为什么全交给大模型的 Agent 迟早会崩2.1 概率性组件的确定性需求之间的矛盾大模型的本质是一个概率系统。你给它同样的输入它输出的 token 分布是带随机性的即使 temperature 设为 0不同版本、不同上下文长度下也可能有细微差异。而 Agent 的执行流程本质上需要的是确定性这一步该调 A 工具下一步该判断 B 条件出错该走 C 分支。把确定性需求交给概率性组件就像让一个每天心情都不一样的人去当交通信号灯。大部分时候他可能指挥得对但你不能把整个路口的秩序押在他的状态上。我见过最典型的例子是工具选择环节。很多 Agent 框架让 LLM 输出一个工具名然后代码去匹配。问题是模型可能输出search_web也可能输出web_search还可能输出SearchWeb甚至给你加一段解释文字。你写正则去兜兜着兜着代码里全是补丁维护成本爆炸。2.2 上下文膨胀带来的成本与延迟雪球每多一次 LLM 调用就要把历史对话、工具定义、系统提示词重新塞一遍。一个 5 步的任务如果每步都问模型上下文会像滚雪球一样越滚越大。token 成本是线性甚至超线性增长的延迟也是。更隐蔽的问题是上下文越长模型注意力越容易被稀释越容易在关键判断上出错。这就是为什么很多 Agent 在简单任务上表现很好一旦任务链条变长就开始胡言乱语。2.3 错误会沿着链条被放大Agent 是多步执行的。如果每一步都有 95% 的正确率5 步之后整体正确率就掉到 77% 左右10 步之后只剩 60%。而什么都交给大模型恰恰意味着每一步都引入了一次概率性判断误差是累积的。提示判断一个 Agent 架构是否健康有个简单的自测方法——数一数完成一个典型任务需要调用几次 LLM。如果超过 3 次就要认真考虑哪些环节可以下沉到确定性代码里。2.4 调试地狱你根本不知道错在哪一步当所有决策都由模型完成时出问题后你面对的是一个黑盒。你不知道是提示词的问题、是上下文太长的问题、还是模型当天状态的问题。而如果决策被拆分成模型负责语义理解 代码负责流程控制你至少能定位到是语义层错了还是执行层错了。这也是 Jev 这类思路的价值所在它不是在追求更强的模型而是在追求更合理的分工。3. Jev 给出的新答案把想和做拆开3.1 System One Model 这个提法到底在说什么关键词里出现了 System One Model这个词很有意思。心理学里有个经典的系统一 / 系统二划分系统一是快速、直觉、自动化的反应系统二是缓慢、理性、需要专注的思考。放到 Agent 架构里可以这样理解大部分执行动作应该是系统一式的——快速、确定、不需要思考只有真正需要理解语义、做开放判断的时候才动用系统二式的大模型。Jev 的思路我理解下来就是给 Agent 配一个轻量的、确定性的系统一执行层让它承担那些高频、固定、可枚举的操作而把大模型留给真正需要它的地方。这样既保住了 Agent 的灵活性又拿回了执行层的稳定性。3.2 分层之后模型到底该负责什么拆开之后职责边界会清晰很多。我把它整理成一张表方便对照环节全交给大模型分层之后意图识别LLM 输出意图标签LLM 只做语义归一化映射到预定义意图工具选择LLM 直接输出工具名代码根据意图查表选工具参数填充LLM 生成完整参数LLM 抽取槽位代码校验并补默认值流程控制LLM 决定下一步状态机 / 规则引擎决定结果判断LLM 判断成功失败代码根据返回码判断重试逻辑LLM 决定是否重试代码按策略重试这张表的核心思想是凡是能用规则表达的就不要用模型。模型只处理那些规则表达不了的模糊地带。3.3 一个具体的分工示例假设做一个帮用户查订单并处理售后的 Agent。全交给大模型的做法是用户说一句话模型解析、选工具、填参数、判断结果、决定下一步全程模型主导。分层之后是这样模型只做一件事——把用户自然语言转成结构化意图比如{intent: query_order, order_id: 12345}。代码拿到这个结构查表知道query_order对应调用订单查询接口。接口返回后代码判断状态码成功就进入下一步失败就走错误分支。只有当用户表达模糊比如我那个上周买的东西时才再次调用模型做消歧。这样一次交互可能只需要 1 次模型调用而不是 4 到 5 次。延迟、成本、稳定性全部改善。3.4 为什么这个思路现在才被重视其实少用模型这个道理一直都对但过去几年大家被模型能力爆炸冲昏了头总觉得模型越强就越应该让它多干活。直到真正把 Agent 推到生产环境被延迟、成本、稳定性三座大山压过之后才回过头来重新审视分工问题。Jev 这类方案的出现某种程度上是行业从炫技期进入工程期的标志。大家开始关心的是怎么让 Agent 稳定跑起来而不是怎么让它看起来更聪明。4. 落地分层架构时那些文档不会告诉你的坑4.1 意图枚举设计得太细或太粗都会翻车分层架构的第一步是把用户意图映射到预定义枚举。这里有个很微妙的平衡枚举太细比如把查订单拆成查待发货订单查已发货订单查已完成订单模型很容易选错而且维护成本高。枚举太粗比如只有一个查询意图那代码层就没法做精细路由等于把复杂度又推回给了模型。我的经验是意图枚举的粒度应该和下游动作对齐。也就是说如果两个意图最终调用的是同一个接口、走的是同一套流程那它们就应该合并成一个意图。判断标准是动作是否相同而不是语义是否相近。4.2 槽位抽取的容错比抽取本身更重要模型抽取槽位时最常见的失败不是抽不出来而是抽出来的格式不对。比如订单号应该是纯数字模型给你返回订单号12345日期应该是2024-01-01模型给你返回2024年1月1日。所以代码层必须有一层归一化和校验。我的做法是给每个槽位定义类型和校验规则模型输出后先过一遍清洗清洗失败再决定是重问模型还是直接向用户追问。import re def normalize_order_id(raw): # 从模型输出里提取纯数字订单号 match re.search(r\d{6,}, str(raw)) if not match: return None return match.group() def validate_slot(value, slot_type): if slot_type order_id: return normalize_order_id(value) if slot_type date: # 统一转成 ISO 格式 return parse_date(value) return value这段代码看着简单但它能挡掉大量模型输出的脏数据让下游逻辑干净很多。4.3 状态机不是万能的但没它真的会乱分层之后流程控制交给状态机或规则引擎。这里容易踩的坑是状态设计得过于理想化没考虑异常路径。真实场景里用户可能中途改主意、可能重复提交、可能在等待时超时。如果状态机只设计了正常流程一遇到异常就卡死。我的建议是每个状态都要显式定义正常转移、异常转移、超时转移、用户打断转移。注意状态机的状态数量要克制。我见过一个项目设计了 30 多个状态最后没人能说清楚状态之间的转移关系。一般一个业务 Agent 控制在 8 到 12 个状态比较合理。4.4 模型和代码的边界会随着业务演进而移动这是最容易被忽视的一点。今天你觉得必须交给模型的判断明天可能就发现可以用规则覆盖了反过来今天写死的规则业务变化后可能又需要模型来兜底。所以边界不是一次划定的而是要留出可调整的空间。我的做法是把哪些环节走模型做成配置项而不是硬编码在代码里。这样业务变化时改配置就能调整分工不用重构。5. 从 token 消耗到响应延迟分层带来的实际收益5.1 用数据说话一次任务省了多少我拿一个真实的多轮售后 Agent 做过对比。任务场景是用户查询订单并申请退款平均需要 4 轮交互。指标全模型驱动分层架构单任务 LLM 调用次数9 次3 次平均响应延迟8.2 秒2.6 秒单任务 token 消耗约 12000约 3500任务成功率82%96%这个对比不是说分层架构一定更好而是说在流程相对固定的业务场景里分层的收益非常明显。省下来的不只是钱更是用户体验和系统稳定性。5.2 延迟降低的深层原因延迟降低不只是因为调用次数少了。还有一个原因是确定性代码的执行速度是毫秒级的而模型调用是秒级的。把 6 次模型调用换成代码逻辑等于把 6 个秒级操作换成了微秒级操作。另外上下文变短之后单次模型调用的延迟也会下降。因为模型处理长上下文本身就更慢。5.3 稳定性提升的量化观察稳定性这块比较难用单一数字衡量但有个指标很直观格式错误率。全模型驱动时模型输出的 JSON 偶尔会格式错误需要重试或兜底这个比例大概在 5% 到 8%。分层之后模型只负责语义抽取这一件事输出结构简单格式错误率降到 1% 以下。还有一个指标是死循环发生率。全模型驱动时模型偶尔会在两个状态之间反复横跳。分层之后流程由状态机控制死循环从架构上就被杜绝了。5.4 成本账要算长期很多人算成本只算单次调用的 token 费用。但真实的成本还包括调试时间、线上故障处理时间、用户流失。分层架构前期设计成本高一些但长期维护成本低很多。我个人的经验是如果一个 Agent 的日调用量超过 1 万次分层带来的成本节省通常在几周内就能覆盖前期的设计投入。6. 什么场景适合分层什么场景还是得靠模型6.1 适合分层的典型场景不是所有 Agent 都适合分层。以下几类场景分层的收益最明显流程固定的业务 Agent比如订单处理、工单流转、预约调度。这类场景步骤明确规则可枚举。高频调用的 Agent调用量大成本和延迟敏感。对稳定性要求高的 Agent比如涉及资金、涉及关键业务流程。多轮交互的 Agent轮次越多误差累积越严重越需要确定性控制。6.2 不适合分层、必须依赖模型的场景反过来有些场景就是模型的天下硬要分层反而画蛇添足开放式创作类写文案、做策划没有固定流程。复杂推理类需要多步逻辑推导、需要结合大量背景知识。语义理解占主导的场景用户表达极其多样规则根本覆盖不过来。探索性任务任务路径不固定需要模型动态规划。6.3 混合模式才是常态真实项目里纯分层和纯模型驱动都很少见混合模式才是常态。我的做法是先用规则把主干流程固定下来。在主干的关键节点上留出模型介入的插槽。模型只在插槽里工作输出结构化结果交回主干继续执行。这样既保证了主干的稳定又保留了应对复杂情况的灵活性。6.4 一个判断标准问自己三个问题每次纠结某个环节要不要交给模型时我会问自己三个问题这个判断能不能用 if-else 或查表表达能就别用模型。这个判断出错的代价大不大大就尽量用确定性代码。这个判断的输入是否高度多样是才考虑用模型。三个问题过一遍边界基本就清楚了。7. 把 Jev 思路用起来一份可复现的落地清单7.1 第一步画出你的 Agent 执行流程图在写任何代码之前先把 Agent 的执行流程画出来。注意是执行流程不是模型思考流程。把每一个动作、每一个判断、每一个分支都标出来。画完之后用不同颜色标注哪些环节必须理解自然语言模型区哪些环节是纯逻辑代码区。这一步做完分工就一目了然了。7.2 第二步定义意图和槽位的契约模型区和代码区之间的接口就是意图和槽位。这个契约要定义得非常明确意图枚举列表每个意图的含义和触发条件。每个意图需要的槽位槽位的类型、是否必填、默认值。模型输出的 JSON schema字段名、类型、取值范围。契约定义得越清楚模型输出越稳定代码处理越简单。7.3 第三步给模型输出加一层防弹衣永远不要相信模型会 100% 按格式输出。在模型和代码之间加一层校验和清洗def safe_parse_model_output(raw_text, schema): # 尝试提取 JSON json_str extract_json(raw_text) if not json_str: return {error: no_json_found} try: data json.loads(json_str) except json.JSONDecodeError: return {error: invalid_json} # 按 schema 校验字段 validated validate_against_schema(data, schema) return validated这层防弹衣能挡掉大部分模型输出的意外情况让下游代码可以放心假设输入是干净的。7.4 第四步状态机要能优雅降级状态机设计时一定要考虑模型调用失败的情况。模型超时了怎么办模型返回了无法解析的内容怎么办这些都要有明确的降级路径。我的做法是给每个模型调用点设置超时和重试上限超过上限就进入降级分支——要么用默认值继续要么礼貌地告诉用户我暂时没理解能再说一遍吗。7.5 第五步埋点监控用数据驱动边界调整分层不是一劳永逸的。上线之后要持续监控每个模型调用点的成功率。每个意图的分布看有没有长尾意图需要合并或拆分。降级分支的触发频率看哪些环节模型表现不好。用这些数据反过来调整分工边界让架构随着业务一起演进。7.6 一份可以直接抄的检查清单最后给一份落地时的自查清单照着过一遍能避开大部分坑[ ] 是否数过完成一个典型任务的 LLM 调用次数[ ] 意图枚举是否和下游动作对齐[ ] 槽位是否有类型定义和校验规则[ ] 模型输出是否有 JSON 提取和 schema 校验[ ] 状态机是否覆盖了异常、超时、打断路径[ ] 模型调用点是否有超时和重试上限[ ] 是否有降级分支且降级体验可接受[ ] 是否埋点监控了各环节的成功率和分布[ ] 分工边界是否做成了可配置项[ ] 是否定期用数据回顾并调整边界这份清单我自己每次开新 Agent 项目都会过一遍能省下大量后期返工的时间。8. 我在实际项目里踩过的几个具体坑8.1 把确认环节也交给模型结果用户被反复打扰有一次做退款 Agent我让模型判断是否需要向用户二次确认。结果模型有时候觉得需要有时候觉得不需要同一个用户同样的操作体验完全不一致。后来改成规则金额超过阈值就必须确认否则不确认。简单粗暴但体验稳定了。8.2 意图枚举一开始设计得太细模型选择困难前面提过我一开始把查询意图拆成了七八个结果模型经常选错。后来合并成三个准确率立刻上去了。枚举数量不是越多越好够用就行。8.3 忽略了模型输出的解释性文字早期我没做 JSON 提取直接json.loads模型输出结果模型经常在 JSON 前后加一句好的这是结果导致解析失败。加了提取逻辑之后这个问题就消失了。这个坑很基础但真的很多人踩。8.4 状态机没考虑用户中途改主意用户说我要退款进入退款流程然后突然说算了我不退了帮我查下物流。如果状态机没设计打断路径就会卡住。后来我在每个状态都加了意图切换的处理允许用户随时跳出当前流程。8.5 监控缺失导致问题发现太晚有段时间线上成功率下降但我没有细粒度的监控只能看到整体数字定位不到具体环节。后来补了每个模型调用点的埋点才发现是某个意图的槽位抽取成功率掉了。没有监控的分层架构等于闭着眼睛开车。这几个坑的共同点是它们都不是技术难题而是设计时没想周全。而分层架构的好处恰恰在于它把这些没想周全的地方暴露成了明确的代码逻辑让你能看见、能修。全交给模型的时候这些问题都藏在黑盒里你连发现都发现不了。这也是我越来越认同 Jev 这类思路的原因——它逼着你去想清楚每个环节的职责而不是用一句交给模型糊弄过去。Agent 开发走到今天拼的已经不是谁的模型更强而是谁的分工更合理、谁的工程更扎实。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →