No ano passado,Comecei a digerir um poucoao redorLançamento 4JÉ um projeto em rápido crescimento, e eu queria me familiarizar com as atualizações.Eu também queria verificar como integrar um servidor de Protocolo de Contexto Modelo em LangChain4J.
Versão Beta 1
Eu escrevi meu último post em novembro de 2024 e usei a versão mais recente disponível na época, v0.35.
Date |
Release |
---|---|
September 25th, 2024 |
0.35.0 |
December 22th, 2024 |
1.0.0-alpha1 |
February 10th, 2025 |
1.0.0-beta1 |
March 13th, 2025 |
1.0.0-beta2 |
April 12th, 2025 |
1.0.0-beta3 |
25 de setembro de 2024
0 35 0 0
22 de dezembro de 2024
1.0.0-Alfa1 do mundo
10 de fevereiro de 2025
1a BETA 1a BETA
13 de março de 2025
1.0.0-Beta2 do Brasil
12 de abril de 2025
1.4 Beta 3
LangChain4J é anunciadoSementeOs manutencionistas usaram a ocasião para introduzir mudanças de quebra.No meu caso, eu tive que atualizar meu código para compensar as mudanças de quebra da API.
v0.35 |
v1.0.0-beta3 |
---|---|
val s = Sinks.many() |
val s = Sinks.many() |
Val s = Sinks.many()
.União()
.onBackpressureBuffer<String>()
chatBot.talk(m.sessionId, m.texto)
.onPróximo(s::tryEmitPróximo)
.onErro(s::provaEditErro)
Não é completo
Página de Avaliação(
Iniciação (
Resenha do livro: O Caminho do Coração (
e.asFlux().asFlux()
)
Val s = Sinks.many()
.União()
.onBackpressureBuffer<String>()
chatBot.talk(m.sessionId, m.texto)
.onPartialResposta(s::tryEmitNext)
.onErro(s::provaEditErro)
.onCompleteResposta {
Página de Avaliação(
Iniciação (
Resenha do livro: O Caminho do Coração (
e.asFlux().asFlux()
)
Integração de Reatores
O LangChain4J oferece uma integração com o Project Reactor; eu perdi isso em meus trabalhos anteriores.a lot.
Estou usandoAiServices
, então eu anteriormente definido uma interface para LangChain4J para implementar no tempo de execução:
interface ChatBot {
fun talk(@MemoryId sessionId: String, @UserMessage message: String): TokenStream
}
Devemos acrescentar a seguinte dependência:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
<version>1.0.0-beta3</version>
</dependency>
Agora podemos alterar o tipo de retorno aFlux<String>
Dois aTokenStream
Aqui está a assinatura atualizada:
interface ChatBot {
fun talk(@MemoryId sessionId: String, @UserMessage message: String): Flux<String>
}
É a criação dasink
acima desnecessário. Podemos simplificar o código da seguinte forma:
val flux = chatBot.talk(m.sessionId, m.text)
ServerResponse.ok().bodyAndAwait(flux.asFlow())
Lembre-se que dois dias de depuração podem facilmente economizar duas horas de leitura da documentação!
Integração de um modelo de servidor de protocolo de contexto
Nesta seção, quero integrar um <abbr title="Model Context Protocol">MCP</abbr> na minha aplicação LangChain4J.
Geração aumentada de recuperação
Um precisa de muitos e muitos recursos para treinar um <abbr title="Large Language Model">LLM</abbr>: ele se traduz diretamente em tempo e dinheiro. Por esta razão, as empresas limitam o treinamento de novas versões do modelo. A relevância de um modelo diminui ao longo do tempo à medida que as informações se acumulam e mudam, enquanto o banco de dados do LLM é imutável.
Retrieval-Augmented Generation é um processo de dois passos.No primeiro passo, a ferramenta analisa os dados, vetoriza-os de acordo com o LLM e armazena-os em um banco de dados vetorial; no segundo, a ferramenta usa o banco de dados como dados adicionais quando consulta o LLM.
Protocolo de Contexto Modelo
The most recent way to handle the static nature of LLMs is MCP.
O MCP é um protocolo aberto que padroniza como os aplicativos fornecem contexto aos LLMs. Pense em MCP como um portão USB-C para aplicações de IA. Assim como o USB-C fornece uma maneira padronizada de conectar seus dispositivos a vários periféricos e acessórios, o MCP fornece uma maneira padronizada de conectar modelos de IA a diferentes fontes de dados e ferramentas.
Comece com o Protocolo de Contexto Modelo
O MCP é um protocolo aberto que padroniza como os aplicativos fornecem contexto aos LLMs. Pense em MCP como um portão USB-C para aplicações de IA. Assim como o USB-C fornece uma maneira padronizada de conectar seus dispositivos a vários periféricos e acessórios, o MCP fornece uma maneira padronizada de conectar modelos de IA a diferentes fontes de dados e ferramentas.
– – –Comece com o Protocolo de Contexto Modelo
O MCP tem duas vantagens sobre o RAG:
-
Data processed by a RAG is tailored for a model. If one wants to use a new model, one must re-execute the parsing phase. MCP standardizes the interactions between a client and a server, making them technology-independent.
-
RAG allows the reading of data. MCP allows any API call to either access data dynamically or execute actions!
MCP DefiniçãoDuas alternativas de transportePara comunicações cliente-servidor:
- stdio: o cliente inicia um subprocesso, e a comunicação ocorre sobre padrão e padrão fora
- HTTP com eventos de envio de servidor
Arquitetura da solução
Após a teoria acima, estamos agora prontos para a parte prática. Começa por escolher um servidor MCP.aquiÉ um bom ponto de partida, mas eu escolhiServiço GitHub MCPporque a documentação LangChain4J menciona isso.
O servidor MCP do GitHub oferece oEstúdioIsso significa que devemos obter o binário e iniciá-lo a partir do aplicativo. É rápido em comparação com o transporte HTTP, mas dado o tempo total que compreende a chamada HTTP para o modelo e o tempo de computação do seu lado, é irrelevante.
Depois de algumas pesquisas, encontrei oConexão ProxyProjeto. Ele permite que você mude de estdio para HTTP ou de HTTP para estdio. Também está disponível como uma imagem do Docker. Podemos combinar o servidor e o proxy com o seguinte:Dockerfile
:
FROM ghcr.io/sparfenyuk/mcp-proxy:latest
ENV VERSION=0.2.0
ENV ARCHIVE_NAME=github-mcp-server_Linux_x86_64.tar.gz
RUN wget https://github.com/github/github-mcp-server/releases/download/v$VERSION/$ARCHIVE_NAME -O /tmp/$ARCHIVE_NAME \ #1
&& tar -xzvf /tmp/$ARCHIVE_NAME -C /opt \ #2
&& rm /tmp/$ARCHIVE_NAME #3
RUN chmod +x /opt/github-mcp-server #4
- Baixe o arquivo
- Extraia o
- Remova o arquivo
- Faça o binário executável
Observe que não podemos definir oCMD
como o binário só permite configurar a porta e o host com parâmetros. Por esta razão, devemos adiar o comando no tempo de execução, ou no meu caso, nodocker-compose.yaml
:
services:
mcp-server:
build:
context: github-mcp-server
env_file:
- .env #1
command:
- --pass-environment #2
- --sse-port=8080 #3
- --sse-host=0.0.0.0 #4
- -- #5
- /opt/github-mcp-server #6
- --toolsets
- all
- stdio
- Precisamos de uma variável de ambiente GITHUB_PERSONAL_ACCESS_TOKEN com um token válido para autenticar no GitHub
- Passar todas as variáveis ambientais para o subprocesso
- Configurar o port de escuta
- Conecte-se a qualquer IP
- O proxy "se conecta" ao servidor MCP do stdio após o dash
- Execute o servidor com todas as opções habilitadas
A imagem fornecerá o/sse
Acesso à porta 8080.
Codificar a solução
A parte de codificação é a mais fácil.Documentação LangChain4J sobre o MCPe siga em frente. No projeto, traduz-se da seguinte forma:
bean {
val transport = HttpMcpTransport.Builder()
.sseUrl(ref<ApplicationProperties>().mcp.url) //1
.logRequests(true) //2
.logResponses(true) //2
.build()
val mcpClient = DefaultMcpClient.Builder()
.transport(transport)
.build()
mcpClient.listTools().forEach { println(it) } //3
McpToolProvider.builder()
.mcpClients(listOf(mcpClient))
.build()
}
bean {
coRouter {
val chatBot = AiServices
.builder(ChatBot::class.java)
.streamingChatLanguageModel(ref<StreamingChatLanguageModel>())
.chatMemoryProvider { MessageWindowChatMemory.withMaxMessages(40) }
.contentRetriever(EmbeddingStoreContentRetriever.from(ref<EmbeddingStore<TextSegment>>()))
.toolProvider(ref<McpToolProvider>()) //4
.build()
POST("/")(PromptHandler(chatBot)::handle)
}
}
- Eu adicionei uma classe ConfigurationProperty para parametrizar a URL SSE
- O protocolo MCP fornece uma maneira de enviar logs de volta para o cliente
- Não é necessário, mas me ajudou a garantir que o cliente esteja conectado ao servidor e pudesse listar as ferramentas fornecidas
- Plug-in no provedor de ferramentas MCP criado acima no AiServices
Neste ponto, o modelo deve encaminhar uma solicitação que corresponda a qualquer uma das ferramentas registradas para o servidor MCP.
curl -N -H 'Content-Type: application/json' localhost:8080 -d '{ "sessionId": "1", "text": "What are my top three most popular GitHub repos?" }'
Eu tentei várias vezes e recebi respostas nestas linhas:
Unfortunately, the provided text does not contain any information about your top three most popular GitHub repositories. The text appears to be a blog post or a personal website, and it mentions some of your projects and experiences with GitHub, but it does not provide any metrics or statistics on the popularity of your repositories.
If you want to know more about the popularity of your GitHub repositories, I would recommend checking out GitHub's own analytics tools, such as GitHub Insights or the Repository Insights API. These tools can provide information about the number of followers, stars, and forks for each repository, as well as other metrics like engagement and activity.
O modelo simplesmente ignorou as ferramentas, apesar da documentação alegar o contrário.
Fixando a solução
Eu li a documentação LangChain4J algumas vezes, mas sem sucesso. Eu tentei usar OpenAI e um punhado de outras ferramentas de IA sem sucesso. A maioria das respostas confirmou que deveria funcionar fora da caixa. Alguns mencionaram chamando a ferramenta diretamente, o que derrota o propósito; um mencionou que Ollama não suporta ferramentas. Verifiquei o blog Ollama: anunciou o suporte de ferramentas em 2024.
A arquitetura desconectada introduz mais peças em movimento. suspeitei que algo poderia estar errado em toda a cadeia de chamadas. removi o proxy MCP, adicionei ogithub-mcp-server
diretamente para a imagem do aplicativo, e alterou o código de HTTP para stdio.
Eu estava prestes a desistir quando decidi voltar às raízes.Amostra da documentaçãoFoi o meu ha-ha momento.
A amostra usa OpenAI, enquanto eu estava usando Ollama. Eu tentei o MCP com OpenAI, Mistral AI e Ollama. Somente o modelo OpenAI funciona com o MCP. Eu enviei o mesmo pedido como acima:
curl -N -H 'Content-Type: application/json' localhost:8080 -d '{ "sessionId": "1", "text": "What are my top three most popular GitHub repos?" }'
Agora, o OpenAI mapeia corretamente a solicitação para a ferramenta correta e retorna a resposta que eu estava esperando:
Here are my findings regarding your top three most popular GitHub repositories:
1. **[opentelemetry-tracing](https://github.com/nfrankel/opentelemetry-tracing)**
- **Description**: Demo for end-to-end tracing via OpenTelemetry.
- **Stars**: 68
- **Forks**: 25
- **Open Issues**: 10
2. **[kaadin](https://github.com/nfrankel/kaadin)**
- **Description**: Kotlin DSL for Vaadin.
- **Stars**: 44
- **Forks**: 12
- **Open Issues**: 3
3. **[jvm-controller](https://github.com/nfrankel/jvm-controller)**
- **Description**: Example on how to write a Kubernetes controller in Java.
- **Stars**: 33
- **Forks**: 10
- **Open Issues**: 0
These repositories demonstrate a range of your interests and contributions in the areas of observability, Kotlin development, and Kubernetes.%
Porque passamos um token de autenticação para o servidor MCP, que o passa para a API do GitHub, este último sabe qual usuário faz a chamada.my reposEu admito que é um caso de uso incomum para aplicativos web regulares que atendem a vários usuários, mas usam um único token de autenticação cada.
Outras perguntas frequentes,e. o g, encontre os repositórios mais populares no GitHub, são relevantes para aplicações web, já que eles não têm contexto implícito – o usuário.
CONCLUSÃO
O foco principal deste post é a integração de um servidor MCP em um aplicativo LangChain4J. Embora a configuração seja simples graças à documentação, existem algumas advertências.
Primeiro, como o servidor MCP se encaixa em sua arquitetura ainda depende de você.mcp-proxy
Então, LangChain4J parece ser uma abstração vazia. Ele faz tudo o que é possível para fornecer-lhe uma forte camada de abstração, mas as implementações sob ele o protege de não são iguais.
Eu aprendi sobre o MCP no mundo real, e isso abriu algumas portas para ideias de projeto.
O código-fonte completo deste artigo pode ser encontrado emGitHub.
To go further:
- Comece com o Protocolo de Contexto Modelo
- Encontre excelentes servidores e clientes MCP
- LangChain4J - Model Context Protocol (MCP)
Publicado originalmente em A Java Geek em 27 de abril de 2025
Sobre o Java Geek