Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Informazioni generali
Questa guida illustra gli aggiornamenti principali dell'archivio vettoriale introdotti in Kernel semantico versione 1.34, che rappresenta una revisione significativa dell'implementazione dell'archivio vettoriale per allinearsi con .NET SDK e fornire un'API più unificata e intuitiva. Le modifiche consolidano tutti gli elementi sottostanti semantic_kernel.data.vector e migliorano l'architettura del connettore.
Riepilogo dei miglioramenti principali
-
Modello campo unificato: una
VectorStoreFieldsingola classe sostituisce più tipi di campo - Incorporamenti integrati: generazione di incorporamento diretto nelle specifiche dei campi vettoriali
- Ricerca semplificata: facile creazione di funzioni di ricerca direttamente nelle raccolte
-
Struttura consolidata: tutto sotto
semantic_kernel.data.vectoresemantic_kernel.connectors - Ricerca di testo migliorata: funzionalità di ricerca di testo migliorate con connettori semplificati
-
Deprecazione: le versioni precedenti
memory_storessono deprecate a favore della nuova architettura dell'archivio vettoriale
1. Incorporamenti integrati e aggiornamenti dei modelli/campi dell'archivio vettoriale
Esistono diverse modifiche al modo in cui definisci il modello di archivio vettoriale, il più grande è che ora supportiamo incorporamenti integrati direttamente nelle definizioni dei campi dell'archivio vettoriali. Ciò significa che quando si specifica un campo come vettore, il contenuto di tale campo viene incorporato automaticamente usando il generatore di incorporamento specificato, ad esempio il modello di incorporamento del testo di OpenAI. Questo semplifica il processo di creazione e gestione dei campi vettoriali.
Quando si definisce tale campo, è necessario assicurarsi di tre elementi, in particolare quando si usa un modello Pydantic:
-
digitazione: il campo probabilmente avrà tre tipi,
list[float],stro qualcos'altro per l'input al generatore di embedding, eNoneper quando il campo non è impostato. -
valore predefinito: il campo deve avere un valore predefinito pari
Noneo diverso, in modo che non si verifichi alcun errore durante il recupero di record dagetosearchcon cuiinclude_vectors=Falseè il valore predefinito.
In questo caso ci sono due problemi, il primo è che quando si decorata una classe con vectorstoremodel, la prima annotazione del tipo del campo viene usata per riempire il type parametro della VectorStoreField classe, quindi è necessario assicurarsi che la prima annotazione del tipo sia il tipo corretto per la raccolta di archivi vettoriali con cui creare, spesso list[float]. Per impostazione predefinita, i metodi get e search non includono i vettori nei risultati, quindi il campo ha bisogno di un valore predefinito, e la tipizzazione deve corrispondere a ciò. Pertanto, spesso None è consentito, e il valore predefinito è impostato su None. Quando il campo viene creato, i valori che devono essere incorporati si trovano in questo campo, spesso stringhe, quindi str devono essere inclusi anche. Il motivo di questa modifica è consentire una maggiore flessibilità in ciò che è incorporato e ciò che viene effettivamente archiviato nei campi dati, si tratta di una configurazione comune:
from semantic_kernel.data.vector import VectorStoreField, vectorstoremodel
from typing import Annotated
from dataclasses import dataclass
@vectorstoremodel
@dataclass
class MyRecord:
content: Annotated[str, VectorStoreField('data', is_indexed=True, is_full_text_indexed=True)]
title: Annotated[str, VectorStoreField('data', is_indexed=True, is_full_text_indexed=True)]
id: Annotated[str, VectorStoreField('key')]
vector: Annotated[list[float] | str | None, VectorStoreField(
'vector',
dimensions=1536,
distance_function="cosine",
embedding_generator=OpenAITextEmbedding(ai_model_id="text-embedding-3-small"),
)] = None
def __post_init__(self):
if self.vector is None:
self.vector = f"Title: {self.title}, Content: {self.content}"
Si noti il metodo post_init, viene creato un valore che viene incorporato, che è più che un singolo campo. Sono presenti anche i tre tipi.
Prima: classi di campo separate
from semantic_kernel.data import (
VectorStoreRecordKeyField,
VectorStoreRecordDataField,
VectorStoreRecordVectorField
)
# Old approach with separate field classes
fields = [
VectorStoreRecordKeyField(name="id"),
VectorStoreRecordDataField(name="text", is_filterable=True, is_full_text_searchable=True),
VectorStoreRecordVectorField(name="vector", dimensions=1536, distance_function="cosine")
]
Dopo: Unified VectorStoreField con incorporamenti integrati
from semantic_kernel.data.vector import VectorStoreField
from semantic_kernel.connectors.ai.open_ai import OpenAITextEmbedding
# New unified approach with integrated embeddings
embedding_service = OpenAITextEmbedding(
ai_model_id="text-embedding-3-small"
)
fields = [
VectorStoreField(
"key",
name="id",
),
VectorStoreField(
"data",
name="text",
is_indexed=True, # Previously is_filterable
is_full_text_indexed=True # Previously is_full_text_searchable
),
VectorStoreField(
"vector",
name="vector",
dimensions=1536,
distance_function="cosine",
embedding_generator=embedding_service # Integrated embedding generation
)
]
Modifiche chiave nella definizione del campo
-
Classe campo singolo:
VectorStoreFieldsostituisce tutti i tipi di campo precedenti -
Specifica tipo di campo: usare
field_type: Literal["key", "data", "vector"]il parametro , può essere un parametro posizionale, quindiVectorStoreField("key")è valido. -
Proprietà avanzate:
-
storage_nameè stato aggiunto, se impostato, che viene usato come nome di campo nell'archivio vettoriale; in caso contrario, viene usato ilnameparametro . -
dimensionsè ora un parametro obbligatorio per i campi vettoriali. -
distance_functioneindex_kindsono entrambi facoltativi e verranno impostati suDistanceFunction.DEFAULTeIndexKind.DEFAULTrispettivamente se non specificati; inoltre, solo per i campi vettoriali, ogni implementazione dell'archivio vettoriale ha una logica che sceglie un valore predefinito per tale archivio.
-
-
Rinominazioni di proprietà:
-
property_type→type_come attributo etypenei costruttori -
is_filterable→is_indexed -
is_full_text_searchable→is_full_text_indexed
-
-
Incorporamenti integrati: aggiungere
embedding_generatordirettamente ai campi vettoriali, in alternativa è possibile impostare nellaembedding_generatorraccolta di archivi vettoriali stessa, che verrà usata per tutti i campi vettoriali in tale archivio, questo valore ha la precedenza sul generatore di incorporamento a livello di raccolta.
2. Nuovi metodi nei negozi e nelle raccolte
Interfaccia del negozio migliorata
from semantic_kernel.connectors.in_memory import InMemoryStore
# Before: Limited collection methods
collection = InMemoryStore.get_collection("my_collection", record_type=MyRecord)
# After: Slimmer collection interface with new methods
collection = InMemoryStore.get_collection(MyRecord)
# if the record type has the `vectorstoremodel` decorator it can contain both the collection_name and the definition for the collection.
# New methods for collection management
await store.collection_exists("my_collection")
await store.ensure_collection_deleted("my_collection")
# both of these methods, create a simple model to streamline doing collection management tasks.
# they both call the underlying `VectorStoreCollection` methods, see below.
Interfaccia raccolta avanzata
from semantic_kernel.connectors.in_memory import InMemoryCollection
collection = InMemoryCollection(
record_type=MyRecord,
embedding_generator=OpenAITextEmbedding(ai_model_id="text-embedding-3-small") # Optional, if there is no embedding generator set on the record type
)
# If both the collection and the record type have an embedding generator set, the record type's embedding generator will be used for the collection. If neither is set, it is assumed the vector store itself can create embeddings, or that vectors are included in the records already, if that is not the case, it will likely raise.
# Enhanced collection operations
await collection.collection_exists()
await collection.ensure_collection_exists()
await collection.ensure_collection_deleted()
# CRUD methods
# Removed batch operations, all CRUD operations can now take both a single record or a list of records
records = [
MyRecord(id="1", text="First record"),
MyRecord(id="2", text="Second record")
]
ids = ["1", "2"]
# this method adds vectors automatically
await collection.upsert(records)
# You can do get with one or more ids, and it will return a list of records
await collection.get(ids) # Returns a list of records
# you can also do a get without ids, with top, skip and order_by parameters
await collection.get(top=10, skip=0, order_by='id')
# the order_by parameter can be a string or a dict, with the key being the field name and the value being True for ascending or False for descending order.
# At this time, not all vector stores support this method.
# Delete also allows for single or multiple ids
await collection.delete(ids)
query = "search term"
# New search methods, these use the built-in embedding generator to take the value and create a vector
results = await collection.search(query, top=10)
results = await collection.hybrid_search(query, top=10)
# You can also supply a vector directly
query_vector = [0.1, 0.2, 0.3] # Example vector
results = await collection.search(vector=query_vector, top=10)
results = await collection.hybrid_search(query, vector=query_vector, top=10)
3. Filtri avanzati per la ricerca
La nuova implementazione dell'archivio vettoriale passa da oggetti FilterClause basati su stringhe a espressioni lambda più potenti e con controllo di tipo o filtri chiamabili.
Prima: Oggetti FilterClause
from semantic_kernel.data.text_search import SearchFilter, EqualTo, AnyTagsEqualTo
from semantic_kernel.data.vector_search import VectorSearchFilter
# Creating filters using FilterClause objects
text_filter = SearchFilter()
text_filter.equal_to("category", "AI")
text_filter.equal_to("status", "active")
# Vector search filters
vector_filter = VectorSearchFilter()
vector_filter.equal_to("category", "AI")
vector_filter.any_tag_equal_to("tags", "important")
# Using in search
results = await collection.search(
"query text",
options=VectorSearchOptions(filter=vector_filter)
)
Dopo: Filtri di Espressione Lambda
# When defining the collection with the generic type hints, most IDE's will be able to infer the type of the record, so you can use the record type directly in the lambda expressions.
collection = InMemoryCollection[str, MyRecord](MyRecord)
# Using lambda expressions for more powerful and type-safe filtering
# The code snippets below work on a data model with more fields then defined earlier.
# Direct lambda expressions
results = await collection.search(
"query text",
filter=lambda record: record.category == "AI" and record.status == "active"
)
# Complex filtering with multiple conditions
results = await collection.search(
"query text",
filter=lambda record: (
record.category == "AI" and
record.score > 0.8 and
"important" in record.tags
)
)
# Combining conditions with boolean operators
results = await collection.search(
"query text",
filter=lambda record: (
record.category == "AI" or record.category == "ML"
) and record.published_date >= datetime(2024, 1, 1)
)
# Range filtering (now possible with lambda expressions)
results = await collection.search(
"query text",
filter=lambda record: 0.5 <= record.confidence_score <= 0.9
)
Suggerimenti per la migrazione per i filtri
-
Uguaglianza semplice:
filter.equal_to("field", "value")diventalambda r: r.field == "value" -
Più condizioni: concatenare
and/orgli operatori anziché più chiamate di filtro -
Contenimento tag/matrice:
filter.any_tag_equal_to("tags", "value")diventalambda r: "value" in r.tags - Funzionalità avanzate: supporto per query di intervallo, logica booleana complessa e predicati personalizzati
4. Miglioramento della facilità di creazione di funzioni di ricerca
Prima: Creazione di funzioni di ricerca con VectorStoreTextSearch
from semantic_kernel.connectors.in_memory import InMemoryCollection
from semantic_kernel.data import VectorStoreTextSearch
collection = InMemoryCollection(collection_name='collection', record_type=MyRecord)
search = VectorStoreTextSearch.from_vectorized_search(vectorized_search=collection, embedding_generator=OpenAITextEmbedding(ai_model_id="text-embedding-3-small"))
search_function = search.create_search(
function_name='search',
...
)
Dopo: Creazione della Funzione di Ricerca Diretta
collection = InMemoryCollection(MyRecord)
# Create search function directly on collection
search_function = collection.create_search_function(
function_name="search",
search_type="vector", # or "keyword_hybrid"
top=10,
vector_property_name="vector", # Name of the vector field
)
# Add to kernel directly
kernel.add_function(plugin_name="memory", function=search_function)
5. Rinomina e importa modifiche del connettore
Consolidamento dei percorsi di importazione
# Before: Scattered imports
from semantic_kernel.connectors.memory.azure_cognitive_search import AzureCognitiveSearchMemoryStore
from semantic_kernel.connectors.memory.chroma import ChromaMemoryStore
from semantic_kernel.connectors.memory.pinecone import PineconeMemoryStore
from semantic_kernel.connectors.memory.qdrant import QdrantMemoryStore
# After: Consolidated under connectors
from semantic_kernel.connectors.azure_ai_search import AzureAISearchStore
from semantic_kernel.connectors.chroma import ChromaVectorStore
from semantic_kernel.connectors.pinecone import PineconeVectorStore
from semantic_kernel.connectors.qdrant import QdrantVectorStore
# Alternative after: Consolidated with lazy loading:
from semantic_kernel.connectors.memory import (
AzureAISearchStore,
ChromaVectorStore,
PineconeVectorStore,
QdrantVectorStore,
WeaviateVectorStore,
RedisVectorStore
)
Ridenominazione della classe connector
| Nome precedente | Nuovo nome |
|---|---|
| AzureCosmosDBforMongoDB* | CosmosMongo* |
| AzureCosmosDBForNoSQL* | CosmosNoSql* |
6. Miglioramenti della ricerca del testo e rimozione del connettore Bing
Rimozione del connettore Bing e interfaccia di ricerca testuale migliorata
Il connettore di ricerca testo Bing è stato rimosso. Eseguire la migrazione a provider di ricerca alternativi:
# Before: Bing Connector (REMOVED)
from semantic_kernel.connectors.search.bing import BingConnector
bing_search = BingConnector(api_key="your-bing-key")
# After: Use Brave Search or other providers
from semantic_kernel.connectors.brave import BraveSearch
# or
from semantic_kernel.connectors.search import BraveSearch
brave_search = BraveSearch()
# Create text search function
text_search_function = brave_search.create_search_function(
function_name="web_search",
query_parameter_name="query",
description="Search the web for information"
)
kernel.add_function(plugin_name="search", function=text_search_function)
Metodi di ricerca migliorati
Prima: tre metodi di ricerca separati con tipi restituiti diversi
from semantic_kernel.connectors.brave import BraveSearch
brave_search = BraveSearch()
# Before: Separate search methods
search_results: KernelSearchResult[str] = await brave_search.search(
query="semantic kernel python",
top=5,
)
search_results: KernelSearchResult[TextSearchResult] = await brave_search.get_text_search_results(
query="semantic kernel python",
top=5,
)
search_results: KernelSearchResult[BraveWebPage] = await brave_search.get_search_results(
query="semantic kernel python",
top=5,
)
Dopo: Metodo di ricerca unificato con parametro del tipo di output
from semantic_kernel.data.text_search import SearchOptions
# Enhanced search results with metadata
search_results: KernelSearchResult[str] = await brave_search.search(
query="semantic kernel python",
output_type=str, # can also be TextSearchResult or anything else for search engine specific results, default is `str`
top=5,
filter=lambda result: result.country == "NL", # Example filter
)
async for result in search_results.results:
assert isinstance(result, str) # or TextSearchResult if using that type
print(f"Result: {result}")
print(f"Metadata: {search_results.metadata}")
7. Deprecazione dei vecchi archivi di memoria
Tutti gli archivi di memoria precedenti, basati su MemoryStoreBase sono stati spostati in semantic_kernel.connectors.memory_stores e sono ora contrassegnati come deprecati. La maggior parte di esse ha una nuova implementazione equivalente basata su VectorStore e VectorStoreCollection, disponibile in semantic_kernel.connectors.memory.
Questi connettori verranno rimossi completamente:
AstraDBMilvusUsearch
Se hai ancora bisogno di uno di questi, assicurati di integrare il codice dal modulo deprecato e dalla semantic_kernel.memory cartella, oppure implementa una raccolta personalizzata di archivi vettoriali basata sulla nuova VectorStoreCollection classe.
Se è presente una grande domanda basata sul feedback di GitHub, si considererà la possibilità di riportarli indietro, ma per il momento non vengono mantenuti e verranno rimossi in futuro.
Migrazione da SemanticTextMemory
# Before: SemanticTextMemory (DEPRECATED)
from semantic_kernel.memory import SemanticTextMemory
from semantic_kernel.connectors.ai.open_ai import OpenAITextEmbeddingGenerationService
embedding_service = OpenAITextEmbeddingGenerationService(ai_model_id="text-embedding-3-small")
memory = SemanticTextMemory(storage=vector_store, embeddings_generator=embedding_service)
# Store memory
await memory.save_information(collection="docs", text="Important information", id="doc1")
# Search memory
results = await memory.search(collection="docs", query="important", limit=5)
# After: Direct Vector Store Usage
from semantic_kernel.data.vector import VectorStoreField, vectorstoremodel
from semantic_kernel.connectors.in_memory import InMemoryCollection
# Define data model
@vectorstoremodel
@dataclass
class MemoryRecord:
id: Annotated[str, VectorStoreField('key')]
text: Annotated[str, VectorStoreField('data', is_full_text_indexed=True)]
embedding: Annotated[list[float] | str | None, VectorStoreField('vector', dimensions=1536, distance_function="cosine", embedding_generator=OpenAITextEmbedding(ai_model_id="text-embedding-3-small"))] = None
# Create vector store with integrated embeddings
collection = InMemoryCollection(
record_type=MemoryRecord,
embedding_generator=OpenAITextEmbedding(ai_model_id="text-embedding-3-small") # Optional, if not set on the record type
)
# Store with automatic embedding generation
record = MemoryRecord(id="doc1", text="Important information", embedding='Important information')
await collection.upsert(record)
# Search with built-in function
search_function = collection.create_search_function(
function_name="search_docs",
search_type="vector"
)
Migrazione del plugin memoria
Quando si vuole avere un plug-in che può anche salvare le informazioni, è possibile creare facilmente questo tipo di codice:
# Before: TextMemoryPlugin (DEPRECATED)
from semantic_kernel.core_plugins import TextMemoryPlugin
memory_plugin = TextMemoryPlugin(memory)
kernel.add_plugin(memory_plugin, "memory")
# After: Custom plugin using vector store search functions
from semantic_kernel.functions import kernel_function
class VectorMemoryPlugin:
def __init__(self, collection: VectorStoreCollection):
self.collection = collection
@kernel_function(name="save")
async def save_memory(self, text: str, key: str) -> str:
record = MemoryRecord(id=key, text=text, embedding=text)
await self.collection.upsert(record)
return f"Saved to {self.collection.collection_name}"
@kernel_function(name="search")
async def search_memory(self, query: str, limit: int = 5) -> str:
results = await self.collection.search(
query, top=limit, vector_property_name="embedding"
)
return "\n".join([r.record.text async for r in results.results])
# Register the new plugin
memory_plugin = VectorMemoryPlugin(collection)
kernel.add_plugin(memory_plugin, "memory")
Elenco di controllo per la migrazione per la ricerca vettoriale
Passaggio 1: Aggiornare le importazioni
- [ ] Sostituire le importazioni dell'archivio memoria con gli equivalenti dell'archivio vettoriale
- [ ] Aggiornare i campi di importazione per utilizzare
VectorStoreField - [ ] Rimuovere le importazioni del connettore Bing
Passaggio 2: Aggiornare le definizioni dei campi
- [ ] Convertire in una classe unificata
VectorStoreField - [ ] Aggiornare i nomi delle proprietà (
is_filterable→is_indexed) - [ ] Aggiungere generatori di incorporamento integrati ai campi vettoriali
Passaggio 3: Aggiorna l'uso della raccolta
- [ ] Sostituire le operazioni di memoria con i metodi dell'archivio vettoriale
- [ ] Usare nuove operazioni batch, se applicabile
- [ ] Implementare la creazione di una nuova funzione di ricerca
Passaggio 4: Aggiornare l'implementazione della ricerca
- [ ] Sostituire le funzioni di ricerca manuale con
create_search_function - [ ] Aggiornare la ricerca di testo per utilizzare nuovi provider
- [ ] Implementare la ricerca ibrida in cui è utile
- [ ] Eseguire la migrazione da
FilterClausealambdacon espressioni di filtro
Passaggio 5: Rimuovere il codice deprecato
- [ ] Rimuovere
SemanticTextMemoryl'uso - [ ] Rimuovere
TextMemoryPluginle dipendenze
Vantaggi delle prestazioni e delle funzionalità
Miglioramenti delle prestazioni
- Operazioni batch: i nuovi metodi di upsert/eliminazione batch migliorano le prestazioni
- Incorporamenti integrati: elimina i passaggi di generazione di incorporamento separati
- Ricerca ottimizzata: le funzioni di ricerca predefinite sono ottimizzate per ogni tipo di archivio
Miglioramenti delle funzionalità
- Ricerca ibrida: combina la ricerca di vettori e testo per ottenere risultati migliori
- Filtro avanzato: espressioni di filtro avanzate e indicizzazione
esperienza di sviluppo
- API semplificata: minor numero di classi e metodi da apprendere
- Interfaccia coerente: approccio unificato in tutti gli archivi vettoriali
- Documentazione migliore: Esempi chiari e percorsi di migrazione
- Future-Proof: allineato a .NET SDK per lo sviluppo multipiattaforma coerente
Conclusione
Gli aggiornamenti dell'archivio vettoriale descritti in precedenza rappresentano un miglioramento significativo in Kernel semantico Python SDK. La nuova architettura unificata offre prestazioni migliori, funzionalità migliorate e un'esperienza di sviluppo più intuitiva. Anche se la migrazione richiede l'aggiornamento delle importazioni e il refactoring del codice esistente, i vantaggi della manutenibilità e delle funzionalità rendono questo aggiornamento altamente consigliato.
Per altre informazioni sulla migrazione, vedere gli esempi aggiornati nella samples/concepts/memory/ directory e la documentazione completa dell'API.