ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

向量与余弦相似度:RAG 背后的数学地基

2026/8/28 15:49:39 拓冰建站 浏览量
向量与余弦相似度:RAG 背后的数学地基 向量与余弦相似度RAG 背后的数学地基文档加载完了切成小块了——然后呢用户问怎么优化 SQL 查询你总不能把所有文档块都扔给模型吧Token 爆炸不说模型也看不过来。解决思路是先找到和问题最相关的文档块再喂给模型。而这个找最相关的能力靠的就是向量和余弦相似度。本文零公式恐惧用直觉和代码讲透这两个概念。一、RAG 到底在干什么——先把全貌装进脑子先搞清楚 RAGRetrieval-Augmented Generation检索增强生成的完整流程这个流程里最关键的就是第②步——怎么判断哪段文档和问题最相关。答案就是向量 余弦相似度。RAG 的活儿就一句话先把相关的料挑出来再让模型照着料说话。挑料挑得准不准直接决定回答质量。二、向量是什么——给文字贴一个GPS 坐标2.1 直觉理解——每个句子都有自己的经纬度想象每段文字都有一个 GPS 坐标苹果好吃 → 坐标 A我喜欢吃苹果 → 坐标 B和 A 很近今天下雨了 → 坐标 C和 A、B 都很远语义相近的文字坐标也相近。这就是向量嵌入Embedding的核心思想。嵌入模型 给文字发 GPS 的定位员。它把一句话变成一个坐标点语义越接近坐标靠得越近。2.2 用代码感受一下——定位员是怎么工作的from langchain_openai import OpenAIEmbeddings ​ embeddings OpenAIEmbeddings(modeltext-embedding-3-small) ​ # 把文字变成向量一串数字 vec1 embeddings.embed_query(苹果是一种很好吃的水果) vec2 embeddings.embed_query(我喜欢吃苹果) vec3 embeddings.embed_query(今天下雨了) ​ print(f向量维度{len(vec1)}) # 1536 维 print(f前 5 个数字{vec1[:5]}) # [0.0123, -0.0456, 0.0789, -0.0234, 0.0567]向量就是一个高维坐标。1536 维听起来吓人但你可以把它想象成有 1536 个坐标轴的 GPS——每个轴代表一种语义方向比如水果程度、天气程度、积极程度……三、余弦相似度衡量两个向量有多近有了坐标怎么算两个点之间的距离这里不用欧几里得距离直线距离而是用余弦相似度——衡量两个向量方向的接近程度而不是绝对距离。3.1 直觉理解——比的是方向不是远近vec1 和 vec2 方向几乎一致 → 余弦相似度接近 1 → 语义相近vec1 和 vec3 方向完全不同 → 余弦相似度接近 0 → 语义不同余弦相似度看的是你俩朝一个方向走吗而不是你俩隔了几公里。同一篇文章的长短版方向一致相似度照样高。3.2 动手算一下——自己写个 10 行公式import numpy as np ​ def cosine_similarity(vec_a, vec_b): 计算两个向量的余弦相似度 dot_product np.dot(vec_a, vec_b) norm_a np.linalg.norm(vec_a) norm_b np.linalg.norm(vec_b) return dot_product / (norm_a * norm_b) ​ # 计算相似度 sim_12 cosine_similarity(vec1, vec2) # 苹果好吃 vs 我喜欢吃苹果 sim_13 cosine_similarity(vec1, vec3) # 苹果好吃 vs 今天下雨了 ​ print(fvec1 vs vec2 相似度{sim_12:.4f}) # 0.85 左右很相似 print(fvec1 vs vec3 相似度{sim_13:.4f}) # 0.30 左右不太相似3.3 余弦相似度的取值范围——给你一把打分尺值含义示例1.0方向完全一致你好 vs 你好0.7~0.9高度相关苹果好吃 vs 我喜欢吃苹果0.3~0.5有一定关联苹果好吃 vs 水果有营养0.0~0.2基本无关苹果好吃 vs 今天下雨了余弦相似度的核心优势它只关心方向不关心长度。一篇 100 字的文章和一篇 10000 字的文章如果语义相同余弦相似度依然很高。欧几里得距离做不到这一点。四、实战用余弦相似度做一个迷你搜索引擎纸上谈兵没用咱们直接手写一个迷你搜索引擎感受一下找最相关文档到底是怎么回事。from langchain_openai import OpenAIEmbeddings import numpy as np ​ embeddings OpenAIEmbeddings(modeltext-embedding-3-small) ​ # 知识库文档块 documents [ SQL 查询优化使用索引可以大幅提升查询速度, Python 装饰器是一种高阶函数用于修改函数行为, 数据库索引类型B-Tree 索引、Hash 索引、全文索引, Docker 容器化部署编写 Dockerfile 的最佳实践, MySQL 慢查询分析使用 EXPLAIN 查看执行计划, ] ​ # 把所有文档向量化 doc_vectors [embeddings.embed_query(doc) for doc in documents] ​ # 用户问题 query 怎么优化 SQL 查询 query_vector embeddings.embed_query(query) ​ # 计算余弦相似度 def cosine_sim(a, b): return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)) ​ # 对每个文档计算相似度 scores [cosine_sim(query_vector, dv) for dv in doc_vectors] ​ # 排序取 Top 3 ranked sorted(zip(scores, documents), reverseTrue)[:3] ​ for score, doc in ranked: print(f相似度 {score:.4f} | {doc})输出效果相似度 0.8901 | SQL 查询优化使用索引可以大幅提升查询速度 相似度 0.8234 | MySQL 慢查询分析使用 EXPLAIN 查看执行计划 相似度 0.7654 | 数据库索引类型B-Tree 索引、Hash 索引、全文索引看到了吗怎么优化 SQL 查询这个自然语言问题自动把SQL 优化、慢查询、索引这三篇最相关的文档找出来了。这就是 RAG 的检索核心。五、为什么不用关键词匹配——认字 vs 懂意思你可能会问直接用if SQL in doc做关键词匹配不行吗来看一个对比用户问题关键词匹配语义匹配向量怎么加快数据库查询速度找不到SQL关键词漏掉找到 SQL 优化相关文档 ✓iPhone 怎么修找不到苹果关键词找到 Apple 维修文档 ✓如何减肥精确匹配减肥也匹配到瘦身、减脂相关内容 ✓关键词匹配是认字语义匹配是懂意思。向量检索不受同义词、近义词的限制这也是为什么 RAG 比传统搜索强大得多。六、嵌入模型选型云端 vs 本地——按场景挑定位员迷你搜索引擎跑通了接下来要上规模了。嵌入模型选哪个先看一张对比表模型维度语言部署方式一句话推荐text-embedding-3-small1536多语言OpenAI 云端综合首选性价比高text-embedding-3-large3072多语言OpenAI 云端精度要求高时用bge-large-zh-v1.51024中文本地部署纯中文场景本地跑nomic-embed-text768英文Ollama 本地本地开发测试# 本地嵌入模型Ollama from langchain_ollama import OllamaEmbeddings ​ embeddings OllamaEmbeddings(modelnomic-embed-text) vec embeddings.embed_query(你好世界) print(len(vec)) # 768 维云端省事、本地省钱关键看你的数据能不能出内网。折腾原型用云端数据敏感就老老实实本地跑。七、总结——一张表 一句金句概念一句话向量嵌入把文字变成一串数字坐标语义相近的文字坐标也相近余弦相似度衡量两个向量方向的接近程度值越接近 1 越相似嵌入模型负责做文字→向量转换的模型RAG 检索用余弦相似度从知识库中找最相关的文档块向量 余弦相似度 RAG 的数学地基。不需要懂数学公式只需要理解同类文字向量方向接近这个直觉就足以理解 RAG 的工作原理了。下一篇我们把这个迷你搜索引擎升级成真正的向量存储与检索系统——百万级文档也照样秒查。参考资料OpenAI Embeddings 文档余弦相似度 - 维基百科