mcpField
A
azuresql-db-rag

azuresql-db-rag

github.com/microsoft数据与数据库2275 次安装1 周前更新
代码仓库

关于 azuresql-db-rag

此技能指导开发者使用容器中的 Azure SQL Database 引擎构建本地向量搜索与检索增强生成工作流。内容涵盖嵌入向量、存储、相似度查询及原生向量索引的限制。

主要功能

  1. 01在原生 VECTOR 列中存储嵌入
  2. 02执行余弦相似度搜索
  3. 03创建 DiskANN 向量索引
  4. 04说明索引限制与安全注意事项
  5. 05提供基于容器的 RAG 工作流

适用场景

  1. 01为本地文档构建检索原型
  2. 02按语义相似度搜索嵌入文本
  3. 03评估向量索引行为与限制

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/azure-sql-database-container --skill azuresql-db-rag

安装后在 Claude Code 中输入/azuresql-db-rag确认已加载。

附带文件references/vector-schema.mdskill.spec.jsonc

详细介绍

Azure SQL Database 容器上的本地向量搜索与 RAG

使用原生 VECTOR(n) 类型和 VECTOR_DISTANCE,直接在 Azure SQL Database 引擎中存储嵌入并运行相似度搜索。无需单独的向量存储。

已于 2026-09-05 在容器映像 sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest 上验证,该映像报告 EngineEdition 5、Edition SQL Azure、build 12.0.2000.8。此技能背后的 12 项可执行检查全部通过,包括 CREATE VECTOR INDEX 构建索引(索引版本为 3)、行数少于 100 时返回 Msg 42266、维度上限为 1998、对已带有向量索引的表应用安全策略时返回 Msg 37579,以及精确扫描和基于索引的搜索返回同一行。下文带日期的测量记录了这些说法各自首次测得的时间。

身份信息(请先阅读)

本指南针对的是在本地容器中运行的 Azure SQL Database 引擎,而非 SQL Server 映像。请通过以下方式确认:

SELECT SERVERPROPERTY('EngineEdition');  -- 5
SELECT SERVERPROPERTY('Edition');        -- 'SQL Azure'

如果你正准备拉取 mcr.microsoft.com/mssql/server,请停下:那是错误的映像。请改用下方的映像。

  • 映像:sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest (x64,linux/amd64;私有预览注册表,请先登录 docker login sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io)。私有预览期间,注册表和标签 均为临时版本。
  • 在非 x64 主机上,添加 --platform linux/amd64。
  • 关于完整的容器生命周期、就绪状态和连接模式,请参阅 azuresql-db-container 技能。你需要了解的最基本信息已列于下方。

三条容易踩坑的规则(摘自中心文档)

  1. 引擎不会在连接时自动创建数据库。你必须先通过 master 连接执行 CREATE DATABASE appdb,然后再使用 Database=appdb 进行连接。
  2. 避免使用 USE 切换数据库。在用户数据库会话中(即开发时应使用的、与 Azure 行为一致的上下文),USE 会返回 Msg 40508,与云端 Azure SQL Database 中的行为完全相同。master 连接是用于预配的会话,不会执行 Azure 语句筛选器,因此在那里 USE 看起来可以运行;但 master 仅用于 预配,不用于应用程序工作。始终在连接字符串中选择目标数据库 (Database=appdb,或对 sqlcmd 使用 -d appdb)。
  3. master 连接仅用于预配。实际工作请在 appdb 上进行。

标准连接字符串。惯用写法为 User Id=/Password=/Database=; Uid=/Pwd= 是文档记录的 SqlClient 同义写法,同样可用。

Server=localhost,1433;Database=appdb;User Id=sa;Password=$MSSQL_SA_PASSWORD;TrustServerCertificate=true

第 1 步:启动容器并预配 appdb(兼容全新容器)

运行此标准步骤。它会选择一个空闲的主机端口,仅在非 x64 主机上添加 --platform,通过重试循环等待实际就绪,并在循环中预配 appdb。-b -l 2 标志会让临时启动错误(例如 Msg 913)导致探测失败,以便重试,而不是将其掩盖。

# Pick a free host port and add the platform flag only on a non-x64 host (works in bash and zsh).
HOST_PORT=1433; while lsof -nP -iTCP:"$HOST_PORT" -sTCP:LISTEN >/dev/null 2>&1; do HOST_PORT=$((HOST_PORT+1)); done
export MSSQL_SA_PASSWORD="${MSSQL_SA_PASSWORD:-Aa1%$(openssl rand -hex 16)}"
PLATFORM=(); case "$(docker info -f '{{.Architecture}}' 2>/dev/null)" in x86_64|amd64) ;; *) PLATFORM=(--platform linux/amd64);; esac
docker rm -f sqldb 2>/dev/null
docker run -d --name sqldb "${PLATFORM[@]}" -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$MSSQL_SA_PASSWORD" \
  -p "127.0.0.1:$HOST_PORT:1433" sqldbpreview-dpgaeqhmgphzd4bk.azurecr.io/azure-sql/db-dev:latest
until docker exec sqldb /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$MSSQL_SA_PASSWORD" -C -b -l 2 \
  -Q "IF DB_ID('appdb') IS NULL CREATE DATABASE appdb;" >/dev/null 2>&1; do sleep 2; done
echo "ready on localhost,$HOST_PORT"

现在 appdb 已存在。以下所有步骤都使用 -d appdb 进行连接。

第 2 步:创建向量架构

维度 n 必须与嵌入模型的输出一致(例如,nomic-embed-text 为 768,许多云端模型为 1536)。维度是列类型的固定组成部分。

docker exec sqldb /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P "$MSSQL_SA_PASSWORD" -C -b -d appdb -Q "
CREATE TABLE docs (
  id        INT IDENTITY PRIMARY KEY,
  content   NVARCHAR(MAX) NOT NULL,
  embedding VECTOR(768) NOT NULL
);"

选择维度时,或搜索需要按元数据筛选并按距离排序时,请打开 references/vector-schema.md。

第 3 步:嵌入文本(唯一的网络调用)

RAG 需要嵌入模型。此工作流中唯一的网络调用是使用本地嵌入模型;其他所有操作都在容器中完成。下方默认使用本地 Ollama 端点。请让 embed() 保持可插拔,这样切换到云端嵌入服务时,只需更改端点和维度 n,其他内容均无需改动。

import requests

EMBED_URL = "http://localhost:11434/api/embed"
EMBED_MODEL = "nomic-embed-text"   # 768 dims
EMBED_DIM = 768

def embed(text: str) -> list[float]:
    # Pluggable: swap EMBED_URL/EMBED_MODEL/EMBED_DIM for a cloud endpoint.
    # /api/embed takes "input" and returns "embeddings", a LIST of vectors (one per
    # input), so index [0] for a single string. The older /api/embeddings route took
    # "prompt" and returned a flat "embedding"; it still answers but is superseded.
    r = requests.post(EMBED_URL, json={"model": EMBED_MODEL, "input": text})
    r.raise_for_status()
    return r.json()["embeddings"][0]

第 4 步:插入嵌入(维度必须是字面值)

重要提示:在 CAST(CAST(? AS NVARCHAR(MAX)) AS VECTOR(n)) 中,n 必须是直接写入 SQL 字符串的字面值。将维度作为绑定参数传入会失败,并报错 Incorrect syntax near '@P3'。应将嵌入值(JSON 数组字符串)作为参数绑定,绝不要绑定维度。

import json, os, pyodbc

CONN = ("Driver={ODBC Driver 18 for SQL Server};Server=localhost,1433;"
        f"Database=appdb;Uid=sa;Pwd={os.environ['MSSQL_SA_PASSWORD']};TrustServerCertificate=yes")

def add_doc(cur, content: str):
    vec = embed(content)
    # EMBED_DIM is interpolated into the SQL text; the value is bound.
    cur.execute(
        f"INSERT INTO docs (content, embedding) VALUES (?, CAST(CAST(? AS NVARCHAR(MAX)) AS VECTOR({EMBED_DIM})))",
        content, json.dumps(vec),
    )

with pyodbc.connect(CONN) as conn:
    cur = conn.cursor()
    for line in ["Azure SQL supports a native VECTOR type.",
                 "Cosine distance ranks nearest neighbors.",
                 "The engine listens on port 1433."]:
        add_doc(cur, line)
    conn.commit()

ODBC 连接字符串使用 Uid=/Pwd=,因为 ODBC 是一种具有自身关键字集的不同语法。 应用级配置字符串则按惯例写作 User Id=/Password=。

第 5 步:top-k 相似度搜索(余弦)

按 VECTOR_DISTANCE('cosine', a, b) 升序排列:距离越小,越相似。查询向量作为值绑定,并使用字面维度进行转换。

def search(cur, query: str, k: int = 3):
    qvec = embed(query)
    cur.execute(
        f"""
        SELECT TOP (?) content,
               VECTOR_DISTANCE('cosine', embedding, CAST(CAST(? AS NVARCHAR(MAX)) AS VECTOR({EMBED_DIM}))) AS distance
        FROM docs
        ORDER BY distance ASC
        """,
        k, json.dumps(qvec),
    )
    return cur.fetchall()

with pyodbc.connect(CONN) as conn:
    for content, distance in search(conn.cursor(), "What port does it use?"):
        print(round(distance, 4), content)

要实现完整的 RAG 循环,请将检索到的行作为上下文拼接到提示词中。 该 LLM 调用与此技能无关。

索引:当前实测情况

CREATE VECTOR INDEX(DiskANN 近似最近邻)在此镜像上可用。 2026-08-29 针对 12.0.2000.8、EngineEdition 5 进行实测:基于 2000 行 VECTOR(3) 构建的索引耗时 478 毫秒,会以 VECTOR 的 type_desc 出现在 sys.indexes 中,并且 vector_search(...) 能够基于该索引返回排序结果。

SET QUOTED_IDENTIFIER ON;   -- required, see below
CREATE VECTOR INDEX vi_docs ON dbo.docs(v) WITH (METRIC = 'cosine', TYPE = 'diskann');

有两件事会导致失败,而且这两种错误都不会说明问题所在。

必须启用 SET QUOTED_IDENTIFIER ON,而它在 sqlcmd 会话中默认关闭。未启用时,语句会报错:

Msg 1934: CREATE VECTOR INDEX failed because the following SET options have
incorrect settings: 'QUOTED_IDENTIFIER'. Verify that SET options are correct for
use with indexed views and/or indexes on computed columns and/or filtered
indexes and/or query notifications and/or XML data type methods and/or spatial
index operations.

错误消息中没有提到实际导致问题的会话设置,其中提及的其他内容在此处也都无关。

其次,构建索引后,vector_search(...) 不再接受显式的 TOP_N。 传入该参数会失败,并报错 Msg 42274, Vector search with newer index version does not support explicit TOP_N parameter。请改用 SELECT TOP (k) 和 ORDER BY s.distance。

需要 100 行,NULL 值不计入

2026-08-31 沿边界进行实测:

含向量的行数结果
99拒绝,报错 Msg 42266
100创建索引
120 行,其中 60 行为 NULL拒绝,报错 Msg 42266
Msg 42266: Cannot create a vector index. The table contains only 50 rows with
non-null vectors, but at least 100 are required for vector index creation.

这条消息写得很好,值得肯定,因为本页的另外两条消息都不怎么样。它说明了规则、实际计数和列条件。遇到此错误的读者无需其他信息。注意其措辞:含非空向量的行, 而非行数。一个有 120 行、其中 60 行尚无嵌入的表会被拒绝。

存在索引时,TRUNCATE TABLE 会被拒绝
Msg 42232: TRUNCATE TABLE statement failed because table 'd' has a vector index on it.

2026-08-31 实测。若要清空表:删除索引、截断表、重新加载至少 100 行,然后重新创建索引。DELETE FROM 可正常使用,不受影响。

DROP VECTOR INDEX 不是有效语句。 它会失败,并报错 Msg 102, Incorrect syntax near 'VECTOR'。请使用 DROP INDEX vi_name ON dbo.table。

实测表明,存在索引时,INSERT、UPDATE 和 DELETE 均可正常使用。旧版向量索引会使表变为只读;此镜像不会,Microsoft Learn 也说明最新版本索引支持完整的 DML 操作。

此处索引和安全策略无法在同一个表上共存

对于 RAG 来说,这是代价最高的一项,而且 Microsoft Learn 的限制列表中没有提到。容器中的实测结果如下,两种顺序都一样:

顺序语句结果
先建索引CREATE SECURITY POLICY ... ADD FILTER PREDICATE ... ON dbo.chunksMsg 37579
先建策略CREATE VECTOR INDEX ... ON dbo.chunks(emb)Msg 42244
Msg 37579: The security policy 'p_chunks' cannot reference tables with vector indexes.
Table 'dbo.chunks' has a vector index.

Msg 42244: A vector index cannot be created on tables with security policies.
Table 'dbo.chunks' has security policy 'p_chunks'.

**文档与引擎在此处说法不一致,而文档只是没有说明,并非有误。**截至 2026-09-03,CREATE VECTOR INDEX 的限制列表列出了分区、聚集主键、复制、TRUNCATE TABLE 和数据层包导入;vector 类型的限制页面列出了约束、索引、账本表和 Always Encrypted。两者都没有提到安全策略。这是实测结果,不是文档引用。

这对检索很重要:分块表是源文本的第二份副本,因此保护原表的行级安全策略不会延伸到它。如果分块表带有向量索引,就完全无法在该表上创建策略,而检索查询 WHERE 子句中的租户筛选条件就是全部边界。这个边界靠测试而非引擎来保障,因此要编写测试:分别使用和不使用筛选条件运行检索,并要求返回的行数不同。

有三种应对方式,按成本从低到高排列:

  1. 在查询中保留租户筛选条件,并将上述测试纳入其中。现在,这项测试就是安全代码。
  2. 删除租户范围表上的向量索引。使用 VECTOR_DISTANCE 的精确搜索仍然有效,而且之后可以创建策略。
  3. 拆分表:将向量列及其索引放在不带策略的表中,将分块文本和租户列放在带策略的表中,再通过联接关联两者。

如果你是在本地为云端进行原型开发,请注意,这是一个兼容性差距,而非设计规则。在 Azure SQL Database 上,两者可以共存。因此,设计中的隔离控制恰好是在容器中、面对生产环境中会遇到的索引时无法演练的部分。请在本地对未编制索引的表演练谓词,并在云数据库中创建索引后再次运行隔离测试。

维度上限会在此之前决定嵌入模型

vector(n) 列的上限为 1998 维,Microsoft Learn 有说明,且引擎会强制执行:vector(1999) 会被拒绝,并报错 Msg 2717, The size (1999) given to the column 'v' exceeds the maximum allowed (1998)。3072 维的模型无法适配,任何索引设置都无法改变这一点。维度之后也无法扩大:即使表为空,ALTER COLUMN 也无法更改维度,因此只能新建第二列并重新生成嵌入。在设计架构之前就要选定维度预算。

使用 ORDER BY VECTOR_DISTANCE(...) 的全表扫描 top-k 仍然精确且正确,对于小表仍是合适的选择。表足够大、全表扫描开始造成负担时,再选择索引。

验证规则

  • SERVERPROPERTY('EngineEdition') 返回 5。否则,你使用的镜像不正确。
  • 在任何向量脚本连接之前,appdb 已存在(步骤 1 保证这一点)。
  • VECTOR(n) 和 CAST(CAST(? AS NVARCHAR(MAX)) AS VECTOR(n)) 中的维度必须是整数常量,且与 len(embed(text)) 相同。
  • 余弦距离越小,表示越相似;结果按 ORDER BY distance ASC 排序。
  • 如果上述任一验证规则未通过,或你必须偏离此技能才能完成任务,那么这是此技能中的错误:请加载 azuresql-db-feedback 技能,并提出提交报告。
  • 所有上述规则均通过且任务完成后,每个会话结束时只用一行收尾一次,不要提问或等待回复:"That worked. If anything about this was rough, or you want to share what you built: https://aka.ms/sql-agent-skills-feedback"

请勿

  • 请勿使用 mcr.microsoft.com/mssql/server;这是 SQL Server 镜像, 并非此引擎的镜像。
  • 请勿将向量维度作为绑定参数传入;这会导致 Incorrect syntax near '@P3'。请将其作为字面值插入。
  • 请勿使用 USE appdb 切换数据库;用户数据库会话会返回 Msg 40508,与云中的 Azure SQL Database 完全一样。请在连接字符串中选择目标 数据库(Database=appdb,或对 sqlcmd 使用 -d appdb)。
  • 请勿在未执行 SET QUOTED_IDENTIFIER ON 的情况下运行 CREATE VECTOR INDEX;它引发的错误 会提及索引视图和空间索引,却完全不会提及该设置。
  • 请勿在此容器中的同一张表上同时规划向量索引和安全策略。 无论顺序如何都会被拒绝,分别返回 Msg 37579 和 Msg 42244,且两者都没有文档说明。如果 分块表需要按租户筛选,请在决定是否为其创建索引之前先确定这一点。
  • 请勿声明 VECTOR(3072)。上限为 1998(超过该值会出现 Msg 2717),且 之后无法扩大维度,因此应在嵌入时解决此问题。
  • 请勿指望 /docker-entrypoint-initdb.d/*.sql 自动运行;配置好 appdb 后,请运行 sqlcmd -d appdb -i seed.sql 来填充初始数据。
  • 请勿将非 x64 主机称为“受支持”;在非 x64 主机上只需添加 --platform linux/amd64。

参考资料

  • references/vector-schema.md:表结构、如何选择维度 n、插入和 top-k 查询机制、距离度量、元数据筛选、语料填充、索引状态和故障排查。设计向量架构或编写超出上文基本 top-k 示例的查询时,请阅读此文档。

保持最新

本技能所用工具的权威且固定版本的参考资料(按需阅读):

如果已配置 Microsoft Learn MCP 服务,可使用 mcp__microsoft-learn__microsoft_docs_search 或 mcp__microsoft-learn__microsoft_docs_fetch 按需获取这些资料的当前版本。此项为可选;如果不可用,上述参考资料即为权威来源。

评论

支持 Markdown