ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

AI Agent判断下沉实战:从大模型推理到系统层优化

AI Agent判断下沉实战:从大模型推理到系统层优化 1. 从“Jev 爆火”说起一个被低估的设计信号Jev 这个项目在社区里火起来的时候我第一时间去翻了它的源码和讨论帖。坦白讲第一眼看上去它并不惊艳——没有花哨的界面没有堆砌一堆模型甚至文档都写得有些随意。但用了一段时间之后我意识到它真正打动人的地方恰恰是一个很容易被忽略的设计选择把一部分判断逻辑从“大模型推理”下沉到了系统层。这个思路在 AI Agent 圈子里其实不算全新但 Jev 把它做得足够彻底、足够自然以至于很多人在用的时候根本没意识到自己正在受益于这个设计。我当时的反应是这套东西能不能搬到我自己的开源 Agent 项目里答案是能而且改造量比我想象的小得多。这篇文章就是那次改造的完整记录。我会讲清楚什么是“System One 判断下沉”、为什么它值得做、我在自己的 Agent 里怎么落地的、踩了哪些坑、以及最终效果到底怎么样。如果你正在搭自己的 AI Agent或者对 Agent 的架构设计感兴趣这篇内容应该能给你一些可以直接抄的作业。如果你只是好奇“判断下沉”到底是个什么东西我也会用最直白的方式把它讲明白。先说结论判断下沉不是让模型变笨而是让系统变聪明。它解决的核心问题是——很多本该由确定性逻辑处理的判断被无脑丢给了大模型结果既慢又贵还不稳定。把这类判断收回到系统层模型只负责它真正擅长的那部分整个 Agent 的响应速度、成本、可靠性都会有肉眼可见的提升。2. 什么是 System One 判断下沉把“条件反射”还给系统2.1 从认知科学借来的一个类比“System One”这个词借自认知科学里的双系统理论。简单说人的思维分两套一套是快速的、直觉的、几乎不消耗能量的System One另一套是慢速的、理性的、需要集中注意力的System Two。你伸手去拿杯子的时候不会先做一遍物理计算这就是 System One 在干活你解一道数学题的时候用的是 System Two。大模型本质上是一个超级强大的 System Two。它能做复杂推理、能理解模糊意图、能生成自然语言但它的每一次“思考”都要消耗算力和时间。问题在于很多 Agent 把所有事情都交给这个 System Two 去做包括那些本该是条件反射的判断。举个最典型的例子用户发来一条消息Agent 需要判断“这是不是一个新话题”。这个判断需要大模型来做吗大多数情况下不需要。消息里有没有明显的转折词、有没有引用上文的指代词、和上一轮对话的语义相似度是多少——这些用轻量规则和向量相似度就能算出来耗时可能只有几毫秒。但如果你让大模型来判断一次调用就是几百毫秒起步还要花钱。判断下沉的核心思想就是把这类“条件反射式”的判断从大模型推理层下沉到系统逻辑层。系统层用规则、状态机、轻量计算来处理确定性高的判断大模型只处理真正需要理解和生成的复杂部分。2.2 判断下沉和“规则引擎”的区别有人可能会说这不就是规则引擎吗不完全是。传统的规则引擎是静态的、写死的if-else 堆出来的。判断下沉强调的是动态分层哪些判断该下沉、下沉到什么程度、什么时候该把判断权交还给模型这些是有策略的。我自己的做法是画一条“判断成本线”。横轴是判断的确定性程度纵轴是判断出错的代价。确定性高、出错代价低的判断坚决下沉到系统层确定性低、出错代价高的判断交给大模型中间地带用混合策略——系统层先做初筛模型做复核。这个分层策略是整套方案的地基。没有它判断下沉就会退化成“到处写 if-else”最后维护成本比全交给模型还高。2.3 为什么现在值得认真做这件事两年前大家不太在意这个因为模型调用便宜、延迟也能忍。但现在情况变了Agent 要处理的任务越来越复杂一轮对话里可能触发十几次模型调用延迟叠加起来用户直接跑掉同时大家对成本的敏感度也上来了尤其是做开源项目或者个人项目每一分钱都要算。更关键的是Agent 的可靠性问题很大程度上就出在“什么都让模型判断”上。模型有幻觉、有随机性同一个输入两次可能给出不同判断。而系统层的判断是确定的、可测试的、可复现的。把该下沉的判断下沉之后Agent 的行为会稳定很多调试也容易得多——你可以单独测试系统层的判断逻辑而不用每次都去猜模型为什么这么想。3. 我为什么决定在自己的 Agent 里动手改造3.1 改造前的真实痛点我的 Agent 项目是一个偏工具型的开源 Agent主要处理文档问答和任务编排。改造之前它的架构很“标准”用户输入进来拼上历史对话和系统提示词丢给大模型模型输出一个 JSON 描述下一步动作系统解析 JSON 执行再把结果拼回去给模型生成回复。这套架构跑 demo 没问题但一上真实场景就露馅。最明显的问题是响应慢。一轮简单的问答从用户发送到收到回复经常要三四秒。我抓了一下耗时分布发现模型调用占了 80% 以上其中又有相当一部分调用是在做“判断”而不是“生成”。比如用户问“刚才那个文档的第三页讲了什么”Agent 需要先判断“刚才那个文档”指的是哪个文档。这个判断我原本是让模型做的——把历史对话里所有文档名塞进提示词让模型选一个。但实测下来模型经常选错尤其是对话轮次多了之后。而实际上我完全可以用一个简单的“最近提及的文档”栈来维护这个状态根本不需要模型参与。另一个痛点是成本。我统计过改造前平均每轮对话触发 3.2 次模型调用其中至少 1.5 次是在做本可以下沉的判断。按当时的调用量算一个月下来光判断类的调用就烧掉不少钱。3.2 改造的目标和边界动手之前我给自己定了三条规矩第一不改变 Agent 的外部行为。用户感知到的能力不能缩水只是内部实现变了。这条最重要否则改造就变成了重写。第二下沉的判断必须可测试。每个下沉到系统层的判断逻辑都要能写单元测试给定输入必须得到确定输出。做不到这点的判断不下沉。第三保留回退路径。系统层判断不确定的时候要能优雅地交还给模型而不是硬猜。这条是安全网防止下沉过度导致 Agent 变傻。这三条规矩后来证明非常关键尤其是第三条。我见过一些项目为了追求“快”把判断全下沉了结果遇到边界情况直接崩掉用户体验反而更差。3.3 改造范围的划定我没有一上来就大改而是先做了一轮“判断审计”。具体做法是把 Agent 运行过程中的所有模型调用打上标签记录每次调用的目的。跑了一周的真实数据之后我把调用分成了三类纯判断类输出是离散的选项或布尔值比如“是不是新话题”“选哪个文档”“要不要调用工具”。判断生成混合类先判断再生成比如“判断用户意图然后生成回复”。纯生成类输出是自然语言或结构化内容比如“总结这段文字”“生成任务计划”。审计结果很清晰纯判断类调用占了总调用次数的 47%但消耗的 token 只占 12%。也就是说将近一半的调用是在做“小事”但每件小事都要走一遍完整的模型推理流程。这就是改造的主战场。4. 判断下沉的落地架构三层判断模型4.1 三层结构的设计基于审计结果我把 Agent 的判断逻辑重构成了三层第一层是状态层。这一层维护 Agent 的运行时状态包括当前对话主题、最近提及的实体、已执行的动作历史等。状态层的更新和查询完全是确定性的不涉及任何模型调用。比如“最近提及的文档”就是一个栈用户每次提到文档就压栈需要的时候取栈顶。第二层是规则层。这一层处理有明确规则的判断用轻量逻辑实现。比如“用户消息里包含问号且长度小于 20 字判定为简单问答”“连续两轮用户消息的向量相似度低于阈值判定为主题切换”。规则层的判断结果带置信度高置信度直接采用低置信度往上抛。第三层是模型层。只有前两层无法确定或者置信度不足的判断才交给大模型。模型层的调用会带上前两层已经确定的信息作为上下文减少模型的判断负担。这三层不是简单的串联而是有优先级的。状态层能直接回答的判断根本不进规则层规则层高置信度的判断不进模型层。这样大部分判断在前两层就被消化掉了。4.2 状态层的实现细节状态层是整个架构的地基它决定了哪些信息是“随时可用”的。我的实现里状态层维护了这么几类状态对话主题栈记录当前对话涉及的主题支持主题切换和回退。实体注册表记录对话中出现过的实体文档、任务、人名等带时间戳和提及次数。动作历史记录 Agent 已经执行过的动作防止重复执行。用户偏好缓存记录用户的显式偏好比如“以后都用中文回复”。这些状态的更新时机很关键。我的做法是在每次模型调用返回后用规则解析模型输出更新状态。而不是让模型直接输出状态更新指令——那样又变成模型判断了。比如模型回复里提到了某个文档名规则层用实体识别把它抽出来更新实体注册表。这里有个细节值得说实体识别我用的是轻量方案没有上大模型。具体就是维护一个已知实体列表用字符串匹配加编辑距离来识别。对于文档名这种格式相对固定的实体准确率足够高。如果实体列表里没有匹配项才考虑让模型帮忙识别但这种情况很少。4.3 规则层的设计原则规则层最容易写成一团乱麻所以我定了几个原则规则要可组合。每条规则是一个独立的判断函数输入是状态和当前消息输出是“确定/不确定/否定”三态加置信度。规则之间可以组合比如“主题切换”规则可以由“相似度低于阈值”和“出现转折词”两条子规则组合而成。规则要有优先级。不是所有规则平等有些规则一旦触发就短路后续判断。比如“用户明确说‘换个话题’”这条规则优先级最高直接判定主题切换不用再算相似度。规则要能热更新。我把规则配置抽成了独立的配置文件改规则不用重新部署。这对于调优特别重要——你可以根据线上数据快速调整阈值观察效果。下面是我规则层配置的一个片段用 YAML 写的rules: - name: topic_switch_by_keyword priority: 100 condition: type: keyword_match keywords: [换个话题, 不聊这个了, 说点别的] action: type: set_flag flag: topic_switch confidence: 0.95 - name: topic_switch_by_similarity priority: 50 condition: type: vector_similarity threshold: 0.35 compare_with: last_user_message action: type: set_flag flag: topic_switch confidence: 0.7这个配置的意思是如果用户消息里出现明确的换话题关键词置信度 0.95 直接判定否则算和上一条用户消息的向量相似度低于 0.35 判定为可能换话题置信度 0.7。0.7 这个置信度不足以直接采用会往上抛给模型层复核。4.4 模型层的“减负”调用模型层不是简单地“剩下的都给它”而是要做减负。具体做法是调用模型时把前两层已经确定的信息作为“已知事实”注入提示词让模型只处理不确定的部分。比如判断用户意图这个任务改造前我会把整段对话历史丢给模型让它输出意图分类。改造后状态层已经知道当前主题和最近实体规则层已经排除了几种明显意图那么给模型的提示词就变成“当前对话主题是 X最近提及的实体是 Y用户消息是 Z请判断用户意图是以下哪一类排除已排除的 A、B”。这样模型的处理负担小了很多输出也更稳定。实测下来这种减负调用的延迟比全量调用低了 40% 左右准确率反而略有提升——因为干扰信息少了。5. 核心判断的下沉实操四个真实案例5.1 案例一主题切换判断这是下沉收益最明显的一个判断。改造前每轮对话都要调一次模型判断“是否切换主题”平均延迟 600ms。改造后规则层用关键词匹配加向量相似度平均耗时 15ms只有置信度不足的情况才调模型占比不到 10%。具体实现上向量相似度我用的是一个轻量嵌入模型本地跑不调 API。嵌入计算在消息进入时就做完了和后续判断解耦。相似度阈值我调了几轮最终定在 0.35。这个值偏低意味着规则层倾向于“认为没换话题”把换话题的判断更多交给模型。为什么这么定因为误判“换话题”的代价比漏判高——误判会导致上下文丢失用户得重新解释漏判只是多带了一点无关上下文模型一般能处理。提示相似度阈值没有通用最优值一定要用自己的真实对话数据调。我的做法是人工标注 200 轮对话的“是否换话题”然后画 ROC 曲线选阈值。5.2 案例二工具调用决策Agent 要不要调用工具、调用哪个工具这个判断改造前也是模型做的。模型输出一个工具名系统执行。问题是模型经常在该调用的时候不调用或者调用了不该调用的工具。下沉之后我加了一层“工具适用性预判”。状态层维护了当前可用的工具列表和每个工具的适用条件。规则层根据用户消息的关键词和当前状态先筛出一批候选工具再把候选工具和用户消息一起给模型让模型在候选里选。如果规则层筛完只剩一个候选直接调用不问模型。这个改动的效果很直接工具调用的准确率从 78% 提到了 91%而且平均每轮对话的工具判断延迟从 800ms 降到了 200ms 以下。剩下的 9% 错误主要出在规则层筛候选时漏掉了正确工具这个通过扩充规则覆盖来逐步改善。5.3 案例三多轮对话的指代消解“它”“那个”“刚才说的”这类指代词的处理是 Agent 的老大难。改造前全靠模型模型经常指错。下沉之后状态层的实体注册表派上了用场。我的做法是规则层扫描用户消息里的指代词如果找到就去实体注册表里找最近提及的、类型匹配的实体。如果只有一个候选直接替换如果有多个候选把候选列表给模型让模型选。如果注册表里没有候选才让模型从对话历史里找。这个改动让指代消解的成功率从 65% 提到了 88%。关键点在于实体注册表要维护“最近提及”的顺序而且要考虑实体类型。比如“它”通常指代物体或文档“他/她”指代人。类型匹配能大幅缩小候选范围。5.4 案例四回复长度和风格控制这个判断比较隐蔽但下沉之后效果很好。改造前我是在系统提示词里写“回复要简洁”但模型经常不听话回复忽长忽短。改造后我把“回复长度”下沉成了一个系统层参数。具体做法是状态层根据当前场景简单问答/复杂解释/任务确认设定一个目标长度区间规则层根据用户消息的特征长度、问句类型微调这个区间然后把区间作为硬约束传给模型。模型生成时系统层会监控生成长度超出区间就截断或要求重生成。这个改动让回复长度的方差降低了很多用户体验更一致。而且因为长度可控生成延迟也更稳定了。6. 改造过程中的踩坑记录与排查技巧6.1 坑一状态层和模型层的信息不一致改造初期遇到的最烦人的问题是状态层记录的信息和模型实际使用的信息对不上。比如状态层认为当前主题是 A但模型在生成回复时用的上下文里主题还是 B。原因是状态更新和模型调用之间有竞态。解决办法是把状态更新做成原子操作并且在模型调用前做一次状态快照。模型调用用的是快照状态更新不影响正在进行的调用。调用返回后再用返回结果更新状态。这样虽然状态会有一轮延迟但一致性有保证。6.2 坑二规则层过度拦截有一段时间我为了追求下沉率把规则层的阈值调得很激进结果规则层经常“自信地”做出错误判断把本该给模型的判断拦截了。最典型的是主题切换判断阈值调高之后用户稍微换个说法就被判定为换话题上下文频繁丢失。教训是规则层的置信度阈值要保守宁可多抛给模型也不要自信地犯错。下沉的目的是提效不是替代模型。我现在规则层的策略是“高置信度才拦截中等置信度标记后抛给模型低置信度直接抛”。6.3 坑三向量相似度的计算开销一开始我把向量相似度计算放在了判断的实时路径上结果发现嵌入计算本身就要几十毫秒加上相似度计算整体耗时并没有比调模型少多少。后来改成嵌入预计算消息一进入系统就算好嵌入并缓存判断时直接取缓存算相似度。这样实时路径上只剩相似度计算耗时降到几毫秒。6.4 常见问题速查表问题现象可能原因排查方向解决思路下沉后 Agent 变“傻”规则层过度拦截统计规则层拦截率降低置信度阈值多抛给模型状态和模型不一致状态更新竞态检查更新时机状态快照 原子更新判断延迟没降实时路径有重计算打点各环节耗时预计算 缓存规则维护困难规则耦合严重检查规则依赖规则独立化 优先级短路模型调用没减少下沉判断选错了重新做判断审计只下沉高确定性判断6.5 一个容易被忽略的坑测试覆盖下沉的判断逻辑必须写测试这点我前面强调过但实际做的时候还是偷懒了。结果有一次改了一条规则的阈值没跑测试就上线导致一个边缘场景下 Agent 完全无法响应。后来我强制要求每条下沉规则必须有对应的单元测试覆盖正常、边界、异常三种情况。测试用例从真实对话数据里采样保证贴近实际。7. 改造效果与后续扩展方向7.1 量化效果改造完成后跑了一周对比改造前一周的数据指标改造前改造后变化平均每轮模型调用次数3.21.4-56%平均响应延迟3.4s1.6s-53%判断类调用占比47%12%-35pp工具调用准确率78%91%13pp指代消解成功率65%88%23pp每千轮对话成本基准约 0.45 倍-55%这些数字里我最看重的是响应延迟和成本。延迟减半意味着用户体验有质变成本减半意味着项目能跑得更久。准确率的提升算是意外之喜但也在情理之中——确定性逻辑本来就比模型判断更稳定。7.2 后续可以继续下沉的判断目前还有几类判断我暂时没下沉因为确定性不够或者实现成本高情感判断用户情绪是正面还是负面这个目前还是模型做。轻量方案准确率不够暂时保留。复杂意图分类多意图混合的情况规则层处理不了留给模型。跨会话的长期偏好这个需要持久化存储和更复杂的状态管理后续考虑。7.3 给想动手的人的几点建议如果你也想在自己的 Agent 里做判断下沉我的建议是先审计再动手。别凭感觉猜哪些判断该下沉用数据说话。给模型调用打标签跑一周真实数据你会看到很清晰的分布。从最简单的判断开始。主题切换、指代消解这类判断规则明确、收益明显适合作为第一批下沉对象。复杂的判断等架构稳定了再说。保留回退路径。这是安全网也是你敢于激进下沉的底气。没有回退路径你会在调阈值的时候畏手畏脚。测试要跟上。下沉的判断逻辑是确定性的这意味着它可以被完整测试。别浪费这个优势把测试写全。别追求 100% 下沉率。下沉率是个虚荣指标真正重要的是整体效果。有些判断就是该模型做硬下沉只会让 Agent 变傻。我在实际改造中最大的体会是判断下沉本质上是一种“架构自律”。它逼着你去想清楚哪些事情是系统该负责的哪些是模型该负责的。想清楚这个问题Agent 的架构自然就清晰了。这个思路不限于我自己的项目任何 Agent 项目都可以借鉴——先分层再下沉最后用数据验证。
返回列表