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
16 KiB
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
- 语言约束: 纯 Go 实现,最小化外部依赖
- 存储约束: 使用 JSON Lines(无 SQLite/数据库依赖)
- 隔离约束: 进程级限制(chroot + 资源限制),不依赖 Docker
- 模型约束: 仅接入 Ollama 本地模型,默认 gemma4:e4b
- Skill 目录: 读取
~/.agents/skills/下的 Skill 定义 - 部署约束: 单二进制文件,零配置启动
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 结构:
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,保持轻量
安全策略:
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
策略
-
分层错误处理:
- Kernel 层: 插件加载失败 → 记录日志,跳过该插件,继续启动
- Agent 层: 任务执行失败 → 返回错误消息,让 Orchestrator 决策重试或终止
- Tool 层: 工具执行失败 → 返回结构化错误,LLM 可据此调整策略
- Sandbox 层: 命令超时/内存超限 → 强制终止进程,返回错误
-
重试机制:
- LLM API 调用:指数退避重试 3 次
- 工具执行:不重试(避免循环),由 LLM 决策
-
优雅降级:
- Ollama 不可用 → 提示用户检查服务
- Skill 解析失败 → 跳过该 Skill,不影响其他
- 沙箱执行失败 → 返回错误信息,LLM 可尝试其他工具
错误类型
type ErrorCategory int
const (
ErrCategoryKernel ErrorCategory = iota // 内核错误
ErrCategoryAgent // Agent 错误
ErrCategoryTool // 工具错误
ErrCategorySandbox // 沙箱错误
ErrCategoryLLM // LLM 错误
ErrCategoryNetwork // 网络错误
)
Testing Strategy
测试金字塔
-
单元测试(60%):
Kernel:插件注册/卸载、消息路由SessionManager:JSONL 读写、上下文窗口截断SkillManager:Skill 解析、触发词匹配Sandbox:资源限制、超时控制OllamaDriver:HTTP 请求封装(使用 mock server)
-
集成测试(30%):
- Agent + Tool:端到端任务执行
- Agent + LLM:使用 mock LLM 测试 Function Calling 流程
- Skill + Sandbox:加载 Skill 并执行其脚本
-
E2E 测试(10%):
- 完整 CLI 工作流
- 多 Agent 协作场景
Mock 策略
LLMClient:使用接口,测试时注入 mockSandbox:提供DryRun模式,记录命令但不执行MessageBus:内存实现,用于测试
Open Questions
-
Skill 执行方式: Skill 脚本是用 Shell 调用还是直接在 Go 中执行?当前设计倾向 Shell 调用(通过 Sandbox),但 Python/Node 脚本需要对应运行时。
- 假设: 用户环境已安装所需运行时(Python、Node 等),Sandbox 只负责安全执行。
-
Function Calling 格式: gemma4:e4b 对 Function Calling 的支持程度?
- 假设: 使用 Ollama 的
tools参数格式,如果不支持则 fallback 到 prompt-based tool calling。
- 假设: 使用 Ollama 的
-
多 Agent 协作粒度: Agent 之间是平等协作还是有层级?
- 假设: 支持两种模式:层级(Orchestrator + Workers)和平等(对等协作),由用户配置。
-
会话共享: 多个 Agent 是否可以共享同一个会话上下文?
- 假设: 是,Session Manager 通过文件锁支持并发读取,但同一时间只有一个 Agent 写入。
-
Tool 参数 Schema: 使用 JSON Schema 还是简化格式?
- 假设: 使用简化版 JSON Schema(支持 string/number/boolean/array/object + description)。