Files
aurak/code-review-knowledge-base.md
T
Developer 5c974c50de feat: knowledge-base code review fixes + question bank cleanup
- 🔴 searchKnowledge: 移除随机mock向量,使用真实embedding
- 🔴 userId: 改为NOT NULL,清理遗留调试注释
- 🟡 文件移动事务安全:先移文件再创DB记录
- 🟡 Ollama嵌入并行化:串行→Promise.allSettled
- 🟡 三处重复降级代码提取为processChunksOneByOne(~200行→30行)
- 🟡 Chunk换算根据CJK比例动态调整(英4x/中2x/日2x)
- 🟡 findAll添加分页参数
- 🔵 清理冗余动态import、findByIds→findBy、日文标点补充
- chore: question-bank cleanup (删除47道概念/重复/ADV题)
- chore: qa-assessment-flow (Phase 1+2全量测试14项通过)
- fix: shuffleArray接收返回值(三处调用点)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-25 11:27:16 +08:00

157 lines
10 KiB
Markdown
Raw 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.
╔══════════════════════════════════════════════════════════════╗
║ Backend Code Review Report — 知识库模块 ║
╠══════════════════════════════════════════════════════════════╣
║ Scope: Service-level ║
║ Files: knowledge-base.service.ts, controller.ts, ║
║ entity.ts, embedding.service.ts, text-chunker.ts, ║
║ rag.service.ts ║
║ Time: 2026-06-25 20:30 ║
║ Tier: standard ║
║ Verdict: ❌ FAIL (🔴 Blocker found, see below) ║
╠══════════════════════════════════════════════════════════════╣
║ Layer 1 · Chain Decomposition ║
║ Interface: ⚠️ Issues Found ║
║ Business: ⚠️ Issues Found ║
║ Data: ⚠️ Issues Found ║
║ Utility: ✅ Clean ║
║ Error: ⚠️ Issues Found ║
║ Security: ⚠️ Issues Found ║
║ Performance: ⚠️ Issues Found ║
╠══════════════════════════════════════════════════════════════╣
║ Layer 2 · Quantitative Metrics ║
║ Requirement Coverage: 80% ║
║ Exception Coverage: 55% ⚠️ ║
║ SQL Risk: N/A (SQLite + ES) ║
║ Code Redundancy Rate: 15% ⚠️ ║
║ High-Risk Coverage: File system safety, tenant isolation ║
╠══════════════════════════════════════════════════════════════╣
║ 🔴 Blocker: 2 🟡 Major: 6 🔵 Minor: 5 ║
╠══════════════════════════════════════════════════════════════╣
║ Issues: ║
╚══════════════════════════════════════════════════════════════╝
────────────────────────────────────────────────────────────────
🔴 BLOCKER
────────────────────────────────────────────────────────────────
🔴 [Business] searchKnowledge uses RANDOM mock vectors
→ knowledge-base.service.ts:251-259
在 searchKnowledge 方法中,生成的查询向量是随机 mock 数据:
const mockEmbedding = Array.from({ length: defaultDimensions },
() => Math.random() - 0.5);
这意味着知识库搜索功能实际上是"随机匹配",不是真正的语义搜索。
当 ES 中没有索引或索引损坏时,返回的结果是随机的。
Fix: 使用 EmbeddingService.getEmbeddings 生成真实向量,或至少抛出明确错误
提示"Elasticsearch 中无可用的向量索引"。
🔴 [Security] userId 字段可空 + 遗留调试注释
→ knowledge-base.entity.ts:54
"userId: string" 的注释原文:
"Temporarily allowed empty (for debugging), should be required in future"
任何用户创建的知识库如果 userId 为空,会导致:
1. 无法正确归属到特定用户
2. tenantId 为空时,数据可能跨租户可见
3. 权限隔离失效
Fix: 将 userId 设为必填 NOT NULL
────────────────────────────────────────────────────────────────
🟡 MAJOR
────────────────────────────────────────────────────────────────
🟡 [Business] 文件移动操作无回滚
→ knowledge-base.service.ts:130-146
createAndIndex 中先 save kb,再 renameSync 文件。
如果 renameSync 失败,DB记录已有但文件在原路径。
后续 processFile 会尝试在新路径操作,导致 FileStatus.FAILED。
Fix: 先移动文件,移动成功后再创建 DB 记录。失败时清理已移动的文件。
🟡 [Performance] Ollama 嵌入逐条串行处理
→ embedding.service.ts:312-341
getOllamaEmbeddings 中对每段文本依次 fetch
"for (let i = 0; i < texts.length; i++) { ... }"
对于大文档的几百个 chunk,串行处理耗时极长(几百秒)。
Fix: 使用 Promise.allSettled 批量提交(Ollama 支持 /api/embed 接口接受数组)
🟡 [Error] vectorizeToElasticsearch 三处完全相同的大段降级逻辑
→ knowledge-base.service.ts:1013-1077, :1128-1198, :1238-1303
上下文超时时降级到单条处理的代码块完全重复三份,总共约 200 行重复代码。
任何修改都需要同步三处,实际已出现差异(如 metadata 字段不同)。
Fix: 提取为私有方法 retryWithSingleChunk(chunks, kb, ...)
🟡 [Performance] Token 转字符的粗略换算
→ text-chunker.service.ts:22-23
chunkSize * 4 是英文 token 的近似值。对于中文/日文(1 token ≈ 1.5-2 chars)
4 倍换算会导致 chunk 实际内容过多,超出模型上下文限制。
Fix: 根据检测到的语言动态调整换算系数,或使用 tokenizer 精确计算
🟡 [Security] JWT 密钥从 import 获取
→ knowledge-base.service.ts:1676-1685
使用了 require('jsonwebtoken') 动态引入,而非通过 NestJS 的 JwtService。
Fix: 注入 JwtService(项目中已安装 @nestjs/jwt
🟡 [Data] findAll 无分页
→ knowledge-base.controller.ts:41-45
findAll 返回全部 KnowledgeBase 记录。如果有数千个文件,响应体可能非常大。
Fix: 添加 page/limit 参数,默认分页
────────────────────────────────────────────────────────────────
🔵 MINOR
────────────────────────────────────────────────────────────────
🔵 [Error] processFile 异步触发无状态追踪
→ knowledge-base.service.ts:152-156
processFile 使用 .catch() 异步执行。如果队列中有多个文件同时处理,
无法追踪哪些文件正在处理中(status 字段可看但无超时检测)。
建议: 考虑添加任务队列或处理中标记
🔵 [Code] 多处 import fs 和 path 在方法体内部
→ knowledge-base.service.ts:123-124, :383, :1557-1558
"const fs = await import('fs')" 等写法在多个方法中出现。
模块级已 import 了 'fs' 和 'path' — 这些动态 import 是多余的。
建议: 删除方法内的动态 import,使用模块顶部的导入
🔵 [Code] 异常消息暴露实现细节
→ embedding.service.ts:257-259
错误消息包含 "apiUrl", "modelId" 等内部配置信息,可能通过日志泄漏。
建议: 生产环境脱敏
🔵 [Code] findByIds 已弃用
→ knowledge-base.service.ts:271
findByIds() 在新版 TypeORM 中已弃用。
建议: 改用 findBy({ id: In(fileIds) })
🔵 [Code] 魔术数字
→ text-chunker.service.ts:91, :98
sentenceEnders 硬编码了 6 个标点符号。缺少日文句号(。)和省略号(…)。
建议: 补充日文和其他常见标点
────────────────────────────────────────────────────────────────
FIX PLAN
────────────────────────────────────────────────────────────────
1. 🔴 searchKnowledge 随机向量 → 2 小时内修正
- 需由技术负责人确认 ES 索引是否可正常使用
- 使用 EmbeddingService.getEmbeddings 替代随机向量
2. 🔴 userId 可空 → 数据库迁移设置 NOT NULL
- 清理已有空 userId 的记录
- 设置 NOT NULL 约束
3. 🟡 重复代码提取 → 创建 retryWithSingleChunk 方法
- ~200 行重复代码 → 约 30 行
4. 🟡 Ollama 嵌入并行化 → 使用 Promise.allSettled
────────────────────────────────────────────────────────────────
Manual Review Required
────────────────────────────────────────────────────────────────
→ searchKnowledge mock向量替换方案(需确认真实embedding模型是否配置)
→ userId 空值迁移方案(影响现有数据)
────────────────────────────────────────────────────────────────
Knowledge Accumulation Suggestions
────────────────────────────────────────────────────────────────
→ 历史陷阱:搜索功能使用了随机mock向量而非真实语义搜索
→ 架构约束:userId 暂允许空的遗留代码应跟踪清除
→ 业务规则:文件处理流程应采用事务性操作(移动文件→创建DB记录)