경고
의미 체계 커널 벡터 저장소 기능은 RC이며, 릴리스 전에 제한된 상황에서도 호환성이 손상되는 변경이 필요한 개선 사항이 계속 발생할 수 있습니다.
경고
시맨틱 커널 벡터 저장소 기능은 프리뷰 상태에 있으며, 출시 전 제한된 상황에서도 호환성을 깨는 변경이 필요한 개선이 계속 발생할 수 있습니다.
팁
레거시 메모리 저장소 커넥터에 대한 정보를 찾는 경우 메모리 저장소 페이지를 참조하세요.
벡터 데이터베이스에는 NLP(자연어 처리), CV(컴퓨터 비전), RS(권장 시스템) 및 데이터의 의미 체계 이해 및 일치가 필요한 기타 영역을 포함하는 여러 도메인 및 애플리케이션에서 많은 사용 사례가 있습니다.
벡터 데이터베이스에 정보를 저장하는 한 가지 사용 사례는 LLM(큰 언어 모델)이 보다 관련성 있고 일관된 응답을 생성할 수 있도록 하는 것입니다. 대용량 언어 모델은 부정확하거나 관련이 없는 정보를 생성하는 것과 같은 문제에 직면하는 경우가 많습니다. 사실 일관성 또는 상식이 결여됨; 반복하거나 자신을 모순; 편향되거나 공격적입니다. 이러한 문제를 해결하기 위해 벡터 데이터베이스를 사용하여 원하는 도메인 또는 장르와 관련된 다양한 토픽, 키워드, 팩트, 의견 및/또는 원본에 대한 정보를 저장할 수 있습니다. 벡터 데이터베이스를 사용하면 특정 질문 또는 토픽과 관련된 정보의 하위 집합을 효율적으로 찾을 수 있습니다. 그런 다음 프롬프트를 사용하여 벡터 데이터베이스의 정보를 대용량 언어 모델로 전달하여 보다 정확하고 관련 있는 콘텐츠를 생성할 수 있습니다.
예를 들어 AI의 최신 추세에 대한 블로그 게시물을 작성하려는 경우 벡터 데이터베이스를 사용하여 해당 토픽에 대한 최신 정보를 저장하고 LLM에 요청과 함께 정보를 전달하여 최신 정보를 활용하는 블로그 게시물을 생성할 수 있습니다.
의미 체계 커널 및 .net은 벡터 저장소와 상호 작용하기 위한 추상화 및 다양한 데이터베이스에 대해 이러한 추상화 구현을 구현하는 기본 구현 목록을 제공합니다. 기능에는 레코드 컬렉션 만들기, 나열 및 삭제, 레코드 업로드, 검색 및 삭제가 포함됩니다. 추상화하면 무료 또는 로컬로 호스트되는 Vector Store를 쉽게 실험한 다음, 강화해야 할 때 서비스로 전환할 수 있습니다.
기본 구현은 의미 체계 커널과 함께 사용할 수 있지만 핵심 의미 체계 커널 스택에 의존하지 않으므로 필요한 경우 완전히 독립적으로 사용할 수도 있습니다. '세맨틱 커널'에서 제공하는 구현을 '커넥터'라고 합니다.
RAG(검색 증강 생성) 벡터 저장소 사용
벡터 저장소 추상화는 벡터 저장소에서 데이터를 추가하고 검색하기 위한 하위 수준 API입니다.
의미 체계 커널은 RAG에 대한 벡터 저장소 구현 중 하나를 사용하기 위한 기본 제공 지원을 제공합니다.
이를 위해 IVectorSearchable<TRecord>
래핑하고 텍스트 검색 구현으로 노출합니다.
팁
RAG에 벡터 저장소를 사용하는 방법에 대한 자세한 내용은 벡터 저장소를 사용한 의미 커널 텍스트 검색을 참조하세요.
팁
텍스트 검색에 대한 자세한 내용은 의미 체계 커널(Semantic Kernel) 텍스트 검색이란 무엇인가?
팁
에이전트에 RAG을 빠르게 추가하는 방법에 대한 자세한 내용은 Semantic Kernel Agents에 RAG 추가하기를 참조하세요.
벡터 저장소 추상화
벡터 저장소 추상화는 Microsoft.Extensions.VectorData.Abstractions
NuGet 패키지에서 제공됩니다.
다음은 기본 추상 기본 클래스 및 인터페이스입니다.
Microsoft.Extensions.VectorData.VectorStore
VectorStore
에는 벡터 저장소의 모든 컬렉션(예: ListCollectionNames)에 걸쳐 있는 작업이 포함됩니다.
또한 인스턴스를 가져오는 VectorStoreCollection<TKey, TRecord>
기능도 제공합니다.
Microsoft.Extensions.VectorData.VectorStoreCollection<TKey, TRecord>
VectorStoreCollection<TKey, TRecord>
는 컬렉션을 나타냅니다.
이 컬렉션은 존재할 수도 있고 없을 수도 있으며 추상 기본 클래스는 컬렉션이 있는지 확인하거나 만들거나 삭제하는 메서드를 제공합니다.
추상 기본 클래스는 레코드를 upsert, 가져오기 및 삭제하는 메서드도 제공합니다.
마지막으로, 추상 기본 클래스는 벡터 검색 기능을 제공하는 IVectorSearchable<TRecord>
로부터 상속받습니다.
Microsoft.Extensions.VectorData.IVectorSearchable<TRecord>
-
SearchAsync<TRecord>
은 다음 중 하나를 수행하는 데 사용할 수 있습니다.- 등록된 임베딩 생성기 또는 벡터 데이터베이스가 지원하는 경우 이러한 데이터베이스에서 벡터화할 수 있는 입력을 받아 벡터 검색을 수행합니다.
- 벡터는 벡터를 입력으로 사용하여 검색합니다.
RAG(검색 증강 생성) 벡터 저장소 사용
벡터 저장소 추상화는 벡터 저장소에서 데이터를 추가하고 검색하기 위한 하위 수준 API입니다.
의미 체계 커널은 RAG에 대한 벡터 저장소 구현 중 하나를 사용하기 위한 기본 제공 지원을 제공합니다.
이 작업은 VectorSearchBase[TKey, TModel]
을 VectorizedSearchMixin[Tmodel]
, VectorizableTextSearchMixin[TModel]
, 또는 VectorTextSearch[TModel]
으로 감싸고 이를 텍스트 검색 구현으로 노출함으로써 수행됩니다.
팁
RAG에 벡터 저장소를 사용하는 방법에 대한 자세한 내용은 벡터 저장소를 사용한 의미 커널 텍스트 검색을 참조하세요.
팁
텍스트 검색에 대한 자세한 내용은 의미 체계 커널(Semantic Kernel) 텍스트 검색이란 무엇인가?
벡터 저장소 추상화
벡터 저장소 추상화의 기본 인터페이스는 다음과 같습니다.
com.microsoft.semantickernel.data.vectorstorage.VectorStore
VectorStore
에는 벡터 저장소의 모든 컬렉션(예: listCollectionNames)에 걸쳐 있는 작업이 포함됩니다.
또한 인스턴스를 가져오는 VectorStoreRecordCollection<Key, Record>
기능도 제공합니다.
com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection<Key, Record>
VectorStoreRecordCollection<Key, Record>
는 컬렉션을 나타냅니다.
이 컬렉션은 존재할 수도 있고 존재하지 않을 수도 있으며, 인터페이스는 컬렉션이 있는지 확인하거나 만들거나 삭제하는 메서드를 제공합니다.
또한 인터페이스는 레코드를 갱신삽입, 가져오기 및 삭제하기 위한 메서드를 제공합니다.
마지막으로, 인터페이스는 벡터 검색 기능을 제공하는 VectorizedSearch<Record>
로부터 상속됩니다.
com.microsoft.semantickernel.data.vectorsearch.벡터화된검색<레코드>
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
데이터 모델 정의
벡터 저장소 추상화는 데이터베이스와 상호 작용하는 모델 첫 번째 방법을 사용합니다. 즉, 첫 번째 단계는 스토리지 스키마에 매핑되는 데이터 모델을 정의하는 것입니다. 구현에서 레코드 컬렉션을 만들고 스토리지 스키마에 매핑할 수 있도록 모델에 주석을 추가하여 각 속성의 함수를 나타낼 수 있습니다.
using Microsoft.Extensions.VectorData;
public class Hotel
{
[VectorStoreKey]
public ulong HotelId { get; set; }
[VectorStoreData(IsIndexed = true)]
public string HotelName { get; set; }
[VectorStoreData(IsFullTextIndexed = true)]
public string Description { get; set; }
[VectorStoreVector(Dimensions: 4, DistanceFunction = DistanceFunction.CosineSimilarity, IndexKind = IndexKind.Hnsw)]
public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; }
[VectorStoreData(IsIndexed = true)]
public string[] Tags { get; set; }
}
from dataclasses import dataclass, field
from typing import Annotated
from semantic_kernel.data.vector import (
DistanceFunction,
IndexKind,
VectorStoreField,
vectorstoremodel,
)
@vectorstoremodel
@dataclass
class Hotel:
hotel_id: Annotated[str, VectorStoreField('key')] = field(default_factory=lambda: str(uuid4()))
hotel_name: Annotated[str, VectorStoreField('data', is_filterable=True)]
description: Annotated[str, VectorStoreField('data', is_full_text_searchable=True)]
description_embedding: Annotated[list[float], VectorStoreField('vector', dimensions=4, distance_function=DistanceFunction.COSINE, index_kind=IndexKind.HNSW)]
tags: Annotated[list[str], VectorStoreField('data', 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
Docker를 사용하여 Qdrant를 로컬로 실행하려면 다음 명령을 사용하여 이 예제에 사용된 설정으로 Qdrant 컨테이너를 시작합니다.
docker run -d --name qdrant -p 6333:6333 -p 6334:6334 qdrant/qdrant:latest
Qdrant 인스턴스가 제대로 실행되고 있는지 확인하려면 Qdrant docker 컨테이너에 기본 제공되는 Qdrant 대시보드를 방문하세요. http://localhost:6333/dashboard
데이터베이스는 다양한 유형의 키와 레코드를 지원하므로 제네릭을 사용하여 컬렉션에 대한 키 및 레코드의 형식을 지정할 수 있습니다.
이 경우 레코드의 유형은 이미 정의한 Hotel
클래스가 되고, 키의 유형은 ulong
가 됩니다. 이는 HotelId
속성이 ulong
이기 때문이며, Qdrant는 Guid
또는 ulong
키만 지원합니다.
using Microsoft.SemanticKernel.Connectors.Qdrant;
using Qdrant.Client;
// Create a Qdrant VectorStore object
var vectorStore = new QdrantVectorStore(new QdrantClient("localhost"), ownsClient: true);
// 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는 str
또는 int
키만 지원합니다.
from semantic_kernel.connectors.qdrant import QdrantCollection
# Create a collection specify the type of key and record stored in it via Generic parameters.
collection: QdrantCollection[str, Hotel] = QdrantCollection(
record_type=Hotel,
collection_name="skhotels" # this is optional, you can also specify the collection_name in the vectorstoremodel decorator.
)
데이터베이스는 다양한 유형의 키와 레코드를 지원하므로 제네릭을 사용하여 컬렉션에 대한 키 및 레코드의 형식을 지정할 수 있습니다.
이 경우에는 레코드의 형식이 우리가 이미 정의한 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()
);
}
}
팁
각 Vector Store 구현에서 지원하는 키 및 필드 형식에 대한 자세한 내용은 각 구현에 대한 설명서를 참조하세요.
컬렉션 만들기 및 레코드 추가
// Placeholder embedding generation method.
async Task<ReadOnlyMemory<float>> GenerateEmbeddingAsync(string textToVectorize)
{
// your logic here
}
// Create the collection if it doesn't exist yet.
await collection.EnsureCollectionExistsAsync();
// 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.
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.ensure_collection_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();
팁
포함을 생성하는 방법에 대한 자세한 내용은 포함 생성을 참조 하세요.
벡터 검색 수행
// Placeholder embedding generation method.
async Task<ReadOnlyMemory<float>> GenerateEmbeddingAsync(string textToVectorize)
{
// your logic here
}
// Generate a vector for your search text, using your chosen embedding generation implementation.
ReadOnlyMemory<float> searchVector = await GenerateEmbeddingAsync("I'm looking for a hotel where customer happiness is the priority.");
// Do the search.
var searchResult = collection.SearchAsync(searchVector, top: 1);
// Inspect the returned hotel.
await foreach (var record in searchResult)
{
Console.WriteLine("Found hotel description: " + record.Record.Description);
Console.WriteLine("Found record score: " + record.Score);
}
벡터 검색 수행
검색 메서드를 사용하여 컬렉션에서 레코드를 검색할 수 있습니다. 그런 다음 모델 또는 컬렉션의 포함 생성 설정을 사용하여 벡터화되는 문자열 또는 이미 생성된 벡터를 사용합니다.
# Do a search.
search_result = await collection.search("I'm looking for a hotel where customer happiness is the priority.", vector_property_name="description_embedding", top=3)
# Inspect the returned hotels.
async for result in search_result.results:
print(f"Found hotel description: {result.record.description}")
검색 함수 만들기
호텔을 검색하는 데 사용할 수 있는 간단한 검색 함수를 만들려면 컬렉션에서 메서드를 create_search_function
사용할 수 있습니다.
이름 및 설명뿐만 아니라 매개 변수의 이름과 설명은 함수 호출을 사용할 때 LLM으로 전송되는 함수 서명을 생성하는 데 사용됩니다. 즉, 이를 조정하면 LLM에서 올바른 함수 호출을 생성하는 데 유용할 수 있습니다.
collection.create_search_function(
function_name="hotel_search",
description="A hotel search engine, allows searching for hotels in specific cities, "
"you do not have to specify that you are searching for hotels, for all, use `*`."
)
다른 많은 매개 변수가 있습니다. 예를 들어 더 복잡한 버전에서는 매개 변수의 사용자 지정과 string_mapper
레코드를 문자열로 변환하는 데 사용되는 함수를 확인합니다.
from semantic_kernel.function import KernelParameterMetadata
collection.create_search_function(
function_name="hotel_search",
description="A hotel search engine, allows searching for hotels in specific cities, "
"you do not have to specify that you are searching for hotels, for all, use `*`.",
search_type="keyword_hybrid", # default is "vector"
parameters=[
KernelParameterMetadata(
name="query",
description="The terms you want to search for in the hotel database.",
type="str",
is_required=True,
type_object=str,
),
KernelParameterMetadata(
name="tags",
description="The tags you want to search for in the hotel database, use `*` to match all.",
type="str",
type_object=str,
default_value="*",
),
KernelParameterMetadata(
name="top",
description="Number of results to return.",
type="int",
default_value=5,
type_object=int,
),
],
# finally, we specify the `string_mapper` function that is used to convert the record to a string.
# This is used to make sure the relevant information from the record is passed to the LLM.
string_mapper=lambda x: f"Hotel {x.record.hotel_name}: {x.record.description}. Tags: {x.record.tags} (hotel_id: {x.record.hotel_id}) ",
)
팁
엔드투엔드 예제를 비롯한 더 많은 샘플은 의미 체계 커널 샘플 리포지토리를 참조하세요.
// 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());
팁
포함을 생성하는 방법에 대한 자세한 내용은 포함 생성을 참조 하세요.