☰
子智能体路由层设计:让Agent调用成本下降六成
2026/10/15 7:05:32 网站建设 项目流程

上个月我们把整套多智能体系统做了一次“手术”,核心改动只有一处:在子智能体前面加了一个路由层,把所有原本由大模型直接处理的调度请求,先交给一个参数量很小的轻量级模型去判断分发。这个改动听起来不起眼,但跑完一个月看账单,Agent调用成本直接掉了六成,延迟还降了差不多三分之一。

这篇文章就把整个事情从头到尾拆开讲清楚:为什么Agent系统会越跑越贵、子智能体路由到底是怎么设计的、轻量模型凭什么能扛住路由层的活、六成成本是怎么一笔一笔省出来的,以及我们在上线前后踩过的坑和排查实录。无论你是正在被账单逼疯的Agent应用开发者,还是准备优化多智能体系统成本的架构师,这篇都值得花十分钟看完。

1. 为什么你的Agent系统越跑越贵

1.1 大模型直接做调度的隐性浪费

先说个扎心的事实:绝大多数Agent系统的调度逻辑,都是让主控大模型一边做意图理解,一边做任务规划,一边决定调用哪个子Agent,还要负责把子Agent的结果汇总成最终回复。这样做在原型阶段很爽,因为不用写任何路由代码,大模型“什么都会”,说两句话它就自己把链路串起来了。

但一旦进入生产环境,这个设计就变成了成本黑洞。

原因很直白:大模型做调度,本质上是一种“用高级武器干杂活”的行为。举个例子,用户问“把昨天的订单数据汇总一下发我”,这条请求的意图识别和参数抽取,其实就是一个分类问题加上两个字段提取——目标数据是什么、报告给谁。这类任务根本不需要多强的世界知识和推理能力。但在传统的单一大模型调度架构里,这条请求会完整地走一遍大模型推理链路,模型会把“理解意图—规划步骤—生成调用参数—等待工具返回—整理回答”整个思维链全部推理一遍。

这里面的token开销远比你想象的大。我们在某个内部模拟项目X上线初期打过一次日志统计,调度层(就是主控大模型做规划、选工具、传参数的环节)消耗的token,占了整个系统总token消耗的61%。真正干业务的子Agent反而只吃了一小部分。更麻烦的是,调度层的token基本都是输入侧的,因为每次调度要把系统提示词、可用工具列表、历史对话、当前用户输入全部塞进去,一段几千字的工具描述,每次请求都要完整过一遍模型。用行话说,这些token“不带任何业务价值”,纯粹是编排开销。

一句话概括:大模型做调度,能力是绝对够的,但性价比太差了。你的钱有大半花在了“让模型想一想该怎么做”上,而不是“把事情做成”上。

1.2 路由层要解决的核心矛盾

既然问题出在“调度”和“干活”混在了一起,那解法就变得非常清晰:把判断和做事拆开。

判断——也就是“用户这句话该找哪个子Agent、参数是什么”——这件事的本质是一个分类任务,或者说是受限的选择题。它不需要写一篇小作文,不需要创造性输出,只需要从枚举列表里选一个意图标签,再抽取几个槽位参数。而“干活”——真正写文案、做分析、跑计算、生成图片——才是需要大模型能力的地方。

子智能体路由的核心,就是在这两者中间加一层独立的决策模块。这个模块不做生成,只负责回答三个问题:

  1. 这条请求属于哪一类?
  2. 应该交给哪个子Agent处理?
  3. 需要传给它哪些参数?

把这三个问题单独拎出来之后,你会发现一个很关键的事实:这类决策问题的推理复杂度,远低于开放式的对话生成。一个参数量小得多的轻量级模型,完全有能力做对这类分类任务。这就给了我们一个巨大的降本空间——轻量模型的调用价格,通常只有大模型的几十分之一甚至更低。

所以在设计阶段,我们团队就定了一个原则:路由层不是要替代大模型,而是要让大模型把精力集中在真正需要它的事情上。凡是能被规则化、分类化、参数化的请求,一律在路由层分流掉;只有那些需要深度推理、开放生成的请求,才允许继续走大模型链路。

这个思路听起来简单,但它动了一个很多团队不敢动的根基:他们怕路由误判,怕用户体验下降,宁可在调度层多花钱也不愿意冒准确性风险。事实证明,只要路由层的兜底设计够好,误判率完全可以控制在可接受范围,而省下来的成本是实打实的。

2. 子智能体路由的技术设计与选型

2.1 路由层的职责边界

动手写路由之前,最重要的不是选型,而是把路由层的职责边界划清楚。我们在第一次重构时就是因为职责没划清,差点把路由层做成第二个大模型调度器,白折腾了两周。

现在回头看,子智能体路由层只做三件事。

第一,意图识别。把用户输入映射到一个或多个预设的意图标签上。比如一个客服场景下,标签可以是“查订单”“申请退款”“转人工”“询问物流”。这一步是纯分类问题,输出本质上是枚举值。

第二,能力匹配。系统里有很多个子Agent,每个负责一个能力域。路由层要根据意图标签和系统的Agent注册表,决定把请求交给哪一个。这里要特别注意,匹配逻辑最好做成配置驱动的,而不是把Agent名字硬编码在Prompt里。否则后面每新增一个子Agent都要改Prompt,迟早被逼疯。

第三,参数槽位抽取。这是最容易被忽略的一步。很多团队做路由只做意图分类,分类完了直接把原句丢给子Agent让它自己理解。这样做不是不行,但会带来两个问题:一是子Agent需要重复理解一遍上下文,浪费token;二是遇到需要精确参数的任务(比如指定时间范围、指定对象ID),子Agent自己抽错参数的概率很高。所以,路由层应该在分流的同时,把那些明确的参数槽位一并抽出来,打包传给子Agent。

同时,必须明确路由层不做什么。它不生成业务内容,不写最终回复,不做复杂推理,不承担任何知识问答的逻辑。这一点要在系统约束里写死,否则轻量模型很容易跑偏,忍不住“帮忙”生成点内容,既不专业又浪费钱。

2.2 为什么轻量模型能扛住路由工作

很多人一听到“用轻量模型做路由”,第一反应是不放心:轻量模型会不会理解不了复杂意图?会不会把请求分错?这里要分清一个概念:轻量模型在开放生成任务上确实不如大模型,但路由任务根本不属于开放生成。

我再强调一次,路由的本质是“从N个选项里选一个,再抽几个字段”。这个任务的复杂度,跟“写一篇800字产品分析报告”完全不在一个量级。Lightweight模型在分类任务上的表现,只要经过适当的Prompt约束和微调,准确率做到90%以上并不难。而真正剩下的10%,可以靠兜底机制接住。

选型的时候不要只看通用榜单的分数,要看三个更实际的指标:

  • 分类准确率:拿你们业务里真实的历史请求做一批测试集,直接跑混淆矩阵看误判。
  • 结构化输出成功率:路由层必须靠JSON和模型沟通,模型能不能稳定输出合法JSON是关键。有些不擅长结构化的轻量模型,十次里有三次输出坏JSON,这种再便宜也不能用。
  • 延迟:路由链路本身要增加一次模型调用,所以要选延迟低的模型,理想情况是P99延迟在300毫秒以内。

我们的经验是,选一个参数量在几十亿级别的轻量模型,专门做路由,完全够用。如果你手头有历史日志,先抽几千条请求打标签作为测试集,在测试集上跑一轮再决定用哪款,这是最靠谱的选型方法。

2.3 路由决策的三种典型输出

路由层的模型输出,建议统一设计成一种可校验的结构。不要输出自由文本,否则后面解析就是噩梦。我们最终用的是三段式输出:意图标签、参数字典、置信度分数。

下面是一个简化版的输出约定:

{ "intent": "query_order", "confidence": 0.97, "params": { "date_range": "2025-04-01~2025-04-30", "aggregation": "summary", "target": "email" } }

intent字段必须是调用方预设枚举之一,params是传给子Agent的槽位字典,confidence则是模型对这次分类的把握程度。为什么一定要置信度分数?因为它是兜底策略的输入信号。没有置信度,路由层遇到低质量请求时只能硬着头皮分流,误判率高得没法收场。

在代码层面,路由层的核心逻辑其实不复杂。下面是我们在Demo里用的简化版实现思路:

routing_result = routing_model.classify( system_prompt=ROUTING_SYSTEM_PROMPT, user_query=user_input, available_agents=agent_registry.list_names(), schema=ROUTING_OUTPUT_SCHEMA ) if routing_result.confidence < LOW_CONFIDENCE_THRESHOLD: agent_name = "default_fallback" else: agent_name = routing_result.intent execute_agent(agent_name, routing_result.params)

这段逻辑有几个关键点:available_agents是从注册表动态拉取的,不是写死的;schema会强校验输出是不是符合约定;confidence低于阈值时直接走默认兜底Agent。这样设计的好处是,新增子Agent只需注册一下,路由层不用改代码。

3. 路由层落地实现全过程

3.1 路由Prompt的构造思路

前面说了那么多设计原则,真正落到工程上,第一步是把路由Prompt写好。这里直接说我们踩出来的经验。

路由Prompt要大但精。大是指要把能约束模型的信息都放进去,精是指不要让模型有多余的发挥空间。我们最终版的路由系统提示词包含了几个必填模块:

  • 角色与任务定义:一句话说清楚你是一个请求路由助手,只负责分类和参数抽取,不回答用户问题。
  • 子Agent能力清单:每个子Agent的名称、职责描述、适用场景,用枚举列表的形式写清楚。
  • 输出格式强制约定:要求输出JSON,注明字段名和取值枚举。
  • 不确定时的处理指令:模型如果没有把握,必须把confidence设为低值,而不是强行选一个意图。

这里特别强调“不确定时要怎么做”这条指令。没有它,模型为了完成“必定有输出”的任务,会对模糊请求强行选一个意图,这类误判最隐蔽,因为它交给下游Agent后往往直接报错,用户看到的是莫名其妙的结果。

补一个参考性的Prompt结构:

你是智能体系统的请求路由助手。你的职责是从候选智能体中选择一个最适合处理用户请求的智能体,并提取必要参数。 候选智能体: - order_agent:查询订单、退货退款相关。 - report_agent:生成数据报表、汇总统计。 - search_agent:知识库检索、文档问答。 - default_fallback:默认兜底,用于无法明确分类的请求。 输出JSON格式(不要输出其他内容): {"intent": "候选智能体名称", "confidence": 0.0-1.0 的数值, "params": {...}} 规则: 1. 如果无法确定意图,将 intent 设为 default_fallback,并将 confidence 设为 0.2 以下。 2. params 只提取能明确从问题中获得的参数,不要猜测缺失值。

注意一个细节:对轻量模型来说,Prompt里的枚举列表一定要简洁。每个Agent的描述控制在两行以内,太长反而会混淆模型对边界的分辨。

3.2 结构化输出与校验

Prompt保证了模型“大概率”输出合法的JSON,但生产环境不能靠“大概率”。你必须在外面再做一道校验,把结构合法性拦下来。

我们在每个路由请求后都会跑一个校验函数,核心做四件事:

  1. 解析JSON,解析失败直接进兜底链路。
  2. 校验intent字段是否在Agent注册表里,不在就进兜底。
  3. 校验params里字段类型是否符合预期(比如日期字段必须是合法日期格式)。
  4. 校验confidence是否在0到1之间,不合法按低置信度处理。

不管用的什么轻量模型,你都要假设输出可能损坏。反正实际跑一段时间就会知道,再聪明的轻量模型也有状态不好的时候,可能突然输出一堆Markdown文本而不是JSON。在这种情况下,如果代码里没有强校验,下游全部会报错。

写校验逻辑时建议直接用通用数据校验库,不用自己造轮子。

from jsonschema import validate, ValidationError ROUTING_SCHEMA = { "type": "object", "properties": { "intent": {"type": "string"}, "confidence": {"type": "number", "minimum": 0, "maximum": 1}, "params": {"type": "object"} }, "required": ["intent", "confidence", "params"] } def parse_routing_response(raw): try: result = json.loads(raw) validate(result, ROUTING_SCHEMA) return result except (json.JSONDecodeError, ValidationError): return {"intent": "default_fallback", "confidence": 0.0, "params": {}}

校验失败时,策略是进兜底链路而不是直接报错。兜底链路很简单——放弃路由,把原始请求直接转给默认大模型Agent处理。这样用户的请求一定能得到响应,只是成本上偶尔会多花一点。这个“优雅降级”的设计,是整个方案能在生产环境安心运行的前提。

3.3 兜底策略与降级逻辑

路由层在设计时就要想清楚一个问题:它会犯错,而且一定会犯错。所以兜底策略不是可选项,而是必选项。

我们最终用的三档置信度策略:

  • confidence >= 0.9:高置信度,直接把请求路由到对应子Agent,同时附带抽取好的参数。
  • 0.5 <= confidence < 0.9:中置信度,路由层把候选意图和大模型复核请求一起发给大模型,让大模型做最终确认。这个策略增加了少量大模型调用,但比全量走大模型便宜得多。
  • confidence < 0.5:低置信度,不猜了,直接走默认兜底Agent,或者转人工处理。

这三档策略的好处是,给了系统一个平滑过渡的能力。前期模型调教的不好,中低置信度请求占比高,成本节约不明显;随着Prompt迭代和测试集反馈,高置信度占比逐步提升,成本优化效果越来越明显。

我们在生产环境的实测是:高置信度请求占比在87%左右,中置信度约占8%,低置信度约占5%。也就是说,接近九成的请求可以不经过大模型直接分发。真正需要大模型二次确认的比例很小,整体成本依然压得住。

另外提醒一句:上线初期别把兜底策略做得太复杂,先保证“错误不可怕”。我们第一版只做了一道兜底——低置信度和解析失败全部走默认大模型Agent。等跑了两个星期积累了真实数据,才把中置信度复核档加进去。一步一步来,比一次设计到位更靠谱。

4. 成本核算:六成成本是怎么省出来的

4.1 改造前后的成本结构对比

口说无凭,直接上算例。假设我们有一套多智能体客服系统,之前每个请求都由大模型走完整调度链路。为了好算,设每次请求平均消耗输入token为4000,输出token为800,我们按主流大模型常见的中位公开价格来模拟测算:输入侧约合5美元每百万token,输出侧约合20美元每百万token。

那么改造前单次Agent请求的成本是:

输入成本 = 4000 / 1000000 × 5 = 0.02美元 输出成本 = 800 / 1000000 × 20 = 0.016美元 单次请求总成本 = 0.036美元

改造后,每个请求先经过路由层,用轻量模型做分类。假设轻量模型输出的输入token为500,输出token为150,价格按输入0.15美元每百万token、输出0.6美元每百万token模拟(具体以实际模型报价为准)。路由层的单次成本约是:

路由成本 = 500 / 1000000 × 0.15 + 150 / 1000000 × 0.6 = 0.00075 + 0.00009 = 0.00084美元

如果系统里有35%的请求确实需要大模型深度处理(比如开放式咨询、复杂投诉),这部分仍然走大模型链路,那改造后的平均单次成本约为:

加权平均成本 = 0.00084 + 0.35 × 0.036 = 0.00084 + 0.0126 = 0.01344美元

对比改造前的0.036美元,单次成本降幅约62.7%。这就是“砍掉六成”的数据来源。

下面是改造前后成本结构的直观对比:

项目改造前(全量走大模型)改造后(路由层分流)
单次请求平均调度成本0.036美元0.00084美元
需大模型深度处理的请求占比100%35%
加权单次请求成本0.036美元约0.0134美元
成本降幅—约62.7%

上面的价格和占比是示例测算数据,每家团队的实际结构和报价不同。你完全可以拿着真实的token日志套进去算一遍,方法是一样的。

4.2 实测延迟与质量变化

降本之外,延迟的变化也是意外收获。原先一条请求要等大模型先做几百甚至上千token的思维链式规划,再调用工具,整体响应时间经常要两三秒。加了路由层之后,大部分能分类的请求由轻量模型快速分出去,子Agent直接执行,省掉了“大模型想一想”的那一大段时间。我们实测的平均响应时间从2.8秒降到了1.9秒左右。路由层本身增加的延迟大概是100到200毫秒,但相比大模型长思维链的开销,完全是净收益。

质量方面,我们盯了三个指标:

  • 路由准确率:抽查1000条请求,人工标注后对比路由结果,准确率约92%。
  • 任务成功率:路由到子Agent后,子Agent成功完成任务的比例,约95%。
  • 人工介入率:使用过程中主动转人工的占比,从改造前的8.1%微升到8.6%。

这几个数字说明,路由层没有带来明显的体验恶化,人工介入率的微小上升,我们分析是源于个别模糊请求被路由到了较窄能力的Agent上,属于可以接受的代价。

4.3 什么场景不适合这个方案

成本核算看起来很漂亮,但必须泼一盆冷水:这个方案不是所有Agent系统都适用。我们试过几个方向之后,总结出三类不太适合的场景。

第一类,任务边界模糊的开放式系统。如果你的子Agent能力范围重叠严重,用户请求经常同时命中多个Agent,路由层很难把意图分得干净。比如一个Agent处理所有类型文案,另一个Agent处理所有类型图片,用户的请求“给这张图配段文案”横跨两者,路由就尴尬了。这种情况要么先重构Agent边界,要么别硬上路由。

第二类,强知识依赖的深度任务。做政策解读、医疗诊断辅助、法律建议这类场景,用户问一个复杂问题,提问本身就隐含了大量前置知识和推理路径。路由层即使分对了Agent,Agent落地的质量也比直接走大模型差得远。省了成本,但省掉了质量,这钱不能省。

第三类,极低频请求的系统。如果一天只有几百个请求,路由层的开发成本、维护成本、测试成本摊到每个请求上可能比省下的钱还多。对于小体量场景,老老实实全量走大模型更省心。路由优化是规模化生意,量越大越划算。

不适合的场景不要硬套,这一点比技术本身更重要。

5. 常见问题与排查实录

5.1 路由误判修复案例

上线第一个星期,我们就遇到一个非常典型的误判。用户问“帮我把这份销售报表发给总监”,路由层把它分到了send_email这个Agent,参数只抽到了“销售报表”。结果子Agent直接调了邮件发送接口,差点没把审批流程绕过。

排查的时候我们先把路由日志打开,发现问题出在参数槽位抽取不完整:路由层识别出了“发送”指令,但没有识别出“发给总监”这个接收人信息,同时也没有识别出“这份报表需要先确认权限”。修复方案是两步:一是在路由Prompt的示例里增加了包含接收人槽位的案例,二是给发送类意图增加了一个“需权限校验”的关联规则,路由完成后让子Agent在读参数时同步检查。

这个案例的教训是:路由层不能只是分类,槽位抽取的完整性直接影响下游安全性。对于涉及发送、删除、修改这类高风险操作,路由层宁可多抽几个槽位,也不要漏抽。漏抽的后果往往不是成本问题,而是事故。

5.2 缓存与去重带来的二次收益

路由层稳定运行之后,我们注意到一个现象:很多请求其实是完全重复的。比如“查今天销售额”这条,同一天内被不同人问了上百次。路由层每次都做同样的分类、抽同样的参数,属于无意义重复计算。

我们在路由层前面加了一道查询缓存:以“去重哈希后的用户输入+当日日期”为Key,把路由结果缓存起来。如果命中缓存,连轻量模型的调用都省掉,直接拿缓存里的意图和参数分发。实测下来,缓存命中率大概在23%左右,这23%的请求连路由token都不用花了,进一步把单次成本往下压了一截。

缓存不是没有副作用。我们用的策略是短TTL加定时刷新,比如查询型缓存5分钟失效,报表型缓存按业务刷新周期主动失效。不要为了追求命中率把TTL拉得太长,否则用户会看到过时数据,得不偿失。对于数据一致性要求极高的场景,建议跳过缓存直接走路由链路。

5.3 日志与监控的关键指标

最后说监控。加了路由层之后,系统的可观测性要求提高了,因为多了一个判断节点。我们最终形成了四个必盯指标:

  • 路由准确率:人工抽样的标注准确率,每周看一次趋势。
  • 兜底触发率:低置信度和解析失败请求占比,超过15%就要查Prompt是不是被改坏了。
  • 平均延迟:路由层耗时和总响应耗时分开统计。
  • 单次请求成本:用账单除以请求数,按天看这个数字,它比任何指标都直观。

此外,每个路由请求必须记录完整日志,包括原始输入、路由输出的intent、confidence、params、是否走了兜底。没有这些日志,出问题复盘就是瞎猜。我们团队的习惯是:路由日志单独存一张表,保留30天,做分析时随时能查。

上线第一个星期,不要调阈值,不要急着改Prompt。先让系统跑着,用这一周时间把真实的请求分布、置信度分布、误判类型全部收集起来。有了数据再优化,效率会高得多。我们当时没忍住,第三天就改了一版Prompt,结果误判率反而高了,花了半天才回滚。

最后说几点实在的体会

整个方案做下来,我最深的一个感受是:子智能体路由这件事,本质上是把“简单的事交给便宜的执行者,复杂的事留给聪明的思考者”。大模型确实能包揽一切,但包揽一切的代价太大了。给系统一个明确的分工,让它学会拒绝不该自己做的事,这个思维模型放到Agent架构、成本控制、甚至团队管理上都说得通。

如果让我给准备动手的团队几个建议,第一,不要一上来就全面铺开,先挑一类高频且边界清晰的任务跑试点,比如查询、报表、简单操作,拿到真实数据和反馈再扩展。第二,成本账要自己算,别人的数字只能参考,token消耗结构和模型报价每个团队都不一样。第三,兜底链路一定要先于路由链路开发,先把失败预案做好再谈优化。

这几年做Agent系统,见太多团队在架构上追求“大而全”,最后死在账单上。省钱的大方向不是让模型变得更便宜,而是让系统变得更聪明——知道什么该干,什么不该干。路由层只是这个思路的一个具体落地,但它带来的成本变化,足够说明方向是对的。

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

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

立即咨询