Просмотр исходного кода

docs: 记录单轮内容评语 review 发现与暂缓修复项

本轮完成 UI 切换到真实 getReport(d1186cb)后跑了跨仓 code review。
发现 2 条 Critical(后端 /speak-stream 绕过 evaluator、前端 getReport
不识别 status=evaluating)和 4 条 Important。由于对话主流程尚未跑通到
结果页,端到端验证缺位,暂缓修复。下次回到本 MVP 前先修 Critical + Important。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jimmylee 2 месяцев назад
Родитель
Сommit
b7f65a2ad1
1 измененных файлов с 51 добавлено и 0 удалено
  1. 51 0
      doc/ContentEvaluationPlan.md

+ 51 - 0
doc/ContentEvaluationPlan.md

@@ -1299,3 +1299,54 @@ echo "frontend: $(git -C /Users/buoy/Development/gitrepo/PPT rev-parse --short H
   - Task 6 实际走 plan 的 Branch C(实现完整 adapter),投资成本略高于 Branch A 的一行 pass-through。发现:`TopicDiscussionPreview.vue` 当前展示的是 `mockEvaluation` 硬编码数据,真实 `getReport()` 并未被 UI 消费。adapter 是结构性就位,真正"打开结果页看到 LLM 评语"需要后续把 UI 切换到走 `DialogueAPI.getReport`——该切换不在本 MVP 范围,留给后续任务
   - 未做端到端 smoke(真实后端 + 真实浏览器操作),仅静态验证(单测 + 类型检查)。进入真实联调时需先在后端启动 `.env` 里配好 `AZURE_SPEECH_KEY` 和 `ONEHUB_API_KEY`
   - 评审中提出的几个 non-blocking 改进项(content_evaluator 的 AsyncOpenAI 生命周期、`_StubDB` 断言说明、`pron_scores` TypedDict、adapter 错误容忍)均标记为后续迭代,未纳入本次 MVP
+
+---
+
+## 2026-04-24 补充:UI 接入 + 跨仓全量 Code Review 发现
+
+本轮继续完成了"UI 切换到真实 getReport"(原遗留项),并对后端/前端分别跑了一次完整 code review。对话主流程尚未跑通到结果页,下次回到本 MVP 前先让对话链路能走完 N 轮进入 completed 态,再基于真实数据验证下列修复。
+
+**新增 commit**:
+- 前端 `d1186cb` — `DialogueChatView` emit `complete` 携带 `DialogueReport | null`;`TopicDiscussionPreview` 用 `displayEvaluation` 优先真实数据、mock 作为 fallback
+- 前端最新 HEAD:`d1186cb`;后端 HEAD 未变(仍 `7d192be`)
+- vue-tsc 通过
+
+### 下次回来必须先修(Critical + Important)
+
+- **[BACKEND CRITICAL] `/speak-stream` WebSocket 路径完全绕过 ContentEvaluator**
+  - `app/api/dialogue.py:159-184` 的 `_background_evaluate_pronunciation` 只跑 Azure,从未调用 content evaluator
+  - 前端录音主路径是 WebSocket(`useDialogueEngine.ts:256+ beginStudentStream`),HTTP `/speak` 只是 fallback
+  - 后果:真实用户的 `content_feedback` 永远 NULL
+  - 修复方向:让 `/speak-stream` 统一走 `DialogueService._evaluate_pronunciation`,或把 evaluator 调用复制进去
+
+- **[FRONTEND CRITICAL] `getReport` 轮询不识别 `status === 'evaluating'`**
+  - `useDialogueEngine.ts:190-202` 的 poll 只对 reject 重试;后端 200 返 `status='evaluating'` 且部分 round `contentFeedback=null` 时直接 resolve
+  - 设计文档 §2.6 已预告此情况但实现未处理
+  - `BackendReportResponse.status` 类型已声明却从未被读取
+  - 修复方向:把 `status === 'evaluating'` 视为"未完成"继续 poll
+
+- **[FRONTEND IMPORTANT] `getReport` 失败悄悄回落到 `mockEvaluation`(I2)**
+  - `fetchReportSafe → null → displayEvaluation → mockEvaluation`(熊猫/竹子那份假数据)
+  - 用户会把虚构报告当作自己的
+  - 修复方向:真实模式下失败必须显示错误态 UI,不回落 mock
+
+- **[FRONTEND IMPORTANT] "结束并查看报告" 阻塞最多 30s(I3)**
+  - `handleExitConfirm` 里 `await fetchReportSafe()` 串在 modal 关闭后,期间 chat view 冻结
+  - 修复方向:先切到 `completed` stage 显示 loading,getReport 后台拉
+
+- **[FRONTEND IMPORTANT] `pending/failed` 轮次 0 分污染 `overallScore`(I5)**
+  - `llmService.ts:90-97` 用 `?? 0` 把未完成轮次填 0,`.filter(s.pronunciation)` 仍会保留
+  - 修复方向:adapter 里只有 `status === 'completed'` 且 score 非 null 才填 `pronunciation`
+
+- **[FRONTEND IMPORTANT] Axis 映射语义不对(I4)**
+  - `prosody → intonation`、`completeness → stress`:completeness 是"读完整度",stress 是"重音"
+  - 修复方向:MVP 先加注释标记为债,后续扩展 `SentenceEvaluation.pronunciation` 为 Azure 四维
+
+### 下下轮改进(Non-blocking)
+
+- Backend I1:`DialogueService.__init__` 每请求 new `AsyncOpenAI`(`get_dialogue_service` 在 `Depends` 里),改 module-level 单例
+- Backend I2:`prior_ai_turn` 依赖"学生消息已 flush 但 AI 未写入"的时序脆弱,加 `role='ai' AND round < current_round` 显式过滤
+- Backend I4:`pron_scores: dict` 缺 TypedDict
+- Backend I5/I6:`test_content_evaluator` 缺 prompt payload 断言;`test_dialogue_service_report` 契约镜像嫌疑
+- Backend M1-6:corrections 内部结构未校验、prompt 注入、migration 非幂等、model 无专用配置、f-string 日志
+- Frontend M1-5:非空断言可避免、`Math.max(...arr)` 栈风险、`dimensions/statistics/aiComment` 占位零未标 TODO、id 方案不统一、`status` 类型不含 `'evaluating'`