跳转至

模型角色系统指南

Flyto Agent Engine 的模型角色抽象和管理系统.

目录

设计目标

  1. 不硬编码模型 ID -- 业务逻辑不直接引用 claude-sonnet-4-6 等具体 ID,而是引用角色 RoleMain
  2. 角色抽象 -- 不同用途使用不同模型,通过角色映射统一管理
  3. 运行时可修改 -- 线程安全的 ModelRegistry,支持运行时切换模型
  4. 第三方模型 -- 支持注册任意模型配置,不限于预置模型

四种角色

角色 常量 用途 典型场景
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")

使用非预置模型的注意事项

  1. 上下文窗口 -- 未注册模型的 ContextWindow() 返回默认值 200000.如果实际窗口更小,可能触发过早的压缩或超限错误
  2. 成本估算 -- 未注册模型的 EstimateCost() 使用 Sonnet 默认定价,成本报告可能不准确
  3. Prompt Caching -- SupportsCaching 为 false 时,引擎不会添加 cache_control 标记
  4. 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