Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Model: claude-opus-4-6 (anthropic/claude-opus-4-6) Generated: 2026-04-03 Book: Claude Code VS OpenCode: Architecture, Design and The Road Ahead 章节: 第12章 — 解剖一个13万行代码的插件 Token Usage: ~120,000 input + ~7,000 output

12.4 智能体系统实现

OMO 的“智能体“不是从零造的

OpenCode 本来就支持 AgentConfig。OMO 没有推翻这个机制,而是在已有的“员工管理系统“上建了一个更高级的“人力资源部“。

graph TD
    subgraph OC_Native["OpenCode Native"]
        A1["AgentConfig A"]
        A2["AgentConfig B"]
        A3["AgentConfig C"]
        Note1["Independent agents<br/>No coordination"]
    end
    subgraph OMO_Layer["OMO Orchestration"]
        S["Sisyphus - Boss"]
        S --> O["Oracle - Advisor"]
        S --> E["Explore - Scout"]
        S --> L["Librarian - Researcher"]
        S --> J["Junior - Worker"]
        Note2["Agents know each other<br/>Cost-aware delegation"]
    end

11 个智能体全家福

智能体角色成本典型用途
Sisyphus主编排者💰💰💰接收请求,拆解任务,协调其他智能体
Hephaestus主实现者💰💰💰偏实现的主编排者
Sisyphus Junior执行者💰💰被委派的具体任务
Prometheus计划者💰💰💰生成详细工作计划
Oracle顾问💰💰💰架构决策、方案评审
Librarian外部研究💰查文档、搜 GitHub
Explore内部搜索💰在项目代码库里搜索
Metis预分析💰💰💰分析需求,识别隐藏意图
Momus评审员💰💰💰审查计划完整性
Atlas持续监控💰监控会话,提供上下文提醒
Multimodal Looker多模态💰分析图片、PDF
graph TD
    subgraph Expensive["High Cost - Strong Models"]
        Sisyphus
        Hephaestus
        Prometheus
        Oracle
        Metis
        Momus
    end
    subgraph Medium["Medium Cost"]
        Junior["Sisyphus Junior"]
    end
    subgraph Cheap["Low Cost - Light Models"]
        Librarian
        Explore
        Atlas
        Looker["Multimodal Looker"]
    end

    Sisyphus -->|"delegate work"| Junior
    Sisyphus -->|"ask architecture"| Oracle
    Sisyphus -->|"search code"| Explore
    Sisyphus -->|"find docs"| Librarian
    Sisyphus -->|"make plan"| Prometheus
    Prometheus -->|"review plan"| Momus

为什么分成本等级? 让 CTO 去复印文件太浪费。简单任务用便宜模型,复杂任务才用贵模型。


智能体创建流程

📁 文件说明:src/agents/builtin-agents.ts 所有内建智能体的工厂函数集合。负责检查模型可用性、构建回退链、应用用户覆盖。

flowchart TD
    Start(["createBuiltinAgents()"]) --> Iterate["Iterate agentSources"]
    Iterate --> Disabled{Disabled by user?}
    Disabled -->|Yes| Skip["Skip"]
    Disabled -->|No| Models["Check Model Availability"]
    Models --> Resolve["applyModelResolution()"]
    Resolve --> Available{Preferred model OK?}
    Available -->|Yes| Build["Build AgentConfig"]
    Available -->|No| Fallback["Try Fallback Chain"]
    Fallback --> Build
    Build --> Env["Apply Environment Context"]
    Env --> Override["Apply User Overrides"]
    Override --> Done(["Agent Ready"])

模型回退链(Fallback Chain)

💡 CS 术语:Fallback chain = “首选方案不可用时按顺序尝试备选方案”。就像周末想吃火锅——第一选择满了去第二选择。

flowchart LR
    P1["claude-opus-4"] -->|unavailable| P2["claude-sonnet-4"]
    P2 -->|unavailable| P3["gpt-4o"]
    P3 -->|unavailable| P4["Use first item anyway"]

    style P1 fill:#c8e6c9
    style P4 fill:#ffcdd2

一个重要的安全考量:插件初始化阶段不能调用 OpenCode client API(可能死锁)。所以 OMO 用 provider 缓存和 fetchAvailableModels() 提前获取可用模型列表。


动态 Prompt 组装

普通 agent 的 system prompt 是写死的。OMO 的 prompt 根据当前环境动态拼装

📁 文件说明:src/agents/dynamic-agent-prompt-builder.ts 一组“prompt 模块工厂“——根据当前工具、技能、类别、智能体信息动态生成 prompt 段落。

为什么不写死?

flowchart TD
    Problem1["If Oracle is disabled<br/>but prompt says 'ask Oracle'"] --> Waste["Model wastes tokens<br/>calling non-existent agent"]
    Problem2["If new skill installed<br/>but prompt doesn't mention it"] --> Miss["Model doesn't know<br/>about the skill"]

所以 prompt 必须动态反映当前环境:

flowchart LR
    subgraph Input["Runtime Environment"]
        T["Registered Tools x26"]
        A["Available Agents x11"]
        S["Installed Skills"]
        C["Task Categories"]
    end

    subgraph Builder["Prompt Builder"]
        M1["Identity Module"]
        M2["Intent Gate"]
        M3["Tool Selection Table"]
        M4["Delegation Guide"]
        M5["Category + Skill Protocol"]
        M6["Hard Blocks"]
        M7["Anti-Patterns"]
    end

    Input --> Builder --> Output["Final System Prompt"]

📁 文件说明:src/agents/sisyphus.ts Sisyphus 的 prompt 由十几个模块拼成:身份定义、Intent Gate、代码库评估、探索策略、实现策略、委派规则、session continuity、todo 纪律、category+skill 协议、硬性约束、反模式清单。

什么是“工厂模式“? 不直接手写最终对象,而是通过“制造函数“根据输入动态产生对象。就像不提前做好简历,而是每次根据求职岗位动态填充内容。

具体例子categorizeTools() 根据当前注册工具自动分类:

flowchart TD
    CT["categorizeTools()"] --> C1["LSP: goto_def, find_ref..."]
    CT --> C2["AST: ast_grep..."]
    CT --> C3["Search: grep, glob..."]
    CT --> C4["Session: session tools..."]
    CT --> C5["Command: slashcommand..."]
    C1 & C2 & C3 & C4 & C5 --> Table["Tool Selection Table<br/>in System Prompt"]

两层结构:宿主层 vs 编排层

graph TD
    subgraph Host["OpenCode Host Layer"]
        HA["AgentConfig: sisyphus"]
        HB["AgentConfig: oracle"]
        HC["AgentConfig: explore"]
        HD["AgentConfig: librarian"]
        Note_H["Host sees: independent configs<br/>No coordination info"]
    end

    subgraph Orch["OMO Orchestration Layer"]
        OA["Sisyphus knows:<br/>oracle=expensive, read-only<br/>explore=cheap, fast<br/>junior=medium, can code"]
        Note_O["Each agent knows others'<br/>roles, costs, triggers"]
    end

    Host -.->|"Same agents<br/>two perspectives"| Orch

桥梁:AgentPromptMetadata

flowchart LR
    APM["AgentPromptMetadata"] --> F1["cost: expensive/cheap"]
    APM --> F2["triggers: when to use"]
    APM --> F3["useWhen: ideal scenarios"]
    APM --> F4["avoidWhen: anti-patterns"]
    APM --> F5["promptAlias: display name"]
    APM -->|"read by"| Builder["Prompt Builder"]
    Builder -->|"writes into"| SP["Sisyphus System Prompt"]

本节要点

  • 不造新抽象:在 OpenCode 原生 AgentConfig 上叠加编排逻辑
  • 11 个 agent 分 3 个成本层:高成本做决策,低成本做搜索
  • 模型回退链:首选不可用自动尝试备选
  • 动态 prompt:根据当前环境实时拼装,确保与实际资源一致
  • 两层结构:宿主看独立 configs,编排层让它们彼此协作
  • 元数据是桥梁:AgentPromptMetadata 让 Sisyphus 知道“该找谁“