startup-plan/技术设计/去掉自动生成知识点并改为基于KnowledgeSource出题-修订计划.md

15 KiB
Raw Blame History

去掉自动生成知识点并改为基于 KnowledgeSource 出题 - 修订计划

修订日期2026-07-05
对照仓库:rag-worker / api-server / ios-projects/AIStudyApp


1. 目标确认

本次改造的目标不是“优化自动生成知识点”,而是把系统职责重新切开:

  1. 上传资料后的 RAG 导入流程只负责解析、分块、向量化、索引,不再自动产出候选知识点。
  2. 知识点生成改为用户手动触发,继续沿用现有 generate-knowledge 流程。
  3. Quiz 生成不再依赖 KnowledgeItem,改为直接基于 KnowledgeSource + KnowledgeChunk 原文出题。
  4. iOS 侧同步移除“候选审批”相关死页面/死路由/死 API并补齐“按资料出题”的客户端能力。

2. 现状核对

2.1 已确认符合目标的部分

  1. 手动 AI 解析知识点链路已经存在:

    • api-server/src/modules/knowledge-source/knowledge-source.service.ts
    • api-server/src/modules/ai/workflows/knowledge-import.workflow.ts
    • ios-projects/AIStudyApp/AIStudyApp/Core/Services/API/KnowledgeSourceAPI.swift
    • ios-projects/AIStudyApp/AIStudyApp/Features/MaterialReader/MaterialReaderView.swift
  2. Quiz 的 prompt / schema 基础设施已经存在:

    • api-server/src/modules/ai/prompts/quiz-generation.prompt.ts
    • api-server/src/modules/ai/prompts/schemas/quiz-generation.schema.ts
  3. Prisma 已支持 Quiz 挂载资料来源与题目来源块:

    • api-server/prisma/schema.prisma
    • Quiz.sourceType
    • Quiz.sourceId
    • QuizQuestion.sourceBlockIds

2.2 与目标冲突的现状

  1. Python RAG Worker 仍然会自动生成候选知识点:

    • rag-worker/pipelines/import_pipeline.py
    • rag-worker/candidate_generator.py
    • rag-worker/api_client.py
  2. API Server 仍保留完整的 ImportCandidate 审批链路:

    • api-server/src/modules/import-candidate/*
    • api-server/src/modules/rag/internal-rag.controller.ts
    • api-server/src/modules/rag/rag.module.ts
    • api-server/src/app.module.ts
  3. iOS 仍保留候选审批页面与 API

    • ios-projects/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift
    • ios-projects/AIStudyApp/AIStudyApp/Core/Navigation/Route.swift
    • ios-projects/AIStudyApp/AIStudyApp/Core/Services/API/ImportAPI.swift
  4. 当前 Quiz 仍然直接从 KnowledgeItem 拼题:

    • api-server/src/modules/quiz/quiz.service.ts
  5. ai-job 的 quiz snapshot 体系仍然以 KnowledgeItem 为输入,不符合“从资料原文出题”:

    • api-server/src/modules/ai-job/quiz-generation-snapshot-builder.ts
    • api-server/src/modules/ai-job/quiz-generation-registration.service.ts
    • api-server/src/modules/ai-job/quiz-generation-job-definition.ts
    • 对应 spec 文件
  6. iOS 当前 Quiz API 只支持按知识库生成,不支持按资料生成:

    • ios-projects/AIStudyApp/AIStudyApp/Core/Models/APIModels.swift
    • ios-projects/AIStudyApp/AIStudyApp/Core/Services/API/QuizAPI.swift
    • ios-projects/AIStudyApp/AIStudyApp/Features/Quiz/QuizViews.swift

3. 修订后的执行范围

本次改造不应只做你原计划里的 3 个点,而应拆成 5 个批次。

批次 1去掉 Worker 自动候选知识点生成

1.1 Python 主流程

文件:

  • rag-worker/pipelines/import_pipeline.py

修改:

  1. 删除 generate_candidates import。
  2. 删除 save_candidates import。
  3. 删除 GENERATING_CANDIDATES 状态更新与整段候选生成逻辑。
  4. 更新文件头部注释导入流程从“下载→解析→清洗→切片→embedding→Qdrant→AI 候选”改为“下载→解析→清洗→切片→embedding→Qdrant”。

1.2 Python 死代码清理

文件:

  • rag-worker/candidate_generator.py
  • rag-worker/api_client.py

修改建议:

  1. 若确认后续完全不再保留候选知识点机制,删除 candidate_generator.py
  2. 删除 api_client.pysave_candidates()
  3. 若短期内想保留历史兼容,可先不删文件,但必须确保运行时不再被引用。

1.3 API 端导入状态枚举同步

文件:

  • api-server/src/modules/document-import/document-import.repository.ts

修改:

  1. findStaleJobs() 中移除 GENERATING_CANDIDATES,避免恢复逻辑继续认为该状态合法。

1.4 Internal RAG API 同步清理

文件:

  • api-server/src/modules/rag/internal-rag.controller.ts

修改:

  1. 删除 /internal/rag/candidates 保存入口。
  2. 删除 ImportCandidateRepository 注入。
  3. 删除“候选创建成功后将 learningStatus 置为 completed”的逻辑。

注意:

learningStatus 的完成语义需要改成“手动 AI 解析成功后完成”,不能再绑定到上传流程。


批次 2删除 ImportCandidate 审批体系

这是原计划漏掉的最大后端范围。

2.1 API 模块清理

文件:

  • api-server/src/modules/import-candidate/import-candidate.controller.ts
  • api-server/src/modules/import-candidate/import-candidate.service.ts
  • api-server/src/modules/import-candidate/import-candidate.repository.ts
  • api-server/src/modules/import-candidate/import-candidate.module.ts

修改策略二选一:

  1. 如果决定彻底废弃候选知识点体系:删除整个模块,并移出所有引用。
  2. 如果担心一次删太多:先停用对外入口与 worker 写入口,但保留模块代码一版作为过渡。

建议选项:

优先选 彻底废弃。因为当前产品目标已经变为“知识点只能手动生成”,保留审批模块只会制造错误认知和死维护成本。

2.2 模块依赖清理

文件:

  • api-server/src/modules/rag/rag.module.ts
  • api-server/src/app.module.ts

修改:

  1. 移除 ImportCandidateModule import。
  2. 清理随之失效的 provider / constructor 依赖。

2.3 数据模型处理

文件:

  • api-server/prisma/schema.prisma

建议分两步:

  1. 第一阶段先保留 ImportCandidate 表,不再写入、不再读取,避免一次触发大迁移。
  2. 第二阶段若确认无回滚需求,再执行 Prisma migration 删除 ImportCandidate 模型及关联字段。

这样更稳,先完成行为切换,再做数据库瘦身。


批次 3改造 Quiz 生成链路为基于资料原文

3.1 新增 Workflow

新文件:

  • api-server/src/modules/ai/workflows/quiz-generation.workflow.ts

实现建议:

  1. 注入 AiGatewayServicePrismaService
  2. 根据 sourceIds 查询 KnowledgeChunk
  3. 对原文做长度控制,避免 prompt 失控。
  4. chunk.id 一并带入 prompt 上下文,便于返回 sourceBlockIds
  5. 调用 promptKey = quiz-generation,按 schema 解析。

建议输入结构:

{
  userId: string;
  knowledgeBaseId: string;
  sourceIds: string[];
  questionCount: number;
}

3.2 Prompt 改写

文件:

  • api-server/src/modules/ai/prompts/quiz-generation.prompt.ts

当前问题:

系统提示明确写的是“根据知识点内容创建题目”,这与新目标冲突。

修改方向:

  1. 明确输入是“学习资料原文/资料分块”。
  2. 要求题目依据资料事实,不依赖知识点摘要。
  3. 要求输出尽量回填 sourceBlockIds
  4. 继续保留 choice/fill/judge 三种题型,兼容现有 iOS 作答页。

3.3 Schema 核对

文件:

  • api-server/src/modules/ai/prompts/schemas/quiz-generation.schema.ts

当前 schema 基本够用,但要确认:

  1. answer 的编码规则继续兼容现有判分逻辑:
    • choice 用选项索引字符串
    • judge"true" / "false"
    • fill 用标准答案文本
  2. sourceBlockIds 可选且允许返回多个 chunk id。

3.4 注册到 AiModule

文件:

  • api-server/src/modules/ai/ai.module.ts

修改:

  1. QuizGenerationWorkflow 加入 providers。
  2. QuizGenerationWorkflow 加入 exports。

3.5 改写 QuizService

文件:

  • api-server/src/modules/quiz/quiz.service.ts
  • api-server/src/modules/quiz/quiz.module.ts

修改:

  1. create() 不再查询 knowledgeItem.findMany()
  2. 改为根据 dto.sourceType / dto.sourceId / dto.knowledgeBaseId 决定出题范围。
  3. 查询 KnowledgeSource,然后将 sourceIds 传给 QuizGenerationWorkflow
  4. AI 返回结果后落库到 QuizQuizQuestion
  5. quiz.title 可优先使用 dto.title,其次 result.quizTitle,最后兜底“自测”。
  6. quiz.description 建议写入 result.quizDescription,避免浪费模型输出。

3.6 DTO / Controller 收口

文件:

  • api-server/src/modules/quiz/quiz.controller.ts

修改建议:

  1. 不要继续使用 dto: any
  2. 显式定义 create dto至少包含
    • knowledgeBaseId: string
    • title?: string
    • sourceType?: 'kb' | 'source'
    • sourceId?: string
    • questionCount?: number

这样才能和 iOS 的“按整库出题 / 按单资料出题”契约对齐。


批次 4处理 ai-job 的 quiz snapshot 旧设计

这是原计划第二个漏项。

4.1 必须先决策 ai-job 是否仍承载 Quiz 生成

当前仓库同时存在两套 Quiz 生成路径:

  1. quiz.service.ts 里的同步生成逻辑。
  2. ai-job/quiz-generation-* 里的统一 Job Engine 迁移体系。

如果本次不处理这个分叉,后面一定会出现“一个入口按原文出题,一个入口按知识点出题”的双标行为。

4.2 建议方案

建议分两阶段:

  1. 本次先让线上主链路 QuizService.create() 切到 KnowledgeSource + KnowledgeChunk
  2. 同步把 ai-job/quiz-generation-snapshot-builder.ts 改成同样基于 source/chunk 构建 snapshot至少保证未来迁移方向一致。

4.3 需要修改的点

文件:

  • api-server/src/modules/ai-job/quiz-generation-snapshot-builder.ts
  • api-server/src/modules/ai-job/quiz-generation-registration.service.spec.ts
  • api-server/src/modules/ai-job/quiz-generation-snapshot-builder.spec.ts(如存在)
  • api-server/docs/architecture/m-ai-07-quiz-generation-migration-contract.md

修改:

  1. snapshot 输入不能再以 knowledgeItems 为核心。
  2. 应改为 knowledgeSources + chunks 的截断快照。
  3. knowledgePointIds 这类字段若无业务价值,应移除或重新定义。
  4. 契约文档需要同步说明“资料原文出题”而非“知识点出题”。

如果这批不做,至少要在计划里标成 必须跟进,不能留空。


批次 5iOS 清理候选审批,并补齐按资料出题

5.1 删除候选审批页面与 API

文件:

  • ios-projects/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift
  • ios-projects/AIStudyApp/AIStudyApp/Core/Navigation/Route.swift
  • ios-projects/AIStudyApp/AIStudyApp/Core/Services/API/ImportAPI.swift
  • ios-projects/AIStudyApp/AIStudyApp/Core/Services/APIService.swift

修改:

  1. 删除 ImportReviewPage
  2. 删除 Route.importReview(sourceId:) 及对应 label / destination。
  3. 删除 ImportCandidate model。
  4. 删除 ImportCandidateService
  5. 同步清理注释与文档中“ImportAPI = DocumentImport + ImportCandidate”的描述。

5.2 扩展 Quiz 创建请求

文件:

  • ios-projects/AIStudyApp/AIStudyApp/Core/Models/APIModels.swift
  • ios-projects/AIStudyApp/AIStudyApp/Core/Services/API/QuizAPI.swift

修改:

  1. QuizGenerateRequest 需要扩展为:
struct QuizGenerateRequest: Codable {
    let knowledgeBaseId: String
    let sourceType: String?
    let sourceId: String?
    let questionCount: Int
}
  1. QuizService.generate(...) 需要支持:
    • 按知识库生成
    • 按单资料生成

5.3 Quiz UI 文案与交互修正

文件:

  • ios-projects/AIStudyApp/AIStudyApp/Features/Quiz/QuizViews.swift
  • ios-projects/AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift
  • ios-projects/AIStudyApp/AIStudyApp/Features/MaterialReader/MaterialDetailView.swift

修改方向:

  1. QuizViews.swift 中“基于知识库内容自动生成测验题目”文案应改为“基于资料内容 AI 生成测验题目”。
  2. 知识库详情页仍可保留“按整库生成测验”入口。
  3. 资料详情页或资料阅读页建议新增“按当前资料生成测验”入口。
  4. 如果资料维度新增入口,返回列表/详情时可考虑展示题目来源范围。

5.4 iOS 解码模型补齐

文件:

  • ios-projects/AIStudyApp/AIStudyApp/Core/Models/Quiz.swift

建议:

  1. Quiz 增加 sourceTypesourceIddescription 字段,便于后续 UI 展示。
  2. 如果后端继续返回 type 而不是 questionType,要确认当前 QuizQuestion 的解码是否正确,否则会出现题型丢失。

4. 推荐执行顺序

第一阶段:先切行为,不动大表

  1. 批次 1停掉 Worker 自动候选生成。
  2. 批次 3让 Quiz 改为基于资料原文生成。
  3. 批次 5iOS 侧删除候选审批死代码,并补齐按资料出题请求参数。

这三步做完,核心业务目标已经成立。

第二阶段:再收废弃系统

  1. 批次 2下线 ImportCandidate 模块。
  2. 批次 4统一 ai-job quiz snapshot 设计。
  3. 最后再决定是否通过 Prisma migration 删除 ImportCandidate 表及关联字段。

5. 验证清单

后端验证

  1. rag-worker/pipelines/import_pipeline.py 运行后不再发出 candidates 请求。
  2. api-server 中不再出现 GENERATING_CANDIDATES 相关运行状态依赖。
  3. 调用 POST /quizzes
    • knowledgeBaseId 能成功出题
    • sourceType=source + sourceId 能成功按单资料出题
  4. 当资料存在但还没有 KnowledgeItemQuiz 仍能正常生成。
  5. 当资料没有 chunk 时,接口返回明确错误,而不是空题或 500。

iOS 验证

  1. 编译通过,无 ImportReviewPage / ImportCandidateService 残余引用。
  2. 资料阅读页手动 AI 解析仍能正常生成 KnowledgeItem
  3. 知识库页生成测验正常。
  4. 单资料页生成测验正常。
  5. Quiz 作答、提交、结果页不受影响。

命令建议

python3 -m py_compile /Users/Admin1/Documents/Project/rag-worker/pipelines/import_pipeline.py
cd /Users/Admin1/Documents/Project/api-server && npx tsc --noEmit

iOS 仍需在 Xcode 中完整编译验证。


6. 风险与注意事项

  1. KnowledgeSource.learningStatus 目前与候选生成存在隐式绑定,移除候选后要重新定义其状态流转。
  2. DocumentImportWorker 与 Python RAG Worker 是两条不同导入链路:
    • 纯文本导入NestJS Worker 直接 AI 提取知识点
    • 文件导入Python Worker 只做解析索引 这两条链路的产品语义要在文档里写清楚。
  3. ai-job 的 Quiz 迁移体系如果暂时不改,后续会再次引入“按知识点出题”的旧逻辑。
  4. 若后续决定删除 ImportCandidate 表,需要先确认生产上没有后台/运营侧依赖该数据。

7. 结论

原计划方向基本正确,但范围明显偏小。
最关键的补充有三项:

  1. 不只是删 Worker 候选生成,还要同步处理 api-serverimport-candidate 体系。
  2. 不只是改 quiz.service.ts,还要同步处理 ai-job/quiz-generation-* 的旧快照设计。
  3. iOS 不只是删审批页还要补上“按资料出题”的请求模型、API 调用和入口。

按本修订版执行,才是一次完整的业务语义切换。