☰
Agent开发别再全交给大模型:Jev分层架构与System One Model实践
2026/11/4 4:26:37 网站建设 项目流程

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。全交给大模型的做法是:用户说一句话,模型解析、选工具、填参数、判断结果、决定下一步,全程模型主导。

分层之后是这样:

  1. 模型只做一件事——把用户自然语言转成结构化意图,比如{"intent": "query_order", "order_id": "12345"}。
  2. 代码拿到这个结构,查表知道query_order对应调用订单查询接口。
  3. 接口返回后,代码判断状态码,成功就进入下一步,失败就走错误分支。
  4. 只有当用户表达模糊(比如"我那个上周买的东西")时,才再次调用模型做消歧。

这样一次交互可能只需要 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 混合模式才是常态

真实项目里,纯分层和纯模型驱动都很少见,混合模式才是常态。我的做法是:

  1. 先用规则把"主干流程"固定下来。
  2. 在主干的关键节点上,留出模型介入的"插槽"。
  3. 模型只在插槽里工作,输出结构化结果,交回主干继续执行。

这样既保证了主干的稳定,又保留了应对复杂情况的灵活性。

6.4 一个判断标准:问自己三个问题

每次纠结某个环节要不要交给模型时,我会问自己三个问题:

  1. 这个判断能不能用 if-else 或查表表达?能,就别用模型。
  2. 这个判断出错的代价大不大?大,就尽量用确定性代码。
  3. 这个判断的输入是否高度多样?是,才考虑用模型。

三个问题过一遍,边界基本就清楚了。

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 开发走到今天,拼的已经不是谁的模型更强,而是谁的分工更合理、谁的工程更扎实。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询