# API 与编排接口设计 > 版本: v1.0 | 日期: 2026-07-30 | 状态: 初版 > > 本文档定义 **Web 后端(FastAPI Orchestrator)的 REST API 端点、WebSocket 事件通道、编排调用链与部署拓扑**。是 `docs/design.md` §8(Web 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 为 v2 预留,见 §5) └── RagService 调用(规则检索) ``` **架构决策**(与用户确认): - **编排形态**:抽象 `TaskQueue` 接口 + **单一 `InMemoryQueue` 实现**(开发/测试/演示零依赖)。(T5 架构审查整改:Scope 缩减裁定移除 Redis/Valkey 双实现;接口保留供 v2 扩展。) - 所有 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`/`write_instruction`/`rules`/`existing_system`) | `{file_id, file_name, size}` | `uploading` 保持 | > `file_type` 取值说明(v1.1 修订,随 web-ui-design §3.1 补齐大赛输入资料): > - `requirements` — 要件定义 Excel(核心数据源) > - `template` — 概要设计模板 docx(输出结构/样式) > - `write_instruction` — 概要设计做成说明书 docx(各章作成指引;RAG 归类 Type A 写入规则,Parser 解析) > - `rules` — 记入规则 / 图表规则等规则文档(可多个) > - `existing_system` — 现系统源码或既有设计书(追加/改修场景) | 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 进程内) (v2 预留)RedisQueue/ValkeyQueue: Orchestrator 投递 → Redis/Valkey Stream worker 进程消费 → 执行 → 状态写回 SQLite / 事件回传 需额外部署 worker 容器(见 §6)—— v1 不实现(Scope 缩减裁定) ``` --- ## 5. 任务队列抽象 ### 5.1 接口定义 ```python class TaskQueue(ABC): """统一任务队列抽象(v1 仅 InMemory 实现;Redis/Valkey 为 v2 预留,Scope 缩减裁定)""" @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` / `ValkeyQueue` | redis-py | **v2 预留**(不实现)| Scope 缩减裁定移除双实现;接口保留供 v2 扩展 | ### 5.3 幂等去重 - 任务幂等键:`(session_id, step, chapter_id)`(runtime §7.3) - 重复 enqueue 同一幂等键 → 已完成直接返回缓存结果;进行中则返回原 handle - v1 仅 `InMemoryQueue` 实现(单测覆盖) --- ## 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 生产(v1 单容器;Redis/Valkey worker 为 v2 预留) ``` docker-compose.yml(扩展): services: api: # FastAPI 编排 + REST/WS ... command: uvicorn app.main:app --host 0.0.0.0 --port 8000 # worker / queue: v2 预留(Scope 缩减裁定移除 Redis/Valkey 双实现,v1 不启用) ``` ### 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/ # SQLite(sessions/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 | exceptions.LLMTimeoutError | | `LLM_NETWORK_ERROR` | 502 | 网络失败/5xx 重试耗尽 | retry / skip / abort | exceptions.LLMNetworkError | | `LLM_NOT_CONFIGURED` | 503 | LLM Key 未配置 | 配置 Key | exceptions.LLMNotConfiguredError | | `LLM_PARSE_ERROR` | 502 | 结构化输出解析失败 | retry | exceptions.LLMResponseError | | `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) |