chore: 基线提交——既有设计文档与样本数据

This commit is contained in:
lhl
2026-08-08 15:16:42 +08:00
parent 56da6c9917
commit 82cd2f270e
21 changed files with 5827 additions and 0 deletions
+321
View File
@@ -0,0 +1,321 @@
# API 与编排接口设计
> 版本: v1.0 | 日期: 2026-07-30 | 状态: 初版
>
> 本文档定义 **Web 后端(FastAPI Orchestrator)的 REST API 端点、WebSocket 事件通道、编排调用链与部署拓扑**。是 `docs/design.md` §8Web UI)与 `docs/agent-runtime-design.md` §3(编排能力)的接口级展开。
---
## 目录
1. [定位与架构](#1-定位与架构)
2. [REST API 端点清单](#2-rest-api-端点清单)
3. [WebSocket 事件通道](#3-websocket-事件通道)
4. [编排调用链](#4-编排调用链)
5. [任务队列抽象](#5-任务队列抽象)
6. [部署拓扑](#6-部署拓扑)
7. [错误码约定](#7-错误码约定)
8. [与各文档的关系](#8-与各文档的关系)
---
## 1. 定位与架构
```
浏览器 (React UI)
│ REST API (JSON) + WebSocket (实时事件)
FastAPI Orchestrator(单进程,默认)
├── SessionManager(会话状态机,见 agent-runtime §3
├── Agent 调度(Parser / Impact / Writer / QA
├── TaskQueue 抽象(默认 InMemory,可切 Redis/Valkey
└── RagService 调用(规则检索)
```
**架构决策**(与用户确认):
- **编排形态**:抽象 `TaskQueue` 接口 + 双实现。默认 `InMemoryQueue`(开发/测试/演示零依赖);部署时可切换 `RedisQueue` / `ValkeyQueue`Redis 协议兼容,`redis-py` 客户端通用)。
- **许可说明**Redis 内部使用合法(RSALv2/SSPLv1 仅限制「提供 Redis 托管服务给第三方」);若需完全开源无限制,使用 Valkey(BSD-3),代码无需改动。
- 所有 API 返回 JSON;长任务(解析/影响调查/生成)采用「异步启动 + 轮询/推送」模式。
---
## 2. REST API 端点清单
### 2.1 会话管理
| Method | Path | 说明 | 请求体 | 响应 | 触发状态转移 |
|--------|------|------|--------|------|-------------|
| POST | `/api/sessions` | 创建会话 | `{user_id}` | `{session_id, status, locked_rule_version}` | `→ uploading` |
| GET | `/api/sessions/{id}` | 获取会话详情 | — | 会话对象(状态/步骤/进度摘要) | 只读 |
| DELETE | `/api/sessions/{id}` | 删除会话 | — | `{deleted: true}` | 终态清理 |
| GET | `/api/sessions` | 会话列表(按用户) | `?user_id=` | `[{session_id, status, updated_at}]` | 只读 |
### 2.2 文件上传
| Method | Path | 说明 | 请求体 | 响应 | 触发状态转移 |
|--------|------|------|--------|------|-------------|
| POST | `/api/sessions/{id}/files` | 上传文件(multipart | `file` + `file_type`requirements/template/rules/existing_system | `{file_id, file_name, size}` | `uploading` 保持 |
| POST | `/api/sessions/{id}/start-parse` | 开始解析(全部文件上传完成后) | `{}` | `{task_id}`(解析异步执行) | `uploading → parsing` |
| GET | `/api/sessions/{id}/parse-result` | 获取解析结果 | — | `{structured_summary, sheets, template_sections}` | 只读 |
### 2.3 解析确认
| Method | Path | 说明 | 请求体 | 响应 | 触发状态转移 |
|--------|------|------|--------|------|-------------|
| POST | `/api/sessions/{id}/confirm-parse` | 确认解析结果 | `{sheet_fixes?, template_fixes?}` | `{ok: true}` | `awaiting_parse_confirm → impact_running` |
| POST | `/api/sessions/{id}/reparse` | 修正后重新解析 | `{sheet_overrides}` | `{task_id}` | `awaiting_parse_confirm → parsing` |
### 2.4 影响调查
| Method | Path | 说明 | 请求体 | 响应 | 触发状态转移 |
|--------|------|------|--------|------|-------------|
| POST | `/api/sessions/{id}/start-impact` | 启动影响调查 | `{}` | `{task_id}` | `impact_running` 保持 |
| GET | `/api/sessions/{id}/impact-result` | 获取影响调查结果 | — | ImpactReport JSON | 只读 |
| POST | `/api/sessions/{id}/impact-edits` | 逐条修正关联 | `{edits: [{type, id, action, data}]}` | `{ok: true, correction_history_id}` | `awaiting_impact_confirm` 保持 |
| POST | `/api/sessions/{id}/confirm-impact` | 确认影响调查 | `{}` | `{ok: true}` | `awaiting_impact_confirm → writing` |
| POST | `/api/sessions/{id}/reject-impact` | 打回(重推或回到解析) | `{target: "impact" \| "parse"}` | `{ok: true}` | `awaiting_impact_confirm → impact_running \| awaiting_parse_confirm` |
### 2.5 生成(Writer + QA
| Method | Path | 说明 | 请求体 | 响应 | 触发状态转移 |
|--------|------|------|--------|------|-------------|
| POST | `/api/sessions/{id}/generate` | 启动章节生成 | `{}` | `{task_ids: [逐章]}` | `writing` 保持 |
| GET | `/api/sessions/{id}/generation-status` | 各章生成进度 | — | `[{chapter_id, status, duration_ms}]` | 只读 |
| GET | `/api/sessions/{id}/chapters/{chapter_id}` | 获取单章内容块 | — | ContentBlock JSON | 只读 |
| POST | `/api/sessions/{id}/regenerate-chapter` | 单章重生成 | `{chapter_id, reason}` | `{task_id}` | `writing` 保持 |
| POST | `/api/sessions/{id}/run-qa` | 启动 QA 校验 | `{}` | `{task_id}` | `writing → qa` |
| GET | `/api/sessions/{id}/qa-result` | QA 校验结果 | — | QAReport JSON | 只读 |
| POST | `/api/sessions/{id}/writer-fix` | QA 发现问题后反馈 Writer 重生成 | `{issues: [...]}` | `{task_ids}` | `qa → writing` |
| POST | `/api/sessions/{id}/rollback-to-impact` | 回退到影响调查(writing 阶段用户要求调整关联/不确定处) | `{}` | `{ok: true}` | `writing → awaiting_impact_confirm` |
### 2.6 结果与下载
| Method | Path | 说明 | 请求体 | 响应 | 触发状态转移 |
|--------|------|------|--------|------|-------------|
| GET | `/api/sessions/{id}/result/preview` | HTML 预览 | — | `{html}` | 只读 |
| GET | `/api/sessions/{id}/result/download` | 下载 docx | — | `application/vnd.openxmlformats...`(文件流) | 只读 |
| GET | `/api/sessions/{id}/result/qa-report` | 下载 QA 报告 | — | `application/json` | 只读 |
| GET | `/api/sessions/{id}/result/impact-report` | 下载影响调查书 | — | `application/json` | 只读 |
### 2.7 规则管理
| Method | Path | 说明 | 请求体 | 响应 | 触发状态转移 |
|--------|------|------|--------|------|-------------|
| GET | `/api/rules/versions` | 规则手册版本列表 | — | `[{version_id, active, created_at, doc_count}]` | 只读 |
| POST | `/api/rules/update` | 触发规则手册重建 | `{files, categories}` | `{version_id \| "no_change"}` | 不涉及会话 |
| POST | `/api/rules/rollback` | 回退到指定版本 | `{version_id}` | `{ok: true}` | 不涉及会话 |
| GET | `/api/rules/conflicts` | 待决策的规则冲突 | `?session_id=` | `[{conflict_id, topic, chunks}]` | 只读 |
| POST | `/api/rules/conflicts/{id}/resolve` | 冲突决策 | `{session_id, decision}` | `{ok: true}` | 继续该章生成 |
### 2.8 设置与状态
| Method | Path | 说明 | 请求体 | 响应 |
|--------|------|------|--------|------|
| GET | `/api/settings` | 获取配置(脱敏) | — | `{models, vector_store, limits}` |
| GET | `/api/health` | 健康检查 | — | `{status: "ok", version}` |
| POST | `/api/sessions/{id}/cancel` | 取消当前任务 | `{task_id?}` | `{ok: true}` |
| GET | `/api/sessions/{id}/logs` | 获取会话事件日志 | `?event_type=` | `[{event_type, ...}]` |
---
## 3. WebSocket 事件通道
### 3.1 端点
```
WS /api/ws/sessions/{id}
```
### 3.2 事件类型(服务端 → 客户端)
| 事件 | 载荷 | 时机 |
|------|------|------|
| `status_change` | `{from, to, at}` | 状态机转移时 |
| `progress` | `{task_id, chapter_id?, percent?, detail}` | 任务进度更新 |
| `tool_call` | `{tool, args_summary, status, duration_ms}` | 工具调用(runtime §5.7|
| `llm_call` | `{model, prompt_version, status, duration_ms, input_tokens, output_tokens}` | LLM 调用(runtime §6.1|
| `conflict_pending` | `{conflict_id, topic, chapter_id}` | 规则冲突待用户决策 |
| `qa_completed` | `{summary: {pass, fail, warnings}}` | QA 完成 |
| `error` | `{code, message, options: ["retry","skip","abort"]}` | 任务失败(异常 UX|
| `done` | `{download_url}` | 全部完成 |
### 3.3 客户端 → 服务端
| 事件 | 载荷 | 说明 |
|------|------|------|
| `ping` | — | 心跳(保持连接)|
| `request_status` | — | 请求当前完整状态(断线重连时同步)|
---
## 4. 编排调用链
### 4.1 正常流程时序
```
客户端 Orchestrator Agent / 基础设施
│ POST /sessions │ │
│──────────────────────►│ 创建会话 → uploading │
│ POST /files │ │
│──────────────────────►│ │
│ POST /start-parse │ │
│──────────────────────►│ 投递解析任务 ────────────────►│ Parser
│◄───WS progress────────│ │
│◄───WS status_change───│ parsing → awaiting_parse_confirm
│ POST /confirm-parse │ │
│──────────────────────►│ → impact_running │
│ POST /start-impact │ 投递影响调查 ────────────────►│ Impact
│◄───WS status_change───│ → awaiting_impact_confirm │
│ POST /confirm-impact │ │
│──────────────────────►│ → writing │
│ POST /generate │ 投递逐章任务 ────────────────►│ Writer
│◄───WS progress(章)────│ │
│ POST /run-qa │ 投递 QA 任务 ────────────────►│ QA
│◄───WS qa_completed────│ → done(或 qa → writing 反馈)│
│ GET /result/download │ │
│──────────────────────►│ 返回 docx 文件流 │
```
### 4.2 Orchestrator 职责边界
- **不做**业务逻辑(解析/推理/生成/校验在各 Agent)
- **做**:状态机推进、任务调度、事件收集与推送、异常路由(重试/跳过/中断)、规则版本锁定、会话持久化
### 4.3 进程内调用 vs 队列
```
默认(InMemoryQueue:
Orchestrator 进程内 asyncio 任务池消费队列
状态与任务结果共享内存(FastAPI 进程内)
切换(RedisQueue/ValkeyQueue:
Orchestrator 投递 → Redis/Valkey Stream
worker 进程消费 → 执行 → 状态写回 SQLite / 事件回传
需额外部署 worker 容器(见 §6)
```
---
## 5. 任务队列抽象
### 5.1 接口定义
```python
class TaskQueue(ABC):
"""统一任务队列抽象(内存 / Redis / Valkey 实现)"""
@abstractmethod
def enqueue(self, task: TaskSpec) -> TaskHandle: ...
# TaskSpec = {task_id, session_id, step, chapter_id?, payload, idempotency_key}
@abstractmethod
def poll(self, session_id: str) -> list[TaskHandle]: ...
@abstractmethod
def update_status(self, handle: TaskHandle, status: str, result: Any = None) -> None: ...
# status: pending | running | completed | failed
@abstractmethod
def get(self, task_id: str) -> TaskHandle | None: ...
@abstractmethod
def cancel(self, task_id: str) -> bool: ...
@abstractmethod
def close(self) -> None: ...
```
### 5.2 实现类
| 实现 | 依赖 | 使用场景 | 说明 |
|------|------|---------|------|
| `InMemoryQueue` | 无 | 开发 / 测试 / 演示(默认)| asyncio 任务池,进程内状态 |
| `RedisQueue` | redis-py | 生产部署 | Redis StreamsRSALv2,内部使用合法)|
| `ValkeyQueue` | redis-py(兼容)| 生产部署(零许可风险)| Valkey 兼容 Redis 协议,代码同 RedisQueue |
### 5.3 幂等去重
- 任务幂等键:`(session_id, step, chapter_id)`runtime §7.3
- 重复 enqueue 同一幂等键 → 已完成直接返回缓存结果;进行中则返回原 handle
- `InMemoryQueue``RedisQueue` 行为一致(单测以 MockAdapter 风格覆盖双实现)
---
## 6. 部署拓扑
### 6.1 默认(单容器,InMemoryQueue
```
docker-compose.yml(最小):
services:
api:
build: .
ports: ["8000:8000"]
env_file: .env
volumes:
- ./data:/data # 用户数据 + 规则手册
- ./config:/config # inference.yaml / rag.yaml
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
```
### 6.2 生产(Redis/Valkey 可选)
```
docker-compose.yml(扩展):
services:
api: # FastAPI 编排 + REST/WS
...
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
worker: # 任务消费(仅切换队列时启用)
build: .
command: python -m app.worker
depends_on: [queue]
queue: # Redis 或 Valkey 二选一
image: valkey/valkey:8 # 零许可风险(或 redis:7,内部使用合法)
volumes: ["queue_data:/data"]
```
### 6.3 目录结构
```
/data/
├── users/{user_id}/ # 用户隔离(web-ui-design §4.3
│ ├── uploads/
│ └── outputs/
├── shared/
│ ├── rules-handbook/ # 规则手册(RAG 层)
│ │ ├── chroma/ # Chroma 持久化
│ │ ├── manifest.json
│ │ └── v1/ v2/ ... # 版本目录
│ └── templates/ # 公共模板
└── db/ # SQLitesessions/events/snapshots
```
---
## 7. 错误码约定
| 错误码 | HTTP | 含义 | 用户选项 |
|--------|------|------|---------|
| `FILE_TYPE_INVALID` | 400 | 文件类型不支持 | 更换文件 |
| `FILE_TOO_LARGE` | 400 | 超过 100MB 限制 | 压缩/分割 |
| `STATE_TRANSITION_INVALID` | 409 | 非法状态转移(如 uploading 直接 generate| 提示正确流程 |
| `LLM_TIMEOUT` | 502 | LLM 调用超时 | retry / skip / abort |
| `LLM_PARSE_ERROR` | 502 | 结构化输出解析失败 | retry |
| `EMBEDDING_FAILED` | 503 | Embedding 服务故障(降级为 BM25)| 继续(降级提示)|
| `RULES_HANDBOOK_MISSING` | 404 | 规则手册不存在 | 上传规则文档 |
| `CHAPTER_NOT_FOUND` | 404 | 章节不存在 | — |
| `CONFLICT_PENDING` | 409 | 规则冲突待用户决策 | 决策后继续 |
| `INTERNAL_ERROR` | 500 | 未知错误 | 重试/联系支持 |
---
## 8. 与各文档的关系
| 文档 | 关系 |
|------|------|
| `docs/design.md` §8 | Web UI 页面设计;本文档为后端 API 的接口级展开 |
| `docs/agent-runtime-design.md` §3 | 状态机与任务队列抽象;本文档定义 REST/WS 入口 |
| `docs/web-ui-design.md` | 前端各页面调用本文档的端点 |
| `docs/config-design.md` | 部署配置(env / yaml / docker-compose |