Agent Zero Orchestrator 插件深度解析:用 Skill 而非 Tool 委派外部终端编码 Agent
【免费下载链接】agent-zeroAgent Zero AI framework项目地址: https://gitcode.com/GitHub_Trending/ag/agent-zero
在 Agent Zero 框架中,Orchestrator 插件负责把仓库与编码类工作委派给外部终端/无头(headless)编码 Agent,例如 Claude Code、Codex CLI、Cursor CLI、Gemini CLI、Grok Build、Hermes Agent、OpenCode,以及另一个 Agent Zero 无头实例。它的核心设计决策是:不注册常驻的terminal_agent工具,而是通过按需加载的orchestratorskill 来承载委派指令,配合状态适配器(status adapter)与 Settings 设置界面完成二进制探测、认证检测和安全断开。读完后,你能理解该插件"skill 驱动 + 适配器只做状态"的架构、各适配器的认证检测机制、default_config.yaml全部配置项,以及如何在框架中验证与扩展这套委派体系。
插件定位:Skill 代替 Tool 的委派架构
插件在 plugin.yaml 中声明为版本 0.2.0,挂载在 Settings 的external分组下,且明确per_project_config: false、per_agent_config: false——即配置是全局唯一的,不按项目或 Agent 拆分。
根据 plugins/_orchestrator/AGENTS.md 的 Purpose 小节,插件承担三项职责:
- 提供一个捆绑的 Agent Zero 插件,把仓库与编码工作委派给外部终端/无头 Agent;
- 通过暴露
orchestratorskill 而非terminal_agent工具,把冗长的委派指令移出每次对话都加载的系统提示词; - 拥有适配器状态元数据、Settings UI、Codex 设备登录 API,以及面向 Agent Zero headless、Codex CLI、Claude Code、Cursor CLI、Gemini CLI、Grok Build、Hermes Agent、OpenCode 和未来终端 Agent 的 skill 指令。
"工具化"与"技能化"不是措辞差异,而是有硬性约束的契约。AGENTS.md 的 Local Contracts 要求插件必须保持 toolless 状态:
- 不得存在
tools/terminal_agent.py; - 不得存在子进程 runner;
- 不得存在
agent.system.tool.terminal_agent.md提示词文件。
这些约束由回归测试强制校验。test_status_adapters.py 中的test_tool_runner_files_are_removed直接断言这三个文件不存在,test_adapters_are_status_only则断言所有适配器都没有install_command、build_command、parse_session_id、format_output等执行类方法:
def test_adapters_are_status_only(): for adapter in list_adapters(): assert not hasattr(adapter, "install_command") assert not hasattr(adapter, "build_command") assert not hasattr(adapter, "parse_session_id") assert not hasattr(adapter, "format_output")实际执行路径因此是:外部 Agent 通过 Agent Zero 普通的 shell/代码执行工具来编排,前提是orchestratorskill 已加载(见 SKILL.md 的 frontmatter,allowed_tools声明为code_execution_tool、code_execution_remote、memory_load、memory_save)。适配器只报告安装状态、二进制解析结果、认证状态、是否可安全断开、是否支持设备登录——它们不构建也不运行任务命令。helpers/AGENTS.md 进一步重申:helpers 不拥有 shell 命令执行、长进程管理或任务输出解析,"如果确实需要命令编排,把指令写进 skill,而不是加一个 runner"。
目录结构与所有权边界
AGENTS.md 的 Ownership 小节划定了源码契约与运行时状态的边界。源码头文件(source-owned)包括.gitignore、plugin.yaml、default_config.yaml、LICENSE、README.md、api/、helpers/、skills/、tests/、webui/(含thumbnail.png);而config.json、data/、__pycache__/、凭据存储和生成的截图属于运行时/用户状态,不是源码契约。
AGENTS.md 末尾的 Child DOX Index 给出了各子目录的文档索引(已转换为仓库根相对路径):
| 子目录 | 职责范围 |
|---|---|
| api/AGENTS.md | 状态查询、设备登录轮询、断开连接的插件 HTTP API 处理器 |
| helpers/AGENTS.md | 适配器注册表、基础契约与共享 helper 行为 |
| skills/AGENTS.md | 插件 skill 集合与面向 Agent 的委派指令 |
| tests/AGENTS.md | 插件契约与 skill 文本的直接回归检查 |
| webui/AGENTS.md | Settings UI 标记、Alpine store、状态展示与设备登录 UI |
被刻意排除在索引之外的生成/本地路径及其原因也做了说明:config.json(本地插件设置状态)、data/(插件自有凭据/状态目录)、__pycache__/(生成的 Python 字节码)。
适配器契约:状态只读,不做执行
所有适配器继承 base.py 中的抽象基类TerminalAgentAdapter,契约面非常小:
- 类级元数据:
id、title、binary、install_hint、description; - 环境能力:
data_dir()返回插件私有目录usr/plugins/_orchestrator/data/<adapter_id>/(自动创建,用于存放认证与状态);resolve_binary(config)优先取配置中的binary字段,回退到类级默认值;is_installed(config)对绝对路径检查可执行文件存在性,对相对名走shutil.which; - 认证能力:唯一的抽象方法
auth_status(config),必须返回{connected: bool, mode: 'plugin'|'external'|'', auth_path: str}; - 可选能力默认关闭:
supports_device_login()和can_disconnect()默认返回False,start_device_login()、poll_device_login()、disconnect()默认抛NotImplementedError。
注册表 registry.py 是"排序与暴露适配器的唯一位置":八个适配器按 A0 在前的顺序构造为字典,get_adapter()按 id 查找(找不到时抛异常并列出可用 id),adapter_config()必须容忍缺失或畸形的插件配置并返回空字典——AGENTS.md 把这条明确写成了契约。注册顺序本身也是被测试锁定的产品决策:test_registry_order_puts_a0_first断言列表顺序严格为a0, codex, claude, cursor, gemini, grok, hermes, opencode,helpers 文档也写明"A0 Headless 必须保持在list_adapters()首位,除非产品方向改变"。
设置界面的数据来源是 api/status.py 的Status处理器:它遍历list_adapters(),逐个取出适配器配置块,调用auth_status()(单适配器异常被捕获为{"connected": False, "error": ...},不让异常逃逸成框架级故障),汇总成{ok: True, agents: [...]}返回,每个条目包含id、title、description、binary、installed、install_hint、supports_device_login、can_disconnect与auth状态。按 api/AGENTS.md 的契约,install_hint仅用于展示/帮助,绝不能触发安装;设备登录端点必须拒绝未显式支持设备登录的适配器;响应中永远不返回 token 值、API key 或原始凭据 JSON。
适配器实现剖析:A0 Headless 作为第一个适配器
A0 适配器(a0.py)是插件的基准实现,也体现了两个典型模式——二进制回退与连接探测:
DEFAULT_HOST = "http://localhost:80" DEFAULT_DOCKER_A0_BINARY = "/opt/venv/bin/a0" class AgentZeroAdapter(TerminalAgentAdapter): id = "a0" binary = "a0" def resolve_binary(self, config=None): binary = super().resolve_binary(config) if binary == self.binary and shutil.which(binary) is None: bundled = Path(DEFAULT_DOCKER_A0_BINARY) if bundled.is_file(): return str(bunduted := str(bundled)) # 实际代码直接 return str(bundled) return binary(示意说明:真实实现中,当配置的a0在 PATH 中找不到时,回退到容器内捆绑的/opt/venv/bin/a0,这正是default_config.yaml中注释 "falls back to /opt/venv/bin/a0 in Agent Zero Docker" 的底层机制。)
host 解析遵循明确的优先级链:适配器配置host>AGENT_ZERO_HOST环境变量 > 容器内本地实例http://localhost:80(容器内 WebUI 监听 80 端口,所以默认目标就是运行本插件的这个实例)。认证检测则退化为一次 2 秒超时的 TCP 连接探测(_probe),连通即{"connected": True, "mode": "external", "auth_path": host}。
从源码结构看,这个设计让 A0 具备两种用法:让 Agent Zero 委派到另一个运行时实例,或让同一实例自问自答一个聚焦问题。但 AGENTS.md 特别标注 A0 是设置流程中的"例外":当用户未指定目标时,Agent Zero 必须先询问"用当前这个 Agent Zero 实例,还是另一个/新拉起的实例",而不是走通用登录流程;且委派目标实例的提示词必须要求其直接作答、不得再通过终端 Agent 委派回来,以避免递归委派死循环(AGENTS.md Work Guidance 的收尾条款)。
配置参考:default_config.yaml 全量参数
default_config.yaml 是各适配器的命令默认值,逐项说明如下:
a0: binary: a0 # 回退到 Agent Zero Docker 中的 /opt/venv/bin/a0 host: "" # 空 = 取 AGENT_ZERO_HOST 环境变量,否则为本地实例 (http://localhost:80) codex: binary: codex model: "" bypass_sandbox: true claude: binary: claude model: "" permission_mode: bypassPermissions allowed_tools: "Bash,Read,Edit" bare: false cursor: binary: agent output_format: text force: true gemini: binary: gemini model: "" grok: binary: grok model: "" output_format: json always_approve: true no_auto_update: true hermes: binary: hermes model: "" provider: "" toolsets: "" yolo: true opencode: binary: opencode model: "" agent: "" auto: true几个默认值背后的意图可以直接在测试中印证:test_claude_defaults_skip_permissions断言 Claude Code 默认跳过权限交互(permission_mode: bypassPermissions),test_grok_defaults_headless_automation与test_cursor_defaults_headless_automation分别锁定 Grok 的output_format: json/always_approve/no_auto_update和 Cursor 的binary: agent/output_format: text/force: true——它们共同保证各 CLI 能无头自动化运行而不卡在交互审批上。运行时用户覆盖后的插件配置落在/a0/usr/plugins/_orchestrator/config.json,skill 指令要求"只读取你需要的适配器块,且绝不打印密钥"。
支持的 Agent 与认证方式
README.md 汇总了当前八个适配器的 CLI 与登录方式,这也是设置界面"External Services > Orchestrator"所展示的内容来源:
| Agent | CLI | 登录方式 |
|---|---|---|
| Agent Zero (headless) | a0 | 实例/login会话;受保护主机下 shell 中的A0_USERNAME/A0_PASSWORD |
| OpenAI Codex | codex | 设置界面发起的 ChatGPT 设备登录,或外部 CLI 登录 |
| Claude Code | claude | 外部claude登录或ANTHROPIC_API_KEY |
| Cursor CLI | agent | CURSOR_API_KEY、NO_OPEN_BROWSER=1 agent login,或已缓存的 Cursor 登录 |
| Gemini CLI | gemini | 已缓存的 Google 登录、GEMINI_API_KEY,或 Vertex AI 凭据 |
| Grok Build | grok | XAI_API_KEY、grok login --device-auth,或已缓存的 Grok 登录 |
| Hermes Agent | hermes | 外部 Hermes/provider 配置、~/.hermes/.env、~/.hermes/auth.json或 provider 环境变量 |
| OpenCode | opencode | 外部opencode auth login、provider 环境变量,或~/.local/share/opencode/auth.json |
认证检测不是猜测而是查具体来源,测试用例给出了可验证的例子:test_cursor_detects_agent_zero_cursor_env_key表明仅设置API_KEY_CURSOR(Agent Zero 风格的命名)就能让 Cursor 适配器报出auth_path == "API_KEY_CURSOR";test_gemini_detects_supported_auth_sources则覆盖GEMINI_API_KEY环境变量与.env文件两种来源。外部 CLI 的凭据留在各 CLI 自己的 home/config 路径(如~/.hermes/auth.json、~/.local/share/opencode/auth.json),这与 AGENTS.md"外部 CLI 状态留在 CLI 自己的 home/config 路径"的契约一致。
设置界面的职责边界同样明确:它只做状态展示与命令默认值,可以刷新状态、仅在适配器能安全移除已知凭据存储时断开凭据,不得提供通用安装按钮——安装/登录属于 skill 引导的人机协同 shell 流程。Codex 设备登录是当前唯一由该插件在设置界面持有的 OAuth 流程,其 token 存于插件数据目录data/codex/auth.json(文件权限 mode 600),README 还特别警告:token 属于等同密码的凭据,不要在同一份可轮换 refresh token 的 auth 文件之间共享多个客户端。
orchestrator skill:委派工作流
skill 是插件的"大脑"。SKILL.md 定义了触发词("delegate to codex"、"delegate to claude code"、"terminal agent" 等)与全局规则,关键约束包括:
- 先定执行位置:对 Codex、Claude Code、Cursor CLI、Gemini CLI、Grok Build、Hermes Agent、OpenCode,先判断跑在用户本地机器(经 A0 CLI 连接器)还是 Agent Zero 容器 shell;用户没说明时,先查记忆中是否已有偏好(
memory_load),没有就问一次,用户选择后用memory_save存下按 Agent 划分的稳定偏好; - 禁止 Computer Use:不得用屏幕操控去驱动编码 Agent 的终端/菜单/TUI,只用
code_execution_remote或code_execution_tool跑无头 CLI 命令,做不到就停下来问; - 认证保持人在环:可以发起登录命令、把 URL/设备码/浏览器步骤转述给用户,等用户确认后再重跑冒烟提示;登录菜单出现时把选项展示到聊天里让用户选,再把用户所选的编号/按键发回原终端会话,而不是让用户钻进 Docker shell 去点菜单;没有更安全路径时绝不要求用户在聊天里粘贴密钥;
- 工作流闭环:检查安装 → 缺失则只装被要求的那个 CLI → 探测
--version/--help→ 跑极小的冒烟提示 → 缺认证时只跑 reference 中指定的登录命令 → 用户确认后重跑冒烟 → 才执行真实任务; - 任务简报要自包含:目标、目标文件或仓库路径、约束、验证命令、期望输出;任务结束后检查终端 Agent 的输出并自行验证关键改动,再报告成功;
- 长任务:在 shell 会话中启动 CLI 并轮询该会话输出,不要给终端 Agent 套自定义超时包装。
SKILL.md 把工作流分成两条路径:
- Host CLI Flow(默认):用户想用自己本机已装好的 Claude Code/Codex 等。要求用
code_execution_remote而非code_execution_tool(路径、shell、登录态、已装 CLI 都归属 A0 CLI 宿主机)。若远程执行不可用,skill 给出一段固定话术引导用户安装 A0 CLI(macOS/Linux 用curl -LsSf https://cli.agent-zero.ai/install.sh | sh,Windows PowerShell 用irm https://cli.agent-zero.ai/install.ps1 | iex),在 A0 CLI 中连接实例后按F4允许 Remote Code Execution、需要宿主文件写入时再按F3。workdir 语义保持在宿主侧:cd到宿主项目路径,而不是/a0/usr/workdir。 - Container Pal Flow:用户明确选择容器内 Agent 时,A0 headless 走
references/a0.md的目标选择流程;其余适配器统一走"读 reference → 查安装 → 按需安装 → 探测版本 → 冒烟 → 认证 → 真实任务"七步循环。两个位置上的 Agent 可以在一个工作流里同时咨询,但 shell 会话必须分开、标注每个答案的来源并比较后再行动。
每个适配器的可复制命令沉淀在skills/orchestrator/references/下的独立文件中(a0.md、codex.md、claude.md 等八份)。例如 Codex 的委派命令:
cd "$WORKDIR" codex exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox "$TASK"Claude Code 对非交互运行默认跳过权限(root 下不加权限参数,普通用户下加--permission-mode bypassPermissions --allowedTools Bash,Read,Edit):
cd "$WORKDIR" if [ "$(id -u)" -eq 0 ]; then claude -p "$TASK" --output-format json else claude -p "$TASK" --output-format json --permission-mode bypassPermissions --allowedTools Bash,Read,Edit fiSKILL.md 末尾也规定了文档维护原则:通用编排规则留在 SKILL.md,Agent 特有的命令、认证怪癖、安装提示与冒烟提示全部下沉到对应 reference 文件——这与 AGENTS.md"通用行为放 skill,逐 Agent 命令细节放 reference 文件"的 Work Guidance 完全一致。
工程协作与验证
AGENTS.md 的 Work Guidance 汇总了若干协作契约:
- 增删适配器时,源码文档、UI 标签、适配器元数据、测试、
skills/orchestrator/SKILL.md与各 Agent reference 必须同步更新; - 偏好直接、可发现的适配器元数据,避免第二层抽象;
- 修改 skill 后要提醒测试者开新对话或重新加载
orchestrator,因为已加载的 skill 文本可能仍附着在旧会话上; - Codex 设备登录是当前唯一由设置界面持有的 OAuth 流程,只有当凭据存储与撤销/断开路径明确时才允许添加第二个。
验证命令(AGENTS.md Verification 小节)原样保留:
# 框架运行时中的适配器自检 docker exec 8dc967046cda bash -lc 'cd /a0 && /opt/venv-a0/bin/python plugins/_orchestrator/tests/test_status_adapters.py' # 编辑 WebUI JavaScript 后的前端语法检查 node --check plugins/_orchestrator/webui/orchestrator-store.js # 打包前清理生成的字节码 find plugins/_orchestrator -type d -name __pycache__ -prune -exec rm -rf {} +其中docker exec 8dc967046cda ...依赖特定容器 id,实际使用时应替换为自己运行中的 Agent Zero 容器;测试文件自身会向上寻找含agent.py的仓库根并插入sys.path,所以脱离 Docker 直接python plugins/_orchestrator/tests/test_status_adapters.py也是可行的。API 层另有纯导入变更的轻量检查(python -m py_compile plugins/_orchestrator/api/*.py,见 api/AGENTS.md)。
扩展指南:如何新增一个终端 Agent
综合 AGENTS.md 的契约与 README.md 的 "Adding A New Agent" 小节,新增适配器的完整步骤是:
- 在 helpers/adapters/ 下新建
<name>.py,子类化TerminalAgentAdapter(base.py)并实现auth_status();只有当凭据存储明确时,才添加可选的安全断开或设备登录支持; - 在 registry.py 的
_ADAPTERS字典中注册实例(A0 必须保持在首位); - 在 default_config.yaml 添加对应配置块;
- 在
skills/orchestrator/references/<name>.md添加简洁的命令指引(安装检查、版本探测、冒烟提示、登录命令); - 在 SKILL.md 的 Reference Files 列表加入该 reference,仅当全局编排循环变化时才更新通用规则;
- 同步 README 的 Supported Agents 表与测试。
状态 API 与设置界面会自动拾取新注册的适配器,无需改动 WebUI——这是"适配器元数据即界面"设计的直接收益:新增能力的工作量集中在适配器类、注册表、配置块与 reference 文档四处,执行路径始终复用普通的 shell/代码执行工具,委派指令始终按需加载而非常驻提示词。
【免费下载链接】agent-zeroAgent Zero AI framework项目地址: https://gitcode.com/GitHub_Trending/ag/agent-zero
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考