不知道你有没有用过 NotebookLM,或者类似的 AI 知识库工具呢?
把几篇学习笔记上传进去,然后问它:“这些笔记里关于 RAG 的内容有哪些,帮我整理一下。”它不只能回答,还能告诉你每段话来自哪篇文章,甚至能把这些内容生成一期播客节目。
第一次用的时候,很多人的反应是:这也太聪明了吧。
但它其实不是“更聪明的大模型”。底层用的 Gemini,和你平时聊天用的没什么区别。真正让它变得不一样的,是大模型外面搭的那几层东西。
这篇文章就把这几层拆开来看。
先建立一个认知:LLM 只做一件事
在拆这五层之前,有一个认知要先建立,否则后面很多设计会看不懂。
LLM 本身极其简单。它只做一件事——接收文本,输出文本。你发给它什么,它就基于此预测接下来最可能出现的内容,然后一个字一个字地往外吐,直到生成完毕。
# 大模型 API 的接口长这样,无论哪家都大同小异
response = llm.chat(
model="gpt-4",
messages=[
{"role": "system", "content": "你是一个学习助手。"},
{"role": "user", "content": "帮我总结上周写的三篇学习笔记"},
]
)
# 文本进,文本出。就这么简单。
它不知道你上周写了什么,不记得上一次对话,不会主动去翻你的笔记,也不会调用任何外部工具。
LLM 的知识在训练时就冻结了。它不知道你的个人文档,不知道今天发生的新闻,不知道你昨天问过它什么。
这不是缺陷,是设计。一个专注预测文本的模型,把这件事做到极致。
但这条局限,直接解释了为什么需要在它外面搭五层。
一个请求的完整旅程
还是用那个问题:帮我总结一下我上周写的三篇学习笔记。用户在聊天框输入这句话,点击发送。
对前端工程师来说,这个动作太熟悉了——
监听事件、收集输入、发一个 POST 请求。但接下来发生的事,和我们以前做的业务接口完全不同。
这个请求要经过五层,才能把回答送回到用户面前。
第一层:前端
收集用户输入,把请求发给后端,然后等待。
大模型是流式输出的,回答不是等全部生成完再一次性返回,而是一小段一小段地推送过来,前端负责拼接渲染。这就是 AI 产品里常见的打字机效果。
// SSE 流式响应,每次推送一小段文本
// 第1次:{ text: "帮" }
// 第2次:{ text: "帮你" }
// 第3次:{ text: "帮你总" }
// 前端拼接每次收到的内容,视觉上就是打字机效果
eventSource.onmessage = event => {
const chunk = JSON.parse(event.data)
appendToUI(chunk.text)
}
第二层:后端 API
整个链路的调度中心。本质上它就是一个普通的后端服务,可能是 Node.js 接口,也可能是 Java 接口,只不过它对外直接面向前端,负责接收请求、做鉴权、决定这次要走哪条路。
职责一:鉴权
// 收到请求,先验证身份
const user = await verifyToken(req.headers.authorization)
if (!user) return res.status(401).json({ error: '未授权' })
职责二:维护对话历史
// 从存储里取出这个用户的历史对话
const history = await getSessionHistory(sessionId)
// 把当前问题追加进去
history.push({ role: 'user', content: message })
// LLM 回答后再追加,下次调用时继续带上
history.push({ role: 'assistant', content: reply })
LLM 每次被调用都是全新的,它不记得之前聊过什么。你以为的「记忆」,其实是后端把每一轮对话存起来,下次调用时手动塞进请求里。 记忆不在 LLM 里,在后端。
职责三:路由判断
// 有知识库就走 RAG,没有就跳过
if (user.hasKnowledgeBase) {
context = await searchKnowledgeBase(message) // 触发第三层
}
// 不是 AI 在决定,是这里的 if/else 在决定
走哪条路不是 AI 在动态决策,是开发者提前写好的逻辑:这个功能有没有关联知识库?有,就走第三层;需不需要调用外部工具?需要,就走第五层。说白了就是代码里的 if/else。
第三层:知识增强层(RAG)
这一层在有知识库的场景下才会介入。NotebookLM 能回答关于你上传文档的问题,靠的就是这层。
RAG 是给 LLM 配眼睛——让它能看到你的文档,否则它只知道训练时学过的东西。
具体怎么做?你的笔记文档在上传时会被提前处理:切成小块,然后调用 Embedding API(比如 OpenAI Embeddings 或 Google 的向量化服务)把每一块转成一串数字,存进向量数据库。
用户提问时,这个问题同样被向量化,然后拿着这串数字去数据库里找“最接近”的几个片段。
为什么要把文字变成数字?
因为计算机不擅长直接判断两句话意思是否相近,但擅长计算数字之间的距离。向量化就是把语义变成可以计算的形式。
检索到的相关片段,最终会被拼进发给 LLM 的请求里,作为它回答的依据。
第四层:LLM 调用层
这一层本质上也是后端服务的一部分,只不过它不对外,专门负责和大模型通信。
第二层把任务交过来之后,这一层做一件事:把所有材料组装成一个完整的请求,发给大模型 API。
async function callLLM(history, context) {
const messages = [
{ role: 'system', content: '你是学习助手' },
// 来自第二层:对话历史
...history,
// 来自第三层:RAG 检索结果(有知识库时才有)
...(context ? [{ role: 'system', content: `相关笔记:\n${context}` }] : []),
]
// 调用大模型 API,文本进文本出
return await llm.chat({ messages })
}
用户以为只发了一句话,LLM 收到的其实是这整包内容——历史对话、检索到的笔记片段、当前问题,全部拼在一起。
第二层和第四层的边界不是物理上的——小项目里它们可能在同一个服务里,大项目里会拆成独立服务。
但不管怎么部署,职责是分开的:第二层对外面向前端,第四层对内面向大模型 API。
第五层:工具执行层(Agent)
NotebookLM 里有一个「生成播客」功能:你上传几篇文章,它能把内容转成两个人互相对话的音频节目。
这个任务光靠 LLM 是完不成的。生成台词 LLM 能做,但把台词真正转成音频文件,它没有这个能力,需要借助外部工具才能完成。这就是第五层存在的原因。
Agent 是给 LLM 配手脚——让它能调用真实函数做事,否则它只能说话。
先说清楚 Agent 到底是什么。
它不是一个独立的产品或工具,而是一个能 自主决策、循环执行 的系统:LLM 判断下一步要做什么,后端去真正执行,把结果告诉 LLM,LLM 再判断下一步,直到任务完成。
这个 判断→执行→拿到结果→再判断 的循环,就是 Agent。
用 NotebookLM 的「生成播客」功能来理解。
LLM(比如 NotebookLM 底层的 Gemini)先把文章内容转成两个人对话的播客台词,写完之后系统调用音频合成工具把台词转成声音,最后把音频文件交给用户。
Agent 把这个多步骤的过程自动串起来——
LLM 充当大脑,负责每一步“接下来该干什么”;
工具调用是它的手,负责真正去执行;
LLM 本身只能输出文字,它输出的是一个指令信号,后端捕获这个信号再去真正执行。
回答经过 LLM 调用层生成,后端 API 层转发,最终回到前端,逐步渲染给用户。
Prompt 是这五层共用的语言
这里要先说清楚一件事:这里说的 Prompt,不是你在聊天框里打的那句话。
用户输入的“帮我总结上周的笔记”只是 Prompt 的一小块原料。
LLM 调用层在调用大模型 API 之前,会把很多东西拼在一起:
系统指令(告诉 LLM 它的角色和行为规范)、用户的问题、之前几轮的对话历史、RAG 检索到的相关笔记片段。
把这些东西统一组装成一个完整的文本包,这整包内容才是真正发给 LLM 的 Prompt。
// 发给 LLM 的不是一句话,而是拼好的完整文字请求
messages = [
'系统指令:你是学习助手', // 开发者写死
'历史对话:RAG 是什么?/ 是检索…', // 来自后端 API 层
'笔记片段:向量化是把文字变成数字…', // 来自知识增强层
'当前问题:帮我总结上周的三篇笔记', // 用户输入
]
// LLM 只能读文字,看不到数据库、看不到文件
// 所有信息都必须先变成文字,拼进这个请求里
Prompt 是 LLM 调用层和大模型之间的唯一语言。
不管是历史记忆、检索结果还是工具执行的结果,所有信息要传给 LLM,都必须先被翻译成文字,拼进这个请求里。LLM 看不到数据库,看不到文件系统,它只能读到这些文字。
这也解释了为什么“怎么组装 Prompt”在整个链路里这么重要。每一层往里塞什么、怎么表达,直接决定了 LLM 最终能不能给出好的回答。
读完之后,试着回答这三个问题
读完这篇文章,试着不看上面的内容,用自己的话回答这三个问题:
你跟 AI 聊了半天,可是打开新窗口,它又变成了陌生人。为什么 AI 没有记忆——它的“记忆”到底存在哪里?
你把一份 PDF 上传给 AI,它能准确回答里面的内容。但换一个没有上传功能的 AI 问同样的问题,它却一无所知。同样是大模型,差距在哪?
明明只在聊天框打了一句话,AI 却能结合你的历史对话、文档内容一起回答。大模型实际收到的,远不止你输入的那几个字——那还有什么?
如果这三个问题都能说清楚,说明你对 AI 应用是怎么运作的已经有了初步的认识。
本文介绍的这五层是个起点,接下来我会逐层拆开来写——从流式输出到 RAG 检索,再到让 AI 真正能调用工具做事。每一块都有自己的原理和坑,慢慢来。
下一篇我们就从最直观的现象入手:那个逐字出现的打字机效果,是怎么来的?
这里是AI应用开发系列,本文是整个系列的入门地图。
接下来我会把这条链路上最值得搞清楚的东西一块一块写出来——比如流式输出、文档检索、对话记忆、工具调用、多步骤任务编排等等,一直到工程化落地。希望每读一篇,都能让你对这条链路多一分真实的理解。
如果你也在走这条路,欢迎分享或关注微信公众号前端 Fusion,我们一起学习进步吧。💪