QMD 仓库 API 设计原则解析:从 REST 七条准则到检索评测的实战验证
【免费下载链接】qmdmini cli search engine for your docs, knowledge bases, meeting notes, whatever. Tracking current sota approaches while being all local项目地址: https://gitcode.com/GitHub_Trending/qmd1/qmd
本指南以 test/eval-docs/api-design-principles.md 中沉淀的 REST API 设计原则为核心骨架,系统梳理名词化 URL、复数资源、层级关系、过滤分页、版本化、错误处理与限流等七条准则,并对照本仓库(qmd,一个全本地的迷你 CLI 搜索引擎)的源码与评测体系,说明这些文档在检索评测中的实际用途、如何把它们接入本地知识库,以及如何借助 BM25 与语义检索验证 Agent 能否基于它们回答真实的 API 设计问题。读完本文,你将既掌握一套可直接落地的 REST API 设计规范,也理解"规范文档如何成为可评测的语料"这一完整闭环。
一、文档定位:这份 API 设计原则在仓库中的角色
在 qmd 仓库中,test/eval-docs/api-design-principles.md 并非普通的代码注释,而是一份被专门用于检索评测的"黄金语料"。它位于test/eval-docs/目录,与 distributed-systems-overview.md(分布式系统)、machine-learning-primer.md(机器学习)、remote-work-policy.md(远程办公政策)、startup-fundraising-memo.md(融资备忘录)等文档共同构成评测用文档集。
从仓库结构看,test/eval-docs目录在多个评测链路中被引用:
- test/eval.test.ts 中通过
evalDocsDir定位该目录,将其中每份文档插入评测集合(对应代码位置 test/eval.test.ts); - test/eval-bm25.test.ts 同样以
eval-docs为插入目标(test/eval-bm25.test.ts); - test/bench-guard.test.ts 使用
eval-docs作为基准集合就绪性断言的对象(如 test/bench-guard.test.ts); - test/eval-deep-research.ts 中的查询集直接引用
api-design文档作为期望命中结果(见下节)。
也就是说,这份 API 设计原则文档在本仓库中扮演"知识基准"角色:搜索引擎的检索质量、重排效果,都以"能否命中这份文档"为衡量标准。这也是为什么理解它本身的内容,与理解仓库评测机制同等重要。
二、核心原则逐条拆解:七条可落地的 REST 设计准则
原文档正文完整地给出了七条设计原则,以下是每条原则的完整展开与工程化注释。
原则一:用名词,不用动词(Use Nouns, Not Verbs)
URL 应当表示资源而非动作,动作交给 HTTP 方法来表达。这是 REST 风格与 RPC 风格最直观的分界线。
推荐写法:
GET /users/123 → 读取 123 号用户资源 POST /orders → 在 orders 集合中创建新订单 DELETE /products/456 → 删除 456 号产品资源应避免的写法:
GET /getUser?id=123 POST /createOrder GET /deleteProduct/456工程化要点:当 URL 中出现get、create、delete等动词时,通常意味着动作语义被塞进了路径,而 HTTP 方法(GET/POST/PUT/DELETE/PATCH)本就承担了动作表达。保持名词化还有助于路由配置、权限控制(基于资源粒度)与缓存层设计保持一致。
原则二:始终使用复数名词(Use Plural Nouns)
为了一致性,资源集合应统一用复数形式:
/users (而不是 /user) /orders (而不是 /order) /products (而不是 /product)工程化要点:复数约定消除了"单数到底指集合还是指单个资源"的歧义,配合原则三的层级嵌套,GET /users/123/orders与GET /users/123/orders/456能天然读作"用户 123 的订单集合"与"用户 123 的某笔订单"。复数集合 + 数字 ID 的路径模式也是 OpenAPI/Swagger 生态最常见的约定。
原则三:用 URL 层级表达资源关系(Hierarchical Relationships)
通过 URL 层级表达"从属/嵌套"关系:
GET /users/123/orders → 获取用户 123 的全部订单 GET /users/123/orders/456 → 获取用户 123 的订单 456工程化要点:层级结构适用于"一对多"强从属关系;当关系变成"多对多"或资源间无强父子约束时,文档(原则四)给出更合适的做法——用查询参数过滤而非无限加深路径。从源码结构看,qmd 自身的 MCP 服务器同样使用层级化资源寻址:文档通过qmd://URI 暴露(见 src/mcp/server.ts),与"资源化寻址"的思路一脉相承。
原则四:过滤与分页(Filtering and Pagination)
过滤、排序、分页统一交给查询参数:
GET /products?category=electronics&sort=price&page=2&limit=20参数语义参考:
| 参数 | 作用 | 常见取值 |
|---|---|---|
category | 按字段过滤 | 业务枚举值 |
sort | 指定排序字段 | price、-price(降序) |
page | 页码(从 1 起) | 1、2… |
limit | 每页条数 | 常用10/20/50,需设上限 |
工程化要点:分页参数务必设置上限并文档化;排序字段应白名单化,防止任意字段注入导致性能问题或信息泄露。page+limit之外,游标分页(cursor-based)在大数据集下更稳定,但本原则文档以page+limit为基线,两种方案可依业务取舍。
原则五:版本化(Versioning)
API 应当始终携带版本号,本原则文档明确偏好 URL 版本化:
/v1/users /v2/users工程化要点:URL 版本化(/v1、/v2)与 Header 版本化(Accept: application/vnd.example.v1+json)各有取舍,本规范选择前者,理由是它直观、可缓存、便于在网关层按版本分流。实践中建议:破坏性变更升大版本、向后兼容变更留在当前版本内,并配合迁移窗口。
原则六:错误处理(Error Handling)
返回一致的错误响应结构,并配以恰当的 HTTP 状态码:
{ "error": { "code": "VALIDATION_ERROR", "message": "Email format is invalid", "field": "email" } }错误对象字段语义:
| 字段 | 含义 | 示例 |
|---|---|---|
code | 机器可读的错误码,便于客户端分支处理 | VALIDATION_ERROR、NOT_FOUND、RATE_LIMITED |
message | 面向开发者的可读描述 | Email format is invalid |
field | 出错字段(校验类错误的定位信息) | email |
工程化要点:code与 HTTP 状态码配合使用——状态码表达大类(4xx 客户端错误/5xx 服务端错误),code表达精确子类;field字段让前端能直接把错误定位到表单控件。错误响应体结构一旦发布即成为对外契约,务必与版本化策略绑定。
原则七:限流(Rate Limiting)
实现限流,并通过响应头告知客户端额度与重置时间:
X-RateLimit-Limit: 1000 # 窗口内允许的总请求数 X-RateLimit-Remaining: 999 # 窗口内剩余请求数 X-RateLimit-Reset: 1640000000 # 额度重置的 Unix 时间戳(秒)工程化要点:这三个响应头(Limit/Remaining/Reset)已成为事实上的行业惯例,客户端可以据此做本地退避,而不是盲目重试;配合429 Too Many Requests状态码与Retry-After头,可构成完整的限流反馈闭环。文档末尾的结论强调:最好的 API 是开发者无需阅读文档就能上手的 API——一致性、直觉化正是七条原则的共同目标。
三、这些原则在本仓库中的实际价值:作为检索评测的"语义靶场"
上文反复强调这份文档在test/eval-docs/中的语料身份,这里给出完整的实证链路。
3.1 先决条件:把 eval-docs 接入本地知识库
要让评测运行,需先把test/eval-docs注册为 qmd 集合(文档只读,此处仅说明操作方式):
qmd collection add test/eval-docs --name eval-docs qmd embed这两步的提示直接出现在 test/eval-deep-research.ts 与 test/eval-harness.ts 中:评测脚本会先检查eval-docs集合是否存在,不存在则输出上述命令并退出。
3.2 评测查询集:针对 api-design 的"难题"
test/eval-deep-research.jsonl 中与本文档直接相关的查询有(含行号):
| 行号 | 查询 | 期望命中 | 难度 | 说明 |
|---|---|---|---|---|
| L7 | how to structure URLs for our service | api-design | hard | REST 端点,无精确关键词命中 |
| L18 | why URLs should be things not actions | api-design | hard | 名词而非动词的概念反转 |
| L24 | how to get user 123's purchases | api-design | hard | 层级 URL 的示例式提问 |
注意这些查询的刻意设计:与目标文档没有任何精确关键词重合(notes字段明确标注 "no exact match")。例如why URLs should be things not actions与文档中的 "Use Nouns, Not Verbs" 需要语义等价理解才能建立关联——这正是 qmd 查询扩展与重排能力要解决的问题。
3.3 评测机制:BM25 基线 vs 深度研究链路
test/eval-deep-research.ts 实现了双方法对比评测:
- BM25 基线:通过
bun src/qmd.ts search "${query}" -c eval-docs --json -n 5调用纯关键词检索(test/eval-deep-research.ts); - 深度研究链路:通过
bun src/qmd.ts query "${query}" -c eval-docs --json -n 5触发"查询扩展 → 重排"的完整语义链路(test/eval-deep-research.ts)。
评测统计 Hit@1 / Hit@3 / Hit@5 三项指标,即期望文档出现在前 1/3/5 条结果中的比例(test/eval-deep-research.ts),并以findRank定位期望文档的命中排名(test/eval-deep-research.ts)。运行方式:
bun test/eval-deep-research.ts而 test/eval-bm25.test.ts 则从另一角度验证:即使没有语义扩展,BM25 对eval-docs集合也能完成索引与检索(其插入逻辑位于 test/eval-bm25.test.ts),为对比提供基线参照。
3.4 通用检索入口:在命令行里"问"这份文档
不依赖评测脚本,也可以直接用 qmd CLI 检索这份原则文档:
# 建立集合(首次) qmd collection add test/eval-docs --name eval-docs qmd embed # 关键词检索(BM25) bun src/qmd.ts search "how to get user 123's purchases" -c eval-docs --json -n 5 # 语义检索(查询扩展 + 重排) bun src/qmd.ts query "why URLs should be things not actions" -c eval-docs --json -n 5-c eval-docs指定集合,--json输出结构化结果(含file、score、title),-n 5限制返回条数。这套 CLI 参数在评测脚本中与上述两条命令完全一致。
四、延伸:REST 原则与 qmd 架构的对应观察
从源码结构看,qmd 自身的对外接口设计也体现了资源化、一致性的思路,可作为七条原则的仓库内印证:
- 资源寻址:MCP 服务器将文档以
qmd://URI 资源形式暴露,并实现qmd://资源的模板化访问(见 src/mcp/server.ts),对应"资源而非动作"的资源化设计; - 结构化响应:搜索结果以统一结构返回
docid、file、title、score、context、line、snippet等字段(src/mcp/server.ts),类似错误处理原则中"一致响应结构"的实践; - 限制与防御:仓库包含 src/mcp/origin-guard.ts(来源校验),是服务端防御性设计的一环,与"限流/错误处理"所强调的服务端自我保护精神一致。
需要说明的是,以上是基于仓库现有结构的对应性观察,并非文档声称 qmd 实现了某条 REST 原则——文档本身只是作为评测语料存在。
五、结语:规范文档如何成为可评测资产
回到这份 api-design-principles.md:它同时具备双重身份——对开发者是一份可直接落地的 REST 设计清单(名词化 URL、复数资源、层级关系、查询参数过滤分页、URL 版本化、结构化错误、限流头),对 qmd 仓库则是一份"语义难度拉满"的评测语料(三条例证查询均无关键词重合,强制依赖语义理解)。
七条原则最终指向同一目标——让 API 直觉化、一致化,"最好的 API 是开发者无需读文档就能上手的 API"。而在本仓库中,检验"Agent 是否真的理解这份文档"的方式同样朴素而严格:构造无关键词重合的问题,看检索链路能否把它找回来。这份文档因此成为"规范 → 语料 → 评测 → 反哺"闭环中的一环,也是理解 qmd 检索与重排能力的绝佳起点。
如需深入:评测脚本见 test/eval-deep-research.ts 与 test/eval-bm25.test.ts,查询集见 test/eval-deep-research.jsonl,集合注册与状态检查见 test/eval-harness.ts 与 test/bench-guard.test.ts。
【免费下载链接】qmdmini cli search engine for your docs, knowledge bases, meeting notes, whatever. Tracking current sota approaches while being all local项目地址: https://gitcode.com/GitHub_Trending/qmd1/qmd
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考