ForcePilot/docs/changelog/run-architecture-migration-v4.md
Wenjie Zhang 62bb928064 refactor: 更新文档部署说明
- 移除对于双版本文档的支持,更加清晰
- 将 docs 的入口从根目录移动到子目录
2026-03-24 11:09:46 +08:00

186 lines
5.4 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.

# Run 流式架构改造说明
## 1. 改造目标
本次改造将对话输出从 **HTTP 直连流** 升级为 **异步任务执行 + SSE 增量拉取**,目标是:
1. 页面离开/刷新不影响后台执行。
2. 前端支持断线重连与续流。
3. 提升系统稳定性、并发能力与可观测性。
4. 控制存储成本:过程数据短期保存,结果数据长期保存。
---
## 2. 改造前后对比(仅与 HTTP 直连流对比)
| 维度 | 改造前HTTP 直连流) | 改造后Run + SSE |
|---|---|---|
| 触发方式 | `POST /agent/{id}` 后长连接直接流式输出 | `POST /runs` 创建任务worker 异步执行 |
| 任务生命周期 | 绑定前端连接 | 与前端连接解耦 |
| 页面离开/刷新 | 常导致任务中断或前端丢上下文 | 任务继续执行,前端可续流 |
| 前端消费方式 | 同一个请求内读取 chunk | `GET /runs/{id}/events?after_seq=...` 增量拉取 |
| 恢复能力 | 弱,重连后难恢复 | 强,依赖 seq 游标恢复 |
| 取消语义 | 中断连接即可能影响任务 | 仅显式 `cancel` 才取消任务 |
---
## 3. 架构方案
### 3.1 组件职责
1. **FastAPI**:负责创建 run、查询 run、SSE 输出、cancel 接口。
2. **ARQ Worker**:负责真正执行模型流式任务。
3. **Redis**
- ARQ 队列
- run 过程事件流Redis Stream
- 取消信号key + pub/sub
4. **Postgres**
- run 执行状态(`agent_runs`
- 最终业务消息(`messages/tool_calls`
- checkpointer会话运行状态
### 3.2 架构图
```mermaid
flowchart LR
FE["Frontend"] -->|"POST /runs"| API["FastAPI"]
API -->|"create run"| PG[("Postgres")]
API -->|"enqueue"| R[("Redis")]
W["ARQ Worker"] -->|"dequeue"| R
W -->|"update run status"| PG
W -->|"write stream events"| R
FE -->|"GET /runs/:id/events?after_seq=..."| API
API -->|"read incremental events"| R
API -->|"SSE events"| FE
FE -->|"POST /runs/:id/cancel"| API
API -->|"cancel mark"| PG
API -->|"publish cancel"| R
W -->|"persist messages/tool_calls"| PG
```
---
## 4. 端到端流程(事件流转)
```mermaid
sequenceDiagram
participant FE as Frontend
participant API as FastAPI
participant R as Redis
participant W as ARQ Worker
participant PG as Postgres
FE->>API: POST /api/chat/agent/{agent_id}/runs
API->>PG: create agent_runs(status=pending)
API->>R: enqueue process_agent_run(run_id)
API-->>FE: run_id
FE->>API: GET /api/chat/runs/{run_id}/events?after_seq=0
W->>R: dequeue run job
W->>PG: mark running
W->>R: append loading/tool/state events (stream)
API->>R: read events after_seq
API-->>FE: SSE incremental events
FE->>API: POST /api/chat/runs/{run_id}/cancel (optional)
API->>PG: mark cancel_requested
API->>R: publish cancel signal
W->>W: cancel current task
W->>PG: mark terminal status
W->>PG: persist messages/tool_calls
API-->>FE: close event
```
---
## 5. 接口与协议变更
### 5.1 对外路径(保持稳定)
1. `POST /api/chat/agent/{agent_id}/runs`
2. `GET /api/chat/runs/{run_id}`
3. `GET /api/chat/runs/{run_id}/events?after_seq=...`
4. `POST /api/chat/runs/{run_id}/cancel`
### 5.2 `after_seq` 语义
1. 主格式为字符串游标Redis Stream ID`1700000000000-3`)。
2. 兼容旧整数参数输入。
3. SSE 返回 `seq` 字段统一为字符串,前端按单调递增去重。
### 5.3 SSE 事件格式
```json
{
"run_id": "...",
"seq": "1700000000000-3",
"event_type": "loading",
"payload": {"items": [...]},
"ts": 1700000000000
}
```
控制事件:`heartbeat` / `error` / `close`
---
## 6. 前端行为变化
1. 本地记录活跃 run 快照:`active_run:{threadId}`。
2. 刷新/切回页面时按 `run_id + last_seq` 自动续流。
3. 接收事件先做 seq 去重,再更新 UI。
4. 保留打字机效果(`requestAnimationFrame + throttle`)。
5. 保留首条消息自动更新会话标题逻辑。
---
## 7. 稳定性设计
1. 幂等:`request_id` 避免重复创建 run。
2. 重试:仅可恢复错误触发 ARQ 重试(`max_tries=2`)。
3. 取消DB 状态 + Redis 信号双通道。
4. SSE 生命周期:心跳、超时、终态关闭、断线重连。
5. 状态单一真相:执行态在 `agent_runs`,业务态在 `messages/tool_calls + checkpointer`
---
## 8. 本次代码变更范围(未提交部分)
### 后端
1. `/Yuxi-Know/backend/package/yuxi/services/run_queue_service.py`
2. `/Yuxi-Know/backend/package/yuxi/services/run_worker.py`
3. `/Yuxi-Know/backend/package/yuxi/services/agent_run_service.py`
4. `/Yuxi-Know/backend/package/yuxi/repositories/agent_run_repository.py`
5. `/Yuxi-Know/server/routers/chat_router.py`
6. `/Yuxi-Know/server/worker_main.py`
7. `/Yuxi-Know/backend/package/yuxi/storage/postgres/manager.py`
8. `/Yuxi-Know/backend/package/yuxi/storage/postgres/models_business.py`
### 前端
1. `/Yuxi-Know/web/src/apis/agent_api.js`
2. `/Yuxi-Know/web/src/components/AgentChatComponent.vue`
### 测试
1. `/Yuxi-Know/test/test_run_queue_service.py`
2. `/Yuxi-Know/test/test_agent_run_service.py`
3. `/Yuxi-Know/test/test_run_worker.py`
### 配置
1. `/Yuxi-Know/docker-compose.yml`
2. `/Yuxi-Know/docker-compose.prod.yml`
3. `/Yuxi-Know/.env.template`
---
## 9. 验收标准
1. 发送消息后SSE 能持续收到增量事件。
2. 页面刷新后,可按 `after_seq` 恢复输出。
3. 页面离开不影响后台执行。
4. 取消后 run 状态正确收敛,输出停止。
5. 最终消息与工具调用正常入库。