晨光里的AI
被绿色植物覆盖生长的白色机械臂,背景是柔和的墨绿色

动手落地AI

动手落地AI:我的第一个四行代码构建RAG应用

用 LlamaIndex 四行代码跑通第一个 RAG 应用,并逐行拆解这四行背后的加载、切片向量化、检索策略与生成合成。

Written by 晨旭发布于 约 4 分钟同步发布

TL;DR

过去我对 RAG 的理解一直停留在架构图上,知道要有数据处理、向量数据库、检索生成,但真正参与项目时总有隔靴搔痒的感觉。 这周我跟着教程亲手写出了第一个 Naïve RAG 应用,发现在 LlamaIndex 下它只有四行代码。 这篇文章逐行拆解这四行分别对应 RAG 的哪个核心组件、每行背后藏着哪些可调参数, 以及从能跑的 Demo 到能商用的产品之间,还差哪些工作。

目录

在很长一段时间里,我对 RAG 的理解停留在架构图上:我知道要有数据处理、要有向量数据库、要有检索生成。

但在真正参加一个 AI 项目开发时,我就会有一种隔靴搔痒的感觉。不懂代码逻辑,这似乎成了我深入理解 AI 边界的最大阻碍。

这周,我做了一个决定:打破这个边界。我跟着教程,亲手用 Python 写出了我的第一个 RAG 应用(Naïve RAG 应用)。

曾经以为隔着座山的 RAG 开发,原来只隔着这四行代码。今天这篇文章,我想通过这四行代码,解剖 RAG 的真实运作机理。

见证奇迹的四行代码

如果我不亲手去尝试,我不敢相信,传说中复杂的 RAG 系统,在 LlamaIndex 这个框架下,可以被浓缩到如此极致:

# 1. 加载数据
documents = SimpleDirectoryReader("./data").load_data()
# 2. 构建索引(切片 + 向量化 + 存储)
index = VectorStoreIndex.from_documents(documents)
# 3. 构建查询引擎(检索策略)
query_engine = index.as_query_engine()
# 4. 提问并生成
response = query_engine.query("晨光的名字是什么")

但我们不能只看到热闹。这四行代码,其实分别对应了 RAG 架构中四个最核心的组件。接下来,让我们逐行拆解。

第一行:数据的入口

documents = SimpleDirectoryReader("./data").load_data()

这一行代码在做什么?它在把我们人类能看懂的 PDF、Word、TXT,变成机器能处理的对象。

技术拆解SimpleDirectoryReader 是 LlamaIndex 的搬运工。它不仅是读取文件,更是把非结构化的数据标准化。

Garbage In, Garbage Out:在实操中我发现,这行代码虽然简单,但也是最容易翻车的地方。如果你喂给它一个排版复杂的 PDF(比如双栏论文或带有复杂表格的财报),它读出来的可能是一堆乱码。这让我深刻理解了:

RAG 产品的护城河,往往不在模型端,而在数据处理端。谁能把复杂文档解析得更干净,谁的 RAG 效果就更好。

第二行:构建大脑(Indexing)

index = VectorStoreIndex.from_documents(documents)

这是含金量最高的一行代码。它在后台悄悄完成了三件大事:Chunking(切片)、Embedding(嵌入)和 Storage(存储)。

技术拆解

  1. 切片:它把长文档切成一个个小块(Node),就像把一本书撕成一页页笔记。
  2. 向量化:它调用 Embedding 模型(如 OpenAI 或 BGE),把这些文字片段变成一串串数字(向量)。
  3. 存储:它把这些向量存进内存或向量数据库中,建立索引。

成本与效果的权衡:这里有一个关键参数值得关注——chunk_size(切片大小)。

  • 切得太碎?语义不连贯,模型看不懂。
  • 切得太大?包含噪音多,而且检索一次消耗的 Token 多,成本飙升。

这行代码背后,其实是我们在做检索颗粒度和 Token 成本之间的博弈。

第三行:定义检索策略(Retrieval)

query_engine = index.as_query_engine()

这一行定义了系统怎么找答案。

技术拆解:默认情况下,它采用的是向量相似度检索。当用户提问时,系统会把问题也变成向量,然后去数据库里计算距离,找出最接近的几个片段。

Top_K 的艺术:这里隐藏着一个参数 similarity_top_k(默认为 2),意思是找出最相似的 2 个片段给大模型。

  • 如果是做法律咨询,可能需要把 K 调大(比如 5),确保信息不遗漏(高召回);
  • 如果是做闲聊,K 小一点(比如 1)可能反应更快。

需要根据业务场景来定义这个 K 值。

第四行:生成回答(合成)

response = query_engine.query("你的问题...")

最后这一行,才是大模型真正登场的时刻。

技术拆解:这一步发生了什么?框架在后台做了一个「Prompt 拼凑」的工作。它把第三步检索到的知识片段和你的问题,填入到一个预设的 Prompt 模板中:

请基于以下背景信息:(检索到的片段),回答用户的问题……

RAG 真相:RAG 并不是大模型学会了知识,它只是在做一场开卷考试。它的本质是:检索系统 + 阅读理解系统。

从 Demo 到 Product:四行代码之外的世界

虽然四行代码就能跑通 Demo,但通过这次学习,我更清醒地认识到,要把它变成一个可商用的产品,还需要做多少工作:

  1. 数据持久化:Demo 里的索引在内存里,程序一关就没了。做产品必须引入 FAISS 或 Milvus 等向量数据库,把知识存下来。
  2. 复杂解析:简单的 Reader 搞不定表格,我们需要引入 LlamaParse 或 MinerU 这样的高级解析工具。
  3. 效果评测:不能靠肉眼看回答好不好,需要引入自动化评测机制。

写在最后

这次手搓代码的经历,对我来说是一次视角的重构。

以前看 RAG,我看的是架构图上的一个个方框;现在看 RAG,我看到的是一个个可调节的参数,是一行行数据流动的逻辑:

解析器 → 切片策略 → 向量数据库(FAISS)→ Embedding 模型 → 检索策略 → 生成模式

这每一个环节,都是可以优化的战场。

这一次手搓代码的经历,让我对 AI 产品有了全新的掌控感。不要被代码吓倒——在 AI 时代,代码正在变得越来越像自然语言。

行动是缓解焦虑的唯一解药。哪怕只写四行代码,也感到自己好像比昨天更强了一点。

核心结论

标注「判断」「假设」的是我的看法而非事实;标注「已推翻」的保留在这里,不删除。

  • LlamaIndex 把 RAG 浓缩成四行代码,但每一行背后都是一片可以优化的战场。#

    判断

  • RAG 产品的护城河往往不在模型端,而在数据处理端:谁能把复杂文档解析得更干净,谁的效果就更好。#

    判断 · 把握中等

  • chunk_size 是检索颗粒度与 Token 成本的博弈,similarity_top_k 要按业务场景定。#

  • RAG 不是大模型学会了知识,它只是在做一场开卷考试:检索系统 + 阅读理解系统。#

  • 从 Demo 到 Product,还差数据持久化、复杂文档解析和自动化评测这三件事。#

    判断 · 把握中等

引用本文

晨旭,《动手落地AI:我的第一个四行代码构建RAG应用》,晨光里的AI,2025-11-22

[晨旭:《动手落地AI:我的第一个四行代码构建RAG应用》](https://chenxu.xin/writing/first-rag-in-four-lines)