LLM与AI智能体完全指南 - 从单词如何变成词元,到智能体如何为你预订航班
这份指南适合谁?任何希望深入理解现代AI(而不仅仅是使用它)的人。工程师、好奇的学习者,以及那些想要了解流行术语背后“为什么”的面试候选人——所有内容都集中在一处,用通俗易懂的英语呈现。
目录
- 宏观图景:什么是LLM?
- 第0步:分词——将文字转化为数字
- 第1步:嵌入——赋予数字意义
- 第2步:位置编码——教会模型词序
- ️ 第3步:注意力机制——词语如何相互交流
- 第4步:多头注意力——同时拥有多个视角
- ️ 第5步:多层结构——走向更深层次
- 第6步:前馈网络——知识存储之处
- 第7步:解码——将数字变回文字
- ⚡ KV缓存——让一切变得实用的速度技巧
- Transformer:整合所有组件
- LLM如何被训练
- ️ 微调:教老模型新把戏
- ✍️ 提示工程:智能地与模型对话
- RAG:赋予模型记忆
- ️ 向量数据库:意义的文件柜
- AI智能体:从回答问题到采取行动
- 多智能体系统:AI之间的团队协作
- 评估:如何知道它真的有效?
- 生产工程:交付不会崩溃的AI
- ️ 安全与保障
- ️ 心智模型:一切尽在一张图中
- 缩放定律——为什么模型大小并非一切
- ️ 多模态——当Token不仅仅是文字
- 知识蒸馏——教小模型发挥超常实力
- 结构化输出生成——保证输出格式
- 长上下文挑战
- 将护栏作为基础设施
- 基准测试——如何正确解读它们
- ⚖️ 宪法AI与RLAIF——AI教AI
1. 宏观图景:什么是LLM?
大型语言模型(LLM)是一种机器,其基本任务只有一个:
根据已有的内容,预测接下来会出现什么。
就是这样。ChatGPT、Claude、Llama——它们的核心都在做同一件事:接收一个词序列,然后逐个词地生成最有可能的后续内容。
神奇之处在于,从这样一个简单的目标出发,通过在海量文本上进行训练,某种能够推理、编程、翻译、总结并进行对话的能力涌现了出来。
要理解这其中的原理,我们需要追踪一个句子在模型中的完整旅程。让我们用这个句子:
“Go to the moon”
我们将追踪从你输入这句话到模型吐出下一个词的每一个步骤。
2. 第0步:分词——将文字转化为数字
计算机理解的是数字,而不是字母。在进行任何其他操作之前,文本会被分解成token——模型所操作的原子语言单位。
Token并不总是完整的单词。它们通常是子词单元:
“unbelievable” → [“un”, “believ”, “able”]
“tokenization” → [“token”, “ization”]
“Go to the moon” → [“Go”, “ to”, “ the”, “ moon”] ← 4个token
最常见的算法是BPE(字节对编码):从单个字符开始,然后合并最频繁出现的字符对,直到拥有大约30,000到100,000个单元的词汇表。这使得模型可以通过将罕见词分解成熟悉的部分来处理它们。
为什么这在实践中很重要:
- LLM的成本和上下文限制是以token为单位计算的,而不是单词
- 特定领域的术语(医学术语、代码标识符)通常会被分割成许多token → 成本更高,有时还会影响质量
- 英语大约每词1.3个token;其他语言通常使用更多
每个token通过一个查找表映射到一个整数ID:
“Go” → 5002
“ to” → 264
“ the” → 287
“ moon” → 9230
3. 第1步:嵌入——赋予数字意义
Token ID(5002, 264, 287, 9230)只是任意数字——它们无法向模型传达任何关于意义的信息。数字5002并不能表明“Go”是一个暗示移动的动词。
嵌入解决了这个问题。每个token ID在一个学习到的表格(称为嵌入矩阵)中被查找,并替换为一个包含数百或数千个浮点数的向量。可以把向量中的每个数字看作是衡量意义的一个不同维度。
一个简化的三维示例:
Token [是动作吗?] [与空间相关吗?] [是具体的吗?]
“Go” 0.92 0.12 0.60
“moon” 0.05 0.98 0.85
“love” 0.30 0.02 0.10
真实的嵌入有4,096个或更多维度,能够捕捉极其细微的关系。关键特性是:意义相近的词在这个高维空间中会彼此靠近。
- “car”和“automobile” → 彼此靠近
- “king”减去“man”加上“woman” ≈ “queen” → 著名的词向量算术
此时,我们4个单词的句子变成了4个向量,每个向量的长度是4,096(或模型的嵌入维度)。
4. 第2步:位置编码——教会模型词序
这里有一个微妙但关键的问题:注意力计算是不考虑顺序的。
如果你把“dog bites man”打乱成“man bites dog”,一个朴素的注意力计算会产生完全相同的结果——相同的词,相同的向量。但这两个句子的意思完全不同。
解决办法是位置编码:在将嵌入输入模型之前,我们添加一个向量,该向量编码了每个token在序列中的位置。
final_input[i] = embedding[i] + position_vector[i]
现代LLM使用RoPE(旋转位置编码):它不是添加一个固定值,而是将Query和Key向量旋转一个与token位置成比例的角度。这优雅地编码了相对距离——模型学习到“moon”距离“Go”有3个位置——并且它能够更好地泛化到比训练时见过的更长的序列。
结果是:同一个词在位置1和位置10会产生不同的向量,因此模型始终知道每个词在哪里。
5. ️ 第3步:注意力机制——词语如何相互交流
这是一切的核心。注意力机制回答了这个问题:对于句子中的任何一个词,它应该最关注哪些其他词?
图书馆搜索类比
想象一个图书馆系统:
- 你带着一个Query(你的搜索请求)走进去:“我需要关于快速奔跑动物的信息”
- 每本书的书脊上都有一个Key(对其内容的摘要):“大型猫科动物:速度与捕猎”
- 每本书还有Value(里面的实际内容)
图书管理员将你的Query与每一个Key进行比较,评估每本书的相关性得分,然后给你一份按相关性加权后的阅读清单。你主要吸收得分高的书(Values),并略读其余部分。
在数学上:Q, K, V
对于每个token,模型通过将嵌入乘以三个学习到的矩阵来创建三个向量:
Q (Query) = embedding × W_Q ← “我在找什么?”
K (Key) = embedding × W_K ← “我包含什么?”
V (Value) = embedding × W_V ← “我持有何种信息?”
矩阵W_Q、W_K、W_V是在训练过程中学习到的——经过数百万次梯度下降步骤,教会模型如何将嵌入投影到有用的Query/Key/Value空间。
注意力公式
Attention(Q, K, V) = softmax(QK^T / sqrt(d_k)) V
用通俗易懂的英语分解它:
第1步 — 评分:Q × K^T
将每个token的Query向量与所有其他token的Key向量相乘(点积)。结果大意味着“高度相关”。单词“cheetah”和单词“fast”会一起得到非常高的分数。“Cheetah”和“the”会得到非常低的分数。
第2步 — 归一化:÷ √d_k 然后 Softmax
用Key维度的平方根做除法,使分数保持在稳定范围内。若不如此,巨大的点积会将softmax推向饱和区,导致梯度消失、学习停滞。随后应用Softmax,将每个token的分数转化为总和为100%的百分比。这些就是注意力权重——表示每个token应"关注"其他token的程度。
第三步——提取:× V
将每个注意力权重与对应的Value向量相乘并求和。这为每个token生成一个更丰富的新向量——它现在包含整个句子的加权混合摘要,权重由相关性决定。
代词指代示例
在句子"The cheetah chased its prey across the grassland; it ran very fast."中:
当处理"it"时,模型:
- 创建Query:"我是代词——我指代谁?"
- 检查每个Key:"cheetah"发出信号"我是可以奔跑的动物名词"
- 给"cheetah"打出高分,"prey"和"grassland"分数低得多
- 主要吸收"cheetah"的Value
- "it"的结果向量现在包含它指代cheetah的理解
这就是突破所在。无论序列中两个词相隔多远,注意力都能一步直达连接它们。之前的架构(RNN)必须通过中间每个词传递信息,导致信息逐渐丢失。
因果掩码——模型为何不能窥视未来
对于文本生成的LLM有一条关键规则:处理某个token时,模型只能关注它之前的token,绝不能关注之后的。否则它会通过"偷看"本应预测的答案来"作弊"。
这通过因果掩码(也称掩码自注意力)实现:在softmax之前,所有连接当前token与未来token的分数都被设为−∞,因此其注意力权重变为0。
"Go to the moon"中"the"的注意力分数:
Go → ✓ 允许
to → ✓ 允许
the → ✓ 允许(自身)
moon→ ✗ 被掩码(未来token,权重强制为0)
这正是使模型成为"仅解码器"和因果模型的原因。它还有两个重要后果:
- 预填充阶段(读取你的提示):所有token并行处理,但每个token仍然只能看到其左侧的token。此时整个提示的K、V向量被一次性计算出来。
- 解码阶段(生成):每个新token会关注所有之前的token。由于过去的内容从不改变,这些K、V向量可以被缓存并复用——这就是KV缓存的基础(第10节)。
6. 第四步:多头注意力——同时拥有多个视角
一次注意力计算只提供一个视角。但语言具有多重同时存在的关系:语法关系、语义关系、空间关系、时间关系、指代关系。
多头注意力并行运行多次注意力计算,每次专注于不同类型的关系。
工作原理
模型不采用单个大型W_Q、W_K、W_V,而是将嵌入维度拆分为H个较小的部分,并在每个部分上独立运行注意力:
头1:专攻代词/名词指代
头2:专攻动词-主语关系
头3:专攻空间/位置上下文
头4:专攻时间/因果关系
……(实际使用32或64个头)
每个头可以自由学习任何有助于模型的关系。所有头并行运行后,它们的输出被拼接并投影回原始维度:
MultiHead(Q,K,V) = Concat(head₁, head₂, ..., headₕ) × W_O
在我们的句子中:当处理"Go to the moon"中的"moon"时:
- 头1可能注意到"moon"与"to"相关(目的地关系)
- 头2可能将"moon"与"Go"联系起来(移动的对象)
- 头4可能将"moon"归类为天体而非姓氏
拼接后的结果是一个同时携带所有这些视角的单一向量。
7. ️ 第五步:多层结构——向更深层推进
单次注意力操作只能捕捉表层关系。深层理解需要堆叠多个层。
可以将其类比为企业层级:
层 学习内容
第1-2层 基本语法:哪些词是动词、名词、主语
第3-10层 共指关系、短语级语义:"it" → "cheetah"
第11-20层 语篇结构、主题连贯性
第21-32+层 抽象推理、语气、言外之意、世界知识
经过第1层的多头注意力后,每个token的向量变得更丰富——现在编码了来自邻居的一些上下文。第2层接收这些增强后的向量,再进行一轮注意力计算,构建更深层的关系。以此类推。
现代模型通常有32到96层(更大的前沿模型层数更高;GPT-4等闭源模型的具体数量未公开)。每层都有自己独立的W_Q、W_K、W_V矩阵(自己的"头团队")和KV缓存的独立部分。
关键洞察:层数越多=模型能表示越抽象的概念。浅层模型知道"cheetah"和"fast"共现;深层模型理解原因,并能在新情境中进行推理。
残差连接("快捷高速公路")
当层数达到32+时,出现一个关键工程问题:训练期间,误差信号(梯度)必须反向流经所有32层。它们往往会指数级衰减——到达第1层时几乎为零。第1层停止学习。这就是梯度消失问题。
解决方案是残差连接:每层将其输出加到输入上,而不是替换输入:
output = LayerNorm(input + AttentionOutput(input))
这创建了"快捷高速公路",梯度可以绕过某些层直接流向网络早期部分。这使得训练非常深的网络成为可能。
层归一化——保持数值稳定
你在上面的公式中看到了LayerNorm。当向量经过数十层时,它们的值可能变得非常大或非常小,从而破坏训练稳定性。归一化在每一步将它们重新缩放到稳定范围。
有两种类型,选择很重要:
- 批归一化跨批次样本进行归一化(广泛用于视觉/CNN)。当序列长度变化时它会失效——而语言中序列长度总是变化的(一个句子3个token,下一个句子500个)。
- 层归一化跨单个token的特征进行归一化,独立于其他token或批次大小。这使其对变长文本具有鲁棒性。
这就是Transformer使用LayerNorm而非BatchNorm的原因。(现代LLM通常使用更轻量的变体RMSNorm以提高速度。)
8. 第六步:前馈网络——知识存储之处
多头注意力连接token之后,每个Transformer块中还有一个组件:前馈网络(FFN)。
注意力处理token间关系,而FFN处理token内部处理。在token通过注意力从邻居收集上下文后,FFN通过两个线性层(中间带有非线性激活函数)处理这个增强后的向量:
FFN(x) = activation(x × W₁ + b₁) × W₂ + b₂
FFN的宽度通常是注意力维度的4倍——这种大规模扩展使其能够表示复杂的非线性变换。
它实际做什么?
如果说注意力是模型寻找相关信息的方式,那么FFN就是它存储和应用事实知识的地方。研究表明,FFN中的特定神经元会为特定事实关联而激活:
- "Paris is the capital of ___" → 某些神经元为法国-巴黎关联激活
- "H₂O is ___" → 不同神经元编码水的化学式
FFN(前馈网络)是模型存储世界知识的地方。这就是为什么单纯增加参数(更宽/更深的FFN)就能提升模型的事实性知识。
混合专家模型(MoE)—— 无需付出代价的规模扩展
这里有个问题:FFN占据了模型的大部分参数,而扩大FFN会使每个token的处理成本更高。混合专家模型打破了这种权衡。
MoE层不是使用一个巨大的FFN,而是包含多个较小的"专家"FFN(例如8个或64个),外加一个小型路由网络。对于每个token,路由器只选择最相关的1-2个专家激活,其余专家保持休眠状态。
Token → 路由器 → 选择专家#3和专家#7(共64个)→ 合并输出
结果:模型可以拥有数千亿的总参数(巨大的知识容量),而每个token只激活其中一小部分(运行成本低廉)。这就是Mixtral、DeepSeek以及据称GPT-4等模型能够在不产生相应推理成本的情况下获得巨大容量的原因。代价是复杂性增加,以及需要在VRAM中存储所有专家模型的内存开销。
9. 第七步:解码——将数字还原为文字
经过所有N层处理后,每个token已被转换为富含上下文信息的向量。现在我们需要将这个向量转换为实际的预测词。
这个过程分为四个步骤,称为解码:
第一步:语言模型头(线性投影)
最后一个token(模型正在预测的下一个词)的最终向量与语言模型头矩阵相乘,该矩阵的形状为:
[嵌入维度] × [词汇表大小]
这会将(例如)4096个数字投影到100000个数字——词汇表中每个词对应一个分数。这些原始分数被称为logits。
第二步:Softmax → 概率分布
对logits应用softmax函数。词汇表中的每个词现在都有一个介于0和1之间的概率,总和为100%。
"and": 8.3%
"orbit": 4.1%
"someday": 2.7%
"landing": 2.1%
...其他50000个概率极小的词
第三步:采样
从这个分布中选择一个词。几种常见策略:
- 贪婪采样:总是选择概率最高的词。确定性高,但可能产生重复、可预测的文本。
- 温度采样:在选择前重塑分布。高温(>1)使分布更平坦(更随机、更有创意)。低温(<1)使分布更尖锐(更确定、更保守)。温度=0 → 贪婪采样。
- Top-p(核)采样:仅从累积概率≥p的最小词集中采样。去除长尾无意义词,同时保留多样性。
第四步:自回归循环
将选中的词追加到输入中,整个流程重复进行:
输入:"Go to the moon" → 预测 "and"
输入:"Go to the moon and" → 预测 "back"
输入:"Go to the moon and back" → 预测 "."
这被称为自回归生成——每个生成的token都成为下一个输入的一部分。模型一次生成一个token,直到生成特殊的<end>标记。
10. ⚡ KV缓存——让一切变得实用的速度技巧
注意自回归循环的问题:要生成第100个token,模型需要对前面99个token运行注意力机制。要生成第1000个,它需要对前面999个token进行注意力计算。没有优化,每一步都会变慢。
前面token的K和V向量始终相同——无论后面跟着多少个token,"moon"的Key和Value始终不变。那么为什么要在每一步重新计算它们呢?
KV缓存会在计算K和V向量时将其存储起来并重复使用:
预填充阶段:一次性处理"Go to the moon"
→ 计算并缓存所有4个token的K,V
解码步骤1:新token只需要自己的Q向量
→ Q_new × [缓存的K₁, K₂, K₃, K₄] → 下一个token
解码步骤2:缓存增加一个条目(新token的K,V)
→ Q_newer × [缓存的K₁...K₅] → 下一个token
在每个解码步骤中,模型只计算一个新token的Q,然后从缓存中查找所有之前的K,V。每个token的生成时间现在是恒定的,无论序列有多长。
代价:KV缓存消耗的GPU内存与序列长度×层数×注意力头数成正比。这就是为什么:
- 运行具有长上下文的大型模型需要大量GPU VRAM
- 当上下文过长时会出现"内存不足"错误
- 服务提供商对更大的上下文窗口收取更高费用
生产模型如何应对内存成本:GQA(分组查询注意力)让多个Query头共享一个Key/Value头,将KV缓存缩小数倍而几乎没有质量损失(用于Llama 3、Mistral)。Flash Attention重新排列注意力计算,避免将巨大的分数矩阵写入内存,使其更快且内存效率更高。两者现在都是严肃LLM服务中的标准配置。
11. Transformer:整合所有组件
Transformer是结合上述所有组件的架构名称。它在2017年的论文《Attention Is All You Need》中提出,在几年内完全取代了主流的RNN/LSTM架构。
这个名字反映了其数学本质:它逐层持续变换token表示,从原始嵌入到深度上下文化的向量,为预测做好准备。
完整流程
文本输入
↓
分词
↓
Token嵌入
↓
+ 位置编码
↓
┌─── Transformer块 ×N ────────────────┐
│ 多头注意力 │
│ 残差连接 + 层归一化 │
│ 前馈网络 │
│ 残差连接 + 层归一化 │
└─────────────────────────────────────┘
↓
语言模型头(线性层)
↓
Softmax
↓
采样Token
↓ (循环返回,追加新token)
三种Transformer家族
| 家族 | 架构 | 注意力类型 | 最佳用途 | 示例 |
|---|---|---|---|---|
| 编码器-only | 仅编码器块 | 双向(看到完整序列) | 分类、嵌入、搜索 | BERT、RoBERTa |
| 解码器-only | 仅解码器块 | 因果(只看到过去token) | 文本生成、聊天、编码 | GPT-4、Claude、Llama、Mistral |
| 编码器-解码器 | 两者皆有 | 编码器:双向;解码器:因果 | 翻译、摘要 | T5、BART |
为什么现代LLM是解码器-only:
最初的2017年Transformer是编码器-解码器架构,专为翻译构建。要训练它,你需要配对数据:"法语句子"→"英语句子。"这限制了规模。
解码器-only模型可以在任何原始文本上使用更简单的目标进行训练:预测下一个token。互联网拥有几乎无限的原始文本。这使得能够在数千亿个token上进行训练,产生具有远超架构师预期的涌现能力的模型。
12. LLM如何训练
训练LLM分阶段进行:
第一阶段:预训练(最昂贵的部分)
模型使用自监督学习在庞大的语料库上训练——爬取的网页、书籍、代码、论文。模型看到文本,预测下一个token,将其预测与实际token进行比较,计算误差(损失),并通过反向传播和梯度下降调整其权重。
这个阶段在数千个GPU上运行数周或数月。这是模型获取世界知识和语言理解的地方。GPT-3在约3000亿个token上训练;现代模型在10-100万亿+个token上训练。
第二阶段:监督微调(SFT)
预训练后,模型可以预测文本,但不知道如何提供帮助。它可能会通过生成更多它认为接下来应该出现的内容来完成你的提示——而不是回答你的问题。
SFT在由人类标注者编写的(提示,理想回答)对数据集上训练模型。这教会模型作为有用助手的格式和风格。
第三阶段:RLHF——对齐(使其真正有用)
基于人类反馈的强化学习是模型学会偏好优质回答而非平庸回答的方式。
- 收集偏好数据:让人类评分者查看同一提示的多个模型回答;让他们从最佳到最差排序
- 训练奖励模型(RM):一个独立的神经网络,学习预测人类偏好分数
- RL微调:使用奖励模型对LLM进行微调——将其推向奖励模型评分高的回答
DPO(直接偏好优化)是一种更新、更简单的替代方案,它跳过了独立的奖励模型步骤,直接在偏好对上训练。因其稳定性而日益受到青睐。
RLHF将"补全文本"的机器转变为有用、无害且诚实的助手。
两个值得了解的训练陷阱
正则化(对抗过拟合)。拥有数十亿参数的模型可能记忆训练数据而非学习通用模式。正则化可防止这种情况。经典方法:L2将所有权重向零收缩(更平滑、更通用);L1将部分权重精确推至零(稀疏性)。在深度网络和LLM中,主力方法是Dropout——训练期间随机禁用一部分神经元,使网络无法过度依赖任何单一路径,被迫学习冗余、稳健的表征。
数据泄露(基准污染)。如果测试/评估数据意外出现在训练集中,模型会"记忆答案"并得分虚高,但实际毫无理解。对于在整个互联网上训练的LLM,这是一个严重且微妙的问题:公共基准常常泄露到训练语料中,夸大报告分数。通过严格的训练/测试分离、去重、截止日期过滤以及保留或新创建的模型从未见过的评估集来缓解。
13. ️ 微调:教老模型新把戏
一旦你有了预训练、对齐的LLM,你可能希望针对你的用例进行特化:用你品牌的语气说话、遵循你的特定输出格式、处理你领域的术语。
微调是在你自己的数据集上继续训练。但存在重要的权衡:
全量微调
更新模型中的每个权重。功能最强大,但:
- 需要与预训练相同的GPU算力(通常不可行)
- 灾难性遗忘:过度特化可能破坏模型的通用能力
- 你需要数十万个高质量示例
PEFT:参数高效微调
关键在于:你不需要更新所有权重。你可以冻结基础模型,添加小的可训练适配器层。
LoRA(低秩适配)——主流方法:
不直接更新权重矩阵W,而是添加两个小矩阵A和B,其中A × B近似更新量:
W' = W + A × B
其中A为[d × r],B为[r × d],r << d
如果原始权重矩阵为4096×4096(1600万参数),秩为16的LoRA适配器为4096×16 + 16×4096(13.1万参数)——不到原始大小的1%。你只训练A和B,而W保持冻结。
QLoRA扩展了这一点:将基础模型量化到4位整数(内存减少4-8倍),然后应用LoRA适配器。这使你可以在单个消费级GPU上微调700亿参数的模型。
何时微调 vs. 仅用提示
| 情境 | 方法 |
|---|---|
| 需要一致的特定输出格式 | 微调 |
| 需要特定的语气/风格/角色 | 微调 |
| 需要添加事实性知识 | RAG(非微调) |
| 探索模型能力 | 提示 |
| 一次性任务,任意质量 | 提示 |
| 高吞吐量、低延迟、窄范围任务 | 微调 |
默认规则:先尝试提示和RAG。仅在你已穷尽这些选项且有明确、可衡量的质量要求时才进行微调。
14. ✍️ 提示工程:智能地与模型对话
提示就是代码。糟糕的提示带来糟糕的结果;优秀的提示能从同一模型中引出近乎神奇的表现。
核心技巧
零样本:直接提问。适用于简单、常见的任务。
少样本/上下文学习:在提示中包含2-5个输入/输出对示例。模型推断模式并应用。对于结构化任务,通常比零样本好得多。
思维链(CoT):指示模型"逐步思考"。通过外化推理过程,在数学、逻辑和多步骤任务中减少错误。模型必须通过可见的中间步骤"赢得"最终答案。
系统消息:设置行为、角色和护栏的持久指令。"你是一位简洁的技术写作者。仅根据提供的上下文回答。如果不确定,请说明。"
输出格式化:明确指定你想要的内容——JSON模式、编号列表、Markdown表格。模型是下一个词元预测器;告诉它要生成什么词元。
推理模型——当模型在回答前思考时
思维链曾经是你需要提示的内容。现在有一整类推理模型(OpenAI的o系列、DeepSeek-R1、Claude的扩展思考、Gemini的思考模式),它们经过训练,在最终答案前生成长的内部思维链——通常通过奖励正确推理的强化学习。
- 它们花费额外的"思考词元"来解决问题,这显著提高了数学、编程和多步骤逻辑的表现。
- 这是测试时计算:质量随模型被允许思考的时间而扩展,而不仅仅是模型大小。
- 权衡:它们更慢且每次回答更昂贵。将推理模型用于困难任务;将标准快速模型用于简单、高吞吐量的任务——与模型选择相同的"按难度路由"原则。
提示鲁棒性
在5个示例上有效的提示可能在第六个上失败。将提示视为代码:
- 针对多样化的输入测试集编写提示
- 在Git中版本管理
- 更改时测量回归
- 绝不在仅测试1-2个示例后部署提示
常见陷阱:
- 模糊指令("要有用")→ 行为模糊
- 冲突的指令 → 结果不可预测
- 未指定边缘情况行为("如果答案不在上下文中,请说'我不知道'")
- 将用户提供的内容与指令混合,导致注入风险
15. RAG:赋予模型记忆
LLM的知识在其训练截止日期时冻结。它无法了解上周的事件、你公司的私人文档或1000页的技术手册。
RAG(检索增强生成)通过在查询时将模型连接到外部知识库来解决这个问题,无需重新训练:
用户问题 → [检索相关文档] → [注入到提示中] → LLM回答
完整的RAG流水线
离线(索引)阶段:
- 摄取:收集文档(PDF、数据库、网页、代码)
- 分块:将文档分割成更小的片段(见下文)
- 嵌入:将每个块转换为嵌入向量
- 索引:将向量存储在向量数据库中以便快速检索
在线(查询)阶段:
- 嵌入查询:将用户问题转换为向量
- 检索:找到最相似的前k个块(通过向量搜索)
- 重排序(可选):使用更精确的模型重新评分和排序块
- 增强:将检索到的块作为上下文注入提示
- 生成:LLM基于提供的上下文回答
- 引用:可选地返回答案的源引用
分块策略很重要
如何分割文档显著影响检索质量:
| 策略 | 工作原理 | 最佳适用场景 |
|---|---|---|
| 固定大小 | 每N个字符,带重叠 | 简单、基线、通常足够好 |
| 递归拆分 | 按段落、句子、字符逐级拆分 |