模型角色系统指南¶
Flyto Agent Engine 的模型角色抽象和管理系统.
目录¶
设计目标¶
- 不硬编码模型 ID -- 业务逻辑不直接引用
claude-sonnet-4-6等具体 ID,而是引用角色RoleMain - 角色抽象 -- 不同用途使用不同模型,通过角色映射统一管理
- 运行时可修改 -- 线程安全的 ModelRegistry,支持运行时切换模型
- 第三方模型 -- 支持注册任意模型配置,不限于预置模型
四种角色¶
| 角色 | 常量 | 用途 | 典型场景 |
|---|---|---|---|
| Main | config.RoleMain |
主对话模型 | 用户直接交互,工具调用决策,代码生成 |
| Fast | config.RoleFast |
快速/廉价模型 | 上下文压缩摘要,工具结果摘要,命令分类 |
| Thinking | config.RoleThinking |
深度思考模型 | 复杂推理,安全分析,架构决策 |
| Embed | config.RoleEmbed |
嵌入模型 | 语义搜索(预留,当前未使用) |
角色使用场景¶
用户输入 "重构这个模块"
│
├── RoleMain ──► 理解任务、规划步骤、调用工具、生成代码
│
├── RoleFast ──► 压缩旧对话历史为摘要(节省成本)
│ 工具输出过长时生成简短摘要
│
└── RoleThinking ──► 分析复杂的重构方案(如果启用 extended thinking)
成本对比¶
以 100K input tokens + 10K output tokens 为例:
| 角色 | 默认模型 | 输入成本 | 输出成本 | 总计 |
|---|---|---|---|---|
| Main | claude-sonnet-4-6 | $0.30 | $0.15 | $0.45 |
| Fast | claude-haiku-4-5 | $0.08 | $0.04 | $0.12 |
| Thinking | claude-sonnet-4-6 | $0.30 | $0.15 | $0.45 |
Fast 模型用于摘要等内部任务,节省约 73% 的成本.
SubAgent Fork 模式的成本优势¶
子 Agent 从独立 Engine 实例改为共享 prompt cache 的 fork 模式(pkg/engine/subagent.go),显著降低子 Agent 调用成本.
核心机制:API 层传完整工具列表(和父 agent 一样),确保 cache key 一致.实际执行时用 canUseTool 函数限制可用工具集.
经济账(以 Sonnet 定价计算):
| 项目 | 独立 Engine(旧) | Fork 模式(新) |
|---|---|---|
| 系统提示 10K tokens | $0.03(全量付费) | $0.003(缓存读取 10%) |
| 多余工具描述 3K tokens | 不需要 | $0.009(多传但缓存命中) |
| 每次子 agent 净成本差 | 省 ~$0.018 |
一个复杂任务调用 10 个子 agent = 省 $0.18.长时间多轮对话中,子 agent 调用越多,fork 模式优势越明显.
安全性不降低:canUseTool 在运行时拦截,子 agent 请求被禁工具会收到错误消息,模型会自己换工具.
默认映射¶
var DefaultRoles = map[ModelRole]string{
RoleMain: "claude-sonnet-4-6",
RoleFast: "claude-haiku-4-5",
RoleThinking: "claude-sonnet-4-6",
}
默认不设置 RoleEmbed,因为当前记忆系统使用文本相似度搜索而非向量嵌入.
ModelRegistry API¶
创建¶
// 使用默认配置
registry := config.NewModelRegistry()
// 查看当前映射
fmt.Println(registry) // ModelRegistry{main=claude-sonnet-4-6, fast=claude-haiku-4-5, thinking=claude-sonnet-4-6}
查询¶
// 按角色获取模型 ID
modelID := registry.GetRole(config.RoleMain) // "claude-sonnet-4-6"
// 获取模型配置
cfg := registry.GetConfig("claude-sonnet-4-6")
fmt.Println(cfg.ContextWindow) // 200000
fmt.Println(cfg.MaxOutputTokens) // 16384
fmt.Println(cfg.SupportsCaching) // true
fmt.Println(cfg.SupportsThinking) // true
// 便捷方法:按角色获取配置
cfg = registry.GetConfigForRole(config.RoleFast) // claude-haiku-4-5 的配置
// 获取上下文窗口(未知模型返回默认值 200000)
window := registry.ContextWindow("unknown-model") // 200000
修改¶
// 切换 Main 角色到 opus
registry.SetRole(config.RoleMain, "claude-opus-4-6")
// 切换 Fast 角色
registry.SetRole(config.RoleFast, "claude-3-5-haiku")
在 Engine 中使用¶
agent, err := engine.New(&engine.Config{
Model: "claude-sonnet-4-6", // 向后兼容:设置 RoleMain
Models: registry, // 完整的角色系统
APIKey: os.Getenv("ANTHROPIC_API_KEY"),
Cwd: ".",
})
自定义角色映射¶
通过配置文件¶
在 settings.json 中配置(计划中的功能):
{
"models": {
"main": "claude-opus-4-6",
"fast": "claude-haiku-4-5",
"thinking": "claude-opus-4-6"
}
}
通过代码¶
registry := config.NewModelRegistry()
// 高端配置:Main 用 Opus,Fast 用 Haiku
registry.SetRole(config.RoleMain, "claude-opus-4-6")
registry.SetRole(config.RoleFast, "claude-haiku-4-5")
registry.SetRole(config.RoleThinking, "claude-opus-4-6")
// 经济配置:全部用 Haiku
registry.SetRole(config.RoleMain, "claude-haiku-4-5")
registry.SetRole(config.RoleFast, "claude-haiku-4-5")
registry.SetRole(config.RoleThinking, "claude-haiku-4-5")
非预置模型支持¶
ModelRegistry 允许注册任意第三方模型.SetRole 不要求模型已注册(允许使用未预置的模型 ID),但如果需要精确的成本计算和上下文窗口管理,应先注册模型配置.
注册第三方模型¶
registry := config.NewModelRegistry()
// 注册一个兼容 API 的第三方模型
registry.Register("my-custom-model", &config.ModelConfig{
ID: "my-custom-model",
ContextWindow: 128000,
MaxOutputTokens: 8192,
InputPrice: 1.0, // 每百万 token(美元)
OutputPrice: 5.0,
CacheReadPrice: 0.1,
CacheWritePrice: 1.25,
SupportsCaching: false,
SupportsThinking: false,
SupportsImages: false,
})
// 设置为主模型
registry.SetRole(config.RoleMain, "my-custom-model")
使用非预置模型的注意事项¶
- 上下文窗口 -- 未注册模型的
ContextWindow()返回默认值 200000.如果实际窗口更小,可能触发过早的压缩或超限错误 - 成本估算 -- 未注册模型的
EstimateCost()使用 Sonnet 默认定价,成本报告可能不准确 - Prompt Caching --
SupportsCaching为 false 时,引擎不会添加 cache_control 标记 - Extended Thinking --
SupportsThinking为 false 时,引擎不会发送 thinking 配置
定价与成本计算¶
预置模型定价¶
| 模型 | 输入 | 输出 | 缓存读 | 缓存写 |
|---|---|---|---|---|
| claude-opus-4-6 | $15.00/M | $75.00/M | $1.50/M | $18.75/M |
| claude-sonnet-4-6 | $3.00/M | $15.00/M | $0.30/M | $3.75/M |
| claude-haiku-4-5 | $0.80/M | $4.00/M | $0.08/M | $1.00/M |
价格单位:每百万 token(美元).
成本估算 API¶
// 完整成本估算(含缓存)
cost := registry.EstimateCost(
"claude-sonnet-4-6",
100000, // inputTokens
10000, // outputTokens
50000, // cacheReadTokens
20000, // cacheWriteTokens
)
// cost = 100000*3/1M + 10000*15/1M + 50000*0.3/1M + 20000*3.75/1M
// = 0.30 + 0.15 + 0.015 + 0.075 = $0.54
// 简化版(不含缓存,向后兼容)
cost := registry.EstimateSimpleCost("claude-sonnet-4-6", 100000, 10000)
// = $0.45
通过 Prompt Caching 节省成本¶
启用 Prompt Caching 后,重复的系统提示和工具描述可从缓存读取(10% 原价),首次写入缓存多付 25%.
以 Sonnet 4.6 为例,系统提示 10K tokens 在 10 轮对话中的成本:
| 无缓存 | 有缓存 | |
|---|---|---|
| 第 1 轮 | $0.03 | $0.0375(写入缓存) |
| 第 2-10 轮 | $0.27 | $0.027(缓存读取) |
| 总计 | $0.30 | $0.0645 |
节省 78%.
Prompt Caching¶
机制¶
通过在 API 请求的 system content block 上添加 cache_control 标记,标记静态内容为可缓存.
// API 请求中的系统提示块
blocks := []api.SystemContentBlock{
{
Type: "text",
Text: "...静态的系统提示词...",
CacheControl: &api.CacheControl{Type: "ephemeral"}, // 标记为可缓存
},
{
Type: "text",
Text: "...动态的环境信息...", // 不缓存
},
}
缓存边界¶
引擎自动识别系统提示中的静态和动态部分:
┌─────────────────────────────────┐
│ 角色定义 + 行为准则 (静态) │ ← cache_control: ephemeral
│ 工具使用指南 (静态) │
│ Git 安全协议 (静态) │
│ 代码质量准则 (静态) │
├─────────────────────────────────┤
│ 环境信息 (动态: cwd, git) │ ← 不缓存
│ 技能列表 (会话级动态) │
│ 用户追加提示 (动态) │
└─────────────────────────────────┘
Beta Headers¶
Prompt Caching 需要对应的 beta header:
req := &api.MessageRequest{
Beta: &api.BetaFeatures{
PromptCaching: true, // prompt-caching-2024-07-31
PromptCachingScope: "global", // prompt-caching-scope-2025-02-19
},
}
Extended Thinking¶
配置¶
req := &api.MessageRequest{
Thinking: &api.ThinkingConfig{
Type: "enabled",
BudgetTokens: 10000, // thinking token 预算
},
Beta: &api.BetaFeatures{
ExtendedThinking: true, // extended-thinking-2025-01-24
},
}
Effort / Fast Mode¶
通过 BetaFeatures 控制模型的推理深度:
// 低 effort(快速响应)
Beta: &api.BetaFeatures{
Effort: "low", // effort-2025-04-01
}
// Fast Mode(更激进的加速)
Beta: &api.BetaFeatures{
FastMode: true, // fast-mode-2025-04-01
}
| 模式 | Effort | 说明 |
|---|---|---|
| 默认 | (无) | 标准推理深度 |
| 低 | low |
减少推理深度,更快响应 |
| 中 | medium |
适中推理深度 |
| 高 | high |
最深推理,最慢但最准确 |
| 快速 | FastMode | 极速模式,跳过部分推理 |
模型能力矩阵¶
| 模型 | Caching | Thinking | Images |
|---|---|---|---|
| claude-opus-4-6 | Yes | Yes | Yes |
| claude-sonnet-4-6 | Yes | Yes | Yes |
| claude-haiku-4-5 | Yes | No | Yes |
| claude-haiku-3-5 | Yes | No | Yes |
| claude-3-5-sonnet | Yes | No | Yes |
| claude-3-opus | Yes | No | Yes |
代码位置:pkg/config/models.go