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

417 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
date: 2026-05-07
topic: "Go Agent Framework - Orca"
status: 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专家
- 消息类型:`TaskRequest``TaskResponse``ToolCall``Observation`
**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`
- 提取元数据:`name``description``triggers`(触发词)
- Skill 可以包含脚本文件(`scripts/` 目录)
- 提供 `FindSkill(query string)` 方法,基于触发词匹配
**Skill 结构:**
```yaml
name: "md2pdf"
description: "Convert Markdown to PDF..."
triggers: ["pdf", "markdown", "export"]
scripts:
- "scripts/convert.py"
- "scripts/setup.sh"
```
### 5. Tool Manager (工具系统)
**职责:** 管理可执行工具的注册和调用。
**设计要点:**
- **内置工具:** `exec`(执行命令)、`read_file``write_file``list_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保持轻量
**安全策略:**
```yaml
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 │────▶│ 决策:继续/完成 │
└──────┬──────┘ └─────────────┘
┌─────────────┐
│ 保存会话 │
│ 返回结果 │
└─────────────┘
```
### 消息类型定义
```go
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 可尝试其他工具
### 错误类型
```go
type ErrorCategory int
const (
ErrCategoryKernel ErrorCategory = iota // 内核错误
ErrCategoryAgent // Agent 错误
ErrCategoryTool // 工具错误
ErrCategorySandbox // 沙箱错误
ErrCategoryLLM // LLM 错误
ErrCategoryNetwork // 网络错误
)
```
## Testing Strategy
### 测试金字塔
1. **单元测试60%**
- `Kernel`:插件注册/卸载、消息路由
- `SessionManager`JSONL 读写、上下文窗口截断
- `SkillManager`Skill 解析、触发词匹配
- `Sandbox`:资源限制、超时控制
- `OllamaDriver`HTTP 请求封装(使用 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