188 читања

Преглед на LangChain4J 6 месеци подоцна

од страна на Nicolas Fränkel11m2025/05/01
Read on Terminal Reader

Премногу долго; Да чита

Главниот фокус на оваа статија е интеграцијата на MCP серверот во апликацијата LangChain4J. Додека конфигурацијата е едноставна благодарение на документацијата, постојат неколку предупредувања.
featured image - Преглед на LangChain4J 6 месеци подоцна
Nicolas Fränkel HackerNoon profile picture

Минатата година,Почнав да се мачкам малкуоколуСеријал 4JТоа е брзо растечки проект, и сакав да се запознаам со надградбите. исто така, сакав да проверам како да се интегрира сервер за протокол за контекст на модел во LangChain4J.

Бета верзија 1

Јас го напишав мојот последен пост во ноември 2024 година и ја користев најновата верзија достапна во тоа време, 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 септември 2024

35.0 од

22 декември 2024

1.4 Алфа 1

10 февруари, 2025

1.1 Бета 1

13 март, 2025

1.1 Бета 2

12 април, 2025

1.1 Бета 3


LangChain4J следиСемејВо мојот случај, морав да го ажурирам мојот код за да одговорам на промените во API.

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()
)

Вредноста на S = Sinks.many()
Ѓорѓиќ (
.onBackpressureБуфер <String>()
chatBot.talk(m.sessionId, m.text) на сајтот
.onNext(s::tryEmitNext) на веб-страницата
.onError(s::tryЕмитувањеError)
Не е комплетно
Заврши со работа(
Почеток на настанот (
Потврда за прекршување на прекршување на прекршување (
Соодветно на фактот дека (
)

Вредноста на S = Sinks.many()
Ѓорѓиќ (
.onBackpressureБуфер <String>()
chatBot.talk(m.sessionId, m.text) на сајтот
Одговор на прашањето(s::tryEmitNext)
.onError(s::tryЕмитувањеError)
.onCompleteодговор {
Заврши со работа(
Почеток на настанот (
Потврда за прекршување на прекршување на прекршување (
Соодветно на фактот дека (
)

Интеграција на проектни реактори

LangChain4J нуди интеграција на Project Reactor; го пропуштив во моите претходни размислувања.a lot.

Јас користамAiServices, така што претходно го дефинирав интерфејсот за LangChain4J да се имплементира во време на извршување:


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


Треба да се додаде следната зависност:


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


Сега можеме да го смениме типот на враќање одFlux<String>Две аTokenStreamЕве го ажурираниот потпис:


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


Тоа го прави создавањето наsinkПодолу не е потребно.Можеме да го поедноставиме кодот како што следува:


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


Запомнете дека два дена дебагирање лесно може да ви заштеди два часа на читање на документацијата!

Интегрирање на модел на протокол сервер

Во овој дел, сакам да интегрирам <abbr title="Model Context Protocol">MCP</abbr> во мојата LangChain4J апликација.

Повторно зголемена генерација

Потребни се многу ресурси за да се обучи <abbr title="Large Language Model">LLM</abbr>: тоа директно се преведува во време и пари. Поради оваа причина, компаниите го ограничуваат обуката на нови верзии на моделот. Релевантноста на моделот се намалува со текот на времето како информациите се акумулира и се менува, додека базата на податоци на LLM е непроменлива. Покрај тоа, LLMs се обучени на јавни податоци-по природа, додека повеќето компании сакаат да ги прашаат своите приватни податоци исто така.


Во првиот чекор, алатката ги анализира податоците, ги векторизира според LLM и ги складира во векторска база на податоци; во вториот, алатката ја користи базата на податоци како дополнителни податоци при барање на LLM.

Модерен контекст протокол

Најновиот начин да се справи со статичката природа на LLMs е MCP.


MCP е отворен протокол кој стандардизира како апликациите обезбедуваат контекст за LLMs. Размислете за MCP како USB-C порт за апликации за AI. Исто како што USB-C обезбедува стандардизиран начин за поврзување на вашите уреди со различни периферии и додатоци, MCP обезбедува стандардизиран начин за поврзување на моделите на AI со различни извори на податоци и алатки.


Започнете со протоколот Модел контекст

MCP е отворен протокол кој стандардизира како апликациите обезбедуваат контекст за LLMs. Размислете за MCP како USB-C порт за апликации за AI. Исто како што USB-C обезбедува стандардизиран начин за поврзување на вашите уреди со различни периферии и додатоци, MCP обезбедува стандардизиран начин за поврзување на моделите на AI со различни извори на податоци и алатки.


- наЗапочнете со протокол за контекст на моделот


MCP има две предности во однос на 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 дефинира2 Алтернативни начини на транспортЗа комуникација клиент-сервер:


  • stdio: Клиентот лансира подпроцес, а комуникацијата се случува преку стандард во и стандард надвор
  • HTTP со настани за испраќање на сервери

Архитектура на решението

По горенаведената теорија, сега сме подготвени за практичниот дел. Тоа започнува со изборот на MCP сервер.Овде's a good starting point. However, I chose the Официјален GitHub MCP сервербидејќи документацијата LangChain4J го споменува тоа.


GitHub MCP серверот нудиСтадионотТоа значи дека треба да го добиеме бинарниот и да го започнеме од апликацијата. Тоа е брзо во споредба со HTTP транспортот, но со оглед на вкупното време кое го сочинува HTTP повикот на моделот и времето за пресметување на неговата страна, тоа е ирелевантно.


По некои истражувања, најдовмеMCP-прокси софтверПроектот. Тоа ви овозможува да се префрлите помеѓу или од студио на HTTP или од HTTP на студио. Исто така е достапен како слика Docker. Можеме да ги комбинираме и серверот и прокси со следново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
  1. Преземете го архивот
  2. Извадете го
  3. Избришете го архивот
  4. Направете ги бинарните извршни


Забележете дека не можеме да го дефинирамеCMDкако што бинарниот дозволува само конфигурирање на портот и домаќинот со параметри. Поради оваа причина, мораме да ја одложиме командата на време на извршување, или во мојот случај, воdocker-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. Потребна ни е променлива на GITHUB_PERSONAL_ACCESS_TOKEN животната средина со валиден токен за да се автентифицира на GitHub
  2. Пренесете ги сите променливи на животната средина во подпроцесот
  3. Поставете пристаниште за слушање
  4. Поврзете се на било кој IP
  5. Проксиот "се поврзува" со MCP серверот на студиото по дашот
  6. Извршете го серверот со сите опции


Сликата ќе обезбеди/sseПоврзување на портот 8080

Кодирање на решението

Кодирањето е најлесниот дел.LangChain4J документација за MCPи следете понатаму. Во проектот, тоа се преведува како што следува:


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. Додадов класа ConfigurationProperty за параметризирање на URL-то на SSE
  2. MCP протоколот обезбедува начин за испраќање на logs назад до клиентот
  3. Не е неопходно, но ми помогна да се осигурам дека клиентот е поврзан со серверот и може да ги наведе алатките обезбедени
  4. Вклучете го провајдерот на MCP алатки создаден погоре во AiServices


Во овој момент, моделот треба да испрати барање кое одговара на која било од регистрираните алатки до MCP серверот.


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


Се обидов неколку пати, и добив одговори во текот на овие линии:


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.


Моделот едноставно ги игнорираше алатките, и покрај документите кои тврдат спротивно.

Поставување на решението

Прочитав документацијата на LangChain4J неколку пати, но без никаква корист. Се обидов да користам OpenAI и неколку други алатки за вештачка интелигенција без успех. Повеќето од одговорите потврдија дека треба да работи надвор од кутијата. Некои споменаа директно повикување на алатката, што ја победува целта; еден спомена дека Оллама не ги поддржува алатките.


Раздвојувањето на архитектурата воведува повеќе движечки парчиња. Се сомневав дека нешто може да не е во ред во целиот синџир на повици.github-mcp-serverдиректно на сликата на апликацијата, и го промени кодот од HTTP на stdio.


Бев подготвен да се откажам кога решив да се вратам на корените.Пример од документацијатаТоа беше мојот ха-ха момент.


Примерот користи OpenAI, додека јас го користев Ollama. јас се обидов MCP со OpenAI, Mistral AI, и Ollama. Само OpenAI модел работи со MCP. Јас го испратив истото барање како погоре:


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


Сега, OpenAI правилно ја мапира барањето до вистинската алатка и го враќа одговорот што го очекував:


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


Бидејќи го пренесуваме токенот за автентикација на MCP серверот, кој го пренесува на GitHub API, тој знае кој корисник го прави повикот.my reposПризнавам дека тоа е необичен случај на употреба за редовните веб апликации кои се однесуваат на повеќе корисници, но користат еден идентификациски токен секој.


Други редовни прашања,на Г.Најпопуларните репозитории на GitHub се релевантни за веб апликации, бидејќи немаат имплицитен контекст – корисникот.

Заклучок

Главниот фокус на оваа статија е интеграцијата на MCP серверот во апликацијата LangChain4J. Додека конфигурацијата е едноставна благодарение на документацијата, постојат неколку предупредувања.


Прво, како MCP серверот се вклопува во вашата архитектура е сè уште до вас. морав да бидам креативен за да го одвојам, користејќи го одличниотmcp-proxyПотоа, LangChain4J се чини дека е течна апстракција. Тој прави сè што е можно за да ви обезбеди силен слој на апстракција, но имплементациите под него ве штити од не се еднакви.


Научив за MCP во реалниот свет, и тоа отвори неколку врати за проект идеи.


Целосниот изворниот код за оваа статија може да се најде наGitHub.


To go further:


  • Започнете со протокол за контекст на моделот
  • Find Awesome MCP Servers and Clients
  • LangChain4J - Протокол за моделен контекст (MCP)



Првично објавено на A Java Geek на 27 април, 2025

Јава гејк
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!

ВИСЕТЕ ТАГОВИ

ОВОЈ СТАТИЈА БЕШЕ ПРЕТСТАВЕН ВО...

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks