Files
group_fqcd_jr/docs/99-已废弃-公共Agent平台接口规范.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

714 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 公共 Agent 平台接口规范(历史稿,已废弃)
> 版本:v1.0
> 修订日期:2026-09-08
> 文档性质:历史评审稿,不再作为实现依据
> 适用对象:底座负责人、业务模块开发者、前端与客户端、编码 Agent
> 关联文档:`00-新数据库基线设计.md`(数据基线)、`01-通用Agent平台开发设计.md`(架构与内部契约权威源)、`02-数据库建表设计.md`(增量表)、`03-平台端到端流程文档.md`(业务流程)
> **废弃声明(2026-09-09)**:本文已被 [`05-接口文档.md`](05-接口文档.md) 完整取代,不得据此新增或修改接口。两份文档冲突时,以 `05-接口文档.md` 为唯一 HTTP 接口权威源;本文仅保留用于追溯早期设计决策。
---
## 0. 文档定位
### 0.1 本文负责
- HTTP 信封、认证方式、幂等、分页、追踪和 SSE 传输规则。
- 公共 Agent 平台接口:运行、会话、记忆、配置查询、模型路由查询、Prompt 引用、知识引用、转人工入口、审计查询。
- 平台管理面接口:配置发布与回滚、模型端点、模型路由规则、Prompt 版本、意图配置、禁止表达。
- 业务接口的**扩展格式、命名映射、权限声明和契约测试**要求。
### 0.2 本文不负责
- 内部 Service / Repository / 事件类型定义:见第 4 章索引,本文不复制。
- 业务域字段、状态机和业务校验规则:由各业务模块文档定义。
- 数据库表结构与迁移:以 `00-新数据库基线设计.md` 为不可变基线,增量见 `02`。
- Agent 执行骨架、配置权威链、工具与合规策略:以 `01` 为权威源。
### 0.3 权威源矩阵
| 契约项 | 唯一权威源 | 本文的处理方式 |
|---|---|---|
| HTTP 路径、信封、认证、幂等、分页、追踪、SSE 传输 | **本文** | 唯一定义 |
| SSE 事件名与载荷 | 01 §12 | 索引,不重复定义 |
| Service Protocol(9 个依赖) | 01 §5.4 | 索引 |
| 错误分类 `AgentError` 体系 | 01 §5.5 | 索引;本文只定义 HTTP 状态码映射 |
| `AgentRequest`、`RequestContext`、`AgentResult`、`CoreResult` 等 | 01 §5.2、§5.3 | 索引 |
| 执行骨架与七步顺序 | 01 §6 | 索引 |
| 配置权威链与发布回滚 | 01 §7.3、§7.4 | 索引 |
| `DomainEvent` 与 Outbox 语义 | 01 §5.3、02 §8.2 | 索引;本文只定义“何时产生” |
| 表结构、字段、约束 | 00 基线 + 02 | 索引 |
| 业务字段、状态机、业务校验 | 各业务模块文档 | 本文只列入口与 Agent 边界 |
### 0.4 边界裁决规则
1. **骨架优先**:本文定义的通用约定(信封、错误码、认证、幂等、分页、追踪、SSE 传输)优先于任何业务文档;业务文档不得在信封之外新增顶层字段。
2. **载荷归属**:业务字段、状态机、业务校验一律由业务文档定义,本文只引用。
3. **冲突处理**:同一契约项出现两处定义时,以《权威源矩阵》指定的文档为准,另一处必须删除并改为引用。禁止两个定义同时进入实现或迁移。
4. **新增错误码**:本文若需新增错误码,必须先在 01 §5.5 注册,再在本文映射 HTTP 状态码;未注册的 `code` 不得出现在响应中。
---
## 1. 通用约定
### 1.1 前缀与版本
- 所有接口统一前缀 `/api/v1`,网关按前缀做统一限流、大小限制和来源校验。
- 版本策略:路径版本。不兼容变更升为 `/api/v2`,同一版本内只允许向后兼容的新增字段。
- 01 §3.3 示例中的 `/agents/{agent_type}/chat` 在本文固化为 `POST /api/v1/agent-runs`(见 2.1)。
### 1.2 认证与上下文
- 认证方式:`Authorization: Bearer <JWT>`,所有接口强制,无匿名接口。
- **JWT 载荷**:
| 声明 | 含义 | 说明 |
|---|---|---|
| `sub` | `user_id` | 唯一身份标识 |
| `jti` | 令牌唯一 ID | 用于吊销与审计 |
| `iat` / `exp` / `iss` / `aud` | 标准声明 | 标准校验 |
| `portal` | 入口标识 | **签发时绑定**,请求参数不得覆盖 |
- **不得放入 JWT 的字段**:`roles`、`data_scope`、`assigned_customer_ids`。
依据 03 §4.2“FastAPI 认证依赖解析令牌,并重新加载有效角色”:角色与数据范围每次请求从 `sys_user_role` / `sys_role_permission` / `sys_customer_assignment` 加载(Redis 缓存 + 版本失效),保证权限降级即时生效;客户归属是动态集合,无法进令牌。
- 01:319 的约束在 HTTP 层落地为:`user_id`、`roles`、`portal`、`data_scope`、`clarification_round` **只来自服务端上下文**,客户端通过 query、header 或 body 提交这些字段一律忽略并记安全审计。
**网关与应用层职责(防御纵深)**
| 层 | 职责 | 不承担 |
|---|---|---|
| 网关 | JWT 签名校验、过期校验、限流、请求大小、来源白名单、`/api/v1` 前缀路由 | 业务授权、数据范围过滤 |
| 应用层 | 加载有效角色与数据范围、构造 `RequestContext`、`AgentFactory` 授权、工具与数据层过滤 | 不做令牌签名校验的替代 |
### 1.3 请求与响应信封
**请求头**
| 头 | 必填 | 说明 |
|---|---|---|
| `Authorization` | 是 | `Bearer <JWT>` |
| `Content-Type` | 写操作是 | `application/json; charset=utf-8` |
| `Idempotency-Key` | 写操作是 | 长度 8–64,见 1.5 |
| `X-Request-Id` | 否 | 客户端链路号,仅用于关联,不替代 `trace_id` |
**成功响应**
```json
{
"code": "OK",
"message": "成功",
"data": {},
"trace_id": "b7f1c2e0-4a6d-4f2b-9c31-0d5e7a8b9c01"
}
```
**错误响应**
```json
{
"code": "AGENT_INPUT_INVALID",
"message": "请求参数不正确",
"trace_id": "b7f1c2e0-4a6d-4f2b-9c31-0d5e7a8b9c01",
"error_id": null,
"details": []
}
```
- `details` 只在参数校验失败时填充字段级错误,禁止回传堆栈、SQL 或依赖原始响应。
- SSE 接口不使用该信封,见 1.8。
### 1.4 错误码与 HTTP 状态映射
错误码取值以 01 §5.5 为权威源,本文只做 HTTP 映射。
| code | HTTP | 场景 | 来源 |
|---|---|---|---|
| `OK` | 200 | 成功 | 本文 |
| `AGENT_INPUT_INVALID` | 400 | 参数、编码、长度校验失败 | 01:506 |
| `AGENT_PERMISSION_DENIED` | 403 | 角色、入口或数据范围不允许 | 01:511 |
| `AGENT_SESSION_NOT_FOUND` | 404 | 会话不存在**或**不属于当前用户 | **本文新增,需在 01 §5.5 注册** |
| `AGENT_IDEMPOTENCY_CONFLICT` | 409 | 同幂等键但请求体不同 | 01:984 |
| `AGENT_IDEMPOTENCY_PROCESSING` | 202 | 同幂等键请求仍在处理中 | 01:984 |
| `AGENT_RATE_LIMITED` | 429 | 网关或应用层限流 | 本文 |
| `AGENT_INTERNAL_ERROR` | 500 | 未预期异常,响应含 `error_id` | 01:669 |
**重要约定**
- **降级不是错误**:模型失败、Milvus 超时等可恢复故障经安全模板降级后,HTTP 返回 `200`,结果中带 `degraded: true` 与 `degradation_reason`(01 §6.2 的 `REPLACE` + `done` 路径)。客户端不得把 `degraded` 当作失败处理。
- **会话不存在与越权统一返回 404**:避免通过 403/404 差异探测他人会话是否存在。
- `AGENT_SESSION_NOT_FOUND` 注册前,实现方应临时使用 `AGENT_INPUT_INVALID`,不得自定义其他 `code`。
### 1.5 幂等
- 所有写操作(`POST` / `PUT` / `PATCH` / `DELETE`)必须携带 `Idempotency-Key`。
- 幂等范围:`user_id + agent_type + idempotency_key`(01:984),落表 `request_idempotency`(02 §8.3)。
- 行为:
| 情况 | 响应 |
|---|---|
| 键不存在 | 抢占记录(`processing`),正常执行 |
| 键存在、`request_hash` 不同 | `409 AGENT_IDEMPOTENCY_CONFLICT` |
| 键存在、`completed` | 返回原结果,`code=OK` |
| 键存在、`processing` 且租约未过期 | `202 AGENT_IDEMPOTENCY_PROCESSING` |
| 键存在、`processing` 且租约已过期 | 允许接管,重新执行 |
| 键存在、`failed` | 按业务决定是否允许重试,默认允许 |
- `request_hash` 由服务端对规范化后的请求体计算,客户端不得提交该字段。
### 1.6 分页
- 统一游标分页:`?limit={1..100}&cursor={opaque}`,`limit` 默认 20,上限 100。
- 响应结构:
```json
{
"code": "OK",
"message": "成功",
"data": { "items": [], "next_cursor": "eyJpZCI6MTIzfQ", "has_more": false },
"trace_id": "..."
}
```
- `cursor` 为不透明字符串,客户端不得解析或构造。禁止使用 `offset` 深分页。
### 1.7 追踪
- 服务端为每个请求生成唯一 `trace_id`,贯穿 API、模型、工具、数据库与事件日志(01 §6.4)。
- 响应头必须回传 `X-Trace-Id`,响应体 `trace_id` 与之一致。
- `trace_id` 同时是 Agent 运行的对外标识(见 2.1),本文不引入独立的 `run_id`。
### 1.8 SSE 传输规则
事件名称与载荷以 01 §12 为权威源,本节只定义如何通过 HTTP 传输。
**响应头**
```text
Content-Type: text/event-stream; charset=utf-8
Cache-Control: no-cache
Connection: keep-alive
X-Accel-Buffering: no
X-Trace-Id: <trace_id>
```
**认证**:与 1.2 一致,`Authorization: Bearer <JWT>`。不接受把令牌放在 query 参数中。
**事件帧格式**
```text
id: <seq>
event: <event_type>
data: <json>
```
- `id` 为单调递增序号(从 1 开始),供客户端排序与去重;即使 MVP 不实现事件级续传,服务端也必须提供该字段。
- `data` 为单行 JSON,不得包含裸换行;多行文本按 JSON 字符串转义。
**事件顺序与终止条件**
| 阶段 | 事件 | 说明 |
|---|---|---|
| 1 | `start` | 首帧,携带 `trace_id`、`session_id` |
| 2 | `tools` | 可选,工具调用摘要(已脱敏) |
| 3 | `delta` | 0..N 帧,安全文本分块 |
| 4 | `replace` | 可选,降级时用完整安全文本替换 |
| 5 | `done` | 正常终止,携带 intent、confidence、sources、suggestions、degraded |
| — | `error` | 异常终止,携带 error_code、message、trace_id |
- `done` 或 `error` 之后服务端必须关闭连接,不再发送任何帧。
- 合规约束:`delta` 只在输出合规检查完成后发送(01:987);MVP 为“全量生成、全量合规、持久化后分块发送”,不承诺模型 Token 级真流式(01 §12)。
- 持久化约束:`AgentPersistenceService.complete_run()` 成功返回后才允许发送最终 SSE(01:963、03 §5.6)。
**心跳**
- 空闲超过 15 秒发送注释行:`: keep-alive` + 空行。
- 注释帧不占 `id` 序号,客户端必须忽略。
**重连与断流恢复(结果级)**
- MVP **不实现事件级续传**。客户端可选携带 `Last-Event-ID`,服务端若无法续传,应按 2.1 的规则正常结束连接,不返回部分流。
- 断流后的恢复方式:客户端调用 `GET /api/v1/agent-runs/{trace_id}` 获取完整结果。
- 该规则与 01 §6.4“同一 `trace_id` 的重复请求返回已有结果”一致:运行结果在发送 `delta` 之前已落库,因此恢复查询总是能拿到最终内容。
- 客户端断开后,服务端仍须完成归档与审计(01 §6.4、03 §13)。
**超时**
- 服务端整体 SSE 生命周期上限 120 秒;超时发送 `error`(`AGENT_INTERNAL_ERROR`)并关闭。
- 模型单次调用超时 15 秒、最多 3 个端点(01:1168-1170)。
### 1.9 时间、金额与编码
| 项 | 约定 |
|---|---|
| 时间 | ISO 8601 UTC,微秒精度,如 `2026-09-08T12:00:00.000000Z`,与 02 §3 的 `DATETIME(6)` 对齐 |
| 金额 | 字符串,两位小数,语义同 `DECIMAL(18,2)`;禁止用浮点数 |
| 价格 | 字符串,六位小数 |
| 数量 | 字符串,四位小数 |
| 编码 | UTF-8;`Content-Type: application/json; charset=utf-8` |
| 空值 | 统一使用 `null`,禁止空字符串与 `null` 混用表达“无值” |
### 1.10 审计写入范围
审计表 `interaction_audit` 只追加、不可改(02 §12)。为避免技术噪声淹没受监管记录,写入范围固定如下。
**必须写入 `interaction_audit`**
| # | 类别 | 示例 |
|---|---|---|
| 1 | 受监管业务状态变化 | 委托、成交、资金、持仓、预警处置、工单流转 |
| 2 | 配置发布 | `config_release` 的创建、校验、审核、激活、回滚 |
| 3 | 权限决策 | 越权拒绝、适当性拦截、跨客户访问拒绝 |
| 4 | 人工处置 | 工单分配/接单/解决/关闭、投顾方案审核 |
| 5 | 对客内容与运行留痕 | `client_facing_content` 发布、Agent 运行结果 |
**只写运行日志与指标,不写审计**
| # | 类别 | 示例 |
|---|---|---|
| 1 | 心跳与租约 | SSE 心跳、幂等租约续期 |
| 2 | 幂等重试 | 抢占失败、`processing` 轮询 |
| 3 | 缓存操作 | 配置缓存命中/失效、记忆热缓存刷新 |
| 4 | 传输状态 | SSE 游标、断流、重连 |
| 5 | 运维流量 | 健康检查、限流拒绝、网关拦截 |
**边界情况**
- `request_idempotency` 的**完成**随 `complete_run` 在同一事务写审计(与业务结果绑定);**租约续期与接管**只写日志。
- 降级运行写审计(`outcome="degraded"`,01:888),但降级原因的技术细节写日志。
- 审计写入失败时,受监管业务不得返回成功(01 §13)。
---
## 2. 公共平台接口
统一约定:均需认证;均返回 1.3 信封(SSE 除外);均按 `data_scope` 过滤;均写 `trace_id`。
### 2.1 Agent 运行
#### 2.1.1 发起运行(SSE)
```text
POST /api/v1/agent-runs
```
**权限**:由 `AgentFactory` 按 `AgentDefinition.allowed_roles` + `allowed_portals` 判定;本文不在此处重复权限规则。
**幂等**:`Idempotency-Key` 必填。
**请求体**
```json
{
"agent_type": "customer_service",
"session_id": "session-uuid",
"message": "基金赎回多久到账?",
"idempotency_key": "client-request-uuid",
"end_session": false,
"metadata": {}
}
```
**与内部契约的映射(重要)**
`agent_type` 不在 01 §5.2 的 `AgentRequest` 中。为避免修改该契约,Controller 使用独立的 HTTP DTO `AgentRunRequest`,再映射为 Service 层命令对象:
```python
class AgentRunRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
agent_type: str
session_id: str
message: str
idempotency_key: str
end_session: bool = False
metadata: dict[str, Any] = Field(default_factory=dict)
def to_agent_request(self) -> AgentRequest:
return AgentRequest(
session_id=self.session_id,
message=self.message,
idempotency_key=self.idempotency_key,
end_session=self.end_session,
metadata=self.metadata,
)
@router.post("/agent-runs")
async def create_agent_run(
payload: AgentRunRequest,
context: RequestContext = Depends(build_request_context),
service: AgentService = Depends(get_agent_service),
) -> StreamingResponse:
events = service.run_stream(
payload.agent_type, payload.to_agent_request(), context
)
return AgentSseView.response(events)
```
该写法符合 MVC+S:Controller 持有 API DTO,Service 持有命令对象,Controller 不含业务判断(01:131)。
**响应**:`200` + `text/event-stream`,事件见 1.8 与 01 §12。
#### 2.1.2 查询运行结果(断流恢复)
```text
GET /api/v1/agent-runs/{trace_id}
```
**权限**:仅可查询本人或职责范围内的运行;越权统一返回 `404 AGENT_SESSION_NOT_FOUND`。
**数据来源**:由 `conversation_message` + `request_idempotency` + `interaction_audit` 按 `trace_id` 聚合,不新增运行实体表。
**响应 `data`**
```json
{
"trace_id": "b7f1c2e0-...",
"session_id": "session-uuid",
"agent_type": "customer_service",
"status": "completed",
"reply": "……",
"intent": "faq",
"confidence": "0.8231",
"source_references": [],
"tool_calls": [],
"suggestions": [],
"transfer_required": false,
"degraded": false,
"degradation_reason": null,
"created_at": "2026-09-08T12:00:00.000000Z"
}
```
- `status` 取值:`processing` / `completed` / `failed`(由 `request_idempotency.status` 映射)。
- `tool_calls` 为脱敏后的摘要,字段结构以 01 §5.3 `ToolCallRecord` 为权威源。
- 运行不存在或尚未落库时返回 `404 AGENT_SESSION_NOT_FOUND`。
#### 2.1.3 运行列表(可选)
```text
GET /api/v1/agent-runs?session_id=&agent_type=&limit=&cursor=
```
按 1.6 分页;仅返回数据范围内的运行。
### 2.2 会话与消息
| 方法 | 路径 | 说明 | 关联表 |
|---|---|---|---|
| `GET` | `/api/v1/conversations` | 会话列表,按 `last_active_at` 倒序 | `svc_conversation_session` |
| `GET` | `/api/v1/conversations/{session_id}` | 会话详情,含状态与 `clarification_round` | 同上 |
| `GET` | `/api/v1/conversations/{session_id}/messages` | 消息列表,游标分页 | `conversation_message` |
| `POST` | `/api/v1/conversations/{session_id}/end` | 结束会话,幂等 | `svc_conversation_session` |
| `POST` | `/api/v1/conversations/{session_id}/feedback` | 提交反馈 | `conversation_feedback` |
| `POST` | `/api/v1/conversations/{session_id}/handover` | 发起转人工 | `svc_handover_ticket` |
**约束**
- `clarification_round` 为只读字段,只能由服务端在澄清路径中原子递增(01:985),客户端不得提交。
- 反馈接口按 `message_id` 去重;匿名场景的唯一性由业务文档定义(见 7.2 遗留项)。
- 会话归属校验失败统一返回 `404`。
### 2.3 记忆
| 方法 | 路径 | 说明 |
|---|---|---|
| `GET` | `/api/v1/memories` | 记忆列表,按状态与有效期过滤 |
| `GET` | `/api/v1/memories/{memory_id}` | 记忆详情 |
| `GET` | `/api/v1/memories/{memory_id}/evidences` | 证据列表 |
| `GET` | `/api/v1/memories/conflicts` | 冲突列表(仅员工角色) |
| `POST` | `/api/v1/memories/{memory_id}/forget` | 发起遗忘,异步清理 Milvus/Neo4j/Redis |
**约束**
- 客户只能访问自己的记忆;员工按 `data_scope` 与客户归属过滤。
- 遗忘是异步流程(03 §12.5),接口返回受理状态,不代表物理删除已完成。
- 依法必须保留的交易、审计与对话归档不参与遗忘。
### 2.4 配置查询
| 方法 | 路径 | 说明 |
|---|---|---|
| `GET` | `/api/v1/agent-configs/{agent_type}/resolved` | 返回解析后的 `ResolvedAgentConfig`(脱敏) |
| `GET` | `/api/v1/agent-configs/releases/active` | 当前 active 发布批次摘要 |
- 响应中不得出现 `secret_ref` 的实际值、密钥、供应商完整地址。
- 配置的写操作见第 3 章;本组接口只读,用于排障与前端展示。
### 2.5 模型路由查询
```text
GET /api/v1/model-routes/resolved?agent_type=&task_type=
```
- 返回本次会选中的策略名、主端点代号、备用链代号、`max_attempts`、`latency_budget_ms`。
- 不返回 `secret_ref`、完整 `base_url`、成本单价。
- 端点与路由的增删改见第 3 章。
### 2.6 Prompt 引用
- 公共侧不提供 Prompt 内容的读取接口;每次运行使用的 Prompt 版本通过 2.1.2 的 `trace_id` 关联审计记录获取(01 §7.4)。
- Prompt 的创建与版本管理见 3.4。
### 2.7 知识引用
| 方法 | 路径 | 说明 |
|---|---|---|
| `GET` | `/api/v1/knowledge/{knowledge_id}` | 查询已发布知识元数据(不含全文) |
| `GET` | `/api/v1/agent-runs/{trace_id}` | 已包含本次运行的 `source_references` |
- 只返回 `review_status='published'` 且 `status='active'` 且在有效期内的条目(02 §6.2)。
- 知识上传、审校与发布流程由知识运营业务文档负责(03 §7)。
### 2.8 转人工(通用入口)
```text
POST /api/v1/conversations/{session_id}/handover
```
**请求体**
```json
{
"reason_code": "complaint",
"reason_detail": "客户投诉资金争议"
}
```
**响应 `data`**
```json
{ "ticket_no": "HT20260908000001", "status": "pending", "priority": "P0" }
```
**边界**
- 本接口只负责“发起转接”这一跨 Agent 骨架动作,落 `svc_handover_ticket`。
- 工单的队列、分配、接单、解决、关闭状态机与字段由客服业务文档定义(02 §7.2、03 §6.4)。
- 转人工事件 `conversation.transfer_requested` 由底座在 `complete_run` 时同事务写入 Outbox(01:937)。
### 2.9 审计查询
```text
GET /api/v1/audit-records?actor_id=&action_type=&target_customer_id=&from=&to=&limit=&cursor=
```
- 权限:`admin`、`super_admin`;`risk_operator` 按风控数据范围。
- 只读;`interaction_audit` 不允许任何更新或删除接口(02 §12)。
- `detail` 字段的结构由产生该审计的业务模块文档定义。
---
## 3. 平台管理面接口
统一前缀 `/api/v1/admin`,权限限 `admin` / `super_admin`。所有写操作需 `Idempotency-Key`,全部写审计(1.10 第 2 类)。
### 3.1 配置发布批次
| 方法 | 路径 | 说明 |
|---|---|---|
| `POST` | `/admin/config-releases` | 创建草稿 |
| `GET` | `/admin/config-releases` | 批次列表 |
| `GET` | `/admin/config-releases/{id}` | 批次详情与配置项 |
| `POST` | `/admin/config-releases/{id}/validate` | Schema 与安全上限校验 |
| `POST` | `/admin/config-releases/{id}/review` | 审核(`reviewer_id <> created_by`) |
| `POST` | `/admin/config-releases/{id}/activate` | 原子激活 |
| `POST` | `/admin/config-releases/{id}/rollback` | 回滚到指定历史版本 |
**约束**
- 状态机以 02 §8.4 的 CHECK 取值为准:`draft` / `validating` / `pending_review` / `approved` / `active` / `superseded` / `rejected` / `rolled_back`。
- 全局同一时刻只允许一个 `active` 批次,由 `uk_config_release_active_one` 在数据库层强制(02:582)。
- 回滚是重新激活历史不可变版本,不原地修改历史记录(01 §7.4)。
- 激活后必须使 `agent-config:{agent_type}:{release_id}` 缓存失效。
### 3.2 模型端点
| 方法 | 路径 | 说明 |
|---|---|---|
| `GET` | `/admin/model-endpoints` | 端点列表(`secret_ref` 只回显引用名) |
| `POST` | `/admin/model-endpoints` | 新建端点 |
| `POST` | `/admin/model-endpoints/{id}/status` | 启用/禁用/归档 |
- 禁止通过任何接口读取或写入明文密钥(02 §8.6、§12)。
### 3.3 模型路由规则
| 方法 | 路径 | 说明 |
|---|---|---|
| `GET` | `/admin/model-routes?release_id=` | 规则列表 |
| `POST` | `/admin/model-routes` | 在指定 release 内新增规则 |
- `max_attempts` 取值 1–3,由 02:683 的 CHECK 强制。
- `fallback_endpoint_ids` 为 JSON 数组,端点有效性由应用层在发布校验阶段验证(见 7.2 遗留项)。
### 3.4 Prompt 版本
| 方法 | 路径 | 说明 |
|---|---|---|
| `GET` | `/admin/prompts?task_type=&agent_type=` | 版本列表 |
| `POST` | `/admin/prompts` | 新增不可变版本 |
- `prompt_code + version` 唯一(02 §8.8),版本一经创建不可修改。
### 3.5 意图配置
| 方法 | 路径 | 说明 |
|---|---|---|
| `GET` | `/admin/intent-configs?agent_type=` | 配置列表 |
| `POST` | `/admin/intent-configs` | 新增版本 |
- 不得新增 `AgentDefinition.supported_intents` 之外的意图(01:1106)。
- 工具白名单按意图配置,解析时与代码上限、角色权限求交集(01:1099)。
### 3.6 禁止表达
| 方法 | 路径 | 说明 |
|---|---|---|
| `GET` | `/admin/negative-words` | 规则列表 |
| `POST` | `/admin/negative-words` | 新增规则(初始 `draft`) |
| `POST` | `/admin/negative-words/{id}/status` | 启用/停用/归档 |
- 只有审核通过的规则才可置为 `active`(02 §7.1)。
---
## 4. 内部契约索引
本章只做索引,不复制任何定义。修改内部契约必须修改权威源,并同步本节引用。
| 契约 | 权威源 | 变更要求 |
|---|---|---|
| `AgentRequest`、`RequestContext`、`AgentDefinition`、`ResolvedAgentConfig` | 01 §5.2 | 改动需评估 HTTP 映射影响 |
| `SseEvent`、`IntentResult`、`SourceReference`、`ToolCallRecord`、`ToolResult`、`CoreResult`、`AgentResult` | 01 §5.3 | 本文 2.1.2 响应结构随之更新 |
| 依赖协议(`ModelGateway`、`MemoryService`、`ComplianceService`、`ToolExecutor`、`AgentPersistenceService` 等 9 项) | 01 §5.4 | 不影响 HTTP 层 |
| 错误分类 `AgentError` 体系 | 01 §5.5 | 新增 `code` 必须在此注册 |
| 执行骨架与七步顺序 | 01 §6 | 决定 SSE 事件时序 |
| `AgentFactory` / `AgentRegistry` | 01 §7 | 决定 2.1.1 的权限判定入口 |
| 配置权威链与发布回滚 | 01 §7.3、§7.4 | 决定第 3 章接口语义 |
| `DomainEvent` | 01 §5.3 | 本文只定义何时产生 |
| `domain_event_outbox`、`request_idempotency`、`svc_conversation_session` 等增量表 | 02 §8 | 字段变更以 02 为准 |
| 基线表与字段 | 00 基线 | 只增不改(`AGENTS.md` 第 2–4 条) |
---
## 5. 扩展规范
### 5.1 A 类扩展:Agent 能力
新增某类 Agent 的意图与 `handle()` 时:
- **不新增 HTTP 接口**,复用 `POST /api/v1/agent-runs`。
- 变更范围限定为:`implementations/<agent_type>_agent.py`、`bootstrap.py`(一行注册)、单元测试、契约测试数据(01 §16.4)。
- 禁止修改 `base.py`、`factory.py`、`contracts.py`、`app/controller/**`、`app/view/**`(01 §16.5)。
### 5.2 B 类扩展:业务 API
新增领域接口(如模拟下单、预警处置、方案审核)时:
- **新增 Controller 与 Service**,且 Controller 只做路由、参数校验、调用 Service、返回 View。
- 必须继承以下公共骨架,缺一不可:
| # | 约束 | 依据 |
|---|---|---|
| 1 | 统一前缀 `/api/v1`、统一信封与错误码 | 1.1、1.3、1.4 |
| 2 | 认证走统一上下文,禁止自建鉴权 | 1.2 |
| 3 | 写操作必须幂等 | 1.5 |
| 4 | 列表必须游标分页 | 1.6 |
| 5 | 响应回传 `trace_id` | 1.7 |
| 6 | 按 1.10 写入审计 | 1.10、02 §12 |
| 7 | Controller 禁止访问 Model / ORM,禁止业务条件 | 01:131、02 §3 |
- 业务字段、状态机、业务校验规则必须在对应业务模块文档中定义,本文不预先写死。
### 5.3 命名映射规则
| 场景 | 规则 | 示例 |
|---|---|---|
| `agent_type` | snake_case,正则 `[a-z][a-z0-9_]{1,31}` | `customer_service` |
| HTTP 路径段 | kebab-case,资源用复数 | `/api/v1/risk-alerts` |
| 域路径 | 仅在该域存在独立业务 API 时使用,与 `agent_type` 无强制同名 | `customer_service` → `/api/v1/customer-service/**` |
| 状态流转 | 资源 + 子资源 | `/risk-alerts/{id}/actions` |
| 数据库表名 | 沿用基线前缀约定 | `fin_`、`sys_`、`svc_`、`agent_` |
- `operations` 仅作为 `agent_type` 保留,对话走统一 `agent-runs`,**不设** `/operations/**` 域前缀。
- 场外运营业务 API 使用语义明确的独立资源名,例如 `/api/v1/offshore-subscriptions`、`/api/v1/fund-operation-mails`,并遵守 `AGENTS.md` 第 8 条(独立建表、独立接口)。
### 5.4 权限声明格式
每个 B 类接口必须在业务文档中声明:
```text
接口:POST /api/v1/sim-orders
allowed_roles: customer, operator, admin
allowed_portals: web, app
data_scope: own_only
幂等: 必需,幂等键 = client_order_no
审计: 是(1.10 第 1 类,受监管业务状态变化)
Agent 边界: Agent 只读查询委托与成交,不得代客下单
```
### 5.5 契约测试要求
每个 B 类接口至少覆盖:
- 未认证 → `401`;令牌无效 → `401`。
- 角色/入口不允许 → `403`。
- 越权访问他人数据 → `404`(统一口径)。
- 写操作缺少 `Idempotency-Key` → `400`;重复提交 → 幂等命中。
- 分页边界:`limit=0`、`limit=101`、非法 `cursor`。
- 审计写入成功且不可被业务接口修改。
- 响应信封与错误码符合第 1 章。
---
## 6. 业务接口清单
本清单只列入口、归属文档和 Agent 边界;详细字段与状态机由归属文档负责。
| 入口 | 类型 | 归属文档 | Agent 边界 |
|---|---|---|---|
| `POST /api/v1/sim-orders` | B | 交易域文档 | Agent 只读查询委托/成交,**不得代客下单**(03 §2) |
| `GET /api/v1/sim-orders`、`/api/v1/holdings` | B | 交易域文档 | 只读,按客户归属过滤 |
| `POST /api/v1/risk-alerts/{alert_id}/actions` | B | 风控域文档 | Agent **不能**确认、关闭或升级预警(03 §10.3) |
| `POST /api/v1/risk-scan-runs` | B | 风控域文档 | 规则引擎产生预警,模型只做辅助研判(03 §10.1) |
| `POST /api/v1/advisory-plans/{plan_id}/reviews` | B | 投顾域文档 | Agent 只生成草案,审核由持证投顾执行(03 §8) |
| `GET/POST /api/v1/client-facing-contents` | B | 投顾域文档 | 草稿状态内容不得作为正式建议返回(03 §8) |
| `GET/POST /api/v1/handover-tickets` | B | 客服域文档 | 状态流转由人工执行(02 §7.2、03 §6.4) |
| `GET/POST /api/v1/faq-synonyms` | B | 知识运营文档 | 只有 `approved` 参与检索(02 §7.3) |
| `GET/POST /api/v1/knowledge-documents` | B | 知识运营文档 | 发布需审校(03 §7) |
| `GET/POST /api/v1/offshore-subscriptions` | B | 场外运营文档 | 人工在回路确认后才提交清算(03 §11) |
| `GET/POST /api/v1/feedback-reviews` | B | 客服域文档 | 质检池归人工处理(03 §6.5) |
> 本清单为**索引**,不是接口定义的权威源。新增业务接口时在此登记一行,并在归属文档中定义字段。
---
## 7. 边界裁决与遗留项
### 7.1 裁决规则
见 0.4。补充两条操作要求:
- 修改权威源后,必须同步本文第 4 章索引,并在提交说明中写明“权威源 + 同步位置”。
- 任何契约项若出现两处定义,实现与迁移脚本必须停止推进,先完成裁决再继续。
### 7.2 已知遗留项
| # | 遗留项 | 影响 | 处理 |
|---|---|---|---|
| 1 | `AGENT_SESSION_NOT_FOUND`、`AGENT_RATE_LIMITED` 尚未在 01 §5.5 注册 | 错误码权威性 | 提请在 01 §5.5 补注册 |
| 2 | 匿名反馈的唯一性依赖 API 限流,`uk_feedback_message_customer` 对 `customer_id IS NULL` 不生效 | 重复刷票风险 | 由客服业务文档定义哨兵值或指纹方案 |
| 3 | `fallback_endpoint_ids` 为 JSON 数组,无外键约束 | 备用端点可能失效 | 3.3 的发布校验必须验证端点存在且状态为 `active` |
| 4 | `fin_knowledge_meta.content_text` 基线定义为非空,02 实施为可空 | 基线一致性 | 由 02 登记偏差或提请基线修订 |
| 5 | 事件级 SSE 续传未实现 | 重连体验 | MVP 采用结果级恢复(1.8) |
---
## 8. 变更记录
| 版本 | 日期 | 变更 |
|---|---|---|
| v1.0 | 2026-09-08 | 首版:确立 HTTP 层权威源边界、七章结构、SSE 传输规则、审计写入范围、A/B 类扩展规范 |