Início Tecnologia Revisitando Langchain4J 6 meses depois

Revisitando Langchain4J 6 meses depois

7
0

No ano passado, comecei a cavar um pouco em torno de Langchain4J. É um projeto de 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 de modelo em Langchain4J.

Versão 1 beta

Escrevi meu último publish em novembro de 2024 e usei a versão mais recente disponível na época, v0.35. Langchain4J começou sua jornada em direção a 1,0 em dezembro passado.

Information

Liberar

25 de setembro de 2024

0,35.0

22 de dezembro de 2024

1.0.0-alfa1

10 de fevereiro de 2025

1.0.0-beta1

13 de março de 2025

1.0.0-beta2

12 de abril de 2025

1.0.0-beta3

Langchain4j segue Semver. Os mantenedores usaram a ocasião para introduzir mudanças de ruptura. No meu caso, tive que atualizar meu código para contabilizar as alterações da API.

v0.35

v1.0.0-beta3

val s = pia.Many ()
.Unicast ()
.OnbackPressureBuffer()
Chatbot.Discuss (M.SessionId, M.Textual content)
.ONNEXT (S :: TryemitNext)
.ONERROR (S :: TryEmitError)
.OnComplete {
S.TryEmitComplete ()
}.começar()
retornar serverResponse.okay (). Bodyandawait (
S.Asflux (). Asflow ()
)

val s = pia.Many ()
.Unicast ()
.OnbackPressureBuffer()
Chatbot.Discuss (M.SessionId, M.Textual content)
.ONPARTIALResponse (S :: TryEmitNext)
.ONERROR (S :: TryEmitError)
.OnCompleteterSponse {
S.TryEmitComplete ()
}.começar()
retornar serverResponse.okay (). Bodyandawait (
S.Asflux (). Asflow ()
)

Integração do reator do projeto

Langchain4J oferece uma integração de reatores de projeto; Eu perdi nas minhas reflexões anteriores. Com Kotlin Coroutines, simplifica o código bastante.

Estou usando AiServicesentão eu defini anteriormente uma interface para Langchain4J implementar no tempo de execução:

interface ChatBot {
    enjoyable discuss(@MemoryId sessionId: String, @UserMessage message: String): TokenStream
}

Devemos adicionar a seguinte dependência:


    dev.langchain4j
    langchain4j-reactor
    1.0.0-beta3

Agora podemos alterar o tipo de retorno de um Flux para um TokenStream. Aqui está a assinatura atualizada:

interface ChatBot {
    enjoyable discuss(@MemoryId sessionId: String, @UserMessage message: String): Flux
}

Faz a criação do sink acima desnecessário. Podemos simplificar o código da seguinte forma:

val flux = chatBot.discuss(m.sessionId, m.textual content)
ServerResponse.okay().bodyAndAwait(flux.asFlow())

Lembre -se de que dois dias de depuração podem economizar facilmente duas horas lendo a documentação! Eu não fiz o último.

Integração de um servidor de protocolo de contexto de modelo

Até este ponto, nossas mudanças foram mínimas. Nesta seção, quero integrar um MCP no meu aplicativo Langchain4j.

Geração de recuperação une a geração

Precisa de muitos e muitos recursos para treinar um Llm: Ele se traduz diretamente em tempo e dinheiro. Por esse motivo, as empresas limitam o treinamento de novas versões de modelos. A relevância de um modelo diminui com o tempo à medida que as informações se acumulam e mudam, enquanto o banco de dados do LLM é imutável. Além disso, os LLMs são treinados em dados públicos – pela natureza, enquanto a maioria das empresas também deseja consultar seus dados privados.

A geração aumentada de recuperação foi a maneira tradicional de lidar com esses limites. A geração de recuperação com agente de recuperação é um processo de duas etapas. Na primeira etapa, a ferramenta analisa os dados, o vetoriza de acordo com o LLM e o armazena em um banco de dados vetorial; No segundo, a ferramenta usa o banco de dados como dados adicionais ao consultar o LLM.

Modelo Protocolo de contexto

A maneira mais recente de lidar com a natureza estática do LLMS é o MCP.

O MCP é um protocolo aberto que padroniza como os aplicativos fornecem contexto ao LLMS. Pense no MCP como uma porta USB-C para aplicativos 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 e ferramentas de dados.

– Comece com o protocolo de contexto do modelo

O MCP tem dois benefícios sobre o RAG:

  • Os dados processados ​​por um pano são adaptados para um modelo. Se alguém quiser usar um novo modelo, deve-se reexecionar a fase de análise. O MCP padroniza as interações entre um cliente e um servidor, tornando-os independentes da tecnologia.

  • RAG permite a leitura de dados. O MCP permite qualquer chamada de API para acessar dados dinamicamente ou executar ações!

O MCP outline duas alternativas de transporte para comunicações cliente-servidor:

  • Stdio: o cliente lança um subprocesso, e a comunicação ocorre sobre o padrão e o padrão
  • HTTP com eventos enviados ao servidor

Arquiteta a solução

Após a teoria acima, agora estamos prontos para a parte prática. Começa escolhendo um servidor MCP. Aqui está um bom ponto de partida. No entanto, escolhi o servidor oficial do GitHub MCP porque a documentação do Langchain4J menciona.

O servidor Github MCP oferece o stdio transporte. Isso 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 complete que compreende a chamada HTTP para o modelo e o tempo de computação do seu lado, é irrelevante. Do ponto de vista da arquitetura, eu prefiro um componente dedicado ao seu processo.

Depois de algumas pesquisas, encontrei o projeto MCP-Proxy. Ele permite alternar entre o stdio para o http ou o http para o stdio. 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:newest

ENV VERSION=0.2.0
ENV ARCHIVE_NAME=github-mcp-server_Linux_x86_64.tar.gz

RUN wget  -O /tmp/$ARCHIVE_NAME  #1
    && tar -xzvf /tmp/$ARCHIVE_NAME -C /decide                       #2
    && rm /tmp/$ARCHIVE_NAME                                       #3

RUN chmod +x /decide/github-mcp-server                                #4
  1. Baixe o arquivo
  2. Extraia -o
  3. Remova o arquivo
  4. Faça o executável binário

Observe que não podemos definir o CMD Como o binário permite apenas configurar a porta e o host com parâmetros. Por esse motivo, devemos adiar o comando em tempo de execução, ou no meu caso, no docker-compose.yaml:

companies:
  mcp-server:
    construct:
      context: github-mcp-server
    env_file:
      - .env                                                       #1
    command:
      - --pass-environment                                         #2
      - --sse-port=8080                                            #3
      - --sse-host=0.0.0.0                                         #4
      - --                                                         #5
      - /decide/github-mcp-server                                     #6
      - --toolsets
      - all
      - stdio
  1. Precisamos de um GITHUB_PERSONAL_ACCESS_TOKEN Variável de ambiente com um token válido para autenticar no GitHub
  2. Passe todas as variáveis ​​de ambiente para o subprocesso
  3. Defina a porta de escuta
  4. Vincular a qualquer IP
  5. O proxy “se conecta” ao servidor Stdio MCP após o traço
  6. Execute o servidor com todas as opções ativadas

A imagem fornecerá o /sse endpoint na porta 8080.

Codificando a solução

A parte da codificação é a mais fácil. Vá para a documentação Langchain4J no MCP e siga em frente. No projeto, ele se traduz como o seguinte:

bean {
    val transport = HttpMcpTransport.Builder()
        .sseUrl(ref().mcp.url)              //1
        .logRequests(true)                                         //2
        .logResponses(true)                                        //2
        .construct()
    val mcpClient = DefaultMcpClient.Builder()
        .transport(transport)
        .construct()
    mcpClient.listTools().forEach { println(it) }                  //3
    McpToolProvider.builder()
        .mcpClients(listOf(mcpClient))
        .construct()
}
bean {
    coRouter {
        val chatBot = AiServices
            .builder(ChatBot::class.java)
            .streamingChatLanguageModel(ref())
            .chatMemoryProvider { MessageWindowChatMemory.withMaxMessages(40) }
            .contentRetriever(EmbeddingStoreContentRetriever.from(ref>()))
            .toolProvider(ref())                  //4
            .construct()
        POST("/")(PromptHandler(chatBot)::deal with)
    }
}
  1. Eu adicionei um ConfigurationProperty classe para parametrizar o URL SSE
  2. O protocolo MCP fornece uma maneira de enviar logs de volta ao cliente
  3. Não é necessário, mas me ajudou a garantir que o cliente conectado ao servidor e pudesse listar as ferramentas fornecidas
  4. Conecte o provedor de ferramentas MCP criado acima no AiServices

Nesse ponto, o modelo deve encaminhar uma solicitação que corresponda a qualquer uma das ferramentas registradas ao servidor MCP.

curl -N -H 'Content material-Kind: software/json' localhost:8080 -d '{ "sessionId": "1", "textual content": "What are my prime three hottest GitHub repos?" }'

Eu tentei várias vezes e recebi respostas nesse sentido:

Sadly, the offered textual content doesn't include any details about your prime three hottest GitHub repositories. The textual content seems to be a weblog publish or a private web site, and it mentions a few of your initiatives and experiences with GitHub, however it doesn't present any metrics or statistics on the recognition of your repositories.

If you wish to know extra concerning the recognition of your GitHub repositories, I'd advocate trying out GitHub's personal analytics instruments, equivalent to GitHub Insights or the Repository Insights API. These instruments can present details about the variety of followers, stars, and forks for every repository, in addition to different metrics like engagement and exercise.

O modelo apenas ignorou as ferramentas, apesar da documentação reivindicando o contrário.

Corrigindo a solução

Eu li a documentação Langchain4J algumas vezes, mas sem sucesso. Tentei usar o OpenAI e um punhado de outras ferramentas de IA sem sucesso. A maioria das respostas confirmou que deveria funcionar fora da caixa. Alguns mencionaram chamar a ferramenta diretamente, que derrota o objetivo; Um mencionou que o Ollama não suportou ferramentas. Eu verifiquei o weblog Ollama: ele anunciou o suporte da Instruments em 2024. Fiquei preso por quase um dia, imaginando o que fiz de errado.

A arquitetura dissociada apresenta mais peças em movimento. Eu suspeitava que algo poderia estar errado em toda a cadeia de chamadas. Eu removi o proxy do MCP, adicionei o github-mcp-server Diretamente para a imagem do aplicativo e alterou o código de HTTP para STDIO. Não resolveu o problema.

Eu estava prestes a abandonar quando decidi voltar às raízes. Eu copiei-me a amostra da documentação: apenas funcionou! Foi o meu momento ha-ha.

A amostra usa o OpenAI, enquanto eu estava usando Ollama. Eu tentei MCP com o Openai, Mistral AI e Ollama. Somente o modelo OpenAI funciona com o MCP. Enviei o mesmo pedido acima:

curl -N -H 'Content material-Kind: software/json' localhost:8080 -d '{ "sessionId": "1", "textual content": "What are my prime three hottest GitHub repos?" }'

Agora, o OpenAI mapeia corretamente a solicitação para a ferramenta correta e retorna a resposta que eu esperava:

Listed here are my findings relating to your prime three hottest GitHub repositories:

1. **[opentelemetry-tracing](  
   - **Description**: Demo for end-to-end tracing through OpenTelemetry.  
   - **Stars**: 68  
   - **Forks**: 25  
   - **Open Points**: 10  

2. **[kaadin](  
   - **Description**: Kotlin DSL for Vaadin.  
   - **Stars**: 44  
   - **Forks**: 12  
   - **Open Points**: 3  

3. **[jvm-controller](  
   - **Description**: Instance on learn how to write a Kubernetes controller in Java.  
   - **Stars**: 33  
   - **Forks**: 10  
   - **Open Points**: 0  

These repositories show a spread of your pursuits and contributions within the areas of observability, Kotlin growth, and Kubernetes.%    

Como passamos um token de autenticação para o servidor MCP, que o passa para a API do GitHub, o último sabe qual usuário faz a chamada. Portanto, pode interpretar o meus repositórios parte na consulta acima. Admito que é um caso de uso incomum para aplicativos da Net common que atendem a vários usuários, mas usam um único token de autenticação cada. No entanto, ele se encaixa perfeitamente no caso de uso de um aplicativo de desktop.

Outras perguntas regulares, por exemploEncontre os repositórios mais populares no GitHub, são relevantes para os aplicativos da Net, pois não têm contexto implícito – o usuário.

Conclusão

O foco principal desta postagem é a integração de um servidor MCP em um aplicativo Langchain4J. Embora a configuração seja direta graças à documentação, existem algumas advertências.

Primeiro, como o servidor MCP se encaixa em sua arquitetura ainda depende de você. Eu tinha que ser criativo para desviar -se, usando o excelente mcp-proxy. Então, Langchain4J parece ser uma abstração com vazamento. Isso torna tudo o que é possível fornecer uma forte camada de abstração, mas as implementações embaixo que ele protege você não são iguais. Eu gostaria que a documentação o mencionasse, mesmo que eu entenda que a versão atual está na versão beta.

Em suma, foi um passeio divertido. Aprendi sobre o MCP no mundo actual e abriu algumas portas para idéias de projetos.

O código -fonte completo para esta postagem pode ser encontrado no GitHub.

Ir além:


Publicado originalmente em um geek java em 27 de abril de 2025

fonte

DEIXE UMA RESPOSTA

Por favor digite seu comentário!
Por favor, digite seu nome aqui