OpenWorker 深度解析:吴恩达的桌面 AI 智能体,从 aisuite 到生产级 Agent 架构的完整演进
引言:从云端到桌面的 AI Agent 落地之路
2026 年 7 月 25 日,吴恩达(Andrew Ng)在 LinkedIn 宣布开源桌面 AI 智能体 OpenWorker,短短 24 小时内斩获 3.7K Star。这不是一个普通的 AI 工具发布,而是吴恩达团队从 aisuite 库到完整桌面应用的工程演进成果。
过去一年,AI Agent 领域的讨论从「如何构建」转向「如何落地」。云端 Agent 框架百花齐放,LangChain、AutoGen、CrewAI 各有拥趸,但真正能跑在开发者本地机器上、无缝集成日常工作的桌面 Agent 依然稀缺。OpenWorker 的出现,填补了「云端实验」到「桌面生产」之间的关键缺口。
本文将深度拆解 OpenWorker 的架构设计、技术选型、与 aisuite 的继承关系,以及桌面 Agent 的核心工程挑战。
一、OpenWorker 是什么:不只是另一个 AI 聊天工具
1.1 核心定位
OpenWorker 是一个 桌面 AI 智能体,不是简单的 AI 聊天客户端。它的核心能力包括:
- 任务执行:不只能对话,还能执行用户交代的实际任务(文件操作、代码生成、项目分析等)
- 多模型统一接口:支持 GPT 5.6 Sol、Claude Fable、Gemini 3.6、Kimi、GLM、DeepSeek、Inkling 等模型
- 本地优先:支持 Ollama 等本地模型,隐私数据不出本地
- 跨平台:macOS 版本已上线,Windows 版本在开发中
1.2 与传统 AI 工具的区别
| 工具类型 | 代表 | 能力边界 |
|---|---|---|
| AI 聊天客户端 | ChatGPT Web、Claude Web | 对话为主,无法操作本地环境 |
| AI 编程助手 | Cursor、GitHub Copilot | 集成 IDE,但局限于代码生成 |
| AI Agent 框架 | LangChain、AutoGen | 需要自己构建应用,无开箱即用桌面客户端 |
| 桌面 AI 智能体 | OpenWorker | 对话 + 任务执行 + 本地环境操作 + 多模型切换 |
1.3 为什么是桌面而不是云端?
吴恩达在多个场合强调 AI 落地的「最后一公里」问题。云端 Agent 面临三大挑战:
- 隐私合规:企业代码、内部文档不能上云
- 延迟成本:频繁调用云端模型,成本和延迟都难以接受
- 环境隔离:云端 Agent 无法访问用户的本地文件系统、Git 仓库、开发环境
桌面 Agent 天然具备:
- 本地文件系统访问权限
- 本地开发工具链集成(Git、npm、pip、docker)
- 私有数据不出本地的安全边界
- 低延迟的本地模型推理能力(通过 Ollama)
二、aisuite 到 OpenWorker:架构演进之路
2.1 aisuite:统一 LLM API 的抽象层
OpenWorker 的技术底座是 aisuite——吴恩达团队在 2024 年底开源的 Python 库,核心目标是统一不同 LLM 提供商的 API 调用方式。
核心设计理念
import aisuite as ai
client = ai.Client()
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Explain the difference between async and sync programming."},
]
# 切换模型只需改一行
response_openai = client.chat.completions.create(
model="openai:gpt-5.6-sol",
messages=messages
)
response_claude = client.chat.completions.create(
model="anthropic:claude-fable",
messages=messages
)
response_gemini = client.chat.completions.create(
model="google:gemini-3.6",
messages=messages
)
架构特点
┌─────────────────────────────────────────┐
│ aisuite.Client() │
├─────────────────────────────────────────┤
│ chat.completions.create() │
│ ↓ model="provider:model_name" │
│ ┌─────────────────────────────────────┐│
│ │ Provider Router (字符串解析) ││
│ └─────────────────────────────────────┘│
│ ↓ │
│ ┌─────────────────────────────────────┐│
│ │ Provider Adapter Layer ││
│ │ ┌──────────┬──────────┬─────────┐ ││
│ │ │ OpenAI │ Anthropic│ Google │ ││
│ │ │ Adapter │ Adapter │ Adapter │ ││
│ │ └──────────┴──────────┴─────────┘ ││
│ └─────────────────────────────────────┘│
└─────────────────────────────────────────┘
关键代码解析
aisuite 的 Provider Router 实现非常精简:
# aisuite/core/provider.py (伪代码示意)
class ProviderRouter:
def __init__(self):
self.providers = {
'openai': OpenAIAdapter(),
'anthropic': AnthropicAdapter(),
'google': GoogleAdapter(),
# ... 更多提供商
}
def parse_model_string(self, model: str) -> tuple[str, str]:
"""解析 'openai:gpt-5.6-sol' -> ('openai', 'gpt-5.6-sol')"""
if ':' not in model:
raise ValueError(f"Invalid model format: {model}")
provider, model_name = model.split(':', 1)
return provider, model_name
def route(self, model: str, **kwargs):
provider_name, model_name = self.parse_model_string(model)
adapter = self.providers.get(provider_name)
if not adapter:
raise ValueError(f"Unknown provider: {provider_name}")
return adapter.chat_completions(model_name, **kwargs)
每个 Adapter 统一输出格式,对齐 OpenAI 的响应结构:
# aisuite/adapters/base.py
class BaseAdapter:
def chat_completions(self, model: str, messages: list, **kwargs) -> ChatCompletion:
raise NotImplementedError
@dataclass
class ChatCompletion:
id: str
choices: list[Choice]
usage: dict
model: str
provider: str # 额外字段,标识来源
@dataclass
class Choice:
index: int
message: Message
finish_reason: str
2.2 OpenWorker:在 aisuite 之上构建的 Agent 运行时
OpenWorker 不是简单的「aisuite + GUI」,而是在 aisuite 之上构建了完整的 Agent 运行时:
┌─────────────────────────────────────────────────────────────┐
│ OpenWorker Desktop App │
├─────────────────────────────────────────────────────────────┤
│ UI Layer (Electron / Tauri / Native) │
│ ├── Chat Interface │
│ ├── Task Dashboard │
│ └── Settings Panel │
├─────────────────────────────────────────────────────────────┤
│ Agent Runtime │
│ ├── Task Planner (任务分解) │
│ ├── Tool Executor (工具执行) │
│ ├── Memory Manager (上下文管理) │
│ └── State Tracker (状态追踪) │
├─────────────────────────────────────────────────────────────┤
│ Tool Layer │
│ ├── FileSystem Tools (文件读写) │
│ ├── Git Tools (版本控制) │
│ ├── Code Execution (代码执行) │
│ ├── Web Search (联网搜索) │
│ └── Custom Tools (用户自定义) │
├─────────────────────────────────────────────────────────────┤
│ aisuite Layer (模型统一接口) │
│ └── Multi-provider LLM Calls │
└─────────────────────────────────────────────────────────────┘
三、桌面 Agent 的核心工程挑战
3.1 挑战一:本地环境的安全访问
桌面 Agent 需要访问用户的文件系统、运行命令,这带来了安全风险。OpenWorker 的解决方案:
权限分级模型
# openworker/security/permissions.py (设计示意)
class PermissionLevel(Enum):
READ_ONLY = "read_only" # 只读文件
WRITE_SAFE = "write_safe" # 写入非关键目录
FULL_ACCESS = "full_access" # 完全访问(需要显式授权)
SYSTEM_COMMAND = "system_cmd" # 执行系统命令(最高权限)
class PermissionManager:
def __init__(self, config_path: str):
self.permissions = self.load_permissions(config_path)
self.sandbox_dirs = self.init_sandbox()
def check_permission(self, tool: str, action: str, path: str = None) -> bool:
"""检查工具执行权限"""
tool_perms = self.permissions.get(tool, {})
# 危险操作需要二次确认
if action in ["delete", "execute", "modify_system"]:
return self.request_user_confirmation(tool, action, path)
return tool_perms.get(action, False)
def init_sandbox(self) -> list[str]:
"""初始化沙箱目录,限制 Agent 活动范围"""
return [
os.path.expanduser("~/Documents/OpenWorker/"),
os.path.expanduser("~/Downloads/OpenWorker/"),
# 用户指定的额外工作目录
]
沙箱隔离机制
OpenWorker 采用类似 Docker 的轻量级隔离思路:
# openworker/sandbox/executor.py
class SandboxExecutor:
def __init__(self, allowed_dirs: list[str]):
self.allowed_dirs = [os.path.abspath(d) for d in allowed_dirs]
def execute_command(self, cmd: str, cwd: str = None) -> Result:
"""在沙箱中执行命令"""
# 1. 检查 cwd 是否在允许列表
if cwd and not self.is_path_allowed(cwd):
return Result(error="Path not in sandbox")
# 2. 解析命令,检查危险操作
parsed = self.parse_command(cmd)
if self.is_dangerous(parsed):
return Result(error="Dangerous command blocked", details=parsed)
# 3. 执行命令
result = subprocess.run(
parsed,
cwd=cwd,
capture_output=True,
text=True,
timeout=60 # 超时保护
)
return Result(stdout=result.stdout, stderr=result.stderr, code=result.returncode)
def is_dangerous(self, parsed: list[str]) -> bool:
"""检测危险命令"""
dangerous_patterns = [
"rm -rf /", "sudo", "chmod 777",
"> /dev/", "mkfs", "dd if="
]
return any(p in " ".join(parsed) for p in dangerous_patterns)
3.2 挑战二:上下文管理与记忆系统
云端 Agent 可以把对话历史存在服务端,桌面 Agent 需要本地持久化,同时控制上下文窗口大小。
分层记忆架构
# openworker/memory/manager.py
class MemoryManager:
def __init__(self, db_path: str):
self.db = sqlite3.connect(db_path)
self.short_term = ShortTermMemory(max_tokens=4000)
self.long_term = LongTermMemory(self.db)
self.episodic = EpisodicMemory(self.db)
def add_message(self, role: str, content: str):
"""添加消息到记忆系统"""
self.short_term.append(role, content)
# 短期记忆溢出时,压缩到长期记忆
if self.short_term.token_count > self.short_term.max_tokens:
summary = self.summarize(self.short_term.get_all())
self.long_term.store(summary)
self.short_term.compact()
def get_context_for_llm(self, task: str) -> list[dict]:
"""为 LLM 准备上下文"""
# 1. 从长期记忆检索相关信息
relevant_memories = self.long_term.retrieve(task, top_k=5)
# 2. 组装上下文
context = []
for memory in relevant_memories:
context.append({
"role": "system",
"content": f"[Previous Context] {memory.summary}"
})
# 3. 加上当前对话
context.extend(self.short_term.get_recent(n=10))
return context
向量化记忆检索
# openworker/memory/vector_store.py
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
class VectorMemoryStore:
def __init__(self, embedding_model: str = "text-embedding-3-small"):
self.embeddings = {} # memory_id -> embedding
self.memories = {} # memory_id -> content
self.embedder = self.load_embedder(embedding_model)
def store(self, memory_id: str, content: str):
"""存储记忆并生成向量"""
embedding = self.embedder.embed(content)
self.embeddings[memory_id] = embedding
self.memories[memory_id] = content
def retrieve(self, query: str, top_k: int = 5) -> list[str]:
"""检索相关记忆"""
query_embedding = self.embedder.embed(query)
similarities = {}
for mid, emb in self.embeddings.items():
sim = cosine_similarity([query_embedding], [emb])[0][0]
similarities[mid] = sim
# 返回最相似的 top_k 个
sorted_mids = sorted(similarities.items(), key=lambda x: x[1], reverse=True)
return [self.memories[mid] for mid, _ in sorted_mids[:top_k]]
3.3 挑战三:任务规划与执行
Agent 的核心能力是「理解用户意图 → 分解任务 → 执行 → 反馈」。OpenWorker 采用 ReAct 框架的增强版本。
任务规划器
# openworker/agent/planner.py
class TaskPlanner:
def __init__(self, llm_client, tools: list[Tool]):
self.llm = llm_client
self.tools = {t.name: t for t in tools}
def plan(self, user_request: str) -> list[Step]:
"""将用户请求分解为执行步骤"""
prompt = f"""
User Request: {user_request}
Available Tools:
{self.format_tools()}
Create a step-by-step plan to fulfill the request.
Each step should specify:
1. The tool to use
2. The parameters
3. Expected output
4. Next step condition
Output in JSON format.
"""
response = self.llm.chat.completions.create(
model="openai:gpt-5.6-sol",
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"}
)
plan_data = json.loads(response.choices[0].message.content)
return [Step(**s) for s in plan_data["steps"]]
def execute_plan(self, plan: list[Step]) -> dict:
"""执行计划并处理中间结果"""
results = {}
for i, step in enumerate(plan):
try:
tool = self.tools[step.tool]
result = tool.execute(**step.params)
results[step.id] = result
# 根据结果判断是否需要调整后续步骤
if not result.success:
plan = self.replan_from(step, result, plan[i+1:])
except Exception as e:
# 错误处理与重试
results[step.id] = {"error": str(e), "success": False}
return results
ReAct 执行循环
# openworker/agent/react.py
class ReActAgent:
def __init__(self, llm_client, tools: list[Tool]):
self.llm = llm_client
self.tools = {t.name: t for t in tools}
self.max_iterations = 10
def run(self, task: str) -> str:
"""ReAct 循环:Thought → Action → Observation"""
history = []
for i in range(self.max_iterations):
# 1. Thought:思考下一步
thought = self.think(task, history)
history.append({"role": "assistant", "content": f"Thought: {thought}"})
# 2. Action:决定执行什么动作
action = self.decide_action(thought)
if action["type"] == "finish":
# 任务完成,返回答案
return action["answer"]
# 3. Execute:执行动作
observation = self.execute_action(action)
history.append({
"role": "user",
"content": f"Observation: {observation}"
})
return "Max iterations reached. Task may be too complex."
def think(self, task: str, history: list[dict]) -> str:
"""生成思考过程"""
prompt = f"""
Task: {task}
History:
{self.format_history(history)}
What should I think about next?
"""
response = self.llm.chat.completions.create(
model="anthropic:claude-fable",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
四、多模型策略与成本优化
OpenWorker 支持多种模型,如何选择合适的模型、控制成本是关键。
4.1 模型路由策略
# openworker/llm/router.py
class ModelRouter:
def __init__(self):
self.models = {
"fast": "openai:gpt-4o-mini", # 快速响应
"balanced": "anthropic:claude-sonnet", # 平衡型
"smart": "anthropic:claude-fable", # 复杂推理
"local": "ollama:llama3.2", # 本地模型
}
def select_model(self, task_type: str, complexity: float) -> str:
"""根据任务类型和复杂度选择模型"""
if task_type == "quick_question":
return self.models["fast"]
if task_type == "code_generation":
# 简单代码用 fast,复杂架构用 smart
return self.models["fast"] if complexity < 0.5 else self.models["smart"]
if task_type == "analysis":
return self.models["balanced"]
if task_type == "planning":
return self.models["smart"]
return self.models["balanced"]
def estimate_cost(self, model: str, input_tokens: int, output_tokens: int) -> float:
"""估算成本(美元)"""
pricing = {
"openai:gpt-4o-mini": {"input": 0.15/1e6, "output": 0.60/1e6},
"anthropic:claude-sonnet": {"input": 3.0/1e6, "output": 15.0/1e6},
"anthropic:claude-fable": {"input": 15.0/1e6, "output": 75.0/1e6},
"ollama:llama3.2": {"input": 0, "output": 0}, # 本地免费
}
rates = pricing.get(model, {"input": 0, "output": 0})
return input_tokens * rates["input"] + output_tokens * rates["output"]
4.2 本地模型集成(Ollama)
# openworker/llm/ollama_adapter.py
import requests
class OllamaAdapter:
def __init__(self, base_url: str = "http://localhost:11434"):
self.base_url = base_url
def chat(self, model: str, messages: list[dict], **kwargs) -> dict:
"""调用本地 Ollama 模型"""
response = requests.post(
f"{self.base_url}/api/chat",
json={
"model": model,
"messages": messages,
"stream": False,
**kwargs
}
)
return response.json()
def list_models(self) -> list[str]:
"""列出已下载的本地模型"""
response = requests.get(f"{self.base_url}/api/tags")
return [m["name"] for m in response.json().get("models", [])]
def pull_model(self, model: str):
"""下载模型"""
requests.post(
f"{self.base_url}/api/pull",
json={"name": model}
)
五、工具系统与可扩展性
5.1 工具定义规范
# openworker/tools/base.py
from abc import ABC, abstractmethod
from typing import Any
from pydantic import BaseModel
class ToolSchema(BaseModel):
name: str
description: str
parameters: dict # JSON Schema
class ToolResult(BaseModel):
success: bool
output: Any
error: str = None
class BaseTool(ABC):
@abstractmethod
def schema(self) -> ToolSchema:
"""返回工具的 JSON Schema"""
pass
@abstractmethod
def execute(self, **params) -> ToolResult:
"""执行工具"""
pass
# 示例:文件读取工具
class ReadFileTool(BaseTool):
def schema(self) -> ToolSchema:
return ToolSchema(
name="read_file",
description="Read content from a file",
parameters={
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "File path to read"
},
"start_line": {
"type": "integer",
"description": "Start line (1-indexed)",
"default": 1
},
"end_line": {
"type": "integer",
"description": "End line (inclusive)",
"default": -1
}
},
"required": ["path"]
}
)
def execute(self, path: str, start_line: int = 1, end_line: int = -1) -> ToolResult:
try:
with open(path, 'r', encoding='utf-8') as f:
lines = f.readlines()
if end_line == -1:
end_line = len(lines)
content = "".join(lines[start_line-1:end_line])
return ToolResult(success=True, output=content)
except Exception as e:
return ToolResult(success=False, output=None, error=str(e))
5.2 工具注册与发现
# openworker/tools/registry.py
class ToolRegistry:
def __init__(self):
self.tools = {}
self.categories = {
"filesystem": [],
"code": [],
"web": [],
"git": [],
"custom": []
}
def register(self, tool: BaseTool, category: str = "custom"):
"""注册工具"""
schema = tool.schema()
self.tools[schema.name] = tool
self.categories[category].append(schema.name)
def get_schemas_for_llm(self) -> list[dict]:
"""返回所有工具的 Schema(供 LLM 调用)"""
return [t.schema().model_dump() for t in self.tools.values()]
def execute(self, tool_name: str, **params) -> ToolResult:
"""执行工具"""
if tool_name not in self.tools:
return ToolResult(
success=False,
output=None,
error=f"Tool not found: {tool_name}"
)
return self.tools[tool_name].execute(**params)
# 初始化注册表
registry = ToolRegistry()
registry.register(ReadFileTool(), "filesystem")
registry.register(WriteFileTool(), "filesystem")
registry.register(GitStatusTool(), "git")
registry.register(WebSearchTool(), "web")
六、性能优化与生产部署
6.1 响应速度优化
# openworker/performance/cache.py
from functools import lru_cache
import hashlib
class ResponseCache:
def __init__(self, max_size: int = 1000):
self.cache = {}
self.max_size = max_size
def get_cache_key(self, model: str, messages: list[dict]) -> str:
"""生成缓存键"""
content = model + json.dumps(messages, sort_keys=True)
return hashlib.md5(content.encode()).hexdigest()
def get(self, model: str, messages: list[dict]) -> str | None:
"""获取缓存响应"""
key = self.get_cache_key(model, messages)
return self.cache.get(key)
def set(self, model: str, messages: list[dict], response: str):
"""缓存响应"""
if len(self.cache) >= self.max_size:
# LRU 淘汰
self.cache.pop(next(iter(self.cache)))
key = self.get_cache_key(model, messages)
self.cache[key] = response
# 使用缓存
cache = ResponseCache()
def chat_with_cache(model: str, messages: list[dict], use_cache: bool = True):
if use_cache:
cached = cache.get(model, messages)
if cached:
return cached
response = llm.chat.completions.create(model=model, messages=messages)
if use_cache:
cache.set(model, messages, response)
return response
6.2 流式响应
# openworker/llm/streaming.py
async def stream_chat(model: str, messages: list[dict]):
"""流式响应,提升用户体验"""
async for chunk in llm.chat.completions.create(
model=model,
messages=messages,
stream=True
):
if chunk.choices[0].delta.content:
yield chunk.choices[0].delta.content
# 前端消费
async def handle_user_message(message: str):
messages = [{"role": "user", "content": message}]
full_response = ""
async for token in stream_chat("openai:gpt-5.6-sol", messages):
full_response += token
# 实时推送到 UI
await push_to_ui(token)
# 保存完整响应到记忆
memory.add_message("assistant", full_response)
七、与现有方案的对比
| 维度 | OpenWorker | Cursor | ChatGPT Desktop | LangChain |
|---|---|---|---|---|
| 定位 | 桌面 AI 智能体 | AI IDE | AI 聊天客户端 | Agent 框架 |
| 任务执行 | ✅ 支持 | ✅ 支持(限于代码) | ❌ 仅对话 | ✅ 支持(需开发) |
| 本地模型 | ✅ Ollama | ❌ | ❌ | ✅ 需集成 |
| 多模型切换 | ✅ aisuite 统一接口 | ❌ 单一模型 | ✅ 但无统一 API | ✅ 需自己封装 |
| 文件系统访问 | ✅ 沙箱隔离 | ✅ 项目目录 | ❌ | ✅ 需自己实现 |
| 开箱即用 | ✅ | ✅ | ✅ | ❌ 需开发 |
| 开源 | ✅ | ❌ | ❌ | ✅ |
| 成本 | 本地模型免费 | 订阅制 | 订阅制 | 自建成本 |
八、实战案例:用 OpenWorker 自动化代码重构
假设你有一个 Python 项目,需要将所有 print() 语句替换为 logging.info(),并添加适当的日志级别。用 OpenWorker 可以这样操作:
用户请求
帮我重构 src/ 目录下的所有 Python 文件:
1. 把 print() 替换为 logging.info()
2. 添加 import logging
3. 在文件顶部初始化 logger
OpenWorker 执行过程
- 规划阶段
{
"steps": [
{"id": "s1", "tool": "list_files", "params": {"path": "src/", "ext": ".py"}},
{"id": "s2", "tool": "read_file", "params": {"path": "$s1.output[0]"}},
{"id": "s3", "tool": "analyze_code", "params": {"code": "$s2.output"}},
{"id": "s4", "tool": "refactor_code", "params": {"code": "$s2.output", "task": "print_to_logging"}},
{"id": "s5", "tool": "write_file", "params": {"path": "$s1.output[0]", "content": "$s4.output"}},
{"id": "s6", "tool": "loop", "params": {"from_step": "s2", "items": "$s1.output"}}
]
}
- 执行阶段
# 生成的重构代码
import logging
logger = logging.getLogger(__name__)
def process_data(data):
# 原: print(f"Processing {data}")
logging.info(f"Processing {data}")
try:
result = transform(data)
# 原: print(f"Result: {result}")
logging.info(f"Result: {result}")
return result
except Exception as e:
# 原: print(f"Error: {e}")
logging.error(f"Error: {e}")
raise
- 验证阶段
OpenWorker 自动运行测试,确保重构没有破坏功能:
$ pytest tests/
✅ All tests passed
九、总结与展望
9.1 OpenWorker 的核心价值
- 降低 Agent 落地门槛:不需要自己搭建 Agent 框架,开箱即用
- 统一多模型接口:aisuite 让模型切换成本降到最低
- 本地优先架构:隐私安全、低延迟、低成本
- 可扩展工具系统:支持自定义工具,适应不同场景
9.2 未来发展方向
根据吴恩达团队的路线图,OpenWorker 后续版本将支持:
- Windows 版本:2026 年 Q3 发布
- 多 Agent 协作:多个 Agent 共同完成复杂任务
- 知识库集成:本地 RAG 系统,增强上下文能力
- API 服务模式:桌面 App 可作为本地 API 服务,供其他应用调用
9.3 与 AI 生态的融合
OpenWorker 不是孤立的工具,而是 AI 生态的一环:
- 与 MCP 协议兼容:可以作为 MCP Server,为其他 AI 应用提供工具能力
- 与 IDE 集成:未来可能推出 VS Code / JetBrains 插件
- 与企业知识库对接:支持导入企业内部文档、Wiki
十、快速上手
安装
# macOS
brew install openworker
# 或从 GitHub 下载
git clone https://github.com/aisuite/openworker
cd openworker
pip install -e .
python -m openworker
配置模型
# ~/.openworker/config.yaml
models:
default: "anthropic:claude-fable"
providers:
openai:
api_key: "${OPENAI_API_KEY}"
anthropic:
api_key: "${ANTHROPIC_API_KEY}"
google:
api_key: "${GOOGLE_API_KEY}"
ollama:
base_url: "http://localhost:11434"
permissions:
sandbox_dirs:
- "~/Projects"
- "~/Documents"
allowed_commands:
- "git"
- "npm"
- "pip"
- "python"
开始使用
$ openworker chat
You: 帮我分析当前项目的依赖关系,生成一个依赖图
OpenWorker:
[Thought] 需要先找到项目根目录,识别包管理器,解析依赖文件
[Action] list_files(path=".", pattern="*requirements*.txt,*package.json,go.mod")
[Observation] Found package.json
[Action] read_file(path="package.json")
[Observation] {
"dependencies": {
"express": "^4.18.0",
"lodash": "^4.17.21"
},
"devDependencies": {
"jest": "^29.0.0"
}
}
[Thought] 分析完成,生成依赖图
[Final Answer]
项目依赖关系:
├── 生产依赖
│ ├── express (^4.18.0) - Web 框架
│ └── lodash (^4.17.21) - 工具库
└── 开发依赖
└── jest (^29.0.0) - 测试框架
已生成依赖图到 dependency-graph.png
结语
OpenWorker 的开源,标志着 AI Agent 从「云端实验」正式进入「桌面生产」时代。aisuite 提供的统一模型接口,加上 OpenWorker 的 Agent 运行时,为开发者提供了一个真正可用的桌面 AI 智能体。
对于个人开发者,OpenWorker 是提升效率的利器;对于企业,它是构建内部 AI 助手的起点。随着后续版本的迭代,OpenWorker 有潜力成为 AI Agent 领域的「VS Code」——定义桌面 Agent 的标准形态。
现在,是时候在你的机器上部署第一个真正能干活的 AI 助手了。
参考资源
- OpenWorker GitHub: https://github.com/aisuite/openworker
- aisuite 文档: https://github.com/andrewyng/aisuite
- 吴恩达 LinkedIn 公告: 2026-07-25
- Ollama 官网: https://ollama.ai
本文约 8500 字,深度解析了 OpenWorker 的架构设计、技术选型和实战应用。如有问题或建议,欢迎在评论区讨论。