动手实现一个 AI chatbot 那篇做了一个能聊天的机器人,但它只见过模型训练时的数据。如果你想让 chatbot 回答你公司内部的产品问题,比如「会员多少钱」、「能不能导出我的数据」,模型一无所知,只能基于概率瞎编。
最直接的想法是把整份产品文档塞进 context 里,但对于有点规模的产品,文档可能有上千页,再大的上下文窗口也装不下。就算硬装得下,每次提问都把整份文档发一遍,token 费用也吃不消。
但仔细想想,用户每次提问其实只关心整份文档里很小的一部分,比如想开通会员的人只关心价格等信息,并不关心其他的产品细节。
所以真正要解决的问题是:先从一大堆文档里挑出和当前问题相关的几段,再把这几段塞进 chatbot 的上下文里,让模型根据这些真实准确的信息回答问题。这就是 **RAG(Retrieval-Augmented Generation,检索增强生成)**的全部思路:检索 + 生成。
为什么需要 embedding
搜索相关片段,最朴素的办法是关键词搜索,比如用户问「会员多少钱」,就搜索文档中包含「会员」等关键词的片段。
但这里有一个问题:精确字符串匹配算法无法处理语义相似的文本。比如用户问「怎么开通高级版」,文档里相关段落写的是「Pro 订阅的购买流程」,「高级版」和「Pro 订阅」一个字都不重合,grep 找不到。
再比如用户问「我能下载我的数据吗」,文档里的标题是「数据导出」,「下载」和「导出」也对不上。
要解决这个问题,就得给文字找一种新的表示方式,让计算机能够判断两段话是否是「意思相近」的,而不是仅通过字符串匹配来判断。这就是 embedding 模型干的事:给一段文本,输出一个固定长度的向量(一组浮点数),关键性质是意思相近的文本,向量在空间中也相近。
实际维度通常是几百到几千,比如本文后面用的 Qwen3-Embedding-0.6B 输出 1024 维向量。每一维代表什么没有显式含义,是模型从海量数据里学出来的隐式特征。
你可以类比成地图上的坐标来理解,北京和天津地理位置近,坐标就接近,北京和巴黎位置远,坐标就差得多。embedding 就是给每段文字配了一个「语义空间」里的坐标,相当于空间中的一个点,两段文本相当于两个点,语义相近的话两个点的距离就近,语义不相近的话距离就远。
具体的相近程度可以用一个公式算出来,叫余弦相似度(cosine similarity),取值在 -1 到 1 之间,越接近 1 说明语义越相似,接近 -1 说明语义越不相似。公式细节先不用管,后面会有现成的 API 帮你算,我们直接动手实现一个简单的 RAG 系统。