feat: add generation trace and partial-ready workflow status

This commit is contained in:
2026-04-18 21:53:55 +08:00
parent 96dfc677e2
commit e99a7fbe14
36 changed files with 2597 additions and 144 deletions

View File

@@ -39,7 +39,7 @@
旧生成 API 兼容层策略。用于说明历史接口如何迁移到统一 generation 入口。
- `technical/generation-job-state.md`
Generation Job 状态落库决策。用于说明当前为什么先复用 story 状态,何时再拆 job/event 表
Generation Job 状态落库决策。用于说明 job/event 如何追踪 workflow、资产补全、provider 调用和查询入口
- `technical/provider-routing.md`
Provider Routing 技术说明。用于解释 Capability / Provider / Adapter / Routing Policy 的职责边界。

View File

@@ -52,9 +52,15 @@ SMOKE_AUDIO=1 ./scripts/demo_smoke.sh
- [ ] admin-backend health 返回 `ok`
- [ ] dev login 能拿到 session
- [ ] `/api/generations` 能生成普通故事
- [ ] 普通故事生成响应返回 `generation_job_id`,且 job 事件可查询
- [ ] 普通故事 provider stats 返回成功率、耗时和成本字段
- [ ] 普通故事封面 retry 后 `image_status=ready`
- [ ] 故事详情页能看到生成轨迹和 Provider 调用结果
- [ ] `/api/generations` 能生成绘本
- [ ] 绘本生成响应返回 `generation_job_id`,且 story job history 可查询
- [ ] 绘本 provider stats 返回成功率、耗时和成本字段
- [ ] 绘本图片 retry 后 `image_status=ready`
- [ ] 绘本阅读页能看到生成轨迹和资源重试历史
- [ ] `/admin/providers/capabilities` 返回 `text/image/tts/storybook`
- [ ] 如果启用 `SMOKE_AUDIO=1`,音频 retry 后 `audio_status=ready`
- [ ] 验证结果已记录到 `docs/planning/demo-validation-log.md`
@@ -117,7 +123,7 @@ DreamWeaver 是面向 3-8 岁亲子场景的个性化 AI 绘本与陪伴式讲
### 2:20 - 3:00 取舍与下一步
求职版优先稳定闭环和可解释性,不做支付、多租户和复杂监控。下一步会继续打磨前端状态体验、旧 API 兼容策略和 generation job 是否落库
求职版优先稳定闭环和可解释性,不做支付、多租户和复杂监控。现在 job/event 已能查询 workflow、资产补全、provider 调用轨迹和聚合指标,用户端和管理端也能展示生成轨迹;下一步会迁移到后台 worker 和进度轮询
---
@@ -126,6 +132,7 @@ DreamWeaver 是面向 3-8 岁亲子场景的个性化 AI 绘本与陪伴式讲
| 风险 | 现场处理 |
| --- | --- |
| 网络导致 TTS 失败 | 说明音频是可恢复资产,不阻塞故事阅读;使用已缓存样本或跳过 TTS |
| 图片 provider 未补全 | 展示 partial ready说明主内容已可读、资产可稍后补全 |
| 图片 provider 失败 | 展示 degraded completed 与 retry 机制 |
| Docker 冷启动慢 | 演示前提前运行 smoke 脚本并保持容器运行 |
| Admin 页面不适合主展示 | 只用 Provider 分层说明辅助讲系统设计 |

View File

@@ -4,6 +4,15 @@
## 2026-04-18
补充验证:
- 后端新增 `partial_ready``text_status` 与迁移 `0012_story_text_status` 后,`backend/.venv/bin/python -m pytest backend/tests -q` 通过82 个测试通过。
- `backend/.venv/bin/python -m ruff check backend/app backend/tests backend/alembic/versions/0012_add_story_text_status_and_partial_ready.py` 通过。
- 用户端与管理端 `npm run build` 均通过。
- `docker compose up -d --build` 已用当前代码重建本地演示栈。
- 当前本地 Docker 数据卷来自早期 `create_all`,缺少 `alembic_version` 且旧 `stories` 表没有 `text_status`;本轮已为演示库补齐 `text_status`、回填状态,并 `alembic stamp head``0012_story_text_status`
- `./scripts/demo_smoke.sh` 通过:普通故事以 `partial_ready` 可读返回,封面补全后仍可读且音频待补;绘本无图时 `partial_ready`,插图补全后 `completed`generation job、story job history 和 provider stats 均可查询。
验证范围:
- 用户前端 Docker 生产构建

View File

@@ -31,10 +31,13 @@ AI 生成产品最大的问题不是“能不能调模型”,而是结果不
后端通过统一状态字段表达结果:
- `generation_status`
- `text_status`
- `image_status`
- `audio_status`
- `last_error`
其中 `partial_ready` 表示主内容已经可读但资产还可以继续补全,`degraded_completed` 表示主内容可读但某个资产失败,需要用户稍后重试。
服务层也抽出了 `AssetCompletionResult`,用来表达资产补全类型、状态、结果值、错误信息和是否阻塞主结果。
---
@@ -58,7 +61,7 @@ AI 生成产品最大的问题不是“能不能调模型”,而是结果不
目前本地 Docker 可以跑通完整链路,并且有 smoke 脚本验证健康检查、登录、生成、资产重试、故事列表和 Provider 能力分层。
下一步我会继续打磨前端状态体验,让生成中、部分完成、失败重试这些 AI 产品特有状态更清楚;同时明确旧 API 兼容层和 generation job 是否需要落库
现在 generation job 已经能查询完整事件流,包括 workflow、资产补全和 provider 调用;用户端和管理端都能展示生成轨迹,也能看到 provider 成功率、耗时和成本视角
我希望通过这个项目展示的是:我不只是会接 AI API而是能把不确定的模型能力收敛成稳定、可解释、可恢复的产品体验。
@@ -80,4 +83,4 @@ AI 生成产品最大的问题不是“能不能调模型”,而是结果不
### 这个项目下一步怎么上线?
我会先完成演示级前端状态体验和旧 API 兼容策略,再决定 generation job 是否落库。生产上线前还需要补真实用户鉴权配置、密钥管理、监控告警和部署策略。
我会先把当前轻量 job/event 模型迁移到后台 worker 和进度轮询,再补跨时间窗口的 provider 运营分析。生产上线前还需要补真实用户鉴权配置、密钥管理、监控告警和部署策略。

View File

@@ -49,7 +49,7 @@ Week 2 的目标不是做“完整商业产品”,而是做出一个面试时
- 会员、支付、商业化
- 多租户 Provider 市场
- 大规模视觉重做
- 复杂 generation job 落库
- 复杂工作流引擎和生产级任务编排
- 生产级部署、高可用、监控大盘
- 新增大量第三方 Provider
@@ -89,6 +89,7 @@ Week 2 的目标不是做“完整商业产品”,而是做出一个面试时
| W2-14 | Frontend | 同步管理端生成状态与资产补全体验 | 用户端/管理端状态体验不再分叉 | P1 | 0.5d | Done |
| W2-15 | Security | 移除管理后台弱默认密码 | 非 debug 管理后台拒绝空/弱密码 | P1 | 0.5d | Done |
| W2-16 | Workflow | 轻量落库 generation job/event 与 retryable assets | 生成/资产补全过程可追踪,前端按标准字段展示 CTA | P1 | 1.0d | Done |
| W2-17 | Workflow | 落地 `partial_ready``text_status` 细粒度状态 | 主内容可读、资产待补全、资产失败三类状态可明确区分 | P1 | 0.5d | Done |
---
@@ -129,12 +130,13 @@ Week 2 的目标不是做“完整商业产品”,而是做出一个面试时
## 7. Definition of Done
- [ ] smoke 脚本能在本地 Docker 栈中完成健康检查、登录、生成、重试和读回验证。
- [ ] 用户端主链路可手动演示,不需要打开数据库或日志解释状态。
- [ ] 故事和绘本的主要失败降级态有清楚展示和重试方式。
- [ ] README、docs index、演示 checklist 与当前代码一致。
- [ ] 面试讲解能在 3 分钟内说明产品价值、技术工作流和取舍。
- [ ] 全量后端测试、ruff、Docker build 在演示前可通过。
- [x] smoke 脚本能在本地 Docker 栈中完成健康检查、登录、生成、重试和读回验证。
- [x] 用户端主链路可手动演示,不需要打开数据库或日志解释状态。
- [x] 故事和绘本的主要失败降级态有清楚展示和重试方式。
- [x] README、docs index、演示 checklist 与当前代码一致。
- [x] 面试讲解能在 3 分钟内说明产品价值、技术工作流和取舍。
- [x] 全量后端测试、ruff、Docker build 在演示前可通过。
- [x] `partial_ready``text_status`、job progress 和 Provider stats 在 API、前端与文档中保持一致。
---

View File

@@ -144,10 +144,10 @@ DreamWeaver 是一款面向 3-8 岁亲子场景的个性化 AI 绘本与陪伴
**Acceptance Criteria**
- [ ] 用户可以选择孩子档案并输入主题或教育目标
- [ ] 系统能结合档案与宇宙上下文生成故事文本
- [ ] 故事保存后可在故事库中查看
- [ ] 当图片或语音生成失败时,故事文本仍可正常保留并查看
- [x] 用户可以选择孩子档案并输入主题或教育目标
- [x] 系统能结合档案与宇宙上下文生成故事文本
- [x] 故事保存后可在故事库中查看
- [x] 当图片或语音生成失败时,故事文本仍可正常保留并查看
### Story 2: 生成并阅读绘本
@@ -157,10 +157,10 @@ DreamWeaver 是一款面向 3-8 岁亲子场景的个性化 AI 绘本与陪伴
**Acceptance Criteria**
- [ ] 系统支持多页绘本生成
- [ ] 绘本可通过唯一 ID 被再次打开,而不是只依赖前端内存状态
- [ ] 页面刷新或重新进入时,绘本内容仍能恢复
- [ ] 若部分页面插图失败,文本页仍可正常展示
- [x] 系统支持多页绘本生成
- [x] 绘本可通过唯一 ID 被再次打开,而不是只依赖前端内存状态
- [x] 页面刷新或重新进入时,绘本内容仍能恢复
- [x] 若部分页面插图失败,文本页仍可正常展示
### Story 3: 听故事
@@ -170,9 +170,9 @@ DreamWeaver 是一款面向 3-8 岁亲子场景的个性化 AI 绘本与陪伴
**Acceptance Criteria**
- [ ] 故事详情页支持加载和播放语音
- [ ] 同一故事音频应支持缓存或复用,避免重复生成
- [ ] 音频生成失败时,页面应给出明确状态与重试方式
- [x] 故事详情页支持加载和播放语音
- [x] 同一故事音频应支持缓存或复用,避免重复生成
- [x] 音频生成失败时,页面应给出明确状态与重试方式
### Story 4: 管理模型供应与成本风险

View File

@@ -17,7 +17,7 @@ DreamWeaver 当前同时支持普通故事生成、完整故事生成和绘本
## Implementation Snapshot
**Updated**: 2026-04-18 afternoon
**Updated**: 2026-04-18 evening
当前代码已经从“纯目标态设计”进入“部分落地”阶段,主要进展如下:
@@ -25,10 +25,12 @@ DreamWeaver 当前同时支持普通故事生成、完整故事生成和绘本
- `Story` 主记录已持久化以下统一状态相关字段:
- `generation_status`
- `text_status`
- `image_status`
- `audio_status`
- `last_error`
- `audio_path`
- `partial_ready` 已在服务层、迁移、API schema、用户端与管理端状态展示中落地用于表达“主内容可读但仍有封面、插图或音频可补全”
- 已新增轻量可查询的生成过程记录:
- `generation_jobs`
- `generation_job_events`
@@ -42,25 +44,39 @@ DreamWeaver 当前同时支持普通故事生成、完整故事生成和绘本
- `POST /api/generations`
- `GET /api/generations/{story_id}`
- `POST /api/generations/{story_id}/retry-assets`
- `GET /api/generations/jobs/{job_id}`
- `GET /api/generations/{story_id}/jobs`
- `GET /api/generations/{story_id}/provider-stats`
- 用户前端与 admin 前端创建弹窗已切换到 `POST /api/generations`
- service 内部已开始收束统一工作流步骤:
- 上下文准备:档案/宇宙校验 + memory context 构建
- 主记录保存:文本故事与绘本统一持久化入口
- 资产补全:普通故事封面、绘本缺失插图、故事音频缓存/生成统一封装
- 已引入首版服务层 `AssetCompletionResult`,用于表达资产补全类型、状态、结果值、错误信息和是否阻塞主结果
- `generation_job_events` 已从首版请求/完成事件扩展到关键 workflow 节点:
- `context_prepared`
- `narrative_generated`
- `story_saved`
- 普通故事封面开始/成功/失败
- 绘本封面与逐页插图成功/失败
- 音频缓存命中、生成开始、成功和失败
- Provider failover 已记录到 job event包含 capability、adapter、strategy、latency 和 estimated cost
- Provider 调用已可按故事聚合为成功率、平均耗时、预估成本和 adapter 明细
- generation job 响应已提供 `progress_percent``progress_label``is_terminal`,前端可直接用于进度条和轮询
- `POST /api/generations` 响应已返回 `generation_job_id`smoke 脚本会验证 job 查询与 story job history
- 用户端与管理端的故事详情页、绘本阅读页已接入生成轨迹,展示生成/重试任务、关键事件、Provider 调用结果和聚合指标
- 故事详情页封面补全已切换到统一资产重试入口
- 管理端前端构建阻塞已修复,主前端与 admin 前端均可完成生产构建
### Still Missing
### Remaining Production Work
- 普通故事、完整生成、绘本生成已有统一外部入口,内部 workflow 已开始抽取公共步骤,但旧 service 函数仍作为兼容层保留
- 统一资产重试入口仍是首版:已覆盖普通故事封面、绘本缺失插图故事音频,并已抽出 asset completion helper 与 `AssetCompletionResult`
- `generation_jobs` 已记录请求、完成、失败和资产重试事件,但尚未扩展到逐 provider 调用、逐页面资产步骤和完整运营分析
- `partial_ready``text_status` 等更细粒度状态仍停留在目标态
- 普通故事、完整生成、绘本生成已有统一外部入口,内部 workflow 仍可继续减少兼容层分支
- 统一资产重试入口已覆盖普通故事封面、绘本缺失插图故事音频,后续可继续扩展更细的资产级审计
- 后台异步 worker 进度流、跨故事 Provider 运营分析和断点续跑仍属于后续生产化增强
### What This Means
这份 PRD 仍然目标态文档,但它对应的主干方向已经不是纸面方案。当前最适合的继续方式,不是重写文档,而是继续把 service workflow 和资产补全过程收拢成统一实现
这份 PRD 仍然保留目标态设计,但主干能力已经可在当前代码中演示。当前最适合的继续方式,是继续把同步请求迁移到可复用的后台任务与运营分析视角,而是继续扩大功能范围
---
@@ -71,13 +87,13 @@ DreamWeaver 当前同时支持普通故事生成、完整故事生成和绘本
DreamWeaver 当前存在以下工作流层面问题:
1. **生成入口已建立,内部路径正在收束**
当前前端已切到 `/api/generations`,旧的 `/api/stories/generate``/api/stories/generate/full``/api/storybook/generate` 仍作为兼容入口保留。service 内部已抽取上下文准备、主记录保存、封面补全、绘本插图补全和音频补全 helper并用 `AssetCompletionResult` 表达资产补全结果。下一步重点是决定这些结果是否需要进一步沉淀为可查询的 generation job
当前前端已切到 `/api/generations`,旧的 `/api/stories/generate``/api/stories/generate/full``/api/storybook/generate` 仍作为兼容入口保留。service 内部已抽取上下文准备、主记录保存、封面补全、绘本插图补全和音频补全 helper并用 `AssetCompletionResult` 表达资产补全结果。generation job/event 已落库并可查询Provider 调用轨迹和聚合指标也已进入用户端与管理端展示。下一步重点是为后台异步 worker 与运营成本分析复用这些事件
2. **保存与资产补全过程正在统一**
文本故事和绘本已拥有更清晰的主记录保存 helper普通故事封面、绘本缺失插图、故事音频生成/缓存已共用各自的 asset completion helper。服务层已经能表达资产任务结果剩余差异集中在还没有持久化 job 对象
文本故事和绘本已拥有更清晰的主记录保存 helper普通故事封面、绘本缺失插图、故事音频生成/缓存已共用各自的 asset completion helper。服务层已经能表达资产任务结果并会把统一入口、资产重试、绘本逐页插图和音频生成的关键节点写入 job event
3. **状态表达不统一**
系统缺少标准的“生成中、部分完成、完成、失败可重试”等状态定义,导致前端难以做出成熟体验
3. **状态表达已基本统一,仍需生产化扩展**
当前已经能用 `generation_status``text_status``image_status``audio_status``retryable_assets` 表达生成中、部分可读、完成、降级完成、失败可重试。后续重点是让后台 worker、运营分析和通知系统复用同一套状态语义
4. **失败处理策略不统一**
图片、音频、绘本页生成失败时,系统没有统一的降级定义,用户体验和技术行为都不够稳定。
@@ -165,9 +181,9 @@ DreamWeaver 当前存在以下工作流层面问题:
**Acceptance Criteria**
- [ ] 创建入口支持选择输出类型:普通故事或绘本
- [ ] 系统能根据输入类型走统一流程,而不是完全独立逻辑
- [ ] 用户提交后立即看到生成状态
- [x] 创建入口支持选择输出类型:普通故事或绘本
- [x] 系统能根据输入类型走统一流程,而不是完全独立逻辑
- [x] 用户提交后立即看到生成状态
### Story 2: 获得可用结果
@@ -177,9 +193,9 @@ DreamWeaver 当前存在以下工作流层面问题:
**Acceptance Criteria**
- [ ] 文本生成完成后,主记录应被保存
- [ ] 图片、音频、绘本页可后续补全
- [ ] 即使部分资产失败,用户仍可查看文本结果
- [x] 文本生成完成后,主记录应被保存
- [x] 图片、音频、绘本页可后续补全
- [x] 即使部分资产失败,用户仍可查看文本结果
### Story 3: 恢复历史结果
@@ -189,9 +205,9 @@ DreamWeaver 当前存在以下工作流层面问题:
**Acceptance Criteria**
- [ ] 故事详情页支持按 ID 加载
- [ ] 绘本阅读器支持按 ID 加载
- [ ] 刷新页面不会导致内容丢失
- [x] 故事详情页支持按 ID 加载
- [x] 绘本阅读器支持按 ID 加载
- [x] 刷新页面不会导致内容丢失
### Story 4: 理解系统状态
@@ -201,9 +217,9 @@ DreamWeaver 当前存在以下工作流层面问题:
**Acceptance Criteria**
- [ ] 前端展示统一状态模型
- [ ] 失败原因对用户可解释
- [ ] 可补全资产应有独立重试入口
- [x] 前端展示统一状态模型
- [x] 失败原因对用户可解释
- [x] 可补全资产应有独立重试入口
### Story 5: 以统一方式扩展能力
@@ -213,9 +229,9 @@ DreamWeaver 当前存在以下工作流层面问题:
**Acceptance Criteria**
- [ ] 工作流步骤具备清晰边界
- [x] 工作流步骤具备清晰边界
- [x] 新能力接入时能挂入现有状态模型
- [ ] 不需要再新增完全平行的一套生成接口
- [x] 不需要再新增完全平行的一套生成接口
---
@@ -263,6 +279,8 @@ DreamWeaver 当前存在以下工作流层面问题:
- 每个状态必须有明确进入条件
- 前端可根据状态做 UI 展示
- `degraded_completed` 必须代表“主结果可用,部分资产失败”
- `partial_ready` 必须代表“主结果可读,资产尚未全部完成但没有失败”
- `text_status` 必须只表达主文本或绘本结构是否可读,不被图片、音频状态覆盖
### Feature 3: 统一主记录保存
@@ -466,7 +484,7 @@ DreamWeaver 当前存在以下工作流层面问题:
|------|------------|--------|---------------------|
| 工作流抽象过度 | Medium | High | 先围绕现有故事/绘本/音频场景做最小抽象 |
| 历史接口兼容性问题 | Medium | Medium | 保留兼容入口,内部统一服务实现 |
| 前后端状态模型理解不一致 | High | High | 先写清统一状态表,再进入实现 |
| 前后端状态模型理解不一致 | Medium | High | 通过共享状态 helper、API schema 和回归测试保持一致 |
| Storybook 恢复实现不彻底 | Medium | High | 把“按 ID 加载”作为硬性验收项 |
| 资产状态字段新增引发迁移成本 | Medium | Medium | 允许先在服务层实现,再视需要落库 |
@@ -483,7 +501,7 @@ DreamWeaver 当前存在以下工作流层面问题:
**Known Blockers**
- 统一入口尚未建立
- 当前没有阻塞 MVP 演示的已知问题;后续生产化主要受后台异步化与运营分析范围影响
- 多条生成链路重复实现
---

View File

@@ -21,6 +21,9 @@
- `POST /api/generations`
- `GET /api/generations/{story_id}`
- `POST /api/generations/{story_id}/retry-assets`
- `GET /api/generations/jobs/{job_id}`
- `GET /api/generations/{story_id}/jobs`
- `GET /api/generations/{story_id}/provider-stats`
前端创建弹窗、绘本阅读器、故事详情页的资产重试应优先使用这些入口。

View File

@@ -12,26 +12,37 @@
- `stories` 继续承载用户可见结果和当前状态。
- `generation_jobs` 记录一次生成或资产补全尝试。
- `generation_job_events` 记录关键步骤事件,例如 `request_accepted``generation_completed``asset_retry_started``asset_retry_completed`
- `generation_job_events` 记录关键步骤事件,例如 `request_accepted``context_prepared``narrative_generated``story_saved``cover_image_succeeded``storybook_page_image_succeeded``audio_succeeded``provider_call_succeeded``asset_retry_completed`
当前已提供三个查询入口:
- `GET /api/generations/jobs/{job_id}`:查询单次生成/补全任务及其事件流。
- `GET /api/generations/{story_id}/jobs`:查询某个故事或绘本的生成与重试历史。
- `GET /api/generations/{story_id}/provider-stats`:按故事聚合 Provider 调用成功率、平均耗时、预估成本和 adapter 明细。
job 响应会返回 `progress_percent``progress_label``is_terminal`,用户端与管理端已经消费这些查询入口,在故事详情页和绘本阅读页展示最近任务、任务历史、事件时间线、进度条和 Provider 聚合指标。
## 现有状态模型
当前 `stories` 表已承载演示所需状态:
- `generation_status`: 主流程状态,例如 `narrative_ready``assets_generating``completed``degraded_completed``failed`
- `generation_status`: 主流程状态,例如 `narrative_ready``partial_ready``assets_generating``completed``degraded_completed``failed`
- `text_status`: 主文本或绘本结构状态,当前用于区分主内容是否已经可读
- `image_status`: 封面或绘本插图状态
- `audio_status`: 语音状态
- `last_error`: 最近一次资产失败原因
这些字段足够支撑前端展示、smoke 检查、失败降级和资产重试
`partial_ready` 表示主内容已经可读、但仍有封面、插图或音频可以继续补全;`degraded_completed` 表示主内容可读但至少一个资产失败。两者的区分能让前端把“正常待补全”和“需要重试失败资源”分开展示
这些字段足够支撑前端展示、smoke 检查、失败降级、资产重试和生成轨迹解释。
## 什么时候需要落库 job
如果后续进入真实生产化,需要扩展当前 job/event 模型:
- 生成流程改成真正异步,前端需要轮询 job 进度。
- 单个故事会产生多次生成尝试,需要审计每次 provider 调用
- 需要展示更细颗粒度步骤,例如 prompt 构建、文本生成、封面生成、每页插图、TTS
- 生成流程改成真正异步,前端需要轮询后台 worker 的实时进度。
- 单个故事会产生多次生成尝试,需要对比每次任务的 provider 表现、重试原因和资产结果
- 需要展示比当前事件更细颗粒度步骤,例如 prompt 构建、provider 选择依据、provider failover 原因、每次调用 token/图片/语音成本
- 需要按 provider、成本、延迟和失败原因做运营分析。
- 需要断点续跑,避免 Worker 重启后丢失中间状态。
@@ -39,9 +50,9 @@
当前已有两层记录,未来可以继续扩展字段和事件颗粒度:
- `generation_job_events` 中补 provider、耗时、成本和错误摘要
- 对绘本逐页插图、TTS、后处理任务记录更细事件
- 为前端提供 job 查询接口,用于真正异步生成时轮询进度。
- job/event 查询继续接入真正异步生成时的进度条
- 将当前按故事聚合的 provider 指标扩展为跨用户、跨时间窗口的运营分析
- 将当前同步生成请求迁移到后台 worker 后,复用现有 job 查询接口做轮询进度。
## 面试表达