Spring AI e Oracle Database: dando memória a um agente de IA
Pare de deixar seu LLM esquecer o contexto. Aprenda a criar um agente de IA com memória episódica, semântica e procedimental usando Spring AI e Oracle Database.
Todo LLM tem o mesmo problema: ele esquece tudo assim que a conversa termina — às vezes até durante conversas longas. Você passa vinte minutos explicando seu projeto, seus limites e preferências, e ele acerta em cheio. Fecha a aba, abre uma nova sessão, e ele te cumprimenta como se nunca tivesse te visto. Todo aquele contexto, sumiu.
Se você quer criar um agente de IA — algo que realmente lembra do contexto e conhece seu domínio — você precisa dar memória a ele. Do tipo prático, que guarda o que você disse e consegue consultar os fatos que você ensinou.
Este é um POC que eu construí exatamente para isso. Três tipos de memória, um banco de dados e pouco código. O código-fonte completo está no GitHub.
Arquitetura de agente de IA com Spring AI
Figura 1. Arquitetura ponta a ponta de memória de agente com Spring AI e Oracle AI Database 26ai
Ollama para inferência de chat (qwen2.5), rodando localmente
Oracle AI Database 26ai para os três armazenamentos de memória, com Hybrid Vector Indexes (vetor + busca por palavras-chave fundidos com Reciprocal Rank Fusion) para recuperação semântica e um modelo ONNX carregado (all-MiniLM-L12-v2) para embeddings dentro do banco
Streamlit para uma web UI rápida (~100 linhas de Python)
Java 21, Gradle 8.14
Três tipos de memória para agentes de IA
Costuma-se falar de memória episódica, semântica, procedimental e de trabalho para agentes.
A memória de trabalho é só a janela de contexto do LLM; o "rascunho" ativo do pedido atual. Ela não é persistida, então não há nada a construir. Eu implementei as outras três:
Memória episódica: persistindo o histórico do chat
Memória episódica é o histórico da conversa. O agente lembra o que você disse antes. "Meu nome é Victor" na mensagem 1 significa que ele ainda sabe seu nome na mensagem 50. Isso é armazenado como linhas em uma tabela relacional.
Figura 2. Memória episódica é o histórico do chat
Memória semântica: integração RAG
Memória semântica é o conhecimento do domínio. Você alimenta o agente com fatos (documentação de produto, políticas da empresa etc.) e ele busca os mais relevantes para responder.
Isso é RAG (Retrieval-Augmented Generation): o texto é convertido em vetores densos (embeddings) que mapeiam significado em um espaço geométrico, aproximando textos semanticamente similares.
Mas a busca puramente vetorial tem pontos cegos; ela captura bem o sentido, mas sofre com termos exatos como IDs de pedidos ou códigos de produto.
Por isso, este POC usa os Hybrid Vector Indexes da Oracle, que executam a busca por similaridade vetorial e a busca por palavras-chave (lexical) em paralelo, e depois fundem as duas listas de resultados com Reciprocal Rank Fusion (RRF).
Na consulta, a busca híbrida encontra documentos que correspondem por significado ou por termos exatos e injeta os principais resultados no prompt do LLM. As embeddings são calculadas dentro do banco por um modelo ONNX (all-MiniLM-L12-v2, 384 dimensões) carregado diretamente no Oracle, sem chamadas a APIs externas de embedding. Mais sobre isso abaixo.
Figura 3. Memória semântica como conhecimento de domínio
Memória procedimental: tool calling do LLM
Memória procedimental é o "como", os fluxos passo a passo que o agente sabe executar. Consultar um pedido, iniciar uma devolução, escalar para o suporte. No Spring AI, isso são métodos anotados com @Tool, que o LLM pode chamar quando decide que a tarefa exige ação, não só uma resposta.
Figura 4. Memória procedimental em ação: o agente usa tool calls para consultar dados de pedidos em tempo real e retornar resultados específicos da tarefa.
Figura 5. Fluxo de requisição no AgentController, onde memórias episódica, semântica e procedimental são combinadas a partir de tabelas do Oracle AI Database antes de gerar a resposta com o Ollama.
As duas tabelas vivem no mesmo Oracle Database. Sem Pinecone. Sem Redis. Sem segundo banco. Um pool de conexões, um conjunto de credenciais, uma coisa para monitorar.
Implementando ferramentas do Spring AI
A memória procedimental é implementada como métodos anotados com @Tool em um componente Spring que consulta tabelas reais no banco. Aqui vão dois métodos representativos, simplificados para clareza; a classe completa tem seis ferramentas (veja AgentTools.java):
@Tool(description ="Look up the status of a customer order by its order ID. "+"Returns the current status including shipping information.")publicStringlookupOrderStatus(@ToolParam(description ="The order ID to look up, e.g. ORD-1001")String orderId){// Fetches order from DB via JPA, returns formatted status string}@Tool(description ="Initiate a product return for a given order. "+"Validates the order exists, checks that it is in DELIVERED status, "+"and verifies the return is within the 30-day return window.")publicStringinitiateReturn(@ToolParam(description ="The order ID to return")String orderId,@ToolParam(description ="The reason for the return")String reason){// Validates order exists, checks DELIVERED status and 30-day window, updates status via JPA}Tecnologia
A descrição do @Tool informa ao LLM quando usar cada método, e @ToolParam descreve os argumentos. Quando o usuário diz "Quero devolver o pedido ORD-1001", o LLM lê as descrições das ferramentas, decide que initiateReturn é o procedimento certo, extrai os argumentos da conversa, chama o método e incorpora o resultado na resposta.
As outras quatro ferramentas são getCurrentDateTime (busca data/hora atual no banco), listOrders, escalateToSupport e listSupportTickets. Todas seguem o mesmo padrão: consultas via JPA ou JDBC. O LLM decide quando agir; os métodos Java definem como.
Construindo o controller do Spring Boot
O controller integra tudo: dois advisors, seis ferramentas, um ChatClient. Aqui está o núcleo, simplificado para clareza (a versão completa adiciona validação de entrada, tratamento de erros e endpoints de gerenciamento de conversa. Veja AgentController.java):
@RestController@RequestMapping("/api/v1/agent")publicclassAgentController{publicAgentController(ChatClient.Builder builder,JdbcChatMemoryRepository chatMemoryRepository,JdbcTemplate jdbcTemplate,AgentTools agentTools){// Builds a ChatClient with:// - MessageChatMemoryAdvisor (episodic: last 100 messages per conversation)// - RetrievalAugmentationAdvisor + OracleHybridDocumentRetriever (semantic: hybrid search)// - AgentTools via .defaultTools() (procedural: 6 @Tool methods)// - System prompt defining the agent persona and tool usage rules}@PostMapping("/chat")publicResponseEntity<String>chat(@RequestBodyString message,@RequestHeader("X-Conversation-Id")String conversationId){// Sends message to ChatClient with conversation ID, returns LLM response}@PostMapping("/knowledge")publicResponseEntity<String>addKnowledge(@RequestBodyString content){// Inserts text into POLICY_DOCS table via JDBC (hybrid index handles embedding)}}Tecnologia
Dois endpoints, dois advisors, seis ferramentas, um ChatClient. Vamos dissecar os três tipos de memória.
Gerenciando memória de chat com advisors do Spring
O padrão de advisors do Spring AI é onde a mágica acontece. Eles interceptam cada chamada ao LLM, podem ajustar o prompt antes do envio e processar a resposta na volta.
MessageChatMemoryAdvisor cuida da memória episódica. Antes de cada chamada ao LLM, ele carrega as últimas 100 mensagens da conversa atual da tabela SPRING_AI_CHAT_MEMORY e as adiciona ao início do prompt. Depois da resposta, salva a nova troca. A conversa é identificada pelo header X-Conversation-Id: ID diferente, memória diferente.
Implementando RAG com document retrievers
RetrievalAugmentationAdvisor cuida da memória semântica. Antes de cada chamada ao LLM, um OracleHybridDocumentRetriever customizado chama DBMS_HYBRID_VECTOR.SEARCH, que executa a busca por similaridade vetorial e a busca por palavras-chave do Oracle Text em paralelo e funde os resultados com RRF.
Os 5 documentos mais relevantes são injetados no prompt como contexto por um ContextualQueryAugmenter customizado que trata os documentos como suplementares; o LLM é instruído a usá-los apenas para perguntas de política, não para pedidos de ação ou contexto conversacional. Isso evita que o contexto de RAG sobreponha o histórico do chat ou impeça chamadas de ferramentas.
Por que híbrido em vez de apenas vetorial? Embeddings densas capturam significado: uma consulta sobre "política de devolução" vai casar com documentos sobre reembolso e trocas mesmo sem essas palavras exatas.
Mas são fracas para termos exatos: uma consulta por "ORD-1001" degrada porque o modelo de embedding codifica semântica, não palavras-chave. A busca híbrida cobre os dois: o lado vetorial trata do significado, o lado lexical cobre correspondências exatas, e o RRF combina as duas listas por posição no ranking, sem tentar normalizar escores incompatíveis.
Registrando ferramentas do agente
AgentTools cuida da memória procedimental. A chamada .defaultTools(agentTools) registra os seis métodos anotados com @Tool do componente. Em toda requisição, o LLM recebe as descrições das ferramentas junto com a mensagem do usuário. Se a tarefa requer ação, não só conhecimento, o LLM chama a ferramenta apropriada, obtém o resultado e o incorpora à resposta. O Spring AI gerencia o protocolo de tool calling automaticamente.
Os três tipos de memória rodam a cada requisição. O agente lembra o que você disse, consulta conhecimento relevante e sabe executar tarefas ao mesmo tempo.
Figura 6. Sequência ponta a ponta em que histórico do chat, contexto RAG híbrido e chamadas de ferramentas opcionais se combinam para produzir e persistir a resposta final.
Criando um endpoint de conhecimento para RAG
O endpoint /knowledge é simples: faça um POST com um texto e ele é inserido na tabela POLICY_DOCS via JDBC. O índice vetorial híbrido cuida automaticamente da embedding usando o modelo ONNX no banco, sem precisar de chamada a API externa de embedding. Na próxima pergunta relacionada, a busca híbrida vai encontrá-lo.
Fazendo o seeding do Oracle AI Database
Um DataSeeder (Spring CommandLineRunner) popula o banco na inicialização com 8 pedidos de demo e 12 documentos de políticas (devolução, envio, suporte, garantia, pagamento, cancelamento, troca, frete internacional, privacidade, promoções, garantia de produto e compras em volume). As políticas são carregadas de um recurso policies.json e inseridas na tabela POLICY_DOCS via JDBC. Os pedidos usam datas relativas para que a lógica da janela de devolução de 30 dias funcione sempre na demo. O seeder verifica contagens existentes para evitar duplicatas em reinicializações.
Evoluindo a memória semântica: busca híbrida
A primeira versão deste POC usava o QuestionAnswerAdvisor do Spring AI com OracleVectorStore: busca por similaridade vetorial pura com threshold de cosseno. Funcionava bem para perguntas limpas e bem formuladas sobre políticas. Mas desmoronava em termos exatos e typos. Uma busca por "order ORD-1001" tentava casar semanticamente com documentos de políticas, o que não faz sentido. Um "retrun polcy" com erro de digitação perdia score porque o modelo de embedding não entende que é um typo.
Criando índices vetoriais híbridos no Oracle
O Oracle 26ai oferece o DBMS_HYBRID_VECTOR.SEARCH, uma única chamada PL/SQL que executa busca por similaridade vetorial e busca por palavras-chave do Oracle Text em paralelo e depois funde os resultados.
O diferencial é o Reciprocal Rank Fusion (RRF): em vez de tentar normalizar escores de similaridade do cosseno (limitados entre 0 e 1) com escores BM25 de palavras-chave (não limitados), ele ranqueia os documentos pela posição em cada lista.
Um documento que é 1º no resultado vetorial e 3º no lexical recebe um ranking combinado que reflete ambos os sinais.
/SQL
-- Load the ONNX model for in-database embeddings
BEGIN
DBMS_VECTOR.LOAD_ONNX_MODEL(
directory => 'DM_DUMP',
file_name => 'all_MiniLM_L12_v2.onnx',
model_name => 'ALL_MINILM_L12_V2'
);
END;
/
-- Create a hybrid index: vector similarity + Oracle Text keyword search
CREATE HYBRID VECTOR INDEX POLICY_HYBRID_IDX
ON POLICY_DOCS(content)
PARAMETERS('MODEL ALL_MINILM_L12_V2 VECTOR_IDXTYPE HNSW');Tecnologia
Depois que o índice existe, as embeddings são geradas automaticamente quando as linhas são inseridas — sem necessidade de chamadas externas de embedding.
Integração de retrieval no Spring AI
O QuestionAnswerAdvisor do Spring AI só encapsula VectorStore.similaritySearch(), ou seja, apenas busca vetorial. Para usar busca híbrida, eu troquei para o RetrievalAugmentationAdvisor, a alternativa modular: ele aceita um DocumentRetriever customizado e um QueryAugmenter customizado para controlar como os documentos recuperados são injetados no prompt.
O OracleHybridDocumentRetriever custom implementa DocumentRetriever e chama DBMS_HYBRID_VECTOR.SEARCH via JDBC, passando um parâmetro JSON que especifica o índice híbrido, o scorer (RRF) e uma correspondência por palavra-chave:
publicList<Document>retrieve(Query query){// Builds a JSON spec with hybrid index name, RRF scorer, vector + text search clauses// Calls DBMS_HYBRID_VECTOR.SEARCH via JDBC, parses JSON results into List<Document>}Tecnologia
Isso contorna totalmente o OracleVectorStore para recuperação. A cláusula text.contains usa correspondência simples por palavra-chave com OR (palavras com mais de 2 caracteres), deixando o stemming nativo do Oracle Text lidar com variações.
Por que a busca híbrida melhora agentes de IA
O agente precisa de recuperação precisa para tomar boas decisões. Se a memória semântica retornar documentos de política errados ou com baixa confiança, o LLM pode alucinar parâmetros de ferramenta ou deixar de chamar uma ferramenta que deveria usar.
Busca híbrida significa contexto com mais confiança — e, portanto, decisões autônomas melhores; o agente tem menos chance de citar uma política errado ou perder um documento relevante quando tanto significado quanto termos exatos são considerados.
Configuração de banco de dados para Spring AI
A configuração fica em um único application.yaml. Decisões-chave: o Hibernate cria automaticamente as tabelas JPA (ddl-auto: update), o Spring AI cria automaticamente a tabela de memória de chat (initialize-schema: always), a tabela POLICY_DOCS e o índice vetorial híbrido são criados por um script SQL único (setup-hybrid-search.sql) e o Oracle UCP compartilha um pool de conexões entre os três tipos de memória.
Sem Flyway, sem classes @Configuration customizadas. A auto-configuração do Spring AI detecta o driver JDBC do Oracle e faz o wiring. Veja o application.yaml completo no repositório.
Construindo a Web UI com Streamlit
O frontend em Streamlit envia mensagens para o backend e renderiza as respostas. Aqui está o núcleo (o app completo inclui botões de quick start e novo chat. Veja app.py):
defsend_message(prompt, url):# POSTs plain text to /api/v1/agent/chat with X-Conversation-Id header# Renders user message and assistant response in Streamlit chat UIif prompt := st.chat_input("Type a message..."):
send_message(prompt, backend_url)Tecnologia
Ele gera um UUID por sessão para o ID da conversa, envia texto puro ao backend e renderiza a resposta. Só isso.
Rodando o POC do agente de IA localmente
Versão curta: suba um container do Oracle DB, carregue o modelo ONNX e crie o índice híbrido (setup único), instale o Ollama e puxe o modelo de chat (qwen2.5), rode o backend Spring Boot com o perfil local e, opcionalmente, inicie a UI em Streamlit. As embeddings são geradas dentro do banco pelo modelo ONNX, sem precisar de modelo de embedding no Ollama. O passo a passo completo está noREADME do repositório.
Teste rápido com curl:
curl-X POST http://localhost:8080/api/v1/agent/chat \-H"Content-Type: text/plain"\-H"X-Conversation-Id: test-1"\-d"What orders do I have?"Tecnologia
Conclusão
Essa arquitetura é um ótimo padrão para construir agentes reais com Spring AI e Oracle Database porque mantém todas as camadas de memória em uma única stack operacional: contexto episódico, recuperação semântica e ações procedimentais. O Spring AI oferece abstrações limpas (Advisors + @Tool) para que o comportamento do agente permaneça legível e testável, enquanto o Oracle cuida de dados transacionais e da recuperação híbrida no mesmo sistema, com embeddings dentro do banco e ranking por RRF para mais precisão tanto em significado quanto em termos exatos.
O resultado é prático: menos partes móveis, menos falhas de integração, menor latência e operações em produção mais simples. Em vez de costurar sistemas separados para histórico de chat, busca vetorial, busca por palavras-chave e tabelas de negócio, você constrói em uma plataforma e ainda assim obtém recuperação de alta qualidade e execução confiável de ferramentas. Para times lançando features de agentes, essa combinação de simplicidade, precisão e controle operacional é difícil de superar.
O que é memória de agente e por que isso importa? ⌄
Memória de agente permite que um sistema com LLM persista contexto entre requisições para lembrar conversas passadas, recuperar conhecimento do domínio e executar fluxos de trabalho com consistência.
Preciso de um banco vetorial separado para memória semântica?⌄
Não. Neste tutorial, o Oracle AI Database armazena dados relacionais, histórico do chat e índices de recuperação híbrida em um único sistema.
Qual a diferença entre memória episódica, semântica e procedimental? ⌄
Memória episódica guarda o histórico da conversa; memória semântica guarda conhecimento recuperável; memória procedimental define ações executáveis via ferramentas.
Por que usar recuperação híbrida e não apenas busca vetorial?⌄
A recuperação híbrida combina significado semântico e correspondência exata por palavra-chave, melhorando resultados tanto para perguntas vagas quanto para IDs ou termos exatos.
Essa arquitetura está pronta para produção?⌄
É uma base sólida, mas ambientes de produção ainda precisam de autenticação, autorização, observabilidade e testes de carga.
Sou arquiteto de backend e tech lead com mais de uma década de experiência construindo sistemas escaláveis e cloud-native. Sou especialista em arquiteturas distribuídas usando Java, Kotlin e plataformas modernas de nuvem, com foco em domain-driven design, sistemas orientados a eventos e design de software prático.
Meu trabalho é voltado para projetar plataformas de backend resilientes e aprimorar práticas de engenharia, explorando cada vez mais como a IA pode elevar a produtividade dos desenvolvedores e a qualidade do design de sistemas.
Saiba mais sobre os principais tipos de agentes de IA, como eles interagem com os ambientes e como são usados em todos os setores. Entenda o reflexo simples, baseado em modelo, baseado em meta, baseado em utilidade, agentes de aprendizagem e muito mais.
Os avanços recentes na IA têm o potencial de mudar drasticamente a ciência de dados. Dá uma olhada nesse artigo pra conhecer as cinco melhores ferramentas de IA que todo cientista de dados precisa saber.
Mergulhe na IA explicável (XAI) e saiba como criar confiança em sistemas de IA com LIME e SHAP para interpretabilidade de modelos. Entenda a importância da transparência e da justiça nas decisões baseadas em IA.
Uma visão geral abrangente da API Assistants com nosso artigo, que oferece uma análise aprofundada de seus recursos, usos no setor, orientação de configuração e práticas recomendadas para maximizar seu potencial em vários aplicativos de negócios.
Saiba como usar os acionadores SQL para automatizar tarefas, manter a integridade dos dados e melhorar o desempenho do banco de dados. Experimente exemplos práticos como os comandos CREATE, ALTER e DROP no MySQL e no Oracle.
Todo LLM tem o mesmo problema: ele esquece tudo assim que a conversa termina — às vezes até durante conversas longas. Você passa vinte minutos explicando seu projeto, seus limites e preferências, e ele acerta em cheio. Fecha a aba, abre uma nova sessão, e ele te cumprimenta como se nunca tivesse te visto. Todo aquele contexto, sumiu.
Se você quer criar um agente de IA — algo que realmente lembra do contexto e conhece seu domínio — você precisa dar memória a ele. Do tipo prático, que guarda o que você disse e consegue consultar os fatos que você ensinou.
Este é um POC que eu construí exatamente para isso. Três tipos de memória, um banco de dados e pouco código. O código-fonte completo está no GitHub.
Arquitetura de agente de IA com Spring AI
Figura 1. Arquitetura ponta a ponta de memória de agente com Spring AI e Oracle AI Database 26ai
A stack:
Três tipos de memória para agentes de IA
Costuma-se falar de memória episódica, semântica, procedimental e de trabalho para agentes.
A memória de trabalho é só a janela de contexto do LLM; o "rascunho" ativo do pedido atual. Ela não é persistida, então não há nada a construir. Eu implementei as outras três:
Memória episódica: persistindo o histórico do chat
Memória episódica é o histórico da conversa. O agente lembra o que você disse antes. "Meu nome é Victor" na mensagem 1 significa que ele ainda sabe seu nome na mensagem 50. Isso é armazenado como linhas em uma tabela relacional.
Figura 2. Memória episódica é o histórico do chat
Memória semântica: integração RAG
Memória semântica é o conhecimento do domínio. Você alimenta o agente com fatos (documentação de produto, políticas da empresa etc.) e ele busca os mais relevantes para responder.
Isso é RAG (Retrieval-Augmented Generation): o texto é convertido em vetores densos (embeddings) que mapeiam significado em um espaço geométrico, aproximando textos semanticamente similares.
Mas a busca puramente vetorial tem pontos cegos; ela captura bem o sentido, mas sofre com termos exatos como IDs de pedidos ou códigos de produto.
Por isso, este POC usa os Hybrid Vector Indexes da Oracle, que executam a busca por similaridade vetorial e a busca por palavras-chave (lexical) em paralelo, e depois fundem as duas listas de resultados com Reciprocal Rank Fusion (RRF).
Na consulta, a busca híbrida encontra documentos que correspondem por significado ou por termos exatos e injeta os principais resultados no prompt do LLM. As embeddings são calculadas dentro do banco por um modelo ONNX (all-MiniLM-L12-v2, 384 dimensões) carregado diretamente no Oracle, sem chamadas a APIs externas de embedding. Mais sobre isso abaixo.
Figura 3. Memória semântica como conhecimento de domínio
Memória procedimental: tool calling do LLM
Memória procedimental é o "como", os fluxos passo a passo que o agente sabe executar. Consultar um pedido, iniciar uma devolução, escalar para o suporte. No Spring AI, isso são métodos anotados com
@Tool, que o LLM pode chamar quando decide que a tarefa exige ação, não só uma resposta.Figura 4. Memória procedimental em ação: o agente usa tool calls para consultar dados de pedidos em tempo real e retornar resultados específicos da tarefa.
Figura 5. Fluxo de requisição no AgentController, onde memórias episódica, semântica e procedimental são combinadas a partir de tabelas do Oracle AI Database antes de gerar a resposta com o Ollama.
As duas tabelas vivem no mesmo Oracle Database. Sem Pinecone. Sem Redis. Sem segundo banco. Um pool de conexões, um conjunto de credenciais, uma coisa para monitorar.
Implementando ferramentas do Spring AI
A memória procedimental é implementada como métodos anotados com
@Toolem um componente Spring que consulta tabelas reais no banco. Aqui vão dois métodos representativos, simplificados para clareza; a classe completa tem seis ferramentas (veja AgentTools.java):A descrição do
@Toolinforma ao LLM quando usar cada método, e@ToolParamdescreve os argumentos. Quando o usuário diz "Quero devolver o pedido ORD-1001", o LLM lê as descrições das ferramentas, decide queinitiateReturné o procedimento certo, extrai os argumentos da conversa, chama o método e incorpora o resultado na resposta.As outras quatro ferramentas são
getCurrentDateTime(busca data/hora atual no banco),listOrders,escalateToSupportelistSupportTickets. Todas seguem o mesmo padrão: consultas via JPA ou JDBC. O LLM decide quando agir; os métodos Java definem como.Construindo o controller do Spring Boot
O controller integra tudo: dois advisors, seis ferramentas, um
ChatClient. Aqui está o núcleo, simplificado para clareza (a versão completa adiciona validação de entrada, tratamento de erros e endpoints de gerenciamento de conversa. Veja AgentController.java):Dois endpoints, dois advisors, seis ferramentas, um
ChatClient. Vamos dissecar os três tipos de memória.Gerenciando memória de chat com advisors do Spring
O padrão de advisors do Spring AI é onde a mágica acontece. Eles interceptam cada chamada ao LLM, podem ajustar o prompt antes do envio e processar a resposta na volta.
MessageChatMemoryAdvisorcuida da memória episódica. Antes de cada chamada ao LLM, ele carrega as últimas 100 mensagens da conversa atual da tabelaSPRING_AI_CHAT_MEMORYe as adiciona ao início do prompt. Depois da resposta, salva a nova troca. A conversa é identificada pelo headerX-Conversation-Id: ID diferente, memória diferente.Implementando RAG com document retrievers
RetrievalAugmentationAdvisorcuida da memória semântica. Antes de cada chamada ao LLM, umOracleHybridDocumentRetrievercustomizado chama DBMS_HYBRID_VECTOR.SEARCH, que executa a busca por similaridade vetorial e a busca por palavras-chave do Oracle Text em paralelo e funde os resultados com RRF.Os 5 documentos mais relevantes são injetados no prompt como contexto por um
ContextualQueryAugmentercustomizado que trata os documentos como suplementares; o LLM é instruído a usá-los apenas para perguntas de política, não para pedidos de ação ou contexto conversacional. Isso evita que o contexto de RAG sobreponha o histórico do chat ou impeça chamadas de ferramentas.Por que híbrido em vez de apenas vetorial? Embeddings densas capturam significado: uma consulta sobre "política de devolução" vai casar com documentos sobre reembolso e trocas mesmo sem essas palavras exatas.
Mas são fracas para termos exatos: uma consulta por "ORD-1001" degrada porque o modelo de embedding codifica semântica, não palavras-chave. A busca híbrida cobre os dois: o lado vetorial trata do significado, o lado lexical cobre correspondências exatas, e o RRF combina as duas listas por posição no ranking, sem tentar normalizar escores incompatíveis.
Registrando ferramentas do agente
AgentToolscuida da memória procedimental. A chamada.defaultTools(agentTools)registra os seis métodos anotados com@Tooldo componente. Em toda requisição, o LLM recebe as descrições das ferramentas junto com a mensagem do usuário. Se a tarefa requer ação, não só conhecimento, o LLM chama a ferramenta apropriada, obtém o resultado e o incorpora à resposta. O Spring AI gerencia o protocolo de tool calling automaticamente.Os três tipos de memória rodam a cada requisição. O agente lembra o que você disse, consulta conhecimento relevante e sabe executar tarefas ao mesmo tempo.
Figura 6. Sequência ponta a ponta em que histórico do chat, contexto RAG híbrido e chamadas de ferramentas opcionais se combinam para produzir e persistir a resposta final.
Criando um endpoint de conhecimento para RAG
O endpoint
/knowledgeé simples: faça um POST com um texto e ele é inserido na tabelaPOLICY_DOCSvia JDBC. O índice vetorial híbrido cuida automaticamente da embedding usando o modelo ONNX no banco, sem precisar de chamada a API externa de embedding. Na próxima pergunta relacionada, a busca híbrida vai encontrá-lo.Fazendo o seeding do Oracle AI Database
Um
DataSeeder(SpringCommandLineRunner) popula o banco na inicialização com 8 pedidos de demo e 12 documentos de políticas (devolução, envio, suporte, garantia, pagamento, cancelamento, troca, frete internacional, privacidade, promoções, garantia de produto e compras em volume). As políticas são carregadas de um recursopolicies.jsone inseridas na tabelaPOLICY_DOCSvia JDBC. Os pedidos usam datas relativas para que a lógica da janela de devolução de 30 dias funcione sempre na demo. O seeder verifica contagens existentes para evitar duplicatas em reinicializações.Evoluindo a memória semântica: busca híbrida
A primeira versão deste POC usava o QuestionAnswerAdvisor do Spring AI com OracleVectorStore: busca por similaridade vetorial pura com threshold de cosseno. Funcionava bem para perguntas limpas e bem formuladas sobre políticas. Mas desmoronava em termos exatos e typos. Uma busca por "order ORD-1001" tentava casar semanticamente com documentos de políticas, o que não faz sentido. Um "retrun polcy" com erro de digitação perdia score porque o modelo de embedding não entende que é um typo.
Criando índices vetoriais híbridos no Oracle
O Oracle 26ai oferece o DBMS_HYBRID_VECTOR.SEARCH, uma única chamada PL/SQL que executa busca por similaridade vetorial e busca por palavras-chave do Oracle Text em paralelo e depois funde os resultados.
O diferencial é o Reciprocal Rank Fusion (RRF): em vez de tentar normalizar escores de similaridade do cosseno (limitados entre 0 e 1) com escores BM25 de palavras-chave (não limitados), ele ranqueia os documentos pela posição em cada lista.
Um documento que é 1º no resultado vetorial e 3º no lexical recebe um ranking combinado que reflete ambos os sinais.
A preparação é um script SQL único que carrega um modelo de embedding ONNX no Oracle AI Database e cria um índice híbrido:
Depois que o índice existe, as embeddings são geradas automaticamente quando as linhas são inseridas — sem necessidade de chamadas externas de embedding.
Integração de retrieval no Spring AI
O QuestionAnswerAdvisor do Spring AI só encapsula
VectorStore.similaritySearch(), ou seja, apenas busca vetorial. Para usar busca híbrida, eu troquei para o RetrievalAugmentationAdvisor, a alternativa modular: ele aceita um DocumentRetriever customizado e umQueryAugmentercustomizado para controlar como os documentos recuperados são injetados no prompt.O
OracleHybridDocumentRetrievercustom implementaDocumentRetrievere chamaDBMS_HYBRID_VECTOR.SEARCHvia JDBC, passando um parâmetro JSON que especifica o índice híbrido, o scorer (RRF) e uma correspondência por palavra-chave:Isso contorna totalmente o
OracleVectorStorepara recuperação. A cláusulatext.containsusa correspondência simples por palavra-chave comOR(palavras com mais de 2 caracteres), deixando o stemming nativo do Oracle Text lidar com variações.Por que a busca híbrida melhora agentes de IA
O agente precisa de recuperação precisa para tomar boas decisões. Se a memória semântica retornar documentos de política errados ou com baixa confiança, o LLM pode alucinar parâmetros de ferramenta ou deixar de chamar uma ferramenta que deveria usar.
Busca híbrida significa contexto com mais confiança — e, portanto, decisões autônomas melhores; o agente tem menos chance de citar uma política errado ou perder um documento relevante quando tanto significado quanto termos exatos são considerados.
Configuração de banco de dados para Spring AI
A configuração fica em um único application.yaml. Decisões-chave: o Hibernate cria automaticamente as tabelas JPA (ddl-auto: update), o Spring AI cria automaticamente a tabela de memória de chat (initialize-schema: always), a tabela POLICY_DOCS e o índice vetorial híbrido são criados por um script SQL único (setup-hybrid-search.sql) e o Oracle UCP compartilha um pool de conexões entre os três tipos de memória.
Sem Flyway, sem classes
@Configurationcustomizadas. A auto-configuração do Spring AI detecta o driver JDBC do Oracle e faz o wiring. Veja o application.yaml completo no repositório.Construindo a Web UI com Streamlit
O frontend em Streamlit envia mensagens para o backend e renderiza as respostas. Aqui está o núcleo (o app completo inclui botões de quick start e novo chat. Veja app.py):
Ele gera um UUID por sessão para o ID da conversa, envia texto puro ao backend e renderiza a resposta. Só isso.
Rodando o POC do agente de IA localmente
Versão curta: suba um container do Oracle DB, carregue o modelo ONNX e crie o índice híbrido (setup único), instale o Ollama e puxe o modelo de chat (qwen2.5), rode o backend Spring Boot com o perfil local e, opcionalmente, inicie a UI em Streamlit. As embeddings são geradas dentro do banco pelo modelo ONNX, sem precisar de modelo de embedding no Ollama. O passo a passo completo está no README do repositório.
Teste rápido com curl:
Conclusão
Essa arquitetura é um ótimo padrão para construir agentes reais com Spring AI e Oracle Database porque mantém todas as camadas de memória em uma única stack operacional: contexto episódico, recuperação semântica e ações procedimentais. O Spring AI oferece abstrações limpas (Advisors +
@Tool) para que o comportamento do agente permaneça legível e testável, enquanto o Oracle cuida de dados transacionais e da recuperação híbrida no mesmo sistema, com embeddings dentro do banco e ranking por RRF para mais precisão tanto em significado quanto em termos exatos.O resultado é prático: menos partes móveis, menos falhas de integração, menor latência e operações em produção mais simples. Em vez de costurar sistemas separados para histórico de chat, busca vetorial, busca por palavras-chave e tabelas de negócio, você constrói em uma plataforma e ainda assim obtém recuperação de alta qualidade e execução confiável de ferramentas. Para times lançando features de agentes, essa combinação de simplicidade, precisão e controle operacional é difícil de superar.
Para aprender mais sobre agentes de IA e como eles funcionam, recomendo a trilha de habilidades AI Agent Fundamentals da DataCamp.