news 2026/9/29 3:39:54

gsd-2 动态模型路由实战指南:capability-aware 两阶段选型、预算压力与扩展 Hook 全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
gsd-2 动态模型路由实战指南:capability-aware 两阶段选型、预算压力与扩展 Hook 全解析
  • 人工智能
  • AI Agent
  • 代码智能体
  • Agent 编排
  • CLI
  • AI 应用

【免费下载链接】gsd-2

A powerful meta-prompting, context engineering and spec-driven development system that enables agents to work for long periods of time autonomously without losing track of the big picture

项目地址:https://gitcode.com/gh_mirrors/gs/gsd-2
点击查看免费下载

导读

动态模型路由(Dynamic Model Routing)是 gsd-2 自动模式下的成本控制核心:它为每个派发的工作单元自动挑选"够用且最便宜"的模型,把昂贵模型(如 Opus 级)留给真正需要深度推理的复杂任务,官方文档给出的典型收益是在有成本上限的套餐下减少 20-50% 的 token 消耗。本文以 docs/zh-CN/user-docs/dynamic-model-routing.md 为骨架,结合仓库中gsd扩展的实际实现(model-router.ts、complexity-classifier.ts、auto-model-selection.ts),完整讲解 tier 分类、capability scoring、预算压力降级、用户覆盖、verbose 日志与before_model_select扩展 Hook 的配置与原理,让你既能直接上手配置,也能理解每一步决策背后的源码逻辑。

动态路由引入于 v2.19.0,capability scoring 引入于 v2.52.0。下文描述以当前仓库实现为准。


一、工作原理:只允许降级,不允许升级

自动模式派发的每个工作单元(unit)都会经过一个两阶段流水线:

  • 阶段 1:复杂度分类(Complexity Classification)——先把工作划分到某个 tier:light/standard/heavy。这一步是纯启发式规则,不涉及 LLM 调用,耗时通常低于 1ms。
  • 阶段 2:能力评分(Capability Scoring)——在符合该 tier 的候选模型里,根据模型能力与 task 需求的匹配程度排序打分,选出最合适的模型(v2.52.0 起)。

核心规则是"只允许降级,不允许升级":用户在偏好设置中配置的 model 始终是上限,router 不会把它升级到比你配置更强的模型。这个约束在源码中有明确体现——resolveModelForComplexity() 通过tierOrdinal(requestedTier) >= tierOrdinal(configuredTier)判断:当请求的 tier 不低于用户配置的 model tier 时,直接返回配置的 primary model,不做任何降级。

默认 tier 与模型级别的对应关系如下:

Tier典型工作默认模型级别
Lightslice completion、UAT、hooksHaiku 级
Standardresearch、planning、execution、milestone completionSonnet 级
Heavyreplan、roadmap reassessment、复杂 executionOpus 级

需要说明的是,源码中的UNIT_TYPE_TIERS映射(见 complexity-classifier.ts)比文档表格更精细:complete-slice在 v2.52+ 版本中默认为Standard而非 Light(避免把携带大量内联上下文的 slice completion 路由到最便宜模型,见代码注释 #4520),plan-*默认即为Heavy(规划需要最强的配置模型,动态路由不会把 Opus 降下去)。


二、启用方式与完整配置

动态路由默认关闭,需要在偏好设置中开启:

--- version: 1 dynamic_routing: enabled: true ---

完整配置项如下(全部选项及默认值):

dynamic_routing: enabled: true tier_models: # 可选:为每个 tier 显式指定 model light: claude-haiku-4-5 standard: claude-sonnet-4-6 heavy: claude-opus-4-6 escalate_on_failure: true # task 失败时提升 tier(默认:true) budget_pressure: true # 接近预算上限时自动降级(默认:true) cross_provider: true # 可跨 provider 选择 model(默认:true) hooks: true # 是否对 post-unit hooks 也应用路由(默认:true) capability_routing: true # 在 tier 内启用 capability scoring(默认:true)

配置项在源码中对应的结构体是 DynamicRoutingConfig。这里有几个值得注意的细节:

  • enabled默认为关闭,但一旦开启,defaultRoutingConfig()(model-router.ts)中其余特性(capability_routing、escalate_on_failure、budget_pressure、cross_provider、hooks)全部默认开启。
  • 源码中还有一个文档未展开的选项allow_flat_rate_providers:对包月制 provider(如 claude-code、GitHub Copilot)默认不启用路由(保留 #3453 的绕过逻辑,因为订阅下每次请求成本相同),只有当你想在包月订阅内按任务选择模型(比如 research 用 haiku、architecture 用 opus)时才开启(#4386)。
  • tier_models支持 provider 前缀匹配:配置anthropic/claude-sonnet-4-6这类带前缀的 ID 时,router 会剥离前缀后与可用模型列表做 bare ID 匹配(见 getEligibleModels())。

三、各配置项深度解析

3.1tier_models:显式覆盖各 tier 的模型

如果省略tier_models,router 会使用内置的 capability mapping。当前仓库维护了一张远超文档列举范围的 tier 映射表MODEL_CAPABILITY_TIER(model-router.ts),文档列出的代表性模型为:

  • Light:claude-haiku-4-5、gpt-4o-mini、gemini-2.0-flash
  • Standard:claude-sonnet-4-6、gpt-4o、gemini-2.5-pro
  • Heavy:claude-opus-4-6、gpt-4.5-preview、gemini-2.5-pro

从源码结构看,实际映射中还包括claude-3-5-haiku-latest、gpt-4.1-mini、gemini-flash-2.0(light);claude-3-5-sonnet-latest、gpt-4.1、deepseek-chat(standard);o1、o3、gpt-4-turbo、claude-3-opus-latest等(heavy)。未知模型的容错策略:未在映射表中的模型默认按standard处理(getModelTier()返回 "standard"),而resolveModelForComplexity()会先检查用户配置的 model 是否在已知映射中——如果不是,则直接尊重用户的显式选择、不做任何降级(#2192,避免基于猜测静默忽略用户配置)。

3.2escalate_on_failure:失败后自动升级 tier

当 task 在某个 tier 上失败时,router 会在重试时提升到下一层:Light → Standard → Heavy。这样可以避免便宜模型在其实需要更强推理能力的工作上浪费重试次数。

源码实现是 escalateTier() 的线性升级链;在 auto-model-selection.ts 中,重试上下文(retryContext.isRetry)携带上一次的 tier,升级后 UI 会主动通知Tier escalation: light → standard (retry after failure)(#3962:模型变化必须可见)。还有一个值得注意的细节:若已处于 heavy(最高 tier),升级函数返回null,此时会保留上一次已升级的 tier,而不是让新一次的复杂度分类把模型静默降回更低的 tier(#4973)。

3.3budget_pressure:预算压力驱动的自动降级

当预算接近上限时,router 会逐步降低 tier。分类器classifyUnitComplexity()会接收当前预算使用比例(0.0-1.0),并在 applyBudgetPressure() 中按如下梯度降级:

已使用预算影响
< 50%不调整
50-75%Standard → Light
75-90%更激进地降级(除 heavy 外全部 → Light)
> 90%几乎所有工作都 → Light;连 Heavy 也降级到 Standard

注意最后一个区间:源码实现中当budgetPct >= 0.9时,heavy 也会被降到 standard("everything except replan-slice gets cheapest model"),比文档描述"只有 Heavy 保持在 Standard"更精确地反映了代码行为。降级发生时,ClassificationResult.downgraded置为true,reason 会追加(budget pressure: 87%)之类的说明。

3.4cross_provider:跨 provider 选最便宜

开启后,router 可以从你的主 provider 之外选择 model。它使用内置成本表(按每 1K input tokens 的近似美元价格,见MODEL_COST_PER_1K_INPUT,model-router.ts),在每个 tier 里找到最便宜的 model。要求目标 provider 已经正确配置。

getEligibleModels()在未显式指定tier_models时,会按 tier 过滤可用模型并按成本升序排序,因此eligible[0]就是该 tier 内最便宜的模型。关闭cross_provider时(cross_provider: false),findModelForTier()会把搜索范围限制在同 provider(仅保留claude-*前缀的模型,见 model-router.ts)。另一个连带行为:配置的 primary model 不可用(例如配置了 Anthropic 模型却在非 Anthropic provider 上运行)时,router 会寻找同 tier 的跨 provider 等价模型,并把它插入 fallback 链首位,保证路由在跨 provider 场景下依然可用。

3.5capability_routing:tier 内的能力评分开关

开启后(默认:true),router 会通过 capability scoring 在某个 tier 内选出"最适合"的 model,而不是永远只选最便宜的那个。设为false可恢复到纯 cheapest-in-tier 行为:

dynamic_routing: enabled: true capability_routing: false # 关闭评分,改用 tier 内最便宜的 model

在 resolveModelForComplexity() 中,评分路径有两个前提条件:capability_routing !== false且该 tier 的 eligible 模型数 > 1且提供了unitType。因此当 tier 内只有一个候选模型时,即便评分开启也会退化为 tier-only 路径。


四、Capability Profiles:7 维能力画像

每个 model 都有一个内置的capability profile,它是一个 7 维评分(0-100),表示该 model 在不同 task 类型下的能力强弱:

维度含义
coding代码生成和实现准确性
debugging诊断与修复错误的能力
research信息综合与主题探索能力
reasoning多步逻辑推理能力
speed延迟与吞吐(可视为能力深度的反向维度)
longContext处理大代码库和长文档的能力
instruction精确遵循结构化指令的能力

文档说明目前 9 个 models 带有内置 profile:claude-opus-4-6、claude-sonnet-4-6、claude-haiku-4-5、gpt-4o、gpt-4o-mini、gemini-2.5-pro、gemini-2.0-flash、deepseek-chat、o3。而当前仓库源码中的MODEL_CAPABILITY_PROFILES表(model-router.ts)已经扩展到 30+ 个模型,覆盖 Anthropic(opus/sonnet/haiku 各代)、OpenAI GPT 全系(含 gpt-4o/4.1、gpt-5 系列、o 系列推理模型)、Google Gemini 以及 DeepSeek。例如:

  • claude-opus-4-6:coding 95 / reasoning 95 / speed 30(深度优先、速度慢)
  • claude-haiku-4-5:coding 60 / speed 95(速度快、能力适中)
  • o3:reasoning 92 / speed 25(推理极强但吞吐低)
  • gemini-2.5-pro:longContext 90 / research 85(长上下文与信息综合见长)

没有内置 profile 的 models 会收到全维度均为 50 的默认分数。这是一个冷启动策略:未知模型可以参与竞争,但不会凭空占优(对应 scoreEligibleModels() 中{ coding: 50, ... }的兜底 profile)。从用户角度看,这类模型的路由行为和 capability scoring 引入前保持一致。

重要声明:这些 profiles 是启发式排序,不是 benchmark。它们表达的是大致的相对优势,而不是经过严格验证的 benchmark 结果(源码注释中也标注了如 gpt-5.5 的评分参考 OpenAI 官方 2026-04-23 公布的 eval 增量)。如果你很了解某个 model,可通过下面的用户覆盖项修正这些分值。


五、评分方式:加权平均与动态需求向量

tier 内的路由流程如下:

classify complexity tier ↓ filter eligible models for tier ↓ fire before_model_select hook (optional override) ↓ capability score eligible models ↓ select winner (or first eligible if scoring is disabled)

评分公式:各能力维度的加权平均

score = Σ(weight × capability) / Σ(weights)

这正是 scoreModel() 的实现:遍历需求向量的每个维度,累加weight × capability再除以总权重;若需求向量为空则返回中性分 50。

Task requirements 是动态的,不同 unit types 对维度的权重不同(源码中的BASE_REQUIREMENTS,model-router.ts):

Unit Type核心维度
execute-taskcoding (0.9)、instruction (0.7)、speed (0.3)
research-milestone/research-sliceresearch (0.9)、longContext (0.7)、reasoning (0.5)
plan-milestone/plan-slicereasoning (0.9)、coding (0.5)
replan-slicereasoning (0.9)、debugging (0.6)、coding (0.5)
complete-sliceinstruction (0.8)、speed (0.7)
run-uatinstruction (0.7)、speed (0.8)
reassess-roadmapreasoning (0.9)、research (0.5)
discuss-milestonereasoning (0.6)、instruction (0.7)

对于execute-task,computeTaskRequirements() 还会进一步根据 task metadata 微调需求:

  • 带有docs、config、readme、comment、typo、rename等 tag:提高 instruction 权重(instruction: 0.9、speed: 0.7、coding 降为 0.3)
  • 包含concurrency、compatibility等复杂度关键词:提高 debugging 和 reasoning 权重(各 0.9 / 0.8)
  • 包含migration、architecture等关键词:提高 reasoning 和 coding 权重(0.9 / 0.8)
  • 文件数较多(≥6)或估计行数较大(≥500):提高 coding 和 reasoning 权重(0.9 / 0.7)

平分时的决策:当两个 models 的得分相差不超过 2 分时,优先选择更便宜的那个;如果成本也相同,则按 model ID 字典序打破平局(确定性结果)。这条规则在 scoreEligibleModels() 的排序器里逐字实现:Math.abs(scoreDiff) > 2时按分数降序,否则按成本升序,成本相同按localeCompare字典序。


六、用户覆盖:用modelOverrides修正内置画像

如果你对某个 model 的能力认知比内置 profile 更准确,可以通过models配置里的modelOverrides修正:

{ "providers": { "anthropic": { "modelOverrides": { "claude-sonnet-4-6": { "capabilities": { "debugging": 90, "research": 85 } } } } } }

这些覆盖会与内置默认值进行深度合并:你只需覆盖指定维度,未指定的维度仍保留内置值。源码中 loadCapabilityOverrides() 负责从偏好配置提取覆盖项,scoreEligibleModels()对带覆盖的模型执行{ ...builtin, ...override }浅层合并(维度级别即"深合并")。

典型用法:如果你发现某个 model 在某一类工作上持续优于内置 profile,就覆盖对应维度,把 router 更积极地引导到该 model。例如上面把 claude-sonnet-4-6 的 debugging 提到 90、research 提到 85 后,它在 replan 与 research 类单元上的评分会显著上升,从而更频繁地被选中。


七、详细输出:verbose 模式下的决策日志

开启 verbose mode 时,router 会把自己的路由决策打印出来。如果使用了 capability scoring,日志会包含完整评分拆分:

Dynamic routing [S]: claude-sonnet-4-6 (capability-scored) — claude-sonnet-4-6: 82.3, gpt-4o: 78.1, deepseek-chat: 72.0

如果只使用了 tier 级路由(例如评分被禁用、只有一个符合条件的 model,或命中了路由守卫):

Dynamic routing [S]: claude-sonnet-4-6 (standard complexity, multiple steps)

路由决策中的selectionMethod字段会说明采用了哪种路径(对应 RoutingDecision 接口的selectionMethod):

  • "capability-scored":使用 capability scoring 选出了最终 model
  • "tier-only":使用了 tier 内最便宜的 model(或显式固定值)

此外,在评分路径下RoutingDecision还会携带capabilityScores(每个候选模型的得分表)与taskRequirements(本次使用的需求向量),方便调试;而wasDowngraded为 true 时,auto-model-selection.ts 会无条件向用户发送 UI 通知(#3962:模型被降级必须可见,而不仅仅在 verbose 日志里),通知文本会包含 tier 标签(L / S / H)与完整评分拆分。


八、扩展 Hook:before_model_select

扩展可以通过before_model_selecthook 拦截并覆盖 model 选择。

Hook 触发时机在tier 过滤之后(已知符合条件的 models),但在capability scoring 之前(尚未计算分数)。Hook 可以完全接管选择,也可以返回undefined,让 scoring 按默认逻辑继续。这在源码 auto-model-selection.ts 中实现:先计算 eligible 列表,再emitBeforeModelSelect(...),若返回了modelId则直接构造 hook 覆盖的 routingResult 并跳过整个 capability scoring。

注册处理器:

pi.on("before_model_select", async (event) => { const { unitType, unitId, classification, taskMetadata, eligibleModels, phaseConfig } = event; // 自定义路由策略:research 一律优先用 gemini if (unitType.startsWith("research-")) { const gemini = eligibleModels.find(id => id.includes("gemini")); if (gemini) return { modelId: gemini }; } // 返回 undefined,让 capability scoring 继续 return undefined; });

事件负载:

字段类型说明
unitTypestring当前派发单元类型(例如"execute-task")
unitIdstring此次单元派发的唯一标识符
classification{ tier, reason, downgraded }复杂度分类结果
taskMetadataRecord<string, unknown> \| undefined从单元 plan 中提取出的 task 元数据
eligibleModelsstring[]符合该 tier 的 models
phaseConfig{ primary, fallbacks } \| undefined用户为该 phase 配置的 model

返回值:{ modelId: string }表示覆盖默认选择;返回undefined表示交给 capability scoring。

第一个覆盖者生效:如果多个扩展都注册了处理器,第一个返回非undefined的处理器获胜,后续处理器不会再被调用。另注意:hooks配置项控制的是 post-unit hooks 是否也应用路由,而before_model_select属于扩展 API(ADR-004 / D-03 的实现),两者是独立机制;若routingConfig.hooks === false,则该 hook 不会触发(见 auto-model-selection.ts)。


九、复杂度分类:纯启发式规则

工作单元通过纯启发式规则分类,不涉及 LLM 调用,耗时通常低于 1ms(complexity-classifier.ts 全程只做正则匹配与文件读取)。

9.1 Unit Type 默认值

Unit Type默认 Tier
run-uatLight
hook/*Light
research-*、discuss-*Standard
complete-sliceStandard(v2.52+ 从 Light 上调,避免大内联上下文打到最便宜模型,见 #4520)
execute-taskStandard(可被 task 分析升级)
plan-*、replan-slice、reassess-roadmapHeavy
complete-milestoneStandard(instruction 0.8 / reasoning 0.5)

9.2 Task Plan 分析

对于execute-task单元,分类器会分析 task plan(读取{milestone}/slices/{slice}/tasks/{task}-PLAN.md,见 extractTaskMetadata()):

信号简单 → Light复杂 → Heavy
Step 数量≤ 3≥ 8
文件数≤ 3(Light 还要求 ≤1 且非新文件)≥ 6
描述长度< 500 chars> 2000 chars
代码块数—≥ 5
复杂度关键词无≥ 2 个
依赖数—≥ 3

源码中的实际阈值与文档表格略有出入(以源码为准):dependencyCount >= 3、fileCount >= 6、estimatedLines >= 500、codeBlockCount >= 5、complexityKeywords >= 2直接判 Heavy;1 个复杂度关键词判 Standard;单文件非新建文件的修改判 Light。

复杂度关键词:research、investigate、refactor、migrate、integrate、complex、architect、redesign、security、performance、concurrent、parallel、distributed、backward compat。源码正则还会从 plan 内容中自动检测migration、architecture、security、performance、concurrency、compatibility等信号并填充到complexityKeywords。

此外,plan-*单元还有专门的 plan 复杂度分析:milestone 级规划直接判 Heavy;slice 级规划若其RESEARCH.md超过 200 行也会上调到 Heavy。

9.3 自适应学习

路由历史.gsd/routing-history.json(源码中定义为HISTORY_FILE = "routing-history.json",见 routing-history.ts)会按 unit type 和 tier 记录成功 / 失败情况。如果某种模式下某个 tier 的失败率超过 20%,未来相似分类会自动上调一个 tier。用户反馈(over/under/ok,通过/gsd:rate-unit记录)的权重是自动结果的2 倍(源码FEEDBACK_WEIGHT = 2):

  • rating: "over"(模型能力过剩)→ 反馈让该 tier 降级倾向
  • rating: "under"(模型能力不足)→ 反馈让该 tier 升级倾向

反馈数组上限 200 条(超出后裁剪最旧的)。自适应调整逻辑在 classifyUnitComplexity() 中:仅当getAdaptiveTierAdjustment()返回的 tier 高于当前分类时才会采用(只升不降),并在 reason 中标注(adaptive: high failure rate at standard)。


十、与 Token Profile 的关系

动态路由和 token profile 是互补的:

  • Token profiles(budget/balanced/quality)控制阶段跳过和上下文压缩
  • Dynamic routing控制每个工作单元在对应 phase 内的 model 选择

两者同时开启时,token profile 负责给出基础模型集(phase 配置的 primary + fallbacks),dynamic routing 再在这些基础之上做进一步优化。budgettoken profile + dynamic routing 组合能带来最大的成本节省:token profile 通过压缩上下文和跳过阶段削减 token 总量,动态路由则通过降价模型削减单价,两者叠加效果最显著。


十一、成本表

Router 内置了一张常见 models 的成本表(源码中为每 1K input tokens 的近似美元价格,model-router.ts),用于跨 provider 成本比较。文档给出的成本单位为每百万 tokens(input / output):

ModelInputOutput
claude-haiku-4-5$0.80$4.00
claude-sonnet-4-6$3.00$15.00
claude-opus-4-6$15.00$75.00
gpt-4o-mini$0.15$0.60
gpt-4o$2.50$10.00
gemini-2.0-flash$0.10$0.40

源码成本表还覆盖了gpt-4.1、gpt-5系列、o4-mini、deepseek-chat等更多模型,并且对未知模型采用成本兜底值 999(getModelCost(),model-router.ts)——即未知成本按"昂贵"处理,避免把任务路由给成本未知的便宜模型。这张成本表仅用于比较,实际计费仍然来自你所使用的 provider。


结语:从配置到源码的完整决策链

动态模型路由的价值在于"把每一分 token 预算花在刀刃上":light/standard/heavy 三级分类 + capability scoring 的组合,让 slice completion、UAT 这类轻量工作稳定落在 Haiku 级模型上,而 replan、roadmap reassessment 这类重推理工作保留 Opus 级质量;预算压力与失败升级两条自适应通道又保证了成本失控时自动收敛、质量不足时自动提升。若要进一步定制,modelOverrides修正画像、before_model_selectHook 接管选型、/gsd:rate-unit反馈驱动自适应学习,三层手段覆盖了从个人经验到团队策略的全部诉求。相关测试用例可参见 capability-router.test.ts、model-router.test.ts、dynamic-routing-default.test.ts 与 guided-flow-dynamic-routing.test.ts,可作为进一步理解路由边界行为的入口。

  • 人工智能
  • AI Agent
  • 代码智能体
  • Agent 编排
  • CLI
  • AI 应用

【免费下载链接】gsd-2

A powerful meta-prompting, context engineering and spec-driven development system that enables agents to work for long periods of time autonomously without losing track of the big picture

项目地址:https://gitcode.com/gh_mirrors/gs/gsd-2
点击查看免费下载
上一篇:IoT-For-Beginners 实战:在 Raspberry Pi 上接入 Grove GPS Air530 传感器并读取 NMEA 定位数据
下一篇:Unreleased

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 3:38:34

AI编程工具Cursor实战:用TaoToken统一Key接入并验证配置文件

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 3:37:51

Zephyr BSP: 47-BSP Customer SDK

BSP 是公司内部平台基础设施,Customer SDK 才是客户开发产品的入口。SDK 通过「稳定接口边界」把内部实现与客户代码解耦,客户只依赖受版本承诺保护的 Public API。一个完整 SDK 包含 Toolchain、Zephyr/BSP、Board Support、SDK API、Samples、Docs 与 Build/Flash/Debug 工…

作者头像 李华