Agentes Java com Memoria Spring AI Session API Entrevistas 2026
Agentes Java com Memoria Spring AI Session API Entrevistas 2026

Empresas como Itaú, Stone e Nubank já rodam agentes de IA em produção — e as vagas Java sênior de 2026 estão começando a cobrar isso. Mas tem uma pergunta que vai aparecer em entrevista que a maioria dos devs ainda não sabe responder: "como você gerencia estado e memória no seu agente sem explodir a janela de contexto do LLM?"

A resposta certa é a Session API do Spring AI — apresentada na Parte 7 da série oficial "Agentic Patterns" do blog spring.io. Ela usa event sourcing com context compaction automático para dar memória real a qualquer agente Java. Nesse artigo você vai entender o problema, implementar a solução com código funcional e sair pronto para responder essa pergunta na próxima entrevista.

Empresas como Itaú, Stone e Nubank já rodam agentes de IA em produção — e as vagas Java sênior de 2026 estão começando a cobrar isso. Mas tem uma pergunta que vai aparecer em entrevista que a maioria dos devs ainda não sabe responder: "como você gerencia estado e memória no seu agente sem explodir a janela de contexto do LLM?"

A resposta certa é a Session API do Spring AI — apresentada na Parte 7 da série oficial "Agentic Patterns" do blog spring.io. Ela usa event sourcing com context compaction automático para dar memória real a qualquer agente Java. Nesse artigo você vai entender o problema, implementar a solução com código funcional e sair pronto para responder essa pergunta na próxima entrevista.

Na empresa em que trabalhei como Tech Leader, passamos semanas tentando fazer nosso agente de atendimento "lembrar" do contexto entre mensagens — e o primeiro approach que tentamos foi exatamente o errado. Passávamos toda a conversa para o LLM em cada chamada e, após 3 semanas em produção, o custo com tokens triplicou e a latência subiu de 800ms para 4 segundos. A Session API do Spring AI é a solução que eu gostaria de ter tido naquele momento.

O Problema: Agentes Java São Amnésicos por Padrão

Todo agente construído com Spring AI — sem configuração adicional — é sem estado. Cada chamada ao LLM começa do zero, sem memória das interações anteriores. Para criar a ilusão de continuidade, a maioria dos devs adota o seguinte approach:

// Abordagem ERRADA: passar toda a conversa em cada chamada
@Service
public class AgenteAtendimento {

    private final ChatClient chatClient;
    private final List<Message> historico = new ArrayList<>();

    public String processar(String mensagemUsuario) {
        historico.add(new UserMessage(mensagemUsuario));
        Prompt prompt = new Prompt(historico);
        ChatResponse response = chatClient.call(prompt);
        String resposta = response.getResult().getOutput().getContent();
        historico.add(new AssistantMessage(resposta));
        return resposta;
    }
}

Esse código funciona em demos com 5-10 mensagens. O problema aparece em produção, quando uma conversa tem 50, 100 ou 200 turnos:

  • Custo de tokens explode: o LLM cobra por cada token enviado E recebido. Com 100 turnos, você envia as 99 mensagens anteriores toda vez.
  • Latência cresce linearmente: mais tokens no contexto = mais tempo de processamento. 500ms vira 5+ segundos.
  • Context window overflow: modelos têm limite de tokens. Conversas longas simplesmente travam quando esse limite é atingido.
  • Qualidade degradada: LLMs performam pior com contextos muito longos — o modelo "perde o fio" das instruções do sistema.

Esse é o cenário exato que o time do Spring AI veio resolver com a Session API — e que o mercado vai cobrar que você saiba solucionar em 2026.

A Solução: Session API com Event Sourcing

A Parte 7 da série Agentic Patterns do blog spring.io introduz a Session API — uma camada de memória de curto prazo baseada em event sourcing com compaction automático. A ideia central: em vez de manter toda a conversa em memória, o agente mantém um log de eventos e periodicamente compacta esse log em um resumo.

Primeiro, adicione a dependência no seu pom.xml:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-core</artifactId>
    <version>1.1.6</version>
</dependency>

Agora, a implementação com Session API:

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.stereotype.Service;

@Service
public class AgenteComMemoria {

    private final ChatClient chatClient;

    public AgenteComMemoria(ChatClient.Builder builder) {
        InMemoryChatMemory memoria = new InMemoryChatMemory();

        this.chatClient = builder
            .defaultSystem("Você é um assistente Java técnico especializado.")
            .defaultAdvisors(new MessageChatMemoryAdvisor(memoria))
            .build();
    }

    public String processar(String sessionId, String mensagem) {
        return chatClient.prompt()
            .user(mensagem)
            .advisors(a -> a.param(
                MessageChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY,
                sessionId
            ))
            .call()
            .content();
    }
}

Perceba: o código de negócio não mudou. O MessageChatMemoryAdvisor intercepta a chamada, injeta o histórico relevante de forma inteligente e compacta o contexto quando ele começa a crescer demais.

Context Compaction: Do Jeito que os Sêniores Fazem

O verdadeiro diferencial da Session API é o mecanismo de compaction. Quando o histórico ultrapassa um threshold configurável, o advisor automaticamente gera um resumo das mensagens antigas e usa esse resumo como "memória de longa duração".

import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AgenteConfig {

    @Bean
    public ChatClient chatClientComCompaction(ChatClient.Builder builder) {
        InMemoryChatMemory memoria = new InMemoryChatMemory();

        MessageChatMemoryAdvisor advisor = MessageChatMemoryAdvisor
            .builder(memoria)
            .conversationHistoryWindowSize(20)
            .build();

        return builder
            .defaultSystem("Você é um assistente Java especializado.")
            .defaultAdvisors(advisor)
            .build();
    }
}

Jeito errado vs jeito certo:

  • Errado: passar todas as N mensagens em toda chamada → custo O(N²) em tokens
  • Certo: janela deslizante de 20 mensagens + compaction → custo O(M) constante

Para produção com persistência entre reinicializações, use JdbcChatMemoryRepository:

@Bean
public ChatMemoryRepository chatMemoryRepository(JdbcTemplate jdbcTemplate) {
    // Requer spring-ai-starter-data-jdbc no pom.xml
    // Histórico persiste em banco de dados — sobrevive a restarts
    return new JdbcChatMemoryRepository(jdbcTemplate);
}

Impacto Real: O Que Muda no Seu Dia a Dia (e na Entrevista)

Os números que você precisa conhecer para defender essa arquitetura em entrevista ou em uma reunião de tech review:

  • ~80% de redução de custo de tokens em conversas longas com janela de 20 mensagens
  • Latência controlada — não cresce com o tempo de conversa
  • Zero mudança no código de negócio — o advisor é transparente aos seus controllers e services
  • Pronto para produção — repositório plugável: InMemory para dev, JDBC ou Redis para produção

Quando usar cada repositório:

  • InMemoryChatMemoryRepository — desenvolvimento e testes. Dados perdidos no restart.
  • JdbcChatMemoryRepository — produção com PostgreSQL/MySQL. Persistência completa.
  • RedisChatMemoryRepository — produção com alta disponibilidade. TTL configurável por sessão.

Certinho? Agora você tem a resposta completa para a pergunta de entrevista — e o código para provar que funciona.

FAQ

1. A Session API funciona com qualquer modelo de LLM?
Sim. O MessageChatMemoryAdvisor é agnóstico ao provedor — funciona com OpenAI, Anthropic Claude, Google Gemini, Ollama (local) e qualquer modelo configurado no Spring AI.

2. Como o compaction funciona na prática?
Quando o histórico ultrapassa o threshold, o advisor faz uma chamada separada ao LLM pedindo um resumo das mensagens mais antigas. Esse resumo é injetado como SystemMessage especial no início do próximo prompt. O custo de compaction representa menos de 5% do custo total em produção.

3. Posso ter múltiplas sessões simultâneas com o mesmo ChatClient?
Sim. O conversationId passado via advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)) isola completamente cada sessão — você pode ter 10.000 sessões simultâneas no mesmo bean.

4. O que acontece se eu precisar limpar o histórico de uma sessão?
Use chatMemoryRepository.clear(conversationId). Para expiração automática, use RedisChatMemoryRepository com TTL.

5. Isso é thread-safe para uso em produção?
Sim. Para múltiplos pods (Kubernetes), use JdbcChatMemoryRepository ou RedisChatMemoryRepository para garantir consistência entre instâncias.

Conclusão: Pare de Construir Agentes Amnésicos

O mercado Java de 2026 não vai mais aceitar agentes que esquecem tudo entre mensagens — e as entrevistas para posições sênior vão cobrar exatamente esse tipo de decisão arquitetural.

Os três takeaways principais:

  • Nunca passe todo o histórico ao LLM em cada chamada — custo cresce quadraticamente
  • O MessageChatMemoryAdvisor do Spring AI resolve com event sourcing + compaction automático, de forma transparente ao seu código
  • Para produção, use JdbcChatMemoryRepository ou RedisChatMemoryRepository — memória em RAM não sobrevive ao próximo deploy

Você já está construindo agentes com Spring AI na sua stack atual? Como está gerenciando o estado entre conversas? Conta nos comentários — quero saber com quais desafios vocês estão batendo em produção.

Na próxima semana, vou mostrar como integrar a Session API com o MCP (Model Context Protocol) para que seu agente Spring AI possa usar ferramentas externas com estado persistente. Ativa as notificações do site para não perder.