
1. 从一次 Agent 翻车说起为什么“全交给大模型”是条死路去年冬天我接手了一个内部工单系统的 Agent 改造项目需求听起来很朴素让 Agent 自动读取用户提交的问题描述判断类型然后调用对应的处理流程。团队里几个人的第一反应出奇一致——把问题描述、系统提示词、可用工具列表一股脑塞给大模型让它自己决定调哪个工具、传什么参数。第一版 Demo 跑起来确实惊艳十次里有七八次能给出像样的结果演示的时候大家都觉得这事成了。上线第三天就出事了。一个用户提交的是“打印机连不上昨天还好好的”Agent 把这句话理解成了网络故障调了网络诊断工具返回一堆无关信息然后大模型又基于这些无关信息编了一段看起来很有道理的排查建议发给用户。用户照着做了半小时问题没解决反而把打印机的网络配置改乱了。事后复盘问题不在于大模型不够聪明而在于我们把一个本该由确定性逻辑处理的分类和路由任务交给了一个概率模型去“猜”。这件事让我开始认真思考一个被很多人忽略的问题Agent 系统里到底哪些部分该交给大模型哪些部分不该Jev 在最近的一次分享里给了一个我觉得相当清醒的答案——System One Model 和 LLM 应该各司其职而不是让 LLM 包揽一切。这个观点乍听有点反直觉毕竟现在的主流叙事是大模型能力越来越强什么都能干。但真正在生产环境里跑过 Agent 的人会明白把什么都交给大模型本质上是在用不确定性去对抗不确定性结果就是系统行为不可预测、调试成本极高、线上问题难以复现。这篇文章我想从实际工程的角度把 Jev 这个思路拆开讲清楚。核心关键词包括Agent、大模型、Jev、System One Model、LLM适合正在做 Agent 开发、被线上问题折磨过、或者正在设计 Agent 架构的同行参考。我不会讲太多虚的重点放在“为什么这样设计”和“具体怎么落地”上中间会穿插我自己踩过的坑和实测有效的方案。2. Jev 的核心主张System One Model 不是配角是地基2.1 什么是 System One Model为什么它被长期忽视System One Model 这个概念借用了认知心理学里“系统一”的说法——快速、直觉、自动化的决策过程。在 Agent 架构里它指的是那些不依赖大模型推理、由确定性逻辑或轻量模型完成的决策层。比如意图分类、实体抽取、路由判断、参数校验、状态机流转这些任务的特点是输入输出边界清晰、对延迟敏感、要求结果可复现。过去两年大家做 Agent习惯性地把这些任务也塞给 LLM理由是“大模型理解能力强写个提示词就能干”。短期看确实省事长期看是在给自己挖坑。我见过一个客服 Agent光是意图分类就用了 2000 token 的提示词每次请求先花 1.5 秒做分类然后再花 3 秒做实际处理。用户等 5 秒才看到第一句话体验极差。后来我们把分类换成一个蒸馏过的小模型加规则引擎分类耗时降到 80 毫秒准确率反而从 89% 提升到 96%。原因很简单分类这个任务边界是明确的用确定性方法做比让大模型“自由发挥”更靠谱。Jev 的观点之所以有价值是因为他没有停留在“小模型也能干活”这种泛泛之谈而是明确指出System One Model 应该承担 Agent 的“骨架”角色——负责流程控制、状态管理、工具调度这些不能出错的部分而 LLM 负责“血肉”——自然语言理解、内容生成、复杂推理这些它真正擅长的事。这个分工一旦理清整个系统的可维护性会有质的提升。2.2 LLM 在 Agent 里的正确位置不是大脑是专家顾问很多人把 LLM 比作 Agent 的“大脑”我觉得这个比喻有误导性。大脑要负责所有决策但 LLM 不应该。更准确的比喻是LLM 是一个知识渊博但偶尔会胡说八道的专家顾问。你可以咨询它但不能让它直接操作你的生产系统。具体来说LLM 在 Agent 里适合做这几类事第一把用户的模糊表达转成结构化输入比如“我昨天买的那个东西还没到”转成{intent: 物流查询, order_time: 昨天, missing_field: 订单号}第二在多个候选方案里做语义层面的排序和选择第三生成面向用户的自然语言回复第四处理那些规则覆盖不到的边缘情况。而不适合 LLM 做的事包括精确的数值计算、严格的状态流转控制、需要 100% 确定性的工具调用参数生成、以及任何涉及权限和安全的判断。我自己的经验是当一个任务可以用“如果 A 则 B否则 C”清晰描述时就不该交给 LLM。LLM 的价值在于处理那些“说不清规则”的模糊地带。Jev 在分享里提到一个判断标准我觉得很实用如果你无法用一段确定性的代码描述这个任务的正确行为那才考虑用 LLM如果你能描述那就用代码。这个标准帮我砍掉了 Agent 里至少一半不必要的 LLM 调用。2.3 两者协作的边界怎么划一张决策表光讲原则不够实际落地时需要可操作的判断依据。我整理了一张自己在项目里用的决策表每次设计新功能时对照着过一遍能避免大部分架构层面的错误。任务类型推荐承担者判断依据典型例子意图分类System One Model类别有限且边界清晰工单类型判断、情感极性实体抽取System One Model 规则格式相对固定订单号、日期、金额提取流程路由System One Model状态机可穷举根据意图分发到不同处理链参数校验System One Model有明确校验规则必填字段检查、格式验证开放域问答LLM需要世界知识和推理产品咨询、故障排查建议内容生成LLM需要自然语言表达回复话术、摘要生成多方案排序LLM需要语义理解候选工具选择、结果重排边缘情况处理LLM规则无法覆盖用户表达严重偏离预期这张表不是绝对的但能帮你快速判断一个任务该往哪边放。我的经验是凡是能用规则或小模型做到 95% 以上准确率的就不要用 LLM。LLM 的调用成本和延迟都是数量级的差距省下来的资源可以用在真正需要它的地方。3. 拆开看System One Model 在 Agent 里到底管什么3.1 意图识别与路由别让大模型猜用户想干嘛意图识别是 Agent 的第一道关口也是最容易出问题的地方。我见过太多项目在这里偷懒直接把用户输入丢给 LLM让它输出一个意图标签。问题是LLM 的输出不稳定——同样的输入今天分类成 A明天可能分类成 B温度参数调低也没用因为提示词里稍微加个例子就可能改变整体分布。更麻烦的是当意图类别超过 10 个时LLM 的分类准确率会明显下降。我们做过一个测试15 个意图类别下GPT-4 级别的模型零样本分类准确率只有 82% 左右而一个用 500 条标注数据微调过的 BERT 小模型能达到 94%。推理成本上小模型是 LLM 的几十分之一延迟从 800 毫秒降到 30 毫秒。这个账怎么算都划算。具体落地时我的建议是分层处理先用规则匹配处理那些有明显关键词的输入比如包含“退款”“退货”的直接归到售后意图规则覆盖不到的走小模型分类小模型置信度低于阈值的才交给 LLM 做兜底判断。这样三层下来LLM 的实际调用量能压到总请求的 5% 以下而整体准确率反而比纯 LLM 方案高。注意小模型的训练数据要从真实日志里挖不要自己拍脑袋造。我见过团队用生成的假数据训练分类模型上线后准确率惨不忍睹因为真实用户的表达方式和生成数据差距太大。3.2 状态管理与流程控制Agent 不能“失忆”Agent 在多轮对话里最容易出的问题是状态丢失。用户第一轮说了订单号第三轮问“那个订单到哪了”如果 Agent 没有把订单号存下来LLM 再聪明也答不出来。很多团队的做法是把整个对话历史塞给 LLM让它自己从上下文里找。这个方案在对话轮次少的时候能用一旦超过 10 轮token 消耗爆炸不说LLM 还会“忘记”早期信息——这不是模型能力问题是注意力机制本身的局限。正确的做法是用 System One Model 维护一个显式的状态对象。每轮对话结束后由确定性逻辑更新状态字段比如{order_id: 12345, intent: 物流查询, last_query_time: ...}。下一轮开始时只把当前状态和最新用户输入传给 LLM而不是整个历史。这样 token 消耗可控状态也不会丢。我自己的项目里状态管理是用一个简单的 JSON 对象加版本号实现的。每次状态变更都记录版本方便回滚和调试。这个设计看起来朴素但线上出问题时能救命——你可以精确知道 Agent 在每一步“知道什么”而不是对着一堆对话历史猜它为什么做出了某个决定。3.3 工具调用的参数组装确定性优先工具调用是 Agent 和外部系统交互的接口参数错了轻则调用失败重则造成数据污染。我强烈建议工具调用的参数组装由 System One Model 完成LLM 只负责提供语义层面的信息。举个例子用户说“帮我查一下上周三下的那个订单”。LLM 的任务是把这句话解析成{action: query_order, time_ref: 上周三, order_ref: 那个订单}然后 System One Model 根据当前日期计算出具体日期根据会话状态找到对应的订单号组装成工具需要的{order_id: 12345, date: 2024-01-10}。这样分工的好处是LLM 不需要知道今天是几号也不需要知道订单号存在哪里它只做它擅长的语义解析而日期计算和状态查询这些确定性任务由代码保证 100% 正确。我踩过的一个坑是让 LLM 直接生成工具调用的完整参数结果它把日期算错了——它不知道“上周三”具体是哪天就编了一个。这种错误在测试环境很难发现因为测试时你往往用的是“今天”“明天”这种相对日期上线后用户说“上周三”问题就暴露了。3.4 结果校验与兜底最后一道防线LLM 生成的内容不能直接返回给用户必须经过校验。校验层也是 System One Model 的一部分。校验内容包括格式是否符合预期、是否包含敏感信息、数值是否在合理范围、是否和已知事实矛盾。我们做过一个统计LLM 生成的回复里大约有 3% 到 5% 存在事实性错误或格式问题。这个比例在 Demo 里可以忽略在生产环境里就是事故。校验层的作用就是把这些错误拦下来触发重试或降级到预设回复。校验规则不需要很复杂大部分问题用正则和简单的逻辑判断就能发现。比如回复里出现了订单号就检查这个订单号是否在数据库里存在回复里提到了金额就检查金额是否和订单实际金额一致。提示校验层不要做得太“聪明”不要试图用 LLM 去校验 LLM。用确定性规则做校验错了能定位改起来也快。4. 实操怎么把 Jev 的思路落地到一个真实 Agent 项目4.1 架构设计三层分离基于 Jev 的思路我把 Agent 架构分成三层。第一层是接入层负责接收用户输入、做基础清洗和格式化第二层是控制层也就是 System One Model 所在的地方负责意图识别、状态管理、路由决策、参数组装、结果校验第三层是智能层LLM 在这里工作负责语义解析、内容生成、复杂推理。三层之间的通信通过明确定义的接口进行。控制层调用智能层时传入的是结构化的请求对象而不是原始文本智能层返回的也是结构化的结果而不是自由文本。这个约束看起来限制了 LLM 的发挥实际上让整个系统可控了很多。LLM 不需要知道用户是谁、之前聊过什么、系统有哪些工具它只需要完成当前这一步的语义任务。这个架构的另一个好处是可测试性。控制层的逻辑可以用单元测试覆盖智能层的输出可以用固定输入做回归测试。两层分开测试问题定位快很多。以前纯 LLM 方案出问题时你只能对着日志猜是提示词的问题还是模型的问题现在你可以先看控制层的状态流转对不对再看智能层的输出合不合理排查路径清晰。4.2 关键代码结构控制层怎么调度 LLM控制层的核心是一个调度器它根据当前状态决定下一步做什么。下面是一个简化版的 Python 伪代码展示控制层如何协调 System One Model 和 LLM。class AgentController: def __init__(self, state_store, intent_classifier, llm_client, tools): self.state_store state_store self.intent_classifier intent_classifier self.llm_client llm_client self.tools tools def handle(self, user_input, session_id): state self.state_store.get(session_id) # 第一层规则匹配 intent self.rule_match(user_input) # 第二层小模型分类 if intent is None: intent, confidence self.intent_classifier.predict(user_input) if confidence 0.7: # 第三层LLM 兜底 intent self.llm_client.classify_intent(user_input, state) # 更新状态 state.intent intent state.turn 1 # 根据意图路由 handler self.route(intent) result handler(user_input, state) # 校验结果 if not self.validate(result): result self.fallback_response(state) self.state_store.save(session_id, state) return result这段代码的关键点在于LLM 只在规则和小模型都搞不定时才被调用而且调用时传入的是明确的分类任务不是开放式的“你来决定怎么办”。这样 LLM 的输出空间被限制在很小的范围内稳定性大幅提升。4.3 提示词设计给 LLM 划清边界即使 LLM 只负责语义任务提示词设计依然重要。我的原则是提示词里只放 LLM 需要知道的信息不放它不需要知道的。比如做意图分类时提示词里只放意图类别定义和几个例子不要放系统架构、工具列表、用户历史这些无关信息。信息越多LLM 越容易分心输出越不稳定。另一个技巧是要求 LLM 输出结构化格式比如 JSON。这样解析起来方便也容易做校验。如果 LLM 输出的是自由文本你还得再写一套解析逻辑得不偿失。我通常会在提示词里明确给出输出格式的示例并加上“只输出 JSON不要有其他内容”这样的约束。注意不要指望 LLM 每次都严格遵守格式。即使你说了“只输出 JSON”它偶尔还是会加一句“好的以下是结果”。所以解析时要做容错用正则提取 JSON 部分而不是直接json.loads整个输出。4.4 性能与成本实测数据说话我们在一个日请求量 5 万左右的客服 Agent 上做了对比测试。纯 LLM 方案所有决策都走 LLM的平均响应时间是 4.2 秒P99 是 11 秒每万次请求的 token 成本大约是 180 元。改成 System One Model LLM 混合方案后平均响应时间降到 1.1 秒P99 降到 3.5 秒token 成本降到 22 元。准确率方面纯 LLM 方案的意图分类准确率是 87%混合方案是 95%。这个数据不是要证明混合方案一定更好而是想说在 Agent 这种对延迟和成本敏感的场景里把确定性任务交给确定性方法收益是数量级的。省下来的钱和延迟可以用在真正需要 LLM 的地方比如提升生成质量、增加兜底能力。5. 踩坑记录那些年我们过度依赖 LLM 的教训5.1 常见问题速查表问题现象根本原因解决方案同样输入输出不一致LLM 概率性本质确定性任务改用规则或小模型多轮对话状态丢失依赖 LLM 从历史中提取显式状态对象 确定性更新工具调用参数错误LLM 生成完整参数LLM 只出语义参数由代码组装响应延迟高所有步骤都走 LLM分层处理LLM 只做兜底成本失控token 消耗无节制压缩提示词减少 LLM 调用次数线上问题难复现系统行为不可预测记录状态快照分离控制层和智能层分类准确率低类别多、提示词冗长微调小模型规则前置生成内容有事实错误LLM 幻觉校验层拦截 重试机制5.2 三个我亲自踩过的坑第一个坑是用 LLM 做数值计算。有个场景需要根据用户输入的折扣码计算最终价格我们让 LLM 直接算结果它偶尔会算错尤其是涉及小数和百分比的时候。后来改成 LLM 只负责提取折扣码计算由代码完成问题消失。这个教训让我记住LLM 是语言模型不是计算器。第二个坑是把 LLM 的输出直接当命令执行。早期版本里LLM 判断需要调用某个工具后直接生成工具名和参数系统拿到就执行。有一次 LLM 生成了一个不存在的工具名系统报错用户看到的是“系统内部错误”。后来加了白名单校验LLM 只能从预定义的工具列表里选参数也要经过 schema 校验这类问题再没出现过。第三个坑是过度依赖 LLM 做多轮对话管理。我们曾经把整个对话历史塞给 LLM让它决定下一步问什么。结果在对话超过 15 轮后LLM 开始重复问已经问过的问题因为它“忘记”了之前的信息。改成显式状态管理后每轮只传当前状态和最新输入问题解决。这个坑让我明白LLM 的上下文窗口再大也不如一个显式的状态对象可靠。5.3 独家避坑技巧第一个技巧是给 LLM 调用加超时和降级。LLM 服务偶尔会慢如果不设超时整个 Agent 就卡住了。我的做法是设一个 3 秒的超时超时后走降级逻辑返回预设的兜底回复同时记录日志。这样用户至少能得到一个响应而不是一直等。第二个技巧是用影子模式测试新提示词。每次改提示词不要直接上线而是让新提示词和旧提示词并行跑一段时间对比两者的输出差异。确认新版本没有引入回归问题后再切换。这个做法帮我们避免了好几次因为提示词微调导致的线上事故。第三个技巧是把 LLM 的每次调用都记录下来包括输入、输出、耗时、token 数。这些日志在排查问题时极其有用。我们有一次发现某个意图的分类准确率突然下降查日志发现是 LLM 服务商那边模型版本更新了输出分布变了。如果没有日志这个问题可能要排查很久。6. 这套思路适合谁不适合谁Jev 的 System One Model LLM 分工思路最适合的是已经在生产环境跑 Agent、被稳定性和成本问题困扰的团队。如果你还在做 Demo怎么快怎么来没问题但一旦要上线这套思路能帮你省很多事。另外对延迟敏感的场景比如实时客服、语音助手也强烈建议采用这种分层架构因为纯 LLM 方案的延迟很难压到用户可接受的范围内。不太适合的情况是任务本身高度开放、规则几乎无法描述。比如创意写作助手、开放式研究 Agent这些场景里 LLM 的“自由发挥”恰恰是价值所在强行加规则反而会限制它的能力。这种情况下System One Model 的角色应该退回到只做安全校验和格式约束把大部分决策权留给 LLM。我自己的判断标准是看这个 Agent 的错误成本有多高。如果错误会导致用户损失、数据污染、或者需要人工介入修复那就应该多用 System One Model如果错误只是让用户觉得“回答不够好”那可以多给 LLM 一些空间。这个标准不完美但在实际决策时很好用。最后分享一个我在实际项目里总结的小经验每次想加一个 LLM 调用之前先问自己“这个任务我能不能用 20 行代码写清楚”。如果能就写代码如果不能再用 LLM。这个习惯帮我砍掉了大量不必要的 LLM 调用系统稳定性和响应速度都上了一个台阶。Jev 的思路本质上也是这个道理——不是否定 LLM 的能力而是把它放在正确的位置上让整个系统跑得更稳、更快、更便宜。