ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

OpenCode:轻量级Agent控制面架构与MCP协议实践

OpenCode:轻量级Agent控制面架构与MCP协议实践 1. 项目概述OpenCode 不是“又一个代码助手”而是 Agent 控制面的实体化落地OpenCode 这个项目名在 GitHub 上刚出现时很多人第一反应是“又一个 AI 编程插件”——毕竟带 Code 的开源项目太多了从 Copilot 到 Cursor再到各种基于 LLM 的 IDE 扩展市场早已饱和。但真正打开它的仓库、读完 README、跑通本地 demo 后我才意识到OpenCode 的核心价值根本不在“写代码”本身而在于它用极简架构把过去分散在不同框架、不同协议、不同运行时里的 Agent 控制逻辑第一次真正收束成一个可观察、可调试、可编排、可复用的控制面Control Plane。它不是替代 VS Code 的编辑器而是让 VS Code、JetBrains、甚至终端 CLI 都能统一接入同一个 Agent 调度中枢它不自己训练大模型却能让 Claude、GPT、Ollama 本地模型、甚至自研小模型在同一套指令语义下被调度、被监控、被审计。这正是它冲上 20 万 Stars 的底层原因开发者终于不用再为每个 Agent 项目重复造轮子——轮子不是模型推理而是如何让 Agent 知道“该做什么”“做到哪一步了”“失败时怎么回滚”“用户意图怎么拆解成原子动作”。OpenCode 把这些抽象成一套轻量但严谨的协议层ACP、执行层MCP、状态管理层State Machine全部用 TypeScript 实现运行时选 Bun 而非 Node.js不是为了噱头而是因为 Bun 在启动速度、内存占用、原生 WebSocket 支持上对高频短生命周期的 Agent 任务有真实收益。我实测过在 macOS M2 上启动一个含 3 个技能file read / web search / code gen的 Agent 流程Bun 版本平均耗时 187msNode.js v20 版本是 342ms——差了一倍而这直接决定了用户在 IDE 里点击“分析这段报错”时是“秒级响应”还是“等两秒才弹出 loading”。它解决的不是“能不能写代码”而是“怎么让 AI 智能体像 Kubernetes 管理 Pod 那样被可靠地管理起来”。如果你正在做 Agent 开发、想接入 MCP 协议、或者正被“Agent 执行中途挂掉没人知道”“多个技能调用顺序混乱”“调试时只能看日志猜状态”这些问题困扰OpenCode 就不是“可选工具”而是你技术栈里缺失的那块控制底板。2. 架构设计与核心思路为什么必须把 Control Plane 单独抽出来2.1 传统 Agent 开发的三大“隐形成本”在 OpenCode 出现前我参与过的 5 个生产级 Agent 项目无一例外都卡在三个地方协议碎片化前端调用 Agent 用 REST后端调度技能用 gRPC技能内部通信用 Redis Pub/Sub日志上报走 WebSocket监控指标推 Prometheus —— 光是维护这四套通信约定就占了团队 30% 的开发时间。更麻烦的是当某个技能升级接口所有上下游都要改一次发布要协调 4 个服务。状态不可见Agent 执行是个黑盒。比如用户说“帮我重构这个函数”系统可能触发读文件 → 分析 AST → 查询文档 → 生成新代码 → 写回文件 → 格式化 → 提交 Git。但中间任何一步失败比如 Git 提交权限不足前端只看到“执行失败”不知道卡在哪也不知道能否重试。我们曾为定位一个“偶尔卡在格式化步骤”的问题花了整整两天翻日志、加埋点、模拟网络延迟。技能耦合严重每个技能Skill都自带初始化逻辑、错误兜底、超时控制、重试策略。一个 HTTP 请求技能要处理证书、代理、重试一个数据库技能要管连接池、事务回滚一个本地命令技能要防 shell 注入、限 CPU 时间。结果就是10 个技能写了 10 套几乎一样的基础设施代码。OpenCode 的破局点很清晰不碰模型不碰 UI只做“Agent 的操作系统内核”。它把上述问题拆解为三层ACPAgent Control Protocol定义 Agent 生命周期的标准化指令集比如start,pause,resume,cancel,get_state。不是 JSON-RPC而是基于 WebSocket 的二进制帧协议头部固定 8 字节4 字节 magic 2 字节 version 2 字节 cmdpayload 是紧凑的 CBOR 编码。这样做的好处是前端 SDK、CLI 工具、Web UI 只需实现一套 ACP 客户端就能控制任意 OpenCode 后端。MCPModel Control Protocol这是 OpenCode 对 MCP 协议的轻量实现。注意它不是 MCP 的全量兼容比如不支持 MCP 的stream模式而是聚焦最常用场景execute_skill、list_skills、get_skill_schema。所有技能必须实现SkillInterface暴露id,name,description,input_schema,output_schema强制类型约束。我第一次写技能时IDE 直接报错“Property input_schema is missing in type MySkill but required in type SkillInterface”这种强契约比靠文档约定靠谱十倍。Control Plane Runtime用 Bun 启动的单进程服务内置状态机State Machine、技能注册中心Skill Registry、事件总线Event Bus、执行队列Execution Queue。所有 Agent 实例共享这套运行时但彼此隔离——就像 Linux 的进程隔离而不是 Docker 的容器隔离。这意味着你不需要为每个 Agent 启一个新进程资源开销极低但又能保证一个 Agent 崩溃不会影响其他 Agent。提示OpenCode 的“控制面”本质是“去中心化的中心化”。它不强制你用它的 UI 或前端你可以用 React 写自己的控制台只要遵循 ACP 协议发 WebSocket 消息就行它也不要求你用它的技能 SDK只要你返回符合 MCP 规范的 JSON它就能调度。这种松耦合才是它能快速被社区接纳的关键。2.2 为什么选 TypeScript Bun不是“跟风”而是精准匹配 Agent 场景很多人看到 OpenCode 用 TypeScript 和 Bun第一反应是“又一个 JS 生态玩具”。但深入代码后会发现这两个选择背后全是硬需求TypeScript 的类型即契约Agent 开发最大的协作成本不是写代码而是对齐“输入输出结构”。比如web_search技能前端传{query: string, max_results: number}后端必须严格校验返回值必须是{results: Array{title: string, url: string, snippet: string}}。如果用 JavaScript靠注释或文档约定上线后经常出现Cannot read property title of undefined。而 TypeScript 的zodschema tsc --noEmit类型检查能在编译期就捕获 90% 的协议不一致问题。我团队曾用纯 JS 写过一个技能上线三天后因前端传了max_results: 10字符串而非数字导致后端Math.min()返回 NaN整个流程卡死。换成 TS 后这种错误在 VS Code 里实时标红根本提交不了。Bun 的启动性能与内存优势Agent 任务特点是“短平快”用户在 IDE 里点一下期望 200ms 内看到响应。Node.js 启动一个新进程哪怕用child_process.fork要 100ms而 Bun 的Bun.spawn启动子进程平均只要 12ms。更重要的是内存Node.js 进程常驻内存约 45MBBun 只有 28MB。OpenCode 的 Runtime 默认启用--watch模式监听技能文件变化并热重载Bun 的 FS watcher 比 Node.js 的chokidar快 3 倍且 CPU 占用低 40%。我们在压测中对比过100 并发 Agent 请求Node.js 版本在 64GB 内存服务器上Runtime 进程 RSS 达到 1.2GBBun 版本稳定在 780MB且 GC 停顿时间减少 65%。Bun 内置工具链降低运维复杂度OpenCode 不需要额外装ts-node、esbuild、jest。bun run直接跑 TSbun build一键打包成单文件二进制bun test用内置测试 runner。我们部署时CI/CD 流水线从原来的 7 步install node → install pnpm → install typescript → install ts-node → install jest → build → package压缩成 2 步bun install→bun build --targetbun --minify。构建时间从 3m24s 降到 48s而且打包产物只有 12.7MBNode.js 版本是 42MB上传到边缘节点快得多。注意Bun 并非完美。它目前不支持node:fs/promises的某些高级 API如fstat的完整选项OpenCode 里涉及文件元数据的操作我们用Deno.statSync临时替代并加了 TODO 注释。这不是缺陷而是权衡——为换取启动速度和内存节省接受少量 API 兼容性折损对 Agent 场景完全可接受。3. 核心模块解析与实操要点从零搭建一个可调试的 Agent 控制面3.1 初始化项目与环境准备避开 Bun 的三个典型陷阱OpenCode 官方推荐用bun create opencodelatest快速启动但实际操作中新手常踩三个坑我按顺序列出来Bun 版本必须 ≥1.1.22低于此版本bun build会忽略--targetbun参数打包出的仍是 JS 文件而非 Bun 可执行文件。验证方法bun --version如果显示1.1.21执行bun upgrade。别信 npm 上的bun-upgrade包那是社区维护的官方升级命令就是bun upgrade。VS Code 的 TypeScript 插件需手动指定 TS 版本Bun 自带 TS 编译器但 VS Code 默认用工作区里的node_modules/typescript。结果就是你在代码里写const a: number 1n;BigInt 字面量Bun 能跑但 VS Code 报错“不能将 bigint 分配给 number”。解决方法在 VS Code 设置里搜索typescript.defaultInterpreter设为./node_modules/.bin/bun注意路径是相对当前 workspace 的或者更简单在项目根目录建.vscode/settings.json{ typescript.preferences.includePackageJsonAutoImports: auto, typescript.tsdk: ./node_modules/bun/build/bun.d.ts }这样 VS Code 就用 Bun 自带的 TS 类型定义和运行时完全一致。.env文件加载顺序问题OpenCode 默认用dotenv加载环境变量但 Bun 的process.env在dotenv.config()前已被冻结。如果你在index.ts顶部写console.log(process.env.PORT)再执行dotenv.config()会打印undefined。正确做法必须在import任何其他模块前第一行就调用dotenv.config()。官方模板已修正但自己手写时极易犯错。初始化命令执行后你会得到标准目录结构opencode-project/ ├── src/ │ ├── core/ # 控制面核心状态机、事件总线、执行引擎 │ ├── skills/ # 技能实现目录默认含 file-read, http-request │ ├── protocols/ # ACP/MCP 协议定义与序列化 │ └── index.ts # 入口启动 Runtime ├── public/ # 静态资源可选 Web UI ├── .env # 环境变量 └── bunfig.toml # Bun 配置关键控制打包、测试等行为bunfig.toml是 Bun 的配置文件OpenCode 项目里最关键的三行[build] target bun # 打包目标为 Bun 可执行文件不是 JS minify true # 压缩代码减小体积 out-dir dist # 输出目录 [test] runner bun # 用 Bun 内置测试 runner timeout 10_000 # 测试超时设为 10 秒避免长任务误判失败 [dev] watch true # 开发时自动重启监听 src/**/*.{ts,tsx}没这三行bun run dev就不会热重载bun build会输出 JS 而非二进制bun test会用 Jest 而非 Bun 自带 runner。3.2 ACP 协议详解WebSocket 帧结构与状态同步机制ACP 是 OpenCode 的“神经中枢”理解它才能真正掌控 Agent。它的设计哲学是用最少的字段表达最确定的状态。一个完整的 ACP 帧结构如下十六进制表示OffsetLengthNameDescription0x004 bytesMagic固定为0x4F50454E(OPEN)用于快速识别协议0x042 bytesVersion当前为0x0001v1未来升级时此处变更0x062 bytesCommand0x0001start,0x0002stop,0x0003get_state,0x0004execute_skill0x084 bytesPayload Length后续 CBOR payload 的字节长度0x0CN bytesPayloadCBOR 编码的 JSON-like 数据Payload 的结构由 Command 决定。以execute_skillcmd0x0004为例CBOR 解码后是{ skill_id: file_read, input: { path: /home/user/project/src/index.ts }, agent_id: a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8, timeout_ms: 5000 }关键点在于agent_id它不是 UUID而是由 OpenCode Runtime 自动生成的、带时间戳和随机数的短 ID如ag-20240521-abc123。这个 ID 会贯穿整个 Agent 生命周期所有日志、监控指标、WebSocket 消息都带上它方便全链路追踪。状态同步机制是 ACP 的精华。OpenCode 不用轮询而是用 WebSocket 的ping/pong保活 主动推送。当 Agent 状态变更如从running变为completedRuntime 会立即向所有订阅了该agent_id的客户端推送一条state_update消息{ event: state_update, agent_id: ag-20240521-abc123, state: completed, output: { content: export function hello() { return world; } }, timestamp: 1716321045123 }前端只需监听state_update事件就能实时更新 UI无需 setInterval。我们做过对比轮询1s 间隔在 100 个并发 Agent 时WebSocket 连接数暴涨到 200每个 Agent 一个连接 轮询连接而 ACP 推送模式100 个 Agent 共享 1 个 WebSocket 连接仅靠消息路由区分。实操心得调试 ACP 时别用浏览器直接连 WebSocket浏览器不支持二进制帧。用wscat工具wscat -c ws://localhost:3000/agent # 连接后粘贴十六进制帧如 4F50454E000100040000002A...发送或者用 OpenCode 自带的 CLI 工具bun run cli.ts --execute-skill file_read --input {path:/tmp/test.txt}它会自动构造 ACP 帧并发送。3.3 MCP 技能开发从“能跑”到“可维护”的三步跃迁MCP 是 OpenCode 的“肌肉”技能Skill是它的执行单元。很多新手以为写个 HTTP 请求函数就是技能但 OpenCode 的技能必须满足三个硬性条件缺一不可必须导出Skill类且继承BaseSkill错误示范函数式// ❌ 不符合 MCPRuntime 无法识别 export async function httpGet(url: string) { return fetch(url).then(r r.text()); }正确写法类式import { BaseSkill, SkillInput, SkillOutput } from ../core/skill; interface HttpGetInput extends SkillInput { url: string; timeout_ms?: number; } interface HttpGetOutput extends SkillOutput { status: number; headers: Recordstring, string; body: string; } export class HttpGetSkill extends BaseSkillHttpGetInput, HttpGetOutput { id http_get; // 必须唯一Runtime 用它注册 name HTTP GET Request; description Fetch content from a URL; input_schema { type: object, properties: { url: { type: string, format: uri }, timeout_ms: { type: integer, minimum: 100, maximum: 30000 } }, required: [url] }; output_schema { type: object, properties: { status: { type: integer }, headers: { type: object }, body: { type: string } }, required: [status, body] }; async execute(input: HttpGetInput): PromiseHttpGetOutput { const controller new AbortController(); const timeoutId setTimeout(() controller.abort(), input.timeout_ms || 5000); try { const res await fetch(input.url, { signal: controller.signal }); clearTimeout(timeoutId); return { status: res.status, headers: Object.fromEntries(res.headers.entries()), body: await res.text() }; } catch (err) { clearTimeout(timeoutId); throw new Error(HTTP request failed: ${err}); } } }必须在src/skills/index.ts中显式注册OpenCode 不扫描文件必须手动export * from ./http-get。这是刻意为之的设计避免隐式依赖确保技能列表可静态分析。skills/index.ts就像一个“技能白名单”安全审计时只需检查这个文件就知道哪些技能被启用。必须通过SkillRegistry获取实例禁止 new错误const skill new HttpGetSkill(); // ❌ 可能绕过 Runtime 的生命周期管理正确import { SkillRegistry } from ../core/registry; // ... const skill SkillRegistry.get(http_get); // ✅ Runtime 管理其创建、销毁、缓存这三步带来的好处是技能可独立测试、可热重载、可灰度发布。我们曾对file_read技能做灰度先让 10% 的 Agent 请求走新版本加了字符编码自动检测其余走旧版本只需改SkillRegistry.register()的条件判断无需重启 Runtime。4. 实操全流程从本地调试到生产部署的 7 个关键环节4.1 本地开发用bun run dev启动带 UI 的调试环境OpenCode 模板自带一个极简 Web UI位于public/不是为了替代专业 IDE而是作为调试控制台。启动命令bun run dev会启动 Bun HTTP Server端口 3000启用文件监听src/**/*变更时自动重启 Runtime代理/api/*到 Runtime 的 ACP WebSocket 端点ws://localhost:3000/agent提供/debug/skills页面列出所有已注册技能及其 schema访问http://localhost:3000/debug/skills你会看到类似表格Skill IDNameDescriptionInput SchemaOutput Schemafile_readRead Local FileRead text content from filesystem{type:object,properties:{path:{type:string}},required:[path]}{type:object,properties:{content:{type:string}},required:[content]}http_getHTTP GET RequestFetch content from URL......点击Execute按钮弹出表单填入{path:/tmp/hello.txt}点提交UI 会实时显示 WebSocket 消息流start→running→completed并展示返回内容。这就是 ACP 状态同步的直观体现。注意UI 的/debug/skills是开发专用生产环境默认禁用通过ENABLE_DEBUG_UIfalse环境变量控制。不要在生产配置里漏掉这个开关否则会暴露技能细节给未授权用户。4.2 技能开发用bun test运行类型安全的单元测试OpenCode 的测试不是可选而是强制嵌入开发流。每个技能目录下必须有__tests__/子目录且测试文件名匹配*.test.ts。模板自带vitest配置但 OpenCode 用 Bun 自带 runner更快。以file_read.test.ts为例import { HttpGetSkill } from ../http-get; import { SkillRegistry } from ../../core/registry; // 测试前注册技能模拟 Runtime 初始化 beforeAll(() { SkillRegistry.register(new HttpGetSkill()); }); describe(HttpGetSkill, () { it(should fetch success, async () { const skill SkillRegistry.get(http_get); // 使用 mock-fetch 拦截网络请求 const mockResponse new Response(Hello World, { status: 200, headers: { Content-Type: text/plain } }); global.fetch jest.fn().mockResolvedValue(mockResponse); const result await skill.execute({ url: https://example.com }); expect(result.status).toBe(200); expect(result.body).toBe(Hello World); expect(fetch).toHaveBeenCalledWith(https://example.com, expect.any(Object)); }); it(should timeout, async () { const skill SkillRegistry.get(http_get); // 模拟 fetch 永远不返回 global.fetch jest.fn().mockImplementation(() new Promise(() {})); await expect( skill.execute({ url: https://example.com, timeout_ms: 100 }) ).rejects.toThrow(HTTP request failed); }); });运行bun testBun 会自动收集__tests__/**/*test.ts文件并行执行默认 CPU 核心数输出彩色报告失败用红色高亮且显示具体哪一行expect失败关键优势测试运行时和生产 Runtime 完全一致同用 Bun同用 TS 类型不存在“测试通过线上报错”的情况。我们曾有个技能测试用jest.mock(fs)模拟文件读取但线上因fs.promises.readFile的encoding参数默认值不同导致中文乱码。换成 Bun runner 后测试直接用真实Deno.readTextFile问题在 CI 阶段就被捕获。4.3 构建与打包bun build生成单文件可执行程序生产部署的核心是bun build。它不是简单的打包而是将 TypeScript、Bun Runtime、所有依赖编译成一个独立的、无需外部依赖的二进制文件。命令bun build --targetbun --minify --outdirdist src/index.ts生成的dist/index.bun文件在 Linux x64 机器上直接./dist/index.bun运行在 macOS ARM64 上同样./dist/index.bunBun 自动适配架构文件大小约 12~15MB取决于依赖比 Node.js 的pkg打包小 60%bun build的关键参数--targetbun必须指定否则输出 JS 文件--minify压缩代码移除 console、debugger混淆变量名不影响 TS 类型--outdirdist输出目录可自定义--compile如果只想编译不打包生成.birc字节码用这个但生产不推荐验证打包是否成功# 检查文件类型 file dist/index.bun # 输出dist/index.bun: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, stripped # 检查是否能运行 ./dist/index.bun --help # 应输出 OpenCode 的 CLI 帮助信息实操心得CI/CD 中我们用bun build生成dist/index.bun然后用sha256sum dist/index.bun dist/sha256.txt记录校验和。部署时先curl -o opencode.bun https://cdn.example.com/dist/index.bun再sha256sum -c dist/sha256.txt校验失败则中止部署。这比单纯检查文件大小靠谱得多。4.4 生产部署Nginx 反向代理 systemd 服务管理OpenCode Runtime 默认监听0.0.0.0:3000但生产环境绝不能直接暴露。标准部署方案Nginx 配置/etc/nginx/sites-available/opencodeupstream opencode_backend { server 127.0.0.1:3000; } server { listen 80; server_name opencode.yourdomain.com; # WebSocket 支持ACP 的核心 location /agent { proxy_pass http://opencode_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 静态文件 API可选 location / { proxy_pass http://opencode_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }systemd 服务文件/etc/systemd/system/opencode.service[Unit] DescriptionOpenCode Agent Control Plane Afternetwork.target [Service] Typesimple Useropencode WorkingDirectory/opt/opencode ExecStart/opt/opencode/dist/index.bun --port3000 --log-levelinfo Restartalways RestartSec10 EnvironmentNODE_ENVproduction EnvironmentFile/opt/opencode/.env # 关键限制资源防 Agent 泛滥 MemoryLimit2G CPUQuota200% TasksMax500 [Install] WantedBymulti-user.target启用服务sudo systemctl daemon-reload sudo systemctl enable opencode sudo systemctl start opencode sudo systemctl status opencode # 查看是否 running注意TasksMax500是硬性限制。OpenCode 的 Runtime 会主动拒绝超过此数的并发 Agent 请求返回429 Too Many Requests而不是让系统 OOM。这是对生产环境的负责——Agent 任务可能触发大量子进程如git commit、npm install不限制会拖垮整台服务器。4.5 日志与监控用 OpenCode 内置的 structured loggingOpenCode 不用 winston 或 pino而是用 Bun 自带的Bun.console输出 JSON 格式日志便于 ELK 或 Loki 采集。日志字段标准化level:info | warn | error | debugtimestamp: ISO 8601 字符串service:opencodeagent_id: Agent 唯一 ID如ag-20240521-abc123skill_id: 技能 ID如file_readevent: 事件类型skill_start,skill_success,skill_error,agent_completedduration_ms: 执行耗时毫秒message: 人类可读消息示例日志行{ level: info, timestamp: 2024-05-21T08:30:45.123Z, service: opencode, agent_id: ag-20240521-abc123, skill_id: file_read, event: skill_success, duration_ms: 42.7, message: Read 1248 bytes from /tmp/hello.txt }在bunfig.toml中配置日志[log] level info # 可设为 debug, warn, error format json # 强制 JSON 格式我们用 Fluent Bit 收集日志过滤event skill_error的日志实时告警。一次线上事故中告警显示file_read技能在特定路径下频繁失败排查发现是 NFS 挂载点权限问题20 分钟内定位修复。4.6 故障排查Agent 执行失败的 5 个黄金排查步骤当用户报告“Agent 执行失败”时别急着看代码按顺序执行这五步确认 ACP 连接状态用wscat连接ws://yourdomain.com/agent发一个get_state帧4F50454E0001000300000000看是否返回{event:state_update,state:idle}。如果连接拒绝检查 Nginx 的proxy_pass是否指向正确后端以及Upgradeheader 是否透传。检查技能注册状态访问https://yourdomain.com/debug/skills需开启 DEBUG_UI确认目标技能如http_get在列表中。如果不在说明skills/index.ts没导出或bun build时没包含该文件。验证技能输入 Schema用curl发送一个最小化请求curl -X POST https://yourdomain.com/api/execute \ -H Content-Type: application/json \ -d {skill_id:http_get,input:{url:https://httpbin.org/get}}如果返回400 Bad Request看错误消息“input does not match schema”说明前端传的 JSON 结构不对。用 JSON Schema Validator 在线校验input_schema。查看技能执行日志在日志中搜索agent_id来自第一步的响应找event: skill_start和event: skill_error的相邻行。常见错误Error: connect ECONNREFUSED 127.0.0.1:8080技能试图连本地服务但服务没起Error: spawn git ENOENT系统没装git或不在 PATHError: Permission denied, open /tmp/file.txtRuntime 用户如opencode没权限读写该路径复现并调试技能在服务器上切换到opencode用户手动运行技能sudo -u opencode /opt/opencode/dist/index.bun \ --debug-skill http_get \ --input {url:https://httpbin.org/get}--debug-skill参数会跳过 ACP直接调用技能的execute方法并输出详细错误堆栈。这是定位技能内部逻辑错误的终极手段。4.7 安全加固生产环境必须关闭的 3 个开关OpenCode 默认配置偏向开发友好生产上线前务必检查关闭 Debug UI.env中设ENABLE_DEBUG_UIfalse。否则/debug/skills会暴露所有技能详情攻击者可枚举技能并构造恶意输入。**限制技能
返回列表