orca.ai/thoughts/shared/designs/2026-05-07-orca-agent-framework-design.md
大森 6b94476347 Initial commit: Orca Agent Framework
Core features:
- Microkernel architecture with Actor model
- Session management with JSONL persistence
- Tool system (5 built-in tools)
- Skill system with SKILL.md parsing
- Sandbox security execution
- Ollama integration with gemma4:e4b
- Prompt-based tool calling (compatible with native function calling)
- REPL interface

11 packages, all tests passing
2026-05-08 00:55:48 +08:00

16 KiB
Raw Permalink Blame History

date, topic, status
date topic status
2026-05-07 Go Agent Framework - Orca validated

Go Agent Framework (Orca) 设计文档

Problem Statement

构建一个基于 Go 的基础 Agent 框架,支持多 Agent 协作、持久化会话记忆、Skill 技能自动识别、沙箱安全执行、自定义 Tool 注册扩展,并接入 Ollama 本地模型gemma4:e4b

核心挑战:

  • 如何在 Go 中实现轻量、高并发的多 Agent 系统
  • 如何安全地执行用户命令和 Skill 脚本
  • 如何设计可扩展的插件机制Skill / Tool
  • 如何管理会话上下文和记忆

Constraints

  1. 语言约束: 纯 Go 实现,最小化外部依赖
  2. 存储约束: 使用 JSON Lines无 SQLite/数据库依赖)
  3. 隔离约束: 进程级限制chroot + 资源限制),不依赖 Docker
  4. 模型约束: 仅接入 Ollama 本地模型,默认 gemma4:e4b
  5. Skill 目录: 读取 ~/.agents/skills/ 下的 Skill 定义
  6. 部署约束: 单二进制文件,零配置启动

Approach

架构风格:微内核 + Actor 模型

采用微内核架构作为基础所有功能Skill、Tool、LLM 驱动)都以插件形式注册到核心。

每个 Agent 实例是一个独立的 Actor,通过 消息总线Message Bus 进行通信。这完美契合 Go 的 goroutine + channel 并发模型。

为什么选择这个组合?

  • 微内核保证核心最小化Skill 和 Tool 热插拔
  • Actor 模型天然支持高并发,避免共享状态
  • 两者结合 = 轻量级、高扩展、Go 原生友好

放弃的其他方案:

  • Docker 沙箱:太重,违背最小依赖原则
  • SQLite 存储增加依赖JSONL 已足够
  • 中央协调器:单点瓶颈,不如 Actor 模型灵活

Architecture

整体架构图

┌─────────────────────────────────────────────────────────────┐
│                        CLI / API Layer                       │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                      Core Kernel (微内核)                     │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────┐  │
│  │  Message Bus │  │  Plugin Reg  │  │  Session Manager │  │
│  │  (channel)   │  │  (registry)  │  │   (JSONL-based)  │  │
│  └──────────────┘  └──────────────┘  └──────────────────┘  │
└─────────────────────────────────────────────────────────────┘
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│   Agent Actor   │ │   Agent Actor   │ │   Agent Actor   │
│  (Specialist 1) │ │  (Specialist 2) │ │  (Orchestrator) │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
         │                   │                   │
         └───────────────────┼───────────────────┘
                             ▼
┌─────────────────────────────────────────────────────────────┐
│                      Plugin Layer                            │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────────┐│
│  │  Skills  │  │  Tools   │  │  Ollama  │  │ Custom Tools ││
│  │(Skill Mgr)│  │(Tool Mgr)│  │ (Driver) │  │  (Registry)  ││
│  └──────────┘  └──────────┘  └──────────┘  └──────────────┘│
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                      Sandbox Layer                           │
│         (Process-level isolation + Resource limits)          │
└─────────────────────────────────────────────────────────────┘

模块职责

模块 职责
Core Kernel 消息路由、插件生命周期管理、会话协调
Message Bus 基于 Go channel 的异步消息传递系统
Plugin Registry 统一的 Skill/Tool/LLM 驱动注册中心
Session Manager 基于 JSONL 的会话历史读写和上下文窗口管理
Agent Actor 独立 goroutine持有状态接收/发送消息
Skill Manager 扫描 ~/.agents/skills/,解析 SKILL.md加载技能
Tool Manager 管理内置工具和自定义工具的注册/调用
Ollama Driver 封装 Ollama HTTP API支持流式响应
Sandbox 安全执行 shell 命令和脚本,限制资源和时间

Components

1. Core Kernel (微内核)

职责: 框架的最小化核心,只负责消息路由和插件生命周期。

设计要点:

  • 使用 Go 的 interface{} 或泛型定义插件契约
  • 启动时加载所有已注册的插件
  • 提供事件总线供插件间通信
  • 包含任何业务逻辑(如 LLM 调用、命令执行)

核心接口:

// 所有插件必须实现
Plugin interface {
    Name() string
    Init(kernel *Kernel) error
    Shutdown() error
}

// 消息总线
MessageBus interface {
    Publish(topic string, msg Message) error
    Subscribe(topic string, handler Handler) (Subscription, error)
}

2. Actor System (多 Agent 引擎)

职责: 管理 Agent 生命周期和消息通信。

设计要点:

  • 每个 Agent 是一个独立的 goroutine通过 channel 接收消息
  • Agent 持有自己的状态(角色、上下文、工具列表)
  • 支持三种 Agent 类型Orchestrator协调者、Worker执行者、Specialist专家
  • 消息类型:TaskRequestTaskResponseToolCallObservation

Agent 状态机:

Idle → Processing → [ToolCall] → WaitingForTool → Processing → Completed
                    ↓
              [Error] → Failed

3. Session Manager (会话记忆)

职责: 持久化会话历史,支持上下文窗口管理。

设计要点:

  • 每个会话一个 JSONL 文件:~/.orca/sessions/{session_id}.jsonl
  • 每行一个 JSON 对象:{role, content, timestamp, metadata}
  • 提供 GetContext(windowSize) 方法,返回最近的 N 条消息
  • 支持会话列表、搜索、归档

为什么 JSON Lines

  • 追加写入 O(1),无需加载整个文件
  • 人类可读,便于调试
  • 零依赖,无需数据库驱动
  • 通过简单文件锁保证并发安全

4. Skill Manager (技能系统)

职责: 自动发现和加载 Skill。

设计要点:

  • 启动时扫描 ~/.agents/skills/ 下的所有子目录
  • 解析每个 Skill 目录下的 SKILL.md
  • 提取元数据:namedescriptiontriggers(触发词)
  • Skill 可以包含脚本文件(scripts/ 目录)
  • 提供 FindSkill(query string) 方法,基于触发词匹配

Skill 结构:

name: "md2pdf"
description: "Convert Markdown to PDF..."
triggers: ["pdf", "markdown", "export"]
scripts:
  - "scripts/convert.py"
  - "scripts/setup.sh"

5. Tool Manager (工具系统)

职责: 管理可执行工具的注册和调用。

设计要点:

  • 内置工具: exec(执行命令)、read_filewrite_filelist_dir
  • Skill 工具: 从 Skill 的 scripts/ 目录自动注册
  • 自定义工具: 通过代码注册,实现 Tool 接口
  • 每个工具定义:名称、描述、参数 schema、执行函数
  • LLM 通过 Function Calling 调用工具

Tool 接口:

Tool interface {
    Name() string
    Description() string
    Parameters() JSONSchema
    Execute(ctx Context, args map[string]any) (Result, error)
}

6. Ollama Driver (LLM 驱动)

职责: 封装 Ollama API提供统一的 LLM 调用接口。

设计要点:

  • 默认模型:gemma4:e4b
  • 支持流式响应SSE
  • 支持 Function Calling通过 tools 参数)
  • 自动处理上下文窗口截断
  • 可配置参数temperature、top_p、max_tokens

API 封装:

LLMClient interface {
    Chat(messages []Message, tools []Tool) (Response, error)
    ChatStream(messages []Message, tools []Tool) (Stream, error)
}

7. Sandbox (沙箱执行)

职责: 安全地执行终端命令和脚本。

设计要点:

  • 使用 os/exec 创建子进程
  • 资源限制CPU 时间、内存、输出大小
  • 超时控制:默认 30 秒,可配置
  • 工作目录限制:可选 chroot 或指定工作目录
  • 环境变量隔离:只允许白名单环境变量
  • 使用 Docker保持轻量

安全策略:

sandbox:
  timeout: 30s
  max_memory: 512MB
  max_output: 64KB
  allowed_env: [PATH, HOME, USER]
  working_dir: /tmp/orca-sandbox
  read_only_dirs: []
  blocked_commands: [rm -rf /, mkfs, dd]

Data Flow

典型交互流程

用户输入
    │
    ▼
┌─────────────┐
│   CLI/API   │
└──────┬──────┘
       │
       ▼
┌─────────────┐     ┌─────────────┐
│ Session Mgr │────▶│ 加载历史上下文 │
└──────┬──────┘     └─────────────┘
       │
       ▼
┌─────────────┐
│ Orchestrator │ (Agent Actor)
│   Agent      │
└──────┬──────┘
       │
       ▼
┌─────────────┐     ┌─────────────┐
│  Skill Mgr  │────▶│ 匹配相关 Skill │
└──────┬──────┘     └─────────────┘
       │
       ▼
┌─────────────┐     ┌─────────────┐
│ Ollama Driver│────▶│ 发送 prompt  │
└──────┬──────┘     └─────────────┘
       │
       ▼
┌─────────────┐
│ LLM Response │
│ (Function    │
│   Calling)   │
└──────┬──────┘
       │
       ▼
┌─────────────┐     ┌─────────────┐
│  Tool Call   │────▶│ 执行 Tool/   │
│              │     │ 沙箱命令     │
└──────┬──────┘     └─────────────┘
       │
       ▼
┌─────────────┐
│ Observation  │ (工具执行结果)
└──────┬──────┘
       │
       ▼
┌─────────────┐     ┌─────────────┐
│ Orchestrator │────▶│ 决策:继续/完成 │
└──────┬──────┘     └─────────────┘
       │
       ▼
┌─────────────┐
│  保存会话     │
│  返回结果     │
└─────────────┘

消息类型定义

type Message struct {
    ID        string
    Type      MessageType // TaskRequest, TaskResponse, ToolCall, Observation, Error
    From      string      // Agent ID
    To        string      // Agent ID or "broadcast"
    Content   interface{} // 根据 Type 不同而变化
    Timestamp time.Time
}

type TaskRequest struct {
    Query    string
    SessionID string
    Context  []ChatMessage
}

type ToolCall struct {
    ToolName string
    Arguments map[string]interface{}
}

type Observation struct {
    ToolCallID string
    Output     string
    Error      string
}

Error Handling

策略

  1. 分层错误处理:

    • Kernel 层: 插件加载失败 → 记录日志,跳过该插件,继续启动
    • Agent 层: 任务执行失败 → 返回错误消息,让 Orchestrator 决策重试或终止
    • Tool 层: 工具执行失败 → 返回结构化错误LLM 可据此调整策略
    • Sandbox 层: 命令超时/内存超限 → 强制终止进程,返回错误
  2. 重试机制:

    • LLM API 调用:指数退避重试 3 次
    • 工具执行:不重试(避免循环),由 LLM 决策
  3. 优雅降级:

    • Ollama 不可用 → 提示用户检查服务
    • Skill 解析失败 → 跳过该 Skill不影响其他
    • 沙箱执行失败 → 返回错误信息LLM 可尝试其他工具

错误类型

type ErrorCategory int

const (
    ErrCategoryKernel    ErrorCategory = iota // 内核错误
    ErrCategoryAgent                          // Agent 错误
    ErrCategoryTool                           // 工具错误
    ErrCategorySandbox                        // 沙箱错误
    ErrCategoryLLM                            // LLM 错误
    ErrCategoryNetwork                        // 网络错误
)

Testing Strategy

测试金字塔

  1. 单元测试60%

    • Kernel:插件注册/卸载、消息路由
    • SessionManagerJSONL 读写、上下文窗口截断
    • SkillManagerSkill 解析、触发词匹配
    • Sandbox:资源限制、超时控制
    • OllamaDriverHTTP 请求封装(使用 mock server
  2. 集成测试30%

    • Agent + Tool端到端任务执行
    • Agent + LLM使用 mock LLM 测试 Function Calling 流程
    • Skill + Sandbox加载 Skill 并执行其脚本
  3. E2E 测试10%

    • 完整 CLI 工作流
    • 多 Agent 协作场景

Mock 策略

  • LLMClient:使用接口,测试时注入 mock
  • Sandbox:提供 DryRun 模式,记录命令但不执行
  • MessageBus:内存实现,用于测试

Open Questions

  1. Skill 执行方式: Skill 脚本是用 Shell 调用还是直接在 Go 中执行?当前设计倾向 Shell 调用(通过 Sandbox但 Python/Node 脚本需要对应运行时。

    • 假设: 用户环境已安装所需运行时Python、Node 等Sandbox 只负责安全执行。
  2. Function Calling 格式: gemma4:e4b 对 Function Calling 的支持程度?

    • 假设: 使用 Ollama 的 tools 参数格式,如果不支持则 fallback 到 prompt-based tool calling。
  3. 多 Agent 协作粒度: Agent 之间是平等协作还是有层级?

    • 假设: 支持两种模式层级Orchestrator + Workers和平等对等协作由用户配置。
  4. 会话共享: 多个 Agent 是否可以共享同一个会话上下文?

    • 假设:Session Manager 通过文件锁支持并发读取,但同一时间只有一个 Agent 写入。
  5. Tool 参数 Schema 使用 JSON Schema 还是简化格式?

    • 假设: 使用简化版 JSON Schema支持 string/number/boolean/array/object + description