gwy-exam/docs/checks/task-11.md

78 lines
6.2 KiB
Markdown
Raw Permalink 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.

# 任务 11 检查记录AI 讲解与申论占位
日期2026-09-01
## 交付内容
### 后端
- `server/src/ai.ts`(新增):
- `readAiConfig()`:从环境变量读取 `AI_BASE_URL` / `AI_API_KEY` / `AI_MODEL`(默认 gpt-4o-mini/ `AI_TIMEOUT_MS`(默认 20000未配置返回 null。
- `buildMessages()`:组装模块/题干/选项/标准答案/题库解析/标签/用户作答,要求模型输出严格 JSONsummary / steps / knowledgePoints / commonMistakes / answer
- `parseExplainJson()`:兼容 markdown 代码块等杂文的稳健 JSON 提取与字段校验。
- `explainWithAi()`OpenAI 兼容 Chat Completions 调用(`${baseUrl}/chat/completions` + BearerAbortController 超时;未配置/超时/网络/HTTP/解析失败分别抛可识别错误;任何错误信息不含 API Key。
- `server/src/handlers/ai.ts`(重写):配置有效 → 调用 AI 并返回 `source:'ai'`;未配置 → `source:'fallback'`「AI 尚未配置」);超时 → `source:'fallback'`「AI 请求超时」);其余失败 → `source:'fallback'`「AI 讲解暂时不可用」)。回退内容为题库解析 + 标签 + 答案,前端可识别。
- `server/src/schemas/api.ts``AiExplainBodySchema.userAnswer` 改为可选(从错题详情进入且无作答历史时省略)。
- `server/.env.example`(新增):记录 PORT / DATA_DIR / AI 配置项说明。
- `server/src/env.ts` + `server.ts`(补充):引入 dotenv启动时最先加载 `server/.env`(进程内环境变量优先),确保 `PORT` / `DATA_DIR` / `AI_*` 在模块读取前就位;实测 `server/.env` 中配置 AI 变量后 `aiConfigured=true` 且讲解走 AI删除 `.env` 后自动回退。
### 前端
- `client/src/views/practice/AiExplainView.vue`(新增):
- 路由 `/practice/explain?questionId=&userAnswer=&requestType=`,加载/错误/重试三态,缺少题目参数给出明确提示。
- 展示来源徽章AI 生成 / 题库解析回退、讲解结论、分步解析编号步骤、考点chip、常见错误、正确答案绿色高亮回退时显示说明提示条。
- `requestType=deep` 时标题为「AI 深度讲解」。
- `client/src/views/practice/AnswerView.vue`
- 单题结果「没看懂?让 AI 讲一讲」接入跳转(携带题目 ID + 用户答案)。
- 整卷结果页错题回顾每项新增「AI 讲解」入口。
- `client/src/views/practice/WrongDetailView.vue`AI 讲解按钮由占位禁用改为可用,携带题目 ID 与最近一次作答(无历史则省略)。
- `client/src/views/practice/EssayView.vue`(新增):申论占位页——功能说明(五大题型)、后续能力(在线写作/AI 批改/范文库)、不保存写作内容的提示。
- `client/src/views/practice/PracticeView.vue`:申论 tab 由通用 ComingSoon 替换为 `EssayView`
- `client/src/router/index.ts`:新增 `/practice/explain``client/src/api/index.ts` 导出 `AiExplain` 类型。
## 接口实测(本地 OpenAI 兼容 mock + curl
| 场景 | 结果 |
|---|---|
| 未配置 AI | `source:fallback`「AI 尚未配置已回退到题库标准解析用户答案Asteps=题库解析、answer=C |
| 配置有效 Tokenmock | `source:ai`summary/steps/knowledgePoints/commonMistakes/answer 结构化解析正确 |
| deep 模式且无 userAnswer | 正常返回 `source:ai`prompt 中用户作答为「未作答」) |
| 超时AI_TIMEOUT_MS=1200 + 8s 慢响应) | 1.2s 内返回 `source:fallback`「AI 请求超时」 |
| AI 返回不可解析内容 | `source:fallback`「AI 讲解暂时不可用」 |
| 非法输入 | 缺 questionId → VALIDATION_ERROR不存在题目 → NOT_FOUND非法 requestType → VALIDATION_ERROR |
| Token 不泄漏 | 后端日志仅含请求方法/URL/状态码,无 API KeyOpenAPI 无 AI Token仅有的 `apiKey` 字段是要闻 API 导入占位请求结构任务06 既有);前端源码无密钥 |
## 浏览器检查Chrome headless + CDP
| 场景 | 结果 |
|---|---|
| AI 讲解页(配置) | AI 生成徽章、结论、分步解析、考点、常见错误、答案 C 全部渲染 |
| deep 模式 | 标题「AI 深度讲解」 |
| 错题详情 AI 按钮 | 可用;点击跳转 `/practice/explain?questionId=demo-q-004&userAnswer=A` |
| AI 未配置回退 UI | 「题库解析回退」徽章 + 回退说明 + 题库解析步骤 + 正确答案 |
| 申论占位页 | 功能说明 + 五大题型 + 后续能力 + 不保存写作内容提示 |
| 移动 390 | AI 讲解页与申论页均无横向溢出390/390 |
| 类型检查与构建 | vue-tsc / tsc 通过;生产构建 139 模块通过;`api:generate` 与 OpenAPI 一致 |
截图:`deliverables/checks/task11-ai-desktop.png``task11-ai-mobile.png``task11-ai-fallback-desktop.png``task11-essay-desktop.png``task11-essay-mobile.png`
## 完成标准核对开发计划任务11
- ✅ OpenAI 兼容客户端Chat Completions + Bearer Token环境变量配置
- ✅ Token 配置读取(`AI_BASE_URL` / `AI_API_KEY` / `AI_MODEL` / `AI_TIMEOUT_MS``server/.env.example` 示例)。
- ✅ 结构化讲解summary / steps / knowledgePoints / commonMistakes / answer
- ✅ 超时处理AbortController + `AI_TIMEOUT_MS`,超时回退题库解析)。
- ✅ 题库解析回退(未配置/超时/解析失败均回退,`source:fallback` 可识别,不阻塞刷题)。
- ✅ 前端结果展示AI 讲解页 + 刷题结果/错题详情入口 + 未配置与失败提示)。
- ✅ 申论占位页面(功能说明与后续入口,不保存写作内容)。
- ✅ Token 不出现在前端、OpenAPI 与日志。
## 边界说明
- 测试使用本地 OpenAI 兼容 mock 服务127.0.0.1:3199/3198/3197验证「配置有效」「超时」「不可解析」三条链路未使用真实外部 Token。
- 未配置 AI 时不影响刷题、错题复习、模考等任何流程;设置页 `aiConfigured` 同步反映配置状态。
## 当前结论
任务 11 完成AI 讲解接口与前端结果页、未配置/超时/失败回退、申论占位页全部实测通过桌面与移动双端可操作Token 仅存于后端环境变量且未进入日志/文档/前端。