ruflo OpenAPI 文档工程实战:从 Agent 写作规范到 Cognitum v1 契约落地
ruflo 仓库内嵌了一套「OpenAPI 文档专家」Agent 定义(.claude/agents/documentation/api-docs/docs-api-openapi.md),用规范化的方式指导如何编写 OpenAPI 3.0/3.1 契约文档。本文以该文档为骨架,结合仓库中真实存在的 Cognitum v1 OpenAPI 规范(openapi: 3.1.0)与其背后的 ADR-308 公共 API 契约决策,系统讲解 OpenAPI 文档的结构、最佳实践、契约式治理流程以及「文档与现实漂移」这一真实工程陷阱,帮助你在 ruflo 生态内外写出可被 CI、Agent、LLM 直接消费的高质量 API 文档。
一、这是什么样的文档?一套面向「API 文档写作」的 Agent 人格
仓库中该文件本质是一个 Claude Code Agent 定义:其 frontmatter 声明了 name: api-docs 与 description: Expert agent for creating and maintaining OpenAPI/Swagger documentation,正文则是一份完整的角色设定(system prompt)。也就是说,ruflo 并不是把 OpenAPI 写作当作一次性人工任务,而是把它封装成一个可复用的专门 Agent,在与网络打交道的边界上(auth、事件、代理、额度等)持续产出、校验并维护契约文档。
该 Agent 的能力定位(Key responsibilities)可归纳为五个方面:
- 编写符合 OpenAPI 3.0 的规范(specification)文件;
- 为所有端点撰写 description 与示例;
- 精确建模请求/响应 schema;
- 完整纳入认证与安全方案(security schemes);
- 为所有操作提供清晰可复用的例子。
这套职责在 ruflo 仓库中的真实载体,就是 Cognitum v1 规范:它把 ruflo CLI 与 api.cognitum.one 服务之间的 8 个端点(auth 设备流、令牌交换/吊销、事件上报、事件删除、funnel 策略、代理聊天补全、额度查询)全部写成结构化 YAML。因此,理解「怎么写 OpenAPI 文档」的最佳方式,就是对照这份真实 spec 逐项验证 Agent 的每一条要求。
二、OpenAPI 规范的标准骨架(原文 YAML 全解析)
原文档给出了一份可作为起点的 OpenAPI 3.0 YAML 模板,这是任何 OpenAPI 文档写作的「最小骨架」,此处逐段还原并注明其用途:
openapi: 3.0.0 # 版本声明:3.0.x 或 3.1.x 均须显式写出
info:
title: API Title # 必填:API 名称
version: 1.0.0 # 必填:契约版本,配合语义化版本管理
description: API Description
servers:
- url: https://api.example.com # 服务器地址;多环境可列出多条
paths:
/endpoint:
get:
summary: Brief description # 短摘要:出现在索引/目录中
description: Detailed description
parameters: [] # 查询/路径/头参数逐一在此声明
responses:
'200':
description: Success response
content:
application/json:
schema:
type: object
example: # 为文档读者提供可直接粘贴的样例
key: value
components:
schemas:
Model: # 可复用模型(配合 $ref 引用)
type: object
properties:
id:
type: string
对照仓库真实 spec,上述骨架在 cognitum-v1.openapi.yaml 中每一块都有更严谨的升级用法:
- 版本更高但同样显式声明:该文件首行即为
openapi: 3.1.0,紧随其后是一段规范性注释——本 spec 同时 check-in 于 ruflo 与 Cognitum server 两个仓库,双端 CI 都会对照它校验,发生漂移即构建失败。这直接体现「文档是评审产物与单点契约」的价值。 - servers + security 全局声明:
servers: [{url: https://api.cognitum.one}],且顶层security: [{bearerAuth: []}],而无需鉴权的端点(如/v1/auth/device、/v1/funnel-policy)通过端点级security: []显式放行。这种「全局默认鉴权 + 局部显式豁免」是最不容易漏配安全要求的写法。 - components 的三种复用:
schemas(如ApiErrorBody、PolicyVersions、RequestReceipt、FunnelEvent)、responses(ApiError、RateLimited)、securitySchemes(bearerAuth)。所有端点统一通过$ref: '#/components/responses/...'引用错误响应,避免同一个 429/401 形态在多处重复定义、日后改漏。
三、五大写作职责如何落到真实端点:以 Cognitum v1 为镜
原文档要求「为所有端点撰写描述与示例」「精确建模 schema」「包含认证与安全方案」。以下逐条给出仓库中的实证写法,作为可对照的标杆。
3.1 精确建模请求/响应 schema
以 POST /v1/auth/device(启动 RFC 8628 设备授权流)为例,spec 用 required 数组约束请求与响应的最小契约:
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [client_id, scope]
properties:
client_id: { type: string }
scope:
type: string
description: >
Space-separated scopes ... (account.create, proxy.use,
cloud.route, telemetry.write, hosted.memory.use)
响应侧则声明必填字段 [device_code, user_code, verification_uri, expires_in, interval],并给出 verification_uri 的 format: uri。description 里还交代了 scope 与 ADR-302 同意域一一映射的业务语义——这符合原文档「用描述性 summary 与 description」的要求。
令牌端点 POST /v1/auth/token 更进一步演示了 enum 约束与数值边界约束:
grant_type:
type: string
enum: [urn:ietf:params:oauth:grant-type:device_code, authorization_code, refresh_token]
code_verifier: { type: string, description: PKCE verifier }
# 响应中 access token 生命周期被约束为 10–15 分钟:
expires_in: { type: integer, minimum: 600, maximum: 900 }
这类 minimum/maximum/enum/pattern 约束正是「文档与实现强契约」的体现:阅读者无须翻源码即可得知令牌有效期区间与合法授权类型。
3.2 完整记录所有错误响应与速率限制
原文档明确要求「document all possible error responses」「Include rate limiting information」。仓库 spec 通过 components.responses 集中定义了统一的错误响应形态 ApiError(指向 ApiErrorBody)与 RateLimited,后者带三个响应头:
RateLimited:
description: Rate limited — limits documented per endpoint and echoed in headers
headers:
Retry-After: { schema: { type: integer } }
X-RateLimit-Limit: { schema: { type: integer } }
X-RateLimit-Remaining: { schema: { type: integer } }
值得注意的错误建模细节(对写作极具参考价值)是 ADR-303 的错误分类法如何在 spec 中落地:
- 所有错误使用机器可读 code,客户端只按 code 分类、永不解析 message 文案;
ApiErrorBody中 code 的 enum 即为规范全集:cognitum_credit_exhausted、insufficient_quota、rate_limit_exceeded、authentication_error、permission_error、service_unavailable、invalid_request; message仅供人类阅读,另附retryable: { type: boolean }供客户端决定是否重试;- 唯一产生
402的端点被显式注释为「the ONLY source of COGNITUM_CREDIT_EXHAUSTED」,避免多端点语义冲突。
3.3 认证与安全方案的声明
原文档要求「include authentication and security schemes」。仓库 spec 的写法是:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
配合前文提到的顶层 security 与端点级 security: [] 豁免。与之对应的真实 OAuth 客户端实现位于 v3/@claude-flow/security/src/oauth/client.ts,其文件头注释即说明 URL 构造与 POST /oauth/token、authorization_code / refresh_token 授权的对应关系,并明确引用这份 check-in 的 OpenAPI spec 作为契约来源——文档声明与安全代码由此形成闭环。
3.4 幂等键与可重试语义写入契约
仓库 spec 在 POST /v1/events 上要求客户端生成的 Idempotency-Key(format: uuid,每个批次一个,重试不会重复计数),在 POST /v1/events/{subject_id} 的 DELETE 上同时声明 200(已完成,返回 receipt_id + deleted)与 202(服务降级时先收据、服务端重试直至确认)。这类面向故障的契约文档比简单列出「成功/失败」两种响应更能指导真实客户端实现。
四、文档工程的更高形态:把 OpenAPI spec 变成组织级契约(ADR-308)
单一文档如何升级为「跨组织边界的强制契约」?ruflo 的答案是 ADR-308-cognitum-public-api-contract.md。它对「OpenAPI 文档化」提出了六条工程化要求,每一条都可直接复用到其他 API 项目:
- 双仓库 check-in + CI 校验:规范同时存在于 ruflo 与 server 仓库,双方 CI 都对照同一 spec 校验,漂移即构建失败。文档因此成为评审任何服务端改动的首要 artifact。
- 语义化版本:
/v1稳定;破坏性变更必须升/v2并提供重叠窗口;CLI 显式声明自己支持的 API 版本。 - 幂等键强制:
POST /v1/events必须携带客户端生成 UUID,杜绝重试导致的事件/转化重复计数。 - 显式限流 + 退避:限流说明写在 spec、通过响应头回传,客户端背压(back off)且绝不向限流重试。
- 错误分类法:错误 code 与 ADR-303 的
CreditErrorCode/分类表一一对应,客户端一律按 code 分类。 - 数据保留与策略版本收据:契约中直接写明保留策略(原始事件 ≤ 90 天,此后仅聚合数据)、terms/privacy 版本回传与再同意规则。
此外,ADR-308 还定义了客户端侧的规范性故障策略表,这属于 spec 之外但对文档化 API 至关重要的补充约定:
| 不可用组件 | 客户端行为 |
|---|---|
| 认证(Auth) | 本地 ruflo 继续完整工作;受限能力以明确错误降级 |
遥测(/v1/events) |
丢弃或使用有界本地队列(≤ 24h、≤ 1MB);绝不阻塞或拖慢 CLI |
| Funnel 策略 | 沿用最近一次有效签名策略,否则用包内默认;绝不 fail-open 展示促销 |
| 代理后端 | 向调用方返回错误;绝不静默改路由到其他付费/云厂商 |
| 删除 | 向用户返回持久请求收据,服务端重试直至确认 |
与之配套的还有同类 ADR 相互引用:错误分类见 ADR-303、funnel 与删除/保留见 ADR-305 与 ADR-309、认证流程见 ADR-306、代理运行时分发见 ADR-304 与 ADR-307。这些 ADR 与 OpenAPI spec 相互印证——一份好的 API 文档从来不是孤立的 YAML,而是与架构决策记录共同演进的。
五、深入 spec 内部:funnel 事件与代理路由 schema 的边界约束艺术
规范写作的价值在封闭枚举与严格 schema 上体现得最充分,仓库 spec 的 components.schemas.FunnelEvent 是绝佳范例:
FunnelEvent:
type: object
description: Closed ADR-309 schema — extending the event enum requires an ADR amendment.
required: [schemaVersion, event, surface, release, timestampBucket]
additionalProperties: false # 拒绝未知字段
properties:
schemaVersion: { type: integer, const: 1 } # const 锁定版本
event:
type: string
enum: [disclosure_shown, funnel_disabled, signup_opened, account_created, proxy_activated]
surface:
type: string
enum: [statusline, init, credit_exhaustion]
release: { type: string }
region: { type: string, description: Coarse, self-declared only }
pseudonymousId: { type: string, format: uuid }
timestampBucket:
type: string
pattern: '^\d{4}-\d{2}-\d{2}(T\d{2})?$' # 仅允许日/小时桶
description: Daily (default) or hourly bucket — full timestamps are rejected.
这条 schema 传达了多个文档写作要点:const: 1 锁定 schema 版本;additionalProperties: false 让解析器拒绝一切未知字段;用 enum 表达「扩展事件枚举需要走 ADR 修订」的治理约束;用 pattern 从格式层禁止完整时间戳的写入(隐私设计落到 schema 而非口头约定)。
代理路由端点 POST /v1/proxy/chat/completions 则演示了「开放 + 受控」的混合建模:请求侧要求 [model, messages],其中 model 是「具体模型或路由别名 cognitum-auto|low|mid|high」,同时放开 additionalProperties: true 以保持 OpenAI 兼容的透传能力;响应侧除透传内容外,强制内联 RequestReceipt:
RequestReceipt:
type: object
required: [cost_usd, tier, model, data_plane]
properties:
cost_usd: { type: number }
tier: { type: string }
model: { type: string }
data_plane:
type: string
description: '"local" or "cloud:<provider>" — visible per request (ADR-304)'
即每次补全都在带内(in-band)返回计量成本、解析后的 tier/model 与数据面,把「谁在处理、花了多少钱」写进契约,而不是依赖客户端事后猜测。
六、诚实记录漂移:一份 OpenAPI 文档的自我约束与局限
对文档作者最有借鉴意义的一点,也许藏在 ADR-308 的 Addendum(2026-07-16)里:实现 ADR-306 时对照线上 OAuth 客户端(cognitum-one/meta-proxy 的 oauth/client.rs,已跑通生产集成测试)发现,实际身份服务走的是 auth.cognitum.one/oauth/{authorize,token} 与 auth.cognitum.one/v1/oauth/code-exchange——与 spec 中 api.cognitum.one/v1/auth/{device,token,revoke} 的 host 和路径方案都不一致。
该 ADR 的处理方式极具示范意义:它没有静默放任,而是明确标注——本仓库 check-in 的 spec 对 auth 端点而言是「aspirational(理想的)」而非「authoritative(权威的)」,并解释 ruflo auth 之所以按已被验证的 auth.cognitum.one 面实现,正是为了避免为「没人确认存在的端点」写客户端。仓库 v3/@claude-flow/security/src/oauth/client.ts 的实际实现同样走 /oauth/token 与 /v1/oauth/code-exchange,与这份标注相互佐证。
这提醒每一位 OpenAPI 文档写作者:文档与实现之间的漂移是常态而非异常。规范的写作纪律至少包括——把契约 check-in 到源码库并接入 CI 比对;遇到漂移时在文档/ADR 中显式标记「哪个部分是权威的、哪个部分是理想的」;端到端接入已跑通生产流量的客户端实现后再将文档视为事实来源。
七、如何在 ruflo 中复用以该 Agent 为首的文档工作流
若要在 ruflo 仓库内(或借鉴其模式在其他项目)开展 OpenAPI 文档工作,入口与资产如下:
- 阅读并复用 Agent 定义:
.claude/agents/documentation/api-docs/docs-api-openapi.md的 frontmatter 已声明其适用描述;后续 Agent 任务可基于该人格调用,产出结构与最佳实践一致的 OpenAPI 文件。 - 参考真实标杆:
v3/docs/api/cognitum-v1.openapi.yaml是仓库内已落地、且被 CI 与客户端代码共同引用的 3.1 spec(共 8 个端点、343 行),适合作为「精确 schema、统一错误响应、$ref 复用、安全方案声明」的对照蓝本。 - 理解契约治理前提:读 ADR-308 了解双仓库 check-in、CI 漂移失败、
/v2语义化版本与规范性故障策略,再结合 ADR-303 的错误 code 全集理解错误建模。 - 以源码反哺文档准确性:auth 相关契约以 v3/@claude-flow/security/src/oauth/client.ts 的真实端点为准,谨记 Addendum 的漂移警告——写作前先确认文档描述的端点是否真实存在。
结语
从 .claude 目录里一份 63 行的 Agent 角色设定出发,ruflo 把「写 OpenAPI 文档」这件事做成了覆盖规范结构、错误建模、安全声明、幂等设计、契约治理与漂移审计的完整工程链路。这份 Agent 文档 提供了方法论骨架,Cognitum v1 spec 与 ADR-308 则证明了其落地形态:一份可被 CI 校验、可被客户端代码引用、可被后续 Agent 检索续写的 OpenAPI 文档,远比一次性的手工写作更有价值。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00