# Java Moderno com IA: LangChain4j, Quarkus, RAG e MCP na Prática Enterprise

> Source: <https://dev.to/ochimenes_rocha_f78f5dbb0/java-moderno-com-ia-langchain4j-quarkus-rag-e-mcp-na-pratica-enterprise-52po>
> Published: 2026-06-24 01:02:41+00:00

O ecossistema Java está formalizando IA em produção. Este artigo apresenta os blocos concretos de construção para quem quer sair do protótipo e chegar ao contrato estável.

Antes de entrar no código, vale nomear o momento. Na sua newsletter de junho de 2026, o professor Elder Moraes — referência no ecossistema Java e criador do Método Java AI Specialist — sintetizou com precisão o que está acontecendo na plataforma:

"O ecossistema Java está colocando estrutura formal em volta do que já roda em produção: padrão de interop, governança de contribuição, default de framework."

— Elder Moraes, Newsletter Java Weekly, jun. 2026 (eldermoraes.ai)

A leitura do professor Moraes é precisa e serve como bússola para este artigo. O A2A Java SDK atingiu GA (1.0.0.Final), o Quarkus 3.37 ativou serialização Jackson livre de reflexão por padrão, e o próprio OpenJDK teve que legislar sobre código gerado por IA — um sinal de que a adoção já acontece em escala. O trabalho do desenvolvedor agora não é mais avaliar *se* usar IA em Java, mas saber *como* construir em cima do que já é contrato estável.

Este artigo trata exatamente disso: os três pilares concretos que você pode colocar em produção hoje — LangChain4j como camada de orquestração de LLM, RAG (Retrieval-Augmented Generation) como estratégia de contexto, e MCP (Model Context Protocol) como borda de tool e dados.

LangChain4j é a port Java do ecossistema LangChain, mas construída com idioma Java de verdade: anotações declarativas, integração nativa com Spring Boot e Quarkus, e suporte a múltiplos provedores de LLM (OpenAI, Anthropic, Ollama, Azure OpenAI, Bedrock, entre outros) trocáveis via configuração, sem alterar a lógica de negócio.

O conceito central é o **AI Service**: uma interface Java anotada que o framework implementa em tempo de build (ou runtime), abstraindo o ciclo completo de prompt, chamada ao modelo e parse da resposta.

```
// Declaração da interface — tudo que o dev precisa escrever
@RegisterAiService(retriever = EmbeddingStoreRetriever.class)
public interface DocumentAssistant {

    @SystemMessage("Você é um assistente especialista em regulatório financeiro.")
    @UserMessage("Com base nos documentos disponíveis, responda: {{question}}")
    String answer(@V("question") String question);
}
```

Com Quarkus, a extensão `quarkus-langchain4j`

injeta o serviço via CDI, resolve o provider de LLM pelo `application.properties`

, e aplica os ganhos de native image automaticamente — incluindo o flip de Jackson reflection-free que o Quarkus 3.37 ativou por padrão, reduzindo cold start e consumo de heap sem nenhuma mudança no código da aplicação.

```
# application.properties
quarkus.langchain4j.ollama.base-url=http://localhost:11434
quarkus.langchain4j.ollama.chat-model.model-id=llama3
quarkus.langchain4j.ollama.embedding-model.model-id=nomic-embed-text
quarkus.langchain4j.ollama.timeout=60s
```

Para produção, troca-se o bloco `ollama`

por `openai`

ou `anthropic`

sem tocar em nenhuma linha Java. Esse isolamento é o primeiro contrato estável que o arquiteto precisa firmar: a lógica de negócio nunca deve conhecer o provedor de LLM.

Modelos de linguagem sabem muito, mas não sabem nada sobre os seus dados. RAG — Retrieval-Augmented Generation — é o padrão que resolve isso: em vez de treinar ou fazer fine-tuning (caro e lento), você recupera os fragmentos mais relevantes dos seus próprios dados no momento da pergunta e os injeta no contexto do prompt.

O pipeline tem três etapas fixas: ingestão (parse e chunking dos documentos), indexação (geração de embeddings e armazenamento em vector store) e recuperação (busca por similaridade no momento da query). LangChain4j cobre todas as três com APIs unificadas.

```
@ApplicationScoped
public class DocumentIngestionService {

    @Inject EmbeddingModel embeddingModel;
    @Inject EmbeddingStore<TextSegment> embeddingStore;

    public void ingest(Path filePath) {
        // 1. Carrega o documento (PDF, TXT, HTML...)
        Document document = FileSystemDocumentLoader.loadDocument(filePath);

        // 2. Divide em chunks com overlap para preservar contexto
        DocumentSplitter splitter = DocumentSplitters
            .recursive(512, 64, new OpenAiTokenizer());

        // 3. Gera embeddings e persiste na vector store
        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
            .documentSplitter(splitter)
            .embeddingModel(embeddingModel)
            .embeddingStore(embeddingStore)
            .build();

        ingestor.ingest(document);
    }
}
@ApplicationScoped
public class EmbeddingStoreRetriever implements ContentRetriever {

    @Inject EmbeddingModel embeddingModel;
    @Inject EmbeddingStore<TextSegment> embeddingStore;

    @Override
    public List<Content> retrieve(Query query) {
        Embedding queryEmbedding = embeddingModel
            .embed(query.text()).content();

        List<EmbeddingMatch<TextSegment>> matches =
            embeddingStore.findRelevant(queryEmbedding, 5, 0.75);

        return matches.stream()
            .map(m -> Content.from(m.embedded()))
            .toList();
    }
}
```

Para ambientes enterprise com Oracle ou PostgreSQL (via pgvector), o `EmbeddingStore`

troca de implementação pela configuração — nenhuma linha de recuperação muda. Em produção com base Oracle, o Oracle AI Vector Search (disponível desde o Oracle 23ai) é uma opção que elimina um componente de infraestrutura extra.

"A regra de decisão que eu usaria é separar o que é contrato estável pra construir em cima do que ainda é empolgante-mas-instável."

— Elder Moraes, Newsletter Java Weekly, jun. 2026 (eldermoraes.ai)

Aplicando a regra do professor Moraes ao RAG: o padrão de pipeline (ingestão, embedding, busca por similaridade, augmented prompt) é contrato estável. O que ainda varia é a escolha de vector store e o tamanho ótimo de chunk para o seu domínio. Mexa no segundo, confie no primeiro.

Model Context Protocol (MCP) é o padrão aberto, governado pela Anthropic e adotado pela indústria, para expor ferramentas e fontes de dados a modelos de linguagem de forma interoperável. Se o RAG resolve o problema de *conhecimento* (o que o modelo sabe), o MCP resolve o problema de *ação* (o que o modelo pode fazer).

A distinção entre o A2A (Agent2Agent, para comunicação agente-a-agente) e o MCP (para a borda de tool e dados) é fundamental para uma arquitetura limpa. Misturar os dois papéis em um único componente é o caminho mais curto para um sistema impossível de testar.

A extensão `quarkus-mcp-server`

expõe beans CDI como ferramentas MCP com uma única anotação:

```
@ApplicationScoped
public class ContaCorrenteTools {

    @Inject ContaCorrenteRepository repository;

    @Tool("Consulta o saldo atual de uma conta corrente pelo número da conta")
    public SaldoResponse consultarSaldo(
        @P("Número da conta no formato XXXXXXX-D") String numeroConta) {

        return repository.findSaldo(numeroConta)
            .map(SaldoResponse::of)
            .orElseThrow(() -> new ContaNaoEncontradaException(numeroConta));
    }

    @Tool("Lista os últimos lançamentos de uma conta em um período")
    public List<LancamentoResponse> listarLancamentos(
        @P("Número da conta") String numeroConta,
        @P("Data inicial no formato yyyy-MM-dd") String dataInicio,
        @P("Data final no formato yyyy-MM-dd") String dataFim) {

        return repository.findLancamentos(numeroConta,
            LocalDate.parse(dataInicio), LocalDate.parse(dataFim));
    }
}
```

O Quarkus registra automaticamente essas ferramentas no endpoint MCP da aplicação. Um agente externo — seja um assistente Claude, seja um orquestrador LangChain4j do próprio sistema — descobre e chama as ferramentas via protocolo padrão sem conhecer a implementação Java.

```
@RegisterAiService(tools = McpToolProvider.class)
public interface AssistenteFinanceiro {

    @SystemMessage("""
        Você é um assistente financeiro cooperativista.
        Use as ferramentas disponíveis para consultar dados reais antes de responder.
        Nunca invente números. Se não tiver dados suficientes, diga claramente.
        """)
    String conversar(@MemoryId String sessionId,
                     @UserMessage String mensagem);
}
```

O ciclo completo fica assim: o usuário envia uma mensagem, o LLM decide quais ferramentas chamar, o Quarkus executa as chamadas MCP contra os seus próprios endpoints Java, os resultados retornam ao LLM como contexto, e a resposta final é gerada com dados reais. Tudo rastreável, tudo testável.

O fluxo completo de uma pergunta do usuário até a resposta com dados reais e contexto documental:

```
Usuário
  |
  v
[AssistenteFinanceiro — AI Service]
  |
  |-- (1) Recuperação RAG --> EmbeddingStoreRetriever
  |                               |
  |                           Vector Store
  |                               |
  |                           Fragmentos relevantes <--|
  |
  |-- (2) Tool calls via MCP --> ContaCorrenteTools
  |                               |
  |                           Repository / Oracle DB
  |                               |
  |                           Dados transacionais <--|
  |
  v
[LLM: Prompt = contexto RAG + dados MCP + histórico de sessão]
  |
  v
Resposta fundamentada
```

Cada camada tem uma responsabilidade única. O AI Service orquestra. O RAG fornece conhecimento documental. O MCP fornece dados transacionais em tempo real. O LLM sintetiza. Nenhuma camada precisa conhecer as outras diretamente — apenas o contrato de interface.

Há um aspecto que vai além da arquitetura técnica e que o professor Moraes nomeia com precisão na sua newsletter: a oportunidade real não está em adotar o framework mais novo, mas em ser o desenvolvedor que sabe *governar* o uso de IA no time.

A decisão do OpenJDK de barrar contribuições geradas por LLM — mantendo o uso privado para entender, debugar e revisar — e a decisão oposta da GraalVM ilustram que não existe uma resposta única. O que existe é a necessidade de uma política deliberada. Para um time que usa assistentes de IA no dia a dia, as perguntas práticas são:

Essas perguntas têm respostas técnicas (regras de linter, gates no pipeline, cobertura mínima), mas a decisão de fazer as perguntas é liderança de engenharia.

Voltando à divisão que o professor Moraes propõe — contrato estável versus empolgante-mas-instável:

**Construa agora:**

**Acompanhe, não deploya ainda:**

O ecossistema Java tem histórico de levar tempo para padronizar e, quando padroniza, padronizar de forma que dura décadas. O desenvolvedor que entender os contratos estáveis hoje vai construir sobre fundação sólida enquanto o restante ainda debate qual framework adotar.

**[1]** MORAES, Elder. *A2A Java SDK 1.0.0.Final: o primeiro GA.* Newsletter Java Weekly, jun. 2026. Disponível em: [https://quarkus.io/blog/a2a-java-sdk-1-0-0-final-released/](https://quarkus.io/blog/a2a-java-sdk-1-0-0-final-released/) (citado via newsletter eldermoraes.ai).

**[2]** MORAES, Elder. *Quarkus 3.37 liga o Jackson reflection-free por padrão.* Newsletter Java Weekly, jun. 2026. Disponível em: [https://github.com/quarkusio/quarkus/releases/tag/3.37.0.CR1](https://github.com/quarkusio/quarkus/releases/tag/3.37.0.CR1) (citado via newsletter eldermoraes.ai).

**[3]** MORAES, Elder. *OpenJDK proíbe contribuição gerada por IA; a GraalVM, da mesma Oracle, permite.* Newsletter Java Weekly, jun. 2026. Disponível em: [https://www.infoq.com/news/2026/06/oracle-genai-policies/](https://www.infoq.com/news/2026/06/oracle-genai-policies/) (citado via newsletter eldermoraes.ai).

**[4]** MORAES, Elder. *Método Java AI Specialist.* Disponível em: [https://eldermoraes.ai](https://eldermoraes.ai). Acesso em: jun. 2026.

**[5]** LangChain4j. *Documentation.* Disponível em: [https://docs.langchain4j.dev](https://docs.langchain4j.dev).

**[6]** Quarkus. *LangChain4j Extension Guide.* Disponível em: [https://quarkus.io/guides/langchain4j](https://quarkus.io/guides/langchain4j).

**[7]** Anthropic. *Model Context Protocol Specification.* Disponível em: [https://modelcontextprotocol.io](https://modelcontextprotocol.io).
