fix(ai): V3 长期问题修复+规则合规+竞品对标

## P1 安全加固
- 原子化每日限额(tryConsumeDailyQuota)解决 TOCTOU 竞态
- 流式端点补齐 Zod 校验 + rate limit + 服务端强制 systemPrompt
- 配额回退机制(refundDailyQuota):过滤/失败不扣配额
- PII 最小化:移除 AI prompt 中的学生姓名

## P1 数据一致性
- 修复 capability 埋点缺失 child_summary/study_path 类型
- 创建 data-access.ts:真实统计聚合替代硬编码零
- 修复 generateChildSummary/recommendStudyPath 的 capability 标记

## P2 可靠性
- AI 调用重试机制(withRetry 指数退避,429/5xx,2 次重试)
- 30s 超时配置
- 流式 controller 安全 enqueue(防已关闭抛错)
- localStorage 防抖持久化(500ms,流式过程中跳过)

## P2 TypeScript/规则合规
- 移除 as 断言(VariantType 类型守卫、Permission 类型、StreamErrorKey)
- 补齐返回类型标注(POST/getStatusFromError/DashboardLayout)
- 拆分 use-ai-chat-stream hook(190→107 行,函数体≤80 行)
- 抽取 stream-utils.ts(SSE 解析/错误映射/消息工具)
- Tailwind 任意值添加注释说明(max-w-[80%] 聊天气泡)

## P3 竞品对标
- 苏格拉底式辅导强化(对标 Khanmigo):
  - SOCRATIC_TUTOR_SYSTEM_PROMPT 3 级提示升级
  - 强化 STUDENT_BLOCKED_PATTERNS 正则(中英文答案拦截)
  - validateSocraticOutput 服务端校验(问号结尾+连续陈述句限制)
  - socratic_warning SSE 事件类型
- 知识图谱集成(对标 Squirrel AI):
  - StudyPathInput 新增 knowledgeGraph/textbookId 字段
  - recommendStudyPathAction 自动从 textbooks 模块获取图谱+掌握度
  - STUDY_PATH_SYSTEM_PROMPT 增加前置依赖链规则
  - WEAKNESS_ANALYSIS_SYSTEM_PROMPT 增加 rootCause 字段

## 架构文档同步
- 004 更新 AI 模块章节(V3 标记/新导出/依赖关系/安全机制/文件清单)
- 005 更新 modules.ai 节点(dependsOn/exports/dataAccess/streamUtils/dependencyMatrix)
This commit is contained in:
SpecialX
2026-06-23 09:39:18 +08:00
parent 036a2f2839
commit 696346dc08
22 changed files with 847 additions and 238 deletions

View File

@@ -1,10 +1,11 @@
import "server-only"
import { trackEvent, type EventName } from "@/shared/lib/track-event"
import { recordAiEvent } from "../data-access"
export type AiUsageEvent = {
userId: string
capability: "chat" | "similar_question" | "grading_assist" | "lesson_content" | "question_variant" | "weakness_analysis"
capability: "chat" | "similar_question" | "grading_assist" | "lesson_content" | "question_variant" | "weakness_analysis" | "child_summary" | "study_path"
providerId?: string
model?: string
success: boolean
@@ -20,16 +21,31 @@ const AI_EVENT_MAP: Record<AiUsageEvent["capability"], EventName> = {
lesson_content: "ai.lesson_content",
question_variant: "ai.question_variant",
weakness_analysis: "ai.weakness_analysis",
child_summary: "ai.child_summary",
study_path: "ai.study_path",
}
/**
* AI 使用埋点
*
* 记录每次 AI 调用的元数据,用于监控、成本分析与异常排查。
* 同时写入 data-access 层的内存事件存储(供管理员仪表盘聚合查询)。
* 非阻塞,失败不影响主流程。
*/
export const trackAiUsage = (event: AiUsageEvent): void => {
const eventName = AI_EVENT_MAP[event.capability]
// 写入 data-access 层(供 getAiUsageStats 聚合)
recordAiEvent({
userId: event.userId,
capability: event.capability,
success: event.success,
durationMs: event.durationMs,
timestamp: Date.now(),
errorMessage: event.errorMessage,
})
// 写入全局 trackEvent供外部监控系统
void trackEvent({
event: eventName,
userId: event.userId,