前端转 AI 实战 · 总纲:用「垂直切片 + 螺旋升级」六阶段,从零造一个企业级 RAG 知识库
本文是系列第 0 篇(总纲)。适合读者:有前端基础、想做 AI 应用 / 全栈、希望把东西真正跑起来的同学。
一、为什么要写这个系列
带过几个前端同学入坑 AI 应用开发,发现大家几乎都会卡在同一个地方:知道 RAG 是什么,但不知道怎么从零把它做成一个能跑的东西。
常见的两种失败姿势:
- 姿势一:先啃理论。 花 4~6 周看 Transformer、看向量数据库原理、看各种综述,笔记记了一堆,一行代码没写,两个月后什么都拿不出来。
- 姿势二:一上来就上企业架构。 Day 1 就设计多租户、SSO、审批流、可观测,表结构画了三版,MVP 遥遥无期,最后热情耗尽。
我自己走通之后的结论是:这两种都错在「没有可交付的中间态」。
所以这个系列采用另一条路线——垂直切片 + 螺旋升级:
- 每个阶段交付一个完整可用的增量产品(不是半成品模块)
- 学什么,完全由「这个阶段要实现的功能」倒推
- 早期允许有限重构,但绝不为了「完美架构」阻塞 MVP
说人话就是:先让它跑起来,再让它变好,最后让它变成企业级。
二、这个系列写什么(7 篇目录)
| 篇号 | 标题 | 阶段 | 状态 |
|---|---|---|---|
| 00 | 总纲:六阶段路线全景(本篇) | — | ✅ |
| 01 | P0 地基:不写一行前端,先用 CLI 跑通 RAG 闭环 | P0 | ✅ |
| 02 | P1 MVP:FastAPI + Next.js,做出能演示的知识库 | P1 | ✅ |
| 03 | P2 质量:混合检索、rerank 与 RAG 评测 | P2 | ✅ |
| 04 | P3 工程化:异步入库、权限、审计、可观测 | P3 | ✅ |
| 05 | P4 企业能力:多租户、SSO、审批流、连接器 | P4 | ✅ |
| 06 | P5 产品化:Agent、多模态、私有化、计费 | P5 | 🚧 |
每篇都会把这一阶段的每个步骤拆开写,并且标出 ⚠️ 易错点 和 ✅ 解决方案——这些都是真实踩过的,不是从文档抄的注意事项。
阅读约定:文中所有
⚠️ 易错点都是实战高频坑,紧跟的✅ 解决方案可以直接照抄。代码已脱敏,但结构和参数与真实实现一致。
三、最终会做出什么
一个单租户可演示 → 企业级可用的知识库产品,最终形态:
┌─────────────────────────────────┐
│ Next.js 管理台 + 对话 │
│ 上传 / 文档管理 / 流式问答 │
└────────────────┬────────────────┘
│ HTTP + SSE
┌────────────────▼────────────────┐
│ FastAPI │
│ 鉴权 / 路由 / SSE │
├─────────────────────────────────┤
│ 编排层 Orchestration │
│ ┌───────────┐ ┌────────────┐ │
│ │ 工作流 │ │ 对话流 │ │
│ │ Workflow │ │ Chatflow │ │
│ │ 入库管线 │ │ 问答管线 │ │
│ └─────┬─────┘ └──────┬─────┘ │
│ └──── nodes ────┘ │
├─────────────────────────────────┤
│ services 原子能力 │
│ chunking / embed / retrieve │
└──┬──────────┬──────────────┬────┘
│ │ │
┌────────▼──┐ ┌─────▼───┐ ┌────────▼────┐
│ 元数据库 │ │ 向量库 │ │ LLM / │
│ meta.json │ │ Chroma │ │ Embedding │
│ → Postgres│ │ → Qdrant│ │ (OpenAI兼容)│
└───────────┘ └─────────┘ └─────────────┘
图里的编排层是 P2 才会出现的,P0/P1 阶段 FastAPI 直接调
services。为什么要等到 P2、它到底解决什么问题,第六节专门讲。
而 RAG 的核心链路,从头到尾就这一条,六个阶段都是在这条链路上做加法:
文档 ──切分──▶ chunk ──向量化──▶ 向量库
│
用户提问 ──向量化──▶ 相似度检索 ────┘
│
top-k chunk ──▶ 拼进 Prompt ──▶ LLM ──▶ 带引用的回答
能把这条链路口述清楚,比背下十篇论文有用得多。 这也是 P0 唯一的目标。
四、技术栈(贯穿全程)
| 层 | 选型 | 为什么这么选 |
|---|---|---|
| 前端 | React / Next.js | 前端老本行,直接发挥优势 |
| 后端 | Python + FastAPI | AI 生态在 Python,FastAPI 的类型体验对前端很友好 |
| RAG 框架 | LlamaIndex | 入库 / 检索管线开箱即用,MVP 阶段省时间 |
| 编排(P2 起) | llama_index.core.workflow |
事件驱动、自带会话上下文;已在依赖里,不用自己造 DAG 引擎 |
| 向量库 | Chroma(本地)→ 可换 Qdrant / pgvector | 先本地零依赖跑通,后期再换 |
| 元数据 | meta.json → Postgres(P3 起) |
MVP 别急着上数据库;P3 必须分离 |
| LLM | 云 API(DeepSeek / 通义 / 任意 OpenAI 兼容) | 不折腾显卡,后期可选本地模型 |
| 部署 | Docker Compose | 一键起,方便演示 |
⚠️ 路线级易错点 1:一上来就纠结「选 LangChain 还是 LlamaIndex」「选 Qdrant 还是 Milvus」,选型对比看了三天,代码零行。
✅ 解决方案:MVP 阶段选型不重要,跑通才重要。这套链路的抽象是通的,换框架/换向量库的成本远比你想象的低(P0 里我会把IndexManager单独抽出来,就是为了后面能换)。先用 LlamaIndex + Chroma 跑通,等你真的遇到瓶颈了再谈替换。
五、六阶段路线全景
| 阶段 | 参考时长 | 产品形态 | 这一阶段的核心命题 |
|---|---|---|---|
| P0 地基 | 1–2 周 | CLI:上传 → 切分 → 检索 → 回答 | 建立 AI 开发语感 |
| P1 MVP | 3–4 周 | 可演示的单租户知识库(Web) | 端到端产品闭环 |
| P2 质量 | 3–4 周 | 检索/回答明显更好 + 评测面板 | 让答案「真的对」 |
| P3 工程化 | 3–4 周 | 异步入库、权限、审计、可观测 | 从玩具到工程 |
| P4 企业能力 | 4–6 周 | 多租户、SSO、审批流、连接器 | 从工程到企业级 |
| P5 产品化 | 持续 | Agent、多模态、私有化、计费 | 持续演进 |
下面逐个说清楚:做什么、验收什么、明确不做什么。
P0 地基(1–2 周)
做什么:不碰任何 Web,用两个 CLI 脚本跑通 RAG 全链路。
- Python 实用向:类型标注、Pydantic、
uv包管理 - LLM 基础概念:token、temperature、embedding、chunking
- 向量检索直觉:相似度、top-k、切分质量与回答质量的关系
验收:用 3–5 份自己的文档,能问出「文档里有、模型不该瞎编」的答案;能完整口述 文档 → chunk → vector → retrieve → generate。
明确不做:登录、权限、多格式解析、评测、队列、审核。
详见 [第 01 篇:P0 地基]。
P1 MVP(3–4 周)
做什么:把 P0 的 CLI 包装成产品。
- FastAPI 项目结构、依赖注入、错误模型
- SSE 流式输出(这是前端同学的主场)
- 知识库创建、文档上传(PDF / MD / TXT)、解析状态
- 多轮对话、流式回答、展示引用 chunk
- 文档列表、删除、重建索引
- Docker Compose 一键起
验收:5 分钟演示走通——上传 → 提问 → 带引用回答 → 删掉文档后再问,必须无法引用该内容。最后一条是整个 P1 最容易翻车的验收项。
明确不做:多租户、RBAC、SSO、连接器、复杂 Agent、审核流。
P2 质量(3–4 周)
做什么:让答案从「能答」变成「答得准」。
- 混合检索(向量 + BM25)、rerank
- Query 改写 / HyDE / 多查询
- RAG 评测:忠实度、相关性、上下文召回;自建 Golden Set
- 引用高亮、来源跳转、👍/👎 反馈
- 对话流节点化:新建
orchestration/,把问答链路拆成 classify / rewrite / retrieve / rerank / answer,让两条策略能并存对比(详见第六节)
验收:同一批文档,在自建 Golden Set 上相对 P1 有可量化的提升;能一键切换两条对话流跑同一批题目比分数。
⚠️ 路线级易错点 2:没有 Golden Set 就开始「凭感觉调参」——改了 chunk_size,感觉好像变好了?其实不知道。
✅ 解决方案:进 P2 的第一件事不是接 rerank,是先攒 20~50 条问答对做基线。没有基线,后面所有优化都是玄学。
P3 工程化(3–4 周)
做什么:从「能跑」到「能上线」。
- 异步任务(Celery / ARQ):大文件入库不再阻塞 API,入库链路搬成工作流,事件流直接当进度条
- JWT + 基础 RBAC;知识库级读/管权限
- 结构化日志、请求追踪、token / 费用统计
- Postgres 元数据与向量库分离
- 轻量发布门禁:
draft → published,未发布不参与检索
验收:大文件上传后可以离开页面,回来看进度、失败可重试;无权限用户看不见对应知识库;能画出 API / Worker / DB / Vector / LLM 的边界图。
⚠️ 路线级易错点 3:MVP 用 JSON 文件存元数据很爽,然后一路带到生产,并发写直接丢数据。
✅ 解决方案:JSON store 是有意为之的临时方案,P0–P2 够用(我在 P0 里会给它加线程锁兜底),但 P3 必须迁 Postgres。关键是从一开始就把它抽成MetaStore接口,迁移时只换实现。
P4 企业能力(4–6 周)
做什么:真正的企业级特性。
- 多租户:
tenant_id隔离,租户 A 的库对租户 B 完全不可见 - SSO / OIDC(Keycloak / Authing 本地体验)
- 完整审批流:提交 → 通过 / 驳回 → 发布;待审队列
- ≥1 个外部连接器(飞书 / Notion / 本地文件夹自动同步)
- 编排流配置化:按知识库存一份 JSON,决定这个库用哪些节点、什么参数(不同业务库用不同的解析 / 切分 / 检索策略)
⚠️ 路线级易错点 4(设计层面的大坑):把「审核」做成用户身上的一个布尔字段,比如
user.is_reviewer = true。
✅ 解决方案:审核不是用户标签,而是资源上的权限 + 文档状态机。正确模型是:User ──< Membership >── KnowledgeBase │ role: admin | editor | reviewer | viewer Document.status: draft → pending_review → published / 驳回回 draft权限(
kb:upload/kb:publish/kb:review)挂在知识库成员角色上。用全局布尔字段的话,「张三在 A 库是审核人、在 B 库只是普通成员」这种再正常不过的需求根本表达不了,到时候只能推倒重来。
P5 产品化(持续)
按需选做,但每一项都必须有用户故事和验收标准:
- Agent:多步检索、工具调用、护栏(编排层这时候才真正派上大用场)
- 编排可视化:只读的流程图 + 节点耗时(不做拖拽画布,理由见第六节)
- 多模态:OCR、表格问答
- 私有化:本地模型、离线部署文档
- 质量运营:坏案例回流、回归评测、策略版本管理
- 商业化:配额、计费、多环境
⚠️ 路线级易错点 5:到了这个阶段容易变成「课程收藏家」——看了一堆 Agent 教程,但产品一点没动。
✅ 解决方案:每一项立项前先写一句用户故事和一条验收标准,写不出来就说明现在不需要做它。
六、编排层:工作流与对话流该放在哪
用过 Dify 的同学一定会问:你这套里,像 Dify 那样拖节点的「工作流 / 对话流」在哪?
先说结论:P0 和 P1 里没有,也不该有。 但从 P2 开始,它会长成后端最核心的一层。这里单独拎出来讲,因为这是整条路线上最容易「做早了」和「做过头」的地方。
6.1 两种流,本质是两件事
Dify 分成两套入口不是产品经理拍脑袋,是这两类流的运行模型根本不同:
| 工作流 Workflow | 对话流 Chatflow | |
|---|---|---|
| 触发方式 | 一次性任务 | 多轮会话 |
| 有没有记忆 | 无 | 有(会话变量 + 历史) |
| 输出形态 | 跑完给个结果 | 中途多次流式吐字 |
| 关注的指标 | 吞吐、失败重试 | 首字延迟 |
| 对应到本系列 | 入库链路 | 问答链路 |
6.2 其实你从 P0 起就有两条流了,只是写死在函数里
有意思的地方在于:任何一个 RAG 项目天生就有这两条流,只不过它们是用「代码行的先后顺序」表达的,而不是数据。
[ 工作流 ] ingest(file)
读文件 ─▶ 切分 ─▶ 向量化 ─▶ 写库 ─▶ 更新状态
↑ 一次性、无记忆、可以跑很久、失败要能重试
[ 对话流 ] chat(question, history)
检索 ─▶ 拼 Prompt ─▶ LLM 流式输出 ─▶ 带引用返回
↑ 多轮、有历史、首字要快
编排层要做的事,就是把这两条「硬编码的直线」变成「可组合的节点 + 一份声明」。
对话流这条尤其明显:它现在只有「检索 → 回答」两个节点,而 Dify 对话流最核心的几个能力——问题分类器(闲聊 / 知识库问答 / 拒答)、问题改写(HyDE、多查询)、条件分支(检索为空就别硬答)——一个都没有。巧的是,这几样恰好就是 P2 要补的东西。
6.3 什么时候值得做:P2,不是更早
判断标准很简单:当你开始需要「同一条链路跑出两个版本来对比」的时候。
P2 的验收要求是「策略可切换对比」——朴素检索 vs 混合检索 + rerank,到底哪个在 Golden Set 上更好?如果不节点化,你会在 chat() 里写出这种东西:
if strategy == "hybrid":
...
elif strategy == "hyde":
...
elif strategy == "hybrid_rerank":
...
三个策略之后这个函数就没法看了,而且没法做「A/B 各跑一遍比分数」。节点化之后,一条流就是一份声明:
naive_rag(基线,就是 P1 的行为)
retrieve → answer
advanced_rag(增强)
classify 判断:闲聊 / 知识库问答 / 直接拒答
→ rewrite HyDE、多查询改写
→ retrieve 向量 + BM25 混合检索
→ rerank 重排序
→ [条件分支] 检索结果为空 → refuse
否则 → answer
两条流共用同一批节点,只是组合方式不同。评测时跑同一批 Golden Set,分数一比就知道改进有没有效果。
6.4 放在哪:新开一个目录,services/ 一行都不动
backend/app/
├── services/ # 保持不变,降级为「原子能力」
│ ├── ingest.py
│ ├── retrieve.py
│ └── chat.py # 变成薄封装,老接口不破
└── orchestration/ # ← 新增:编排层
├── events.py # RetrievedEvent / RewrittenEvent / AnswerChunkEvent
├── nodes/ # 原子节点,两种流共用
│ ├── classify.py # 闲聊 / 知识库问答 / 拒答
│ ├── rewrite.py # HyDE、多查询
│ ├── retrieve_node.py # 薄薄包一层 services.retrieve
│ ├── rerank.py
│ └── answer.py
├── chatflows/ # 对话流
│ ├── naive_rag.py # 把 P1 的行为原样搬过来,当基线
│ └── advanced_rag.py # 改写 + 混合检索 + rerank + 拒答分支
└── workflows/ # 工作流
└── ingest_flow.py # 把 P1 的入库链路搬过来
关键是节点只是薄薄包一层 services,所以已有的单测和 P1 的验收一条都不会破。这也是我建议把编排层单开目录、而不是就地改造 services/ 的原因。
6.5 引擎不用自己写
这是最值得省的一笔时间:如果你用 LlamaIndex,编排引擎已经在你的依赖里了。
llama_index.core.workflow 自带 Workflow / @step / Event / Context,装了 llama-index-core 就能直接 import,不需要额外装包。它是事件驱动而不是 DAG,这点对 RAG 反而更顺手:
- 「检索为空就拒答」这种分支,DAG 得画条件边,事件驱动就是
return RefuseEvent()还是return AnswerEvent() Context天生是会话变量容器,正好是对话流需要的stream_events()的输出可以直接怼给 SSE,前端协议不用改
⚠️ 路线级易错点 6:手撸一个 DAG 执行器。两三百行确实能跑起来,而且很有成就感。
✅ 解决方案:跑起来只是第一步。重试、并发、超时、中断续跑、变量作用域,这些一个都逃不掉,最后你会花三周重写一个更差的 workflow 引擎。用现成的,把时间花在节点逻辑上——那才是 RAG 的价值所在。
⚠️ 路线级易错点 7:想把工作流和对话流抽象成同一个引擎、同一个基类。
✅ 解决方案:Dify 自己都是两套入口。共享nodes/,但流的定义各写各的。 强行统一的结果通常是一个谁都读不懂的抽象基类,改一个流会莫名其妙影响另一个。这两者一个要重试和吞吐、一个要记忆和首字延迟,硬凑到一起没有好处。
⚠️ 路线级易错点 8(做早了比做晚了更糟):P0/P1 就急着搭编排层,理由是「反正早晚要做」。
✅ 解决方案:只有两个节点的链路,节点化之后代码量翻倍、可读性下降,收益为零。等到你真的需要「两条策略并存对比」的那一刻再做——那时候你已经知道节点边界该切在哪了。抽象是长出来的,不是设计出来的。
6.6 别做拖拽画布
一定会有人想做可视化编排。给个成本参考:Dify 的画布 + 变量系统 + 调试面板是几万行代码,那是它的产品护城河,不是一个学习项目该碰的东西。
真想要视觉效果,有个成本只有 1/50 的替代方案:做一个只读的流程图展示——把 Python 里定义好的节点关系渲染成图,标上每个节点的耗时。前端同学做这个很快,讲架构的时候效果一样好。
配套的低成本改动是在 SSE 里多发一种事件:
{"type": "node", "name": "rewrite", "status": "done", "elapsed_ms": 120}
前端就能展示「这次回答走了哪些节点、各花了多久」——这就是 Dify 的运行日志。严格说属于 P3 可观测的范畴,但成本极低,建议顺手做了。
6.7 编排能力在六个阶段里的演进
| 阶段 | 编排层的状态 |
|---|---|
| P0 | 无。两条硬编码直线,这是对的 |
| P1 | 无。加了 Web 和 SSE,链路本身没变 |
| P2 | 建 orchestration/,问答链路节点化,naive_rag / advanced_rag 两条流并存对比 |
| P3 | 入库链路搬成工作流,丢给 worker 异步跑,事件流直接当进度条 |
| P4 | 流配置化:按知识库存一份 JSON,决定用哪些节点、什么参数 |
| P5 | 才轮到只读流程图 / Agent 多步编排 |
七、三个贯穿全程的坑
前面按阶段列了 8 个,这里再补 3 个每个阶段都会遇到的:
⚠️ 路线级易错点 9:chat 模型和 embedding 模型混为一谈。很多人选了 DeepSeek 做对话,配了一个
OPENAI_API_BASE就以为万事大吉,结果向量化直接 400 / 401。
✅ 解决方案:DeepSeek 目前不提供 embedding 接口。chat 和 embedding 是两个独立能力,可以来自不同厂商。MVP 阶段最省事的做法是全用一家支持两者的(如通义 DashScope 兼容模式、硅基流动、OpenAI),或者把 chat / embedding 拆成两组配置。这个坑我在 P0 会详细写怎么配。
⚠️ 路线级易错点 10:只跑单元测试就宣布「这个阶段完成了」。
✅ 解决方案:每个阶段的验收都必须是端到端的真实演示(真 Key、真文档、真提问)。单测只保证函数没写错,保证不了链路是通的——我在 P0 就吃过这个亏,单测全绿,一跑真实 Key 直接报模型名不在枚举里。
⚠️ 路线级易错点 11:每周做了很多,但说不清楚「为什么这么选」。
✅ 解决方案:养成每周写一条决策笔记的习惯——不用长,三行就够:遇到什么问题、有哪几个选项、为什么选了这个。这个系列里大量的「为什么」都是从这些笔记里来的。
八、每周节奏建议
如果你能全天投入,建议「4 天做 + 1 天学/复盘」:
| 时间 | 安排 |
|---|---|
| 周一–周四 | 实现当前阶段的下一个可演示切片 |
| 周五 | 补原理 + 把本周的决策写成笔记 |
| 周末(可选) | 录 3–5 分钟 Demo,更新 README |
每周强制交付:① 一个可运行的增量功能;② 一条架构 / 决策笔记;③ P2 起:至少一个自动化测试或评测用例。
九、小结
整个系列的方法论,其实就一句话:
别先学 6 周理论,也别 Day 1 上企业架构。垂直切片、每阶段可演示、把坑记下来。
下一篇 [P0 地基] 会从零开始,不写一行前端代码,用两个 CLI 脚本把 切分 → 向量化 → 检索 → 生成 这条链路完整跑通,并且把我在这一步踩的 37 个坑全部标出来——包括那个让我卡了半天的「模型名不在 OpenAI 枚举里」。
系列文章会陆续更新,有问题欢迎评论区交流。
如果你觉得本文还可以,那就点击一下推荐,让更多人看到吧!
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

浙公网安备 33010602011771号