Goose 架构设计
本章概览
本章将深入解析 Goose 的整体架构设计,帮助你理解:
- 三层架构:界面层、核心层、扩展层
- 交互循环(Interactive Loop)的工作原理
- Rust Workspace 的模块组织
- 关键设计决策
1. 整体架构
1.1 三层架构
Goose 采用经典的三层架构设计:
┌─────────────────────────────────────────────────────────────┐
│ Interface Layer │
│ (界面层) │
│ ┌──────────────────────┐ ┌────────────────────────────┐ │
│ │ Desktop App │ │ CLI │ │
│ │ (Electron + React) │ │ (Rust) │ │
│ └──────────────────────┘ └────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Agent Layer │
│ (核心层) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Goose Agent │ │
│ │ ┌──────────┐ ┌──────────┐ ┌────────────────────────┐│ │
│ │ │ Provider │ │Extension │ │ Session Manager ││ │
│ │ │ System │ │ Manager │ │ ││ │
│ │ └──────────┘ └──────────┘ └────────────────────────┘│ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Extension Layer │
│ (扩展层) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
│ │Developer │ │ Computer │ │ Memory │ │ Custom MCP │ │
│ │ Tools │ │Controller│ │ │ │ Servers │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────────────┘通俗比喻:
把 Goose 想象成一个餐厅:
- 界面层 是前台服务员,负责接待客人(用户)
- 核心层 是厨房大厨,负责"烹饪"(处理请求)
- 扩展层 是各种厨具和食材供应商,提供各种能力
1.2 各层职责
| 层级 | 职责 | 技术实现 |
|---|---|---|
| Interface | 用户交互、输入收集、结果展示 | Electron + React / Rust CLI |
| Agent | 核心逻辑、交互循环、状态管理 | Rust (goose crate) |
| Extension | 具体能力、工具实现 | MCP Servers |
2. 交互循环(Interactive Loop)
2.1 循环流程
Goose 的核心是一个交互循环,让 Agent 能够持续与 LLM 和工具交互:
┌────────────────────────────┐
│ Human Request │
│ (用户请求) │
└─────────────┬──────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Provider Chat │ │
│ │ (发送请求到 LLM) │ │
│ └───────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────┐ │
│ │ LLM Response │ │
│ │ - Text 回复 │ │
│ │ - Tool Calls 工具调用 │ │
│ └──────────────┬──────────────┘ │
│ │ │
│ ┌──────────────┴──────────────┐ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Has Tool Calls │ │ No Tool Calls │ │
│ │ (有工具调用) │ │ (无工具调用) │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Execute Tools │ │ Return Response │ │
│ │ (执行工具) │ │ (返回结果) │ │
│ └────────┬────────┘ └─────────────────┘ │
│ │ │
│ └────────────────┐ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────┐ │
│ │ Send Tool Results to LLM │ │
│ │ (将工具结果发回 LLM) │ │
│ └───────────────────────────────┘ │
│ │ │
│ └──────────── 循环 ───────────►│
│ │
└──────────────────────────────────────────────────────────────┘2.2 代码实现
以下是交互循环的核心代码结构(简化版):
rust
// 位于 crates/goose/src/agents/agent.rs
impl Agent {
pub async fn reply(&self, conversation: &mut Conversation) -> Result<()> {
loop {
// 1. 发送消息到 LLM
let response = self.provider.chat(
conversation.messages(),
&self.tools,
).await?;
// 2. 处理 LLM 响应
conversation.add_message(response.clone());
// 3. 检查是否有工具调用
if response.tool_calls.is_empty() {
// 没有工具调用,循环结束
break;
}
// 4. 执行工具调用
for tool_call in response.tool_calls {
let result = self.extension_manager
.call_tool(&tool_call.name, tool_call.arguments)
.await?;
// 5. 将工具结果加入对话
conversation.add_tool_result(tool_call.id, result);
}
// 继续循环,让 LLM 处理工具结果
}
Ok(())
}
}2.3 为什么需要循环?
通俗解释:
想象你让 Goose 帮你"查询天气并根据天气推荐穿搭":
- LLM 首先调用天气 API 工具
- 获取结果后,LLM 继续思考穿搭建议
- 最终返回完整回答
这个过程需要多轮交互,所以需要循环。
3. Rust Workspace 结构
3.1 Crate 组织
Goose 使用 Rust Workspace 组织多个 crate:
goose/
├── Cargo.toml # Workspace 根配置
└── crates/
├── goose/ # 核心库
├── goose-cli/ # 命令行界面
├── goose-server/ # HTTP API 服务器
├── goose-mcp/ # MCP 扩展实现
├── goose-bench/ # 性能基准测试
└── goose-test/ # 测试工具3.2 各 Crate 详解
goose(核心库)
这是 Goose 的核心,包含所有主要功能:
crates/goose/src/
├── agents/ # Agent 相关
│ ├── agent.rs # 主 Agent 实现 (70KB)
│ ├── extension.rs # Extension trait
│ ├── extension_manager.rs # 扩展管理器
│ ├── mcp_client.rs # MCP 客户端
│ └── subagent_tool.rs # 子 Agent 工具
├── providers/ # LLM Provider
│ ├── base.rs # Provider trait
│ ├── openai.rs # OpenAI 实现
│ ├── anthropic.rs # Anthropic 实现
│ ├── ollama.rs # Ollama 实现
│ └── ... # 其他 Provider
├── conversation/ # 对话管理
├── session/ # 会话管理
├── config/ # 配置系统
├── permission/ # 权限控制
├── security/ # 安全检查
└── lib.rs # 模块导出goose-cli(命令行)
CLI 入口和用户交互:
rust
// crates/goose-cli/src/main.rs
#[derive(Parser)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
enum Commands {
Session { resume: bool }, // 开始会话
Configure, // 配置
Update, // 更新
Web { open: bool }, // Web 界面
}goose-mcp(MCP 扩展)
MCP 协议实现和内置扩展:
crates/goose-mcp/
├── developer/ # 开发者工具扩展
├── computercontroller/ # 浏览器控制扩展
├── memory/ # 记忆扩展
└── ...3.3 依赖关系
mermaid
graph TD
A[goose-cli] --> B[goose]
A --> C[goose-mcp]
A --> D[goose-bench]
B --> E[rmcp]
C --> E
B --> F[tokio]
B --> G[reqwest]关键依赖:
| 依赖 | 用途 |
|---|---|
rmcp | Rust MCP 协议实现 |
tokio | 异步运行时 |
reqwest | HTTP 客户端 |
serde | 序列化/反序列化 |
clap | 命令行解析 |
axum | HTTP 服务器 |
4. Provider 架构
4.1 Provider 抽象
Provider 是 Goose 与 LLM 交互的抽象层:
rust
// crates/goose/src/providers/base.rs
#[async_trait]
pub trait Provider: Send + Sync {
/// 获取 Provider 名称
fn name(&self) -> &str;
/// 获取模型信息
fn model_info(&self) -> &ModelInfo;
/// 发送聊天请求
async fn chat(
&self,
messages: &[Message],
tools: &[Tool],
) -> Result<Message, ProviderError>;
/// 流式聊天
async fn chat_stream(
&self,
messages: &[Message],
tools: &[Tool],
) -> Result<BoxStream<StreamEvent>, ProviderError>;
}4.2 Provider 实现
providers/
├── openai.rs # OpenAI (GPT-4, GPT-4o)
├── anthropic.rs # Anthropic (Claude)
├── azure.rs # Azure OpenAI
├── bedrock.rs # AWS Bedrock
├── gcpvertexai.rs # Google Vertex AI
├── ollama.rs # Ollama (本地模型)
├── litellm.rs # LiteLLM 代理
├── openrouter.rs # OpenRouter
└── factory.rs # Provider 工厂4.3 Provider 工厂
rust
// crates/goose/src/providers/factory.rs
pub fn create(
provider_name: &str,
model_name: &str,
config: &Config,
) -> Result<Box<dyn Provider>> {
match provider_name {
"openai" => Ok(Box::new(OpenAIProvider::new(model_name, config)?)),
"anthropic" => Ok(Box::new(AnthropicProvider::new(model_name, config)?)),
"ollama" => Ok(Box::new(OllamaProvider::new(model_name, config)?)),
// ... 其他 Provider
_ => Err(anyhow!("Unknown provider: {}", provider_name)),
}
}5. Extension 架构
5.1 Extension Trait
Extension 是 Goose 与外部工具交互的接口:
rust
// crates/goose/src/agents/extension.rs
#[async_trait]
pub trait Extension: Send + Sync {
/// 扩展名称
fn name(&self) -> &str;
/// 扩展描述
fn description(&self) -> &str;
/// 使用说明(会加入系统提示)
fn instructions(&self) -> &str;
/// 暴露的工具列表
fn tools(&self) -> &[Tool];
/// 扩展状态
async fn status(&self) -> Result<HashMap<String, Value>>;
/// 调用工具
async fn call_tool(
&self,
tool_name: &str,
parameters: HashMap<String, Value>,
) -> ToolResult<Value>;
}5.2 Extension Manager
Extension Manager 负责管理所有扩展:
rust
// crates/goose/src/agents/extension_manager.rs
pub struct ExtensionManager {
extensions: HashMap<String, Arc<dyn Extension>>,
mcp_clients: HashMap<String, McpClient>,
}
impl ExtensionManager {
/// 注册扩展
pub async fn register(&mut self, config: ExtensionConfig) -> Result<()>;
/// 获取所有工具
pub fn all_tools(&self) -> Vec<Tool>;
/// 调用工具
pub async fn call_tool(
&self,
tool_name: &str,
params: Value,
) -> ToolResult<Value>;
}5.3 MCP 集成
Goose 通过 MCP 协议连接外部扩展:
┌─────────────┐ MCP 协议 ┌─────────────┐
│ Goose │ ◄──────────────────────► │ MCP Server │
│ Agent │ JSON-RPC over stdio │ (Extension) │
└─────────────┘ └─────────────┘MCP 消息格式:
json
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "read_file",
"arguments": {
"path": "/path/to/file"
}
},
"id": 1
}6. 会话管理架构
6.1 Session 结构
rust
// crates/goose/src/session/mod.rs
pub struct Session {
pub id: String,
pub session_type: SessionType,
pub conversation: Conversation,
pub metadata: SessionMetadata,
pub extension_data: ExtensionData,
}
pub enum SessionType {
Interactive, // 交互式会话
Scheduled, // 定时任务
Subagent, // 子 Agent
}6.2 Session Manager
rust
pub struct SessionManager {
sessions: HashMap<String, Session>,
storage_path: PathBuf,
}
impl SessionManager {
/// 创建新会话
pub async fn create(&mut self, config: SessionConfig) -> Result<Session>;
/// 恢复会话
pub async fn resume(&mut self, session_id: &str) -> Result<Session>;
/// 保存会话
pub async fn save(&self, session: &Session) -> Result<()>;
}7. 安全架构
7.1 多层安全检查
Goose 实现了多层安全检查机制:
用户请求
│
▼
┌─────────────────────────────────────────┐
│ Security Inspector │
│ - 检测恶意命令 │
│ - 阻止危险操作 │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Permission Inspector │
│ - 检查工具权限 │
│ - 用户确认敏感操作 │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Repetition Inspector │
│ - 防止无限循环 │
│ - 检测重复调用 │
└─────────────────────────────────────────┘
│
▼
工具执行7.2 GooseMode
Goose 支持多种安全模式:
rust
pub enum GooseMode {
SmartApprove, // 智能审批(默认)
AutoApprove, // 自动批准(信任模式)
AskEveryTime, // 每次询问
ChatOnly, // 仅聊天,不执行工具
}8. 设计决策
8.1 为什么选择 Rust?
| 考虑因素 | Rust 的优势 |
|---|---|
| 性能 | 接近 C/C++ 的性能 |
| 内存安全 | 编译期保证,无运行时错误 |
| 并发 | 强大的 async/await 支持 |
| 跨平台 | 轻松编译到多平台 |
| 生态 | 丰富的 crate 生态 |
8.2 为什么采用 MCP?
| 考虑因素 | MCP 的优势 |
|---|---|
| 标准化 | Anthropic 主导的开放标准 |
| 可扩展 | 任何人都可以编写 MCP Server |
| 语言无关 | 扩展可用任何语言编写 |
| 生态 | 已有大量现成的 MCP Server |
8.3 为什么分离 CLI 和 Desktop?
┌─────────────────────────────────────────┐
│ 共享核心 (goose crate) │
└─────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ goose-cli │ │ Desktop App │
│ (Rust 原生) │ │ (Electron) │
└─────────────────┘ └─────────────────┘好处:
- 核心逻辑复用
- 各界面独立演进
- 用户可选择偏好的方式
9. 架构图总览
┌──────────────────────────────────────────────────────────────────┐
│ User Interface │
│ ┌─────────────────────────┐ ┌──────────────────────────────┐ │
│ │ Desktop App │ │ CLI │ │
│ │ (Electron + React) │ │ (Rust) │ │
│ └───────────┬─────────────┘ └───────────────┬──────────────┘ │
└──────────────┼──────────────────────────────────┼────────────────┘
│ │
└──────────────┬───────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ goose-server │
│ (HTTP API / WebSocket) │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ goose (Core) │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Agent │ │ Provider │ │ Extension │ │ Session │ │
│ │ Engine │ │ System │ │ Manager │ │ Manager │ │
│ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └────────────┘ │
│ │ │ │ │
│ └───────────────┼───────────────┘ │
│ │ │
│ ┌─────────────────────┴─────────────────────────────────────┐ │
│ │ Interactive Loop (交互循环) │ │
│ │ User Request → LLM → Tool Calls → Execute → Results → LLM│ │
│ └───────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────────────┐
│ LLM Providers │ │ MCP Extensions │
│ ┌───────┐ ┌───────┐ │ │ ┌─────────┐ ┌─────────────────┐ │
│ │OpenAI │ │Claude │ │ │ │Developer│ │Computer Control │ │
│ └───────┘ └───────┘ │ │ └─────────┘ └─────────────────┘ │
│ ┌───────┐ ┌───────┐ │ │ ┌─────────┐ ┌─────────────────┐ │
│ │Ollama │ │ Azure │ │ │ │ Memory │ │ Custom MCP │ │
│ └───────┘ └───────┘ │ │ └─────────┘ └─────────────────┘ │
└──────────────────────────┘ └──────────────────────────────────┘