Files
group_fqcd_jr/docs/17-接口文档易懂说明.md
T
lzf_0626 6516ccb385 feat: 第二版——接口契约对齐 docs/05,修复静默故障与数据库基线
相对第一版 46fc976 的完整变更。组员迁移对照表见 docs/20。

一、对外契约对齐 docs/05(破坏性,共 4 处,组员需按 docs/20 调整)
1) 配置发布端点改为文档规定的复数资源名:submit→validations、
   approve→reviews(需 body decision)、activate→activations、
   rollback→rollbacks;第一版这 4 个动词式路径 docs/05 从未定义过。
2) 错误码由 8 个笼统码改为 15 个具体语义码(FORBIDDEN→AGENT_PERMISSION_DENIED、
   UNAUTHORIZED→AUTHENTICATION_REQUIRED、CONFLICT→RESOURCE_VERSION_CONFLICT、
   RESOURCE_NOT_FOUND→RUN_NOT_FOUND/SESSION_NOT_FOUND 等),
   输入类错误状态码 400→422。
3) POST /api/v1/agent-runs 与 GET /api/v1/agent-runs/{run_id} 统一为
   {data, meta} 信封(data 内字段名与语义未变)。
4) 错误响应体统一为 {error:{code,message,retryable,field_errors}, meta:{trace_id}},
   不再返回 FastAPI 默认的 {"detail": ...}。

二、数据库基线与约束
新增 39 张表的基线迁移(链根)与联合唯一键纠偏(4 张表、删 8 增 4,幂等收敛);
撤下 config_release 的双人复核 CHECK(应用层已允许自审,审核节点保留,
自审如实写入 reviewer_id);记忆 active key 生成列与唯一键;
activate 开始记录 supersedes_release_id 使版本链可追溯。
docs/00 基线未修改,未重命名或删除任何表与字段。

三、修复会静默出错或无报错的缺陷
- 跑完集成测试后平台会静默失去生效配置:清理只删自己创建的版本,却没有恢复被它
  顶成 superseded 的原生效版本,且审计一并删除因而完全无痕,表现为所有工具被拒
  但没有任何报错。已修清理逻辑并加恢复。
- Worker 单轮异常导致进程退出;记忆抽取调用方的“事务已开始”异常;
  召回缓存丢失 degraded 标记;连接时区未生效导致 created_at/updated_at 差 8 小时;
  .env 与 os.getenv 密钥来源分裂导致“没有可用的已批准模型端点”。
- 记忆信号识别漏判与跨键误命中;SSE 未带 Accept 的协商行为。

四、功能补齐
记忆链路 P1/P2/P3(抽取、受控词表、召回与缓存、生命周期级联及投影事件)、
fin_* 场内交易只读 ORM 层、agent_intent_config 状态流转并在运行期真正生效、
限流(Redis 固定窗口、故障一律放行)、游标校验、trace_id 中间件、
示例业务 Agent fund_query_demo 与一键端到端验证脚本,以及审计/指纹/迁移状态工具。

五、文档与验证
新增 docs/19(业务 Agent 接入实操)、docs/20(第一版迁移指南)与 docs/evidence 证据;
docs/01/02/06/08/09/17 同步实现现状。

验证结果:ruff 通过、mypy 103 文件无错、unit+contract 447 passed、
integration 29 passed、acceptance_check --production 7 PASS、
demo_agent_e2e 9/9 PASS(含失败关闭反证)。
2026-09-10 15:55:54 +08:00

14 KiB
Raw Blame History

接口文档易懂说明

本文是《05-接口文档.md》的阅读指南,不替代 05 文档。
适用对象:前端、业务 Agent 开发人员、测试人员和 AI 编码助手。

1. 接口到底是什么

接口就是前端或其他系统和平台说话的固定方式。调用接口时,必须明确:

请求地址 + 请求方法 + Header + 请求体
→ 服务端处理
→ HTTP 状态码 + 返回数据

本系统有三类接口:

类型 地址前缀 用途
业务运行接口 /api/v1 提交 Agent、查结果、订阅 SSE
平台管理接口 /api/v1/admin 管理配置、模型、Prompt、意图和审计
运维接口 /internal 健康检查和监控

业务 Agent 一般不需要新增公共 HTTP 接口。新增一个 Agent 通常直接使用统一的 /api/v1/agent-runs。

2. 先看懂一次完整请求

2.1 提交 Agent 运行

POST /api/v1/agent-runs
Authorization: Bearer <JWT>
Idempotency-Key: advisor-request-202609100001
Content-Type: application/json
{
  "agent_type": "advisor",
  "session_id": "session-uuid",
  "message": "请查询基金 159511 的行情",
  "metadata": {
    "locale": "zh-CN",
    "client_version": "web-1.0",
    "ui_entry": "advisor-chat"
  }
}

返回 202:

{
  "data": {
    "run_id": "run-uuid",
    "trace_id": "trace-uuid",
    "status": "queued",
    "status_url": "/api/v1/agent-runs/run-uuid",
    "events_url": "/api/v1/agent-runs/run-uuid/events"
  },
  "meta": {
    "trace_id": "trace-uuid"
  }
}

2.2 这几个字段的区别

  • agent_type:要执行哪个业务 Agent;必须已经在 AgentFactory 注册;
  • session_id:这次对话属于哪个会话;
  • message:用户真正说的话;
  • idempotency-key:防止网络重试造成重复运行;
  • run_id:一次运行的唯一编号;
  • trace_id:贯穿日志、审计、事件和模型调用的追踪编号;
  • status_url:查询最终结果;
  • events_url:订阅实时或最终 SSE 结果。

客户端不能通过请求体伪造 user_id、角色、客户范围、模型、工具或权限。

3. 通用 Header

3.1 JWT

除运维接口外,接口都需要:

Authorization: Bearer <access-token>

服务端会检查签名、签发方、受众、有效时间和吊销状态,并重新读取用户当前角色和权限。 不能只相信 JWT 里保存的历史角色。

3.2 幂等键

所有写接口都要按 05 文档要求携带:

Idempotency-Key: unique-request-key

同一个用户、同一路径、同一个幂等键:

  • 请求内容相同:返回第一次请求的结果;
  • 请求内容不同:返回 409 IDEMPOTENCY_CONFLICT;
  • 原请求还在运行:返回原来的 run_id,不会创建第二次运行。

3.3 其他 Header

Content-Type: application/json
Accept: application/json
If-Match: <etag>

Accept 非必填。普通接口按 application/json 返回;SSE 接口见第 6 节, 显式声明不接受 text/event-stream 时会返回 406 SSE_NOT_ACCEPTABLE。

If-Match 主要用于管理接口更新和状态转换,防止两个人同时覆盖配置。

4. 成功和失败格式

4.1 成功格式

单个资源:

{
  "data": {},
  "meta": {"trace_id": "trace-uuid"}
}

列表资源:

{
  "data": [],
  "meta": {
    "trace_id": "trace-uuid",
    "next_cursor": "opaque-cursor",
    "has_more": false
  }
}

4.2 失败格式

{
  "error": {
    "code": "AGENT_PERMISSION_DENIED",
    "message": "当前角色不能使用该 Agent",
    "retryable": false,
    "field_errors": []
  },
  "meta": {"trace_id": "trace-uuid"}
}

错误响应不会返回 SQL、堆栈、模型原文、供应商响应或密钥。

5. Agent 运行接口

5.1 创建运行

POST /api/v1/agent-runs

用途:把用户消息提交给已注册的 Agent。返回 202 只表示“已受理”,不代表业务已经完成。

典型状态:

queued → running → succeeded
                 → failed
queued/running → cancel_requested → cancelled

5.2 查询运行

GET /api/v1/agent-runs/{run_id}

用途:获取最终权威结果。运行未完成时 result=null;成功后结果来自数据库持久化消息,不依赖 Worker 内存。

{
  "data": {
    "run_id": "run-uuid",
    "status": "succeeded",
    "result": {
      "reply": "最终回复",
      "intent": "fund_quote",
      "confidence": "0.9200",
      "source_references": [],
      "transfer_required": false,
      "degraded": false
    }
  },
  "meta": {"trace_id": "trace-uuid"}
}

5.3 取消运行

POST /api/v1/agent-runs/{run_id}/cancellations
Idempotency-Key: cancel-request-001
{"reason": "user_cancelled"}

返回 202 表示已提出取消请求。运行已经成功、已经失败或已进入最终提交阶段时返回 409 RUN_NOT_CANCELLABLE。

重复取消是幂等的:对同一运行再次调用取消,返回与首次相同的状态与受理时间,不会报错; 取消成功后原请求会在 request_idempotency 中记为 status=failed + error_code=RUN_CANCELLED, 表示这次请求已被终止(RUN_CANCELLED 不是 HTTP 响应码,客户端不需要处理它)。

6. SSE 接口怎么用

GET /api/v1/agent-runs/{run_id}/events
Authorization: Bearer <JWT>
Accept: text/event-stream

Accept 是非必填头:不携带时服务端按 SSE 返回;显式携带时必须接受 text/event-stream(text/*、*/* 也算接受),否则返回 406 SSE_NOT_ACCEPTABLE。 运行不存在或不属于当前用户时仍然返回 404 RUN_NOT_FOUND——不因为 Accept 非法就改变 可见性判断,避免被用来探测运行是否存在。

6.1 事件顺序

未完成运行:

start → 心跳 → 等待最终提交

正常完成:

start → tools(可选)→ delta(一个或多个)→ done

已完成运行重连:

start → replace → done

错误:

start → error

6.2 客户端注意事项

  • SSE 必须携带 JWT;
  • 浏览器原生 EventSource 无法设置 Authorization Header,建议使用支持 Header 的 fetch 流式实现;
  • done 和 error 是终止事件;
  • 当前是结果级恢复,不是事件级 Last-Event-ID 续传;
  • 断线后重新请求同一个 run_id;
  • 使用 run_id + result_version 去重;
  • delta、replace 和 done 只会在最终事务提交后发送。

7. 会话接口

创建会话

POST /api/v1/conversations
Idempotency-Key: session-create-001
{"agent_type": "advisor"}

查询会话

GET /api/v1/conversations/{session_id}

查询消息

GET /api/v1/conversations/{session_id}/messages?limit=20&cursor=<cursor>

结束会话

POST /api/v1/conversations/{session_id}/closures
Idempotency-Key: session-close-001

转人工

POST /api/v1/conversations/{session_id}/handover-requests
Idempotency-Key: handover-001

Agent 可以发起转人工请求,但不能分配、接单、解决或关闭人工工单。

8. 记忆和知识引用接口

查询自己的记忆:

GET /api/v1/users/me/memory-profile

查询授权客户记忆:

GET /api/v1/customers/{customer_id}/memory-profile

解析知识引用:

GET /api/v1/knowledge-references/{reference_token}

记忆和知识数据都受权限和客户范围限制,不能通过 token 枚举其他客户的数据。

9. 平台管理接口

管理接口只给管理员和配置负责人使用,业务 Agent 不应该在 handle() 中调用这些接口。

主要分类:

分类 示例
配置发布 /api/v1/admin/config-releases
平台配置项 /api/v1/admin/config-releases/{id}/platform-config-items
模型端点 /api/v1/admin/model-endpoints
模型路由 /api/v1/admin/config-releases/{id}/model-routing-rules
Prompt /api/v1/admin/prompt-templates
Agent 意图 /api/v1/admin/agent-intent-configs
回复模板 /api/v1/admin/reply-templates
禁止表达 /api/v1/admin/negative-word-rules
审计查询 /api/v1/admin/audit-records

配置发布流程:

draft → pending_review → approved → active
                         ↘ rejected
active → superseded / rollback

管理更新必须使用 If-Match;创建、审核、激活、回滚和停用必须使用幂等键。审核节点不可跳过(单管理员部署下创建人可自审,不再要求复核人不同于创建人)。

10. 运维接口

GET /internal/health/live
GET /internal/health/ready
GET /internal/metrics
  • live:进程是否存活;
  • ready:服务是否可以接收请求,MySQL/Redis 等依赖异常时可能返回 503;
  • metrics:监控指标。

11. 常见错误

下表与唯一权威接口文档 docs/05-接口文档.md §3.6 完全一致(按 §6.4 的澄清, RUN_CANCELLED 不是 HTTP 响应错误码,因此单列在表末并标注用途),并由 tests/unit/core/test_errors.py 逐条锁定(实现里每个异常类的码、状态码和可重试标注 都必须能对回这张表)。错误响应信封见 §3.4:

{
  "error": {
    "code": "IDEMPOTENCY_CONFLICT",
    "message": "幂等键已用于不同请求",
    "retryable": false,
    "field_errors": []
  },
  "meta": {"trace_id": "trace-uuid"}
}
状态码 错误码 说明 是否重试
400 INVALID_CURSOR 游标非法、过期或与过滤条件不符 否
401 AUTHENTICATION_REQUIRED Token 缺失、无效、过期或已吊销 修复 Token 后再试
403 AGENT_PERMISSION_DENIED 角色、入口或数据范围不允许 否
404 SESSION_NOT_FOUND 会话不存在,或为防枚举而被隐藏;其他被隐藏资源(消息、工单、客户、管理面资源)复用此码 否
404 SESSION_NOT_ACCESSIBLE 当前身份不能访问该会话(含跨用户运行受理) 否
404 AGENT_TYPE_NOT_FOUND 请求的 agent_type 未注册(受理前拒绝,不写库) 否
404 RUN_NOT_FOUND 运行不存在或不可见;越权与不存在返回同一码,不泄露存在性 否
406 SSE_NOT_ACCEPTABLE Accept 不接受 text/event-stream 否
409 IDEMPOTENCY_CONFLICT 幂等键复用但请求不同;唯一性约束冲突同样归此码 否
409 RESOURCE_VERSION_CONFLICT If-Match 版本过期或缺失 可以重试
409 RUN_NOT_CANCELLABLE 运行已成功、失败或进入最终提交事务;非法状态转换(审核、停用、关闭会话等)也归此码 否
(仅状态标识) RUN_CANCELLED 只写在 request_idempotency(status=failed),表示取消后原请求已终止;不作为 HTTP 响应码返回,重复取消返回同一状态 —
409 FEEDBACK_ALREADY_EXISTS 同一用户对同一消息重复提交且内容不同 否
422 AGENT_INPUT_INVALID 已解析请求不满足字段或业务输入约束(含工具参数校验失败) 否
429 RATE_LIMITED 频率、并发或配额限制 可以重试
500 AGENT_INTERNAL_ERROR 未分类内部错误 视情况
503 DEPENDENCY_UNAVAILABLE 必需依赖不可用(模型端点、embedding、行情源、工具调用失败),Worker 会重试 可以重试
504 UPSTREAM_TIMEOUT 上游超过时间预算(模型、工具、Agent 执行超时) 可以重试

注意事项:

  • 401 与其他错误使用同一个信封:code=AUTHENTICATION_REQUIRED,并带 error.retryable 与 error.field_errors;令牌缺失、非法、过期、吊销以及账号不可用都返回这一种形态, 调用方只需要一套解析逻辑。认证失败时请求上下文尚未建立,meta.trace_id 复用请求头里的 X-Trace-ID,没有则为空字符串(服务端不会凭空生成)。
  • 越权资源统一返回 404,不泄露资源是否存在;明确功能无权限时返回 403。
  • Worker 落库的 agent_run.error_code 是任务层字段,与 HTTP 错误码不同层, 例如 RUN_CANCELLED、RUN_LEASE_LOST 出现在该字段中不代表 HTTP 响应码。
  • RUN_CANCELLED 只作为 request_idempotency 的状态标识(status=failed)使用, 不是 HTTP 响应错误码;对同一运行重复取消必须幂等返回同一状态。

12. 业务 Agent 与接口的关系

A 类:Agent 能力扩展

新增 Agent、意图或 handle() 分支时,继续使用:

POST /api/v1/agent-runs

不需要新增 Controller,不允许复制一套 HTTP 运行接口。

B 类:业务 API 扩展

只有确实需要独立领域资源,例如模拟委托、风险处置、方案审核时,才新增业务接口。新增时必须:

  • 使用 /api/v1 前缀;
  • 由 Controller 调 Service,不能直接访问 Model;
  • 使用统一 JWT、错误信封、幂等、追踪和审计;
  • 清楚写出 Agent 能做什么、不能做什么;
  • 同时更新 05 文档、OpenAPI、权限、审计和测试。

13. 前端或业务联调清单

[ ] 使用真实 agent_type,确认已注册
[ ] Authorization 使用 Bearer JWT
[ ] 所有写请求有唯一 Idempotency-Key
[ ] POST 受理后使用 run_id 查询或订阅 SSE
[ ] SSE 断线后重新请求同一个 run_id
[ ] 按 data/meta 读取成功信封
[ ] 按 error/meta 读取错误信封
[ ] 不把 202 当成业务完成
[ ] 不把 degraded 行情当成成交结果
[ ] 不把客户端传入的身份字段当成权限依据

14. 接口变更规则

新增或修改接口必须同时更新:

  1. docs/05-接口文档.md;
  2. OpenAPI 定义;
  3. 权限码、审计类别、幂等和错误码;
  4. 正常、越权、重复提交、故障恢复和安全测试;
  5. 对应业务文档的入口索引。

已有接口不能随意删除、改名、改字段类型或改变既有含义。发生破坏性变更时升级到新的主版本路径。

15. 权威文档关系

接口路径、Header、信封、错误、SSE、幂等 → docs/05-接口文档.md
Agent 内部执行契约 → docs/01-通用Agent平台开发设计.md
数据库表和字段 → docs/00-新数据库基线设计.md、docs/02-数据库建表设计.md
组员开发步骤 → docs/15、docs/16

出现冲突时,不要同时实现两种规则,先按权威源矩阵裁决。