卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
秋招投递表
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
秋招投递表
代码随想录 (opens new window)
  • 本栏必读

    • 卡码大模型专栏介绍
  • 大模型面经

  • 大模型动态

  • Claude学习专栏

  • 入门认知

  • Prompt与调用基础

  • RAG检索增强

    • 为什么有了大模型还需要RAG
    • RAG完整链路拆解
    • Embedding是什么:语义压缩与模型选型
    • 向量数据库解决了什么问题
    • RAG切片策略:四种方式对比
    • RAG系统答不准的常见问题排查
    • RAG优化思路:Query改写到Context压缩
    • 长文档与代码怎么检索?固定切片为什么不够
      • 简要回答
      • 详细回答
      • 项目里怎么落地和评估?
      • 知识拓展
    • Agentic RAG:从传统RAG到智能体检索
    • RAG怎么评估?检索质量和生成质量的度量
    • 面试官怎么问RAG?高频问题与回答框架
  • Agent智能体

  • 微调认知

  • 部署与工程化

  • 多模态入门

  • Transformer原理

  • 手撕Transformer

  • 模型家族与Llama架构

# 长文档与代码怎么检索?固定切片为什么不够

上一篇《RAG优化不是“加个Rerank”就完了》讲了混合检索、Rerank 和 Parent-Child Retrieval。

但碰到几百页的需求文档,或者几十万行的代码仓库,只知道“父子块”还不够。这里多了三个硬问题:结构不能断、版本不能错、权限不能漏。

面试官问:“你们的代码知识库怎么切片?怎么保证搜到的是当前分支,而且用户有权限看?”

很多录友会回答:“按 512 Token 切,加一点 overlap,再做向量检索。”

这个回答适合原型,不适合真实系统。固定切片会把标题和正文、函数签名和函数体拆开;不记录分支与提交,可能拿旧代码回答;不在检索前做权限过滤,还可能把受限内容带进候选集。

真正要解决的不是“Chunk 设多大”,而是:怎么用小块找准,再按结构拿回完整、当前且有权限的证据。

# 简要回答

  • 长文档按标题、章节、条款建树,代码按类、函数、方法等 AST 节点切分;
  • 子块负责检索精度,父块负责给模型补齐上下文,两者用 parent_id 关联;
  • 代码检索要组合语义检索与关键词检索,符号名、路径和错误码不能只靠向量;
  • 每个块都要携带 repo、branch、commit、路径和 ACL 等元数据;
  • 在线检索先按身份和目标版本过滤,再召回、Rerank、父级扩展和组装 Context。

一句话:检索单位不等于返回单位,相关不等于可用,可用还必须满足完整、当前和有权限。

# 详细回答

# 固定切片为什么在长文档里容易失效?

《RAG切片策略》已经讲过 Chunk 太大和太小的矛盾。长文档会把这个问题继续放大。

一份需求文档通常是“章节 → 小节 → 条款 → 表格”的层级。某个子块里只有“退款周期为 7 个工作日”,但适用范围可能写在父标题“企业版年付客户”里。只返回子块,答案缺条件;返回整篇文档,噪声和 Token 又太多。

所以长文档不能只保存文本,还要保存它在标题树中的位置,例如:

产品手册 / 计费规则 / 企业版 / 退款政策
1

这条路径既能参与检索和 Rerank,也能在命中后帮助系统找到父章节、相邻条款和表格说明。

# 代码为什么不能按字符数硬切?

代码的自然边界不是句号和换行,而是模块、类、函数、方法和语句块。

如果固定切片刚好从函数中间切开,Chunk 里可能只有实现,没有函数名、参数和返回类型;也可能只有调用点,没有被调用函数的定义。向量能判断“语义相似”,却不知道这个片段属于哪个符号。

更合适的做法是先用解析器生成语法树,再按 AST 节点切分。Tree-sitter 官方文档 (opens new window)说明,它可以为源码构建具体语法树,并在文件编辑后增量更新。

工程中通常保留这些信息:

  • 函数或方法签名、注释和函数体;
  • 所属类、模块、文件路径和符号全名;
  • 起止行号、语言、导入关系和被调用符号;
  • 仓库、分支、提交哈希与内容哈希。

AST 负责“不把结构切坏”,但不负责解决所有检索问题。README、配置、SQL、错误日志仍要用对应的结构解析器或文本切分策略。

# Parent-Child怎么兼顾找得准和读得懂?

核心做法是建立两级或多级节点:

  • Child:函数、短条款或小段落,用于 Embedding、关键词召回和 Rerank;
  • Parent:类、章节或完整规则,用于最终返回给模型;
  • Document:文件或整篇文档,只在跨章节任务中按需继续向上扩展。

每个 Child 保存 parent_id,父节点保存在文档存储中。命中 Child 后,不是机械返回整篇文档,而是根据问题取父节点、标题路径、必要的相邻节点。

LlamaIndex 的层级节点说明 (opens new window)也采用粗到细的节点层级:小节点参与检索,在需要时替换或合并为父级上下文。

长文档与代码层级检索

这张图回答的是:长文档和代码如何从结构化建索引,到带版本、权限条件检索,再用父级补齐完整证据。主线不是“切得更细”,而是把精准召回、结构补全和访问边界放进同一条链路。

# 为什么版本和权限必须进入索引?

代码不是一份静态文本。同一路径在 main、功能分支和历史 commit 上可能完全不同。Git 的分支会随提交移动,而 commit 表示确定的快照,相关关系可参考 Git 数据模型文档 (opens new window)。

因此索引至少要保存:

{
  "repo": "payment-service",
  "path": "src/refund/RefundService.java",
  "symbol": "RefundService.apply",
  "branch": "feature/refund-v2",
  "commit": "a1b2c3d",
  "parent_id": "class:RefundService",
  "acl": ["team:payment"]
}
1
2
3
4
5
6
7
8
9

在线查询时,用户问题必须和当前工作区范围一起进入检索:目标仓库是什么、当前分支或 commit 是什么、调用者属于哪个租户和权限组。

先过滤,后相似度召回。 如果先召回再删权限不匹配的结果,受限内容仍可能进入候选缓存、Rerank 服务或调试日志,而且删除后候选数量不足,召回质量也会突然下降。

Elasticsearch 文档级安全说明 (opens new window)也是通过查询限制角色可访问的文档。具体产品可以不同,但原则不变:访问控制要在检索边界生效。

# 在线检索链路怎么跑?

一条可落地的链路通常是:

  1. 从会话或 IDE 获取 repo + branch/commit + user/tenant;
  2. 解析 Query,识别符号名、文件名、错误码和自然语言意图;
  3. 先做版本、路径和 ACL 过滤;
  4. 同时跑向量检索与 BM25,合并候选;
  5. 在 Child 粒度 Rerank,避免大父块稀释相关度;
  6. 根据 parent_id 取父级、标题路径或必要的相邻节点;
  7. 去重并按 Token 预算组装 Context,附带路径、行号和 commit 作为引用。

这里最容易写反的是第五步和第六步。先在小块上排序,再向父级扩展。 如果先把所有 Child 展开成大块再 Rerank,相关信号会被大量父级文本冲淡,延迟也会上升。

# 命中子块后,要不要总是返回整个父块?

不要。

父级扩展是一个预算决策,不是固定动作。一个函数只有 30 行,可以返回整个函数;一个类有 3000 行,就只补签名、字段、目标方法和直接依赖。一个章节只有两页,可以返回完整章节;一个章节几十页,就补标题路径和相邻条款。

可以设置三个门槛:父块最大 Token、允许扩展的层级、相邻节点数量。超过预算时,优先保留定义、约束、输入输出和直接依赖,不要粗暴截断末尾。

# 项目里怎么落地和评估?

先用最小方案建立 Baseline:结构化切分、Child 混合检索、Parent 补全,以及版本和 ACL 前置过滤。不要一开始就加调用图、摘要树和复杂 Agent。

评估集要专门覆盖五类问题:跨小节答案、精确符号查找、同文件不同分支、历史 commit、无权限访问。除了 Recall@K、MRR 和答案质量,还要增加:

  • 父级补全正确率:命中 Child 后是否拿到了正确父节点;
  • 版本错误率:是否引用了目标 commit 之外的内容;
  • 越权召回率:无权内容进入候选的比例,目标必须是 0;
  • Context有效率:进入上下文的 Token 中有多少真正支持答案;
  • 索引新鲜度:代码更新到可检索之间的延迟。

索引更新时用 commit + path + content_hash 判断新增、修改和删除,只重建受影响节点及父子关系。否则每次全量重建,代码库一大,成本和更新延迟都会失控。

# 知识拓展

Q:有了 AST 切分,还需要关键词检索吗?

需要。函数名、类名、错误码、配置键和路径是精确符号,BM25 或符号索引通常比纯向量更稳;自然语言描述和业务意图再交给向量检索。两路召回后统一 Rerank。

Q:Parent-Child 和增加 overlap 有什么区别?

Overlap 只缓解相邻切片的边界断裂,不知道标题、类和函数的真实父子关系。Parent-Child 是显式结构关系,可以跨多个子块补回完整父级,但索引和存储更复杂。

Q:代码依赖是不是应该全部展开进 Context?

不是。调用图可能迅速扩散。先返回目标符号,再按问题补一跳直接依赖;只有测试失败分析、跨模块重构等任务,才逐层扩展并设置深度与 Token 上限。

Q:多个分支会不会让索引膨胀?

会。常见做法是长期保留默认分支和活跃分支,对历史版本按需构建或设置过期策略;相同内容可按内容哈希去重,但版本、路径和 ACL 关系不能丢。

别再把“512 Token + overlap”当成长文档和代码检索的完整答案。

能证明返回的内容找得准、补得全、版本对、权限安全,才算把这套检索系统做完整。

Last Updated: 8/29/2026, 3:48:55 PM

← RAG优化思路:Query改写到Context压缩 Agentic RAG:从传统RAG到智能体检索 →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪