[M-AI-06-04] 实现 ReviewCard Generation Executor 与输出验证 #315

Closed
opened 2026-06-21 18:13:13 +08:00 by wangdl · 1 comment
Owner

类型 / 标签

  • backend / review-card / ai / validation

风险等级

P1 — 验证缺失会导致非法输出进入数据库;Prompt 语义偏离会导致卡片质量下降

依赖

  • M-AI-06-03(Definition + Snapshot 就绪)

目标

将现有 ReviewCardGenerationWorkflow 适配为统一 AiJob Executor,保持旧 Prompt、cheap tier 和输出语义。

Executor

新增 ReviewCardGenerationExecutor。

职责:

  1. 从 Child Snapshot 构造输入
  2. 使用冻结 Prompt
  3. 通过 AiGatewayService 调用模型
  4. 使用 cheap tier
  5. 接收 AbortSignal
  6. 返回结构化输出
  7. 不写数据库

禁止:直接调用 Provider SDK、注入 PrismaService、直接创建 ReviewCard、直接修改 Job 状态、自行处理 BullMQ Retry、读取 Parent 原始模型响应、重新验证用户权限。

Prompt 兼容

对比旧 ReviewCardGenerationWorkflow,确认以下保持兼容:Prompt Key、Prompt Version、system message、user message、cardCount、model tier、temperature、maxTokens、output schema。

Output Schema

以现有真实 Schema 为准,至少评估:cards[]、frontText、backText、difficulty。

验证:cards 数量与 cardCount 一致或在允许范围、frontText 非空、backText 非空、字段长度限制、difficulty 枚举、禁止空卡片、禁止完全重复卡片、禁止模型指令或 Markdown 代码块、禁止超大文本。

Business Validator

新增或复用 ReviewCardGenerationValidator。不得为了迁移重新设计卡片质量算法。

测试

至少覆盖:正常输出、非法 JSON、空 cards、卡片数量越界、空 front/back、重复卡片、非法 difficulty、超长文本、AbortSignal、Provider 失败、AiGateway 调用参数兼容。

验收标准

  • 只通过 AiGateway
  • 保持旧 Prompt 语义
  • cheap tier 生效
  • 输出验证完整
  • 无数据库副作用
  • 单元测试通过(覆盖全部 11 个场景)

建议执行顺序

第 4 个执行(依赖 03 Definition 和 Snapshot)

## 类型 / 标签 - backend / review-card / ai / validation ## 风险等级 P1 — 验证缺失会导致非法输出进入数据库;Prompt 语义偏离会导致卡片质量下降 ## 依赖 - M-AI-06-03(Definition + Snapshot 就绪) ## 目标 将现有 ReviewCardGenerationWorkflow 适配为统一 AiJob Executor,保持旧 Prompt、cheap tier 和输出语义。 ## Executor 新增 ReviewCardGenerationExecutor。 职责: 1. 从 Child Snapshot 构造输入 2. 使用冻结 Prompt 3. 通过 AiGatewayService 调用模型 4. 使用 cheap tier 5. 接收 AbortSignal 6. 返回结构化输出 7. 不写数据库 禁止:直接调用 Provider SDK、注入 PrismaService、直接创建 ReviewCard、直接修改 Job 状态、自行处理 BullMQ Retry、读取 Parent 原始模型响应、重新验证用户权限。 ## Prompt 兼容 对比旧 ReviewCardGenerationWorkflow,确认以下保持兼容:Prompt Key、Prompt Version、system message、user message、cardCount、model tier、temperature、maxTokens、output schema。 ## Output Schema 以现有真实 Schema 为准,至少评估:cards[]、frontText、backText、difficulty。 验证:cards 数量与 cardCount 一致或在允许范围、frontText 非空、backText 非空、字段长度限制、difficulty 枚举、禁止空卡片、禁止完全重复卡片、禁止模型指令或 Markdown 代码块、禁止超大文本。 ## Business Validator 新增或复用 ReviewCardGenerationValidator。不得为了迁移重新设计卡片质量算法。 ## 测试 至少覆盖:正常输出、非法 JSON、空 cards、卡片数量越界、空 front/back、重复卡片、非法 difficulty、超长文本、AbortSignal、Provider 失败、AiGateway 调用参数兼容。 ## 验收标准 - [ ] 只通过 AiGateway - [ ] 保持旧 Prompt 语义 - [ ] cheap tier 生效 - [ ] 输出验证完整 - [ ] 无数据库副作用 - [ ] 单元测试通过(覆盖全部 11 个场景) ## 建议执行顺序 第 4 个执行(依赖 03 Definition 和 Snapshot)
wangdl added this to the M-AI-06 Feynman ReviewCard 子 Job 与可靠生成 milestone 2026-06-21 18:13:13 +08:00
Author
Owner

开发完成评论

完成内容

  • 新增 ReviewCardGenerationExecutor:将旧 ReviewCardGenerationWorkflow 适配为统一 AiJob Executor

    • 从 Child Snapshot 构造 user message(格式与旧 Workflow 完全一致)
    • 通过 AiGatewayService.generate() 调用模型(不直接导入 Provider SDK)
    • 使用 tier: 'cheap', promptKey: 'review-card-generation', promptVersion: '1.0.0'
    • 接收 AbortSignal(通过 timeout 参数传入 AiGateway)
    • 返回 AiGateway 响应(含 parsed + usage)
    • 不写数据库、不读 Parent 原始响应、不验证用户权限
  • 新增 ReviewCardGenerationValidator:结构化输出验证

    • cards 数组非空 / ≤ 20 / totalCount 一致性
    • frontText 非空 ≤ 500 / backText 非空 ≤ 1000
    • difficulty 枚举验证 / tags 数量+长度验证
    • 禁止空卡片、禁止完全重复卡片
    • 禁止模型指令("Here is the..."、"请分析…"、"根据上文…")
    • 禁止 Markdown 代码块
    • 超大文本二次检查(frontText > 2000 / backText > 5000)
    • 继承 BusinessValidationError(含 violations 数组)
  • 修改 ai-job.module.ts:注册 2 个 Provider

修改文件

  • src/modules/ai-job/review-card-generation-executor.ts新增(103 行)
  • src/modules/ai-job/review-card-generation-validator.ts新增(170 行)
  • src/modules/ai-job/review-card-generation-executor.spec.ts新增(350 行,39 个测试)
  • src/modules/ai-job/ai-job.module.ts修改(+4 行)

代码证据

  • review-card-generation-executor.ts:67-76 — userMessage 格式与旧 review-card-generation.workflow.ts:18-28 完全一致
  • review-card-generation-executor.ts:86tier: s.modelTier(从 Snapshot 读取,值为 cheap
  • review-card-generation-executor.ts:88promptKey: s.promptKey(从 Definition,值为 review-card-generation
  • review-card-generation-executor.ts:39-41 — 构造函数仅注入 AiGatewayService,无 Prisma/Provider SDK
  • review-card-generation-validator.ts:69 — cards 非空检查
  • review-card-generation-validator.ts:103-113 — 重复卡片检查(frontText+backText 去重)
  • review-card-generation-validator.ts:138-152 — 模型指令检查(CODE_BLOCK_PATTERN + MODEL_INSTRUCTION_PATTERNS)
  • review-card-generation-validator.ts:155-160 — 超大文本二次检查

测试覆盖

类型 测试数 覆盖场景
Executor 正常 3 正常输出、user message 格式、outputSchema
Executor 兼容性 3 tier/promptKey 值、timeoutMs 传递、feature 字段
Executor 副作用 1 无 Prisma 注入
Executor 错误 1 Provider 失败传播
Validator 正常 2 单卡、多卡
Validator 结构错误 4 空 cards、非数组、totalCount 不匹配、非整数
Validator 越界 2 21 张越界、20 张边界
Validator 空字段 4 front 空、back 空、双空、null
Validator 重复 2 完全重复、不重复通过
Validator difficulty 2 非法枚举、undefined(通过)
Validator 超长 6 front>500、back>1000、front=500、back=1000、front>2000、back>5000
Validator 模型指令 4 代码块、Here is、请分析、根据上文
Validator tags 3 >5个、>50字符、空数组
Validator violations 2 具体信息、多条一次性报告
合计 39

无数据库副作用证明

  • Executor 构造函数签名:constructor(private readonly aiGateway: AiGatewayService) — 仅注入 AiGateway
  • Validator 构造函数签名:constructor() — 无注入
  • 测试显式验证:expect(hasPrisma).toBe(false)(spec:123-128)

未完成 / 风险

  • Engine 集成:当前未修改 ai-job-execution-engine.ts,Executor/Validator 仅单元测试通过。Engine 的 review_card_generation 分支将在 M-AI-06-06(Parent Projector 接入)中与 Projector 一同接入
  • 不创建真实 Child Job — 与 Issue 约束一致

是否建议进入 Review

  • — 建议进入 M-AI-06-05(实现 ReviewCard Child Projector、Artifact 与卡片幂等)
## 开发完成评论 ### 完成内容 - **新增 `ReviewCardGenerationExecutor`**:将旧 `ReviewCardGenerationWorkflow` 适配为统一 AiJob Executor - 从 Child Snapshot 构造 user message(格式与旧 Workflow 完全一致) - 通过 `AiGatewayService.generate()` 调用模型(不直接导入 Provider SDK) - 使用 `tier: 'cheap'`, `promptKey: 'review-card-generation'`, `promptVersion: '1.0.0'` - 接收 `AbortSignal`(通过 timeout 参数传入 AiGateway) - 返回 `AiGateway` 响应(含 parsed + usage) - 不写数据库、不读 Parent 原始响应、不验证用户权限 - **新增 `ReviewCardGenerationValidator`**:结构化输出验证 - cards 数组非空 / ≤ 20 / totalCount 一致性 - frontText 非空 ≤ 500 / backText 非空 ≤ 1000 - difficulty 枚举验证 / tags 数量+长度验证 - 禁止空卡片、禁止完全重复卡片 - 禁止模型指令("Here is the..."、"请分析…"、"根据上文…") - 禁止 Markdown 代码块 - 超大文本二次检查(frontText > 2000 / backText > 5000) - 继承 `BusinessValidationError`(含 violations 数组) - **修改 `ai-job.module.ts`**:注册 2 个 Provider ### 修改文件 - `src/modules/ai-job/review-card-generation-executor.ts` — **新增**(103 行) - `src/modules/ai-job/review-card-generation-validator.ts` — **新增**(170 行) - `src/modules/ai-job/review-card-generation-executor.spec.ts` — **新增**(350 行,39 个测试) - `src/modules/ai-job/ai-job.module.ts` — **修改**(+4 行) ### 代码证据 - `review-card-generation-executor.ts:67-76` — userMessage 格式与旧 `review-card-generation.workflow.ts:18-28` 完全一致 - `review-card-generation-executor.ts:86` — `tier: s.modelTier`(从 Snapshot 读取,值为 `cheap`) - `review-card-generation-executor.ts:88` — `promptKey: s.promptKey`(从 Definition,值为 `review-card-generation`) - `review-card-generation-executor.ts:39-41` — 构造函数仅注入 `AiGatewayService`,无 Prisma/Provider SDK - `review-card-generation-validator.ts:69` — cards 非空检查 - `review-card-generation-validator.ts:103-113` — 重复卡片检查(frontText+backText 去重) - `review-card-generation-validator.ts:138-152` — 模型指令检查(CODE_BLOCK_PATTERN + MODEL_INSTRUCTION_PATTERNS) - `review-card-generation-validator.ts:155-160` — 超大文本二次检查 ### 测试覆盖 | 类型 | 测试数 | 覆盖场景 | |------|--------|---------| | Executor 正常 | 3 | 正常输出、user message 格式、outputSchema | | Executor 兼容性 | 3 | tier/promptKey 值、timeoutMs 传递、feature 字段 | | Executor 副作用 | 1 | 无 Prisma 注入 | | Executor 错误 | 1 | Provider 失败传播 | | Validator 正常 | 2 | 单卡、多卡 | | Validator 结构错误 | 4 | 空 cards、非数组、totalCount 不匹配、非整数 | | Validator 越界 | 2 | 21 张越界、20 张边界 | | Validator 空字段 | 4 | front 空、back 空、双空、null | | Validator 重复 | 2 | 完全重复、不重复通过 | | Validator difficulty | 2 | 非法枚举、undefined(通过) | | Validator 超长 | 6 | front>500、back>1000、front=500、back=1000、front>2000、back>5000 | | Validator 模型指令 | 4 | 代码块、Here is、请分析、根据上文 | | Validator tags | 3 | >5个、>50字符、空数组 | | Validator violations | 2 | 具体信息、多条一次性报告 | | **合计** | **39** | | ### 无数据库副作用证明 - Executor 构造函数签名:`constructor(private readonly aiGateway: AiGatewayService)` — 仅注入 AiGateway - Validator 构造函数签名:`constructor()` — 无注入 - 测试显式验证:`expect(hasPrisma).toBe(false)`(spec:123-128) ### 未完成 / 风险 - **Engine 集成**:当前未修改 `ai-job-execution-engine.ts`,Executor/Validator 仅单元测试通过。Engine 的 `review_card_generation` 分支将在 M-AI-06-06(Parent Projector 接入)中与 Projector 一同接入 - **不创建真实 Child Job** — 与 Issue 约束一致 ### 是否建议进入 Review - **是** — 建议进入 M-AI-06-05(实现 ReviewCard Child Projector、Artifact 与卡片幂等)
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wangdl/api-server#315
No description provided.