📦 Microsoft. MEVD(Extensions.VectorData.Abstractions) 패키지는 .NET 벡터 저장소 작업을 위한 통합 API를 제공합니다. 동일한 코드를 사용하여 여러 벡터 데이터베이스 공급자에 포함을 저장하고 검색할 수 있습니다.
이 문서에서는 라이브러리의 주요 기능을 사용하는 방법을 보여줍니다.
사전 요구 사항
- .NET 9 SDK 이상
- 임베딩 및 벡터 데이터베이스 이해
패키지 설치
벡터 데이터베이스에 대한 공급자 패키지를 설치합니다.
Microsoft.Extensions.VectorData.Abstractions 패키지는 전이적 종속성으로 자동으로 가져옵니다. 다음 예제에서는 개발 및 테스트에 메모리 내 공급자를 사용합니다.
dotnet package add Microsoft.SemanticKernel.Connectors.InMemory --prerelease
프로덕션 시나리오의 경우 Microsoft.SemanticKernel.Connectors.InMemory 데이터베이스의 공급자로 바꿉니다. 사용 가능한 공급자는 기본 제공 벡터 저장소 공급자를 참조하세요. (공급자 패키지 이름에 "SemanticKernel"이 포함되더라도 이러한 공급자는 의미 체계 커널 관련이 없으며 에이전트 프레임워크를 포함하여 .NET 어디에서나 사용할 수 있습니다.
데이터 모델 정의
벡터 저장소에 저장할 레코드를 나타내는 .NET 클래스를 정의합니다. 특성을 사용하여 기본 키, 일반 데이터 또는 벡터 데이터를 나타내는지 여부에 따라 클래스의 속성에 주석을 추가합니다. 다음은 간단한 예제입니다.
public class Hotel
{
[VectorStoreKey]
public ulong HotelId { get; set; }
[VectorStoreData(IsIndexed = true)]
public required string HotelName { get; set; }
[VectorStoreData(IsFullTextIndexed = true)]
public required string Description { get; set; }
[VectorStoreVector(Dimensions: 4, DistanceFunction = DistanceFunction.CosineSimilarity, IndexKind = IndexKind.Hnsw)]
public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; }
[VectorStoreData(IsIndexed = true)]
public required string[] Tags { get; set; }
}
특성을 사용하는 대신 , 를 사용하여 프로그래밍 방식으로 스키마를 VectorStoreCollectionDefinition정의할 수 있습니다. 이 방법은 서로 다른 구성으로 동일한 데이터 모델을 사용하려는 경우 또는 데이터 모델 클래스에 특성을 추가할 수 없는 경우에 유용합니다.
자세한 내용은 데이터 모델 정의를 참조하세요.
벡터 저장소 만들기
선택한 데이터베이스에 VectorStore 대한 구현 인스턴스를 만듭니다. 다음 예제에서는 메모리 내 벡터 저장소를 만듭니다.
// Create an in-memory vector store (no external service required).
// For production, replace this with a connector for your preferred database.
var vectorStore = new InMemoryVectorStore();
컬렉션 가져오기
GetCollection을(를) VectorStore에서 호출하여 형식화된 VectorStoreCollection<TKey,TRecord> 참조를 가져옵니다. 그런 다음 컬렉션이 아직 없는 경우 호출 EnsureCollectionExistsAsync 하여 컬렉션을 만듭니다.
// Get a reference to a collection named "hotels".
VectorStoreCollection<int, Hotel> collection =
vectorStore.GetCollection<int, Hotel>("hotels");
// Ensure the collection exists in the database.
await collection.EnsureCollectionExistsAsync();
컬렉션 이름은 데이터베이스의 기본 스토리지 개념(예: SQL Server 테이블, Azure AI 검색 인덱스 또는 Cosmos DB의 컨테이너)에 매핑됩니다.
Upsert 레코드
컬렉션에 레코드를 삽입하거나 업데이트하는 데 사용합니다 UpsertAsync . 동일한 키를 가진 레코드가 이미 있는 경우 업데이트됩니다.
// Upsert records into the collection.
// In a real app, generate embeddings using an IEmbeddingGenerator.
// The CreateFakeEmbedding helper at the bottom of this file generates
// placeholder vectors for demonstration purposes only.
var hotels = new List<Hotel>
{
new()
{
HotelId = 1,
HotelName = "Seaside Retreat",
Description = "A peaceful hotel on the coast with stunning ocean views.",
DescriptionEmbedding = CreateFakeEmbedding(1),
Tags = ["beach", "ocean", "relaxation"]
},
new()
{
HotelId = 2,
HotelName = "Mountain Lodge",
Description = "A cozy lodge in the mountains with hiking trails nearby.",
DescriptionEmbedding = CreateFakeEmbedding(2),
Tags = ["mountain", "hiking", "nature"]
},
new()
{
HotelId = 3,
HotelName = "City Centre Hotel",
Description = "A modern hotel in the heart of the city, close to attractions.",
DescriptionEmbedding = CreateFakeEmbedding(3),
Tags = ["city", "business", "urban"]
}
};
foreach (Hotel h in hotels)
{
await collection.UpsertAsync(h);
}
중요합니다
실제 앱에서는 레코드를 저장하기 전에 MEVD가 임베딩을 생성하도록 하는 것이 좋습니다.
레코드 가져오기
GetAsync을(를) 사용하여 키로 단일 레코드를 검색합니다. 여러 레코드를 검색하려면 IEnumerable<TKey>를 GetAsync에 전달합니다.
// Get a specific record by its key.
Hotel? hotel = await collection.GetAsync(1);
if (hotel is not null)
{
Console.WriteLine($"Hotel: {hotel.HotelName}");
Console.WriteLine($"Description: {hotel.Description}");
}
한 번에 여러 레코드를 검색하려면 다음을 수행합니다.
// Get multiple records by their keys.
IAsyncEnumerable<Hotel> hotelBatch = collection.GetAsync([1, 2, 3]);
await foreach (Hotel h in hotelBatch)
{
Console.WriteLine($"Batch hotel: {h.HotelName}");
}
벡터 검색 수행
쿼리와 의미상 유사한 레코드를 찾는 데 사용합니다 SearchAsync . 쿼리에 대한 포함 벡터와 반환할 결과 수를 전달합니다.
// Search for the top 2 hotels most similar to the query embedding.
IAsyncEnumerable<VectorSearchResult<Hotel>> searchResults =
collection.SearchAsync(queryEmbedding, top: 2);
await foreach (VectorSearchResult<Hotel> result in searchResults)
{
Console.WriteLine($"Found: {result.Record.HotelName} (score: {result.Score:F4})");
}
각각 VectorSearchResult<TRecord> 에는 일치하는 레코드와 유사성 점수가 포함됩니다. 점수가 높을수록 의미 체계 일치가 더 가까워짐을 나타냅니다.
검색 결과 필터링
벡터 비교 전에 검색 결과를 필터링하는 데 사용합니다 VectorSearchOptions<TRecord> . "IsIndexed = true으로/로 표시된 모든 속성을 필터링할 수 있습니다."
// Filter results before the vector comparison.
// Only properties marked with IsIndexed = true can be used in filters.
var searchOptions = new VectorSearchOptions<Hotel>
{
Filter = h => h.HotelName == "Seaside Retreat"
};
IAsyncEnumerable<VectorSearchResult<Hotel>> filteredResults =
collection.SearchAsync(queryEmbedding, top: 2, searchOptions);
await foreach (VectorSearchResult<Hotel> result in filteredResults)
{
Console.WriteLine($"Filtered: {result.Record.HotelName} (score: {result.Score:F4})");
}
필터는 LINQ 식으로 표현됩니다. 지원되는 작업은 공급자에 따라 다르지만 모든 공급자는 같음, 같지 않음, 논리 && 및 ||같은 일반적인 비교를 지원합니다.
VectorSearchOptions를 사용하여 검색 동작 제어
벡터 검색 동작의 다양한 측면을 제어하는 데 사용합니다 VectorSearchOptions<TRecord> .
// Use VectorSearchOptions to control paging and vector inclusion.
var pagedOptions = new VectorSearchOptions<Hotel>
{
Skip = 1, // Skip the first result (useful for paging).
IncludeVectors = false // Don't include vector data in results (default).
};
IAsyncEnumerable<VectorSearchResult<Hotel>> pagedResults =
collection.SearchAsync(queryEmbedding, top: 2, pagedOptions);
await foreach (VectorSearchResult<Hotel> result in pagedResults)
{
Console.WriteLine($"Paged: {result.Record.HotelName}");
}
다음 표에서는 사용 가능한 옵션에 대해 설명합니다.
| Option | 설명 |
|---|---|
Filter |
벡터 비교 전에 레코드를 필터링하는 LINQ 식입니다. |
VectorProperty |
검색할 벡터 속성입니다. 데이터 모델에 여러 벡터 속성이 있는 경우 필요합니다. |
Skip |
반환 전에 건너뛸 결과의 수입니다. 페이징에 유용합니다. 기본값은 0입니다. |
IncludeVectors |
반환된 레코드에 벡터 데이터를 포함할지 여부입니다. 벡터를 생략하면 데이터 전송이 줄어듭니다. 기본값은 false입니다. |
자세한 내용은 벡터 검색을 참조하세요.
내장 임베딩 생성 사용
각 upsert 전에 임베딩을 수동으로 생성하는 대신 벡터 저장소 또는 컬렉션에서 IEmbeddingGenerator을(를) 구성할 수 있습니다. 이렇게 하면 벡터 속성을 형식(원본 텍스트)으로 string 선언하고 저장소는 포함을 자동으로 생성합니다.
자세한 내용은 자동 포함 생성을 참조하세요.
하이브리드 검색
일부 벡터 저장소는 벡터 유사성과 키워드 일치를 결합하는 하이브리드 검색을 지원합니다. 이 방법은 벡터 전용 검색에 비해 결과 관련성을 향상시킬 수 있습니다.
하이브리드 검색을 사용하려면 컬렉션이 IKeywordHybridSearchable<TRecord>을(를) 구현하는지 확인하십시오. 이 기능을 지원하는 데이터베이스에 대한 공급자만 이 인터페이스를 구현합니다.
자세한 내용은 하이브리드 검색을 참조하세요.
레코드 삭제
키별로 단일 레코드를 삭제하려면 다음을 사용합니다 DeleteAsync.
// Delete a record by its key.
await collection.DeleteAsync(3);
컬렉션 삭제
벡터 저장소에서 전체 컬렉션을 제거하려면 다음을 사용합니다 EnsureCollectionDeletedAsync.
// Delete the entire collection from the vector store.
await collection.EnsureCollectionDeletedAsync();
벡터 저장소 공급자 전환
모든 공급자는 동일한 VectorStore 추상 클래스를 구현하므로 시작 시 구체적인 형식을 변경하여 둘 사이를 전환할 수 있습니다. 대부분의 경우 컬렉션 및 검색 코드는 동일하게 유지됩니다. 그러나 다른 데이터베이스가 서로 다른 데이터 형식을 지원하므로 일반적으로 일부 조정이 필요합니다.
관련 콘텐츠
.NET