共用方式為


什麼是語意核心向量存放區連接器? (預覽)

警告

語意核心向量存放區功能處於預覽狀態,且需要重大變更的改善可能仍會在發行前有限的情況下發生。

提示

如果您要尋找舊版記憶體存放區連接器的相關信息,請參閱 記憶體存放區頁面

向量資料庫在涉及自然語言處理 (NLP)、計算機視覺 (CV)、建議系統 (RS) 和其他需要語意理解和比對數據的其他領域,有許多使用案例。

將資訊儲存在向量資料庫中的一個使用案例是讓大型語言模型 (LLM) 產生更相關且一致的回應。 大型語言模型通常面臨挑戰,例如產生不準確或無關的資訊;缺乏事實一致性或常識;重複或矛盾自己:有偏見或冒犯性。 為了協助克服這些挑戰,您可以使用向量資料庫來儲存與所需領域或內容類型相關的不同主題、關鍵詞、事實、意見和/或來源的相關信息。 向量資料庫可讓您有效率地尋找與特定問題或主題相關的資訊子集。 然後,您可以使用提示將向量資料庫的資訊傳遞至大型語言模型,以產生更精確且相關的內容。

例如,如果您想要撰寫 AI 中最新趨勢的部落格文章,您可以使用向量資料庫來儲存該主題的最新資訊,並將資訊連同要求一起傳遞給 LLM,以產生利用最新資訊的部落格文章。

語意核心和 .net 提供抽象概念,以便與 Vector Store 互動,以及實作這些抽象概念的現成連接器清單。 功能包括建立、列出和刪除記錄集合,以及上傳、擷取和刪除記錄。 抽象概念可讓您輕鬆地試驗免費或本機裝載的向量存放區,然後在需要相應增加時切換至服務。

向量存放區抽象概念

向量存放區抽象概念的主要介面如下。

Microsoft.Extensions.VectorData.IVectorStore

IVectorStore 包含跨越向量存放區中所有集合的作業,例如 ListCollectionNames。 它也提供取得 IVectorStoreRecordCollection<TKey, TRecord> 實例的能力。

Microsoft.Extensions.VectorData.IVectorStoreRecordCollection<TKey, TRecord>

IVectorStoreRecordCollection<TKey, TRecord> 表示集合。 這個集合可能或可能不存在,而且 介面會提供方法來檢查集合是否存在、建立或刪除集合。 介面也提供 upsert、get 和 delete 記錄的方法。 最後,介面繼承自 IVectorizedSearch<TRecord> 提供向量搜尋功能。

Microsoft.Extensions.VectorData.IVectorizedSearch<TRecord>

IVectorizedSearch<TRecord> 包含執行向量搜尋的方法。 IVectorStoreRecordCollection<TKey, TRecord> 繼承自 IVectorizedSearch<TRecord> ,因此在只需要搜尋且不需要記錄或集合管理的情況下,可以自行使用 IVectorizedSearch<TRecord>

IVectorizableTextSearch<TRecord>

IVectorizableTextSearch<TRecord> 包含執行向量搜尋的方法,其中向量資料庫能夠自動產生內嵌。 例如,您可以使用文字字串呼叫這個方法,而資料庫將為您產生內嵌,並搜尋向量字段。 這不受所有向量資料庫支援,因此只會由選取連接器實作。

向量存放區抽象概念

向量存放區抽象概念的主要介面如下。

com.microsoft.semantickernel.data.vectorstorage.VectorStore

VectorStore 包含跨越向量存放區中所有集合的作業,例如 listCollectionNames。 它也提供取得 VectorStoreRecordCollection<Key, Record> 實例的能力。

com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection<Key, Record>

VectorStoreRecordCollection<Key, Record> 表示集合。 這個集合可能或可能不存在,而且 介面會提供方法來檢查集合是否存在、建立或刪除集合。 介面也提供 upsert、get 和 delete 記錄的方法。 最後,介面繼承自 VectorizedSearch<Record> 提供向量搜尋功能。

com.microsoft.semantickernel.data.vectorsearch.VectorizedSearch<Record>

VectorizedSearch<Record> 包含執行向量搜尋的方法。 VectorStoreRecordCollection<Key, Record> 繼承自 VectorizedSearch<Record> ,因此在只需要搜尋且不需要記錄或集合管理的情況下,可以自行使用 VectorizedSearch<Record>

com.microsoft.semantickernel.data.vectorsearch.VectorizableTextSearch<Record>

VectorizableTextSearch<Record> 包含執行向量搜尋的方法,其中向量資料庫能夠自動產生內嵌。 例如,您可以使用文字字串呼叫這個方法,而資料庫將為您產生內嵌,並搜尋向量字段。 這不受所有向量資料庫支援,因此只會由選取連接器實作。

開始使用向量存放區連接器

匯入必要的 Nuget 套件

Nuget 套件中 Microsoft.Extensions.VectorData.Abstractions 提供所有向量存放區介面和任何抽象相關類別。 每個向量存放區實作都可在自己的 nuget 套件中使用。 如需已知實作的清單,請參閱 現成連接器頁面

抽象概念套件可以像這樣新增。

dotnet add package Microsoft.Extensions.VectorData.Abstractions --prerelease

警告

從語意核心 1.23.0 版,已從 Microsoft.SemanticKernel.Abstractions 中移除向量存放區抽象概念,而且可在新的專用 Microsoft.Extensions.VectorData.Abstractions 套件中使用。

請注意,從 1.23.0 版起, Microsoft.SemanticKernel.Abstractions 相依於 Microsoft.Extensions.VectorData.Abstractions,因此不需要參考其他套件。 不過,抽象概念現在會位於新的 Microsoft.Extensions.VectorData 命名空間中。

從 1.22.0 或更早版本升級至 1.23.0 或更新版本時,您必須在檔案中新增額外的 using Microsoft.Extensions.VectorData; 子句,其中使用任何向量存放區抽象類型,例如 IVectorStoreIVectorStoreRecordCollection、、 VectorStoreRecordDataAttributeVectorStoreRecordKeyProperty等。

建立自己的實作時,已進行這項變更以支援向量存放區提供者。 提供者只需要參考 Microsoft.Extensions.VectorData.Abstractions 套件。 這可減少潛在的版本衝突,並允許語意核心繼續快速發展,而不會影響向量存放區提供者。

定義您的數據模型

語意核心向量存放區連接器會使用模型第一種方法來與資料庫互動。 這表示第一個步驟是定義對應至記憶體架構的數據模型。 為了協助連接器建立記錄集合並對應至記憶體架構,可以標註模型以指出每個屬性的函式。

using Microsoft.Extensions.VectorData;

public class Hotel
{
    [VectorStoreRecordKey]
    public ulong HotelId { get; set; }

    [VectorStoreRecordData(IsFilterable = true)]
    public string HotelName { get; set; }

    [VectorStoreRecordData(IsFullTextSearchable = true)]
    public string Description { get; set; }

    [VectorStoreRecordVector(Dimensions: 4, DistanceFunction.CosineDistance, IndexKind.Hnsw)]
    public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; }

    [VectorStoreRecordData(IsFilterable = true)]
    public string[] Tags { get; set; }
}
from dataclasses import dataclass, field
from typing import Annotated
from semantic_kernel.data import (
    DistanceFunction,
    IndexKind,
    VectorStoreRecordDataField,
    VectorStoreRecordDefinition,
    VectorStoreRecordKeyField,
    VectorStoreRecordVectorField,
    vectorstoremodel,
)

@vectorstoremodel
@dataclass
class Hotel:
    hotel_id: Annotated[str, VectorStoreRecordKeyField()] = field(default_factory=lambda: str(uuid4()))
    hotel_name: Annotated[str, VectorStoreRecordDataField(is_filterable=True)]
    description: Annotated[str, VectorStoreRecordDataField(is_full_text_searchable=True)]
    description_embedding: Annotated[list[float], VectorStoreRecordVectorField(dimensions=4, distance_function=DistanceFunction.COSINE, index_kind=IndexKind.HNSW)]
    tags: Annotated[list[str], VectorStoreRecordDataField(is_filterable=True)]
import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData;
import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey;
import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector;
import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction;
import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind;

import java.util.Collections;
import java.util.List;

public class Hotel {
    @VectorStoreRecordKey
    private String hotelId;

    @VectorStoreRecordData(isFilterable = true)
    private String name;

    @VectorStoreRecordData(isFullTextSearchable = true)
    private String description;

    @VectorStoreRecordVector(dimensions = 4, indexKind = IndexKind.HNSW, distanceFunction = DistanceFunction.COSINE_DISTANCE)
    private List<Float> descriptionEmbedding;

    @VectorStoreRecordData(isFilterable = true)
    private List<String> tags;

    public Hotel() { }

    public Hotel(String hotelId, String name, String description, List<Float> descriptionEmbedding, List<String> tags) {
        this.hotelId = hotelId;
        this.name = name;
        this.description = description;
        this.descriptionEmbedding = Collections.unmodifiableList(descriptionEmbedding);
        this.tags = Collections.unmodifiableList(tags);
    }

    public String getHotelId() { return hotelId; }
    public String getName() { return name; }
    public String getDescription() { return description; }
    public List<Float> getDescriptionEmbedding() { return descriptionEmbedding; }
    public List<String> getTags() { return tags; }
}

提示

如需如何標註數據模型的詳細資訊,請參閱 定義您的數據模型

提示

如需標註數據模型的替代方案,請參閱 使用記錄定義來定義架構。

線上到您的資料庫並選取集合

定義數據模型之後,下一個步驟是為您選擇的資料庫建立 VectorStore 實例,並選取記錄集合。

在此範例中,我們將使用 Qdrant。 因此,您必須匯入 Qdrant nuget 套件。

dotnet add package Microsoft.SemanticKernel.Connectors.Qdrant --prerelease

由於資料庫支援許多不同類型的索引鍵和記錄,因此我們可讓您使用泛型來指定集合的索引鍵和記錄類型。 在我們的案例中,記錄類型會是 Hotel 我們已經定義的類別,而索引鍵的類型將會 ulong是 ,因為 HotelId 屬性是 ulong 和 Qdrant 僅支援 Guidulong 索引鍵。

using Microsoft.SemanticKernel.Connectors.Qdrant;
using Qdrant.Client;

// Create a Qdrant VectorStore object
var vectorStore = new QdrantVectorStore(new QdrantClient("localhost"));

// Choose a collection from the database and specify the type of key and record stored in it via Generic parameters.
var collection = vectorStore.GetCollection<ulong, Hotel>("skhotels");

由於資料庫支援許多不同類型的索引鍵和記錄,因此我們可讓您使用泛型來指定集合的索引鍵和記錄類型。 在我們的案例中,記錄類型會是 Hotel 我們已經定義的類別,而索引鍵的類型將會 str是 ,因為 HotelId 屬性是 str 和 Qdrant 僅支援 strint 索引鍵。

from semantic_kernel.connectors.memory.qdrant import QdrantStore

# Create a Qdrant VectorStore object, this will look in the environment for Qdrant related settings, and will fall back to the default, which is to run in-memory.
vector_store = QdrantStore()

# Choose a collection from the database and specify the type of key and record stored in it via Generic parameters.
collection = vector_store.get_collection(
    collection_name="skhotels", 
    data_model_type=Hotel
)

由於資料庫支援許多不同類型的索引鍵和記錄,因此我們可讓您使用泛型來指定集合的索引鍵和記錄類型。 在我們的案例中,記錄類型會是 Hotel 我們已經定義的類別,而索引鍵的類型將會 String是 ,因為 hotelId 屬性是 String 和 JDBC 存放區僅支援 String 索引鍵。

import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore;
import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions;
import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions;
import com.microsoft.semantickernel.data.jdbc.mysql.MySQLVectorStoreQueryProvider;
import com.mysql.cj.jdbc.MysqlDataSource;

import java.util.List;

public class Main {
    public static void main(String[] args) {
        // Create a MySQL data source
        var dataSource = new MysqlDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/sk");
        dataSource.setPassword("root");
        dataSource.setUser("root");

        // Create a JDBC vector store
        var vectorStore = JDBCVectorStore.builder()
            .withDataSource(dataSource)
            .withOptions(
                JDBCVectorStoreOptions.builder()
                    .withQueryProvider(MySQLVectorStoreQueryProvider.builder()
                        .withDataSource(dataSource)
                        .build())
                    .build()
            )
            .build();

        // Get a collection from the vector store
        var collection = vectorStore.getCollection("skhotels",
            JDBCVectorStoreRecordCollectionOptions.<Hotel>builder()
                .withRecordClass(Hotel.class)
                .build()
        );
    }
}

提示

如需每個向量存放區連接器所支援之索引鍵和欄位類型的詳細資訊,請參閱 每個連接器的檔。

建立集合並新增記錄

// Create the collection if it doesn't exist yet.
await collection.CreateCollectionIfNotExistsAsync();

// Upsert a record.
string descriptionText = "A place where everyone can be happy.";
ulong hotelId = 1;

// Create a record and generate a vector for the description using your chosen embedding generation implementation.
// Just showing a placeholder embedding generation method here for brevity.
await collection.UpsertAsync(new Hotel
{
    HotelId = hotelId,
    HotelName = "Hotel Happy",
    Description = descriptionText,
    DescriptionEmbedding = await GenerateEmbeddingAsync(descriptionText),
    Tags = new[] { "luxury", "pool" }
});

// Retrieve the upserted record.
Hotel? retrievedHotel = await collection.GetAsync(hotelId);

建立集合並新增記錄

# Create the collection if it doesn't exist yet.
await collection.create_collection_if_not_exists()

# Upsert a record.
description = "A place where everyone can be happy."
hotel_id = "1"

await collection.upsert(Hotel(
    hotel_id = hotel_id,
    hotel_name = "Hotel Happy",
    description = description,
    description_embedding = await GenerateEmbeddingAsync(description),
    tags = ["luxury", "pool"]
))

# Retrieve the upserted record.
retrieved_hotel = await collection.get(hotel_id)
// Create the collection if it doesn't exist yet.
collection.createCollectionAsync().block();

// Upsert a record.
var description = "A place where everyone can be happy";
var hotelId = "1";
var hotel = new Hotel(
    hotelId, 
    "Hotel Happy", 
    description, 
    generateEmbeddingsAsync(description).block(), 
    List.of("luxury", "pool")
);

collection.upsertAsync(hotel, null).block();

// Retrieve the upserted record.
var retrievedHotel = collection.getAsync(hotelId, null).block();

提示

如需如何產生內嵌的詳細資訊,請參閱 內嵌產生

// Generate a vector for your search text, using your chosen embedding generation implementation.
// Just showing a placeholder method here for brevity.
var searchVector = await GenerateEmbeddingAsync("I'm looking for a hotel where customer happiness is the priority.");
// Do the search.
var searchResult = await collection.VectorizedSearchAsync(searchVector, new() { Top = 1 }).Results.ToListAsync()

// Inspect the returned hotels.
Hotel hotel = searchResult.First().Record;
Console.WriteLine("Found hotel description: " + hotel.Description);
// Generate a vector for your search text, using your chosen embedding generation implementation.
// Just showing a placeholder method here for brevity.
var searchVector = generateEmbeddingsAsync("I'm looking for a hotel where customer happiness is the priority.").block();

// Do the search.
var searchResult = collection.searchAsync(searchVector, VectorSearchOptions.builder()
    .withTop(1).build()
).block();

Hotel record = searchResult.getResults().get(0).getRecord();
System.out.printf("Found hotel description: %s\n", record.getDescription());

提示

如需如何產生內嵌的詳細資訊,請參閱 內嵌產生

下一步