尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

LLM与Embedding的区别与配合:从概念到RAG实践

LLM与Embedding的区别与配合:从概念到RAG实践 最近在技术社区里被问到最多的问题之一就是LLM和Embedding到底有什么区别。很多人刚开始接触大模型应用开发一上来就被各种名词绕晕尤其是RAG、向量数据库、微调这些概念里面Embedding几乎无处不在但真让你说清楚它和LLM是什么关系、各自负责什么很多人又讲不透。这篇文章我就用自己的实际经验把这两个核心概念彻底掰开揉碎讲清楚它们在技术链条里分别扮演什么角色。这里先给个一句话的初印象LLM决定“怎么说”Embedding决定“怎么找”。这俩不是替代关系而是上下游配合关系。你要是搞RAG、搞Agent、搞知识库这俩概念理不清后面全乱套。1. 先搞懂概念本身LLM和Embedding各自是什么1.1 LLM是什么它不是“更聪明的AI”而是一个概率文本生成器LLM全称Large Language Model中文叫大语言模型。基于Transformer架构通过海量文本的预训练模型学会了人类语言的统计规律。你给它一段文本作为输入它通过自回归的方式逐个预测下一个最可能出现的token从而生成连贯的回答。这个描述很技术但本质其实就是LLM是个“续写大师”。你给它上句它给你接下句。至于这个下句对不对取决于它的参数规模、训练数据的质量和覆盖度。举个例子你问GPT类模型“今天天气怎么样”它不是真的去查询气象数据而是根据训练中学到的知识判断这个问题在人类语境里通常对应什么样的回答模式然后生成一段大概率正确的文字。所以LLM有时会一本正经地胡说八道这不奇怪因为它的本质就是概率生成不是事实检索。在实际开发中LLM承担的活儿是“语言理解与生成”——包括对话、总结、改写、代码生成、意图识别、情感分析这些自然语言任务。LLM需要的输入是自然语言文本输出也是自然语言文本。它需要消耗大量的算力尤其是推理阶段但换来的是极其强大的语言处理能力。1.2 Embedding是什么它是一串数字却代表着语义坐标Embedding这个词在这两年被大量提及但它的思想实际上很早就有了。简单来说Embedding就是把文本、单词、句子甚至图片映射到一个向量空间用一串固定维度的浮点数来表示这个对象的语义。语义相近的对象在向量空间里的距离也就越近。比如“猫”和“猫咪”的向量距离就会很近而“猫”和“汽车”的距离就会很远。这个特性非常关键它让计算机能够以数学的方式去度量语义相似度。早期的Embedding有Word2Vec、Glove这样基于词粒度的静态向量后来有BERT这样基于上下文的动态向量。而到了大模型时代Embedding模型也有了新的演进很多厂商都提供了专门的Embedding API比如OpenAI的text-embedding-3-small、智谱的embedding-2、阿里的text-embedding-v2等。Embedding模型通常也是Transformer架构但和LLM不同的是它的输出不是一个词一个词地生成文本而是把整个输入文本“压缩”成一个固定维度的向量。比如常见的维度有768、1024、1536、3072等具体维度和模型有关。Embedding的输出本身不具备“生成”能力它不会回答你的问题也不会跟你聊天。它是一种文本的数学化表征是让计算机能够理解语义相似度的一种编码方式。1.3 一句话对比LLM会说话Embedding会定位两者放在一起做个类比也许更好理解。LLM像一个知识渊博的专家你问它问题它能用流畅的语言回答你哪怕它并没有去过现场也能根据已有的知识储备进行推理和表达。Embedding则更像一个图书管理员的索引系统它不负责回答你问题但它能在海量书库里快速定位哪几本书和你的问题最相关。再补一个更贴切的例子你在图书馆里要找一本关于“怎么做红烧肉”的书。如果你直接用LLM它会凭自己的记忆大概给你讲一遍红烧肉的做法但细节可能不准确因为它的知识有截止日期也没有翻你面前的这本书。而你如果先把图书馆里的书全部用Embedding做过向量化再把“怎么做红烧肉”转成向量去匹配就能快速找出那本800页的红烧肉专著然后把这本书的内容喂给LLM让LLM基于书里的原文给你一个精准的答复。这就是RAG检索增强生成的基本原理也是LLM和Embedding最经典的配合用法。2. 深入应用场景为什么现实中两个都要用2.1 只靠LLM的痛点幻觉、知识过期、没有私有数据如果只用LLM做问答最头疼的三个问题就是幻觉、知识过期和数据隔离。幻觉问题最典型。你问LLM一个它不知道的细节问题它不会老老实实说“我不知道”而是会根据上下文编一个看起来很像样的答案。尤其在一些专业领域里比如企业内部制度、某个产品的具体参数、某条法规的准确条款LLM编出来的东西可能逻辑通顺但细节完全错误。知识过期也是个绕不开的问题。LLM的预训练数据是有截止日期的你问它最近三个月新发布的产品、新修订的政策它根本答不上来。除非你重新训练或者微调否则它的知识天花板就固定在那了。数据隔离更是企业场景的硬需求。企业的私域数据、商业机密、内部文档不可能为了接一个LLM就把数据上传训练。即使允许上传训练一次大模型的成本也不是一般公司能承受的。这时候就需要一个方案让LLM在“不更新参数”的前提下依然能回答出基于私有数据的精准问题。2.2 Embedding在这里的关键作用为私域知识建立索引Embedding就是解决上面这些问题的关键一环。核心思路并不复杂先把私域文档全部切片然后通过Embedding模型把每个切片变成向量存入向量数据库。当用户提问时同样把问题向量化然后在向量数据库里做相似度检索找出与问题最相关的几个文本片段。最后把检索到的文本片段和原始问题一起交给LLM让它基于这些片段来生成答案。这个过程里Embedding负责的环节是“召回”也就是从海量切片里找出最相关的候选。它的准确性直接决定了最终答案的质量上限。如果Embedding召回的内容乱七八糟LLM就算再强也只能基于垃圾输入生成垃圾输出。我自己在做知识库问答系统时就踩过这个坑。刚开始图省事把整篇文档不做切片直接平均分成固定长度结果语义被切得支离破碎Embedding召回的效果非常差。后来改成按标题、段落结构来智能切片保留上下文的语义完整性召回准确率一下就上去了。后面详细展开说这个细节。2.3 LLM在RAG链路里做什么答把召回内容变成用户友好的回答在RAG链路中LLM的角色更像一个“精加工车间”。Embedding负责把原材料知识切片找出来LLM负责把这些材料加工成用户能直接看懂的答案。这个过程里你可以通过Prompt工程来做很多控制。比如告诉LLM“你是一个知识库助手请严格基于以下资料回答问题不要使用你自己的知识如果资料里没有答案请直接说不知道。”这样LLM就会克制自己“编造”的冲动尽量围绕检索出的上下文来回答。在实际开发中Prompt的设计对回答质量的影响非常大。我试过同样的向量检索结果配不同的Prompt答案的准确度差很多。关键在于把LLM的角色限定在一个“信息转述者”而不是“知识创造者”的位置上。3. 技术选型什么时候该用Embedding什么时候该用LLM3.1 典型选型速查表场景不同技术选型差异很大。下面是我在实际项目里总结的一个速查表供参考场景推荐方案理由闲聊、通用问答只用LLM不需要私域知识直接利用模型内部知识即可知识库问答LLM Embedding 向量数据库需要从私域文档中检索相关段落文本分类、意图识别Embedding 分类器不需要生成文本只需要语义度量语义搜索、相似匹配Embedding 向量检索核心需求是“找相似”不需要LLM生成代码生成只用LLM代码生成本质是内容创作无需检索数据去重、查重Embedding 向量相似度只需判断是否相似不涉及语义生成这里最容易被误解的场景是“文本分类”。很多初学者一上来就想到用LLM做分类觉得它聪明。但实际上如果只是做简单的二分类或者多分类LLM不仅慢而且贵。用Embedding把文本向量化再训练一个简单的逻辑回归或SVM效果又快又准成本还低。另一个容易被忽略的场景是“语义缓存”。在对话系统里遇到重复问题时你可以先把用户问题转成Embedding然后在缓存里找相似度高的旧问答直接返回。这能省掉大量的LLM调用成本响应速度也快很多。我做的智能客服系统就加了这一层API费用直接降了40%左右。3.2 如果只有LLM没有Embedding能做什么说句公道话并不是所有场景都需要Embedding。如果你做的是一个通用型聊天助手用户的问题不超过模型知识边界那确实直接调LLM接口就行了不用额外引入向量检索。比如给客户做一个简单的官网问答机器人回答的都是公司公开介绍、产品优势这类公开信息LLM本身就比较擅长没必要大动干戈做RAG。再比如做翻译工具、文案润色工具、代码解释器这些都是纯生成任务Embedding确实帮不上什么忙。但如果你发现用户问的问题经常超出模型知识或者答非所问、幻觉严重那大概率就需要引入RAG体系了这时候Embedding就成为关键一环。3.3 如果只有Embedding没有LLM能做什么Embedding也完全可以独立使用。最经典的场景是语义搜索。传统的关键词搜索靠字面匹配搜“苹果”就只出现包含“苹果”二字的文档搜“iPhone”就只出现包含“iPhone”的文档。但如果你把用户查询和文档都做了Embedding那么即使用户搜的是“手机”也能召回包含“iPhone”内容的文档因为它们的语义距离足够近。另一个典型应用是文本去重。新闻聚合平台、论坛管理、工单系统经常需要判断两条文本是不是“同一个意思”哪怕表达方式不同。用Embedding做相似度阈值判断简单有效。再比如推荐系统。利用Embedding计算用户历史兴趣向量和候选内容的余弦相似度能够做到“语义层面的兴趣匹配”比纯标签匹配要精细得多。4. 实操环节如何自己动手体验LLM与Embedding4.1 环境准备这里我用Python OpenAI风格API来做演示。OpenAI的Embedding接口大家最常接触但国内很多厂商的API也兼容这种调用方式比如智谱、阿里的DashScope、硅基流动等接口风格基本一致。下面代码里我统一用openai这个库设置好base_url和api_key就可以切换不同的服务商。# 安装依赖 # pip install openai python-dotenv import os from openai import OpenAI # 初始化客户端这里以某个兼容OpenAI协议的API服务为例 client OpenAI( api_keyos.getenv(API_KEY), base_urlos.getenv(BASE_URL) # 默认为 https://api.openai.com/v1 )核心就是两个调用chat completions用来问LLMembeddings用来做向量化。4.2 直观对比LLM和Embedding的输出形态这是理解两者区别最直接的一步——看它们的输出长什么样。# 1. 调LLM让它生成一段文本 response client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你是一个简洁的助手。}, {role: user, content: 用一句话介绍什么是大语言模型。} ], temperature0.7 ) print(LLM输出:, response.choices[0].message.content) # 输出示例大语言模型是基于海量语料训练的自然语言处理模型能够理解和生成人类语言。 # 2. 调Embedding让文本变成一个向量 text 大语言模型 emb_response client.embeddings.create( modeltext-embedding-3-small, inputtext ) vector emb_response.data[0].embedding print(Embedding向量维度:, len(vector)) print(向量前10个值:, vector[:10])看到区别了吗LLM的输出是自然语言文本一长串。Embedding的输出则是一大堆浮点数比如1536维的向量。这些数字本身对人类没有可读性但计算机可以非常高效地进行数学计算和比较。这个差异背后的本质原因是两者的目标函数不同。LLM的训练目标是最大化下一个token的生成概率所以它学会了“生成语言”。Embedding模型的训练目标是让相似的文本在向量空间里彼此靠近让不相似的彼此远离所以它学会了“刻画语义”。4.3 用余弦相似度体会Embedding的语义度量能力光看向量没有直观感受我们来做一个小实验计算几个句子之间的余弦相似度。import numpy as np def cosine_similarity(vec_a, vec_b): return np.dot(vec_a, vec_b) / (np.linalg.norm(vec_a) * np.linalg.norm(vec_b)) sentences [ 今天天气不错, # 0 外面阳光明媚, # 1 楼下新开了一家火锅店, # 2 I love programming # 3 ] # 批量向量化 emb_resp client.embeddings.create( modeltext-embedding-3-small, inputsentences ) vectors [item.embedding for item in emb_resp.data] # 两两计算相似度 for i in range(len(sentences)): for j in range(i 1, len(sentences)): sim cosine_similarity(vectors[i], vectors[j]) print(f句子{i} vs 句子{j}: {sim:.4f})运行结果大致会是这样句子0和句子1的相似度非常高比如0.86因为都在说天气好。句子0和句子2的相似度很低比如0.12因为一个是天气一个是餐饮。句子2和句子3更低可能只有0.02因为语义完全不同甚至语言都不同。句子0和句子3也会很低但因为“天气”这个概念在中英文里仍然有相近的语义映射所以可能比0.1再稍微高一点点。这个实验能让你直观感受到Embedding的核心能力把语义变成可以计算的距离。4.4 手写一个最小RAG流程把LLM和Embedding串起来既然单独体验过了我们再把它们串起来做一个最小可用的RAG流程这也是目前大模型应用开发里最常用的组合模式。# 1. 准备知识切片 documents [ 公司的年假制度入职满1年可享受5天带薪年假。, 公司的病假制度病假需提前报备连续超过3天需提供医院证明。, 公司的远程办公政策每周可选1天远程办公。, 公司的报销标准差旅住宿上限为每晚500元。 ] # 2. 给每个文档切片生成Embedding向量并存入“内存向量数据库” doc_vecs [] for doc in documents: resp client.embeddings.create( modeltext-embedding-3-small, inputdoc ) doc_vecs.append(resp.data[0].embedding) # 3. 用户提问 question 如果我请了两天病假需要开医院证明吗 # 4. 把问题也转成向量计算与每个文档切片的相似度 q_resp client.embeddings.create( modeltext-embedding-3-small, inputquestion ) q_vec q_resp.data[0].embedding scores [] for i, doc_vec in enumerate(doc_vecs): sim cosine_similarity(q_vec, doc_vec) scores.append((i, sim)) # 5. 取Top2结果作为上下文 scores.sort(keylambda x: x[1], reverseTrue) top_docs [documents[idx] for idx, _ in scores[:2]] print(召回的文档:, top_docs) # 6. 把上下文和问题一起丢给LLM生成答案 context \n.join(top_docs) prompt f请基于以下资料回答问题如果资料中找不到答案请直接回答资料中未提及。 【资料】 {context} 【问题】 {question} response client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: prompt}], temperature0.3 ) print(LLM回答:, response.choices[0].message.content)这个流程就是RAG的最小骨架你平时看到的所有知识库问答产品本质都是这套架构的工程化放大版离线阶段用Embedding给文档做索引在线阶段先用Embedding召回再用LLM精读和生成。在这个例子里你其实已经能看出两者清晰的分工了Embedding负责“找对资料”LLM负责“把资料讲成人话”。缺了任意一个这个系统都不成立。缺了EmbeddingLLM面对这种具体制度问题只能瞎猜大概率会产生幻觉缺了LLM你只能召回一堆文本切片丢给用户自己看体验很差。5. 进阶技巧与避坑指南5.1 不要混淆“微调”和“RAG”很多刚入门的人会困惑既然LLM也会胡诌那我把私域数据拿去微调Embedding模型或LLM不就行了吗为什么还要搞RAG这里要说明一个关键认知RAG解决的是“模型不知道但你可以告诉它”的知识获取问题微调解决的是“模型能力不匹配特定任务风格/格式”的问题。两者解决的问题维度不同不是替代关系。具体来说如果你只是想让模型知道一些事实性知识比如公司制度、产品参数RAG是更高效、更便宜、更容易更新的方案。你不需要重新训练模型只需要更新向量数据库里的文档切片即可秒级生效。而微调更适合让模型学习某种特定的输出风格、结构、行为模式比如让模型学会一套特定的SQL方言、模仿某个角色的说话风格、统一输出严格的JSON格式等。这时候微调的效果会比RAG明显得多。不过这里还有个容易踩的坑有些项目会考虑微调Embedding模型来改善召回效果。这不是不能做但成本很高需要准备大量标注好的训练数据。对绝大多数项目来说先用通用Embedding模型调好切片策略和检索参数效果往往已经够用。我见过太多团队一上来就奔着微调去最后折腾一个月效果还不如老老实实优化切片和Query改写。5.2 Embedding模型选型要点现在市面上的Embedding模型很多选型时我一般看这几个指标第一个是向量维度。维度高的模型理论上能表达更丰富的语义信息但运算成本也更高占用存储也更大。很多向量数据库对大维度的支持也有性能和成本的影响。实际项目里1536维和1024维的性能差距不止一倍要根据数据量来权衡。第二个是支持的语言。如果你处理的是纯中文内容就选中文语料表现好的模型如果是中英混合那就得选跨语言能力强的。很多embedding模型在中英文混合检索上的表现差距极大。第三个是最大输入长度很多模型号称支持8192甚至32768的上下文长度但输入太长时Embedding质量会有所衰减。我的经验是把切片长度控制在300-500个token之间既保证了语义完整性又不会因为过长而葬送了匹配精度。第四个是Sentence-BERT系列还是LLM-based Embedding。像bge-m3、gte、text-embedding-3这些都是基于Transformer训练的专门Embedding模型适用性很强。但也有一种做法是用LLM来生成Embedding比如直接取LLM最后一层的隐藏状态。这种方式的优点是语义理解更深入缺点是推理成本高得离谱。除非你有特别复杂的长文本理解需求否则普通场景用专用Embedding模型就够了。5.3 切片策略Embedding效果的上限分水岭这可能是RAG系统里最影响最终效果但又最容易被忽视的环节。我最早做知识库的时候图省事把文档按照每200个字符硬切。结果就是所有语义都被拦腰斩断Embedding根本召不齐关键信息LLM拿到手的内容经常缺胳膊少腿。后来慢慢摸索出一套相对靠谱的切片规则先按文档结构切。如果文档有markdown标题、HTML标签、Word标题样式优先按标题边界切。每个章节是一个相对完整的语义单元。如果章节太长再按段落边界切。保持段落完整是语义唯一性的基本要求。在做切片时还要注意上下文重叠。前后两个切片之间最好重叠一部分内容比如重叠100-200个字符。原因是如果你恰好把一句完整的话从中间切开下一片的内容会缺少上文检索的时候就容易丢失。重叠一部分后被切坏的边缘内容至少会在两个切片里同时出现无论哪种方式都能找回上下文。还有一个小技巧是大小切片结合。先用大切片做召回保证能命中正确的文档区域再用小程序把命中的大切片切碎让LLM只看最相关的部分。这比从头到尾只用一种切片粒度要灵活得多也能照顾到不同粒度的问题。5.4 Query改写是RAG里最值得投资的优化方向很多人把精力都花在调Embedding模型和检索参数上却忽略了一个非常关键的问题用户的query往往不适合直接用来检索。比如用户问“公司年假能休几天”这个query直接去跟“入职满1年可享受5天带薪年假”做相似度计算效果还行。但如果用户问“我刚入职半年想请几天假出去旅游能请吗”这个query里包含了大量与检索无关的信息直接做Embedding检索很容易混淆语义重点。我的做法是加一层Query改写。在送入Embedding检索前先让LLM把用户的原始问题改写成一个“适合检索的、简洁的、核心意图明确的查询语句”。比如上面那个例子改写后的query可以变成“入职半年 年假 天数规定”。结果是召回效果立竿见影。这一步通常被叫做HyDE或Query Rewriting原理上就是利用LLM对语义的理解能力把用户口语化的问题压扁成一个检索友好型短语。成本很低但收益非常大。我自己做的RAG系统加了Query改写之后准确率大概提升了十几个百分点。6. 大模型应用里的常见误区与排查思路6.1 误区一检索结果不对就怪Embedding模型这是一个特别常见的归因错误。有一次我接到一个知识库项目的反馈说“检索出来的东西牛头不对马嘴”用户第一反应都说“Embedding模型不行换更强的模型”。但排查下来发现问题是出在数据准备环节。源文档里混杂了大量PDF扫描件文字本身就是OCR识别的满是错别字和乱码Embedding模型再强也救不了这种脏数据。先把数据清洗干净、纠错、去噪召回效果立刻好了很多。另一个常见问题是文档里存在大量重复内容。比如FAQ里同一个问题有七八种不同说法但答案各不一样。这时候检索出的TopK结果里有几条都是同义问题真正有效的候选反而被挤掉了。解决方案是做一些去重或者在检索结果里做一次重排把相似度接近的但内容重复的过滤掉。6.2 误区二只要用了RAG就能消除幻觉RAG确实能大幅降低幻觉概率但不能完全消除。原因在于LLM在生成时会“忍不住”加入自己的知识。如果你给的Prompt约束不够严格LLM会自行把检索到的内容扩展到它的知识帮你“圆回来”这时候就容易出现“一半资料一半常识”的混合回答看起来很合理但其实就是幻觉。我的经验是在Prompt里给出明确的指令同时要求LLM在回答时标注所依据的材料片段编号。这既方便用户溯源也能反向约束LLM不要自由发挥。如果业务场景不允许任何幻觉还可以在系统里加一层正则或规则校验对明显的错误表述做拦截。6.3 误区三Embedding模型更新后没有重新向量化Embedding模型一旦切换之前生成的所有向量都得重新生成不然新旧向量不在同一个语义空间里做计算结果毫无意义。这个坑其实非常基础但我在生产环境里见过不止一次。运维同学只改了API配置没触发全量重建向量索引结果线上检索结果变得极不稳定。所以如果是自己部署的向量数据库切换Embedding模型时一定要先做全量重刷确认索引更新完成之后再切流量。另外建议把每个文档的embedding模型标识存在元数据里出现异常时排查会方便很多。6.4 排查技巧速查表现象可能原因快速排查方法召回内容不相关切片太碎/太大、数据太脏、query太长检查切片长度清洗数据测试Query改写召回对但回答错Prompt约束不足、上下文截断查看LLM上下文的实际内容加强Prompt限制相似的query结果不稳定Embedding模型版本不一致检查向量库里的模型标识全量重建索引检索速度慢向量维度高、索引类型不合适更换索引算法HNSW/IVF考虑量化成本飙高检索到过多上下文、切片未去重减少TopK增加重排压缩上下文我自己在实际开发中最常用的排查手段是把RAG链路拆开逐段打日志。先记录用户原始问题再记录改写后的query再记录召回的TopK片段和相似度分数最后记录喂给LLM的完整上下文。这样做的好处是任何一环出了问题都能通过日志快速定位是在检索环节还是生成环节。7. 聊聊这两个方向的学习路线如果你刚接触大模型应用开发我的建议是先动手跑通一个RAG的小案例把LLM和Embedding结合起来对它们各自的能力边界有了直观感知后再深入学习第一步熟悉LLM的API调用方式理解system/user/assistant的对话结构掌握temperature、top_p这些采样参数对生成结果的影响。这一步可以不做任何RAG先把“模型会怎么回答”摸透。第二步了解Embedding的基本原理自己写代码调用API完成文本向量化做一些相似度检索的小实验。如果能把余弦相似度、点积、欧氏距离这些概念亲手计算一遍后面理解向量数据库的原理会轻松很多。第三步完整实现一个RAG先不管工程化细节保证“检索-生成”链路跑通。然后再逐步加功能智能切片、Query改写、重排序、混合检索、多路召回、流式输出。第四步再从工程化角度去学习向量数据库的选型与调优。比如Milvus、Qdrant、Weaviate、ElasticSearch的向量检索能力理解HNSW算法和IVF算法在大规模向量检索时的取舍。到了这一步你就不再是只会调API的初学者了。最后再分享一个小技巧。学习阶段尽量在项目里用开源的Embedding模型本地部署比如bge-m3、gte等这样不仅可以规避调用外部API的一些限制还能让你更直观感受到Embedding模型的温度——看到各种文本在本地模型里被编码成一串串向量你会对它的存在有更深刻的认同感。我最初理解向量相似度对语义的反映就是从本地部署一个embedding模型亲手跑完几千条文本的相似度分析开始的。LLM和Embedding这两件事说到底是两个维度的能力一个是把语言变成文本一个是把语言变成坐标。真正复杂的不是某个单独的模型有多强而是它们如何在一个完整系统里各司其职、互相成就。希望这篇文章能帮你在概念上理清思路在实操里少走几条弯路。
返回列表