187 čitanja

Revisiting LangChain4J 6 Months Later

po Nicolas Fränkel11m2025/05/01
Read on Terminal Reader

Predugo; Čitati

The main focus of this post is the integration of an MCP server in a LangChain4J app. While the configuration is straightforward thanks to the documentation, there are a few caveats.
featured image - Revisiting LangChain4J 6 Months Later
Nicolas Fränkel HackerNoon profile picture

Last year, Počeo sam se maloOkoSljedeći Članak LangChain4JTo je brzo rastući projekt, i želio sam se upoznati s ažuriranjima. također sam želio provjeriti kako integrirati Model Context Protocol server u LangChain4J.

Beta verzija 1

Napisao sam svoj posljednji post u studenom 2024. i koristio najnoviju verziju dostupnu u to vrijeme, 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. rujna 2024

0,35 milijuna

22. prosinca 2024

1.9 alfa1

10. veljače 2025

1.9 Beta1

13. ožujka 2025.

1.9 Beta2

12. travnja 2025

1.9 Beta3


LangChain4J slijedisjemeOdržavatelji su iskoristili priliku da uvedu promjene koje su prekinule.U mom slučaju, morala sam ažurirati svoj kod kako bih odgovorila na promjene API-ja koje su prekinule.

v0.35

v1.0.0-beta3

val s = Sinks.many()
.unicast()
.onBackpressureBuffer<String>()
chatBot.talk(m.sessionId, m.text)
.onNext(s::tryEmitNext)
.onError(s::tryEmitError)
.onComplete {
s.tryEmitComplete()
}.start()
return ServerResponse.ok().bodyAndAwait(
s.asFlux().asFlow()
)

val s = Sinks.many()
.unicast()
.onBackpressureBuffer<String>()
chatBot.talk(m.sessionId, m.text)
.onPartialResponse(s::tryEmitNext)
.onError(s::tryEmitError)
.onCompleteResponse {
s.tryEmitComplete()
}.start()
return ServerResponse.ok().bodyAndAwait(
s.asFlux().asFlow()
)

val s = Sinks.many()
Jednostavno (
.onBackpressureBuffer<String>()
chatBot.talk (m.sessionId, m.text)
.onNasljednje(s::tryEmitNasljednje)
.onError(s::pokušajEmitError)
U cijelosti
Sljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći (
Na početku (
Sljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći (
s.asFlux().asFlow()
)

val s = Sinks.many()
Jednostavno (
.onBackpressureBuffer<String>()
chatBot.talk (m.sessionId, m.text)
.onPartialOdgovor(s::tryEmitNext)
.onError(s::pokušajEmitError)
.onPotpun odgovor {
Sljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći (
Na početku (
Sljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći članakSljedeći (
s.asFlux().asFlow()
)

Projekt integracije reaktora

LangChain4J nudi Project Reactor integraciju; propustio sam je u mojim prethodnim mješavinama.a lot.

Koristim seAiServices, tako da sam prethodno definirao sučelje za LangChain4J za implementaciju u runtime:


interface ChatBot {
    fun talk(@MemoryId sessionId: String, @UserMessage message: String): TokenStream
}


Trebamo dodati sljedeću ovisnost:


<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-reactor</artifactId>
    <version>1.0.0-beta3</version>
</dependency>


Sada možemo promijeniti vrstu povratka iz aFlux<String>Dvije aTokenStreamOvdje je ažurirani potpis:


interface ChatBot {
    fun talk(@MemoryId sessionId: String, @UserMessage message: String): Flux<String>
}


Stvara se stvaranjesinkIznad nepotrebno. možemo pojednostaviti kod kako slijedi:


val flux = chatBot.talk(m.sessionId, m.text)
ServerResponse.ok().bodyAndAwait(flux.asFlow())


Zapamtite da vam dva dana debugiranja lako mogu uštedjeti dva sata čitanja dokumentacije!

Integracija modela kontekstnog protokola

U ovom odjeljku želim integrirati <abbr title="Model Context Protocol">MCP</abbr> u moju aplikaciju LangChain4J.

Povećana generacija

Potrebno je puno i puno resursa za obuku <abbr title="Large Language Model">LLM</abbr>: to se izravno prevodi u vrijeme i novac. Iz tog razloga, tvrtke ograničavaju obuku novih verzija modela. Relevancija modela smanjuje se tijekom vremena kako se informacije nakupljaju i mijenjaju, dok je baza podataka LLM-a nepromjenjiva. Štoviše, LLM-ovi su obučeni na javnim podacima – po prirodi, dok većina tvrtki želi pretraživati i svoje privatne podatke.


Retrieval-Augmented Generation je dvostupanjski proces.U prvom koraku, alat analizira podatke, vektorizira ih prema LLM-u i pohranjuje ih u vektorsku bazu podataka; u drugom, alat koristi bazu podataka kao dodatne podatke prilikom pretraživanja LLM-a.

Kontekstni protokol

Najnoviji način rješavanja statičke prirode LLM-a je MCP.


MCP je otvoren protokol koji standardizira kako aplikacije pružaju kontekst LLM-ima. Misli na MCP kao na USB-C port za AI aplikacije. Baš kao što USB-C pruža standardizirani način povezivanja uređaja s različitim perifernim uređajima i priborom, MCP pruža standardizirani način povezivanja AI modela s različitim izvorima podataka i alatima.


-- Počnite s Modelom kontekstnog protokola

MCP je otvoren protokol koji standardizira kako aplikacije pružaju kontekst LLM-ima. Misli na MCP kao na USB-C port za AI aplikacije. Baš kao što USB-C pruža standardizirani način povezivanja uređaja s različitim perifernim uređajima i priborom, MCP pruža standardizirani način povezivanja AI modela s različitim izvorima podataka i alatima.


-- Počnite s Modelom kontekstnog protokola


MCP ima dvije prednosti u odnosu na 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 definiraDvije alternative prijevozuZa komunikaciju klijenta i poslužitelja:


  • stdio: klijent pokreće podproces, a komunikacija se odvija preko standarda i standarda
  • HTTP s događajima koje šalje poslužitelj

Arhitektura rješenja

Nakon gore navedene teorije, sada smo spremni za praktični dio. započinje odabirom MCP servera.ovdjeTo je dobar početak, ali ja sam odabraoSlužbeni GitHub MCP serverjer je to spomenuto u dokumentaciji LangChain4J.


GitHub MCP server nudiStadijaTo znači da bismo trebali dobiti binarni i započeti ga iz aplikacije. To je brzo u usporedbi s HTTP transportom, ali s obzirom na ukupno vrijeme koje se sastoji od HTTP poziva na model i računanje vrijeme na njegovoj strani, to je irelevantno.


Nakon nekog istraživanja, pronašao sammcp-proxy uređajiProjekt. Omogućuje vam prebacivanje između ili od stdio na HTTP ili od HTTP na stdio. Također je dostupan kao slika Docker. Možemo kombinirati i server i proxy sa sljedećimDockerfile:


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
  1. Preuzmite arhiv
  2. Izvucite ga
  3. Uklonite arhiv
  4. Učinite binarni izvršivim


Imajte na umu da ne možemo definiratiCMDjer binarni samo omogućuje konfiguriranje pristaništa i domaćina s parametrima. iz tog razloga, moramo odgoditi komandu na runtime, ili u mom slučaju, udocker-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
  1. Potrebna nam je GITHUB_PERSONAL_ACCESS_TOKEN promjenjiva okolina s valjanim tokenom za autentifikaciju na GitHub-u
  2. Prenos svih promjenjivih okruženja u podproces
  3. Postavljanje pristaništa za slušanje
  4. Povezivanje na bilo koji IP
  5. Proxy se "povezuje" na stdio MCP server nakon dacha
  6. Pokrenite poslužitelj sa svim mogućim opcijama


Slika će pružiti/sseUgradnja pristaništa 8080.

Kodiranje rješenja

Kodiranje je najjednostavniji dio.LangChain4J dokumentacija o MCP-ui slijedite dalje. u projektu, prevodi se kako slijedi:


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)
    }
}
  1. Dodala sam klasu ConfigurationProperty za parametriziranje URL-a SSE
  2. MCP protokol pruža način slanja dnevnika natrag klijentu
  3. Nije potrebno, ali mi je pomoglo da se pobrinem da je klijent povezan sa poslužiteljem i da može navesti dostupne alate.
  4. Uključite pružatelja alata MCP stvorenog gore u AiServices


U ovom trenutku, model bi trebao proslijediti zahtjev koji odgovara bilo kojem od registriranih alata MCP serveru.


curl -N -H 'Content-Type: application/json' localhost:8080 -d '{ "sessionId": "1", "text": "What are my top three most popular GitHub repos?" }'


Pokušao sam nekoliko puta i dobio sam odgovore u sljedećim redovima:


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.


Model je jednostavno ignorirao alate unatoč dokumentaciji koja tvrdi suprotno.

Ispravljanje rješenja

Pročitao sam dokumentaciju LangChain4J nekoliko puta, ali bez ikakve koristi. Pokušao sam koristiti OpenAI i nekoliko drugih AI alata bez uspjeha. Većina odgovora potvrdila je da bi to trebalo raditi izvan kutije. Neki su spomenuli pozivanje alata izravno, što pobjeđuje svrhu; jedan je spomenuo da Ollama ne podržava alate. Provjerio sam blog Ollama: objavio je podršku alata 2024.


Odvojena arhitektura uvodi više pokretnih dijelova. sumnjala sam da nešto može biti pogrešno u cijelom lancu poziva. uklonila sam MCP proxy, dodalagithub-mcp-serverizravno na sliku aplikacije, a kod je promijenjen s HTTP-a na stdio.


Bio sam na rubu odustajanja kada sam odlučio vratiti se korijenima.Uzorak iz dokumentacijeBio je to moj ha-ha trenutak.


Uzorak koristi OpenAI, dok sam koristio Ollama. Pokušao sam MCP s OpenAI, Mistral AI i Ollama. Samo OpenAI model radi s MCP-om.


curl -N -H 'Content-Type: application/json' localhost:8080 -d '{ "sessionId": "1", "text": "What are my top three most popular GitHub repos?" }'


Sada, OpenAI ispravno preusmjerava zahtjev na ispravan alat i vraća odgovor koji sam očekivao:


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.%    


Budući da prenesemo token za autentifikaciju na MCP server, koji ga prenosi na GitHub API, potonji zna koji korisnik obavlja poziv.my reposPriznajem da je to neobičan slučaj korištenja za redovne web aplikacije koje služe višestrukim korisnicima, ali koriste jedan token za autentifikaciju svaki.


Ostala redovita pitanjae. g, pronađite najpopularnije repozitorije na GitHubu, relevantne su za web aplikacije, jer nemaju implicitni kontekst – korisnika.

Zaključak

Glavni fokus ovog posta je integracija MCP servera u aplikaciju LangChain4J. Dok je konfiguracija jednostavna zahvaljujući dokumentaciji, postoji nekoliko upozorenja.


Prvo, kako se MCP server uklapa u vašu arhitekturu još uvijek je na vama.mcp-proxyZatim, LangChain4J čini se da je ispušna abstrakcija. On čini sve moguće da vam pruži snažan sloj abstrakcije, ali implementacije ispod njega vas štiti od nisu jednaki.


Naučio sam o MCP-u u stvarnom svijetu, a to je otvorilo dosta vrata za projektne ideje.


Cijeli izvorni kod za ovaj članak može se naći naGitHub.


To go further:


  • Počnite s modelom kontekstnog protokola
  • Pronađite nevjerojatne MCP poslužitelje i klijente
  • LangChain4J - Model Kontekstni Protokol (MCP)



Prvotno objavljeno na A Java Geek 27. travnja 2025.

Java geek
L O A D I N G
. . . comments & more!

About Author

Nicolas Fränkel HackerNoon profile picture
Nicolas Fränkel@nfrankel
Dev Advocate | Developer & architect | Love learning and passing on what I learned!

VIJESI OZNAKE

OVAJ ČLANAK JE PREDSTAVLJEN U...

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks