我用 Python 从零开始构建 RAG 以便深入理解它

我在生产环境中使用 LangChain 长达六个月。但我无法解释它是如何工作的。我不知道为什么选择特定的指标,也不知道文本是如何变成向量的。这个库隐藏了底层的逻辑。

为了解决这个问题,我删除了框架。我使用 500 行纯 Python 代码从零开始编写了一个 RAG 流水线。

以下是我通过手动构建技术栈所学到的经验。

黑盒问题

当你使用高级库时,你会失去控制权。我曾看到模型产生幻觉或给出错误的引用。我无法判断错误是出在分块器(chunker)、嵌入模型(embedding model)还是提示词(prompt)上。

当你亲自动手构建时,每一层都是可检查的。你可以打印发送给 LLM 的确切分块。你可以清楚地看到句子是在哪里断开的。

RAG 的五个层级

RAG 不是一种算法。它是五个不同的过程堆叠在一起:

  • 分块 (Chunking):决定如何拆分文本。
  • 嵌入 (Embedding):将文本转化为数学表达。
  • 检索 (Retrieval):寻找正确的片段。
  • 提示词构建 (Prompt Construction):告诉模型该如何表现。
  • 生成 (Generation):获取最终答案。

构建过程中的教训

  1. 分块是最重要的步骤 大多数教程都会跳过这一步。如果你不使用重叠(overlap),你就会丢失边界处的上下文。我使用了带有字符级重叠的滑动窗口。这确保了模型能够看到两个分块之间的联系。

  2. 距离度量至关重要 我花了几个小时来调试糟糕的搜索结果。问题不在于数据,而在于度量标准。ChromaDB 默认使用 L2 距离。对于语义搜索,你需要余弦相似度 (Cosine similarity)。仅仅一行代码就改变了一切。

  3. 提示词需要约束 LLM 是一个补全器,而不是先知。如果你问一个模糊的问题,它会编造答案。我学会了使用严格的拒绝模板。我告诉模型:“如果上下文中不包含答案,请说你不知道。”这使幻觉率从 40% 降到了 5%。

  4. 批量处理请求 每个分块发送一个 HTTP 请求太慢了。批量发送要快得多。这允许本地模型进行流水线化作业。

  5. 自底向上进行测试 不要在最后才写测试。先测试你的分块器。然后测试你的嵌入器。接着测试你的存储器。如果你最后才测试,你测试的将是 Bug 而不是逻辑。

如果你觉得并不真正理解你的 AI 技术栈,那就亲自动手构建它。代码不是目标,思考才是目标。

Source: https://dev.to/avinash_zala_1c6f5e7c4af9/i-built-rag-from-scratch-in-python-to-understand-it-heres-what-i-learned-33kf

Optional learning community: https://t.me/GyaanSetuAi