☰
GSD-Core 按阶段类型选择模型(Per-Phase-Type Model Selection):配置、解析优先级与源码实现
2026/10/10 1:40:39 网站建设 项目流程

【免费下载链接】gsd-core

Git. Ship. Done - Core

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

导读

本文讲解 GSD-Core(Git. Ship. Done - Core)自 v1.41 引入的**按阶段类型选择模型(Per-Phase-Type Model Selection)**能力:通过.planning/config.json中的models配置块,你可以不记忆 30+ 个 Agent 的完整分类体系,直接用planning、research、execution、verification等阶段槽位粗粒度地调整每个阶段使用的模型档位。读完本文,你将掌握models.<phase_type>六个合法槽位、opus/sonnet/haiku/inherit四种取值、与model_overrides/model_profile/dynamic_routing组合时的五层解析优先级,并能从源码与测试层面理解其底层解析链路、校验规则与向后兼容保证。

该特性由 issue #3023 与 settings-management 文档,源码实现集中在 src/model-resolver.cts 与 src/model-catalog.cts,回归测试见 tests/model-resolver.test.cjs。

一、为什么需要按阶段类型选择模型

GSD-Core 的每个阶段由多个专用 Agent 协作完成,例如规划阶段由gsd-planner、gsd-roadmapper、gsd-pattern-mapper承担,验证阶段由gsd-verifier、gsd-plan-checker、gsd-code-reviewer等八个 Agent 承担。在引入本特性之前,调整模型档位只有两条路:

  • 按 Agent 的model_overrides:精确但啰嗦。你必须记住gsd-codebase-mapper属于 research、gsd-doc-writer属于 execution,才能写出针对单个 Agent 的覆盖;
  • 全局model_profile:粗放且一刀切。一个档位策略作用于全部 Agent,无法表达"规划用强模型、执行用标准模型"这类典型成本分配诉求。

models配置块恰好填补两者之间的空档:以阶段类型为粒度(planning / research / execution / verification),无需学习完整 Agent 分类体系即可表达"规划阶段用 Opus、其余阶段用 Sonnet"这样的意图,代码量只要两行 JSON。

从源码结构看,src/model-catalog.cts 中的AGENT_TO_PHASE_TYPE正是把每个 Agent 静态映射到唯一阶段类型的真相来源(取自model-catalog.json中每个 Agent 的phaseType字段),VALID_PHASE_TYPES则是合法阶段槽位的集合,二者共同支撑了"阶段级调参"这一抽象。

二、配置项:.planning/config.json中的models块

2.1 配置键与存放位置

特性对应的配置键为models,位于项目的.planning/config.json(工作流/项目级覆盖路径由planningDir解析,可参考 src/planning-workspace.cts)。models是动态键模式(dynamic key pattern),合法槽位由 schema manifest 严格约束。

在 config-schema.manifest.json 的动态键模式中,可以找到该特性的校验规则:

{ "topLevel": "models", "source": "^models\\.(planning|discuss|research|execution|verification|completion)$", "description": "models.<planning|discuss|research|execution|verification|completion>" }

也就是说,只有六个命名槽位被接受:planning、discuss、research、execution、verification、completion。任何其他阶段类型(如models.deployment)都会被 schema 拒绝(见下文"校验规则")。该 manifest 由 src/config-schema.cts 经 src/configuration.cts 加载,是isValidConfigKey校验与config-set命令的单一事实来源。

2.2 完整配置示例

沿用官方文档 docs/CONFIGURATION.md 中的示例,一个同时使用model_profile、models与model_overrides的完整配置如下:

{ "model_profile": "balanced", "models": { "planning": "opus", "discuss": "opus", "research": "sonnet", "execution": "opus", "verification": "sonnet", "completion": "sonnet" }, "model_overrides": { "gsd-codebase-mapper": "haiku" } }

该配置的效果:所有 research 阶段 Agent 解析为sonnet,除了gsd-codebase-mapper被按 Agent 覆盖钉死为haiku;planning / discuss / execution 阶段全部为opus;verification 与 completion 为sonnet。

2.3 阶段类型 → Agent 映射表

models.<phase_type>的每个槽位会应用到一组 Agent。下表与 docs/CONFIGURATION.md 及特性文档 docs/features/per-phase-type-model-selection.md 保持一致:

阶段类型(Slot)归属 Agent
planninggsd-planner、gsd-roadmapper、gsd-pattern-mapper
discussgsd-assumptions-analyzer
researchgsd-phase-researcher、gsd-project-researcher、gsd-research-synthesizer、gsd-codebase-mapper、gsd-ui-researcher
executiongsd-executor、gsd-debugger、gsd-doc-writer
verificationgsd-verifier、gsd-plan-checker、gsd-integration-checker、gsd-nyquist-auditor、gsd-ui-checker、gsd-ui-auditor、gsd-doc-verifier、gsd-code-reviewer
completion(保留给未来子 Agent,当前无映射)

注意:discuss与completion两个槽位目前被 schema 接受,但尚无 Agent 映射到它们——今天设置它们是一个 no-op(不会报错,也不产生效果),这是为未来子 Agent 预留的向前兼容槽位(对应需求 REQ-PHASE-MODELS-03)。

从实现层面看,这张表不是手写的两份文档,而是由model-catalog.json中每个 Agent 的phaseType元数据统一驱动:src/model-catalog.cts 通过

export const AGENT_TO_PHASE_TYPE: Record<string, string> = Object.fromEntries( Object.entries(_catalog.agents).map(([agent, meta]) => [agent, meta.phaseType]) );

生成映射,因此文档与代码不会漂移。测试 tests/model-resolver.test.cjs 中的#3023 phase-type schema测试组还专门断言:MODEL_PROFILES中每个 Agent 都必须有 phase-type 赋值,且赋值必须是六个合法槽位之一。

2.4 合法取值

models.<phase_type>只接受档位别名(tier alias),不接受完整模型 ID:

取值效果
"opus"标准档位——运行时解析会将该阶段 Agent 映射到当前活跃运行时的 Opus 档模型
"sonnet"标准档位——映射到活跃运行时的 Sonnet 档模型
"haiku"标准档位——映射到活跃运行时的 Haiku 档模型
"inherit"该阶段 Agent 跟随会话模型,语义与model_profile: "inherit"一致

重要限制:如果你需要完整模型 ID(例如"openai/gpt-5"、"google/gemini-2.5-pro"),不要写在models.*里,而应使用按 Agent 的model_overrides。models.*刻意设计为"仅档位",目的是保证在 Codex / OpenCode / Antigravity CLI 等非 Claude 运行时上,运行时感知(runtime-aware)的档位映射依然正确——完整 ID 会破坏这种跨运行时可移植性。

该限制在源码中有对应的硬性守卫:computeProfileTier(src/model-resolver.cts)读取config['models'][phaseType]后,用VALID_TIERS.has(phaseTypeTier)校验——VALID_TIERS由model-catalog.json的adaptiveTierMap(heavy→opus、standard→sonnet、light→haiku)加'inherit'派生而来。因此,非法档位值会落入 profile 兜底解析,不会污染运行时档位解析链。

三、解析优先级:五层从上到下依次生效

models.<phase_type>处于解析链的第三层。完整的解析优先级(从高到低)为:

1. model_overrides[<agent>] ← 按 Agent;可写完整 ID;定向例外 2. dynamic_routing.tier_models[<tier>] ← 启用时生效(见 Dynamic Routing) 3. models[<phase_type>] ← 粗粒度阶段级档位(本特性) 4. model_profile(每个 Agent 一列) ← 全局档位策略 5. Runtime default ← 兜底

五层自上而下组合:model_profile是基础档位;models[<phase_type>]在阶段层面覆盖之;dynamic_routing(启用时)在软失败时按尝试次数升级档位;model_overrides[<agent>]在最顶层雕刻按 Agent 的例外;当没有任何一层生效时,回落到运行时默认档位。

在 2.2 的示例中,五个 research Agent 全部解析为sonnet,唯独gsd-codebase-mapper被按 Agent 覆盖钉为haiku。dynamic_routing默认关闭——当enabled: false或整块省略时,本节行为与未引入该特性之前完全一致。

3.1 优先级在源码中的落地位置

resolveModelInternal(src/model-resolver.cts)严格按上述顺序实现:

  1. Step 1:读取config['model_overrides'],命中即返回(Claude 运行时还会经mapClaudeOverrideForRuntime把完整 Claude ID 折叠回档位别名);
  2. Step 2:computeProfileTier(config, agentType)计算基础档位——其中正是读取config['models'][phaseType]并做VALID_TIERS校验、命中则直接返回的阶段级档位,未命中才回落到MODEL_PROFILES[agent][profile];
  3. Step 2.5:model_policy预设(provider 中立策略)解析;
  4. Step 3:非 Claude 运行时的运行时感知档位映射(_resolveRuntimeTier);
  5. Step 4 / 4.5 / 4.75:resolve_model_ids: "omit"门、Claude 档位覆盖、dynamic_routing.tier_models查询;
  6. Step 5:profile 兜底查询,最终输出档位别名(或inherit)。

其中步骤 4.75 的注释明确引用了特性文档的优先级约定:"model_overrides永远优先;dynamic_routing.tier_models[<tier>]解析在models.<phase_type>与model_profile之上"。因此dynamic_routing.tier_models恰好落在本特性与 profile 之间,与 3 的优先级表完全对应。

3.2 关键语义细节:phase-type 优先于 profile=inherit

一个容易被忽视的语义:models[<phase_type>]优先于model_profile: "inherit"。修复前的缺陷是:当model_profile='inherit'且models.execution='opus'时,profile 的短路逻辑先于阶段级覆盖触发,导致gsd-executor错误解析为inherit,违反"models[phase_type] 高于 model_profile"的文档约定。该缺陷在测试 tests/model-resolver.test.cjs 中以CR Major级别回归锁定:

test('phase-type override wins over profile=inherit (CR Major) — model resolver', () => { writeConfig(projectDir, { model_profile: 'inherit', models: { execution: 'opus' }, }); // gsd-executor (execution) must get the phase-type opus, not inherit. assert.equal(resolveModelInternal(projectDir, 'gsd-executor'), 'opus'); });

同时,没有设置槽位的 Agent 在model_profile: "inherit"下仍然继承会话模型,两条规则互不干扰。

四、校验规则:schema 拒绝、解析器宽容

4.1config-set命令侧(严格校验)

通过gsd config-set写入配置时,schema 严格拒绝未知阶段类型:

$ gsd config-set models.deployment opus Error: 'models.deployment' is not a valid config key # 合法写法: $ gsd config-set models.research sonnet

错误信息来自config-schema的isValidConfigKey校验(对应需求 REQ-PHASE-MODELS-01:六个命名models.*槽位被config-schema接受;config-set拒绝未知阶段类型)。

4.2 直接编辑配置文件侧(宽容兜底)

直接手改.planning/config.json则宽松得多:解析器遇到不认识的取值会静默忽略并回落到 profile 档位,而不是报错中断。因此一个笔误(如haiku3)不会悄悄破坏档位解析。这是文档与测试共同确认的行为:

  • 测试unrecognized tier value falls through to profile (typo safety):models: { research: 'haiku3' }落到balanced档位的sonnet;
  • 测试full model ID in models.<phase_type> is rejected; falls through to profile:models: { research: 'openai/gpt-5' }同样回落,不会把完整 ID 注入运行时档位解析链。

两种校验策略各有分工:CLI 入口(config-set)严格到拒绝即报错,配置文件入口宽容到"坏值即回落",保证既有配置在升级后行为不变。

五、向后兼容保证:没有models块时行为逐字节不变

特性需求 REQ-PHASE-MODELS-02 明确要求:未包含models块的配置,行为与 v1.41 之前逐字节一致。这一点由源码的读取方式与测试双重保证:

  • computeProfileTier中,configModels为空或phaseType未命中时,phaseTypeTier为undefined,VALID_TIERS.has(undefined)为 false,直接进入 profile 查询分支——整体行为等同于没有models配置;
  • 测试empty models block is a no-op与no models block at all is a no-op分别验证models: {}和完全省略models两种情形下,gsd-phase-researcher仍解析为sonnet、gsd-planner仍解析为opus(与balancedprofile 默认一致)。

这一"缺省即无感"的设计,让存量项目无需任何迁移即可升级到 v1.41+。

六、实战:如何选择配置粒度

官方文档给出了一张"按需求选工具"的对照表,可直接作为日常决策依据:

你的诉求使用
一个全局档位策略("处处 balanced")model_profile
粗粒度阶段级调参("规划用 Opus")models.<phase_type>
按 Agent 精确控制("强制 codebase mapper 用 haiku")model_overrides[<agent>]
为某个特定 Agent 指定完整模型 IDmodel_overrides[<agent>]: "openai/gpt-5"

这些方式可以自由混用——只要符合第三节的五层优先级规则,任何重叠都会被确定性地解析,不存在歧义。

典型成本分配实践:规划与讨论阶段是需要深度推理的"重脑力"环节(gsd-planner、gsd-roadmapper、gsd-assumptions-analyzer等 Agent 在model-catalog.json中本就归属heavy默认档位),可以用models.planning: "opus"、models.discuss: "opus"保证质量;research / verification 属于高吞吐的"标准负载",用models.research: "sonnet"、models.verification: "sonnet"控制成本;如果某个高频低风险的 Agent(如gsd-codebase-mapper)想进一步省钱,再用model_overrides钉到haiku。三层配合即可在"质量—成本—精确度"三角中自由取点。

七、相关能力与阅读路径

  • 本文的权威长文档:Per-Phase-Type Models(docs/CONFIGURATION.md),包含完整的配置示例、取值表、优先级表与校验示例;
  • 配置项速查表:settings-management(docs/features/settings-management.md);
  • 实现源码:src/model-resolver.cts(computeProfileTier、resolveModelInternal为核心读取与解析点)、src/model-catalog.cts(AGENT_TO_PHASE_TYPE、VALID_PHASE_TYPES、VALID_TIERS的派生来源)、gsd-core/bin/shared/model-catalog.json(phaseTypes、每个 Agent 的phaseType元数据);
  • Schema 校验来源:gsd-core/bin/shared/config-schema.manifest.json(models.<phase_type>动态键模式);
  • 回归测试:tests/model-resolver.test.cjs(#3023系列:阶段级覆盖、per-agent 优先、typo 回落、inherit 语义、空块 no-op、CR Major 修复等)。

如果你需要与"失败时自动升级档位"组合使用,可进一步阅读 Dynamic Routing with Failure-Tier Escalation(docs/CONFIGURATION.md) 中的dynamic_routing章节——它定义了tier_models[<tier>]如何在models.<phase_type>之上生效,以及max_escalations、escalate_on_failure等配套参数。

【免费下载链接】gsd-core

Git. Ship. Done - Core

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

相关推荐

上一篇:Rampart安全审计:深入分析系统的隐私保护能力和局限性
下一篇:Nightwatch.js 跨平台测试:Windows/macOS/Linux 兼容性保障

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

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

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

立即咨询