1. 为什么模型选型这件事,最后都变成了路由问题做过 Agent 项目的人大概都有过这么一个阶段:一开始兴致勃勃地对比各家模型,跑分、看榜单、测延迟、算成本,折腾了两周,最后在代码里写下了一个硬编码的模型名字。然后项目上线,需求一变,用户量一涨,或者某个场景的效果不达预期,你发现要改的不是一行配置,而是散落在十几个文件里的调用逻辑。这个坑我自己踩过不止一次。早期做对话类 Agent 的时候,所有请求都走同一个模型,简单问答和复杂推理用的是同一套参数,结果就是简单问题浪费算力,复杂问题效果又不够。后来想按场景分流,才发现代码里根本没有一个统一的入口来做这件事,每个调用点都是独立的,改起来像在拆炸弹。所以当我看到"Agent 模型怎么选"这个问题的时候,我的第一反应不是去比较哪个模型更强,而是——选型这件事本身,应该是一个运行时的决策,而不是一个开发时的硬编码。换句话说,模型选择的逻辑应该被抽象成一套路由规则,写进 Runtime 层,让它在请求进来的那一刻动态决定用哪个模型、走哪条链路、带什么参数。这篇文章想聊的就是这件事:怎么把模型选型从"拍脑袋定一个"变成"写一套规则让系统自己判断"。我会从路由规则的设计思路讲起,到具体的实现结构、参数计算、踩坑经验,尽量把一套可以直接抄作业的方案摊开来讲。不管你现在是在做对话 Agent、RAG 系统还是多模态处理流程,这套思路都能用得上。2. 路由规则到底在解决什么问题2.1 模型选型的三个现实约束在讨论怎么做路由之前,得先想清楚为什么要路由。我总结下来,实际项目里推动你做模型分流的,无非是三个约束。第一个是成本约束。不同模型的调用价格差距可能是几十倍。一个简单的意图识别、格式转换、关键词提取,用轻量模型完全够用,但如果你所有请求都走最强的那个模型,账单会教你做人。我见过一个项目,日均调用量在百万级别,全部走同一个模型,后来做了简单的分流——把其中约六成的简单请求切到轻量模型——成本直接降了一半以上,而用户侧几乎感知不到差异。第二个是能力约束。有些任务就是需要强推理能力,比如多步逻辑推导、复杂代码生成、长文档的深度分析。你用轻量模型去做,它可能连指令都理解不全,输出质量惨不忍睹。这时候不是省钱的问题,是能不能用的问题。第三个是延迟约束。实时对话场景对首字延迟非常敏感,用户等两秒和等五秒的体验完全不同。有些强模型的推理链路长,延迟天然就高,你不可能让所有请求都等它。而一些轻量模型响应快,适合做前置的快速响应,或者处理对实时性要求高的交互。这三个约束往往是同时存在的,而且互相冲突。你想要效果好,成本就高、延迟就大;你想要便宜快,效果就可能打折。路由规则的本质,就是在这三个维度之间找到一个动态的平衡点,针对每一个具体请求做出最合适的取舍。2.2 硬编码选型为什么一定会崩很多人一开始的做法是在代码里写死。比如对话主流程用模型 A,摘要用模型 B,翻译用模型 C。这在项目初期没问题,因为场景少、变化慢。但一旦出现下面这几种情况,硬编码就会变成灾难。场景边界模糊的时候。比如用户的一个请求里既有问答又有摘要需求,你按哪个场景走?硬编码没法处理这种混合意图。模型迭代的时候。今天模型 A 是最优解,三个月后可能模型 D 在同样的价格下效果更好。你要换,就得把所有写死的地方找出来改一遍,漏一个就出问题。流量波动的时候。高峰期你想把一部分请求降级到轻量模型来保吞吐,低峰期想全部走强模型来保质量。硬编码做不到这种动态调整。多租户或者多业务线的时候。不同客户对成本、质量的敏感度不一样,有的愿意为效果付费,有的只求便宜能用。你不可能为每个客户维护一套硬编码。所以路由规则要解决的问题,本质上是把"选哪个模型"这个决策从代码逻辑里抽出来,变成一个可配置、可动态调整、可针对单个请求做判断的独立层。这个层放在 Runtime 里,所有模型调用都经过它,改规则不用动业务代码。2.3 路由层应该放在哪个位置这里有个架构上的选择:路由逻辑是放在业务代码里,还是放在一个独立的中间层?放在业务代码里的好处是灵活,每个调用点可以根据自己的上下文做最精细的判断。坏处是分散,规则不统一,改起来麻烦,而且容易写出互相矛盾的逻辑。放在独立中间层的好处是统一管理,所有请求走同一个入口,规则集中,可观测性好。坏处是需要设计一套足够通用的规则表达方式,而且中间层本身不能成为瓶颈。我的建议是混合方案:核心的路由决策放在一个独立的 Runtime 组件里,但允许业务层传入足够的上下文信息(比如任务类型、优先级、预算约束、延迟要求)来影响决策。这样既保证了规则的统一性,又保留了针对具体场景微调的空间。具体来说,这个 Runtime 组件应该是一个函数或者服务,输入是请求的元信息,输出是一个路由决策,包含用哪个模型、带什么参数、走什么链路、超时和重试策略是什么。业务代码只负责组装元信息,不负责做决策。3. 路由规则的核心维度拆解3.1 任务类型:最基础的分类维度任务类型是最直观也最常用的路由维度。不同的任务对模型能力的要求差异很大,按任务类型分流是最容易见效的。我一般会把任务分成这么几类。轻量理解类,包括意图识别、情感判断、关键词提取、简单分类,这类任务用最小的模型就能做,甚至一些专门的小模型效果比通用大模型还好。生成类,包括文案撰写、摘要、翻译、格式转换,这类任务对语言能力要求中等,中档模型通常够用。推理类,包括逻辑推导、数学计算、代码生成、多步规划,这类必须用强模型,省不得。多模态类,涉及图像理解、文档解析的,得看具体模型的多模态能力。在实际的路由规则里,任务类型通常不是业务层直接传进来的,而是通过一个轻量的前置分类器判断出来的。这个分类器本身也可以用最小的模型来做,成本可以忽略不计。我试过用一个几百毫秒延迟的小模型做前置分类,整体链路增加的开销很小,但分流带来的成本节省非常可观。注意:前置分类器不要做得太复杂。它的目标是粗分类,不是精确理解。分类粒度太细反而会增加错误率,导致路由决策失误。我一般控制在四到六类,够用就行。3.2 复杂度评估:让规则更精细光靠任务类型还不够,因为同一个任务类型内部的复杂度差异也很大。比如同样是摘要,摘要一段话和摘要一份几十页的文档,需要的模型能力完全不同。复杂度评估可以从几个信号入手。输入长度是最直接的信号,token 数越多,通常意味着信息量越大,对模型的处理能力要求越高。输入的结构化程度也很关键,结构清晰的输入(比如表格、列表)比大段自由文本更容易处理。历史交互轮次在对话场景里很重要,多轮对话需要模型维持上下文一致性,对能力要求更高。是否包含专业领域内容,涉及代码、数学、法律、医学等专业内容的,通常需要更强的模型。这些信号可以组合成一个复杂度分数,然后根据分数区间来决定路由。比如设定三个档位:低复杂度走轻量模型,中复杂度走中档模型,高复杂度走强模型。每个档位的阈值需要根据实际数据调,没有万能公式。我自己的经验是,先用一个粗略的规则跑一段时间,收集实际的路由决策和最终效果数据,然后根据数据反过来调整阈值。这个过程通常需要迭代两三轮才能稳定下来。3.3 成本预算:把经济账算进规则里成本约束是路由规则里最实际的一个维度,但也是最容易被忽略的。很多团队做路由只考虑效果,不考虑成本,结果分流做了半天,账单没降多少。成本预算应该怎么进规则?我的做法是给每个请求打一个预算标签,然后路由决策在满足效果要求的前提下,优先选择成本最低的模型。预算标签可以来自几个地方。业务层指定,比如某个客户明确要求控制成本,那他的请求就带低成本标签。动态计算,根据当前时间段的整体消耗情况,如果已经接近预算上限,后续请求自动降级。优先级判断,高优先级的请求不设成本限制,低优先级的请求优先走便宜模型。这里有个细节:成本不只是模型调用的单价,还包括重试、失败重跑、人工介入的成本。一个便宜但经常失败的模型,综合成本可能比一个贵但稳定的模型更高。所以路由规则里要考虑模型的稳定性指标,不能只看单价。3.4 延迟要求:实时场景的硬约束延迟要求在很多场景下是一票否决的。用户在前端等着回复,你路由到一个延迟五秒的模型,效果再好也没用。延迟约束的处理方式有两种。一种是硬约束,超过延迟阈值的模型直接排除在候选之外。另一种是软约束,延迟作为一个权重因子参与打分,延迟高的模型分数低,但不是完全不能用。我一般对实时交互场景用硬约束,对后台批处理场景用软约束。实时场景下,我会先根据延迟要求筛掉一批模型,然后在剩下的里面按效果和成本选。后台场景下,延迟不那么敏感,可以更侧重效果和成本。延迟的评估不能只看模型的平均响应时间,要看 P95 甚至 P99。平均值好看但长尾严重的模型,在实时场景下会带来很差的体验。我一般会维护一个模型延迟的滚动统计,路由时参考最近的 P95 数据。3.5 多维度打分:把规则统一成一个决策函数上面这些维度单独看都简单,但组合起来就复杂了。我的做法是设计一个统一的路由决策函数,把各个维度转成分数,加权求和,选总分最高的模型。这个函数大概长这样:对每个候选模型,计算它在效果、成本、延迟三个维度的得分,然后按权重加权。效果得分来自模型在对应任务类型上的历史表现,成本得分来自单价和预估 token 数,延迟得分来自历史 P95 数据。权重根据场景调整,实时场景延迟权重大,成本敏感场景成本权重大。这个方案的好处是可解释、可调整。每个决策都能追溯到是哪个维度起了决定性作用,调参也有明确的方向。坏处是需要维护每个模型在每个任务类型上的表现数据,前期投入比较大。如果项目初期数据不够,可以先简化成规则匹配:if 任务类型是推理 and 延迟要求低,then 用强模型;elif 成本敏感,then 用轻量模型。等数据积累起来再过渡到打分模型。4. 把路由规则写进 Runtime 的具体实现4.1 Runtime 的接口设计Runtime 的接口设计决定了这套方案好不好用。我的经验是,接口要足够简单,让业务层容易接入,同时要足够灵活,能表达各种路由需求。一个典型的接口大概是这样:业务层调用一个route方法,传入请求的元信息,包括任务描述、输入内容、优先级、预算约束、延迟要求等。Runtime 返回一个路由决策,包含模型标识、调用参数、超时设置、重试策略。class RouteRequest: task_hint: str # 业务层对任务的粗略描述 input_text: str # 实际输入内容 priority: str # high / normal / low budget_level: str # strict / normal / unlimited latency_budget_ms: int # 可接受的延迟上限 metadata: dict # 其他上下文信息 class RouteDecision: model_id: str params: dict # temperature, max_tokens 等 timeout_ms: int retry_policy: dict fallback_model: str # 主模型失败时的备选这个接口的关键点是,业务层只提供信息,不做决策。决策逻辑全部在 Runtime 内部。这样业务代码保持干净,路由规则的调整不影响业务逻辑。4.2 规则配置的结构路由规则本身应该是可配置的,而不是写死在代码里。我一般用 YAML 或者 JSON 来定义规则,Runtime 启动时加载,支持热更新。规则的结构大概分三层。第一层是匹配条件,定义这条规则适用于什么样的请求,比如任务类型、优先级、输入长度范围等。第二层是候选模型列表,列出满足条件时可以选择的模型。第三层是选择策略,定义在候选模型里怎么选,是按成本最低、延迟最低还是综合打分。rules: - name: "simple_intent" match: task_type: "intent" input_length: "< 500" candidates: ["model-light-a", "model-light-b"] strategy: "cost_first" fallback: "model-mid-a" - name: "complex_reasoning" match: task_type: "reasoning" priority: "high" candidates: ["model-strong-a", "model-strong-b"] strategy: "quality_first" fallback: "model-mid-b"这种配置方式的好处是,调整路由策略不需要改代码,改配置就行。而且规则之间的优先级、覆盖关系一目了然,不容易出现逻辑冲突。4.3 前置分类器的实现细节前置分类器是路由链路的第一环,它的准确率直接影响后续所有决策。我的做法是用一个轻量模型做分类,输入是用户的原始请求,输出是任务类型标签。分类器的 prompt 设计很关键。我一般会给它几个明确的类别定义,让它做单选。类别不要太多,四到六个比较合适。prompt 里要包含几个典型例子,帮助模型理解边界。CLASSIFIER_PROMPT = """ 判断以下请求属于哪个类别,只输出类别名称: - intent: 意图识别、分类、判断 - generate: 文案生成、摘要、翻译、改写 - reasoning: 逻辑推理、计算、代码、规划 - multimodal: 涉及图像、文档解析 - other: 无法归入以上类别 请求:{input_text} 类别: """分类器的输出要做校验,如果输出了不在预定义类别里的内容,就归到 other,走默认路由。这个兜底逻辑很重要,否则分类器出错会导致整个路由链路异常。分类器的延迟要控制在可接受范围内。我实测下来,用轻量模型做分类,延迟通常在几百毫秒以内,对整体链路的影响很小。如果对延迟极度敏感,可以考虑用更小的专用分类模型,或者用规则做初步筛选,只对不确定的请求调用模型分类。4.4 复杂度评估的量化方法复杂度评估需要把定性判断转成定量分数。我的做法是定义几个信号,每个信号给一个分数,加权求和。输入长度信号:按 token 数分档,比如小于 200 给 1 分,200 到 1000 给 2 分,1000 到 5000 给 3 分,大于 5000 给 4 分。结构信号:结构化输入(JSON、表格、列表)给低分,自由文本给高分。因为结构化输入更容易处理,对模型能力要求低。专业度信号:包含代码、数学公式、专业术语的给高分。这个可以用关键词匹配做初步判断,不需要模型。轮次信号:对话场景下,历史轮次越多给分越高。单轮给 1 分,三到五轮给 2 分,五轮以上给 3 分。把这几个信号加权求和,得到一个复杂度总分,然后按阈值分档。权重的设定需要根据实际数据调,我一般先给长度和结构各 0.3,专业度和轮次各 0.2,跑一段时间再调。提示:复杂度评估不需要非常精确,它的作用是区分"明显简单"和"明显复杂"的请求,中间地带的误判影响不大。不要为了追求精确而把评估逻辑做得过于复杂。4.5 降级与兜底策略路由规则再完善,也会有判断失误的时候。所以降级和兜底策略是必须的。主模型调用失败时,自动切到 fallback 模型。fallback 模型的选择要考虑两点:一是它得能处理这个任务,二是它的可用性要高于主模型。我一般选一个能力稍弱但更稳定的模型做 fallback。主模型输出质量不达标时,也要有降级机制。怎么判断质量不达标?可以用一些启发式规则,比如输出为空、输出格式不符合要求、输出明显偏离主题。检测到这些情况,自动重试或者切到更强的模型。整体链路超时时,要有快速失败机制。不能让用户一直等着。设置一个总超时,超过就直接返回兜底结果或者错误提示。预算耗尽时,自动降级到低成本模型。这个在预算敏感的场景下很重要,避免月底账单爆炸。这些兜底策略要写在 Runtime 里,而不是业务层。业务层不需要关心这些细节,它只管调用,Runtime 保证尽可能返回一个合理的结果。5. 实操中的参数计算与调优5.1 成本预估的计算方法路由决策要算成本,就得预估每个候选模型的调用成本。成本等于输入 token 数乘以输入单价,加上输出 token 数乘以输出单价。输入 token 数可以从请求内容直接算出来,用 tokenizer 数一下就行。输出 token 数不好预估,因为模型输出长度不确定。我的做法是用历史数据估算,对每个任务类型统计平均输出长度,作为预估依据。def estimate_cost(model, input_tokens, task_type): avg_output = OUTPUT_LENGTH_STATS[task_type] input_cost = input_tokens * model.input_price output_cost = avg_output * model.output_price return input_cost + output_cost这个预估不需要很精确,因为路由决策是相对比较,不是绝对计算。只要预估方法对所有候选模型一致,比较结果就是有意义的。有个细节要注意:不同模型的 tokenizer 不一样,同样的文本在不同模型下的 token 数可能不同。严格来说应该用每个模型自己的 tokenizer 来算,但这样开销太大。我的做法是用一个统一的近似方法,比如按字符数除以一个系数,误差在可接受范围内。5.2 延迟阈值的设定延迟阈值怎么定?我的经验是从用户体验倒推。用户能接受的等待时间通常在两到三秒,超过这个时间就会觉得慢。所以端到端的延迟预算大概是两秒,扣掉网络传输、前后处理的时间,留给模型的时间可能只有一秒到一秒五。然后看候选模型的 P95 延迟。如果某个模型的 P95 超过这个预算,就排除掉。如果所有模型都超,那就得考虑降低要求,或者优化链路其他环节。延迟阈值不是固定的,不同场景可以不同。实时对话场景阈值低,后台处理场景阈值高。我一般会为每个场景单独配置延迟预算,而不是全局一个值。5.3 权重调优的实操步骤多维度打分的权重调优是个迭代过程。我的做法分三步。第一步,初始化权重。根据业务目标给一个初始值。如果当前最痛的是成本,成本权重给高一点;如果最痛的是效果,效果权重给高一点。初始值不用太精确,先跑起来。第二步,收集数据。跑一段时间,记录每次路由决策的输入、决策结果、最终效果。效果可以用人工评估或者自动指标来衡量。第三步,分析调整。看哪些决策是"错误"的,比如本该走强模型的走了弱模型导致效果差,或者本该走弱模型的走了强模型浪费成本。根据这些错误调整权重。这个过程通常需要两到三轮才能稳定。不要指望一次调好,也不要频繁调整,每次调整后至少跑几天收集足够数据再调下一次。5.4 灰度发布与 A/B 测试路由规则变更是有风险的,可能影响线上效果。所以变更要走灰度发布。我的做法是新的路由规则先在小比例流量上生效,比如百分之五。对比新规则和旧规则在这部分流量上的效果指标,包括成本、延迟、质量。如果新规则明显更好,逐步扩大比例;如果更差,回滚。A/B 测试的关键是定义好评判指标。成本看单位请求的平均花费,延迟看 P95,质量看人工评估或者自动指标。三个指标要综合看,不能只看一个。有时候成本降了但质量也降了,这种变更要不要上,取决于业务对质量和成本的权衡。注意:灰度期间要保证分流是随机的,不能按用户 ID 或者其他有偏的方式分,否则对比结果不可信。我一般用请求 ID 的哈希来做分流,保证随机性。6. 常见问题与排查技巧实录6.1 路由决策不符合预期怎么办这是最常见的问题。你期望某个请求走强模型,结果走了弱模型,效果不好。排查思路是这样的。先看分类结果,确认前置分类器把请求分到了哪个类别。如果分类错了,问题在分类器,需要调整 prompt 或者补充训练数据。再看复杂度评分,确认评分是否符合预期。如果评分偏低,检查各个信号的权重和阈值。最后看候选模型列表和选择策略,确认在给定条件下,决策逻辑是否正确地选出了预期模型。我遇到过一次,分类器把代码生成请求分到了 generate 类别,导致走了中档模型,代码质量很差。后来在分类器的 prompt 里加了代码相关的例子,问题就解决了。6.2 成本没有明显下降做了路由分流,但账单没降多少,这种情况通常是几个原因。分流比例太低。大部分请求还是走了强模型,只有少量走了弱模型。检查一下分类结果分布,看看是不是分类器把太多请求分到了复杂类别。弱模型的输出太长。弱模型虽然单价低,但如果输出 token 数远多于强模型,总成本可能差不多。检查一下各模型的平均输出长度。重试和失败太多。弱模型失败率高,重试带来的额外调用抵消了成本节省。检查各模型的失败率和重试率。成本计算没算全。只算了模型调用成本,没算前置分类器、后处理等环节的成本。把这些都算进去再看。6.3 延迟波动大延迟波动通常来自几个地方。模型本身延迟不稳定,某些时段负载高,响应慢。路由决策耗时,如果决策逻辑复杂,本身就会增加延迟。重试和降级,失败重试会显著增加延迟。排查方法是给链路各环节打点,看时间花在哪里。如果是模型延迟问题,考虑换更稳定的模型或者做多模型负载均衡。如果是决策耗时问题,优化决策逻辑,把能缓存的缓存起来。如果是重试问题,调整重试策略,减少不必要的重试。6.4 常见问题速查表问题现象可能原因排查方向解决思路路由决策不符合预期分类错误或评分偏差检查分类结果和复杂度评分调整分类 prompt 或评分权重成本没下降分流比例低或重试多看分类分布和失败率调整分类阈值或换更稳定的模型延迟波动大模型不稳定或决策耗时链路各环节打点换模型或优化决策逻辑质量下降弱模型能力不足对比各模型输出质量调整路由规则,复杂请求走强模型规则冲突多条规则匹配同一请求检查规则优先级明确规则优先级或合并规则6.5 几个踩过的坑坑一:分类器过度自信。早期我用分类器的时候,没有设置置信度阈值,分类器输出什么就用什么。结果有些边界请求被分错,效果很差。后来加了置信度判断,低置信度的请求走默认路由或者人工兜底,问题少了很多。坑二:忽略冷启动。新模型刚接入的时候,历史数据不足,延迟和效果数据都不准。这时候如果直接按数据路由,可能会做出错误决策。我的做法是新模型先跑一段时间的影子流量,收集数据,等数据够了再纳入路由候选。坑三:规则太多难维护。一开始觉得规则越多越精细,后来发现规则之间互相冲突,排查问题很痛苦。现在我会控制规则数量,能合并的合并,能用参数表达的不用新规则。坑四:忘了监控。路由规则上线后没有监控,出了问题不知道。现在我会给每个路由决策打点,记录决策依据和结果,定期 review,发现问题及时调整。7. 路由规则的扩展与演进7.1 从规则匹配到学习型路由规则匹配的路由在项目初期够用,但随着场景增多、模型增多,手工维护规则的成本会越来越高。这时候可以考虑引入学习型路由。学习型路由的思路是,用历史数据训练一个模型,输入是请求特征,输出是最优模型选择。训练数据来自历史的路由决策和效果反馈。这个模型可以是一个简单的分类器,也可以是一个更复杂的决策模型。学习型路由的好处是能自动发现规则难以表达的复杂模式,而且随着数据积累会越来越准。坏处是需要足够的数据,而且模型本身的可解释性差,出问题不好排查。我的建议是,规则匹配和学习型路由结合使用。规则处理明确的、高频的场景,学习型路由处理模糊的、长尾的场景。两者互补,效果比单用任何一种都好。7.2 多模型协同的路由有些任务不是单个模型能搞定的,需要多个模型协同。比如一个复杂任务,先用一个模型做规划,再用另一个模型执行,最后用第三个模型做校验。这种场景下,路由不只是选一个模型,而是编排一条模型调用链路。这种编排式的路由,规则会更复杂,需要考虑模型之间的依赖关系、数据传递、失败处理。我的做法是把编排逻辑也抽象成配置,用类似工作流的方式定义,Runtime 负责按配置执行。7.3 路由规则的可观测性建设路由规则上线后,可观测性是保证它持续有效的基础。我一般会建设这几个方面的观测能力。决策日志,记录每次路由的输入、决策结果、决策依据。效果指标,跟踪每个模型在每个任务类型上的效果、成本、延迟。异常告警,当路由决策异常(比如某个模型突然大量失败)时及时告警。定期报告,每周或每月生成路由效果报告,review 规则的有效性。这些观测数据不仅能帮你发现问题,还能为规则调优提供依据。没有观测数据,调优就是盲调。7.4 一个实际项目的演进过程我参与过一个对话 Agent 项目,路由规则的演进大概经历了三个阶段。第一阶段,硬编码。所有请求走同一个模型,简单粗暴。问题是用量上来后成本高,而且简单请求响应慢。第二阶段,规则路由。引入前置分类器,按任务类型分流。简单请求走轻量模型,复杂请求走强模型。成本降了约四成,延迟也有改善。问题是规则越来越多,维护成本上升。第三阶段,打分路由。把规则匹配改成多维度打分,效果、成本、延迟综合评估。规则数量减少,决策更灵活。同时引入学习型路由处理长尾场景。这个阶段成本又降了一些,效果也更稳定。这个演进过程不是一蹴而就的,每个阶段都是被实际问题推动的。我的体会是,不要一开始就追求完美的路由方案,先解决最痛的问题,然后随着项目发展逐步演进。8. 一些实操建议如果你正准备给自己的 Agent 项目加路由,我有几个建议。先从最简单的规则开始。不要一上来就搞多维度打分,先用任务类型做粗分流,跑起来看效果。有了数据再精细化。把决策逻辑和业务逻辑分开。路由决策放在独立的 Runtime 组件里,业务代码只负责组装请求信息。这样后续调整路由规则不影响业务代码。重视前置分类器。分类器的准确率直接决定路由效果。花时间优化分类器的 prompt,补充边界案例,比优化后面的决策逻辑收益更大。建立观测体系。从第一天就记录路由决策和效果数据。没有数据,后续调优无从下手。灰度发布,小步快跑。路由规则变更走灰度,小比例验证后再扩大。不要一次性全量切换,风险太大。定期 review 规则。业务在变,模型在变,路由规则也要跟着变。定期 review 规则的适用性,该删的删,该改的改。不要过度优化。路由的目标是找到性价比合适的方案,不是找到理论最优。80 分的路由方案加上好的观测和迭代,比 90 分的方案但没法维护要好得多。我在实际项目里的体会是,路由这件事的价值不在于用了多复杂的算法,而在于把模型选型从一个拍脑袋的决策变成了一个可管理、可迭代的系统能力。一开始可能只是几条简单的 if-else,但只要结构对了,后续的演进就是水到渠成的事。最怕的是一开始就写死在业务代码里,等到想改的时候发现牵一发动全身,那就被动了。
1. 为什么模型选型这件事,最后都变成了路由问题做过 Agent 项目的人大概都有过这么一个阶段:一开始兴致勃勃地对比各家模型,跑分、看榜单、测延迟、算成本,折腾了两周,最后在代码里写下了一个硬编码的模型名字。然后项目上线,需求一变,用户量一涨,或者某个场景的效果不达预期,你发现要改的不是一行配置,而是散落在十几个文件里的调用逻辑。这个坑我自己踩过不止一次。早期做对话类 Agent 的时候,所有请求都走同一个模型,简单问答和复杂推理用的是同一套参数,结果就是简单问题浪费算力,复杂问题效果又不够。后来想按场景分流,才发现代码里根本没有一个统一的入口来做这件事,每个调用点都是独立的,改起来像在拆炸弹。所以当我看到"Agent 模型怎么选"这个问题的时候,我的第一反应不是去比较哪个模型更强,而是——选型这件事本身,应该是一个运行时的决策,而不是一个开发时的硬编码。换句话说,模型选择的逻辑应该被抽象成一套路由规则,写进 Runtime 层,让它在请求进来的那一刻动态决定用哪个模型、走哪条链路、带什么参数。这篇文章想聊的就是这件事:怎么把模型选型从"拍脑袋定一个"变成"写一套规则让系统自己判断"。我会从路由规则的设计思路讲起,到具体的实现结构、参数计算、踩坑经验,尽量把一套可以直接抄作业的方案摊开来讲。不管你现在是在做对话 Agent、RAG 系统还是多模态处理流程,这套思路都能用得上。2. 路由规则到底在解决什么问题2.1 模型选型的三个现实约束在讨论怎么做路由之前,得先想清楚为什么要路由。我总结下来,实际项目里推动你做模型分流的,无非是三个约束。第一个是成本约束。不同模型的调用价格差距可能是几十倍。一个简单的意图识别、格式转换、关键词提取,用轻量模型完全够用,但如果你所有请求都走最强的那个模型,账单会教你做人。我见过一个项目,日均调用量在百万级别,全部走同一个模型,后来做了简单的分流——把其中约六成的简单请求切到轻量模型——成本直接降了一半以上,而用户侧几乎感知不到差异。第二个是能力约束。有些任务就是需要强推理能力,比如多步逻辑推导、复杂代码生成、长文档的深度分析。你用轻量模型去做,它可能连指令都理解不全,输出质量惨不忍睹。这时候不是省钱的问题,是能不能用的问题。第三个是延迟约束。实时对话场景对首字延迟非常敏感,用户等两秒和等五秒的体验完全不同。有些强模型的推理链路长,延迟天然就高,你不可能让所有请求都等它。而一些轻量模型响应快,适合做前置的快速响应,或者处理对实时性要求高的交互。这三个约束往往是同时存在的,而且互相冲突。你想要效果好,成本就高、延迟就大;你想要便宜快,效果就可能打折。路由规则的本质,就是在这三个维度之间找到一个动态的平衡点,针对每一个具体请求做出最合适的取舍。2.2 硬编码选型为什么一定会崩很多人一开始的做法是在代码里写死。比如对话主流程用模型 A,摘要用模型 B,翻译用模型 C。这在项目初期没问题,因为场景少、变化慢。但一旦出现下面这几种情况,硬编码就会变成灾难。场景边界模糊的时候。比如用户的一个请求里既有问答又有摘要需求,你按哪个场景走?硬编码没法处理这种混合意图。模型迭代的时候。今天模型 A 是最优解,三个月后可能模型 D 在同样的价格下效果更好。你要换,就得把所有写死的地方找出来改一遍,漏一个就出问题。流量波动的时候。高峰期你想把一部分请求降级到轻量模型来保吞吐,低峰期想全部走强模型来保质量。硬编码做不到这种动态调整。多租户或者多业务线的时候。不同客户对成本、质量的敏感度不一样,有的愿意为效果付费,有的只求便宜能用。你不可能为每个客户维护一套硬编码。所以路由规则要解决的问题,本质上是把"选哪个模型"这个决策从代码逻辑里抽出来,变成一个可配置、可动态调整、可针对单个请求做判断的独立层。这个层放在 Runtime 里,所有模型调用都经过它,改规则不用动业务代码。2.3 路由层应该放在哪个位置这里有个架构上的选择:路由逻辑是放在业务代码里,还是放在一个独立的中间层?放在业务代码里的好处是灵活,每个调用点可以根据自己的上下文做最精细的判断。坏处是分散,规则不统一,改起来麻烦,而且容易写出互相矛盾的逻辑。放在独立中间层的好处是统一管理,所有请求走同一个入口,规则集中,可观测性好。坏处是需要设计一套足够通用的规则表达方式,而且中间层本身不能成为瓶颈。我的建议是混合方案:核心的路由决策放在一个独立的 Runtime 组件里,但允许业务层传入足够的上下文信息(比如任务类型、优先级、预算约束、延迟要求)来影响决策。这样既保证了规则的统一性,又保留了针对具体场景微调的空间。具体来说,这个 Runtime 组件应该是一个函数或者服务,输入是请求的元信息,输出是一个路由决策,包含用哪个模型、带什么参数、走什么链路、超时和重试策略是什么。业务代码只负责组装元信息,不负责做决策。3. 路由规则的核心维度拆解3.1 任务类型:最基础的分类维度任务类型是最直观也最常用的路由维度。不同的任务对模型能力的要求差异很大,按任务类型分流是最容易见效的。我一般会把任务分成这么几类。轻量理解类,包括意图识别、情感判断、关键词提取、简单分类,这类任务用最小的模型就能做,甚至一些专门的小模型效果比通用大模型还好。生成类,包括文案撰写、摘要、翻译、格式转换,这类任务对语言能力要求中等,中档模型通常够用。推理类,包括逻辑推导、数学计算、代码生成、多步规划,这类必须用强模型,省不得。多模态类,涉及图像理解、文档解析的,得看具体模型的多模态能力。在实际的路由规则里,任务类型通常不是业务层直接传进来的,而是通过一个轻量的前置分类器判断出来的。这个分类器本身也可以用最小的模型来做,成本可以忽略不计。我试过用一个几百毫秒延迟的小模型做前置分类,整体链路增加的开销很小,但分流带来的成本节省非常可观。注意:前置分类器不要做得太复杂。它的目标是粗分类,不是精确理解。分类粒度太细反而会增加错误率,导致路由决策失误。我一般控制在四到六类,够用就行。3.2 复杂度评估:让规则更精细光靠任务类型还不够,因为同一个任务类型内部的复杂度差异也很大。比如同样是摘要,摘要一段话和摘要一份几十页的文档,需要的模型能力完全不同。复杂度评估可以从几个信号入手。输入长度是最直接的信号,token 数越多,通常意味着信息量越大,对模型的处理能力要求越高。输入的结构化程度也很关键,结构清晰的输入(比如表格、列表)比大段自由文本更容易处理。历史交互轮次在对话场景里很重要,多轮对话需要模型维持上下文一致性,对能力要求更高。是否包含专业领域内容,涉及代码、数学、法律、医学等专业内容的,通常需要更强的模型。这些信号可以组合成一个复杂度分数,然后根据分数区间来决定路由。比如设定三个档位:低复杂度走轻量模型,中复杂度走中档模型,高复杂度走强模型。每个档位的阈值需要根据实际数据调,没有万能公式。我自己的经验是,先用一个粗略的规则跑一段时间,收集实际的路由决策和最终效果数据,然后根据数据反过来调整阈值。这个过程通常需要迭代两三轮才能稳定下来。3.3 成本预算:把经济账算进规则里成本约束是路由规则里最实际的一个维度,但也是最容易被忽略的。很多团队做路由只考虑效果,不考虑成本,结果分流做了半天,账单没降多少。成本预算应该怎么进规则?我的做法是给每个请求打一个预算标签,然后路由决策在满足效果要求的前提下,优先选择成本最低的模型。预算标签可以来自几个地方。业务层指定,比如某个客户明确要求控制成本,那他的请求就带低成本标签。动态计算,根据当前时间段的整体消耗情况,如果已经接近预算上限,后续请求自动降级。优先级判断,高优先级的请求不设成本限制,低优先级的请求优先走便宜模型。这里有个细节:成本不只是模型调用的单价,还包括重试、失败重跑、人工介入的成本。一个便宜但经常失败的模型,综合成本可能比一个贵但稳定的模型更高。所以路由规则里要考虑模型的稳定性指标,不能只看单价。3.4 延迟要求:实时场景的硬约束延迟要求在很多场景下是一票否决的。用户在前端等着回复,你路由到一个延迟五秒的模型,效果再好也没用。延迟约束的处理方式有两种。一种是硬约束,超过延迟阈值的模型直接排除在候选之外。另一种是软约束,延迟作为一个权重因子参与打分,延迟高的模型分数低,但不是完全不能用。我一般对实时交互场景用硬约束,对后台批处理场景用软约束。实时场景下,我会先根据延迟要求筛掉一批模型,然后在剩下的里面按效果和成本选。后台场景下,延迟不那么敏感,可以更侧重效果和成本。延迟的评估不能只看模型的平均响应时间,要看 P95 甚至 P99。平均值好看但长尾严重的模型,在实时场景下会带来很差的体验。我一般会维护一个模型延迟的滚动统计,路由时参考最近的 P95 数据。3.5 多维度打分:把规则统一成一个决策函数上面这些维度单独看都简单,但组合起来就复杂了。我的做法是设计一个统一的路由决策函数,把各个维度转成分数,加权求和,选总分最高的模型。这个函数大概长这样:对每个候选模型,计算它在效果、成本、延迟三个维度的得分,然后按权重加权。效果得分来自模型在对应任务类型上的历史表现,成本得分来自单价和预估 token 数,延迟得分来自历史 P95 数据。权重根据场景调整,实时场景延迟权重大,成本敏感场景成本权重大。这个方案的好处是可解释、可调整。每个决策都能追溯到是哪个维度起了决定性作用,调参也有明确的方向。坏处是需要维护每个模型在每个任务类型上的表现数据,前期投入比较大。如果项目初期数据不够,可以先简化成规则匹配:if 任务类型是推理 and 延迟要求低,then 用强模型;elif 成本敏感,then 用轻量模型。等数据积累起来再过渡到打分模型。4. 把路由规则写进 Runtime 的具体实现4.1 Runtime 的接口设计Runtime 的接口设计决定了这套方案好不好用。我的经验是,接口要足够简单,让业务层容易接入,同时要足够灵活,能表达各种路由需求。一个典型的接口大概是这样:业务层调用一个route方法,传入请求的元信息,包括任务描述、输入内容、优先级、预算约束、延迟要求等。Runtime 返回一个路由决策,包含模型标识、调用参数、超时设置、重试策略。class RouteRequest: task_hint: str # 业务层对任务的粗略描述 input_text: str # 实际输入内容 priority: str # high / normal / low budget_level: str # strict / normal / unlimited latency_budget_ms: int # 可接受的延迟上限 metadata: dict # 其他上下文信息 class RouteDecision: model_id: str params: dict # temperature, max_tokens 等 timeout_ms: int retry_policy: dict fallback_model: str # 主模型失败时的备选这个接口的关键点是,业务层只提供信息,不做决策。决策逻辑全部在 Runtime 内部。这样业务代码保持干净,路由规则的调整不影响业务逻辑。4.2 规则配置的结构路由规则本身应该是可配置的,而不是写死在代码里。我一般用 YAML 或者 JSON 来定义规则,Runtime 启动时加载,支持热更新。规则的结构大概分三层。第一层是匹配条件,定义这条规则适用于什么样的请求,比如任务类型、优先级、输入长度范围等。第二层是候选模型列表,列出满足条件时可以选择的模型。第三层是选择策略,定义在候选模型里怎么选,是按成本最低、延迟最低还是综合打分。rules: - name: "simple_intent" match: task_type: "intent" input_length: "< 500" candidates: ["model-light-a", "model-light-b"] strategy: "cost_first" fallback: "model-mid-a" - name: "complex_reasoning" match: task_type: "reasoning" priority: "high" candidates: ["model-strong-a", "model-strong-b"] strategy: "quality_first" fallback: "model-mid-b"这种配置方式的好处是,调整路由策略不需要改代码,改配置就行。而且规则之间的优先级、覆盖关系一目了然,不容易出现逻辑冲突。4.3 前置分类器的实现细节前置分类器是路由链路的第一环,它的准确率直接影响后续所有决策。我的做法是用一个轻量模型做分类,输入是用户的原始请求,输出是任务类型标签。分类器的 prompt 设计很关键。我一般会给它几个明确的类别定义,让它做单选。类别不要太多,四到六个比较合适。prompt 里要包含几个典型例子,帮助模型理解边界。CLASSIFIER_PROMPT = """ 判断以下请求属于哪个类别,只输出类别名称: - intent: 意图识别、分类、判断 - generate: 文案生成、摘要、翻译、改写 - reasoning: 逻辑推理、计算、代码、规划 - multimodal: 涉及图像、文档解析 - other: 无法归入以上类别 请求:{input_text} 类别: """分类器的输出要做校验,如果输出了不在预定义类别里的内容,就归到 other,走默认路由。这个兜底逻辑很重要,否则分类器出错会导致整个路由链路异常。分类器的延迟要控制在可接受范围内。我实测下来,用轻量模型做分类,延迟通常在几百毫秒以内,对整体链路的影响很小。如果对延迟极度敏感,可以考虑用更小的专用分类模型,或者用规则做初步筛选,只对不确定的请求调用模型分类。4.4 复杂度评估的量化方法复杂度评估需要把定性判断转成定量分数。我的做法是定义几个信号,每个信号给一个分数,加权求和。输入长度信号:按 token 数分档,比如小于 200 给 1 分,200 到 1000 给 2 分,1000 到 5000 给 3 分,大于 5000 给 4 分。结构信号:结构化输入(JSON、表格、列表)给低分,自由文本给高分。因为结构化输入更容易处理,对模型能力要求低。专业度信号:包含代码、数学公式、专业术语的给高分。这个可以用关键词匹配做初步判断,不需要模型。轮次信号:对话场景下,历史轮次越多给分越高。单轮给 1 分,三到五轮给 2 分,五轮以上给 3 分。把这几个信号加权求和,得到一个复杂度总分,然后按阈值分档。权重的设定需要根据实际数据调,我一般先给长度和结构各 0.3,专业度和轮次各 0.2,跑一段时间再调。提示:复杂度评估不需要非常精确,它的作用是区分"明显简单"和"明显复杂"的请求,中间地带的误判影响不大。不要为了追求精确而把评估逻辑做得过于复杂。4.5 降级与兜底策略路由规则再完善,也会有判断失误的时候。所以降级和兜底策略是必须的。主模型调用失败时,自动切到 fallback 模型。fallback 模型的选择要考虑两点:一是它得能处理这个任务,二是它的可用性要高于主模型。我一般选一个能力稍弱但更稳定的模型做 fallback。主模型输出质量不达标时,也要有降级机制。怎么判断质量不达标?可以用一些启发式规则,比如输出为空、输出格式不符合要求、输出明显偏离主题。检测到这些情况,自动重试或者切到更强的模型。整体链路超时时,要有快速失败机制。不能让用户一直等着。设置一个总超时,超过就直接返回兜底结果或者错误提示。预算耗尽时,自动降级到低成本模型。这个在预算敏感的场景下很重要,避免月底账单爆炸。这些兜底策略要写在 Runtime 里,而不是业务层。业务层不需要关心这些细节,它只管调用,Runtime 保证尽可能返回一个合理的结果。5. 实操中的参数计算与调优5.1 成本预估的计算方法路由决策要算成本,就得预估每个候选模型的调用成本。成本等于输入 token 数乘以输入单价,加上输出 token 数乘以输出单价。输入 token 数可以从请求内容直接算出来,用 tokenizer 数一下就行。输出 token 数不好预估,因为模型输出长度不确定。我的做法是用历史数据估算,对每个任务类型统计平均输出长度,作为预估依据。def estimate_cost(model, input_tokens, task_type): avg_output = OUTPUT_LENGTH_STATS[task_type] input_cost = input_tokens * model.input_price output_cost = avg_output * model.output_price return input_cost + output_cost这个预估不需要很精确,因为路由决策是相对比较,不是绝对计算。只要预估方法对所有候选模型一致,比较结果就是有意义的。有个细节要注意:不同模型的 tokenizer 不一样,同样的文本在不同模型下的 token 数可能不同。严格来说应该用每个模型自己的 tokenizer 来算,但这样开销太大。我的做法是用一个统一的近似方法,比如按字符数除以一个系数,误差在可接受范围内。5.2 延迟阈值的设定延迟阈值怎么定?我的经验是从用户体验倒推。用户能接受的等待时间通常在两到三秒,超过这个时间就会觉得慢。所以端到端的延迟预算大概是两秒,扣掉网络传输、前后处理的时间,留给模型的时间可能只有一秒到一秒五。然后看候选模型的 P95 延迟。如果某个模型的 P95 超过这个预算,就排除掉。如果所有模型都超,那就得考虑降低要求,或者优化链路其他环节。延迟阈值不是固定的,不同场景可以不同。实时对话场景阈值低,后台处理场景阈值高。我一般会为每个场景单独配置延迟预算,而不是全局一个值。5.3 权重调优的实操步骤多维度打分的权重调优是个迭代过程。我的做法分三步。第一步,初始化权重。根据业务目标给一个初始值。如果当前最痛的是成本,成本权重给高一点;如果最痛的是效果,效果权重给高一点。初始值不用太精确,先跑起来。第二步,收集数据。跑一段时间,记录每次路由决策的输入、决策结果、最终效果。效果可以用人工评估或者自动指标来衡量。第三步,分析调整。看哪些决策是"错误"的,比如本该走强模型的走了弱模型导致效果差,或者本该走弱模型的走了强模型浪费成本。根据这些错误调整权重。这个过程通常需要两到三轮才能稳定。不要指望一次调好,也不要频繁调整,每次调整后至少跑几天收集足够数据再调下一次。5.4 灰度发布与 A/B 测试路由规则变更是有风险的,可能影响线上效果。所以变更要走灰度发布。我的做法是新的路由规则先在小比例流量上生效,比如百分之五。对比新规则和旧规则在这部分流量上的效果指标,包括成本、延迟、质量。如果新规则明显更好,逐步扩大比例;如果更差,回滚。A/B 测试的关键是定义好评判指标。成本看单位请求的平均花费,延迟看 P95,质量看人工评估或者自动指标。三个指标要综合看,不能只看一个。有时候成本降了但质量也降了,这种变更要不要上,取决于业务对质量和成本的权衡。注意:灰度期间要保证分流是随机的,不能按用户 ID 或者其他有偏的方式分,否则对比结果不可信。我一般用请求 ID 的哈希来做分流,保证随机性。6. 常见问题与排查技巧实录6.1 路由决策不符合预期怎么办这是最常见的问题。你期望某个请求走强模型,结果走了弱模型,效果不好。排查思路是这样的。先看分类结果,确认前置分类器把请求分到了哪个类别。如果分类错了,问题在分类器,需要调整 prompt 或者补充训练数据。再看复杂度评分,确认评分是否符合预期。如果评分偏低,检查各个信号的权重和阈值。最后看候选模型列表和选择策略,确认在给定条件下,决策逻辑是否正确地选出了预期模型。我遇到过一次,分类器把代码生成请求分到了 generate 类别,导致走了中档模型,代码质量很差。后来在分类器的 prompt 里加了代码相关的例子,问题就解决了。6.2 成本没有明显下降做了路由分流,但账单没降多少,这种情况通常是几个原因。分流比例太低。大部分请求还是走了强模型,只有少量走了弱模型。检查一下分类结果分布,看看是不是分类器把太多请求分到了复杂类别。弱模型的输出太长。弱模型虽然单价低,但如果输出 token 数远多于强模型,总成本可能差不多。检查一下各模型的平均输出长度。重试和失败太多。弱模型失败率高,重试带来的额外调用抵消了成本节省。检查各模型的失败率和重试率。成本计算没算全。只算了模型调用成本,没算前置分类器、后处理等环节的成本。把这些都算进去再看。6.3 延迟波动大延迟波动通常来自几个地方。模型本身延迟不稳定,某些时段负载高,响应慢。路由决策耗时,如果决策逻辑复杂,本身就会增加延迟。重试和降级,失败重试会显著增加延迟。排查方法是给链路各环节打点,看时间花在哪里。如果是模型延迟问题,考虑换更稳定的模型或者做多模型负载均衡。如果是决策耗时问题,优化决策逻辑,把能缓存的缓存起来。如果是重试问题,调整重试策略,减少不必要的重试。6.4 常见问题速查表问题现象可能原因排查方向解决思路路由决策不符合预期分类错误或评分偏差检查分类结果和复杂度评分调整分类 prompt 或评分权重成本没下降分流比例低或重试多看分类分布和失败率调整分类阈值或换更稳定的模型延迟波动大模型不稳定或决策耗时链路各环节打点换模型或优化决策逻辑质量下降弱模型能力不足对比各模型输出质量调整路由规则,复杂请求走强模型规则冲突多条规则匹配同一请求检查规则优先级明确规则优先级或合并规则6.5 几个踩过的坑坑一:分类器过度自信。早期我用分类器的时候,没有设置置信度阈值,分类器输出什么就用什么。结果有些边界请求被分错,效果很差。后来加了置信度判断,低置信度的请求走默认路由或者人工兜底,问题少了很多。坑二:忽略冷启动。新模型刚接入的时候,历史数据不足,延迟和效果数据都不准。这时候如果直接按数据路由,可能会做出错误决策。我的做法是新模型先跑一段时间的影子流量,收集数据,等数据够了再纳入路由候选。坑三:规则太多难维护。一开始觉得规则越多越精细,后来发现规则之间互相冲突,排查问题很痛苦。现在我会控制规则数量,能合并的合并,能用参数表达的不用新规则。坑四:忘了监控。路由规则上线后没有监控,出了问题不知道。现在我会给每个路由决策打点,记录决策依据和结果,定期 review,发现问题及时调整。7. 路由规则的扩展与演进7.1 从规则匹配到学习型路由规则匹配的路由在项目初期够用,但随着场景增多、模型增多,手工维护规则的成本会越来越高。这时候可以考虑引入学习型路由。学习型路由的思路是,用历史数据训练一个模型,输入是请求特征,输出是最优模型选择。训练数据来自历史的路由决策和效果反馈。这个模型可以是一个简单的分类器,也可以是一个更复杂的决策模型。学习型路由的好处是能自动发现规则难以表达的复杂模式,而且随着数据积累会越来越准。坏处是需要足够的数据,而且模型本身的可解释性差,出问题不好排查。我的建议是,规则匹配和学习型路由结合使用。规则处理明确的、高频的场景,学习型路由处理模糊的、长尾的场景。两者互补,效果比单用任何一种都好。7.2 多模型协同的路由有些任务不是单个模型能搞定的,需要多个模型协同。比如一个复杂任务,先用一个模型做规划,再用另一个模型执行,最后用第三个模型做校验。这种场景下,路由不只是选一个模型,而是编排一条模型调用链路。这种编排式的路由,规则会更复杂,需要考虑模型之间的依赖关系、数据传递、失败处理。我的做法是把编排逻辑也抽象成配置,用类似工作流的方式定义,Runtime 负责按配置执行。7.3 路由规则的可观测性建设路由规则上线后,可观测性是保证它持续有效的基础。我一般会建设这几个方面的观测能力。决策日志,记录每次路由的输入、决策结果、决策依据。效果指标,跟踪每个模型在每个任务类型上的效果、成本、延迟。异常告警,当路由决策异常(比如某个模型突然大量失败)时及时告警。定期报告,每周或每月生成路由效果报告,review 规则的有效性。这些观测数据不仅能帮你发现问题,还能为规则调优提供依据。没有观测数据,调优就是盲调。7.4 一个实际项目的演进过程我参与过一个对话 Agent 项目,路由规则的演进大概经历了三个阶段。第一阶段,硬编码。所有请求走同一个模型,简单粗暴。问题是用量上来后成本高,而且简单请求响应慢。第二阶段,规则路由。引入前置分类器,按任务类型分流。简单请求走轻量模型,复杂请求走强模型。成本降了约四成,延迟也有改善。问题是规则越来越多,维护成本上升。第三阶段,打分路由。把规则匹配改成多维度打分,效果、成本、延迟综合评估。规则数量减少,决策更灵活。同时引入学习型路由处理长尾场景。这个阶段成本又降了一些,效果也更稳定。这个演进过程不是一蹴而就的,每个阶段都是被实际问题推动的。我的体会是,不要一开始就追求完美的路由方案,先解决最痛的问题,然后随着项目发展逐步演进。8. 一些实操建议如果你正准备给自己的 Agent 项目加路由,我有几个建议。先从最简单的规则开始。不要一上来就搞多维度打分,先用任务类型做粗分流,跑起来看效果。有了数据再精细化。把决策逻辑和业务逻辑分开。路由决策放在独立的 Runtime 组件里,业务代码只负责组装请求信息。这样后续调整路由规则不影响业务代码。重视前置分类器。分类器的准确率直接决定路由效果。花时间优化分类器的 prompt,补充边界案例,比优化后面的决策逻辑收益更大。建立观测体系。从第一天就记录路由决策和效果数据。没有数据,后续调优无从下手。灰度发布,小步快跑。路由规则变更走灰度,小比例验证后再扩大。不要一次性全量切换,风险太大。定期 review 规则。业务在变,模型在变,路由规则也要跟着变。定期 review 规则的适用性,该删的删,该改的改。不要过度优化。路由的目标是找到性价比合适的方案,不是找到理论最优。80 分的路由方案加上好的观测和迭代,比 90 分的方案但没法维护要好得多。我在实际项目里的体会是,路由这件事的价值不在于用了多复杂的算法,而在于把模型选型从一个拍脑袋的决策变成了一个可管理、可迭代的系统能力。一开始可能只是几条简单的 if-else,但只要结构对了,后续的演进就是水到渠成的事。最怕的是一开始就写死在业务代码里,等到想改的时候发现牵一发动全身,那就被动了。