面试知识库

待优化清单#

📌 迁移说明(2026-06-07):本清单含早期「待优化 / 已完成」项;其中 Query Decomposition、串行多跳、Self-Reflection 相关项已于「对标主流四刀改造」移除或被 agentic 循环取代(见 04-优化迭代记录.md #2220-改造实现设计.md)。多跳/拆解现改由真·LLM 工具调用 agentic 循环在运行时自驱;置信度改由结构化引用覆盖率(CitationParser)给出;CRAG 检索质量闸保留。下文历史「已完成」记录原样保留作为时间线,仅在会被误读为「当前能力」处加注。

已识别的优化方向,按优先级排列。每完成一项,移到 04-优化迭代记录.md 并标记完成。

高优先级(快速见效,面试加分明显)#

H10. 离线评测框架(Naive vs Hybrid vs Rerank vs Full 对照) ✅ 已完成(2026-05-04)#

  • 详见 04-优化迭代记录.md #1009-评测体系建设.md
  • 后续工作
    • 数据集从 10 条扩到 50+ 条(按真实 KB 内容补 expectedDocNames)
    • 跑完一次完整评测后把数字回填到 #10 与 09-doc
    • 加 V0(无 RAG 直答 baseline)+ V5(V4 + Query Decomposition)两档对照(注:V4=SelfReflection、V5=Query Decomposition 均已于四刀改造移除;此对照梯属四刀改造前的评测方法学,当前架构需另设对照)

H1. VectorRetriever 向量化失败降级修复 ✅ 已完成(2026-04-27)#

H2. Agent 各步骤耗时统计 ✅ 已完成(2026-04-27)#

H3. RRF/BM25/TextChunker 核心算法单元测试#

  • 问题:核心算法没有测试覆盖,边界情况(空输入、单条输入、超长输入)未验证
  • 方案:参数化测试验证 RRF 融合公式、BM25 评分、文本切分逻辑
  • 面试价值:展示测试驱动的工程素养

H4. Self-Reflection 置信度标记 ✅ 已完成(2026-04-27)#

  • 详见 04-优化迭代记录.md #3
  • 注:该能力已于四刀改造移除;置信度来源改由结构化引用覆盖率(CitationParser)给出(见 04 #22)

H5. Query Decomposition 多跳检索 ✅ 已完成(2026-04-28)#

  • 复杂查询拆解为子问题并行检索,跨子问题保底分配 + 全局补齐合并
  • 详见 04-优化迭代记录.md #4
  • 注:自研拆解 / 串行多跳已于四刀改造移除,多焦点拆解与多跳改由 agentic 循环在运行时自驱(见 04 #22)

H6. Query-Aware Adaptive Retrieval ✅ 已完成(2026-04-28)#

  • 查询感知自适应检索参数:Complexity × Specificity 二维画像 → 8 套参数预设 + RRF 加权融合
  • 详见 04-优化迭代记录.md #5

H7. 双执行路径合并 + Query Decomposition 接入主路径 ✅ 已完成(2026-04-28)#

  • 删除 RagPipeline 旧路径与 ChatController + Med* 实体重复映射
  • Query Decomposition 升级为 DocMindAgent 主路径能力
  • 详见 04-优化迭代记录.md #6
  • 注:自研 Query Decomposition 主路径能力已于四刀改造移除,拆解改由 agentic 循环运行时自驱(见 04 #22)

H8. 链路成本/延迟 Tier 1 优化 ✅ 已完成(2026-04-28)#

  • SelfReflection 高分短路 + 双模型策略(qwen-plus / qwen-turbo)+ 缓存阈值 3→2 + stream_complete SSE 事件
  • 注:SelfReflection(含高分短路)已于四刀改造移除;双模型策略与缓存优化保留(见 04 #22)
  • 预期单查询成本 -50%、p50 延迟 -25%
  • 详见 04-优化迭代记录.md #7

H9. 全格式统一通过 MinerU 入库 —— PDF / PPT / 图片 / 网页 → Markdown ✅ 已完成(2026-04-28)#

  • PDFBox 行交错 + 丢图丢表 + 不支持 PPT / 图片 / 网页:接 MinerU 云端 API(一个外部依赖解决多模态文档入库)
  • 文件流程(PDF/PPT/图片)+ URL 流程(MinerU-HTML)共享轮询主循环,通过 stateExtractor 函数抽象屏蔽 batch / task 两类响应差异
  • 降级分级:PDF 失败降级 PDFBox;PPT / 图片 / URL fail-fast 不静默降级
  • 双层闸门:env 静态开关 + sys_ai_config 动态开关
  • 详见 04-优化迭代记录.md #8

中优先级(功能完善,体现系统性思考)#

M1. 检索结果置信度评分 ✅ 已完成(2026-05-07,Phase 5 Step 13)#

  • 实际方案落点比原计划更深入:参考 CRAG 论文(Yan et al. 2024)做了三档评估器(HIGH / AMBIGUOUS / LOW)
  • 不是简单的”低于阈值就标记”,而是分档触发不同后续动作:HIGH 直接生成,AMBIGUOUS 进入仲裁,LOW 让现有 fallback 接管(注:#28 起 LOW 本身不再触发兜底——有证据走 low-confidence 带证据作答,仅真·无证据才 fallback
  • #36 升级:CRAG 改为 rerank 分 × 词项覆盖率的二信号一致性裁判(不再只给 rerank 分套阈值),灰区默认仲裁 heuristic(覆盖率优先、零额外调用,从 cross_encoder 改默认);同时修掉「AMBIGUOUS 被强制 0-chunk 兜底丢证据」的 bug,Web 补偿改覆盖率门控(LOW 或 AMBIGUOUS 缺实体才补)并两路对齐
  • 详见 04-优化迭代记录.md #16#36

M2. Micrometer 指标监控 ✅ 已被 Langfuse 方案覆盖(Phase 6 增强 → 观测标准化 Part 1)#

  • Phase 6 接入完整 OTel 集成:TracedOp 消除 span 样板代码 + ChatModelObservationFilter 采集 LLM 调用;早期靠手写 OTel SDK + RootNameFilteringSpanProcessor 白名单过滤
  • 观测标准化 Part 1(已完成):删手写 OTel SDK(228 行),改用 Spring Boot 3.4 原生 OTLP tracing autoconfig + 自定义 head-based Sampler(替代 RootNameFilteringSpanProcessor);热切换模型接 ObservationRegistry → 原生 gen_ai 埋点(删手动 gen_ai.* setAttribute,激活 ChatModelObservationFilter)。详见 04-优化迭代记录.md #23
  • 续修 #1 + #4 + #2(已完成):基于真实 trace 复盘——
    • #1:root span 上提到 execute() 顶端,找回过去被 Sampler 丢弃的 QueryUnderstanding/embedding LLM 调用(单条 trace generation 1→10)。
    • #4:经 Public API 注册 DashScope 模型 ¥/token 价表(scripts/langfuse-register-models.sh),totalCost 0→非零。
    • #2:降级回答标 langfuse.observation.level=WARNING;新增 LangfuseScoreClient 把 confidence/citation_coverage/rerank_top1/crag_grade 推成 Langfuse score(Scores API,JDK HttpClient 需强制 HTTP/1.1 绕开 Next.js 网关 EOF)。
    • #3/#5/#6 经实跑核验为伪问题(当初分析基于被 strip 的 UI 导出快照;活 trace 里 rag.* 属性、TTFT、llm_generation input/output 全都在)。详见 04-优化迭代记录.md #24

M6. 观测系统重构 Part 2:三套埋点统一为单一发射门面 ✅ 已完成(2026-06-08)#

  • 问题:SSE 事件、agentTrace、OTel span 三套埋点在 DocMindAgent/SupervisorAgent/AgenticSearchOrchestrator并行手写sendSseEvent 复制 3 份、addTrace/updateTrace 复制 2 份),同一步要发三次、易漂移
  • 方案(已实现):新增 agent/emit/StageEmitter.java 发射门面——收口单一 sse()/trace()/traceObs(),每个 SSE 事件 payload 形状集中定义一次,三类各处局部包装调用、旧 helper 全删。边界:OTel span 是时长(TracedOp 生命周期),仍由 TracedOp 收口,门面只统一 SSE+agentTrace 两类点事件。详见 04-优化迭代记录.md #25
  • 验证:golden SSE 契约 diff(改前抓 6 路径基线 → 迁移后比对),主路径 9/9 全等;全量后用 global-union 契约证明逐事件零回归(per-scenario 的 cache 差异系 LLM 路由漂移 + null 值键省略的运行时非确定性)。#1/#2/#4 全部不回归
  • 面试价值:「加了又删、收敛到简单可组合」延伸到可观测层;难点是 SSE 硬契约 + 用 golden diff 区分「契约漂移 vs 运行时非确定性」

M7. 观测收尾小项:environment 维度 ✅ 已完成(2026-06-08)#

  • 问题:trace 的 environment 恒为 default,dev/prod 不分流
  • 方案(已实现)application.yml 加 OTel resource 属性 management.opentelemetry.resource-attributes."[deployment.environment.name]": ${LANGFUSE_TRACING_ENVIRONMENT:development}(resource 属性 → 全 span 统一归属);docker-compose.yml backend 注入 LANGFUSE_TRACING_ENVIRONMENT=production。验证:容器 trace environment=production、本地 mvn 默认 development
  • 结论:可观测路线图(Part1 + #1/#2/#4 + Part2 + #7)全部清零

M3. QueryRouter 意图识别增强 → 已被 Phase 2 SupervisorAgent 架构取代,Phase 5 进一步加上范畴判定层#

  • 原方案:增强 QueryRouter 正则 or 改用 few-shot LLM 分类
  • Phase 2 演进:引入 QueryClassification(intent + complexity + specificity 三维分类)+ SupervisorAgent 多策略编排 + RetrievalGrader CRAG 条件补偿,原 QueryRouter 的职责被拆解到更精细的组件中。详见 04-优化迭代记录.md #13
  • Phase 5 补强:在三维分类之上加最外层”范畴判定层”,区分六种处理路径(知识检索 / 元对话 / 闲聊 / 超范围 / 知识库元查询 / 任务执行)。原五类 intent 都默认要查知识库,Phase 5 解决了”总结上面的对话”被错误送入检索的问题。详见 04-优化迭代记录.md #16

M5. Markdown-aware Chunker(MinerU 后续) ✅ 已完成(2026-04-30)#

M4. ContextCompressor 去重粒度参数化 ✅ 基本完成(2026-06-12,见 04 #35#

  • 原问题:去重用固定的前 50 字比较,不够灵活
  • 落地ContextCompressor 已下沉进 CrossEncoderReranker.compress;精确去重改用 dedupeKey()(id 优先,缺失退化内容指纹,已无”前 50 字”硬编码),并新增近重复去除(包含关系 + bigram Jaccard,阈值 compress.near_dup_jaccard 默认 0.85、开关 compress.near_dup_enabled 可运行时调)。截断也升级为 query-aware 命中段居中。

低优先级(锦上添花)#

L1. MCP 工具调用统计竞态修复#

  • 问题:查询+更新之间有竞态窗口
  • 方案:数据库 INSERT ON DUPLICATE KEY UPDATE

L2. MemoryTool 并发写入保护(部分完成,2026-06-12 #34 ②)#

  • 原问题:无乐观锁,并发写入丢失更新
  • 已解决:访问计数的读-改-写竞态——SoR 下沉 MySQL 后改用 DB 原子 access_count = access_count + 1setSql),不再读 JSON 改字段写回(旧 Redis-WATCH/版本号方案随 Redis 退为缓存而作废)
  • 残留(已知 LOW):并发写入相同内容仍可能各自通过去重检查、产生内容重复行(user_memory 唯一索引建在 (user_id, memory_id) 而非内容)。低频可忽略;若需根治可加内容 hash 唯一约束或写入串行化

L3. 超长 Query 截断处理#

  • 问题:用户输入 10000 字没有限制
  • 方案:入口处截断到 500 字,日志记录原始长度

L4. 文档提取编码检测#

  • 问题:固定 UTF-8,旧 PDF 可能是 GBK
  • 方案:使用 ICU4J 或 juniversalchardet 自动检测编码

链路成本/延迟优化 Tier 2-3(迭代 #7 后续)#

Tier 1(短路 + 双模型 + 缓存阈值)已落地。下面是延伸方向,按 ROI 排。详见 04-优化迭代记录.md #7 末尾的 Tier 2-3 列表。

T2-1. 拆解路径 Reranker 批量化(中 ROI)#

  • 问题:3 子问题各调 1 次 rerank,3× 网络往返
  • 方案:合并候选集 → 1 次 rerank(query 用 originalQuery)→ SubQueryMerger 用合并分数
  • 预期:拆解路径 rerank API 调用 -67%

T2-2. Prompt 模板瘦身(中 ROI)#

  • 问题:主回答 input ~4000 tokens 里模板 + 元信息占 ~1000+
  • 方案:审 src/main/resources/prompts/,删冗余前言、用更紧凑的 YAML 风格
  • 预期:主回答 input -15%

T2-3. 历史上下文摘要(中 ROI)#

  • 问题buildConversationHistory 取近 6 条原始拼接,长会话膨胀
  • 方案:超过 N 条时把更早内容用小模型摘要为 1 段
  • 预期:长会话主回答 input -20-40%

T2-4. WebSearch 提前并行启动(低 ROI)#

  • 问题:Tavily 1-3s 阻塞主流程
  • 方案:QueryProfiler 标 timeAware=true 时 Decomp 阶段就异步启动,最后 join

T2-5. Reranker 候选数自适应下调(低 ROI)#

  • 问题:当前固定 25-40 候选,简单查询过度
  • 方案QueryProfiler.RetrievalParamsrerankCandidates 字段

T2-6. DashScope Context Cache(Prompt Cache)接入(中-高 ROI)#

概念区分:语义答案缓存 vs Prompt Cache#

项目当前已有的 SemanticCacheService 不是 Prompt Cache,二者是不同层的优化,可叠加使用。

维度语义答案缓存(已有)Prompt Cache(待接入)
缓存对象完整 RAG 答案 + sourcesLLM 输入侧的稳定前缀(系统提示、工具 schema)
命中条件query embedding cosine ≥ 0.92 且 KB 版本一致输入前缀逐字节相同(provider 侧 KV cache)
节省的成本整次 RAG 调用(embedding + 检索 + rerank + LLM)仅 LLM 输入 token 计费 + 首 token 延迟
失效粒度KB 任一变更全失效前缀任意 token 变更即失效
实现层应用层 RedisLLM Provider(DashScope Context Cache)
适用场景高频重复问题每次都跑的 agent 循环(工具描述、系统模板)

关键洞察:当前命中率 ~45% 的语义缓存解决的是”重复问题”,但剩下 55% 不命中的请求每次都把 ~1000+ token 的稳定前缀(工具 schema + 系统模板)原样发给 LLM,这部分才是 Prompt Cache 的目标

改造方案#

  • 问题:每次 agent 循环都把工具 schema(~600 token)+ 系统模板(~400 token)+ 反思模板(~300 token)原样发给 qwen,前缀稳定却未复用
  • 方案
    1. 调用 DashScope /services/aigc/text-generation/generation 时按 context-cache 文档加 cache: { enable: true } 参数(具体字段以 DashScope 当时文档为准)
    2. PromptAssembler 把 prompt 重组为 [稳定前缀] + [动态 chunks] + [用户问题] 三段式,前缀放在最前
    3. 工具调用路径(ChatClient + ToolCallbackProvider)确认 Spring AI 是否透传 cache 参数;不行则降级到自建 OkHttp 客户端走原生 API
    4. AiConfigHoldercache.prompt_cache_enabled 开关,便于 A/B
  • 预期
    • 主回答 input token 计费 -25~40%(前缀命中 50% 折扣,按 DashScope 现价)
    • TTFT 延迟 -15~30%(命中前缀不重新跑 attention)
    • 工具选择 / 反思的小模型路径收益更高(前缀占比更大)
  • 风险
    • DashScope Context Cache 有最小前缀长度门槛(通常 ≥256 token),短模板可能不命中
    • 前缀里任何动态字段(时间戳、用户 ID、随机 nonce)都会破坏命中,需审一遍模板
  • 面试 talking point

    “项目里语义缓存解决的是’同一个问题不要再跑一遍’,但 agent 每次循环里工具 schema 和系统模板都是稳定的,那部分输入 token 还是每次都付钱。所以下一步是接 DashScope 的 Context Cache,把 prompt 重排成’稳定前缀 + 动态 chunks + 用户问题’三段,让 LLM provider 在 KV cache 层复用稳定前缀——和应用层语义缓存是叠加关系,一个省整次调用、一个省每次的输入 token。”