{"slug": "java-moderno-com-ia-langchain4j-quarkus-rag-e-mcp-na-pratica-enterprise", "title": "Java Moderno com IA: LangChain4j, Quarkus, RAG e MCP na Prática Enterprise", "summary": "The Java ecosystem is formalizing AI in production with stable contracts. LangChain4j provides a Java-native LLM orchestration layer with declarative annotations and seamless integration with Quarkus and Spring Boot. RAG (Retrieval-Augmented Generation) enables context injection from proprietary data without fine-tuning, while MCP (Model Context Protocol) standardizes tool and data boundaries. Quarkus 3.37's default reflection-free Jackson serialization and the A2A Java SDK reaching GA further solidify the production-ready stack.", "body_md": "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.\n\nAntes 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:\n\n\"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.\"\n\n— Elder Moraes, Newsletter Java Weekly, jun. 2026 (eldermoraes.ai)\n\nA 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.\n\nEste 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.\n\nLangChain4j é 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.\n\nO 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.\n\n```\n// Declaração da interface — tudo que o dev precisa escrever\n@RegisterAiService(retriever = EmbeddingStoreRetriever.class)\npublic interface DocumentAssistant {\n\n    @SystemMessage(\"Você é um assistente especialista em regulatório financeiro.\")\n    @UserMessage(\"Com base nos documentos disponíveis, responda: {{question}}\")\n    String answer(@V(\"question\") String question);\n}\n```\n\nCom Quarkus, a extensão `quarkus-langchain4j`\n\ninjeta o serviço via CDI, resolve o provider de LLM pelo `application.properties`\n\n, 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.\n\n```\n# application.properties\nquarkus.langchain4j.ollama.base-url=http://localhost:11434\nquarkus.langchain4j.ollama.chat-model.model-id=llama3\nquarkus.langchain4j.ollama.embedding-model.model-id=nomic-embed-text\nquarkus.langchain4j.ollama.timeout=60s\n```\n\nPara produção, troca-se o bloco `ollama`\n\npor `openai`\n\nou `anthropic`\n\nsem 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.\n\nModelos 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.\n\nO 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.\n\n```\n@ApplicationScoped\npublic class DocumentIngestionService {\n\n    @Inject EmbeddingModel embeddingModel;\n    @Inject EmbeddingStore<TextSegment> embeddingStore;\n\n    public void ingest(Path filePath) {\n        // 1. Carrega o documento (PDF, TXT, HTML...)\n        Document document = FileSystemDocumentLoader.loadDocument(filePath);\n\n        // 2. Divide em chunks com overlap para preservar contexto\n        DocumentSplitter splitter = DocumentSplitters\n            .recursive(512, 64, new OpenAiTokenizer());\n\n        // 3. Gera embeddings e persiste na vector store\n        EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()\n            .documentSplitter(splitter)\n            .embeddingModel(embeddingModel)\n            .embeddingStore(embeddingStore)\n            .build();\n\n        ingestor.ingest(document);\n    }\n}\n@ApplicationScoped\npublic class EmbeddingStoreRetriever implements ContentRetriever {\n\n    @Inject EmbeddingModel embeddingModel;\n    @Inject EmbeddingStore<TextSegment> embeddingStore;\n\n    @Override\n    public List<Content> retrieve(Query query) {\n        Embedding queryEmbedding = embeddingModel\n            .embed(query.text()).content();\n\n        List<EmbeddingMatch<TextSegment>> matches =\n            embeddingStore.findRelevant(queryEmbedding, 5, 0.75);\n\n        return matches.stream()\n            .map(m -> Content.from(m.embedded()))\n            .toList();\n    }\n}\n```\n\nPara ambientes enterprise com Oracle ou PostgreSQL (via pgvector), o `EmbeddingStore`\n\ntroca 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.\n\n\"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.\"\n\n— Elder Moraes, Newsletter Java Weekly, jun. 2026 (eldermoraes.ai)\n\nAplicando 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.\n\nModel 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).\n\nA 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.\n\nA extensão `quarkus-mcp-server`\n\nexpõe beans CDI como ferramentas MCP com uma única anotação:\n\n```\n@ApplicationScoped\npublic class ContaCorrenteTools {\n\n    @Inject ContaCorrenteRepository repository;\n\n    @Tool(\"Consulta o saldo atual de uma conta corrente pelo número da conta\")\n    public SaldoResponse consultarSaldo(\n        @P(\"Número da conta no formato XXXXXXX-D\") String numeroConta) {\n\n        return repository.findSaldo(numeroConta)\n            .map(SaldoResponse::of)\n            .orElseThrow(() -> new ContaNaoEncontradaException(numeroConta));\n    }\n\n    @Tool(\"Lista os últimos lançamentos de uma conta em um período\")\n    public List<LancamentoResponse> listarLancamentos(\n        @P(\"Número da conta\") String numeroConta,\n        @P(\"Data inicial no formato yyyy-MM-dd\") String dataInicio,\n        @P(\"Data final no formato yyyy-MM-dd\") String dataFim) {\n\n        return repository.findLancamentos(numeroConta,\n            LocalDate.parse(dataInicio), LocalDate.parse(dataFim));\n    }\n}\n```\n\nO 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.\n\n```\n@RegisterAiService(tools = McpToolProvider.class)\npublic interface AssistenteFinanceiro {\n\n    @SystemMessage(\"\"\"\n        Você é um assistente financeiro cooperativista.\n        Use as ferramentas disponíveis para consultar dados reais antes de responder.\n        Nunca invente números. Se não tiver dados suficientes, diga claramente.\n        \"\"\")\n    String conversar(@MemoryId String sessionId,\n                     @UserMessage String mensagem);\n}\n```\n\nO 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.\n\nO fluxo completo de uma pergunta do usuário até a resposta com dados reais e contexto documental:\n\n```\nUsuário\n  |\n  v\n[AssistenteFinanceiro — AI Service]\n  |\n  |-- (1) Recuperação RAG --> EmbeddingStoreRetriever\n  |                               |\n  |                           Vector Store\n  |                               |\n  |                           Fragmentos relevantes <--|\n  |\n  |-- (2) Tool calls via MCP --> ContaCorrenteTools\n  |                               |\n  |                           Repository / Oracle DB\n  |                               |\n  |                           Dados transacionais <--|\n  |\n  v\n[LLM: Prompt = contexto RAG + dados MCP + histórico de sessão]\n  |\n  v\nResposta fundamentada\n```\n\nCada 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.\n\nHá 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.\n\nA 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:\n\nEssas 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.\n\nVoltando à divisão que o professor Moraes propõe — contrato estável versus empolgante-mas-instável:\n\n**Construa agora:**\n\n**Acompanhe, não deploya ainda:**\n\nO 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.\n\n**[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).\n\n**[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).\n\n**[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).\n\n**[4]** MORAES, Elder. *Método Java AI Specialist.* Disponível em: [https://eldermoraes.ai](https://eldermoraes.ai). Acesso em: jun. 2026.\n\n**[5]** LangChain4j. *Documentation.* Disponível em: [https://docs.langchain4j.dev](https://docs.langchain4j.dev).\n\n**[6]** Quarkus. *LangChain4j Extension Guide.* Disponível em: [https://quarkus.io/guides/langchain4j](https://quarkus.io/guides/langchain4j).\n\n**[7]** Anthropic. *Model Context Protocol Specification.* Disponível em: [https://modelcontextprotocol.io](https://modelcontextprotocol.io).", "url": "https://wpnews.pro/news/java-moderno-com-ia-langchain4j-quarkus-rag-e-mcp-na-pratica-enterprise", "canonical_source": "https://dev.to/ochimenes_rocha_f78f5dbb0/java-moderno-com-ia-langchain4j-quarkus-rag-e-mcp-na-pratica-enterprise-52po", "published_at": "2026-06-24 01:02:41+00:00", "updated_at": "2026-06-24 01:43:56.121307+00:00", "lang": "en", "topics": ["large-language-models", "generative-ai", "developer-tools", "artificial-intelligence", "machine-learning"], "entities": ["LangChain4j", "Quarkus", "Elder Moraes", "OpenJDK", "A2A Java SDK", "MCP", "RAG", "Ollama"], "alternates": {"html": "https://wpnews.pro/news/java-moderno-com-ia-langchain4j-quarkus-rag-e-mcp-na-pratica-enterprise", "markdown": "https://wpnews.pro/news/java-moderno-com-ia-langchain4j-quarkus-rag-e-mcp-na-pratica-enterprise.md", "text": "https://wpnews.pro/news/java-moderno-com-ia-langchain4j-quarkus-rag-e-mcp-na-pratica-enterprise.txt", "jsonld": "https://wpnews.pro/news/java-moderno-com-ia-langchain4j-quarkus-rag-e-mcp-na-pratica-enterprise.jsonld"}}