Vector stores no Agent Framework: guia prático em Python

Vector stores no Agent Framework: guia prático em Python

Vector stores no Agent Framework permitem que agentes escritos em Python consultem os dados da sua aplicação por similaridade semântica, sem amarrar o código a um banco específico. Com isso, o Microsoft Agent Framework herda a base madura do Semantic Kernel e acrescenta recursos pensados desde o início para agentes.

Neste artigo, você vai entender como modelar registros, indexar documentos, criar ferramentas de busca e manter o histórico de conversa pesquisável. Além disso, veremos as integrações disponíveis e os cuidados necessários antes de levar essa estrutura para produção.

O que são vector stores no Agent Framework

Um vector store guarda os dados junto com os seus embeddings, que são vetores numéricos capazes de representar o significado de um texto. Dessa forma, a aplicação encontra registros parecidos com uma pergunta mesmo quando as palavras exatas não coincidem.

Nas aplicações que usam vector stores no Agent Framework, esse recurso atende a dois cenários principais. Primeiro, ele recupera dados de apoio para a técnica de RAG (Retrieval Augmented Generation); em seguida, ele armazena informações que o agente pode consultar mais tarde.

A grande vantagem está na camada de abstração. Por exemplo, você pode começar com uma implementação local durante o desenvolvimento e depois trocar para um serviço gerenciado com poucas mudanças no código.

Na prática, o fluxo típico segue uma sequência bem definida:

  • Definir um modelo de dados com chave, campos de dados e campos vetoriais.
  • Configurar um gerador de embeddings quando o banco não gera vetores sozinho.
  • Conectar ao store e selecionar ou criar uma coleção.
  • Gerar os embeddings e gravar os registros na coleção.
  • Pesquisar a coleção com texto ou com um vetor pronto.
  • Entregar os resultados ao agente como contexto ou como ferramenta.

Vale destacar que as APIs nativas de vector stores no Agent Framework para Python ainda são experimentais. Portanto, pequenas mudanças incompatíveis podem acontecer até a versão estável, e os pacotes de integração estão em alpha ou beta.

Da herança do Semantic Kernel ao novo modelo

Os vector stores já faziam parte da experiência Python do Semantic Kernel havia algum tempo. Por isso, a equipe da Microsoft optou por portar esse trabalho para o novo framework em vez de recomeçar do zero.

Quem já usou as APIs de vetores do Semantic Kernel vai reconhecer os conceitos centrais. Entre eles, estão as definições tipadas de registros, os stores, as coleções, as operações em lote, a geração de embeddings e a busca vetorial.

No entanto, a migração foi além de uma cópia direta. A equipe simplificou o registro de modelos e as APIs em lote, atualizou os filtros e as opções de embedding e integrou os vector stores no Agent Framework ao modo como os agentes recebem contexto.

Outro ponto relevante é a independência de dependências pesadas. Os contratos fazem parte do pacote agent-framework-core e não exigem Pydantic, NumPy, pandas nem o próprio Semantic Kernel.

Como modelar dados para vector stores no Agent Framework

O ponto de partida é o modelo de dados que a sua aplicação já possui, e não o modelo imposto pelo SDK de um banco. Assim, o código de domínio continua limpo e independente do armazenamento.

Campos de chave, dados e vetor

Você marca cada atributo com VectorStoreField, indicando se ele é a chave, um campo de dados ou um campo vetorial. Em seguida, o decorador @vectorstoremodel deriva automaticamente a definição da coleção.

from dataclasses import dataclass
from typing import Annotated

from agent_framework import VectorStoreField, vectorstoremodel


@vectorstoremodel(collection_name="documents")
@dataclass
class Document:
    # Chave única do registro
    id: Annotated[str, VectorStoreField("key")]
    # Campo indexado, útil para filtros
    category: Annotated[str, VectorStoreField("data", is_indexed=True)]
    text: Annotated[str, VectorStoreField("data")]
    # Campo vetorial com dimensões e função de distância declaradas
    embedding: Annotated[
        list[float] | str | None,
        VectorStoreField(
            "vector",
            dimensions=1536,
            distance_function="cosine_similarity",
        ),
    ] = None

Repare que o campo embedding aceita list[float] ou str. Quando você entrega um texto, o framework chama o gerador de embeddings e converte esse texto em vetor durante a gravação.

As dimensões ficam declaradas no próprio modelo. Com isso, os vector stores no Agent Framework validam os vetores gerados ou fornecidos antes que eles cheguem ao banco.

Outros formatos de modelo suportados

Dataclasses representam apenas uma das opções disponíveis. A mesma camada de modelo também aceita modelos Pydantic, structs do msgspec, classes simples e dicionários.

Para dicionários, você usa diretamente VectorStoreCollectionDefinition. Já para tipos que pertencem a outro pacote, a função register_vectorstoremodel() recebe uma definição explícita e, opcionalmente, um encoder e um decoder personalizados.

Os modelos Pydantic oferecem validação, embora tragam um custo extra de conversão. Portanto, escolha o formato conforme o equilíbrio entre segurança de tipos e desempenho que o seu cenário exige.

Indexando e pesquisando documentos

Depois de definir o modelo, o próximo passo é criar uma coleção, gravar registros e executar buscas. O exemplo a seguir usa a coleção em memória, ideal para testes e desenvolvimento local.

Primeira busca com vector stores no Agent Framework

Antes de executar o código, defina a variável de ambiente OPENAI_API_KEY. O cliente de embeddings da OpenAI gera os vetores tanto na gravação quanto na consulta.

import asyncio

from agent_framework import Filter, InMemoryCollection
from agent_framework.openai import OpenAIEmbeddingClient


async def index_and_search() -> None:
    documents: InMemoryCollection[str, Document] = InMemoryCollection(
        Document,
        embedding_generator=OpenAIEmbeddingClient(model="text-embedding-3-small"),
    )
    await documents.ensure_collection_exists()

    # O texto em "embedding" vira vetor durante o upsert
    await documents.upsert([
        Document(
            id="release-checklist",
            category="operations",
            text="Verify rollback, monitoring, and owner sign-off.",
            embedding="Verify rollback, monitoring, and owner sign-off.",
        )
    ])

    results = await documents.search(
        "What should I check before a release?",
        filter=Filter("category", "eq", "operations"),
        top=3,
    )

    # Os resultados chegam de forma assíncrona
    async for result in results:
        print(result["record"].text, result["score"])


asyncio.run(index_and_search())

Os registros ficam apenas na memória do processo, então eles desaparecem quando a aplicação reinicia. Além disso, essa implementação faz uma varredura linear, o que a torna inadequada para cargas de produção.

O detalhe mais interessante aparece na troca de implementação. De fato, com vector stores no Agent Framework você substitui InMemoryCollection por outra coleção suportada sem alterar o restante do código.

Filtros portáveis com Filter e FilterGroup

Nos vector stores no Agent Framework, os filtros são estruturas de dados comuns, e nenhum código Python roda durante a busca. Por isso, eles funcionam de forma portável entre as diferentes integrações.

Quando você precisa combinar condições, o FilterGroup agrupa vários filtros com operadores lógicos. Nesse caso, também vale fornecer vetores pré-calculados e desligar a geração automática.

from agent_framework import Filter, FilterGroup, InMemoryCollection


async def search_hotels(collection: InMemoryCollection) -> None:
    # Combina cidade, faixa de avaliação e comodidade
    search_filter = FilterGroup(
        "and",
        (
            Filter("city", "eq", "Lisbon"),
            Filter("rating", "between", (4.5, 5.0)),
            Filter("amenities", "contains", "pool"),
        ),
    )

    results = await collection.search(
        vector=[1.0, 0.0],
        filter=search_filter,
        top=5,
    )

    async for result in results:
        print(f"{result['record'].name}: {result['score']:.3f}")

Para gravar registros que já possuem vetores, passe generate_vectors=False no upsert. Assim, o framework não chama o provedor de embeddings e respeita os valores que você entregou.

Transformando a busca em ferramenta do agente

Assim como no Semantic Kernel, você pode expor a busca diretamente como uma ferramenta de primeira classe para o agente. A função create_vector_search_tool envolve uma coleção pesquisável e controla nome, descrição, formato do resultado, filtros e comportamento de aprovação.

Essa abordagem dos vector stores no Agent Framework funciona bem quando o agente precisa de uma única busca focada. Em outras palavras, o modelo decide quando consultar a base e recebe apenas o trecho relevante.

Parâmetros tipados com Param

O tipo Param simplifica a criação de ferramentas de busca personalizadas. Você coloca um Param dentro de um Filter ou FilterGroup, e o helper o expõe como um argumento tipado que o modelo pode preencher.

from typing import Literal

from agent_framework import Filter, Param, create_vector_search_tool

# O Literal vira um enum no schema da ferramenta
category = Param(
    "category",
    Literal["engineering", "operations", "product"],
    required=False,
    description="Only return documents from this category.",
)

search_documents = create_vector_search_tool(
    documents,
    name="search_documents",
    description="Search the document collection.",
    filter=Filter("category", "eq", category),
    result_mapper=lambda result: result["record"].text,
)

A ferramenta resultante sempre aceita uma consulta em linguagem natural e, opcionalmente, a categoria. Como os valores do Literal viram um enum no schema, o agente recebe um conjunto claro de escolhas válidas.

Se o modelo omitir o parâmetro opcional, o filtro correspondente simplesmente deixa de existir na consulta. Por outro lado, ferramentas mais complexas podem combinar vários parâmetros por meio do FilterGroup, inclusive com limites como avaliação mínima e máxima.

Context providers e vector stores no Agent Framework

A principal novidade desta versão está nos context providers. Eles expõem os seus dados aos agentes por meio de ferramentas ou usam um vector store para manter o histórico pesquisável sem inflar o contexto do modelo.

Um context provider roda antes e depois de cada invocação do agente. Dessa forma, ele injeta informações relevantes e desacopla a origem dos dados da lógica do agente.

VectorCollectionContextProvider na prática

Quando o agente precisa de mais do que uma busca isolada, o VectorCollectionContextProvider oferece uma experiência de nível mais alto. Ele adiciona ferramentas de upsert, get, delete e search, junto com instruções sobre como usá-las.

Com esse provider, os vector stores no Agent Framework ganham diversas possibilidades de uso. Por exemplo, você pode expor uma base de conhecimento somente leitura, permitir que o agente gerencie registros com aprovação ou substituir a busca padrão por ferramentas especializadas.

from agent_framework import Agent, InMemoryCollection, VectorCollectionContextProvider
from agent_framework.openai import OpenAIChatClient, OpenAIEmbeddingClient


async def run_notes_assistant() -> None:
    collection: InMemoryCollection[str, ProjectNote] = InMemoryCollection(
        ProjectNote,
        embedding_generator=OpenAIEmbeddingClient(model="text-embedding-3-small"),
    )
    await collection.ensure_collection_exists()

    # Upsert sem aprovação; delete continua exigindo aprovação
    collection_context = VectorCollectionContextProvider(
        collection,
        scope_filter=None,
        approval_mode={"upsert": "never_require"},
    )

    async with Agent(
        client=OpenAIChatClient(model="gpt-5.4-nano"),
        name="ProjectNotesAssistant",
        instructions="Use the collection tools to manage project notes. Do not invent stored notes.",
        context_providers=[collection_context],
    ) as agent:
        response = await agent.run("Save a note: the release is planned for Friday.")
        print(response.text)

Por padrão, upsert e delete exigem aprovação, enquanto get e search funcionam sem ela. Esse comportamento seguro evita que o agente altere dados sem supervisão.

O parâmetro scope_filter agrupa registros para as ferramentas geradas. Contudo, a documentação oficial alerta que esse filtro não funciona como fronteira de autorização nem como garantia atômica do banco.

A configuração de embeddings também respeita cada operação. Enquanto a ingestão usa opções voltadas a documentos, a busca usa opções voltadas a consultas, e as ferramentas geradas repassam essas configurações para a mesma coleção.

Histórico de conversa pesquisável

Além de servir como base de conhecimento, os vector stores no Agent Framework também resolvem o crescimento do histórico, que aumenta o contexto a cada turno. Para resolver isso, o VectorStoreHistoryProvider persiste a conversa completa em uma coleção vetorial e carrega no contexto apenas um conjunto compactado.

from agent_framework import (
    Agent,
    InMemoryStore,
    SlidingWindowStrategy,
    VectorStoreHistoryProvider,
)
from agent_framework.openai import OpenAIChatClient, OpenAIEmbeddingClient


async def run_release_assistant() -> None:
    history = VectorStoreHistoryProvider(
        InMemoryStore(),
        application_id="release-planning",
        tenant_id="contoso",
        agent_id="release-assistant",
        collection_name="release_planning_history_text_embedding_3_small",
        contents_format="json",
        embedding_generator=OpenAIEmbeddingClient(model="text-embedding-3-small"),
        embedding_options={"dimensions": 1536, "encoding_format": "float"},
        # Mantém apenas os grupos mais recentes no contexto
        compaction_strategy=SlidingWindowStrategy(keep_last_groups=2, preserve_system=True),
        # Permite pesquisar o histórico completo
        include_search_tool=True,
    )

    async with Agent(
        client=OpenAIChatClient(model="gpt-5.4-nano"),
        name="ReleaseAssistant",
        instructions="Use the history search tool when an older detail is missing.",
        context_providers=[history],
    ) as agent:
        response = await agent.run("Which deadline did we agree on earlier?")
        print(response.text)

Quando include_search_tool=True, o agente recebe uma ferramenta para pesquisar toda a transcrição dentro do escopo. Assim, o contexto ativo permanece limitado, mas o agente ainda recupera uma decisão antiga, um requisito ou uma preferência do usuário quando precisa.

Os identificadores de aplicação, tenant, agente e sessão evitam sobreposições acidentais entre conversas. Mesmo assim, a sua aplicação continua responsável por autorizar o acesso e usar credenciais com escopo adequado.

Os nomes de importação podem variar entre versões prévias. Portanto, confira sempre os samples oficiais do repositório antes de copiar os exemplos para o seu projeto.

Embeddings sem amarrar o provedor

As aplicações podem fornecer vetores pré-calculados ou deixar que o framework chame um serviço de embeddings durante a gravação e a busca. Além disso, é possível gerar todos os campos vetoriais ou apenas alguns deles.

No upsert(), o argumento embeddings_options aplica as opções do provedor a todos os campos gerados. Já o embeddings_options_by_field permite opções diferentes por campo, embora os dois argumentos não possam aparecer juntos.

Na consulta, você passa embeddings_options para search() ou para create_vector_search_tool(). Nesse momento, os vector stores no Agent Framework informam as dimensões declaradas no campo e rejeitam um valor conflitante antes de chamar o provedor.

Há também algumas regras de combinação importantes. As opções de embedding na gravação exigem vetores gerados, então elas não funcionam com generate_vectors=False, e as opções de busca são ignoradas quando você envia um vetor pronto.

A busca usa a mesma API de coleção em todas as integrações, com filtros portáveis e busca híbrida por palavra-chave quando o banco oferece esse recurso. Por isso, cada implementação documenta os índices, filtros, métricas e modos de busca que suporta.

Integrações disponíveis para vector stores no Agent Framework

Atualmente, os vector stores no Agent Framework para Python contam com integrações nativas para diversos bancos. A lista inclui serviços gerenciados da Azure, bancos relacionais e soluções especializadas em vetores.

Integração Pacote Busca suportada
Em memória agent-framework-core Vetorial densa com filtros
Azure AI Search agent-framework-azure-ai-search Vetorial e híbrida
Azure Cosmos DB for NoSQL agent-framework-azure-cosmos Vetorial densa com filtros
Azure DocumentDB agent-framework-azure-documentdb Vetorial com filtros de metadados
DuckDB agent-framework-duckdb Vetorial exata com filtros
MongoDB agent-framework-mongodb Vetorial aproximada ou exata
Oracle AI Database 26ai agent-framework-oracle Vetorial densa com filtros
PostgreSQL com pgvector agent-framework-postgres Exata, HNSW e IVFFlat
Qdrant agent-framework-qdrant Vetorial com filtros no servidor
Redis agent-framework-redis Vetorial sobre HASH ou JSON
SQL Server e Azure SQL agent-framework-sql-server Vetorial exata com filtros

Os pacotes de integração dos vector stores no Agent Framework estão em versão prévia. Assim, você instala o conector desejado com o sinalizador de pré-lançamento:

pip install agent-framework-postgres --pre
pip install agent-framework-azure-ai-search --pre

O mesmo modelo e as mesmas operações centrais funcionam em todas as integrações. No entanto, cada banco mantém recursos e restrições próprios, como versões mínimas, tipos de chave aceitos e ausência de busca híbrida.

Por exemplo, o PostgreSQL exige a versão 13 ou superior com pgvector 0.8.0, enquanto o SQL Server exige a versão 2025 ou um Azure SQL com suporte a vetores. Já o Qdrant aceita apenas chaves inteiras sem sinal ou UUIDs.

Para bancos como Chroma, Pinecone, Faiss e Weaviate, ainda não existe conector nativo. Nesse caso, as aplicações podem continuar usando os vector stores do Semantic Kernel diretamente, lembrando que as duas famílias de conectores não são intercambiáveis.

Cuidados antes de levar para produção

Como as APIs de vector stores no Agent Framework ainda são experimentais, convém isolar o acesso a vetores em uma camada própria da aplicação. Dessa maneira, uma eventual mudança de assinatura afeta poucos arquivos.

Também vale tratar a coleção em memória apenas como ferramenta de teste. Para produção, escolha um conector real e leia o README do pacote, porque ele descreve configuração, limitações e recursos suportados.

Outro cuidado envolve segurança e isolamento de dados. Como vimos, os filtros de escopo não substituem autorização, então a aplicação precisa controlar quem acessa cada coleção.

Por fim, revise as aprovações das ferramentas geradas pelo context provider. Liberar upsert sem aprovação pode ser útil em scripts automatizados, mas em produção o ideal é manter a supervisão nas operações que alteram dados.

Se você está montando a sua base em IA aplicada ao desenvolvimento, vale explorar também os conteúdos do balta.io sobre arquitetura e boas práticas. Além disso, a documentação oficial de integrações com vector stores traz a lista atualizada de requisitos de cada conector.

Conclusão sobre vector stores no Agent Framework

Os vector stores no Agent Framework representam uma evolução natural do trabalho iniciado no Semantic Kernel. A base continua familiar, mas a experiência agora conversa diretamente com a forma como os agentes recebem contexto.

Em resumo, você modela os dados com VectorStoreField, grava e pesquisa coleções com uma API única e expõe essa busca ao agente por ferramentas ou context providers. Com o VectorStoreHistoryProvider, o histórico completo continua acessível sem crescer indefinidamente no contexto do modelo.

Portanto, vale começar pelos samples oficiais com a coleção em memória e, depois, migrar para o banco que a sua aplicação já utiliza. A equipe da Microsoft também pede feedback sobre os context providers e sobre as próximas integrações no repositório do projeto.

FAQ

Os vector stores do Agent Framework substituem os do Semantic Kernel?

Eles representam a evolução do mesmo modelo, agora com contratos nativos no Agent Framework. Contudo, os conectores do Semantic Kernel continuam funcionando para bancos que ainda não possuem integração nativa.

Preciso instalar o Semantic Kernel para usar vector stores em Python?

Não, porque os contratos fazem parte do pacote agent-framework-core. Eles também não exigem Pydantic, NumPy nem pandas.

A coleção em memória serve para produção?

Não, já que ela guarda os dados apenas no processo atual e faz busca por varredura linear. Use essa coleção apenas em testes e desenvolvimento local.

Posso usar vetores que já calculei?

Sim, basta gravar os registros com generate_vectors=False. Na busca, você também pode enviar um vetor pronto em vez de um texto.

O scope_filter protege dados entre tenants?

Não, pois ele apenas agrupa registros para as ferramentas geradas. A autorização continua sendo responsabilidade da sua aplicação.

Qual a diferença entre a ferramenta de busca e o context provider?

A ferramenta de busca expõe uma única consulta focada ao agente. Já o context provider adiciona um conjunto completo de operações, com instruções e aprovações configuráveis.

Glossário

Termo Significado
Vector store Armazenamento que guarda dados junto com seus vetores para busca por similaridade
Embedding Representação numérica do significado de um texto ou outro conteúdo
Coleção Conjunto de registros com o mesmo modelo dentro de um vector store
Upsert Operação que insere um registro novo ou atualiza um existente
RAG Técnica que recupera dados externos para enriquecer a resposta do modelo
Context provider Componente que injeta contexto no agente antes e depois de cada invocação
Similaridade de cosseno Métrica que compara vetores pela direção, usada para medir semelhança semântica
Busca híbrida Combinação de busca vetorial com busca por palavra-chave
Compactação Estratégia que reduz o histórico carregado no contexto do modelo
pgvector Extensão do PostgreSQL que adiciona tipos e índices vetoriais

Fontes