# Circow 开发者文档 > Circow(圈牛)是一个「AI 员工」平台:用户在平台上编排工作流(Flow,即一个 AI 员工),通过网页、桌面客户端、微信客服、HTTP API 等渠道使用它。本文档面向要把 AI 员工接入自己系统、或为员工扩展新工具的外部开发者。所有能力共用同一套账号与计费。 四种接入方式: 1. HTTP API —— 服务端调用工作流:同步 / 流式(SSE)/ 文件上传,Bearer Key 鉴权,session_id 多轮续接 2. Deep Link(桌面唤起)—— 本机软件通过自定义 URL 协议拉起桌面客户端,指定工作流、预填 prompt、可选自动发送 3. Skill 开发 —— 一个 SKILL.md + 本机 CLI 工具,为员工扩展本机能力,可发布到技能市场 4. MCP Server 开发 —— 按 Model Context Protocol 开发工具服务,绑定到工作流后即可被 AI 调用 站点:国内 https://circow.cn (应用 https://app.circow.cn)· 海外 https://circow.com (应用 https://app.circow.com)。 本文档为中文。全文单文件版:https://circow.cn/docs/llms-full.txt ## 文档 - [概览与术语](https://circow.cn/docs/index.md):平台概念(Flow / 员工 / Skill / MCP / 市场)、四种接入方式如何选 - [HTTP API](https://circow.cn/docs/api.md):鉴权、请求体、同步调用、SSE 流式、文件上传、会话列表、消息历史、错误码,含 curl / Python 示例 - [桌面唤起 Deep Link](https://circow.cn/docs/deep-link.md):协议结构、scheme、run-flow / install-skill / install-mcp / manage-mcp / install-template 各 action 参数、安全模型 - [Skill 开发](https://circow.cn/docs/skills.md):目录结构、SKILL.md frontmatter、description 编写规范、skill-manager 命令、注入的环境变量、发布 - [MCP Server 开发](https://circow.cn/docs/mcp.md):mcp.json schema、server.py 要点、mcp_tool.py 安装/列表/发布、npx 预热、分发 - [发布渠道](https://circow.cn/docs/channels.md):微信客服 / API / Deep Link 已可用,网页嵌入 / Webhook 规划中 ## 可选 - [完整文档单文件版 llms-full.txt](https://circow.cn/docs/llms-full.txt):以上全部内容拼接,适合一次性喂给 AI ------------------------------------------------------------------------ # Circow 开发者文档 · 概览 > 本页是 Circow 开发者文档的入口。AI 友好索引见 [llms.txt](https://circow.cn/docs/llms.txt),全文单文件版见 [llms-full.txt](https://circow.cn/docs/llms-full.txt)。 ## Circow 是什么 Circow(圈牛)是一个「AI 员工」平台。用户在平台上创建并编排 **工作流(Flow)**——每个 Flow 就是一个 AI 员工,拥有自己的系统提示词、模型、工具(Skill / MCP)与会话记忆。员工可以通过网页端、桌面客户端(Windows / macOS)、移动端、微信客服、HTTP API 等多种渠道被使用。 开发者中心(登录后 `https://app.circow.cn/flow_app/developers`)提供与本文档相同的内容,并附带只对登录用户有效的交互工具(API Key 管理、Deep Link URL 生成器、工作流 ID 列表)。 ## 术语 | 术语 | 含义 | | --- | --- | | Flow / 工作流 / 员工 | 一个可被调用的 AI 员工。有唯一 UUID(`flowId`)。API、Deep Link 都以它为目标 | | Session / 会话 | 一次多轮对话。由 `session_id` 标识,续传即可保留上下文 | | API Key | 与某个 Flow 绑定的密钥,形如 `fk_xxx`。在开发者中心「API 集成」栏目创建,明文只显示一次 | | Skill | 本机能力扩展:一个目录,含 `SKILL.md`(告诉 AI 何时、如何用)+ CLI 工具实现。在桌面客户端内运行 | | MCP Server | 按 Model Context Protocol 实现的工具服务进程,由桌面客户端拉起并托管 | | 市场 | 官方技能 / MCP / 员工模板市场。Skill 与 MCP 可发布上架,用户一键安装 | | 桌面客户端 | Windows / macOS 客户端。国内版下载 https://circow.cn/download ,海外版 https://circow.com/download | | 区域版本 | 国内版(cn,域名 circow.cn / app.circow.cn)与海外版(global,域名 circow.com / app.circow.com)账号与数据互相独立 | ## 四种接入方式如何选 | 你想要 | 用 | 文档 | | --- | --- | --- | | 从自己的服务端 / 自动化平台(n8n、Zapier、内部服务)调用员工 | HTTP API | [api.md](https://circow.cn/docs/api.md) | | 从本机软件、快捷方式、网页链接一键拉起桌面客户端进入某个员工 | Deep Link | [deep-link.md](https://circow.cn/docs/deep-link.md) | | 让员工在用户电脑上多一项本机能力(操作文件、调本地程序、访问内网) | Skill | [skills.md](https://circow.cn/docs/skills.md) | | 用标准 MCP 协议提供一组工具给员工调用(可复用现成 MCP 生态) | MCP Server | [mcp.md](https://circow.cn/docs/mcp.md) | | 把做好的员工交付给最终用户(微信、API、桌面…) | 发布渠道 | [channels.md](https://circow.cn/docs/channels.md) | ## AI 优先的开发方式 Skill 与 MCP 的推荐创建路径不是手写,而是**直接在桌面客户端的聊天中让 AI 来做**:说「帮我创建一个 skill」或「创建一个 MCP」,内置的 `skill-manager` / `mcp-manager` 技能会完成脚手架、绑定与发布。本文档中的规范供手写与排障参考。 ## 规划中 调用日志与用量统计 · Webhook 回调 · OpenAPI 规范导出 · 网页嵌入组件(iframe / JS Widget)。 ------------------------------------------------------------------------ # HTTP API 通过 HTTP API 把一个工作流(AI 员工)集成到你的外部系统。需先在开发者中心「API 集成」栏目为该工作流创建 API Key,并在请求头携带 `Authorization: Bearer`。 - 同步调用:阻塞至执行完成,一次性返回最终结果(最长约 300 秒) - 流式调用(SSE):逐 token 实时输出,适合实时展示 - 两者都可选传 `session_id` 续接历史,实现多轮对话;执行中再发(带内容)即为「插话」 - 停止执行:随时终止正在运行的会话 - 会话列表 / 消息历史:只读查询接口,用于对账与回放 - 执行身份 = API Key 所属 owner,计费归 owner;调用方无法越权指定身份 ## 基础地址 | 区域版本 | Base URL | | --- | --- | | 国内版 | `https://app.circow.cn/flow-api/public/flow-run/{flowId}` | | 海外版 | `https://app.circow.com/flow-api/public/flow-run/{flowId}` | 下文以 `{BASE}` 代指上表地址。`{flowId}` 为目标工作流的 UUID,在开发者中心「API 集成」栏目左侧工作流列表中获取(也是浏览器地址栏 flow 页面 URL 里的那个 UUID)。`{apiKey}` 为创建 Key 时一次性显示的明文,形如 `fk_xxxxxxxx`。 | 端点 | 方法 | 用途 | | --- | --- | --- | | `{BASE}` | POST | 同步调用 | | `{BASE}/stream` | POST | 流式调用(SSE) | | `{BASE}/upload` | POST | 文件 / 图片上传 | | `{BASE}/sessions/{session_id}/stop` | POST | 停止执行 | | `{BASE}/sessions` | GET | 会话列表 | | `{BASE}/sessions/{session_id}/messages` | GET | 消息历史 | ## 鉴权 所有请求需在请求头携带 API Key。Key 与本工作流绑定,被禁用或不匹配将返回 401(服务端不区分「不存在 / 已禁用 / 不匹配」)。 ```bash Authorization: Bearer {apiKey} ``` ## 请求体 同步与流式两个端点通用同一套请求体。 ```json { "input_value": "your input text", "session_id": null, "file_paths": [] } ``` ### 字段说明 | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | input_value | string | 是 | 输入文本(用户提问 / 任务指令) | | session_id | string \| null | 否 | 多轮对话:不传每次新建会话;传上次返回的 session_id 续接历史 | | file_paths | string[] | 否 | 文件/图片 URL 列表,透传给工作流由 AI 读取;标准用法见「文件上传」 | ## 多轮对话 通过 `session_id` 续接历史,实现连续多轮对话。 - 不传 / null:每次新建独立会话,无上下文记忆 - 传新字符串(建议自生成 UUID,可**预持有**会话 ID 用于停止/插话;SSE 首帧 `event: start` 也会回传):按该 ID 新建会话 - 传上次返回的 session_id:续接历史,连续多轮对话 - 归属校验:传入已存在的会话必须属于本 Key 的 owner 且属于本工作流,否则返回 403 - 会话执行中再次调用(同步 / SSE 均可):**带内容 → 自动转为「插话」投递**(同步返回 `status=delivered`,SSE 回一帧 `event: delivered` 后结束),agent 在当前回合内消费,回复出现在**原会话**的输出流/历史中;**空内容 → 409**。一个会话同一时刻只有一条输出流,插话不会另起新流 两个端点的响应都会回传最终使用的 `session_id`,下次续接时原样回传即可。 --- ## 1. 同步调用 `POST {BASE}` 阻塞直到工作流跑完,一次性返回最后一条回复(最长约 300 秒)。 ```bash curl -X POST "{BASE}" \ -H "Authorization: Bearer {apiKey}" \ -H "Content-Type: application/json" \ -d '{"input_value": "Hello World", "session_id": null}' ``` ```python import requests resp = requests.post( "{BASE}", headers={ "Authorization": "Bearer {apiKey}", "Content-Type": "application/json", }, json={"input_value": "Hello World"}, # multi-turn: add "session_id" timeout=310, ) resp.raise_for_status() data = resp.json() print(data["session_id"], data["status"], data["result"]) ``` ### 响应 ```json { "session_id": "...", "status": "completed", "result": "...", "error": null } ``` `status` 取值:`completed`(跑完)/ `stopped`(被停止,result 为已产出部分)/ `delivered`(插话已入箱,立即返回)/ `running`(超 3600 秒软上限仍在后台执行)。 ## 2. 流式调用 (SSE) `POST {BASE}/stream` 逐 token 实时推送,不设超时(工作流内工具可能执行很久),收到 `done` 或 `error` 事件即结束。注意浏览器原生 `EventSource` 只支持 GET、不支持自定义请求头,无法用于本端点;请在服务端调用,或浏览器端用支持 POST+SSE 的库(如 `@microsoft/fetch-event-source`)。 ### 请求头 | Header | 值 | 说明 | | --- | --- | --- | | Authorization | `Bearer {apiKey}` | 必填 | | Content-Type | `application/json` | 必填 | | Accept | `text/event-stream` | 建议带上 | ### SSE 事件流 响应 `Content-Type: text/event-stream`,每个事件为 `event: <类型>` + `data: ` 两行加空行。 ``` event: start data: {"session_id": "..."} event: chunk data: {"content": "delta text", "message_id": "..."} event: done data: {"session_id": "..."} event: delivered data: {"session_id": "...", "mail_id": "..."} event: error data: {"session_id": "...", "error": "..."} ``` - `start`:首帧回传本次会话 ID——停止执行、插话、查询历史的凭据 - `chunk`:增量正文(只含正文,不含 reasoning 思考过程)。顺序拼接所有 chunk 的 `content` 即完整回答。多轮 Agent(agent→tool→agent)会产生多条 assistant 消息,`message_id` 不同;需要分段展示时按 `message_id` 分组,否则可忽略 - `done`:正常结束 / 被停止,收到即关闭连接 - `delivered`:目标会话正在执行中且本次带内容——输入已作为插话投递,本流随即结束;回复出现在原会话输出中 - `error`:执行出错,收到即流结束 ### 请求示例 ```bash curl -N -X POST "{BASE}/stream" \ -H "Authorization: Bearer {apiKey}" \ -H "Content-Type: application/json" \ -H "Accept: text/event-stream" \ -d '{"input_value": "Hello World", "session_id": null}' ``` ```python import json, requests with requests.post( "{BASE}/stream", headers={ "Authorization": "Bearer {apiKey}", "Content-Type": "application/json", "Accept": "text/event-stream", }, json={"input_value": "Hello World"}, stream=True, ) as resp: resp.raise_for_status() event = None for line in resp.iter_lines(decode_unicode=True): if line.startswith("event:"): event = line[6:].strip() elif line.startswith("data:"): data = json.loads(line[5:].strip()) if event == "chunk": print(data["content"], end="", flush=True) elif event == "done": print("\nsession_id:", data["session_id"]); break elif event == "error": print("\nerror:", data["error"]); break ``` ## 3. 文件 / 图片上传 `POST {BASE}/upload` 先把文件上传到本接口换取可公开访问的 URL,再把该 URL 放进请求体的 `file_paths` 数组,与 `input_value` 一起发送,让 AI 读取文件 / 图片。 ```bash # 1) Upload file, get public_url curl -X POST "{BASE}/upload" \ -H "Authorization: Bearer {apiKey}" \ -F "file=@/path/to/image.png" # 2) Put public_url into file_paths to ask curl -X POST "{BASE}" \ -H "Authorization: Bearer {apiKey}" \ -H "Content-Type: application/json" \ -d '{"input_value": "What is in this image?", "file_paths": ["https://.../image.png"]}' ``` ### 响应 ```json { "public_url": "https://.../xxx.png", "object_key": "...", "filename": "test.png", "content_type": "image/png", "size": 1475, "expires_at": 1781695551, "attachment_ttl_days": 30 } ``` ### 说明 - multipart 字段名为 `file`,单文件上限 40 MB,上传后的 URL 有效期 30 天(`expires_at` 为 Unix 秒) - `file_paths` 可放多个 URL,一次提问携带多个文件 - 也可直接传你自己的公网可访问 URL,不强制使用本上传接口 - 图片 / 文档由 AI 端按需拉取读取,请确保 URL 在调用期间可访问 ## 4. 会话列表 `GET {BASE}/sessions` 分页列出本工作流的全部会话(按创建时间倒序),用于外部系统对账:拿 run 返回的 session_id 查询执行状态。包含所有来源的会话(网页端、API 调用、定时任务等)。 | Query 参数 | 类型 | 默认 | 说明 | | --- | --- | --- | --- | | page | int | 1 | 页码,从 1 开始 | | page_size | int | 50 | 每页条数,上限 500 | ```bash curl "{BASE}/sessions?page=1&page_size=50" \ -H "Authorization: Bearer {apiKey}" ``` ### 响应 ```json { "total": 123, "page": 1, "page_size": 50, "sessions": [ { "id": "session-uuid", "name": "Hello World", "status": "completed", "created_at": "2026-08-19T02:00:00Z", "updated_at": "2026-08-19T02:01:00Z" } ] } ``` ## 5. 消息历史 `GET {BASE}/sessions/{session_id}/messages` 分页获取某个会话的消息记录(时间正序,不含隐藏消息)。默认每页 1000 条,`has_more=true` 时翻下一页。 | Query 参数 | 类型 | 默认 | 说明 | | --- | --- | --- | --- | | page | int | 1 | 页码,从 1 开始 | | page_size | int | 1000 | 每页条数,上限 5000 | | Path 参数 | 说明 | | --- | --- | | session_id | 会话 ID(来自 run 响应或会话列表) | ```bash curl "{BASE}/sessions/SESSION_ID/messages?page=1&page_size=1000" \ -H "Authorization: Bearer {apiKey}" ``` ### 响应 ```json { "session_id": "SESSION_ID", "total": 2, "page": 1, "page_size": 1000, "has_more": false, "messages": [ { "id": "msg-uuid-1", "role": "user", "content": "Hello World", "type": "ui_message", "created_at": "2026-08-19T02:00:00Z" }, { "id": "msg-uuid-2", "role": "assistant", "content": "Hi! How can I help?", "type": "ui_message", "created_at": "2026-08-19T02:00:05Z" } ] } ``` ## 6. 停止执行 `POST {BASE}/sessions/{session_id}/stop` 停止正在执行的会话(无请求体)。仅 running 会话执行停止(撤销执行任务 + 会话置 stopped);其他状态返回 noop、不改动终态(幂等可重试)。停止后复用同一 `session_id` 再调 run 即可续聊。 ```bash curl -X POST "{BASE}/sessions/SESSION_ID/stop" \ -H "Authorization: Bearer {apiKey}" ``` ### 响应 ```json { "session_id": "...", "status": "stopped", "session_status": "stopped", "revoked_tasks": 1 } ``` - `status=stopped`:已停止。原 SSE 流随即收到 `done`;同步调用返回 `status=stopped` 及已产出的部分结果 - `status=noop`:会话不在执行中(completed/stopped/error 等),`session_status` 为当前实际状态 - 404:session 不存在。刚发起执行后的毫秒级窗口内可能出现,短暂重试即可 - 作用域:owner 自己在网页端对同一工作流正在运行的会话,同样会被本端点停止——把 Key 交给第三方系统时请知悉 - 停止前已投递、尚未被消费的插话信件会保留,下一回合执行时一并消费 --- ## 错误码 | 状态码 | 说明 | | --- | --- | | 400 | 请求非法(如上传文件为空),或同步调用鉴权通过但执行失败(`detail` 为错误原因) | | 401 | API Key 缺失 / 无效 / 已禁用 / 与工作流不匹配 | | 403 | 无权执行此工作流,或 session_id 不归属本 Key | | 404 | 工作流不存在(消息历史 / 停止接口:session 不存在) | | 409 | 会话正在执行中且本次请求无内容(无法作为插话投递),稍后重试 | | 413 | 上传文件超过 40 MB 上限 | | 200 + event:error | 流式端点:鉴权通过但执行出错(模型不可用、运行异常等) | 错误响应体为 JSON,`detail` 字段为人类可读的错误说明。 ------------------------------------------------------------------------ # 桌面唤起(Deep Link) Deep Link 让任意本机软件(脚本、快捷方式、第三方应用、网页链接)通过自定义 URL 协议唤起 Circow 桌面客户端并执行动作,无需 SDK。 ## 1. 协议基础 URL 由 scheme(按客户端区域版本二选一)、action 与参数组成。 | scheme | 说明 | | --- | --- | | `circow-desktop-cn://` | 国内版客户端注册的协议头 | | `circow-desktop-global://` | 海外版客户端注册的协议头 | ``` {scheme}://{action}/{path}?{query} ``` - `action`:动词在前的 kebab-case,如 `run-flow` / `install-skill` - `path`:可选路径参数(如 `run-flow/{flowId}`) - `query`:普通 URL query,需 URL 编码 触发后:客户端未运行则冷启动并执行;已运行则由常驻实例接管并聚焦主窗口。调用即发即忘——链接本身不返回结果,参数错误会在客户端内以 toast 提示。 scheme 与当前区域版本不匹配、action 未注册、或签名校验失败的链接会被直接拒绝,并在客户端内 toast 提示原因。 ### 从各种环境触发 ```html 打开桌面客户端 ``` ```bat start "" "circow-desktop-cn://run-flow/{flowId}?prompt=5L2g5aW9&autosend=1" ``` ```javascript window.location.href = "circow-desktop-cn://run-flow/{flowId}?prompt=5L2g5aW9&autosend=1" ``` ```bash # macOS open "circow-desktop-cn://run-flow/{flowId}" ``` 登录开发者中心「桌面唤起」栏目有一个 run-flow URL 生成器,可自动完成 base64url 编码并一键测试唤起。 ## 2. Action 参考 当前注册的全部公开 action。示例中的 `` 为文件内容的 SHA-256 十六进制摘要。 ### run-flow(L0) 唤起客户端并进入指定工作流的聊天页,预填 prompt,可选自动发送。 | 参数 | 位置 | 必填 | 说明 | | --- | --- | --- | --- | | flowId | path | 是 | 目标工作流的 UUID(可在开发者中心「API 集成」栏目的工作流列表中获取) | | prompt | query · base64url | 否 | base64url(无填充,即 `+`→`-`、`/`→`_`、去掉尾部 `=`)编码的 UTF-8 文本,解码后不超过 8000 字符;缺省则只跳转不预填 | | autosend | query | 否 | 值为 `1` 时自动发送 prompt;其他值或缺省仅预填不发送 | ``` circow-desktop-cn://run-flow/8b1f…d3a0?prompt=5L2g5aW9&autosend=1 ``` base64url 编码示例(Python): ```python import base64 def b64url(s: str) -> str: return base64.urlsafe_b64encode(s.encode()).decode().rstrip("=") url = f"circow-desktop-cn://run-flow/{flow_id}?prompt={b64url('你好')}&autosend=1" ``` ### install-skill(L0) 下载并安装技能包(zip)。安装前客户端会弹出确认,进度在客户端内展示。 | 参数 | 位置 | 必填 | 说明 | | --- | --- | --- | --- | | url | query · URL | 是 | 技能包 zip 的下载地址 | | name | query | 否 | 技能名(展示用) | | hash | query · SHA-256 | 否 | zip 的 SHA-256,用于防篡改校验,市场分发时必带 | ``` circow-desktop-cn://install-skill?url=https://example.com/my-skill.zip&name=my-skill&hash= ``` ### install-mcp(L0) 两种模式:市场安装(传 url + hash,下载 zip 解压注册);本地安装(`mcps//` 目录已就位,仅注册启动)。传了 `url` 即走市场模式。 | 参数 | 位置 | 必填 | 说明 | | --- | --- | --- | --- | | url | query · URL | 市场模式必填 | MCP 包 zip 下载地址 | | hash | query · SHA-256 | 市场模式必填 | 包的 SHA-256(身份与去重依据) | | env_vars | query · JSON | 否 | 市场模式可选:JSON 对象,注入 MCP 进程的环境变量 | | name | query | 本地模式必填 | MCP 名(即目录名),要求 `{CIRCLE_CONFIG_DIR}/mcps//` 下已有 mcp.json 与代码 | ``` # 市场安装 circow-desktop-cn://install-mcp?url=https://example.com/my-mcp.zip&hash=&env_vars={"API_KEY":"xxx"} # 本地安装 circow-desktop-cn://install-mcp?name=my-mcp ``` ### manage-mcp(L0) 管理已安装 MCP 的生命周期。start / stop 是持久声明(写 `auto_start`,应用重启后仍生效)。 | 参数 | 位置 | 必填 | 说明 | | --- | --- | --- | --- | | op | query · start\|stop\|uninstall | 是 | start(启动)/ stop(停止)/ uninstall(停进程 + 删目录 + 删配置) | | name | query | 是 | 目标 MCP 名 | ``` circow-desktop-cn://manage-mcp?op=stop&name=my-mcp ``` ### install-template(L0) 从官方市场安装一个员工模板(即复制到自己账号)。模板是统一的 `.circle` 包,可能是单个员工、一个团队或一个合集(多个团队 + 独立员工);安装时一次性创建包内全部团队与员工。员工公开主页 `https://circow.cn/e/{template_id}` 的下载按钮在检测到已装客户端时走的就是这条链接;macOS 上该 https 链接也作为 universal link 直接映射到本 action。 | 参数 | 位置 | 必填 | 说明 | | --- | --- | --- | --- | | template_id | query | 是 | 市场员工模板的 UUID | ``` circow-desktop-cn://install-template?template_id= ``` ## 3. 安全模型 每个 action 有固定安全等级,派发前统一校验。 | 等级 | 包含 action | 说明 | | --- | --- | --- | | L0 · Public | run-flow / install-skill / install-mcp / manage-mcp / install-template | 任意软件可触发,无需签名。run-flow 的 autosend 视为用户知情授权;安装类动作有 hash 校验与客户端内确认兜底 | | L1 · BackendSigned | oauth-callback | 需要后端签名参数(`__sig` / `__exp`,HMAC-SHA256,5 分钟内有效),仅由官方服务端签发,外部开发者不可直接调用 | Public 类 action 的 URL 即使被附加 `__sig` / `__exp` 也会在校验后被剔除,无法借此提权。 ------------------------------------------------------------------------ # Skill 开发 一个 Skill 就是一个目录:`SKILL.md` 告诉 AI 何时、如何调用;`.bat` 启动器 + Python 模块实现能力。绑定到工作流后,其 `description` 会注入对话供 AI 按需调用。Skill 在用户的桌面客户端内运行,因此可以操作本机文件、调用本地程序、访问内网。 > 推荐路径:在桌面客户端聊天中对 AI 说「帮我创建一个 skill」,内置的 `skill-manager` 技能会完成脚手架、绑定与发布。以下规范供手写与排障参考。 ## 1. 目录结构 ``` my-skill/ ├── SKILL.md # frontmatter: name / description / command ├── my-skill.bat # 统一启动器(自动测速选镜像 + uv sync) ├── pyproject.toml └── my_skill/__init__.py ``` ### SKILL.md frontmatter ```markdown --- name: my-skill description: 具备 [能力1、能力2、能力3] 能力。当用户需求与 [关键词1、关键词2、英文别名…] 相关时调用此 skill。 command: my-skill --- ``` | 字段 | 必填 | 说明 | | --- | --- | --- | | name | 是 | 字母开头,允许字母 / 数字 / `-` / `_` | | description | 是 | AI 只凭 description 决定是否调用该 skill(不读正文),召回质量完全取决于它 | | command | 否 | 终端命令名,默认与 name 相同 | ## 2. description 编写规范(最重要) `description` 是**唯一**决定 AI 是否会加载该 skill 的字段。AI 在每次对话开始时只看到所有 skill 的 description,不会读 SKILL.md 正文,因此 description 写不好等于 skill 永远不会被调用。 ### 强制模板(双段式中文) ``` 具备 [能力1、能力2、能力3] 能力。当用户需求与 [关键词1、关键词2、英文别名1、英文别名2…] 相关时调用此 skill。 ``` 两段缺一不可: - **前半句「能力」**:3-5 个动词性能力词,告诉 AI 这个 skill 能做什么 - **后半句「触发关键词」**:5-10 个用户可能用到的同义词、场景词、英文别名,这是召回的核心 ### 关键词覆盖原则 写关键词时假装自己是用户,列举所有可能的表达方式: - 中文同义词:用户说「创建技能」还是「新建 skill」还是「加一个工具」?都列上 - 英文别名 / 缩写:docx、pdf、Cloudflare、MCP、scaffold —— 用户夹中英文表达时也要能命中 - 场景词:用户描述场景而非名词时(如「我想自动点击网页」对应浏览器自动化 skill),把场景动作也写进去 ### 强约束前置 如果该 skill 有「必须用我而不是 X 工具」的硬规则,直接写进 description 末尾,例如:`注意:办公文档与 PDF 必须用此 skill,禁用 read_file。` 理由:AI 召回 skill 时只看 description,硬规则前置才能阻止 AI 在不加载本 skill 的情况下错用其他工具。 ### 反面 vs 正面 ❌ 功能描述式,关键词稀疏,纯英文: ``` description: Scaffold a new Python-based skill. Generates SKILL.md and pyproject.toml. ``` ✅ 能力 + 关键词双段,中英覆盖: ``` description: 具备 Skill 脚手架、规范校验、市场发布能力。当用户需求与新建 skill、注册 skill、上架 skill、skill 市场等相关时调用此 skill。 ``` ## 3. SKILL.md 正文编写原则 SKILL.md 是 AI 执行 skill 时的唯一指令来源。核心理念:**只写 AI 不知道的**。AI 本身具备广泛的编程和工具知识,SKILL.md 不是教程,而是差异化指令。 必须写(AI 无法推断): - 命令格式和参数:精确的 CLI 接口(命令名、参数名、必选 / 可选) - 环境特殊性:依赖的环境变量、运行前提条件 - 关键约束 / 陷阱:容易出错的边界情况、必须遵守的顺序、格式限制 - 与其他 skill 的协作:何时该调用其他 skill、数据如何传递 - 特殊工作流:执行步骤非直觉时明确写出 不要写(AI 已经知道):通用编程概念、标准工具用法(git / uv / pip 常规操作)、显而易见的事情、冗长的测试步骤、过度详细的示例。 好的 SKILL.md:50-100 行以内,扫一眼就能用,不重复 frontmatter 已说过的内容。 ## 4. skill-manager 命令 在桌面客户端环境中运行(`skill-manager.bat` 是内置技能的启动器)。 ```bash skill-manager.bat create --name --description [--command ] [--sync] [--no-bind] skill-manager.bat pack [-o ] skill-manager.bat upload skill-manager.bat publish [-o ] # pack + upload skill-manager.bat list # 查询市场已有技能 skill-manager.bat bind-flow # 绑定到当前工作流(SKILL.md 变更后重跑以刷新 hash) skill-manager.bat unbind-flow ``` - `create`:生成骨架,并默认自动绑定到当前工作流(写入 flow 的 skills 白名单;不绑定则聊天中不会注入该 skill)。`--sync` 创建后立即测速选源并 `uv sync`;`--no-bind` 跳过绑定 - `bind-flow` / `unbind-flow`:绑定条目格式 `{name, hash}`,hash 为 SKILL.md 的 SHA-256;SKILL.md 变更后需重跑 bind-flow 刷新(幂等) - `pack`:打包为 zip(自动排除 `.venv` / `__pycache__` / `.git`),zip 内以 skill name 为一级根目录 - `upload`:上传 zip 到市场 `POST {MARKET_API_BASE}/skills/upload`(multipart `file` 字段) - `publish` / `upload` 必须先获得用户明确确认,AI 不得自动发布 ### 典型流程 create(默认自动绑定当前工作流)→ 编辑 `/__init__.py` 实现 → 打磨 SKILL.md → 重跑 `bind-flow` 刷新 hash → 测试通过后 `publish` 上架市场。 ### 生成的 .bat 与「测速选源」 `create` 生成的 `.bat` 调用 `_shared/uv-bootstrap.bat` 统一启动器。用户首次运行时并发探测 5 个 PyPI 镜像(pypi / 清华 / 阿里 / 腾讯 / 中科大),≤3 秒选最快,注入 `UV_DEFAULT_INDEX` 后 `uv sync`,结果缓存 7 天;`.venv` 健康时完全跳过。 .bat 里有一个测速代表包名,默认 `pip`。若 skill 有 ≥20MB 的大二进制依赖(pymupdf / torch / pillow / opencv-python…),把它改成该大包名,测速更可靠。不要把 .bat 改回裸 `uv run`——国内用户首装大依赖会卡死数十分钟。 ## 5. 注入的环境变量 客户端运行 Skill / MCP 工具时自动注入以下变量,代码中直接读取,勿硬编码地址或凭证。 | 变量 | 说明 | | --- | --- | | MARKET_API_BASE | 技能 / MCP 市场 API 地址 | | CIRCLE_AUTH_TOKEN | 认证 token,作为 `Authorization: Bearer` 附加 | | FLOW_API_URL | flow_app 后端 API 地址 | | CIRCLE_FLOW_ID / CIRCLE_USER_ID | 当前工作流 / 用户标识,绑定操作依赖它们 | | CIRCLE_CONFIG_DIR | 客户端配置根目录(`mcps/` 等子目录所在),也用于派生 deep link scheme(目录名含 cn → `circow-desktop-cn`,含 global → `circow-desktop-global`) | ## 6. 分发 两条分发通道,二选一或并用: 1. 市场分发:`skill-manager.bat publish` 上架官方市场,用户在客户端内一键安装 2. 链接分发:把 `install-skill` deep link(务必带 SHA-256 hash)放到你的官网或安装器里,用户点击即装。见 [deep-link.md](https://circow.cn/docs/deep-link.md) ------------------------------------------------------------------------ # MCP Server 开发 按 Model Context Protocol 开发工具服务,由 Circow 桌面客户端拉起并托管;绑定到工作流后即可在对话中被 AI 调用。可以直接复用现成的 MCP 生态(npx / python 等任意可执行)。 > 推荐路径:在桌面客户端聊天中对 AI 说「创建一个 MCP」,内置的 `mcp-manager` 技能会完成模板复制、安装、绑定与发布。以下规范供手写与排障参考。 ## 1. 创建 复制 `mcp-manager` 技能自带的 `template/` 目录后只改两个文件:`mcp.json`(元信息与启动方式)和 `server.py`(工具定义与实现)。如需额外 Python 依赖,在 `pyproject.toml` 的 dependencies 中添加。 ### mcp.json ```json { "name": "my-mcp", "display_name": "My MCP", "description": "做什么", "version": "0.1.0", "launch": { "command": "uv", "args": ["run", "--directory", "${MCP_DIR}", "server.py"], "env": {} }, "env_schema": { "API_KEY": "第三方服务的 API Key" } } ``` | 字段 | 必填 | 说明 | | --- | --- | --- | | name | 是 | 唯一标识,仅小写字母 / 数字 / 连字符,与安装目录名一致 | | display_name / description / version | 是 | 展示名 / 描述 / 版本 | | launch.command + launch.args | 是 | 启动命令,支持任意可执行(python / uv / npx / node / exe)。`${MCP_DIR}` 占位符会替换为该 MCP 实际目录,进程 cwd 恒为该目录 | | launch.env | 否 | 内置默认环境变量 | | env_schema | 否 | 声明需用户填写的环境变量(key → 说明),安装时提示用户输入 | npx 类示例:`"command": "npx", "args": ["-y", "@scope/pkg"]`(国内网络需先预热,见下)。 ### server.py 三个要点 - `@server.list_tools()` 中定义工具的 `name` / `description` / `inputSchema` - `@server.call_tool()` 中按工具名分发实现 - 每个工具返回 `[TextContent(type="text", text="结果")]` ## 2. 安装(mcp_tool.py) CLI 入口统一为 `python {skill_dir}/scripts/mcp_tool.py <子命令>`(`{skill_dir}` 为 mcp-manager 技能目录)。路径 / 鉴权全部依赖客户端注入的环境变量(`CIRCLE_CONFIG_DIR` / `CIRCLE_FLOW_ID` / `CIRCLE_USER_ID` / `CIRCLE_AUTH_TOKEN` / `FLOW_API_URL`),勿硬编码。 ```bash # 本地安装(项目目录已写入 {CIRCLE_CONFIG_DIR}/mcps//,name 与目录名一致) python {skill_dir}/scripts/mcp_tool.py install --bind # 市场安装(zip 由客户端自动下载解压,无需先落盘) python {skill_dir}/scripts/mcp_tool.py install --bind --url --hash # 列出已装 MCP(JSON:name / version / phase / ok / tools) python {skill_dir}/scripts/mcp_tool.py list # 校验 + 打包 + 上传市场 python {skill_dir}/scripts/mcp_tool.py publish ``` `install` 一条命令内部自动完成:触发 `install-mcp` deep link(scheme 自动从 `CIRCLE_CONFIG_DIR` 派生)→ 轮询 `status.json` 验收 → `--bind` 时绑定到当前工作流。任一步失败会打印可执行的排障建议并以非零退出码结束。`--bind` 强烈建议带上,否则聊天中无法使用该 MCP 的工具。可选 `--timeout <秒>`(默认 120)。 ### npx 预热(规则,非技巧) `launch.command=npx` 的 MCP 在国内网络首次启动需在线下载包,几乎必然 >60s 握手超时。安装前必须先全局预装: ```bash npm i -g <包名> --registry=https://registry.npmmirror.com ``` 然后把 `mcp.json` 的 `launch.command` 改为该全局命令(或其绝对路径),`launch.args` 去掉 `-y <包名>`,再执行 install。直接用 `npx -y` 在线拉包是已知的失败路径。 ## 3. 启动 / 停止 / 卸载 通过 `manage-mcp` deep link 触发(见 [deep-link.md](https://circow.cn/docs/deep-link.md)),再用 `verify` 轮询验收: ```bash start "" "{scheme}://manage-mcp?op=stop&name=" python {skill_dir}/scripts/mcp_tool.py verify --since <触发前毫秒时间戳> --expect stopped start "" "{scheme}://manage-mcp?op=start&name=" python {skill_dir}/scripts/mcp_tool.py verify --since ``` - start / stop 是持久声明:stop 会将该 MCP 的 `auto_start` 置 false(应用重启不复活),start 置回 true - 卸载:先 `unbind-flow ` 解绑 → `manage-mcp?op=uninstall&name=` → 轮询 `{CIRCLE_CONFIG_DIR}/mcps//` 目录消失 → 再跑一次 `unbind-flow ` 兜底(幂等),防止工作流残留孤儿工具条目 - deep link 命令立即返回,结果一律靠 verify 轮询 status.json / 目录存在性验收,`--since` 用触发前的毫秒时间戳区分本次结果 ## 4. 分发 两条分发通道,二选一或并用: 1. 市场分发:`mcp_tool.py publish` 上架官方市场(自动校验含 launch、打包整目录、上传),用户在客户端内一键安装 2. 链接分发:把 `install-mcp` deep link(务必带 SHA-256 hash,可附 `env_vars`)放到你的官网或安装器里,用户点击即装 ------------------------------------------------------------------------ # 发布渠道 员工(工作流)做好后,通过以下渠道交付给最终用户。 | 渠道 | 状态 | 说明 | 怎么用 | | --- | --- | --- | --- | | 微信客服 | 可用 | 为当前工作流生成企业微信客服二维码,用户扫码即可在微信里与它对话(继承会话记忆) | 在桌面客户端聊天中对 AI 说「把这个员工接入微信」,内置 `im-bridge` 技能会生成二维码 | | HTTP API | 可用 | 以接口形式嵌入你自己的产品或自动化系统(n8n、Zapier、内部服务) | [api.md](https://circow.cn/docs/api.md) | | 桌面唤起(Deep Link) | 可用 | 从你的本机软件、快捷方式或文档链接一键拉起客户端进入指定工作流 | [deep-link.md](https://circow.cn/docs/deep-link.md) | | 员工公开主页 | 可用 | 发布到市场的员工模板拥有公开主页 `https://circow.cn/e/{template_id}`,访客可一键下载客户端并安装该员工 | 在市场发布员工模板 | | 网页嵌入组件 | 规划中 | 以 iframe / JS Widget 形式把对话窗嵌入任意网站 | — | | Webhook 回调 | 规划中 | 工作流运行结束后主动回调你的服务端地址,免轮询 | — |