Final rebrand: rename remaining Rust source file to complete the gsd → forge transition. All parser references already use forge_parser after earlier commits. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
14 KiB
Token 优化
引入于 v2.17.0
SF.17 引入了一套协同工作的 token 优化系统,在大多数工作负载下可以在不牺牲输出质量的前提下,将 token 使用降低 40-60%。这套系统由三部分构成:token profiles、context compression 和 基于复杂度的 task 路由。
Token Profiles
Token profile 是一个单一偏好项,用来统一协调 model 选择、阶段跳过和上下文压缩级别。在偏好设置中这样配置:
---
version: 1
token_profile: balanced
---
可用的 profile 有三个:
budget:最大节省(降低 40-60%)
面向成本敏感型工作流。它会使用更便宜的 models,跳过可选阶段,并把 dispatch 上下文压缩到最低必要程度。
| 维度 | 设置 |
|---|---|
| Planning model | Sonnet |
| Execution model | Sonnet |
| Simple task model | Haiku |
| Completion model | Haiku |
| Subagent model | Haiku |
| Milestone research | 跳过 |
| Slice research | 跳过 |
| Roadmap reassessment | 跳过 |
| Context inline level | Minimal:丢弃 decisions、requirements、额外 templates |
适合:原型开发、小项目、已充分理解的代码库、强调成本控制的迭代。
balanced:智能默认值(默认)
默认 profile。保留关键阶段,跳过那些对大多数项目边际收益不高的阶段,并采用标准级别的上下文压缩。
| 维度 | 设置 |
|---|---|
| Planning model | 用户默认值 |
| Execution model | 用户默认值 |
| Simple task model | 用户默认值 |
| Completion model | 用户默认值 |
| Subagent model | Sonnet |
| Milestone research | 执行 |
| Slice research | 跳过 |
| Roadmap reassessment | 执行 |
| Context inline level | Standard:保留关键上下文,丢弃低信号附加内容 |
适合:大多数项目、日常开发。
quality:完整上下文(不压缩)
所有阶段都会运行。所有上下文产物都会被内联。没有捷径。
| 维度 | 设置 |
|---|---|
| 所有 models | 用户配置的默认值 |
| 所有阶段 | 执行 |
| Context inline level | Full:全部内联 |
适合:复杂架构、需要深度 research 的 greenfield 项目、关键生产环境工作。
Context Compression
每个 token profile 都会映射到一个 inline level,它控制在 dispatch prompt 里预加载多少上下文:
| Profile | Inline Level | 包含内容 |
|---|---|---|
budget |
minimal |
Task plan、关键历史 summaries(截断)。不包含 decisions register、requirements、UAT template、secrets manifest。 |
balanced |
standard |
Task plan、历史 summaries、slice plan、roadmap 摘要。不包含部分辅助 templates。 |
quality |
full |
全部内容:所有 plans、summaries、decisions、requirements、templates 和根文件。 |
压缩如何工作
Dispatch prompt builder 接受一个 inlineLevel 参数。在不同级别下,特定产物会被按规则裁剪:
Minimal 级别的裁剪:
buildExecuteTaskPrompt:丢弃 decisions template,并把历史 summaries 截断到只保留最近一个buildPlanMilestonePrompt:丢弃PROJECT.md、REQUIREMENTS.md、decisions 以及secrets-manifest等补充 templatesbuildCompleteSlicePrompt:丢弃 requirements 和 UAT template 的内联buildCompleteMilestonePrompt:丢弃根级 SF 文件内联buildReassessRoadmapPrompt:丢弃 project、requirements 和 decisions 文件
这些裁剪是累积式的:standard 会丢掉一部分,minimal 会丢掉更多;full 则保留全部上下文(也就是 v2.17 之前的行为)。
覆盖 Inline Level
Inline level 由 token_profile 推导而来。如果你想独立于 profile 控制阶段行为,请使用 phases 偏好设置:
---
version: 1
token_profile: budget
phases:
skip_research: false # 覆盖:即使是 budget,也执行 research
---
显式设置的 phases 总是优先于 profile 默认值。
基于复杂度的 Task 路由
当启用 dynamic routing 时,SF 会根据复杂度对每个 task 做分类,并将其路由到合适的 model tier。简单的文档修复会使用更便宜的模型,而复杂的架构工作会获得所需的推理能力。
前提条件: Dynamic routing 需要在偏好设置里显式配置
models。如果没有models段,routing 会被跳过,所有 phases 都会使用会话启动时的 model。Token profiles 会自动设置models。
上限行为: 当 dynamic routing 启用时,每个 phase 中配置的 model 充当的是上限,而不是固定绑定。Router 可以为更简单的工作降级到更便宜的 model,但绝不会超过你配置的 model。
分类如何工作
Tasks 会通过分析 task plan 来分类:
| 信号 | Simple | Standard | Complex |
|---|---|---|---|
| Step 数量 | ≤ 3 | 4-7 | ≥ 8 |
| 文件数 | ≤ 3 | 4-7 | ≥ 8 |
| 描述长度 | < 500 chars | 500-2000 | > 2000 chars |
| 代码块数 | — | — | ≥ 5 |
| 信号词 | 无 | 任意出现 | — |
会阻止判定为 simple 的信号词: research、investigate、refactor、migrate、integrate、complex、architect、redesign、security、performance、concurrent、parallel、distributed、backward compat、migration、architecture、concurrency、compatibility。
空 plan 或格式错误的 plan 会默认归类到 standard(偏保守的选择)。
Unit Type 默认值
非 task 单元也有内置的 tier 分配:
| Unit Type | 默认 Tier |
|---|---|
complete-slice、run-uat |
Light |
research-*、plan-*、execute-task、complete-milestone |
Standard |
replan-slice、reassess-roadmap |
Heavy |
hook/* |
Light |
Model 路由
每个 tier 会映射到某类 model 配置:
| Tier | 对应 Model Phase Key | 常见 Model |
|---|---|---|
| Light | completion |
Haiku(budget)/ 用户默认值 |
| Standard | execution |
Sonnet / 用户默认值 |
| Heavy | execution |
Opus / 用户默认值 |
如果配置了 execution_simple,simple tasks 会优先使用它。budget profile 会自动把该键设为 Haiku。
预算压力
当接近预算上限时,分类器会自动降低 tier:
| 已使用预算 | 影响 |
|---|---|
| < 50% | 不调整 |
| 50-75% | Standard → Light |
| 75-90% | Standard → Light |
| > 90% | 除 Heavy 之外全部 → Light;Heavy → Standard |
这种逐步降级方式能尽量把最复杂工作的模型质量保留下来,同时随着预算逼近上限逐步降低成本。
自适应学习(Routing History)
SF 会随着时间推移记录每个 tier 分配的成功 / 失败情况,并据此调整未来的分类。它默认自动生效,并持久化在 .sf/routing-history.json 中。
工作方式
- 每个工作单元完成后,系统会把结果(成功 / 失败)记录到对应的 unit type 和 tier 上
- 结果会按 pattern 跟踪,例如
execute-task或execute-task:docs,并维护最近 50 条的滚动窗口 - 如果某个 pattern 下某个 tier 的失败率超过 20%,未来相同 pattern 的分类会自动上调一个 tier
- 系统也支持更细粒度的 tag pattern,例如
execute-task:test和execute-task:frontend
用户反馈
你可以通过 /sf rate 为最近完成的工作单元提交反馈:
/sf rate over # model 太强了,下次更倾向便宜一点
/sf rate ok # model 选得合适,不调整
/sf rate under # model 太弱了,下次更倾向强一点
这些反馈的权重是自动结果的 2 倍。要求 dynamic routing 已启用(最近完成的单元必须带有 tier 数据)。
数据管理
# Routing history 按项目存储
.sf/routing-history.json
# 清空历史以重置自适应学习
# (通过 routing-history 模块 API 完成)
反馈数组最多保留 200 条。每个 pattern 的结果统计使用 50 条滚动窗口,以防陈旧数据长期主导判断。
配置示例
成本优先配置
---
version: 1
token_profile: budget
budget_ceiling: 25.00
models:
execution_simple: claude-haiku-4-5-20250414
---
使用自定义 Models 的平衡配置
---
version: 1
token_profile: balanced
models:
planning:
model: claude-opus-4-6
fallbacks:
- openrouter/z-ai/glm-5
execution: claude-sonnet-4-6
---
面向关键工作的高质量配置
---
version: 1
token_profile: quality
models:
planning: claude-opus-4-6
execution: claude-opus-4-6
---
按阶段覆盖
token_profile 会设置默认值,但显式偏好始终优先:
---
version: 1
token_profile: budget
phases:
skip_research: false # 覆盖:保留 milestone research
models:
planning: claude-opus-4-6 # 覆盖:即使是 budget profile,planning 也用 Opus
---
这些机制如何协同
PREFERENCES.md
└─ token_profile: balanced
├─ resolveProfileDefaults() → model 默认值 + phase 跳过默认值
├─ resolveInlineLevel() → standard
│ └─ prompt builders 根据 level 决定纳入哪些上下文
├─ classifyUnitComplexity() → 路由到 execution / execution_simple model
│ ├─ task plan 分析(steps、files、signals)
│ ├─ unit type 默认值
│ ├─ budget pressure 调整
│ ├─ 从 routing-history.json 做自适应学习
│ └─ capability scoring(当 `capability_routing: true` 时)
│ └─ 7 维 model profile × task requirement vectors
└─ context_management
├─ observation masking(before_provider_request hook)
├─ tool result truncation(tool_result_max_chars)
└─ phase handoff anchors(注入 prompt builders)
Profile 会在 dispatch pipeline 的起点解析一次,并一路向下流动。每一层上,显式偏好都优先于 profile 默认值。
Observation Masking
引入于 v2.59.0
在自动模式会话中,tool results 会不断堆积在会话历史里并占用上下文窗口。Observation masking 会在每次 LLM 调用前,把早于最近 N 个 user turns 的 tool result 内容替换成轻量占位符。这样可以在不增加任何 LLM 开销的前提下减少 token 使用:不需要额外总结调用,也不会带来额外延迟。
Observation masking 在自动模式中默认开启。可通过偏好设置控制:
context_management:
observation_masking: true # 默认:true(设为 false 可关闭)
observation_mask_turns: 8 # 保留最近 8 个 user turns 内的结果(范围:1-50)
tool_result_max_chars: 800 # 单个 tool result 超过该长度时进行截断
工作方式
- 每次 provider request 之前,
before_provider_requesthook 会检查 messages 数组 - 早于阈值的 tool results(
toolResult、bashExecution)会被替换成[result masked — within summarized history] - 最近的 tool results(仍在保留窗口内)会完整保留
- 所有 assistant 和 user messages 始终保留,只有 tool result 内容会被 masking
它与现有的 compaction 系统配套:masking 负责减少两次 compaction 之间的上下文压力,而 compaction 负责在窗口填满时执行完整上下文重置。
Tool Result Truncation
单个 tool result 如果超过 tool_result_max_chars(默认 800),会被加上 …[truncated] 标记后截断。这可以防止某一次特别大的工具输出独占上下文窗口。
Phase Handoff Anchors
引入于 v2.59.0
当自动模式在 phases 之间切换(research → planning → execution)时,系统会把结构化 JSON anchors 写到 .sf/milestones/<mid>/anchors/<phase>.json。下游 prompt builders 会自动注入这些 anchors,让下一阶段继承前一阶段的意图、决策、阻塞点和下一步,而不必重新从 artifact 文件里推断。
这能减少上下文漂移,也就是企业级 agent 失败案例中最常见的一类问题:agent 在 phase 边界上丢失了之前的决策脉络。
Anchors 会在 research-milestone、research-slice、plan-milestone 和 plan-slice 成功完成后自动写入,不需要任何配置。
Prompt Compression
引入于 v2.29.0
SF 可以在退回到 section-boundary truncation 之前,先做确定性的 prompt compression。这样在上下文超预算时,可以保留更多信息。
压缩策略
在偏好设置中配置:
---
version: 1
compression_strategy: compress
---
可用策略有两个:
| 策略 | 行为 | 默认适用对象 |
|---|---|---|
truncate |
在边界处整段丢弃 section(v2.29 之前的行为) | quality profile |
compress |
先做启发式文本压缩,如果仍超预算,再截断 | budget 和 balanced profiles |
Compression 会确定性地去掉冗余空白、缩短啰嗦表达、去重重复内容并删除低信息量样板文本,不涉及任何 LLM 调用。
上下文选择
控制文件如何内联进 prompt:
---
version: 1
context_selection: smart
---
| 模式 | 行为 | 默认适用对象 |
|---|---|---|
full |
内联完整文件 | balanced 和 quality profiles |
smart |
对大文件(>3KB)使用 TF-IDF 语义分块,只纳入相关部分 | budget profile |
结构化数据压缩
在 budget 和 balanced 的 inline level 下,decisions 和 requirements 会被格式化成更紧凑的表示方式,相比完整 markdown tables 可节省 30-50% tokens。
Summary Distillation
如果某个 slice 有 3 个以上依赖 summary,且总量超过 summary 预算,SF 会先提取结构化核心数据(provides、requires、key_files、key_decisions),丢弃冗长 prose 段落,然后才会退回到 section-boundary truncation。
Cache Hit Rate Tracking
指标账本现在会为每个工作单元记录 cacheHitRate(输入 tokens 中来自缓存的比例),并提供 aggregateCacheHitRate() 用于统计整场会话的缓存表现。