1. 一个模型写到底为什么越来越撑不住先说结论多模型编排这件事从锦上添花的优化项变成了不得不做的基建项核心推力不是模型不够强而是成本结构变了。我最早接触这套思路是因为一个内部代码评测流水线单次全量跑下来账单能让人沉默三分钟。后来团队里有人提了个很朴素的想法——不是每道题都值得请最贵的那位出场能不能让便宜的先上搞不定的再往上转这个想法最后长成了一套叫 HydraFusion 的编排方案名字取自九头蛇一个身子、多个头各管一摊谁擅长什么就派谁去。这套东西解决的问题很具体在保证评测结论可信的前提下把单位样本的平均调用成本压下来。官方给出的口径是评测成本降低 67%这个数字我在自己搭的小规模复现里大致对得上后面会把拆解过程摊开讲。它适合谁来读如果你正在做这几类事——多模型接入层、AI 应用的推理网关、批量任务的模型调度、自动化评测流水线——那这套思路基本可以直接搬。哪怕你只是单打独斗写脚本调 API把路由这一层加进去账单也会有肉眼可见的变化。我不打算把它讲成一个高大上的架构神话。真实情况是这套东西的 80% 价值来自几个非常朴素的判断——任务分级、模型分级、失败要有兜底、结果要能验证。剩下的 20% 才是工程实现。下面按我实际落地的顺序一层层拆。1.1 单模型通吃的三个隐性成本很多人算模型成本只算 token 单价这其实漏了一大块。我把实际踩到的成本分成三类你可以对照自己的场景看看中了几条。第一类是能力错配成本。用最强的模型去干格式化、字段抽取、简单分类这类活就像开重型卡车去送一份外卖。单价高只是表象真正贵的是它带来的延迟和并发占用——同一个请求排队时间变长高峰期你就得扩容扩容又是钱。我做过一个粗略统计在一批混合任务里真正需要强推理的样本占比通常不到三成剩下七成用中等模型甚至小模型就能拿到同样质量的结果。第二类是评审放大成本。评测场景有个特点一次评测要跑生成 评审两轮评审那一轮的调用量往往比生成还大。如果评审也一律用最强模型成本直接翻倍。更麻烦的是重跑——某条样本判定不稳定你重跑三次成本乘三。第三类是失败重试成本。单模型方案里一旦模型输出格式跑偏、超时、被限流整条链路就卡住重试是常态。重试的 token 是白烧的而且会放大前面两类成本。注意这三类成本里第二类和第三类最容易被忽略因为它们不出现在单价表上只出现在月底账单里。做成本优化如果只盯着单价通常只能拿到 10%~20% 的改善剩下的大头在调度策略里。1.2 编排到底编的是什么多模型编排这个词听着玄拆开就是三件事分流、执行、收敛。分流是决定这个任务交给谁执行是把请求按各家接口的规范发出去、把返回统一成一种结构收敛是把多个结果合并、校验、必要时再补一次。听着简单但每一层都有坑分流错了后面全白搭执行层不统一代码里到处是 if-else收敛层不做校验你根本不知道便宜模型给的结果靠不靠谱。我见过一些团队的做法是堆提示词试图用一个超长提示词让强模型自己判断难度再决定答不答。这条路我也试过效果一般——模型对自身难度的判断并不准而且你已经在付强模型的钱了省不下来。真正有效的做法是在模型之外加一层轻量的判定逻辑用规则 小模型打分先把任务分档再按档位派单。这层判定本身的成本很低一次几百 token 的量级摊到每个样本上几乎可以忽略。这就是 HydraFusion 的基本盘便宜的部分做决策贵的部分只做决策后的执行。2. 整体架构与选型为什么是轻路由 重执行先把架构图在心里画出来我用文字描述方便你直接照着搭。整条链路分四层入口层 → 路由层 → 执行层 → 收敛层旁边挂两个旁路缓存和埋点。入口层负责把外部请求规整成统一的内部格式字段包括任务类型、输入内容、期望输出结构、优先级、预算上限。路由层拿这些字段做判定输出一个执行计划——不是单个模型而是一个有序的候选列表比如[轻量模型B, 中等模型A, 强模型C]。执行层按计划依次尝试命中即停。收敛层做结构校验、置信度评估、必要的二次确认然后把结果写回缓存并落埋点。2.1 为什么不做端到端一个大脑有一种设计思路是搞一个调度大模型把所有请求丢给它让它输出该用哪个模型。听起来很优雅实际跑下来有两个硬伤。一是成本倒挂。调度本身要花 token如果调度模型不够强判断不准够强那每次调度都在烧钱等于在省钱的地方先花了一笔。我实测过一轮用中等模型做调度单样本调度成本约占总成本的 8%~12%把省下来的又吃回去一截。二是不可解释、不可控。调度模型给出的判断没有理由出问题时你没法定位。而规则 小模型打分的方案每一条判定都有分数、有依据线上出问题一眼能看出是哪条规则误判了改起来也快。所以 HydraFusion 走的是轻路由路线路由层里 90% 的判定由规则和特征完成只有边界模糊的样本才交给一个小模型打分。这个设计让路由层的成本压到了整体成本的 2% 以内同时保留了足够的灵活性。2.2 分层架构的四个关键决策落地时做过的取舍我列成表你可以直接对照决策点我们最终的选择备选方案为什么这么选路由判定方式规则优先 小模型兜底全靠大模型调度成本可控、可解释、易调试执行顺序由轻到重依次尝试并行全跑再挑最好的并行成本翻倍串行命中即停更省结果校验结构化校验 抽样人工复核全量人工复核全量复核人力扛不住抽检足够暴露系统性问题失败处理逐级升级 单级重试上限无限重试直到成功无限重试是成本黑洞必须设硬上限这里展开说两个点。串行 vs 并行。并行全跑再择优质量确实最稳但成本是串行的 N 倍完全背离了优化目标。串行的问题是有延迟累积——第一级失败才走第二级最坏情况延迟是各级之和。我们的处理是给每级设独立超时超时就算失败直接升级不做无谓等待。实测下来95% 的样本在第一级就命中平均延迟反而比单模型方案更低。全量复核 vs 抽检。这条最容易被争论。我的立场很明确评测这种场景全量人工复核在样本量上到几千条之后就不现实了必须接受用统计方法保证结论可信这个前提。具体做法是分层抽样按任务类型和路由档位分层每层抽固定比例做人工核验同时用自动化的结构校验兜住明显的格式错误。这套组合下来实测漏检率能压到 1% 以下。2.3 67% 这个数字是怎么构成的标题里的成本降低 67%很多人第一反应是是不是偷工减料了。我把构成拆开你自己判断合不合理。成本下降主要来自四个部分按贡献排序分级路由减少高价模型调用贡献约 45 个百分点。这是最大头逻辑就是前面说的七成任务不需要最强模型。缓存与去重贡献约 10 个百分点。评测集里重复和近重复样本比想象中多尤其是同一道题的不同变体。评审环节降采样 分级评审贡献约 8 个百分点。简单样本用轻量评审只有判定分歧的才升级。重试次数下降贡献约 4 个百分点。编排层的失败兜底让整条链路的成功率提升白烧的 token 少了。这四项加起来 67%。注意一点这个数字是在结论一致率基本不变的前提下拿到的。如果只看成本不看质量随便换个便宜模型能省 90%但那不叫优化那叫降级。所以任何成本数字都必须配一个质量指标一起报单看一个都是耍流氓。提示对外汇报成本优化成果时一定要把质量口径写在同一页上。我见过太多方案因为只报成本被质疑补上一致率数据之后反而成了亮点。3. 核心细节路由策略怎么设计才不翻车路由是整个方案的心脏也是最容易做砸的地方。做砸的典型症状是成本降了但某几类任务的质量断崖式下滑而你在总指标上看不出来——因为那几类任务占比小被平均值稀释了。所以路由设计的第一原则不是省是**可观测**。3.1 先把任务分清楚四个维度我用的分类框架是四个维度每个维度都能从一个简单的特征里拿到信号结构复杂度期望输出是自由文本、还是严格的 JSON / 表格。要求结构化输出的优先给擅长格式的模型反而是强推理模型容易话多。上下文长度输入 token 数。长上下文任务对模型的窗口和注意力要求高这块不能省。推理深度需不需要多步推导。这个用规则判断很难通常用小模型打一个 0~1 的分数。风险等级结果错了代价大不大。评测场景里这对应这条样本是否属于核心指标集。四个维度里前两个用规则就能拿到第三个要小模型打分第四个是业务侧标注的元数据。组合起来就是一个四元组路由表按这个四元组查。这里有个实操技巧别一上来就设计很细的分档。我最初的版本分了 12 档结果大部分档位的样本量少得可怜统计上没意义调参也没法调。后来收敛到 4 档反而效果更好——粗粒度 明确边界比细粒度 模糊边界可靠得多。3.2 路由打分表让每条判定都有据可查路由的核心是一张打分表。每个候选模型在每个维度上有一个适配分加权求和后排序。表长这样维度权重轻量模型B中等模型A强模型C结构复杂度适配0.250.90.80.6长上下文适配0.200.40.80.9推理深度适配0.400.30.70.95风险等级容忍0.150.20.71.0单位成本系数反向—1.03.29.5读法每个维度打 0~1 分乘权重求和得到该模型的适配总分再除以成本系数得到性价比分按性价比分排序生成候选列表。成本系数这一列不进加权只做最后的除法这样调整成本敏感度时不用重算权重。权重的确定方式我的建议是从业务损失反推而不是拍脑袋。比如推理深度这一项给到 0.40是因为我们统计过推理类任务如果路由错了返工率是其他类型的 3 倍返工成本要计入。这个权重不是理论最优是我们这边最不亏的解。注意这张表必须版本化。每次调整都记录版本号和调整原因线上出问题时能快速回溯到是哪次调参引入的。我们吃过这个亏——某次为了省钱把轻量模型的权重调高了 0.05两周后才发现某类长文本任务的质量在缓慢下滑因为改动没留痕排查花了一整天。3.3 失败回退三级兜底与硬上限回退策略看着不起眼实际是成本控制的关键阀门。设计不好会出现为了省一次调用重试烧掉五次的情况。我的方案是三级兜底每级都有硬约束第一级格式重试。同一模型加一条纠错提示再试一次只针对返回了内容但结构不合法的情况。上限 1 次。第二级模型升级。换候选列表里的下一个模型带上上一轮的错误信息作为上下文。上限 1 次。第三级人工队列。前两级都失败落盘进人工队列同时打标记录。这一步不产生调用成本但必须做否则你会丢掉最难的那批样本——而这批样本恰恰是评测最有价值的部分。硬上限的意思是任何一条样本的总调用次数不超过 4 次首次 格式重试 升级 升级后的格式重试。超过就强制落人工队列。这个数字不是随便定的我们算过一笔账单样本成本超过基准成本的 5 倍时继续自动重试的期望收益已经为负不如交给人。另外还有一个细节升级时要带上下文。很多人升级模型时把上一轮的错误信息丢了导致新模型重复犯同样的错。正确的做法是把上一次输出 校验错误信息一起塞进去明确告诉它哪里不对。这一条改动让我们的二级升级成功率从 40% 出头提到了 70% 以上。4. 实操落地从零搭一条能跑通的编排链路这部分给能直接抄的东西。我用 Python 写示例不依赖特定框架你换成任何语言逻辑都是一样的。目录结构建议这样fusion/ ├── router/ │ ├── rules.py # 规则判定 │ └── scorer.py # 打分与排序 ├── executor/ │ ├── adapters.py # 各模型接口适配 │ └── retry.py # 重试与升级 ├── merger/ │ ├── validate.py # 结构校验 │ └── compare.py # 多结果比对 ├── cache/ │ └── store.py # 结果缓存 └── pipeline.py # 主流程编排4.1 路由层实现规则先跑模型兜底路由层的核心函数要足够快、足够纯——不产生副作用只做判定。from dataclasses import dataclass dataclass class TaskProfile: task_type: str input_tokens: int need_structured: bool risk_level: str # core | normal complexity_score: float 0.0 def route(profile: TaskProfile, model_table: list) - list: # 第一步硬规则拦截这几种情况不走打分 if profile.risk_level core: return [model_c, model_a] if profile.input_tokens 24000: return [model_c] # 第二步轻量特征给 complexity_score 兜底 if profile.complexity_score 0.0: profile.complexity_score estimate_complexity(profile) # 第三步加权打分 性价比排序 ranked [] for m in model_table: score ( 0.25 * m.fit_structure(profile.need_structured) 0.20 * m.fit_long_ctx(profile.input_tokens) 0.40 * m.fit_reasoning(profile.complexity_score) 0.15 * m.fit_risk(profile.risk_level) ) ranked.append((m.name, score / m.cost_factor)) ranked.sort(keylambda x: x[1], reverseTrue) # 只取前三列表太长没有意义 return [name for name, _ in ranked[:3]]几个注意点。硬规则要放在打分之前因为有些情况根本不该进入打分流程——比如核心指标集的样本无论多简单都应该走强模型这是质量底线不能拿成本去换。列表截断到 3 个因为我实测过四级以上的升级链在实际样本里触发率低于 0.1%多留只会增加复杂度。estimate_complexity这个函数用一个小模型做打分提示词要极简让它只输出一个 0~1 的数字不要解释。我最初的版本让它输出理由结果每次多花几十 token而且理由对决策没有帮助——这个分数只用来排序不需要可解释性。def estimate_complexity(profile: TaskProfile) - float: prompt ( 给下面任务的推理难度打一个 0 到 1 的分数 只输出数字不要任何其他文字。\n f任务{profile.task_type}\n f输入{profile.raw_input[:600]} ) raw light_model.complete(prompt, max_tokens8) try: return max(0.0, min(1.0, float(raw.strip()))) except ValueError: return 0.5 # 解析失败给中间值宁可保守解析失败返回 0.5 这个设计很关键。不要返回 0那样会把难题误判成简单题也不要返回 1那样所有异常样本都涌向最贵的模型成本直接失控。中间值是个安全的默认。4.2 执行层统一适配 分级重试执行层的职责是把候选列表消费掉。所有模型接口的差异都收敛在适配器里上层完全感知不到。def execute(plan: list, payload: dict, max_calls: int 4): attempts 0 last_error None history [] for model_name in plan: while attempts max_calls: attempts 1 try: result adapters[model_name].call(payload, history) if validate(result, payload[schema]): return result, model_name, attempts last_error schema_invalid history.append({model: model_name, error: 输出结构不合规}) break # 同模型只重试一次直接升级 except TimeoutError: last_error timeout break except RateLimitError: last_error rate_limit continue # 限流不算模型能力问题同模型再试一次 return None, None, attempts这段代码有两个地方值得说。限流和超时的处理逻辑必须分开。限流是外部因素同一模型再试一次是合理的超时往往意味着输入太长、任务太难重试大概率还是超时直接升级更划算。我早期把两者混在一起处理结果一批长输入样本在轻量模型上反复超时白白烧掉大量时间和调用次数。同模型只重试一次。这一条是成本纪律。有些人会写重试 3 次看起来很稳妥实际上在编排场景里是浪费——你这个模型失败了说明它大概率真不行换个模型比死磕更有效。4.3 收敛层校验、比对、落缓存收敛层容易写得很随意但它才是质量保证的最后一道闸。def converge(results: list, payload: dict): if len(results) 1: return results[0] # 多条结果并存时先比结构合规性再比内容一致性 valid [r for r in results if validate(r, payload[schema])] if not valid: return None if len(valid) 1: return valid[0] # 全部合规但内容不一致标记为分歧样本 if not consistent(valid): mark_as_disputed(payload[id]) return valid[0] # 优先取候选列表里靠前的consistent这个函数值得展开。它是判断多个模型对同一任务给出的结果是否实质相同。简单的字符串比对在这种场景没用我用的是关键字段比对从结果里抽出 3~5 个核心字段逐个比对全部相同才算一致。这个方法粗糙但有效实测能覆盖 90% 以上的分歧情况。分歧样本要落盘单独处理这是质量监控的金矿。我们每周会看一遍分歧样本如果某类任务的分歧率突然上升基本就是某个模型的行为变了或者路由表需要调整。这个习惯帮我们提前发现过两次上游模型改版带来的行为漂移。4.4 缓存设计去重的正确姿势缓存这块很多人只做精确匹配省不了多少。真正有效的是语义级去重。我的做法分两层第一层是精确哈希输入文本规范化去多余空白、统一标点后算哈希命中直接返回第二层是向量近似匹配把输入转成向量相似度超过阈值就认为是同一类任务复用之前的路由结果——注意只复用路由结果不复用生成结果。分界线很重要生成结果不能跨样本复用因为哪怕输入相似输出也可能需要不同但路由决策可以复用因为相似任务的难度判定基本一致复用能省掉那次小模型打分的成本。这个设计让路由层成本又降了一截。注意近似匹配的阈值别设太低。我一开始设 0.85结果把不少看着像但实际不同的样本归到了一起路由判错了。后来提到 0.93误命中率明显下降。这个值需要在你自己的数据上跑一遍才知道没有通用解。4.5 评测流水线的改造要点如果你的场景是评测还要多做一件事把评审环节也纳入编排。评审比生成更适合分级。原因是评审的输出通常是固定结构分数 短理由结构化程度高轻量模型完全能干。我的策略是全量样本先用轻量评审打分把分数落在模糊区间比如 40~60 分的样本挑出来交给强模型重评。模糊区间的样本通常只占 15%~20%这部分用强模型完全负担得起。这个做法有个前提模糊区间的边界要在你的数据上校准。不同任务的分值分布差异很大有些任务分数集中在高位模糊区间应该整体上移。我们的做法是每周跑一次分值分布直方图动态调整边界这个动作花不了多少时间但对成本影响很大。5. 实测数据与成本核算数字要经得起追问我不太喜欢只报一个降低 67%因为这种数字离开口径就没有意义。这一节把我们的统计方式完整摊开你拿去套自己的场景。5.1 口径定义什么叫一条样本的成本我用的口径是单样本平均调用成本计算方式是一段时间内的总调用费用 ÷ 完成的有效样本数。注意分母是完成的有效样本不是提交的样本——失败样本的成本也要摊进去否则成本会被低估。这个口径比token 单价严格得多因为它包含了重试、失败、缓存命中率低等等所有真实损耗。我用这个口径算出来的数字通常比理论最优方案差 10~20 个百分点但这才是能对上账的数字。质量口径同步定义结论一致率 编排方案给出的最终结论与基准方案一致的比例。基准方案就是原来的单模型方案全量强模型。这两个数字一起看才有意义。5.2 分阶段数据对照下面是三个阶段的对比样本量在几千条量级。为了避免误导我强调一下这是特定场景下的结果你的数字一定不同看的是趋势不是绝对值。阶段单样本平均成本相对值结论一致率平均调用次数P95 延迟阶段一单模型全量100基准1.3基准阶段二加路由无缓存4199.2%1.1下降约 20%阶段三路由 缓存 分级评审3398.6%0.9下降约 35%阶段二到阶段三是成本下降最猛的一段因为缓存和分级评审这两项几乎是白捡的——它们不改变生成环节的模型选择只在调度和评审上做文章。一致率从 99.2% 掉到 98.6%掉了 0.6 个百分点。这个损失我们接受因为它集中在非核心指标集上核心集的样本走的是硬规则不做任何降级。这里的关键设计是核心集和普通集分开统计。如果混在一起你会被平均值骗了——平均值看起来很好但核心指标可能已经悄悄下滑。5.3 成本下降的构成拆解实测版理论拆解在 2.3 节这里给实测版更有说服力优化项成本贡献百分点实施难度备注分级路由42中需要维护路由表持续调参结果缓存 语义去重11低一次做好长期收益分级评审 模糊区间重评9中需要校准分值分布重试次数下降4低编排层带来的副作用收益合计66—与官方口径 67% 基本吻合有一项我特意没算进去人工复核成本的下降。理论上编排之后格式错误少了人工返工也少了但这部分成本很难量化索性不算让数字更保守。提示做成本核算时把没算进去的收益单独列一行。这既是诚实的表现也能在汇报时留一个后手——当有人质疑数字时你可以说这还没算上人工返工那部分。6. 常见问题与排查实录那些文档里不会写的事这一节是我最想写的部分。前面都是应该怎么做这里全是实际会怎么坏。6.1 典型故障速查表现象大概率原因排查动作处理方式成本突然上涨 30% 以上路由规则误判样本涌向强模型看各档位的样本占比变化回滚最近一次路由表调整一致率缓慢下滑上游模型行为漂移抽取分歧样本人工看更新路由表权重或换备用模型平均调用次数飙升某级模型的失败率上升按模型统计失败率临时把该模型降级到候选列表末位P95 延迟异常长输入样本走了多级升级按输入长度分布看升级率给长输入单独设路由规则缓存命中率骤降输入格式变了多空格、编码差异抽样比对规范化前后的哈希补全规范化规则这张表我贴在工位上过一段时间因为前三条几乎每周都会碰到一次。6.2 三个踩过的坑坑一路由表调参没有灰度。有次为了压成本我把轻量模型的权重从 0.3 提到 0.38直接全量生效。当天成本确实降了 6%但三天后有人反馈某类任务的输出质量不对——是那种看起来没错但细节有偏差的问题自动化校验抓不到。后来加了灰度路由表调整先在 5% 的流量上跑 24 小时看一致率和分歧率两个指标没问题再全量。这个动作花了不到半天实现省了后面无数次返工。坑二把限流当成了模型能力问题。早期版本里限流触发的失败被计入了模型失败率导致路由表里某个模型被错误地降权。实际上是那段时间上游并发限制收紧了跟模型能力无关。后来把失败原因细分成能力型和外部型两类只有能力型才影响路由权重。这个改动让路由表的稳定性好了很多。坑三缓存键设计太简单。最初缓存键就是输入文本的哈希结果发现同一批样本重跑时命中率很低——因为上游在拼装输入时加了时间戳之类的东西。改成任务类型 规范化后的核心内容之后命中率从 20% 出头提到了 60% 以上。这个坑很隐蔽因为从表面上看缓存是工作的只是效率低你不会觉得它有问题。6.3 上线前的自查清单最后给一份我们内部用的自查清单按顺序过一遍基本能避开大部分坑核心指标集是否走了硬规则有没有被路由逻辑影响。这一条最重要必须第一个查。每级重试是否有硬上限总调用次数上限是否配置在配置中心而非代码里。失败样本是否有落盘包括最终落人工队列的那批。成本核算口径是否包含失败样本分母是不是有效样本。质量指标是否和成本指标同页展示有没有分核心集和普通集。路由表是否版本化改动是否留痕是否有灰度机制。缓存键是否包含任务类型规范化规则是否覆盖了常见的格式噪声。分歧样本是否有定期复盘机制频率至少每周一次。我个人在实际操作中的体会是多模型编排这件事技术难度其实不高难的是把它当成一个有生命的东西去养。路由表要调、阈值要校准、缓存规则要补、上游模型会变——它不是搭完就完事的基建而是需要持续投入的运营工作。如果你的团队没有精力持续维护那不如一开始就把规则设得保守一些宁可少省几个点也别让它在无人看管的情况下慢慢劣化。另一个体会是关于省钱这件事的心态。刚做这套东西的时候我满脑子都是怎么把数字压得更低结果有一次为了省 3% 的成本把某类样本的评审降级了最后被下游发现结论有偏差返工的成本远超省下来的那点。后来我给自己定了个规矩任何优化先问一句如果这里出错了我怎么发现。答不上来就先不做或者先补监控再做。这条规矩比任何架构原则都管用。还有一个后续可以扩展的方向如果你已经把这套跑通了把编排层从静态规则往线上反馈驱动推。具体做法是把每次分歧样本、每次升级成功的样本都回灌成数据定期重算路由表的权重让表跟着实际数据漂移。我们目前是手工每周看一次下一步想做半自动——系统给出建议权重人确认后生效。这条路我觉得是对的但还没跑完就不展开讲了。