简单说说对RAG的理解,以及你们项目中是怎么应用到RAG的
说说什么是LoRA
反向传播的时候我们修改模型的参数矩阵W0,这个矩阵的参数量特别大,我们可以通过奇异值分解(SVD)的方式将它分解成两个小矩阵AxB,其中A是dxr,B是rxd,这样我们就将训练的参数量从dxd降到dxr+rxd。
在实际操作中,我们通常将LoRA挂载在Attention层上,对Q和V矩阵进行调整。研究表明,对这些层调整对模型能力的改变最有效。在训练时,我们只更新A和B的参数,并且会使用一个缩放因子α/r来控制LoRA对原始模型的影响权重。最后我们只需要将W0+(AxB)就可以直接把LoRA训练应用到原始的W0中。
你们用的什么向量检索数据库?说几条数据库用的检索指令
在 Milvus 向量数据库中,检索主要分为 向量搜索 (Search) 和 标量查询 (Query) 两大类。通常我们说的“检索”多指基于向量相似度的 Search。
1 | # 向量相似度搜索 |
1 | # 标量查询 |
用过LangChain这些比较基础的框架吗
向量检索的时候遇到过什么问题,怎么解决的,有没有用过混合检索(展开:向量检索用了什么模型?混合检索是怎么做的?什么是Re-Rank?)
Cohere的Embedding模型和ReRank模型。
目前绝大多数向量模型都基于 Transformer 架构(比如 BERT 的变体)。它们采用“双编码器”(Bi-Encoder)结构,将查询词(Query)和文档(Document)分别转换为高维空间的坐标。向量检索懂语义,但有时会犯糊涂。比如搜索“钨合金”,向量检索可能会给你推荐“钢合金”、“铝合金”,因为它觉得语义很像。这时候就需要关键词搜索来救场,确保精准匹配。
语义相似度≠事实相关性。向量检索(Embedding)本质上是计算两个向量在空间里的几何距离。ReRank模型通过Cross-Encoder将问题和文档同时输入模型进行交互计算,相比检索用的Bi-Encoder精度更高,速度更慢。它的作用是将Bi-Encoder粗检索出的50-100条数据进行重新打分并排序,使LLM能够更加专注于与问题更相关的知识。
1 | # Attention模块 |
- **线性映射 (
nn.Linear)**:虽然输入都是x,但我们通过三个不同的线性层把它们投影到不同的空间,增加了模型的表达能力。 - **缩放因子 ($\sqrt{d_k}$)**:代码中的
math.sqrt(embed_dim)非常关键。如果维度很大,点积的值会爆炸,导致 Softmax 进入梯度极小的区域。缩放一下能让训练更稳定。 - Softmax:它保证了每一行权重的和为 1,这意味着模型在决定“注意力分配”时是一个加权平均的过程。
大模型微调有哪些手段?
从代码和工程实现的角度来看,大模型微调(Fine-tuning)主要分为 全量微调、参数高效微调(PEFT) 以及 对齐微调(RLHF/DPO) 三大类。
目前业界最主流的方案是 PEFT(主要是 LoRA/QLoRA),因为它极大地降低了显存需求。
以下我将结合主流库(Hugging Face transformers, peft, bitsandbytes, trl)的代码片段来详细解析这些手段。
1. 参数高效微调 (PEFT)
核心思想: 冻结原模型的大部分参数,只训练极少量新增的参数(Adapter)。
A. LoRA (Low-Rank Adaptation)
这是目前最常用的微调手段。它在 Transformer 的 Attention 层(如 Q、V 矩阵)旁路插入低秩矩阵。
- 代码实现核心: 使用
peft库。 - 关键配置:
LoraConfig。
1 | from transformers import AutoModelForCausalLM |
B. QLoRA (Quantized LoRA)
在 LoRA 的基础上,将基座模型量化为 4-bit 加载,进一步通过 Double Quantization 和 Paged Optimizers 压榨显存。单卡 24G 显存即可微调 30B 级别的模型。
- 代码实现核心:
bitsandbytes+peft。 - 关键配置:
BitsAndBytesConfig。
1 | import torch |
C. Prompt Tuning / P-Tuning v2
在输入层或每一层插入可训练的 Prompt 向量(Soft Prompt)。
- 代码视角: 这里的改动在于
PeftConfig的类型。 - 现状: 代码实现简单,但目前效果普遍不如 LoRA,用得越来越少。
1 | from peft import PromptTuningConfig, TaskType |
2. 全量微调 (Full Fine-Tuning / SFT)
核心思想: 更新模型的所有权重。这通常用于数据量极大、且算力资源非常充足的场景(如企业私有化大模型继续预训练)。
- 代码实现核心: 标准的 PyTorch 训练循环或
Trainer,但不使用 PEFT 库,也不冻结层。 - 工程难点: 必须结合 DeepSpeed 或 FSDP (Fully Sharded Data Parallel) 来解决显存爆炸问题。
1 | from transformers import Trainer, TrainingArguments |
3. 对齐微调 (Alignment)
在 SFT (Supervised Fine-Tuning) 之后,为了让模型更符合人类偏好(Helpful, Harmless, Honest),通常使用以下方法。
A. RLHF (PPO - Proximal Policy Optimization)
这是 ChatGPT 早期使用的方法。需要训练一个 Reward Model,然后用强化学习更新 LLM。
- 代码库:
trl(Transformer Reinforcement Learning)。 - 复杂度: 极高(涉及到 4 个模型:Policy, Value, Reward, Reference)。
1 | from trl import PPOTrainer, PPOConfig |
B. DPO (Direct Preference Optimization)
这是目前最火的对齐方法。它不需要训练 Reward Model,也不需要复杂的 PPO 采样,直接使用 (prompt, chosen, rejected) 数据对进行优化。
- 代码库:
trl。 - 优势: 显存占用低,训练稳定,代码极简。
1 | from trl import DPOTrainer |
4. 总结:代码视角下的选择指南
| 微调手段 | 核心库/类 | 显存需求 | 修改的参数量 | 适用场景 |
|---|---|---|---|---|
| Full Fine-Tuning | Trainer + DeepSpeed(ZeRO3) |
极大 (80G x 8+) | 100% | 基础模型继续预训练,拥有海量算力 |
| LoRA | peft.LoraConfig |
中等 | < 1% | 垂直领域微调,注入新知识或指令格式 |
| QLoRA | BitsAndBytesConfig + LoRA |
极低 (24G单卡跑30B) | < 1% | 消费级显卡微调,效果接近全量 |
| DPO | trl.DPOTrainer |
中等 (略高于SFT) | < 1% (可结合LoRA) | 让模型更听话、减少幻觉、风格对齐 |
如果你是个人开发者或中小企业,代码起手式通常是:transformers 加载模型 -> bitsandbytes 4bit量化 -> peft 挂载 LoRA -> trl 进行 SFT -> (可选) trl 进行 DPO。
市面主流大模型有什么区别,为什么会产生这些区别
虽然“训练数据”确实是决定模型知识边界的基石,但在数据之外,架构设计(Architecture)、训练目标(Training Objectives)、推理机制(Inference Mechanism)以及对齐策略(Alignment Strategy) 的不同,才是导致各大模型在“智商”、“性格”和“效率”上产生巨大差异的根本原因。
以下从技术原理和工程实现的角度,分析主流大模型(如 GPT-4, Claude 3, Llama 3, DeepSeek-V3/R1, Gemini)的主要区别及产生原因:
1. 稠密模型 (Dense) vs. 混合专家模型 (MoE)
这是目前开源与闭源模型最大的分水岭。
- Dense (稠密模型): 如 Llama 3, Qwen-72B。
- 机制: 每次推理,所有的参数都会被激活参与计算。
- 优点: 训练收敛更稳,微调更容易,社区生态好(容易量化、部署)。
- 缺点: 随着参数变大,推理成本呈线性增长,很难做到极大参数(如 > 500B)。
- MoE (Mixture of Experts): 如 GPT-4, Mixtral 8x7B, DeepSeek-V3。
- 机制: 将模型的一层拆分为多个“专家”(Experts,通常是多个 FFN 层)。每次推理,路由器(Router)只选择 Top-K 个专家(比如 64 个里选 2 个)参与计算。
- 区别产生的原因: 为了打破“参数量 vs 推理成本”的铁律。MoE 可以在拥有巨大总参数量(拥有广博的知识)的同时,保持极低的活跃参数量(推理速度快、成本低)。
- DeepSeek 的特例: DeepSeek 进一步改进了 MoE,引入了 _Shared Expert_(共享专家)和 Load Balancing Loss 的创新,解决了专家负载不均导致的“死神经元”问题。
2. 注意力机制的变体 (Attention Mechanism)
标准的 Transformer Attention 计算复杂度是 $O(N^2)$,这限制了长文本能力。不同模型为了解决显存(KV Cache)瓶颈,采用了不同策略。
- GQA (Grouped-Query Attention): 如 Llama 2/3, Mistral。
- 机制: 多个 Query 头共享一组 Key/Value 头。
- 原因: 为了减少推理时的显存占用(KV Cache)并提高解码速度。这是 Llama 能在消费级显卡跑起来的关键。
- MLA (Multi-Head Latent Attention): DeepSeek-V2/V3 独创。
- 机制: 对 KV 矩阵进行低秩压缩(Low-Rank Compression)。
- 原因: 极度压缩 KV Cache。这使得 DeepSeek 可以在极低显存下处理超长上下文,也是其 API 价格极其便宜的核心技术原因之一。
- Ring Attention / Long-Context 优化: 如 **Gemini 1.5 (支持 1M+ token)**。
- 原因: Google 针对超长文本(整本书、长视频)进行了系统级优化,使得 Attention 计算可以在 TPU 集群间切分,从而突破单卡显存限制。
3. “快思考” (System 1) vs. “慢思考” (System 2)
这是 GPT-4o 与 OpenAI o1 / DeepSeek-R1 的本质区别。
- 标准 LLM (System 1):
- 机制: Next Token Prediction。根据概率直觉,一个词接一个词地吐,不回头,不反思。
- 局限: 遇到复杂逻辑(如数学证明、复杂代码架构),容易一本正经胡说八道。
- 推理模型 (System 2 / Reasoning Models): 如 OpenAI o1, DeepSeek-R1。
- 机制: 在输出最终答案前,强制模型生成一段“思维链”(Chain of Thought),并且这段思维链通常经过了大规模强化学习(RL)的训练。
- 区别产生的原因:
- 传统的 SFT(监督微调)只能让模型模仿人类说话的格式。
- 引入 RL(GRPO 或 PPO) 并不是为了教模型知识,而是教模型如何验证自己的步骤、如何回溯纠错。这种模型在“回答”前会先“思考”几千个 token。
4. 对齐哲学的不同 (Alignment Strategy)
为什么 Claude 看起来“小心翼翼/有道德洁癖”,而 xAI 的 Grok 看起来“放飞自我”?这取决于 RLHF 阶段的 Reward Model 设计。
- RLHF (基于人类反馈的强化学习): 如 GPT 系列。
- 侧重于 Helpful 和无害化,尽量让标注员满意。
- Constitutional AI (宪法级 AI): Anthropic (Claude) 的招牌。
- 机制: 不完全依赖人类标注(人类标注有偏见且累),而是用一个模型(根据一套宪法/原则)去监督另一个模型(RLAIF)。
- 结果: Claude 表现出更强的原则性,但也容易出现拒答(Refusal)。
- DPO / GRPO (直接偏好优化): 如 Llama 3, DeepSeek。
- 机制: 跳过 Reward Model 建模,直接用偏好数据优化 Policy。
- 结果: 训练更稳定,模型更听从指令,较少出现“废话文学”。
5. 原生多模态 vs. 拼接多模态
- 拼接方案 (Connector-based): 如 LlaVA, 早期 GPT-4 Vision。
- 机制: 视觉编码器(CLIP/ViT)提取图片特征 -> 投影层 -> 语言模型。
- 问题: 视觉和语言存在“语义鸿沟”,不仅慢,而且细节丢失严重。
- 原生方案 (Native Multimodal): 如 GPT-4o, Gemini 1.5。
- 机制: 图片、音频直接 tokenize 进入 Transformer,和文本 token 处于同一向量空间。
- 原因: 为了实现实时性(Real-time)。GPT-4o 能听懂你的语气停顿,是因为音频没有转成文字,而是直接作为信号被处理了,保留了副语言特征(语气、情感)。
总结:为什么会产生这些区别?
除了商业壁垒,本质是三个Trade-off(权衡)的选择:
- 推理成本 vs. 模型智力:
- 选 MoE (DeepSeek/GPT-4) 是为了在维持高智力的同时降低 API 成本。
- 选 Dense (Llama) 是为了方便开发者私有化部署。
- 显存瓶颈 vs. 上下文长度:
- 选 MLA/GQA 是为了让模型能塞进有限的 GPU 显存里,从而处理更长的文档。
- 直觉回答 vs. 逻辑正确:
- 选 Reasoning (o1/R1) 是通过牺牲时间(生成更多 token)来换取数学/代码的准确率。
这也是为什么在代码实现微调时,你会发现 DeepSeek 这种模型对 Flash Attention 的版本、显存优化的配置要求与 Llama 截然不同。
不通过大规模训练让大模型达到能分辨正面/负面情感的能力,要求准确性高,并且能输出置信度
要在不进行大规模训练(即不进行全量微调或从头预训练)的前提下,利用大模型(LLM)实现高准确度的情感分析并输出置信度,最佳策略是结合Prompt Engineering(提示工程)、In-Context Learning(上下文学习)以及Logits(逻辑斯特)/ Logprobs(对数概率)分析。
以下是一套分层级的技术方案,从核心机制到准确率优化策略:
核心方案:基于 Logits 的 Few-Shot 分类(Logits-based Classification)
这是目前在不训练模型的情况下,获取高准确率和真实数学置信度的标准做法。
1. 原理
大模型本质上是预测下一个 Token 的概率分布。我们不需要让模型生成一长串文本(如 “This review seems positive…”),而是强制模型在两个特定 Token 之间做选择(例如 “Positive” 和 “Negative”)。
2. 具体步骤
构建 Prompt(提示词): 使用 Few-Shot(少样本) 策略,提供 3-5 个典型的正/负面示例。
Prompt 示例: 评论: “这东西太烂了,浪费钱。” -> 情感: 负面 评论: “非常好用,超出预期!” -> 情感: 正面 评论: “中规中矩,没什么亮点。” -> 情感: 中性 评论: “[输入文本]” -> 情感:
限制输出空间(Token Constraint): 限制模型生成的下一个 Token 必须是映射标签的 Token(例如 ID 对应 “正面” 或 “负面”)。
获取 Logprobs(核心步骤): 调用 API(如 OpenAI 的
logprobs=True)或本地模型推理时,不直接取生成的文本,而是读取候选 Token 的概率值。假设:
- Token A (“正面”) 的 Logit 分数为 $L_{pos}$
- Token B (“负面”) 的 Logit 分数为 $L_{neg}$
计算置信度(Softmax): 我们需要将这两个 Logits 归一化,忽略词表中的其他词。 $P(Positive) = \frac{e^{L_{pos}}}{e^{L_{pos}} + e^{L_{neg}}}$ 这个 $$P$$ 值就是你的置信度。如果 $$P > 0.9$$,说明模型非常有信心;如果 $$P \approx 0.5$$,说明模型很犹豫(可能需要人工介入)。
进阶优化:提升准确率的策略
仅依靠上述核心方案可能无法应对复杂的讽刺或隐晦表达,以下方法可进一步提升准确率:
1. 动态上下文学习 (kNN-ICL / RAG-based Few-Shot)
静态的 3 个例子可能无法覆盖所有情况。
- 做法: 准备一个包含几百条高质量标注数据的小型向量库。
- 流程: 当新文本进来时,先通过向量检索(RAG)找到与之语义最相似的 3-5 个已标注例子。
- 效果: 将这些最相似的例子放入 Prompt 中作为上下文。这能显著提升模型处理特定领域(如金融、医疗或口语俚语)的能力。
2. 思维链(Chain-of-Thought, CoT)
对于复杂情感(如“虽然贵,但是值”),直接分类容易出错。
- 做法: 修改 Prompt,让模型先解释原因,再输出标签。
- Prompt:
请先分析这段话的情感倾向逻辑,最后输出标签。格式:分析:[原因]... 标签:[正面/负面] - 难点: CoT 很难直接通过 Logits 获取置信度。
- 解决方案: 分两步走。
- 让模型生成分析文本。
- 把分析文本拼接到 Prompt 后,再询问“基于上述分析,情感是?”,此时再抓取 Logits 计算置信度。
3. 自洽性投票 (Self-Consistency) - 适用于无法获取 Logits 的场景
如果你调用的模型(如某些封闭 API)不提供 Logprobs,可以使用此方法估计置信度。
- 做法: 设置较高的 Temperature(如 0.7),对同一条输入并行请求 5-10 次。
- 计算: 统计结果分布。
- 如果 10 次里有 10 次是“正面”,置信度 ≈ 100%。
- 如果 6 次“正面”,4 次“负面”,置信度 ≈ 60%(低置信度,建议人工复核)。
专家级技巧:校准 (Calibration)
大模型通常存在过度自信(Overconfidence)的问题(即模型说 99% 确定,但实际准确率只有 80%)。如果不训练,如何解决?
- 无内容输入校准 (Content-Free Calibration):
- 输入 Prompt:”评论: N/A -> 情感:” (输入空内容或无意义字符)。
- 观察模型偏向 “正面” 还是 “负面” 的概率。
- 如果模型天生偏向 “正面”(例如 P=0.7),则在实际推理时,需要减去这个偏差(仿射变换)。
- 温度调整 (Temperature Scaling):
- 找一个小型的验证集(比如 50 条数据),计算模型的 Logits。
- 寻找一个最佳的温度系数 $T$(通常 > 1),用 $Logits / T$ 来平滑概率分布,使其与真实的准确率对齐。这不需要反向传播,只需简单的数值优化。
总结实施路线图
如果你想明天就上线这个功能,建议按以下顺序执行:
- 准备数据: 准备 20-50 条涵盖不同场景的高质量标注数据(金标数据)。
- 构建检索器: 使用 Sentence-BERT 等模型将这些数据向量化,建立简单的索引(RAG)。
- 推理流程:
- 输入用户文本。
- 检索 Top-3 相似的历史案例。
- 组装 Prompt(包含指令 + Top-3 案例)。
- 调用模型(推荐 Llama-3-70B, GPT-4o, 或 Qwen-2.5-72B),开启 Logprobs。
- 关注 “正/负” 两个 Token 的 Logits。
- 输出处理:
- Softmax 归一化得到置信度。
- 设置阈值(例如置信度 < 0.75 则标记为“待人工复核”)。
这种方法既规避了训练的算力成本和灾难性遗忘风险,又能通过 RAG 和 Logits 获得接近微调模型的高准确率和可解释的置信度。
现在的Decoder模型为什么直接就能输入Token,而不需要Encoder编码的语义?
这是一个非常深刻且直指大模型(LLM)架构本质的问题。
简单直接的回答是:Decoder 模型并非“不需要”编码语义,而是它把“编码(Encoding)”和“生成(Decoding)”这两件事在同一个架构里做完了。
在 Decoder-only(如 GPT 系列)架构中,输入部分(Prompt)的处理过程本质上就是一个编码过程。
为了讲清楚这个问题,我们需要打破对“Encoder”和“Decoder”的刻板印象。让我们从以下四个层面来拆解:
1. 第一步:Token 并不是直接进入模型的
你的问题中提到“直接输入 Token”,这里其实有一个中间步骤。 任何 Transformer 模型(无论是 BERT 还是 GPT),Token 进去后的第一件事都是查表,通过 Embedding Layer(嵌入层) 变成一个高维向量。
- Token:
苹果(ID: 1052) - Embedding:
[0.12, -0.59, 0.88, ...](假设是 4096 维的向量)
这个 Embedding 向量本身就已经包含了静态的语义信息(比如“苹果”和“梨”在向量空间离得很近)。所以,模型一开始拿到的就不是干巴巴的数字 ID,而是带有基础语义的数学表示。
2. 核心机制:Self-Attention(自注意力)既是编码也是解码
Encoder 和 Decoder 的核心组件都是 Self-Attention(自注意力机制)。它们的数学公式几乎一模一样,唯一的区别在于“能看谁”。
- Encoder (BERT类): 是双向的。看一个词时,既能看它前面的词,也能看它后面的词。这叫“全局理解”。
- Decoder (GPT类): 是单向(因果)的。看一个词时,只能看它前面的词(历史),不能看后面。
为什么 Decoder 能理解输入? 当你把一句话(比如“把这句话翻译成英文:你好”)输入给 GPT 时,虽然它是 Decoder 架构,但在处理这句提示词(Prompt)时,模型会计算每一个 Token 与它之前所有 Token 的关系。
这个过程就是“编码”。
- 当模型处理到“好”这个字时,它通过 Attention 机制“看”到了前面的“翻译”、“英文”、“:”、“你”。
- 此时,“好”这个位置的隐藏层向量(Hidden State),实际上就聚合了整句话的语义信息。
- 结论: Decoder 的“前半段”(处理 Prompt 的过程)就是在做 Encoder 的工作——将上下文理解并压缩成向量。
3. 架构的同质化:Decoder Block ≈ Encoder Block
如果我们把 Transformer 拆开看,Encoder Block 和 Decoder Block 的内部结构有 90% 是完全一样的:
- Multi-Head Self-Attention
- Feed-Forward Network (MLP)
- Layer Norm & Residual Connection
唯一的区别是 Decoder 多了一个 Mask(掩码),用来防止它“偷看”后面的答案。
既然积木块是一样的,功能自然也是通用的。 Encoder 能提取特征,Decoder 也能提取特征。只要堆叠的层数够多(大模型通常有几十上百层),Decoder 就能通过一层层的迭代,把输入的浅层语义抽象成深层逻辑。
4. 视角的转变:从“翻译”到“续写”
Encoder-Decoder 架构(如 T5, Bart) 的逻辑是“翻译思维”:
先把原句完整读完,压缩成一个“思想向量”(Encoder工作),再根据这个思想把新句子写出来(Decoder工作)。
Decoder-only 架构(如 Llama, GPT) 的逻辑是“续写思维”:
我不需要先把整本书读完合上书再背诵。我是一边读(Encoding context),一边根据读到的内容预测下一个字。
在 GPT 模型中,输入(Prompt)对于模型来说,就是“已经发生的历史”。模型通过计算输入序列的注意力,已经完全获取了输入的语义。
总结
Decoder 模型之所以不需要独立的 Encoder,是因为:
- 功能内化: 它利用 Self-Attention 机制,在处理 Prompt 阶段就已经完成了对上下文的语义编码。
- 向量传递: 输入的 Token 经过 Embedding 和多层 Transformer Block 处理后,最后输出的那个向量(Last Token Representation)已经包含了极其丰富的语义信息,足以用来预测下一个 Token。
- 架构通用: 现代大模型证明了,单向的 Attention(只要规模够大、数据够多)足以通过“预测下一个词”的任务,倒逼模型学会理解上文的语义。
打个比方:
- Encoder-Decoder 像是:先让一个阅读理解专家(Encoder)读题,写个摘要给写作专家(Decoder),写作专家再写答案。
- Decoder-only 像是:一个全能专家,他读题的过程就在脑子里形成了理解,读完题的瞬间(最后一个 Token),他直接顺着思路开始写答案。
本作品采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。