cc_rag_tutorial

第 1 章:总览——什么是“基于 CC 的外挂 RAG”

1.1 开篇段落:重新定义“外挂”

欢迎来到 基于 CC 的外挂 RAG 实战教程。

你正在使用的 Claude Code (CC) 本质上是一个运行在终端里的代码智能体(Coding Agent)。它不同于网页版的 Claude.ai —— 它能读写你的本地文件、运行终端命令、甚至提交 Git。

但是,当你试图让它接手一个庞大的遗留项目,或者让它基于公司内部未公开的框架写代码时,你会撞上“认知墙”:

  1. 它看不见:它只能看见当前目录下 ls 能列出的文件,而且一旦项目超过几百个文件,它无法全量阅读。
  2. 它记不住:虽然它的上下文窗口(Context Window)很大(如 200k token),但每一轮对话都把几十万字的代码塞进去,既昂贵(Token 费爆炸)又缓慢(首字延迟变高),而且容易导致模型“注意力涣散”。

本章将带你构建一个“外挂大脑”。 所谓的“外挂(Sidecar)”,是指我们不修改 CC 的内核,不把所有文档一次性写死在 Prompt 里,而是搭建一个旁路服务。 当 CC 觉得“这一题超纲了”或者“我需要查阅 Payment 模块的定义”时,它会像通过对讲机呼叫总部一样,调用你的服务,获取精准的情报。

本章目标


1.2 核心架构与设计哲学

1.2.1 为什么是“外挂”而不是“微调”或“全量上下文”?

在工程实践中,我们遵循 “上下文经济学(Context Economics)”

方案 描述 缺点 适用场景
全量上下文 (Context Stuffing) 把所有文档/代码 cat 进对话 贵、慢、干扰推理、有物理上限 小型脚本、单文件修改
微调 (Fine-tuning) 拿私有代码重新训练模型 极其昂贵、更新极慢(无法反映昨天的 commit)、丧失通用能力 行业垂直大模型
外挂 RAG (External RAG) 按需检索,动态注入 需要开发额外的工程组件 中大型项目、企业级知识库

Rule of Thumb #1: 动态加载原则

CC 的上下文窗口是 RAM(内存),你的 RAG 是 SSD(硬盘)。 永远不要试图把硬盘里的东西全塞进内存。只有当前正在运行“进程”(用户的具体问题)所需的数据,才会被调入内存。

1.2.2 端到端数据流详解 (The Anatomy of a Request)

这是一个代码智能体(Agent)特有的 RAG 流程,它比传统的“一问一答”更复杂,因为包含工具调用(Tool Use)

请仔细阅读下方的 ASCII 流程图,这将是你后续开发的心智地图:

      [User Terminal]                       [Your Local/Remote Server]
             |
             v
+---------------------------+       +----------------------------------+
|      Claude Code (CC)     |       |         External RAG System      |
|---------------------------|       |----------------------------------|
| 1. 用户指令:               |       |                                  |
| "怎么用内部的 Auth 库?"    |       |                                  |
|                           |       |                                  |
| 2. 思考 (Chain of Thought)|       |                                  |
| "我没在当前目录看到 Auth,  |       |                                  |
|  我需要检索知识库..."      |       |                                  |
|                           |       |                                  |
| 3. 构造工具调用 (Action)   |------> | 4. 接收请求 (Receive)            |
| tool: `search_docs`       | JSON  |    Query: "internal Auth lib"    |
| query: "internal Auth lib"| HTTP/ |    Filters: {tag: "backend"}     |
|                           | CMD   |                                  |
|                           |       | 5. 检索与召回 (Retrieve)         |
|                           |       |    Vector Search (Embedding)     |
|                           |       |    + Keyword Search (BM25)       |
|                           |       |    --> 得到 Top-50 片段           |
|                           |       |                                  |
|                           |       | 6. 重排 (Rerank)                 |
|                           |       |    根据相关性打分,去重            |
|                           |       |    --> 留下 Top-5 精华片段        |
|                           |       |                                  |
|                           |       | 7. 组装 (Pack Context)           |
| 8. 接收工具返回 (Observation)<----|    格式化为 XML/Markdown         |
| "Found 5 relevant chunks: |       |    Metadata: [File: auth.md]     |
|  1. Auth.login()..."      |       |                                  |
+---------------------------+       +----------------------------------+
             |
             v
| 9. 最终生成 (Synthesis)    |
| "根据文档,你应该使用      |
|  Auth.login(token)..."    |
+---------------------------+

关键环节解析:

  1. Intent (意图):是 CC 决定要检索,而不是用户直接检索。用户可能只是说“报错了”,CC 分析后认为“需要查文档”。
  2. Interface (接口):第 3 步是关键。你需要把 RAG 封装成一个 CC 能理解的 Tool(比如 mcp-server 或一个 CLI 命令)。
  3. Pack (组装):第 7 步极其重要。你不能只返回文本,必须返回元数据(Metadata)。CC 需要知道这段代码来自哪个文件、第几行,以便它能正确引用。

1.2.3 MVP 功能清单:我们要造什么?

要实现上述流程,你需要构建以下四个模块。这也是本教程将带你逐一实现的内容:

  1. Ingestion Engine (摄取引擎)
    • 职责:遍历你的文件夹。
    • 核心难点:如何把 .ts.java 文件切分成有意义的块?如何处理 .pdf 设计文档?如何忽略 node_modules
  2. Vector Store (索引存储)
    • 职责:存储文本的数学表示(Embeddings)。
    • 技术选型:为了轻量化,我们会优先考虑本地向量库(如 LanceDB, Chroma, 或简单的 FAISS+SQLite),不强制依赖昂贵的云服务。
  3. Retrieval Logic (检索逻辑)
    • 职责:把 Query 变成向量,去库里找最近邻。
    • 进阶:实现“混合检索”(关键词+向量),因为有时候 CC 搜的是精确的函数名 getUserByID,向量检索对此可能不敏感。
  4. Interface Layer (接口层)
    • 职责:适配 CC 的协议。
    • 形态:可以是一个简单的 Python 脚本(CLI),也可以是一个标准的 MCP (Model Context Protocol) 服务。

1.3 经验法则 (Rules of Thumb)

在进入具体实现前,请记住这些指导原则:


1.4 练习题 (Exercises)

基础题 (熟悉概念)

Q1. 在基于 CC 的开发流中,“外挂 RAG”与“将文件直接拖入对话框”相比,最核心的架构区别是什么?

参考答案 (点击展开) **答案**: 区别在于 **Pull vs Push** 和 **静态 vs 动态**。 * **拖入文件**是 Push(推)模式,且是静态的。你需要在对话开前预判需要什么文件,并手动塞入。 * **外挂 RAG**是 Pull(拉)模式,且是动态的。CC 在运行过程中,根据任务需求,主动去“拉取”它当时缺失的信息。这使得系统能处理远超窗口限制的数据量。

Q2. 下列哪种数据最不适合存入外挂 RAG 系统?

参考答案 (点击展开) **答案:B**
**解析**:**绝对不要**将高敏感的运行时凭证(Credentials/Secrets)存入 RAG。 1. **安全风险**:向量库通常没有复杂的权限加密。 2. **误泄露**:如果用户问“怎么登录”,RAG 可能会把真实的 Session Token 检索出来喂给 CC,CC 再打印到屏幕上,造成严重的安全事故。

Q3. 为什么我们在数据流中强调“重排 (Rerank)”这一步?直接用向量检索出来的 Top-5 不行吗?

参考答案 (点击展开) **答案**: 向量检索虽然能捕捉语义(如“支付”和“付款”),但在精确度上往往有损失(它可能觉得“支付成功逻辑”和“支付失败逻辑”很像,混在一起)。 **重排 (Rerank)** 是使用一个更精细(通常也更慢)的模型,对召回的粗糙结果进行二次打分。在 RAG 中,Rerank 是提高 Precision(准确率)的最有效手段,能有效剔除“看着像但其实无关”的噪声数据。

挑战题 (架构思考)

Q4. (场景模拟) 你正在使用 CC 修改一个 Python 项目。CC 决定调用 RAG 工具查询 process_order 函数。

参考答案 (点击展开) **方案 1(Ingest 阶段 - 推荐):文件排除** 在建立索引的脚本中,配置黑名单(如 `deprecated/`, `v1/`, `archive/`),直接不索引废弃代码。这是最彻底的。 **方案 2(Ingest/Retrieve 阶段):元数据时间戳过滤** 给每个 Chunk 打上 `last_modified` 时间戳或 `is_deprecated` 标签。在检索时,增加一个过滤条件 `filter={is_deprecated: false}`,或者按时间倒序优先取最新的。 **方案 3(Context Pack 阶段):路径加权** 在组装上下文传给 CC 时,显式保文件路径。并修改系统提示词(System Prompt):"If multiple versions of code exist, check the file path. Prefer 'v2' over 'v1'." 但这种方法不可靠,增加了 CC 的推理负担。

Q5. (系统边界) CC 本身可以执行 grepfind 命令。既然它可以自己去文件系统里搜,为什么我们还要费力气做一个向量化的外挂 RAG?

参考答案 (点击展开) 1. **语义理解能力**:`grep` 只能做精确的关键词匹配。如果你搜 "login",但代码里写的是 "signIn" 或 "authenticate",`grep` 会漏掉。向量 RAG 基于语义,能关联这些概念。 2. **跨文件/跨模态关联**:`grep` 是线性的。RAG 可以把“代码实现”和“Markdown 设计文档”中相关的片段同时找出来,即使它们没有共同的关键词。 3. **效率**:在一个 GB 级的代码库中, CC 反复尝试 `grep` 极其消耗 Token 和时间(Agent Loop 会很长)。RAG 是一次索引,毫秒级查询。

Q6. (数据一致性) 你刚刚修改了本地的一个 utils.py 文件,加了一个新函数。此时你问 CC 怎么用这个新函数。RAG 系统会发生什么?如何解决?

参考答案 (点击展开) **问题**:RAG 索引通常是滞后的(Stale)。如果不更新索引,RAG 依然只知道旧的 `utils.py`,CC 会产生幻觉或说不知道。 **解决方案**: 1. **触发式更新**:利用文件系统监听器(如 `watchdog`),当检测到文件变更时,自动重新计算该文件的 Embedding 并更新向量库。 2. **CC 混合上下文**:CC 能够读取当前打开的文件。策略上,对于“刚修改”的文件,应当依赖 CC 的本地读取能力;对于“未打开/遥远”的文件,依赖 RAG。 3. **手动刷新**:提供一个 `refresh_index` 命令供用户或 CC 调用。

1.5 常见陷阱与错误 (Gotchas)

1. “幻觉型引用” (Hallucinated Citations)

2. “上下文污染” (Context Pollution)

3. “大文件黑洞” (The Large File Black Hole)


下一章预告: 我们将深入 CC 的“大脑皮层”,分析它到底支持哪些扩展接口。是把它做成一个 CLI 工具?还是 MCP 服务?我们将在第 2 章确定你的 RAG 在 CC 生态中的具体落脚点。