SQL Server RAG 笔记3:SQLServer2025 向量数据库
SQL Server RAG 笔记3SQLServer2025 向量数据库前言在大模型RAG应用中提起向量数据库大家想到的更多的是Chroma和FAISS微软也紧跟时代的步伐并且在2025年底发布的 SQLServer 2025 也提供了原生向量支持此篇将介绍如何在SQLServer 2025里搭建向量数据库环境。环境准备软件版本要求组件版本要求说明SQL Server2025此版本开始支持原生 VECTOR 数据类型ODBC Driver17用于 Python 连接 SQL ServerPython3.9后端运行环境Ollama最新版本地运行 LLM 和嵌入模型本地嵌入模型也可以考虑使用Microsoft Foundry Local只是模型的支持数量上比较有限所以此篇使用ollama做演示。验证 SQL Server 版本-- 查询 SQL Server 版本SELECTVERSION;-- 版本号对照SQL Server 2025 主版本号为 17.x大家需要下载目前最新的SQLServer 2025从这个版本起微软才开始支持向量数据库。根据部分文档描述后续微软可能对相应部分做调整所以也请留意后续微软的变化。撰写此篇时是2026年5月4日从微软下载的SQLServer 2025 Developer版本也是在这一天。打开SQL Server 2005 preview featureALTERDATABASESCOPED CONFIGURATIONSETPREVIEW_FEATURESON;GO安装 Ollama 及嵌入模型RAG系统中嵌入模型是很关键的用于将文本转换为向量表示从而实现向量检索。这里为了实现和部署的方便我们选择的是本地部署Ollama加一个很小的嵌入模型。# 安装 Ollama (macOS)brewinstallollama# 安装嵌入模型ollama pull nomic-embed-text# 验证模型在返回的结果中看到nomic-embed-text就说明模型下载成功了。ollama list以上Ollama的安装时在命令模式下用brew安装在widows下或者macOS下也可以选择桌面安装相对更容易一些。本文使用的嵌入模型体积很小所以基本在国内网络环境也可以很快的下载完。数据库创建创建向量数据库USEmaster;GOIFNOTEXISTS(SELECTnameFROMsys.databasesWHEREnameVectorDB)BEGINCREATEDATABASEVectorDBCOLLATEChinese_PRC_CI_AS;END;GO数据库的创建跟普通数据库创建没任何区别。表结构设计三张表概述为减少信息冗余这里我们采用三张表结构设计┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Documents │────▶│ TextChunks │────▶│ VectorIndex │ │ 文档表 │ 1:N │ 文本块表 │ 1:1 │ 向量索引表 │ └─────────────┘ └─────────────┘ └─────────────┘大体的切分就是文档信息 - 文本切块原始信息 - 文本切块向量数据信息。文档表 - 存储原始文档CREATETABLEDocuments(DocumentIdBIGINTIDENTITY(1,1)PRIMARYKEY,Title NVARCHAR(500)NOTNULL,Content NVARCHAR(MAX)NOTNULL,Source NVARCHAR(500)NULL,Metadata NVARCHAR(MAX)DEFAULT{},CreatedAt DATETIME2DEFAULTGETDATE(),UpdatedAt DATETIME2DEFAULTGETDATE(),IsDeletedBITDEFAULT0);文本块表 - 存储分块文本CREATETABLETextChunks(ChunkIdBIGINTIDENTITY(1,1)PRIMARYKEY,DocumentIdBIGINTNOTNULL,ChunkIndexINTNOTNULL,ChunkText NVARCHAR(MAX)NOTNULL,ChunkHash NVARCHAR(64)NULL,CreatedAt DATETIME2DEFAULTGETDATE(),IsDeletedBITDEFAULT0,FOREIGNKEY(DocumentId)REFERENCESDocuments(DocumentId));以上两个表跟创建传统表没有任何区别。向量索引表 - 存储分块文本向量化之后的内容CREATETABLEVectorIndex(VectorIdBIGINTIDENTITY(1,1)PRIMARYKEY,ChunkIdBIGINTNOTNULLUNIQUE,EmbeddingVector VECTOR(768)NOTNULL,CreatedAt DATETIME2DEFAULTGETDATE(),IsDeletedBITDEFAULT0,FOREIGNKEY(ChunkId)REFERENCESTextChunks(ChunkId));留意字段EmbeddingVector它的类型是VECTOR。EmbeddingVector VECTOR(768)NOTNULL这是 SQL Server 2025 的原生向量类型VECTOR(768)表示 768 维向量与 nomic-embed-text 模型输出维度一致原生支持向量存储无需像旧版本那样将向量序列化为 JSON 或 Base64向量格式为方括号数组[0.123, -0.456, 0.789, ...]关于如何确定向量类型的维度这个是需要跟使用的嵌入模型对应的而如何获知使用的嵌入模型的维度最简单的方法就是问豆包加交叉验证避免幻觉。需留意如果不是SQLServer 2025那么这个表的创建会失败。创建向量索引ALTERDATABASESCOPED CONFIGURATIONSETPREVIEW_FEATURESON;GOCREATEVECTORINDEXidx_content_vectorONdbo.VectorIndex(EmbeddingVector)WITH(METRICcosine);重要不然后面的VECTOR_SEARCH函数会报错。而且要打开预览版功能目前添加向量索引还是预览功能后续应该会在增量补丁里被扶正。向量化插入与读取这部分的代码本应放在下一篇讲解但涉及到如何做向量检索所以先贴两个关键步骤出来。插入向量defcreate_vector(chunk_id:int,embedding:List[float])-int:# Python 列表转为 SQL Server VECTOR 格式方括号数组embedding_str[,.join(str(x)forxinembedding)]sqlf DECLARE embedding NVARCHAR(MAX) {embedding_str}; INSERT INTO VectorIndex (ChunkId, EmbeddingVector) VALUES ({chunk_id}, CAST(embedding AS VECTOR(768))); withvdb.get_cursor()ascursor:cursor.execute(sql)知识点笔记向量格式转换Python:[0.1, 0.2, 0.3]SQL Server VECTOR:[0.1,0.2,0.3]无空格为何使用 NVARCHAR(MAX) 中转直接CAST(? AS VECTOR)参数化查询会报错原因ODBC 驱动将字符串参数识别为ntext类型无法转换为VECTOR解决使用 T-SQL 局部变量embedding中转到入库这一步查询的内容已经通过嵌入模型转换成向量序列了。具体如何转换会在下一篇做介绍。相似度检索实现使用 SQL Server VECTOR_SEARCH关于如何检索目前国内介绍的很少在国外网站上能找到一些资源但都五花八门。这里我用了一个我自己已经调通的方式就是基于SQL Server 2025 提供的原生的VECTOR_SEARCH函数支持高效的向量相似度检索。staticmethoddefvector_search(query_embedding:List[float],top_k:int5,min_score:float0.0)-List[dict]:embedding_str[,.join(str(x)forxinquery_embedding)]sqlf DECLARE qv VECTOR(768) CAST({embedding_str} AS VECTOR(768)) SELECT tc.ChunkId, tc.DocumentId, tc.ChunkIndex, tc.ChunkText, tc.ChunkHash, tc.CreatedAt, d.Title, vs.distance FROM ( SELECT * FROM VECTOR_SEARCH( TABLE VectorIndex AS vi, COLUMN EmbeddingVector, SIMILAR_TO qv, METRIC cosine, TOP_N {top_k}) AS vs1 ) AS vs INNER JOIN TextChunks tc ON vs.ChunkId tc.ChunkId INNER JOIN Documents d ON tc.DocumentId d.DocumentId WHERE tc.IsDeleted 0 ORDER BY vs.distance withvdb.get_cursor()ascursor:cursor.execute(sql)rowscursor.fetchall()results[]forrowinrows:distancerow[7]ifrow[7]isnotNoneelse1.0score1.0-distance# 距离转相似度ifscoremin_score:results.append({chunk_id:row[0],document_id:row[1],chunk_index:row[2],chunk_text:row[3],chunk_hash:row[4],created_at:row[5],document_title:row[6],score:float(score)})returnresults知识点笔记VECTOR_SEARCH 语法VECTOR_SEARCH(TABLEtable_nameASalias,COLUMNvector_column_name,SIMILAR_TOquery_vector,METRICcosine,TOP_Nn)参数说明TABLE指定向量索引表COLUMN指定向量列必须是 VECTOR 类型SIMILAR_TO查询向量必须先转为 VECTOR 类型METRIC距离度量方式‘cosine’、‘dot’、‘euclidean’TOP_N返回前 N 个最相似的结果为何使用 DECLARE 变量直接在SIMILAR_TO中使用CAST(... AS VECTOR)会报错使用DECLARE qv VECTOR(768)声明变量后再引用可避免此问题尚不清楚报错的原因距离转相似度VECTOR_SEARCH返回的是距离值越接近 0 越相似余弦相似度 1 - 余弦距离为什么不直接去JOIN而要套一层SELECT *。如果直接去JOIN语法会报错说ChunkId有问题尽管其在FROM VECTOR_SEARCH里确实是存在的但就是找不到所以这样折腾了一下。阶段总结经历N多轮报错终于调通了一条能跑通的方式。现在社区资源关于这部分内容不是很多所以解决起来确实花了点时间而且有些问题看上去确实很挠头只能根据自己的经验找办法去规避。确实相比其它技术方案可参考的资料确实少了些不过相信后续随着微软的推进相关参考资料会逐渐丰富起来。另如果你用Vibe Coding生成SQLServer的相应代码运行后大概率会出问题可能当前2026年5月距离SQLServer 2025的发布2025年11月前后时间并不是很长所以相应的代码库还没有更新如果你在Vibe Coding中同样走不通建议把此篇文章的URL提供给它作为参考。也请留意如果在目前这个时间点你部署SQLServer 2025并且使用Vibe Coding生成的话大概率会给一套不用VECTOR字段和索引用NVARCHAR(MAX)然后在python代码里把所有块都读过来python代码里做余弦相似度计算。这个方法可行适用数据量极小的场景当然这在现实场景中是很难满足在数据量上的需求的这是我在学习中踩过的坑所以也是为什么会有这么一篇。当然随着社区内容的增多Vibe Coding工具应该很快也会迭代知识库从而产出SQLServer 2025向量库原生支持的方法。下一篇会继续介绍中间服务层和前端页面的构建并且会把最终的整体代码都更细到Github上。