Files
dreamweaver/docs/technical/harness-engineering-modernization.md
2026-06-21 22:31:38 +08:00

494 lines
18 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.
# Harness Engineering 架构改造技术设计
**项目**: DreamWeaver 梦语织机
**版本**: 0.1
**日期**: 2026-06-21
**状态**: 阶段 0 已建立设计基线
**作者**: Codex
---
## 1. 背景
DreamWeaver 当前已经完成统一生成工作流的第一轮落地:`POST /api/generations` 会创建 `generation_jobs`,后台 worker 执行故事或绘本生成,`generation_job_events` 记录关键过程,前端通过 job 查询和故事状态展示进度、失败与重试入口。
现有架构已经具备 harness engineering 的雏形:
- `story_service` 负责上下文准备、主内容生成、故事落库、资产补全、状态同步和任务收敛。
- `generation_jobs` 负责 job/event、进度摘要、取消、重试和 Provider 聚合。
- `provider_router` 负责 Provider 选择、failover、熔断、成本和调用事件。
- `story_status` 负责把文本、图片、音频状态推导为统一故事状态。
当前主要问题不是缺少能力,而是生成运行时控制逻辑分散在多个 service 内。取消检查、事件记录、资产恢复、Provider 轨迹、失败分类和质量校验还没有形成显式的运行时边界。
本设计的目标,是把现有“隐性 harness”升级为可观测、可恢复、可验证、可演进的 Generation Harness Runtime同时保留当前 API、数据库和前端主行为。
## 2. 目标
### 2.1 产品目标
- 家长提交故事或绘本生成后,能获得稳定、可解释、可恢复的结果。
- 主内容生成成功后,即使图片或音频失败,也不影响阅读。
- 用户能清楚看到任务步骤、失败原因和可重试资产。
- 后续新增语音共创、更多内容模式或新资产类型时,复用同一套运行时模型。
### 2.2 工程目标
-`story_service` 中的运行时控制职责抽到 harness 层。
- 让 workflow step、artifact、trace、failure category 成为一等概念。
- 保持 `/api/generations`、旧兼容接口、现有状态字段和主要测试行为不破坏。
- 优先做渐进式重构,不引入复杂工作流引擎,不进行大爆炸重写。
- 每个大阶段都产出阶段报告,包含实现、审查、验证和风险。
### 2.3 非目标
- 本轮不引入 Temporal、Dagster、LangGraph 等外部工作流引擎。
- 本轮不彻底重做数据库结构。
- 本轮不废弃旧生成接口,只继续保持兼容层指向统一入口。
- 本轮不把 DreamWeaver 抽象成通用 agent 平台,所有抽象必须服务儿童故事生成业务。
- 本轮不要求一次性完成所有 eval、质量门和 replay 能力。
## 3. 架构原则
1. **主内容优先可读**
文本故事或绘本结构是 blocking artifact封面、分页插图、音频是 recoverable artifact。
2. **API 稳定优先**
先重构内部边界再考虑扩展响应字段。现有前端、smoke、测试不应被第一阶段打断。
3. **事件结构稳定**
继续复用 `generation_job_events`,但逐步标准化 metadata避免每个调用点随手定义不同结构。
4. **Provider 不等于产品能力**
Provider 只是 tool invocation 的实现。产品能力应由 capability、workflow step、artifact 和 recovery policy 共同定义。
5. **小步可验证**
每个最小任务都必须能通过单测、局部测试或文档审查验证。
## 4. 目标架构
```mermaid
flowchart TB
API["FastAPI API 层"] --> COMMAND["Generation Command"]
COMMAND --> HARNESS["Generation Harness Runtime"]
HARNESS --> CTX["Context Builder<br/>档案 / 宇宙 / 记忆 / 输入规范化"]
HARNESS --> PLAN["Workflow Plan<br/>story / storybook / asset_generation / asset_retry"]
HARNESS --> CONTROL["Execution Control<br/>取消 / 超时收敛 / 安全检查点"]
HARNESS --> TRACE["Trace Recorder<br/>job events / step metadata / provider trace"]
HARNESS --> ARTIFACT["Artifact Workflows<br/>story_text / storybook_pages / image / audio"]
HARNESS --> GUARD["Quality Gates<br/>schema / 儿童安全 / 内容完整性"]
ARTIFACT --> ROUTER["Provider Router<br/>策略 / failover / 熔断 / 成本"]
ROUTER --> ADAPTERS["Provider Adapters"]
HARNESS --> STATE["State Store<br/>stories / generation_jobs / generation_job_events"]
STATE --> FE["Vue 前端进度 / 详情 / 重试"]
```
## 5. 运行时核心概念
### 5.1 Generation Command
表示一次用户意图,来源包括:
- `POST /api/generations`
- `POST /api/generations/{story_id}/retry-assets`
- `POST /api/generations/jobs/{job_id}/retry`
- 旧兼容接口产生的同步生成调用
标准字段:
| 字段 | 说明 |
| --- | --- |
| `output_mode` | `story``storybook``asset_generation``asset_retry` |
| `input_type` | `keywords``full_story``image``audio` 或资产组合 |
| `user_id` | 当前用户 |
| `story_id` | 已有故事 ID可为空 |
| `request_payload` | 原始请求的 JSON 安全快照 |
### 5.2 Workflow Step
第一阶段先将现有 event type 映射为标准 step不立即改库
| Step | 当前事件 | 是否阻塞主内容 |
| --- | --- | --- |
| `request_acceptance` | `request_accepted``retry_queued` | 是 |
| `worker_start` | `worker_started` | 是 |
| `context_preparation` | `context_prepared` | 是 |
| `narrative_generation` | `narrative_generated` | 是 |
| `story_persistence` | `story_saved` | 是 |
| `image_generation` | `cover_image_*``storybook_*image*` | 否 |
| `audio_generation` | `audio_*` | 否 |
| `postprocessing` | `postprocessing_queued` | 否 |
| `completion` | `generation_completed``asset_*_completed` | 是 |
| `cancellation` | `cancel_requested``generation_canceled` | 是 |
| `stale_recovery` | `generation_stale_failed` | 是 |
### 5.3 Artifact
| Artifact | 来源 | 状态字段 | 恢复策略 |
| --- | --- | --- | --- |
| `story_text` | text provider | `text_status` | 失败则 job failed |
| `storybook_pages` | storybook provider | `text_status` | 失败则 job failed |
| `cover_image` | image provider | `image_status` | 失败后 `degraded_completed`,可重试 |
| `page_image` | image provider | `image_status` | 部分页失败后 `degraded_completed`,可重试 |
| `audio` | tts provider + file cache | `audio_status` | 失败后 `degraded_completed`,可重试 |
| `achievement_memory` | Celery 后处理 | 事件记录 | 失败不影响主内容 |
### 5.4 Failure Category
第一阶段先在代码中定义枚举和 metadata 规范;后续逐步写入事件:
| Category | 说明 |
| --- | --- |
| `provider_error` | 外部 Provider 返回失败或不可用 |
| `schema_error` | Provider 输出无法解析或字段不完整 |
| `safety_error` | 儿童安全或内容安全校验失败 |
| `timeout` | 调用超时或 job 超时 |
| `canceled` | 用户取消 |
| `stale_job` | 后台任务卡住后被系统收敛 |
| `storage_error` | 数据库、文件缓存或持久化失败 |
| `validation_error` | 用户输入、档案或宇宙校验失败 |
| `unknown_error` | 未归类错误 |
### 5.5 Trace Metadata
标准 event metadata 应逐步包含:
```json
{
"step": "narrative_generation",
"artifact": "story_text",
"capability": "text",
"adapter": "demo",
"provider_id": null,
"strategy": "priority",
"latency_ms": 42,
"estimated_cost_usd": 0.01,
"failure_category": null,
"error": null,
"retryable": false,
"blocks_main_result": true
}
```
短期兼容要求:
- 不删除现有 metadata 字段。
- 新增字段必须向后兼容。
- 前端仍可使用当前 `event_type``status``message``event_metadata`
## 6. 模块设计
### 6.1 `app/services/harness/types.py`
新增纯类型模块,不依赖数据库。
职责:
- 定义 `WorkflowStep`
- 定义 `ArtifactKind`
- 定义 `FailureCategory`
- 定义 `StepStatus`
- 定义 `TraceMetadata`
- 定义从旧 event type 到标准 step 的映射函数
验收:
- 单测覆盖 event type 到 step 的映射。
- 未知 event type 映射到 `unknown` 或保守默认,不抛出非预期异常。
### 6.2 `app/services/harness/trace.py`
封装 job event 写入。
职责:
- 提供 `TraceRecorder.record_step(...)`
- 提供 `TraceRecorder.record_provider_call(...)`
- 统一补齐 `step``artifact``failure_category``retryable``blocks_main_result`
- 内部继续调用现有 `record_generation_event`
验收:
- 现有 `generation_job_events` 行为保持。
- 新事件 metadata 含标准字段。
- job 为空时安全跳过,兼容旧同步接口。
### 6.3 `app/services/harness/control.py`
封装执行控制。
职责:
- 提供 `ExecutionControl.stop_if_cancel_requested(...)`
- 保留现有取消语义和 `GenerationJobCanceledError`
- 后续可扩展 step timeout、checkpoint、stale recovery
验收:
- 取消中的 job 仍被标记为 `canceled`
- 现有取消测试继续通过。
### 6.4 `app/services/harness/artifacts.py`
第二阶段再拆。第一阶段先保留 `story_service` 中的资产函数,只把共享结果类型移动或桥接。
职责:
- 表达 `AssetCompletionResult`
- 后续承载封面、绘本插图、音频工作流
验收:
- 资产重试行为不变。
- `retryable_assets` 行为不变。
### 6.5 `story_service` 改造方式
第一阶段仅做低风险替换:
- `_record_job_event_if_present` 代理到 `TraceRecorder`
- `_stop_if_job_cancel_requested` 代理到 `ExecutionControl`
- `AssetCompletionResult` 可先留在原文件,第二阶段再移动
- 不重写 `generate_generation_service``run_generation_job_service` 主流程
第二阶段再拆分:
- `story_generation_workflow.py`
- `storybook_generation_workflow.py`
- `asset_generation_workflow.py`
- `asset_retry_workflow.py`
## 7. 阶段计划
### 阶段 0: 设计与基线
目标:
- 产出本技术设计。
- 产出阶段 0 报告。
- 明确阶段拆解、验收标准和验证方式。
最小任务:
| ID | 任务 | 验收 |
| --- | --- | --- |
| H0-1 | 梳理现有统一生成 PRD、架构文档和测试 | 文档引用现有边界,不重复设计入口 |
| H0-2 | 定义目标 runtime 架构 | 技术设计包含模块、数据、阶段计划 |
| H0-3 | 拆分最小可执行任务 | 每个阶段有任务 ID 和验收标准 |
| H0-4 | 建立阶段报告机制 | `docs/planning/` 下有阶段报告 |
### 阶段 1: Harness 基础类型与事件封装
目标:
- 新增 harness 包。
- 标准化 workflow step、artifact、failure category。
-`TraceRecorder` 封装事件写入。
-`ExecutionControl` 封装取消检查。
最小任务:
| ID | 任务 | 验收 |
| --- | --- | --- |
| H1-1 | 新增 `app/services/harness/__init__.py` | 后端 import 正常 |
| H1-2 | 新增 `types.py` 枚举和映射 | 单测覆盖核心 event type |
| H1-3 | 新增 `trace.py` | record 后 metadata 含 `step` |
| H1-4 | 新增 `control.py` | 取消行为与旧逻辑一致 |
| H1-5 | 替换 `story_service` 中事件和取消 helper 的内部实现 | 现有 API 行为不变 |
| H1-6 | 补 `tests/test_harness_runtime.py` | 后端测试通过 |
验证命令:
```bash
cd backend
pytest tests/test_harness_runtime.py tests/test_generation_jobs.py
ruff check app tests
```
阶段报告:
- `docs/planning/harness-stage-1-report.md`
### 阶段 2: 资产工作流边界抽取
目标:
- 将封面、绘本插图、音频补全从 `story_service` 中拆成 artifact workflow。
- 保持当前 `StoryAssetStatus``sync_story_status` 语义。
最小任务:
| ID | 任务 | 验收 |
| --- | --- | --- |
| H2-1 | 移动或桥接 `AssetCompletionResult` | import 稳定 |
| H2-2 | 抽普通故事封面工作流 | 封面生成、失败、重试测试通过 |
| H2-3 | 抽绘本图片工作流 | 绘本逐页事件顺序不破坏 |
| H2-4 | 抽音频工作流 | 音频缓存和失败状态测试通过 |
| H2-5 | 补 artifact workflow 单测 | 资产相关测试通过 |
验证命令:
```bash
cd backend
pytest tests/test_stories.py tests/test_generation_jobs.py tests/test_audio_cache.py
ruff check app tests
```
阶段报告:
- `docs/planning/harness-stage-2-report.md`
### 阶段 3: Workflow Plan 与执行器
目标:
- 用显式 `WorkflowPlan` 表达 story、storybook、asset_generation、asset_retry。
-`_generate_generation_service_with_job` 的分支压缩到计划构建和执行器。
最小任务:
| ID | 任务 | 验收 |
| --- | --- | --- |
| H3-1 | 定义 `WorkflowPlan``WorkflowTask` | 不依赖 FastAPI schema |
| H3-2 | 为普通故事构建 plan | 不生成图片时步骤正确 |
| H3-3 | 为完整故事构建 plan | 图片为 recoverable step |
| H3-4 | 为绘本构建 plan | 绘本结构和图片步骤可区分 |
| H3-5 | 为资产任务构建 plan | 重试和后台生成共用计划 |
| H3-6 | 增加 plan 单测 | 核心模式计划快照稳定 |
验证命令:
```bash
cd backend
pytest tests/test_harness_runtime.py tests/test_generation_jobs.py tests/test_stories.py
ruff check app tests
```
阶段报告:
- `docs/planning/harness-stage-3-report.md`
### 阶段 4: Quality Gates 与输出验证
目标:
- 在 Provider 输出进入持久化之前,加入低成本、确定性的质量门。
- 后续可扩展模型评审,但第一轮避免额外 AI 成本。
最小任务:
| ID | 任务 | 验收 |
| --- | --- | --- |
| H4-1 | 定义 quality gate 接口 | 不绑定具体 Provider |
| H4-2 | 文本故事完整性检查 | 标题、正文、封面 prompt 缺失可识别 |
| H4-3 | 绘本结构检查 | 页数、页码、正文、图片 prompt 可识别 |
| H4-4 | 儿童内容基础安全检查 | 明显不适龄词或空内容阻断 |
| H4-5 | gate 失败写入 `failure_category` | job event 可解释 |
验证命令:
```bash
cd backend
pytest tests/test_harness_runtime.py tests/test_generation_jobs.py tests/test_stories.py
ruff check app tests
```
阶段报告:
- `docs/planning/harness-stage-4-report.md`
### 阶段 5: Trace Analytics 与前端增量展示
目标:
- 前端继续消费现有 job/event但可展示标准 step、artifact、failure category。
- 管理端可按 failure category 聚合失败原因。
最小任务:
| ID | 任务 | 验收 |
| --- | --- | --- |
| H5-1 | 后端聚合支持标准 step/failure category | 旧字段兼容 |
| H5-2 | 用户端生成轨迹展示 step 名称 | 移动端不溢出 |
| H5-3 | 管理端 Provider dashboard 增加 failure category | 构建通过 |
| H5-4 | 更新 smoke 脚本校验标准 metadata | demo smoke 通过 |
验证命令:
```bash
cd backend
pytest
ruff check app tests
cd ../frontend
npm run build
cd ../admin-frontend
npm run build
```
阶段报告:
- `docs/planning/harness-stage-5-report.md`
## 8. 需求与验收
### 功能需求
| ID | 优先级 | 需求 | 验收标准 |
| --- | --- | --- | --- |
| FR-001 | MUST | 系统必须保留统一生成 API 行为 | `/api/generations` 测试继续通过 |
| FR-002 | MUST | 系统必须有标准 workflow step 类型 | 核心 event type 可映射到 step |
| FR-003 | MUST | 系统必须有标准 artifact 类型 | story、storybook、image、audio 可区分 |
| FR-004 | MUST | 系统必须标准化 job event metadata | 新事件含 `step`,旧字段不删除 |
| FR-005 | MUST | 用户取消语义必须保持 | 取消测试继续通过 |
| FR-006 | SHOULD | Provider 调用应记录标准 trace 字段 | provider event 含 capability、adapter、latency、cost、step |
| FR-007 | SHOULD | 资产工作流应从主 service 拆出 | `story_service` 行数和职责减少 |
| FR-008 | SHOULD | 输出验证应在持久化前执行 | schema 缺失可被测试捕获 |
| FR-009 | COULD | 前端展示标准 step/failure category | 构建通过且无布局溢出 |
### 非功能需求
| ID | 优先级 | 需求 | 验收标准 |
| --- | --- | --- | --- |
| NFR-001 | MUST | 向后兼容 | 现有测试和 smoke 主链路不破坏 |
| NFR-002 | MUST | 可测试 | 每个新增 harness 模块有单测 |
| NFR-003 | MUST | 可观测 | job/event 可以解释 step、artifact、失败原因 |
| NFR-004 | SHOULD | 低耦合 | harness 类型模块不依赖 FastAPI 和 SQLAlchemy |
| NFR-005 | SHOULD | 性能稳定 | 不新增阻塞式外部调用 |
| NFR-006 | SHOULD | 中文一致性 | 文档、用户可见文案和新增注释使用简体中文 |
## 9. 风险与缓解
| 风险 | 影响 | 缓解 |
| --- | --- | --- |
| 过度抽象导致改造变慢 | 中 | 第一阶段只抽类型、trace、control不拆主流程 |
| 事件 metadata 变化影响前端 | 中 | 只新增字段,不删除旧字段 |
| 取消/重试语义被破坏 | 高 | 优先跑 `tests/test_generation_jobs.py` |
| Provider trace 与 job event 重复 | 低 | 保持 Provider 事件专注调用层workflow 事件专注产品步骤 |
| 文档与实现偏离 | 中 | 每个阶段报告必须记录实现偏差 |
| 质量门误伤内容 | 中 | 第四阶段先做确定性低风险检查,模型评审延后 |
## 10. 审查清单
每个阶段完成前必须检查:
- [ ] 是否保持 `/api/generations` 行为兼容
- [ ] 是否有对应测试或验证命令
- [ ] 是否没有引入不必要的外部框架
- [ ] 是否没有重写无关功能
- [ ] 是否保留用户已有工作区改动
- [ ] 是否更新阶段报告
- [ ] 是否更新本设计中的阶段状态或偏差记录
## 11. 当前状态
| 阶段 | 状态 | 备注 |
| --- | --- | --- |
| 阶段 0 | 已完成设计基线 | 已建立本设计与阶段 0 报告 |
| 阶段 1 | 已完成基础实现 | 已新增 harness 类型、trace recorder、execution control并通过定向测试 |
| 阶段 2 | 已完成主要资产补全抽取 | 封面、音频、持久化绘本缺失图片补全已迁入 harness asset workflows |
| 阶段 3 | 已完成计划建模基线 | 已定义 WorkflowPlan/WorkflowTask 和核心模式计划快照;执行器接管留待后续 |
| 阶段 4 | 已完成确定性质量门 | 已接入文本故事和绘本结构完整性/儿童安全基础检查 |
| 阶段 5 | 待执行 | Trace Analytics 与前端展示 |