接手过Agent项目的人应该都有个共同感受:模型选对了、Prompt写得再花,工具一旦调错,整个任务链就全崩了。你说它是路由问题也好,调度问题也好,归根到底就是Agent的工具选择策略没做好。这个环节从最原始的if/else硬编码,到现在依靠模型语义理解做动态决策,中间隔着的不仅是一段代码演进,更是任务成功率、token成本、可维护性和线上稳定性的全面分水岭。
这篇文章我会结合自己实际搭过的Agent项目,把工具选择这条技术路线从头拆到尾:先讲硬编码为什么能跑、又为什么卡脖子,再讲动态决策的几种主流实现路线,最后给出一套能落地的动态工具选择模块设计,包括注册中心、双通道路由、得分计算、降级兜底和快照方案。适合正在做Agent开发、或者准备把Agent接进生产环境的朋友参考,尤其是那些工具数量超过七八个、已经开始觉得提示词快塞不下的团队。
1. 为什么要单独谈“工具选择策略”
1.1 工具选择不只是“调API”
Agent框架的本质,我习惯用一句话概括:模型加工具加记忆,外面套一个执行循环。模型负责理解任务,工具负责执行动作,记忆负责跨轮次的信息保留,而执行循环把它们串起来。在这个循环里,工具选择是开头第一个决策点,也是出错率最高的地方。
很多人以为工具选择就是把用户的话转成一个API调用,但实际上它是“语义理解、上下文判断、任务拆分、风险控制”四个能力的交汇口。工具选错了,后面就算Prompt写得再好、代码执行得再顺,结果也是错的。更麻烦的是,实际生产里工具之间的差异非常大,有的是查数据库,有的是发HTTP请求,有的是改文件,有的是触发一个长时间运行的异步任务。它们的延迟不同、权限边界不同、依赖的参数格式不同,硬要用一套固定规则去统一调度,几乎不可能。
我用一个生活化的类比来解释这件事:正常人走进工具间,看到锤子、螺丝刀、扳手,不会问“我要拧螺丝该用哪个”,因为大脑会自动匹配场景和工具的功能。Agent也一样,它面对的“工具间”可能有几十件工具,每件还带着不同的使用条件和副作用。工具选择策略就是这个“大脑里自动匹配”的过程,策略的好坏直接决定Agent是高效地把活干完,还是在一堆无关工具里来回试探、空转烧token。
另外要留意的是,工具选择不是一次性决策。一个复杂任务往往会在不同阶段调用不同工具,比如先搜索资料,再调用计算服务,最后生成报告。这意味着工具选择策略必须支持“多轮决策”,而且每一轮都要能感知到前面已经发生过的上下文。这比单个工具调用的准确性要求高得多。
1.2 从硬编码到动态决策的变化
硬编码的工具选择,说到底就是“人先把规则写死”:用户输入里包含某个关键词就走某个工具,命中了哪条正则就调哪个接口,或者干脆按固定顺序把工具挨个执行一遍。这种方式在一两个工具的小Demo里非常好用,因为规则简单、结果可控、出问题了也容易排查。
动态决策则完全不同。它让Agent在执行时根据实时任务内容、上下文状态、工具的描述和能力特征,去计算“当前到底该调哪个工具最合适”。这种计算可以是基于规则引擎的配置化推导,可以是用Embedding做语义相似度匹配,也可以直接让LLM模型来选。无论哪种,核心都是把“选择权”从写死的代码里释放出来,交给运行时数据和模型理解力去判断。
我见过很多团队在这条路上反复横跳。一开始大家都在硬编码里快速交付,后来工具一多、需求一变,就开始重构路由逻辑;再后来接触了语义路由和模型自选,又觉得太黑盒、不好控制。实际上硬编码和动态决策不是非此即彼的关系,而是一个光谱,成熟的做法通常是把两者混用。速度要求高的走规则,语义复杂的走模型,拿不准的再降级到人工澄清。
这个光谱上的每一档都有典型的实现方式和使用场景。我见过最快的方案是纯关键字匹配,微秒级响应;最慢的方案是每个任务都调用一次模型做工具选择,几百毫秒起步,代价高但准确率也高。真正的问题是,很多团队一上来就跳到最重的那档,忽略了中间档位的性价比。
1.3 哪些场景最吃这套策略
不是所有Agent都需要复杂的工具选择策略。如果你的Agent只有一个搜索引擎工具,那根本不需要路由,闭着眼睛调就行。真正需要认真设计工具选择策略的场景,通常有这些特征:
第一,工具数量多,且职责边界重叠。当工具超过八个、十个,工具描述开始出现交叉语义时,硬编码的规则表就很容易漏掉说法。第二,任务类型多样且不可穷举。客服、运维、数据分析这类Agent每天面对的用户提问几乎不可能全部列成规则,工具选择必须动态推导。第三,工具之间存在明显副作用差异。比如“删除数据”和“查询数据”虽然都是数据工具,但风险和权限要求截然不同,选择必须谨慎。第四,对执行成本和延迟敏感。这类场景一旦选错工具,不仅浪费一次调用,还可能触发一系列连锁执行动作,造成大量无效token消耗。
我做过的数据分析Agent就是典型例子。工具列表里有查数、画图、跑模型、导出报表、发邮件等十几个工具,用户一句“把上周的销售趋势做成图表发给老板”,如果工具选择策略不过关,Agent可能先去调了发邮件工具,结果发现没有附件,又转去跑画图,上下文一乱,最后给老板发出去一封空邮件。这种问题不是单靠优化Prompt就能解决的,必须在工具选择这一层做结构性改进。
2. 硬编码方案:快速上线但天花板明显
2.1 硬编码的四种常见形态
我梳理过市面上最常见的硬编码工具选择写法,大概有四种形态。第一种是if/else关键词匹配,代码里写死“包含天气就调天气API”,这种最常见但最脆弱。第二种是正则表达式规则,比关键词强一点,能处理“北京明天天气怎么样”这种句式,但依然解决不了同义改写问题。第三种是固定顺序执行,也叫管道模式,不管什么任务进来都按固定顺序把所有相关工具跑一遍,把结果集体丢给模型,让模型自己挑。第四种是配置映射表,把工具名、关键词、触发条件做成一张配置表,运行时查表路由。
我最初做第一个Agent项目时用的就是第四种。配置表一开始很好看,每个工具配了三五个触发词,测试时效果也不错。但上线后真实用户的表达五花八门,“查一下”“看看”“帮我了解一下”“有没有数据”这些说法全被配置表放进了同一个入口,路由准确率立刻跌到不能看。
这里要强调一个关键认知:硬编码不等于低效。在场景封闭、工具数量极少、用户表达高度标准化的时候,硬编码反而是最优解。比如一个内部工单系统,Agent只负责“创建工单、查询进度、关闭工单”三件事,硬编码比任何动态方案都快、都稳、都容易审计。动态决策不是要消灭硬编码,而是要在硬编码够不着的地方接棒。
2.2 硬编码的优点(不全是缺点)
聊硬编码的瓶颈之前,我必须先客观说清楚它的优点,否则很容易让人产生“动态决策才是正道”的误解。
硬编码最大的优点是可控性。每次路由的结果都可以从代码或配置里反推出来,没有不确定性,出问题就是看规则,不需要猜模型意图。第二是延迟极低,查表匹配微秒级完成,没有网络调用,没有模型推理。第三是调试友好,线上问题复现路径清晰,不需要额外设计快照和回放体系,看日志就能快速定界。第四是成本透明,路由过程不消耗token,烧钱只发生在工具执行环节。
这些优点的价值在项目初期尤其明显。我的建议是,做任何Agent都先硬编码把全流程跑通,哪怕规则写得难看,先把业务闭环验证了,再考虑优化工具选择策略。很多团队一上来就搞复杂的动态路由系统,业务还没跑通,先把基础设施建了一堆,最后发现需求跟预期差很远,全部推倒重来。先硬编码是一种战略耐心,不是技术退步。
硬编码真正的问题不在单点准确性,而在规模上去之后的组合爆炸和维护成本。也就是说,它在项目早期是功臣,在项目中期开始变成瓶颈,在项目后期如果不重构,就会成为事故温床。
2.3 硬编码的核心瓶颈:组合爆炸与上下文浪费
组合爆炸怎么理解?假设Agent有5个工具,每个工具平均有3种触发说法,那么规则表就得维护15条映射。如果工具变成10个,每种说法再叠加不同语气和场景,规则不是线性增长,而是接近指数级膨胀。更现实的是,工具描述本身也在不断更新,每新增一个工具,就要重新审查所有现有规则有没有冲突,这种维护工作很快就会占用团队大量时间。
第二个隐藏瓶颈是上下文浪费。很多用硬编码路由失败的团队,最后会陷入一种妥协方案:把所有工具的描述全部塞进系统Prompt,让模型自己看。工具少的时候还行,工具一多,Prompt里光工具说明就占了几千token,每次请求都把这些token烧一遍,既慢又贵,还干扰模型对核心任务的理解。这是从硬编码滑向“伪动态决策”的典型路径,看似聪明,实则把路由成本转嫁给了每次对话。
硬编码第三个瓶颈是低鲁棒性。用户表达千变万化,同一种需求可以有几十种说法,规则再全也总会漏。一旦漏匹配,Agent要么选了错误工具,要么不选工具直接告诉用户“我做不到”。这两种结果对体验都是毁灭性的。而且硬编码对输入的微小变化非常敏感,比如用户多加了一个语气词、换了一个标点,匹配逻辑就可能失效,这种问题在规则表里极难提前发现。
我做过的几次重构都印证了同一件事:硬编码始终是正确的起点,但别把它当成终点。团队应该在硬编码跑通业务的同时,规划好工具注册中心和数据埋点,为后续动态决策留下平滑迁移的通道。
3. 动态决策的三种主流实现路线
3.1 规则引擎与业务路由:动态调度但规则集中管理
很多团队听到“动态决策”就想着必上大模型,其实有一条性价比很高的中间路线:把规则从代码里搬出来,做成可配置的规则引擎,让路由逻辑在运行时动态计算。这仍然不是模型决策,但已经比传统硬编码灵活很多。
规则引擎的思路是把工具选择建模成一系列条件判断,条件包括用户输入的关键词、抽取的实体、当前对话轮次、用户画像、业务线、甚至环境变量。比如同一个“查天气”请求,面向北方用户和南方用户,Agent应该调用不同的气象数据源;同一个“查订单”请求,普通用户和管理员能查的范围完全不同。这些判断不能靠if/else堆在业务代码里,而应该用决策表或规则配置管理起来。
实际落地上,可以用轻量级的规则引擎如Drools,也可以自己写一个决策表框架,把条件列成一行行规则,运行时逐条匹配、按优先级合并。这个方案的优点是延迟低、可控性强、改动快,产品经理都能参与维护。缺点是仍然依赖专家人工梳理规则,对于语言多样性极高的任务,规则还是会漏。
所以我的判断是:规则引擎适合作为动态决策体系里的“前置通道”,也就是优先处理高确定性任务。凡是历史数据里能覆盖80%的标准表达,全部用规则通道处理,只有规则通道匹配置信度不够时,才把请求交给更重的语义通道或模型裁决通道。这个分层思想很关键,它既保证了大部分请求的低延迟,又给复杂任务留了智能兜底。
3.2 向量检索与语义路由:Embedding加相似度的做法
语义路由是当前性价比最高、最值得优先投入的动态决策方案。它的原理和RAG检索非常像:先把每个工具的描述、典型使用场景、输入输出示例转换成向量,存储成工具索引;用户请求到达时,把请求文本也做向量化,然后计算它跟所有工具向量的相似度,按分数排序取TopK作为候选工具。
我经常用这个例子跟团队解释:工具描述写得越像“给朋友推荐工具”,语义路由效果越好。比如一个工具的描述是“根据自然语言查询生成SQL并返回数据表结构和采样数据”,向量化之后,用户说“帮我看看库表里有没有销售额字段”,语义相似度就会很高;而用户说“帮我画个柱状图”,这个工具的描述里完全没有画图语义,分数自然就低。这种“语义匹配”能力是关键词规则完全不具备的。
语义路由的关键参数有三个:Embedding模型的选择、相似度阈值的设置、TopK候选数的大小。Embedding模型建议用跟其他语义检索模块统一的模型,方便复用和缓存。阈值方面,一开始可以把阈值调高一点,比如0.75以上才算强匹配,低于这个分数就进入备选池或走模型裁决,避免“矮子里拔将军”。TopK候选数通常设在3到5个,既不会漏掉正确工具,也不会把太多无关工具交给下游决策。
要注意的是,语义路由不是万能的。工具描述写得含糊时,向量区分度会急剧下降;多个工具语义相近时,TopK里的排序稳定性也不够。所以语义路由更适合做“粗筛”,精确的最终裁决有时候还是需要模型来拍板。但即便如此,它能极大减少模型裁决需要处理的候选数量,把一次“从20个工具里选一个”的高难度任务,降级成“从4个候选里选一个”的简单任务,这对准确率和token成本都是巨大改善。
3.3 让模型自己做选择题:LLM自适应选择
把工具选择直接交给LLM,是这几年来Agent框架最常见的做法。OpenAI的Function Calling、各大Agent框架里的ReAct模式,本质上都是把“工具列表+当前上下文”交给模型,让模型自己判断该调哪个工具,同时输出规范化的参数。
这种方案的优势很明显:语义理解能力强,能处理复杂的隐含意图和模糊表达,并且天然支持参数提取,模型会在选择工具的同时把工具需要的参数也生成好。它尤其适合那些“规则说不清、语义也难区分”的场景,比如用户说“帮我安排一下明天上午和供应商开会,顺便把上次那个方案附件带上”,这里涉及到日历工具、邮件工具、文件检索工具的选择和组合,纯规则根本hold不住。
但LLM自选的路子也有显而易见的成本。每次工具选择都要一次模型调用,延迟从毫秒级上升到几百毫秒甚至秒级,token开销也肉眼可见。而且模型并不是每次都听话,它会选错工具、会幻觉出不存在的工具名、会把参数格式写错。更麻烦的是,模型的选择结果有随机性,相同请求在不同轮次可能选出不同工具,这在生产环境里会直接导致服务行为不一致,用户会觉得Agent“抽风”。
我的建议是,把模型自选放在语义路由之后作为“精排层”。先让规则通道和语义通道把候选压缩到三五个,再把候选工具的完整描述和用户原话一起交给模型,让它做最后的裁决并提取参数。这样既保留了模型的智能优势,又把成本和随机性控制在了极小范围内。如果业务允许,还可以对高确定性请求绕过模型裁决,只用规则通道就返回结果,进一步降低平均延迟。
三条路线各有适用场景,我把核心差异整理成了对比表:
| 方案 | 延迟 | 成本 | 语义理解 | 可控性 | 适用场景 |
|---|---|---|---|---|---|
| 规则引擎 | 极低 | 极低 | 弱 | 高 | 标准化表达、高频场景 |
| 语义路由 | 中低 | 低 | 中强 | 中 | 工具数量多、表达变化大 |
| 模型自选 | 高 | 高 | 强 | 中低 | 复杂推理、多工具组合选择 |
4. 实战:设计一个可落地的动态工具选择模块
4.1 基础架构:工具注册中心
要真正把动态决策落地,第一步不是写路由逻辑,而是建一个工具注册中心。它的作用是把所有工具的信息统一收编,包括名称、描述、使用场景、参数定义、权限要求、调用统计和运行状态,让路由层可以基于这些元数据做决策。
工具注册中心的数据结构,基于常见实践可以设计成这样:
from dataclasses import dataclass, field from enum import Enum from typing import Callable, Any class ToolStatus(Enum): ACTIVE = "active" DEGRADED = "degraded" DISABLED = "disabled" @dataclass class ToolSpec: name: str description: str use_cases: list[str] examples: list[str] tags: list[str] required_scopes: list[str] timeout_ms: int = 5000 status: ToolStatus = ToolStatus.ACTIVE metadata: dict = field(default_factory=dict) def is_usable(self) -> bool: return self.status == ToolStatus.ACTIVE @dataclass class ToolRecord: spec: ToolSpec invoker: Callable[[dict], Any]这里有几个容易被忽略的细节。第一,description要写“给模型看的功能说明”,use_cases和examples要写“给语义匹配用的具体场景”,两者不能混为一谈。很多团队只写一个description,语义路由时效果会很差,因为功能说明偏向抽象,缺少用户自然会说的表达。第二,required_scopes是权限声明,路由决策前必须先用它过滤掉当前会话无权访问的工具,否则动态决策会把Agent带进越权风险。第三,status字段支持动态启停工具,线上出问题时可以快速摘除故障工具,避免路由选到已崩溃的服务。
工具注册中心不仅服务路由,它也服务整个Agent平台的可观察性。每件工具的调用次数、平均延迟、成功率、失败原因都应该在这里统计沉淀,这些数据后续是优化路由权重、调整阈值、评估新工具价值的重要依据。
4.2 决策层:双通道路由
工具注册中心建好后,接着构建决策层。我的推荐方案是“规则前置加语义精排加模型兜底”的瀑布式结构,下面给出的代码是一个能直接落地的核心骨架。
from typing import Optional class ToolDecision: def __init__(self, tool_name: str, score: float, channel: str, reasoning: str): self.tool_name = tool_name self.score = score self.channel = channel self.reasoning = reasoning class DynamicRouter: def __init__(self, registry, rule_matcher, semantic_matcher, llm_adjudicator): self.registry = registry self.rule_matcher = rule_matcher self.semantic_matcher = semantic_matcher self.llm_adjudicator = llm_adjudicator def route(self, query: str, context: dict) -> Optional[ToolDecision]: usable_tools = self.registry.list_usable_tools( scopes=context.get("allowed_scopes", []) ) # 通道1:规则快速匹配 rule_match = self.rule_matcher.match(query, usable_tools) if rule_match and rule_match.score >= self.rule_matcher.accept_threshold: return ToolDecision( tool_name=rule_match.tool.name, score=rule_match.score, channel="rule", reasoning="规则通道高置信匹配" ) # 通道2:语义向量粗筛 semantic_matches = self.semantic_matcher.search( query, usable_tools, top_k=4 ) if not semantic_matches: return None # 通道3:LLM精排裁决 final_decision = self.llm_adjudicator.decide( query=query, candidates=semantic_matches, context=context ) return final_decision这个设计的巧妙之处在于每个通道做了自己最擅长的事。规则通道管高频确定性请求,速度快;语义通道管表达变化大的请求,把候选压缩到四个;LLM裁决只管最后的选择加参数提取。用户请求沿着瀑布从最快的通道开始尝试,只有拿不准时才逐步下放到更重的通道。
实际部署时,规则通道的accept_threshold要保守一点,建议定在0.9以上,宁愿多放一些请求到下游,也不要让规则误杀。语义通道的top_k不宜太大,三到五个比较划算。如果LLM裁决接口超时或返回格式异常,整个路由需要直接降级到语义通道排名第一的工具,保证核心业务不中断。
4.3 关键细节:参数构造、得分计算与降级兜底
路由选择的最终输出,不能只是一个工具名,还应该包含“调用这个工具需要的参数结构”。参数可以来自两个地方:规则和语义通道负责做简单参数提取,模型裁决通道负责做复杂参数补全。任何工具的调用参数必须经过一层参数校验器,防止模型生成多余参数或错误类型。
得分计算是动态决策里最讲究的部分。如果只有向量相似度一个指标,容易出现“相似但不正确”的误选。我建议综合三个维度的得分:规则命中得分、语义相似度得分、上下文场景得分。比如原任务是查天气,但对话历史里用户刚刚明确说过“我想去户外,需要看降水”,那么上下文场景得分就会提升天气降水类工具的权重。
综合得分可以进行加权计算:score = w1 * rule_score + w2 * semantic_score + w3 * context_score。初始权重可以按0.4、0.4、0.2去跑,之后通过线上日志和快照数据持续迭代调参。这里一个实用的小技巧是,不要把最终分数直接暴露给用户,但要把每个子分都记录在路由日志里,方便事后复盘为什么选了A没选B。
降级兜底策略不复杂,但必须提前设计。当所有通道都拿不准时,比起随便选一个工具硬跑,不如诚实地向用户澄清需求。我见过太多Agent在低置信度情况下胡乱调用,结果把线上数据搞坏,这比“不知道”的后果严重得多。降级时可以先尝试通用搜索工具去查资料,如果觉得自己理解不透,就要主动返问用户。Agent要勇敢承认“这条任务我不确定该怎么做”,这恰恰是可靠性的一部分。
还有一个容易忽略的环节,就是路由结果要支持人工干预和动态修正。生产环境里会经常发现某个工具被路由系统错误地无视了,这时候不应该去改模型,而应该通过工具注册中心提升该工具的use_cases覆盖率、增加规则通道中的触发点,甚至临时配置一个覆盖规则,强制高优场景走某工具。这需要在架构上留好“覆盖机制”,没有覆盖机制,动态决策就永远是闭门造车。
5. 稳定性、并发与安全的几个坑
5.1 并发场景下路由会变成瓶颈吗
动态决策引入语义路由和模型裁决之后,给Agent增加的不只是智能,还有明显的IO开销。很多人问“AI Agent怎么扛并发”,我的经验是先看路由层有没有变成单点瓶颈。规则通道是纯内存计算,可以轻松横向扩展;语义通道依赖Embedding模型服务,必须做结果缓存;模型裁决通道最重,必须限制并发、设置超时、做流式响应。
路由层本身建议保持无状态设计,所有上下文都从请求体里带入,这样就能把它部署成多个Pod实例,前面挂负载均衡。向量检索的Embedding结果要按“用户请求文本的归一化形式”做缓存,避免相同或相似请求重复调用Embedding模型。模型裁决通道要单独做线程池和信号量控制,防止用户请求高峰把裁决服务打爆。
并发问题在实践里最痛的其实不是计算资源,而是超时干扰。如果模型裁决通道超时设为5秒,路由层就应该在3秒时主动降级,用语义通道Top1作为结果返回。否则上游请求会因为等待路由而整体超时,用户感知就是Agent卡住了。这个超时降级链路必须提前压测,不能等线上事故了才补。
5.2 动态决策快照:调试和评估的核心依据
动态决策最大的痛点之一是“不可复现”。同一个问题,今天路由选了A工具,明天可能选了B工具,没有记录的话,线上出了事故根本没法追溯。所以我强烈建议,路由层每一次决策都必须生成一条结构化快照,落盘到日志系统,这就是很多团队常说的“动态决策快照”。
一条完整快照应该包含这些字段:
| 字段 | 说明 |
|---|---|
| request_id | 关联用户请求和后续执行步骤 |
| query | 用户原始输入,脱敏后存储 |
| context_snapshot | 对话轮次、历史摘要、权限范围 |
| candidate_tools | 语义通道产出的TopK候选工具列表 |
| sub_scores | 每条候选的规则分、语义分、上下文分 |
| final_tool | 最终选定的工具名称 |
| channel_used | rule、semantic、llm中的哪条通道 |
| latency_ms | 路由决策耗时 |
| execution_status | 后续工具调用执行结果 |
有了快照之后,你可以做几件非常有价值的事:一是线上问题定位,用户投诉时直接调出快照,看路由到底在哪里发生了偏差;二是离线评估,拿一批标注好的测试集,定期回放快照,计算路由准确率的变化;三是权重调优,统计真实案例里哪个子分数产生了误导,针对性调整权重;四是安全审计,当Agent被质疑做了越权操作时,快照能证明路由是否遵守了权限过滤规则。
我见过不少团队一开始觉得快照会增加存储成本、拖慢链路,就一直拖着不做。结果工具一多、路由逻辑一复杂,问题定位全靠翻代码和猜。后来实在扛不住才补上快照体系,落地之后才发现,它对线上稳定性的价值不亚于监控告警。存储成本用异步上报完全能解决,千万别因为这个理由不做。
5.3 安全与合规边界:先权限过滤,再动态决策
动态决策给安全带来的挑战是,路由结果不再由固定的规则保证,而可能由模型“突发奇想”选出一个高风险工具。我在多个知乎热词里看到agent安全相关的问题被反复提及,现实中确实出现过Agent把删除接口当成查询接口调用的案例。
解决办法不是禁止动态决策,而是把安全边界前置到路由之前。用户请求进来后,先做权限审计,确认这个会话有没有访问某类工具的权利;工具注册中心里的每个工具都声明required_scopes,路由候选生成时就过滤掉无权项,让模型根本没有机会选择越权工具。这一步必须在路由的最前端完成,不能依赖模型自觉。
另外,所有工具调用应经过统一执行网关,网关层做三件事:校验参数schema、记录调用日志、拦截高危操作。对删除、写库、发消息这类敏感动作,无论路由怎么选,都强制走二次确认流程。这样就算动态决策偶尔抽风,高危操作也不会直接在无人监督的情况下执行。工具选择策略越动态,安全边界就越要静态、越要前置,这个原则不要搞反了。
6. 常见问题速查与排查思路
6.1 现场高频问题清单
把我在多个生产项目里踩过的坑整理成了一张速查表,基本覆盖了动态工具选择最常见的故障类型:
| 现象 | 可能原因 | 排查方法 | 解决建议 |
|---|---|---|---|
| 工具选错但语义接近 | 工具描述语义区分度不足 | 查看快照里的语义子分数 | 增加use_cases,优化description |
| 相同请求不同结果 | 模型裁决通道随机性 | 看快照channel_used是否走llm | 连续相同请求缓存裁决结果,或调低裁决使用比例 |
| 路由整体超时 | 模型裁决并发过高或Embedding过慢 | 看路由latency_ms统计数据 | 增加语义缓存、限制裁决并发、设置降级开关 |
| 模型编造工具名 | 工具列表塞得过多或格式不规范 | 看模型返回原始内容 | 精简候选数量,规范工具名枚举限制 |
| 新工具上线后没人选 | 新工具描述和示例太少 | 检查语义检索是否命中新工具 | 补充新工具高频表达,临时加规则通道覆盖 |
| 敏感操作被执行 | 权限过滤没放在路由最前端 | 查权限日志和请求scope | 强制前置权限过滤,高危操作二次确认 |
这些问题的共同点,绝大多数不是模型不够聪明,而是工具侧的元数据质量不够、路由层的记录不够、安全边界执行不够。做动态决策之后,花在优化工具描述和积累快照数据上的时间,比调模型本身有价值得多。
6.2 排查方法论:从日志到回放
动态路由的排查方法和传统代码完全不同。传统Bug可以直接本地复现,动态路由问题受模型随机性影响,很难稳定复现。我的方法论是三步走:第一步查快照,重现当时路由选择了什么工具、各个子分数是多少;第二步改元数据,根据快照暴露出的问题,优化工具描述、调整规则阈值、修正权重;第三步回放验证,把历史请求批量回放到新路由配置里,对比准确率和延迟指标,确认优化有效。
这一步“快照加回放”的闭环极其重要。没有回放,你就永远只能靠线上随机发现问题;没有快照,回放就没有数据支撑。所以前期花在快照和日志体系上的投入,会在后续每一次路由优化和事故排查中几十倍地赚回来。
再补充一个实战技巧:双跑对比。调整路由策略后,不要直接全量切换,先在影子环境里双跑旧策略和新策略,让两个版本同时接收请求,线上用户只走旧版本,新版本结果记录到日志。跑个几天看准确率差异,确认新版本确实更优再切换。这个办法能极大降低动态决策改动带来的线上风险。
结语
在搞Agent的这几年里,我越来越确信一件事:工具选择策略没有银弹,从硬编码到动态决策也不是一蹴而就的替代关系,而是一种循序渐进的演进。先把规则写死把业务跑通,再通过注册中心和快照体系沉淀数据,然后逐步引入语义路由、模型裁决,最后形成规则、语义、模型各司其职的瀑布式体系。这个过程中,动态决策快照是我个人觉得最值得投入的部分,因为每天线上排查、权重调优、安全审计都在靠它说话。
最后再分享一个小技巧:任何工具选择策略,都不要把所有候选工具一股脑塞进模型输入里去选。那个做法初看省事,实际会在工具数量超过十个之后,让token成本和决策错误率同时飙升。宁可多花一点精力在语义粗筛和候选压缩上,把最重的模型裁决留给少数真正模糊的选择。工具选择越克制,Agent才越可靠。