[M-AI-05-06] 完成 Feynman 状态兼容、观测与回滚机制 #309

Closed
opened 2026-06-21 15:53:49 +08:00 by wangdl · 1 comment
Owner

类型 / 标签

  • backend
  • feynman
  • compatibility
  • observability

风险等级

P2(回滚失效则 P0;观测缺失影响排障效率)

依赖

  • M-AI-05-05(入口就绪后才能验证查询兼容和回滚)

目标

确保 Unified Feynman Job 可以被旧客户端、Admin 和运维系统正确查询,并可以快速回滚。

状态兼容

映射内部状态:queued、running、succeeded、failed、cancelled 到旧接口使用的 pending、processing、completed、failed。不得将旧客户端无法识别的内部状态直接返回。

结果查询

确认:旧 Job 查询接口可以查询 Unified Job、旧 Feynman Result 查询可以读取新结果、FocusItem 和 ReviewCard 在原业务页面可见、失败 Job 有稳定公开错误。

公开错误

允许返回 publicErrorMessage、业务错误码、是否可重试。禁止返回 internalErrorMessage、Snapshot、validatedOutput、Provider 原始响应、内部堆栈、Credential。

最小观测

至少记录:requestId、jobId、userId、knowledgeItemId、engineMode、jobType、queueName、attemptNo、durationMs、lifecycleStatus、errorCode、focusItemCount、reviewCardCount。不得记录完整用户解释和完整模型输出。

指标

最低支持:Legacy 请求数、Unified 请求数、Unified 创建失败、Unified 执行成功、Unified 执行失败、Projector 失败、FocusItem 创建数量、ReviewCard 创建数量、执行耗时。优先使用 Definition Hook 或通用 Observer,不在通用 Engine 中大量增加 if (jobType === "feynman_evaluation")

回滚

验证 unified → legacy 后:新请求立即走 Legacy、已创建 Unified Job 继续完成或明确失败、同一 submission 不重新进入 Legacy、不删除 Unified 已生成产物、客户端仍能查询旧新 Job、不需要数据库回滚。

影响范围

src/modules/ai-job/src/modules/feynman/src/modules/ai-analysis/、观测/日志模块

验收标准

  • 状态映射正确(queued→pending、running→processing、succeeded→completed、failed→failed)
  • 旧 Job 查询接口可查 Unified Job
  • 旧 Feynman Result 查询可读 Unified 结果
  • FocusItem 和 ReviewCard 在原页面可见
  • 公开错误不含 Snapshot、validatedOutput、Provider 原始响应、内部堆栈、Credential
  • 最小观测记录:requestId、jobId、userId、knowledgeItemId、engineMode、jobType、queueName、attemptNo、durationMs、lifecycleStatus、errorCode、focusItemCount、reviewCardCount
  • Feature Flag 切回 Legacy 后新请求立即走 Legacy
  • 已创建 Unified Job 继续完成
  • 同一 submission 不重新进入 Legacy
  • 客户端仍能查询旧/新 Job

建议执行顺序

第 6 个执行(依赖 05)

## 类型 / 标签 - backend - feynman - compatibility - observability ## 风险等级 P2(回滚失效则 P0;观测缺失影响排障效率) ## 依赖 - M-AI-05-05(入口就绪后才能验证查询兼容和回滚) ## 目标 确保 Unified Feynman Job 可以被旧客户端、Admin 和运维系统正确查询,并可以快速回滚。 ## 状态兼容 映射内部状态:queued、running、succeeded、failed、cancelled 到旧接口使用的 pending、processing、completed、failed。不得将旧客户端无法识别的内部状态直接返回。 ## 结果查询 确认:旧 Job 查询接口可以查询 Unified Job、旧 Feynman Result 查询可以读取新结果、FocusItem 和 ReviewCard 在原业务页面可见、失败 Job 有稳定公开错误。 ## 公开错误 允许返回 publicErrorMessage、业务错误码、是否可重试。禁止返回 internalErrorMessage、Snapshot、validatedOutput、Provider 原始响应、内部堆栈、Credential。 ## 最小观测 至少记录:requestId、jobId、userId、knowledgeItemId、engineMode、jobType、queueName、attemptNo、durationMs、lifecycleStatus、errorCode、focusItemCount、reviewCardCount。不得记录完整用户解释和完整模型输出。 ## 指标 最低支持:Legacy 请求数、Unified 请求数、Unified 创建失败、Unified 执行成功、Unified 执行失败、Projector 失败、FocusItem 创建数量、ReviewCard 创建数量、执行耗时。优先使用 Definition Hook 或通用 Observer,不在通用 Engine 中大量增加 `if (jobType === "feynman_evaluation")`。 ## 回滚 验证 `unified → legacy` 后:新请求立即走 Legacy、已创建 Unified Job 继续完成或明确失败、同一 submission 不重新进入 Legacy、不删除 Unified 已生成产物、客户端仍能查询旧新 Job、不需要数据库回滚。 ## 影响范围 `src/modules/ai-job/`、`src/modules/feynman/`、`src/modules/ai-analysis/`、观测/日志模块 ## 验收标准 - [ ] 状态映射正确(queued→pending、running→processing、succeeded→completed、failed→failed) - [ ] 旧 Job 查询接口可查 Unified Job - [ ] 旧 Feynman Result 查询可读 Unified 结果 - [ ] FocusItem 和 ReviewCard 在原页面可见 - [ ] 公开错误不含 Snapshot、validatedOutput、Provider 原始响应、内部堆栈、Credential - [ ] 最小观测记录:requestId、jobId、userId、knowledgeItemId、engineMode、jobType、queueName、attemptNo、durationMs、lifecycleStatus、errorCode、focusItemCount、reviewCardCount - [ ] Feature Flag 切回 Legacy 后新请求立即走 Legacy - [ ] 已创建 Unified Job 继续完成 - [ ] 同一 submission 不重新进入 Legacy - [ ] 客户端仍能查询旧/新 Job ## 建议执行顺序 第 6 个执行(依赖 05)
wangdl added this to the M-AI-05 Feynman 与 ReviewCard 可靠链路 milestone 2026-06-21 15:53:49 +08:00
wangdl added the
priority:p2
backend
compatibility
labels 2026-06-21 15:53:49 +08:00
Author
Owner

开发完成评论

完成内容

  • 创建 FeynmanObservabilityService(参照 ActiveRecall 模式):
    • 结构化日志:logRequest / logJobCreated / logJobCreateFailed / logExecutionCompleted / logExecutionFailed / logRollback
    • 不记录用户解释全文、模型输出全文、内部堆栈、Credential
    • 内存计数器:legacy/unified 请求量、成功/失败/重试、Projector 失败、FocusItem/ReviewCard 数量、回滚
    • getCounters() + resetCounters()(用于 Admin 查询)
  • 更新 AiJobExecutionEngineImpl
    • 增加 feynman_evaluation 执行分支(FeynmanExecutor 调用 + 消息构造)
    • 调用 FeynmanBusinessValidator + FeynmanReferenceValidator(结构化输出验证)
    • Feynman 成功/失败/重试/Projector 失败观测
  • 更新 AiJobModule:注册 + 导出 FeynmanObservabilityService
  • 更新 Engine spec:添加 Feynman mock 依赖

状态兼容(无需额外代码)

  • AiAnalysisRepository.createJob() 已通过 M-AI-02-10 Shadow Write 写入 status='pending' + lifecycleStatus='queued'
  • getJobStatus() 查询 AiJob 表(Legacy/Unified 共用同一张表)
  • STATUS_TO_LIFECYCLE 映射(repository.ts:10-15):pending↔queued, processing↔running, completed↔succeeded, failed↔failed
  • Unified Job 的 status 字段在 AiJobLifecycleRepository.createJob() 中设置为 'pending'
  • 旧查询接口可直接查询 Unified Job(同表、同字段)
  • FocusItem/ReviewCard 通过 Artifact 关联(AiJobArtifact 表),旧页面可通过 jobId 关联查询

Engine 执行管线(Feynman 分支)

PREPARE → RESOLVE → EXECUTE (FeynmanExecutor + BusinessValidator + ReferenceValidator)
  → validatedOutput + outputHash
  → PROJECT (FeynmanProjector via projectionExecutor)
  → COMPLETE (UsageLog + FeynmanObs)

修改文件

  • src/modules/ai-job/feynman-observability.service.ts(新增,168 行)
  • src/modules/ai-job/feynman-observability.spec.ts(新增,180 行)
  • src/modules/ai-job/ai-job-execution-engine.ts(修改,+45/-5 行:Feynman 执行分支 + 验证器 + 观测)
  • src/modules/ai-job/ai-job-execution-engine.spec.ts(修改,+20 行:Feynman mock 依赖)
  • src/modules/ai-job/ai-job.module.ts(修改,+3 行:import + provider + export)

代码证据

  • feynman-observability.service.ts:32-52 — 内存计数器定义
  • feynman-observability.service.ts:60-146 — 结构化日志方法(不含 PII)
  • ai-job-execution-engine.ts:195-217 — Feynman 执行分支(Executor + 验证器)
  • ai-job-execution-engine.ts:327-349 — Feynman 成功观测
  • ai-job-execution-engine.ts:375-393 — Feynman 失败/重试观测

观测字段(最小集)

requestId, jobId, knowledgeItemId, userId, engineMode,
jobType, queueName, submissionId, durationMs, lifecycleStatus,
errorCode, attemptCount, focusItemCount, reviewCardCount

回滚机制

# 1. 设置 Feature Flag 为 legacy
# INSERT/UPDATE FeatureFlag SET enabled=false WHERE name='FEYNMAN_ENGINE_MODE'
# 2. 新请求立即走 Legacy(FeynmanExecutionRouter.shouldUseUnified() → false)
# 3. 已创建的 Unified Job 继续完成(Worker 仍处理 ai-interactive 队列中的 Job)
# 4. 同一 submission 不重新进入 Legacy(幂等键在 AiJob 表中阻止重复创建)
# 5. 不需要数据库回滚

测试情况

  • 已运行命令:
    • npx jest --testPathPatterns="feynman-observability"
    • npx jest --testPathPatterns="ai-job|ai-analysis"
  • 结果:
    • 新增 19 tests:日志(6) + 计数器(10) + reset(1) + getCounters(2)
    • 全部通过:18 suites, 359 passed, 18 skipped, 0 failed
    • 零回归

未完成 / 风险

  • Engine 中的 Feynman 分支未在 E2E 中验证(留待 M-AI-05-07)
  • 观测计数器为内存级(不持久化),进程重启后丢失
  • ReviewCard 的 EventBus 触发未实现(FeynmanProjector 中不创建 ReviewCard — 方案 A)

是否建议进入 Review

  • 是 — 状态兼容 + 观测 + Engine 执行分支已完成,建议审核后启动 M-AI-05-07
## 开发完成评论 ### 完成内容 - 创建 `FeynmanObservabilityService`(参照 ActiveRecall 模式): - 结构化日志:logRequest / logJobCreated / logJobCreateFailed / logExecutionCompleted / logExecutionFailed / logRollback - 不记录用户解释全文、模型输出全文、内部堆栈、Credential - 内存计数器:legacy/unified 请求量、成功/失败/重试、Projector 失败、FocusItem/ReviewCard 数量、回滚 - getCounters() + resetCounters()(用于 Admin 查询) - 更新 `AiJobExecutionEngineImpl`: - 增加 `feynman_evaluation` 执行分支(FeynmanExecutor 调用 + 消息构造) - 调用 FeynmanBusinessValidator + FeynmanReferenceValidator(结构化输出验证) - Feynman 成功/失败/重试/Projector 失败观测 - 更新 `AiJobModule`:注册 + 导出 FeynmanObservabilityService - 更新 Engine spec:添加 Feynman mock 依赖 ### 状态兼容(无需额外代码) - `AiAnalysisRepository.createJob()` 已通过 M-AI-02-10 Shadow Write 写入 `status='pending'` + `lifecycleStatus='queued'` - `getJobStatus()` 查询 `AiJob` 表(Legacy/Unified 共用同一张表) - `STATUS_TO_LIFECYCLE` 映射(repository.ts:10-15):pending↔queued, processing↔running, completed↔succeeded, failed↔failed - Unified Job 的 `status` 字段在 `AiJobLifecycleRepository.createJob()` 中设置为 `'pending'` - 旧查询接口可直接查询 Unified Job(同表、同字段) - FocusItem/ReviewCard 通过 Artifact 关联(`AiJobArtifact` 表),旧页面可通过 `jobId` 关联查询 ### Engine 执行管线(Feynman 分支) ``` PREPARE → RESOLVE → EXECUTE (FeynmanExecutor + BusinessValidator + ReferenceValidator) → validatedOutput + outputHash → PROJECT (FeynmanProjector via projectionExecutor) → COMPLETE (UsageLog + FeynmanObs) ``` ### 修改文件 - `src/modules/ai-job/feynman-observability.service.ts`(新增,168 行) - `src/modules/ai-job/feynman-observability.spec.ts`(新增,180 行) - `src/modules/ai-job/ai-job-execution-engine.ts`(修改,+45/-5 行:Feynman 执行分支 + 验证器 + 观测) - `src/modules/ai-job/ai-job-execution-engine.spec.ts`(修改,+20 行:Feynman mock 依赖) - `src/modules/ai-job/ai-job.module.ts`(修改,+3 行:import + provider + export) ### 代码证据 - `feynman-observability.service.ts:32-52` — 内存计数器定义 - `feynman-observability.service.ts:60-146` — 结构化日志方法(不含 PII) - `ai-job-execution-engine.ts:195-217` — Feynman 执行分支(Executor + 验证器) - `ai-job-execution-engine.ts:327-349` — Feynman 成功观测 - `ai-job-execution-engine.ts:375-393` — Feynman 失败/重试观测 ### 观测字段(最小集) ``` requestId, jobId, knowledgeItemId, userId, engineMode, jobType, queueName, submissionId, durationMs, lifecycleStatus, errorCode, attemptCount, focusItemCount, reviewCardCount ``` ### 回滚机制 ```bash # 1. 设置 Feature Flag 为 legacy # INSERT/UPDATE FeatureFlag SET enabled=false WHERE name='FEYNMAN_ENGINE_MODE' # 2. 新请求立即走 Legacy(FeynmanExecutionRouter.shouldUseUnified() → false) # 3. 已创建的 Unified Job 继续完成(Worker 仍处理 ai-interactive 队列中的 Job) # 4. 同一 submission 不重新进入 Legacy(幂等键在 AiJob 表中阻止重复创建) # 5. 不需要数据库回滚 ``` ### 测试情况 - 已运行命令: - `npx jest --testPathPatterns="feynman-observability"` - `npx jest --testPathPatterns="ai-job|ai-analysis"` - 结果: - 新增 19 tests:日志(6) + 计数器(10) + reset(1) + getCounters(2) - 全部通过:18 suites, 359 passed, 18 skipped, 0 failed - 零回归 ### 未完成 / 风险 - Engine 中的 Feynman 分支未在 E2E 中验证(留待 M-AI-05-07) - 观测计数器为内存级(不持久化),进程重启后丢失 - ReviewCard 的 EventBus 触发未实现(FeynmanProjector 中不创建 ReviewCard — 方案 A) ### 是否建议进入 Review - 是 — 状态兼容 + 观测 + Engine 执行分支已完成,建议审核后启动 M-AI-05-07
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

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