SQL Server RAG Note 3: Basis Data Vektor SQLServer2025 – Copenhagen Husky (aspnetx)
11 mins read

SQL Server RAG Note 3: Basis Data Vektor SQLServer2025 – Copenhagen Husky (aspnetx)

Dalam aplikasi RAG model besar, ketika orang memikirkan database vektor, mereka lebih memikirkan Chroma dan FAISS. Microsoft juga mengikuti perkembangan zaman, dan SQLServer 2025, yang dirilis pada akhir tahun 2025, juga menyediakan dukungan vektor asli. Artikel ini akan memperkenalkan cara membangun lingkungan database vektor di SQLServer 2025.

Perkenalan

Dalam aplikasi RAG model besar, ketika orang memikirkan database vektor, mereka lebih memikirkan Chroma dan FAISS. Microsoft juga mengikuti perkembangan zaman, dan SQLServer 2025, yang dirilis pada akhir tahun 2025, juga menyediakan dukungan vektor asli. Artikel ini akan memperkenalkan cara membangun lingkungan database vektor di SQLServer 2025.

Persiapan lingkungan

Persyaratan versi perangkat lunak

komponen Persyaratan versi ilustrasi
SQLServer 2025 Versi ini mulai mendukung tipe data VECTOR asli
pengemudi ODBC 17+ Digunakan untuk terhubung ke SQL Server menggunakan Python
ular piton 3,9+ Lingkungan operasi backend
menjadi Versi terbaru Jalankan LLM dan instal model secara lokal

Anda juga dapat mempertimbangkan untuk menggunakan Microsoft Foundry Local untuk model tersemat lokal, namun jumlah model yang didukung relatif terbatas, jadi artikel ini menggunakan ollama untuk demonstrasi.

Verifikasi versi SQL Server

-- 查询 SQL Server 版本
SELECT @@VERSION;

-- 版本号对照,SQL Server 2025 主版本号为 17.x

Anda perlu mengunduh SQLServer terbaru 2025. Mulai versi ini, Microsoft mulai mendukung database vektor.

Berdasarkan uraian beberapa dokumen, Microsoft mungkin akan melakukan penyesuaian pada bagian terkait di kemudian hari, sehingga perlu memperhatikan perubahan selanjutnya dari Microsoft.

Pada saat penulisan ini, tanggal 4 Mei 2026, dan versi Pengembang SQLServer 2025 yang diunduh dari Microsoft juga tersedia hari ini.

Instal Ollama dan sematkan modelnya

Model penyematan dalam sistem RAG penting untuk mengubah teks menjadi representasi vektor untuk mencapai pengambilan vektor.

Untuk kenyamanan implementasi dan penerapan, kami memilih untuk menginstal Ollama secara lokal dan menambahkan model kecil yang disematkan.

# 安装 Ollama (macOS)
brew install ollama

# 安装嵌入模型
ollama pull nomic-embed-text

# 验证模型,在返回的结果中看到nomic-embed-text就说明模型下载成功了。
ollama list

Saat menginstal Ollama di atas, gunakan brew dalam mode perintah. Anda juga dapat memilih instalasi desktop di windows atau macOS, yang lebih mudah.

Model tersemat yang digunakan dalam artikel ini berukuran sangat kecil, sehingga dapat diunduh dengan cepat di lingkungan jaringan domestik.

membuat basis data

Buat database vektor

USE master;
GO

IF NOT EXISTS (SELECT name FROM sys.databases WHERE name="VectorDB")
BEGIN
    CREATE DATABASE VectorDB
    COLLATE Chinese_PRC_CI_AS;
END;
GO

Membuat database tidak berbeda dengan membuat database biasa.

Desain struktur meja

Ringkasan tiga tabel

Untuk mengurangi redundansi informasi, berikut kami menggunakan desain struktur tiga tabel:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Documents  │────▶│  TextChunks │────▶│ VectorIndex │
│   文档表     │ 1:N │   文本块表   │ 1:1 │  向量索引表  │
└─────────────┘     └─────────────┘     └─────────────┘

Segmentasi yang umum adalah: informasi dokumen -> segmentasi teks informasi asli -> segmentasi teks informasi data vektor.

Tabel dokumen – menyimpan dokumen asli

CREATE TABLE Documents (
    DocumentId BIGINT IDENTITY(1,1) PRIMARY KEY,
    Title NVARCHAR(500) NOT NULL,
    Content NVARCHAR(MAX) NOT NULL,
    Source NVARCHAR(500) NULL,
    Metadata NVARCHAR(MAX) DEFAULT '{}',
    CreatedAt DATETIME2 DEFAULT GETDATE(),
    UpdatedAt DATETIME2 DEFAULT GETDATE(),
    IsDeleted BIT DEFAULT 0
);

Tabel blok teks – menyimpan teks suatu karya

CREATE TABLE TextChunks (
    ChunkId BIGINT IDENTITY(1,1) PRIMARY KEY,
    DocumentId BIGINT NOT NULL,
    ChunkIndex INT NOT NULL,
    ChunkText NVARCHAR(MAX) NOT NULL,
    ChunkHash NVARCHAR(64) NULL,
    CreatedAt DATETIME2 DEFAULT GETDATE(),
    IsDeleted BIT DEFAULT 0,
    FOREIGN KEY (DocumentId) REFERENCES Documents(DocumentId)
);

Kedua tabel di atas tidak berbeda dengan membuat meja tradisional.

Tabel indeks vektor – menyimpan konten vektor dari potongan teks

CREATE TABLE VectorIndex (
    VectorId BIGINT IDENTITY(1,1) PRIMARY KEY,
    ChunkId BIGINT NOT NULL UNIQUE,
    EmbeddingVector VECTOR(768) NOT NULL,
    CreatedAt DATETIME2 DEFAULT GETDATE(),
    IsDeleted BIT DEFAULT 0,
    FOREIGN KEY (ChunkId) REFERENCES TextChunks(ChunkId)
);

Perhatikan field: EmbeddingVector, sejenis VECTOR.

EmbeddingVector VECTOR(768) NOT NULL

Ini adalah tipe vektor asli dari SQL Server 2025:

  • VECTOR(768): Mewakili vektor 768 dimensi, konsisten dengan dimensi keluaran model teks yang disematkan nomic
  • Dukungan asli untuk penyimpanan vektor, tidak perlu membuat serial vektor ke JSON atau Base64 seperti versi lama
  • Format vektor sebagai array tanda kurung siku:[0.123, -0.456, 0.789, ...]

Mengenai cara menentukan ukuran jenis vektor harus sesuai dengan model embedding yang digunakan. Sedangkan untuk mengetahui ukuran model embedding yang digunakan, cara termudah adalah dengan menanyakan Doubao dan menambahkan validasi silang (untuk menghindari ilusi).

Perhatikan bahwa jika bukan SQL Server 2025, pembuatan tabel ini akan gagal.

Buat indeks vektor

ALTER DATABASE SCOPED CONFIGURATION
SET PREVIEW_FEATURES = ON;
GO

CREATE VECTOR INDEX idx_content_vector
    ON dbo.VectorIndex(EmbeddingVector)
    WITH (METRIC = 'cosine');

Yang penting, fungsi VECTOR_SEARCH di bawah ini akan melaporkan kesalahan. Selain itu, fungsi versi pratinjau harus diaktifkan. Saat ini, penambahan indeks vektor masih merupakan fungsi pratinjau, dan harus diperbaiki pada patch tambahan berikutnya.

Masukkan vektor dan baca

Bagian kode ini harus dijelaskan di artikel berikutnya, tetapi ini menyangkut cara mendapatkan vektor, jadi saya akan memposting dua langkah penting terlebih dahulu.

masukkan vektor

def create_vector(chunk_id: int, embedding: List[float]) -> int:
    # Python 列表转为 SQL Server VECTOR 格式:方括号数组
    embedding_str="[" + ','.join(str(x) for x in embedding) + ']'

    sql = f"""
    DECLARE @embedding NVARCHAR(MAX) = '{embedding_str}';
    INSERT INTO VectorIndex (ChunkId, EmbeddingVector)
    VALUES ({chunk_id}, CAST(@embedding AS VECTOR(768)));
    """
    with vdb.get_cursor() as cursor:
        cursor.execute(sql)

Perhatikan poin pengetahuannya:

  1. Konversi format vektor:

    • ular piton: [0.1, 0.2, 0.3]
    • VEKTOR SQL Server: [0.1,0.2,0.3](tanpa spasi)
  2. Mengapa menggunakan transfer NVARCHAR(MAX).:

    • secara langsung CAST(? AS VECTOR) Kueri parameter akan melaporkan kesalahan
    • Alasan: Driver ODBC mengenali parameter string sebagai ntext jenis, tidak dapat diubah VECTOR
    • Solusi: Gunakan variabel lokal T-SQL @embedding transit

Pada langkah pergudangan, konten kueri telah diubah menjadi rangkaian vektor melalui model penyematan. Metode konversi spesifiknya akan dijelaskan di artikel berikutnya.

implementasi pengambilan kesamaan

Soal cara pencarian, kini sudah ada beberapa perkenalan di China. Beberapa sumber dapat ditemukan di situs asing, tetapi semuanya berbeda. Di sini, saya menggunakan metode kustomisasi saya sendiri, berdasarkan metode asli yang disediakan oleh SQL Server 2025. VECTOR_SEARCH Berfungsi untuk mendukung pengambilan persamaan vektor yang efisien.

@staticmethod
def vector_search(query_embedding: List[float], top_k: int = 5, min_score: float = 0.0) -> List[dict]:
    embedding_str="[" + ','.join(str(x) for x in query_embedding) + ']'
    sql = f"""
    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
    """

    with vdb.get_cursor() as cursor:
        cursor.execute(sql)
        rows = cursor.fetchall()

        results = []
        for row in rows:
            distance = row[7] if row[7] is not None else 1.0
            score = 1.0 - distance  # 距离转相似度
            if score >= min_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)
                })
        return results

Perhatikan poin pengetahuannya:

  1. Sintaks VECTOR_SEARCH:
VECTOR_SEARCH(
    TABLE = table_name AS alias,
    COLUMN = vector_column_name,
    SIMILAR_TO = query_vector,
    METRIC = 'cosine',
    TOP_N = n
)
  1. Deskripsi parameter:

    • TABLE: Menentukan tabel indeks vektor
    • COLUMN: Tentukan bidang vektor (harus bertipe VECTOR)
    • SIMILAR_TO: Query vektor (harus dikonversi ke tipe VECTOR terlebih dahulu)
    • METRIC: Metode pengukuran jarak (‘cosine’, ‘point’, ‘euclidean’)
    • TOP_N: Mengembalikan N hasil paling mirip teratas
  2. Mengapa menggunakan variabel DECLARE:

    • langsung masuk SIMILAR_TO digunakan di CAST('...' AS VECTOR) Ini akan melaporkan kesalahan
    • menggunakan DECLARE @qv VECTOR(768) Deklarasikan variabel dan rujuk ke variabel tersebut untuk menghindari masalah ini
    • Alasan kesalahan ini masih belum jelas
  3. jarak menuju kesamaan:

    • VECTOR_SEARCH Yang dikembalikan adalah nilai jarak (mendekati 0, semakin mirip)
    • Kosinus sama = 1 – Jarak kosinus

Mengapa tidak langsung ke JOIN, tetapi gunakan layer SELECT * sebagai gantinya. Jika Anda langsung ke JOIN, sintaks akan melaporkan kesalahan yang mengatakan ada masalah dengan ChunkId. Walaupun di FROM VECTOR_SEARCH tidak bisa ditemukan, jadi saya sudah bersusah payah beberapa saat.

Ringkasan panggung

Setelah beberapa kali melaporkan kesalahan, saya akhirnya menemukan jalan keluarnya. Saat ini, tidak banyak sumber daya komunitas yang menangani hal ini, sehingga memerlukan waktu untuk memperbaikinya, dan beberapa masalah tampak sangat membingungkan. Anda hanya dapat menemukan cara untuk mencegahnya berdasarkan pengalaman Anda sendiri. Memang benar bahwa dibandingkan dengan solusi teknis lainnya, bahan referensi yang ada lebih sedikit, namun saya yakin jika Microsoft maju di masa depan, bahan referensi yang relevan secara bertahap akan menjadi lebih kaya.

Selain itu, jika Anda menggunakan Vibe Coding untuk menghasilkan kode yang sesuai untuk SQL Server, ada kemungkinan akan terjadi masalah setelah menjalankannya. Ada kemungkinan bahwa waktu antara sekarang (Mei 2026) dan rilis SQL Server 2025 (sekitar November 2025) tidak terlalu lama, sehingga basis kode terkait belum diperbarui. Jika Anda juga terjebak pada Vibe Coding, kami sarankan untuk memberikan URL artikel ini sebagai referensi.

Perhatikan juga bahwa jika Anda menerapkan SQLServer 2025 saat ini dan menggunakan Vibe Coding untuk menghasilkan, kemungkinan besar Anda tidak akan menggunakan kolom dan indeks VECTOR, menggunakan NVARCHAR (MAX), lalu membaca seluruh blok dalam kode python, dan melakukan perhitungan seperti kosinus dalam kode python. Metode ini layak dan cocok untuk skenario dengan jumlah data yang sangat kecil. Tentu saja, dalam skenario nyata, sulit untuk memenuhi permintaan volume data. Ini adalah jebakan yang saya temui dalam studi saya, itulah artikelnya. Tentu saja, dengan penambahan konten komunitas, alat Vibe Coding akan segera mengubah basis pengetahuannya untuk menghasilkan metode yang secara asli didukung oleh pustaka vektor SQLServer 2025.

Artikel selanjutnya akan terus memperkenalkan konstruksi lapisan layanan perantara dan halaman depan, dan akan membuat kode keseluruhan akhir secara lebih rinci di Github.

PakarPBN

A Private Blog Network (PBN) is a collection of websites that are controlled by a single individual or organization and used primarily to build backlinks to a “money site” in order to influence its ranking in search engines such as Google. The core idea behind a PBN is based on the importance of backlinks in Google’s ranking algorithm. Since Google views backlinks as signals of authority and trust, some website owners attempt to artificially create these signals through a controlled network of sites.

In a typical PBN setup, the owner acquires expired or aged domains that already have existing authority, backlinks, and history. These domains are rebuilt with new content and hosted separately, often using different IP addresses, hosting providers, themes, and ownership details to make them appear unrelated. Within the content published on these sites, links are strategically placed that point to the main website the owner wants to rank higher. By doing this, the owner attempts to pass link equity (also known as “link juice”) from the PBN sites to the target website.

The purpose of a PBN is to give the impression that the target website is naturally earning links from multiple independent sources. If done effectively, this can temporarily improve keyword rankings, increase organic visibility, and drive more traffic from search results.

Jasa Backlink

Download Anime Batch