187 판독값

Revisiting LangChain4J 6 Months Later

~에 의해 Nicolas Fränkel11m2025/05/01
Read on Terminal Reader

너무 오래; 읽다

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, I started to dig a bit (나는 약간 씹기 시작했다)주변랭킹4J그것은 빠르게 성장하는 프로젝트이며, 업데이트에 익숙해지고 싶었습니다.나는 또한 LangChain4J에 모델 컨텍스트 프로토콜 서버를 통합하는 방법을 확인하고 싶었습니다.

버전 1 beta

나는 2024 년 11 월에 마지막 포스트를 썼고 당시 사용할 수있는 최신 버전, v0.35을 사용했습니다. LangChain4J는 지난 12 월 1.0로의 여정을 시작했습니다.

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

2024년 9월 25일

035 0 0

12월 22일, 2024

1.0.0 알파1

2월 10일, 2025

1.0 - 베타 1

3월 13일, 2025

1.0.0 베타2

4월 12일, 2025

1.0.0 - 베타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()
)

(
유니콘(
.onBackpressure 버퍼<String>()
chatBot.talk(m.sessionId, m.text)에 대한 정보
.on다음(s::tryEmit다음)
오류(s::tryEmitError)
완전한
( )
시작하기 시작하기 시작하기
◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◎

)

(
유니콘(
.onBackpressure 버퍼<String>()
chatBot.talk(m.sessionId, m.text)에 대한 정보
.onPartial 응답(s::tryEmitNext)
오류(s::tryEmitError)
응답을 완료합니다.
( )
시작하기 시작하기 시작하기
◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◎

)

프로젝트 Reactor Integration

LangChain4J는 Project Reactor 통합을 제공합니다; 나는 이전에 그것을 놓쳤습니다.a lot.

나는 사용하고 있다AiServices, 그래서 이전에 Runtime에서 구현할 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>


우리는 이제 A에서 반환 형식을 변경할 수 있습니다.Flux<String>2 ATokenStream다음은 업데이트된 서명입니다:


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


It makes the creation of the sink위에서 불필요한.우리는 다음과 같이 코드를 단순화 할 수 있습니다:


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


두 일간의 디버깅이 문서를 읽는 데 2 시간을 쉽게 절약 할 수 있다는 것을 기억하십시오!

모델 컨텍스트 프로토콜 서버의 통합

이 부분에서는 <abbr title="Model Context Protocol">MCP</abbr>를 내 LangChain4J 응용 프로그램에 통합하고 싶습니다.

Retrieval-Augmented Generation 부근의 호텔

하나는 많은 자원을 훈련 할 필요가있다 <abbr title="Large Language Model">LLM</abbr> : 그것은 직접 시간과 돈으로 번역.이 때문에 회사는 새로운 모델 버전의 훈련을 제한합니다. 모델의 관련성은 정보가 증가하고 변화함에 따라 시간이 지남에 따라 감소하고, LLM의 데이터베이스는 변하지 않습니다.


Retrieval-Augmented Generation은 2단계의 프로세스이며, 첫 번째 단계에서는 도구가 데이터를 분석하고 LLM에 따라 벡터화하고 벡터 데이터베이스에 저장하며, 두 번째 단계에서는 도구가 LLM을 쿼리할 때 데이터베이스를 추가 데이터로 사용합니다.

모델 컨텍스트 프로토콜

LLM의 정적 성격을 다루는 가장 최근의 방법은 MCP입니다.


MCP는 응용 프로그램이 LLM에 컨텍스트를 제공하는 방법을 표준화하는 오픈 프로토콜입니다.MCP는 AI 응용 프로그램을위한 USB-C 포트와 같습니다.USB-C는 다양한 외부 장치 및 액세서리에 장치를 연결하는 표준화 된 방법을 제공하는 것과 마찬가지로 MCP는 AI 모델을 다른 데이터 소스와 도구에 연결하는 표준화 된 방법을 제공합니다.


-- 모델 컨텍스트 프로토콜을 시작하십시오

MCP는 응용 프로그램이 LLM에 컨텍스트를 제공하는 방법을 표준화하는 오픈 프로토콜입니다.MCP는 AI 응용 프로그램을위한 USB-C 포트와 같습니다.USB-C는 다양한 외부 장치 및 액세서리에 장치를 연결하는 표준화 된 방법을 제공하는 것과 마찬가지로 MCP는 AI 모델을 다른 데이터 소스와 도구에 연결하는 표준화 된 방법을 제공합니다.


- - -모델 컨텍스트 프로토콜(Model Context Protocol)


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 Server-Sent 이벤트

솔루션을 건축하는

위의 이론에 따르면, 우리는 이제 MCP 서버를 선택하여 시작합니다.여기에훌륭한 출발점이었지만, 나는 그걸 선택했다.GitHub MCP 서버왜냐하면 LangChain4J 문서가 그것을 언급하기 때문입니다.


GitHub MCP 서버는스튜디오그것은 우리가 바이너리를 얻고 응용 프로그램에서 시작해야한다는 것을 의미합니다. 그것은 HTTP 전송에 비해 빠르지만, 모델에 HTTP 호출을 포함하는 총 시간과 측면의 계산 시간을 감안할 때, 그것은 중요하지 않습니다.


몇 가지 연구를 한 후, 나는 그것을 발견했다.MCP 프록시프로젝트. 그것은 당신이 stdio에서 HTTP 또는 HTTP에서 stdio 사이를 전환 할 수 있습니다. 그것은 또한 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. 다운로드 the archive
  2. 를 추출
  3. 파일 삭제
  4. Binary Executable 만들기


우리가 정의할 수 없다는 것을 명심하십시오.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. Listening Port 설정
  4. 모든 IP에 연결
  5. 프록시는 dash 후에 stdio MCP 서버에 "연결"합니다.
  6. 모든 옵션을 사용하여 서버를 실행합니다.Run the server with all options enabled


그림은 그를 제공할 것이다/sse포트 8080을 사용합니다.

해결책을 코딩하기

코딩 부분은 가장 쉬운 부분입니다.MCP에 대한 LangChain4J 문서화다음과 같이 번역되며, 프로젝트에서는 다음과 같이 번역됩니다:


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 클래스를 추가하여 SSE URL을 파라미터화했습니다.I added a ConfigurationProperty class to parameterize the SSE URL
  2. MCP 프로토콜은 로그를 클라이언트로 되돌려 보내는 방법을 제공합니다.
  3. 필요하지 않지만 클라이언트가 서버에 연결되어 제공되는 도구를 나열할 수 있도록 도와주었습니다.
  4. AiServices에서 위에서 만든 MCP 도구 공급자에 플러그


이 시점에서 모델은 등록된 도구 중 하나에 일치하는 요청을 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와 몇 가지 다른 AI 도구를 사용하려고 시도했습니다. 대부분의 응답은 그것이 상자 밖에서 작동해야한다는 것을 확인했습니다. 어떤 사람들은 도구를 직접 호출하는 것을 언급했는데, 이는 목적을 이길 수 있습니다. 한 사람은 Ollama가 도구를 지원하지 않았다고 언급했습니다. 나는 Ollama 블로그를 확인했습니다 : 그것은 도구의 지원을 발표했습니다.


분리된 아키텍처는 더 많은 움직이는 조각을 소개합니다.나는 전체 통화 체인에서 뭔가 잘못 될 수 있다고 의심했습니다.I removed the MCP proxy, added thegithub-mcp-server직접 응용 프로그램 이미지로, 그리고 HTTP에서 stdio로 코드를 변경.


내가 뿌리로 돌아가기로 결심했을 때 나는 포기하고 있었다.문서에서 샘플: 그것은 단지 작동했다!그것은 나의 ha-ha 순간이었다.


샘플은 OpenAI를 사용하고 있었지만 Ollama를 사용했습니다. OpenAI, Mistral AI, Ollama와 함께 MCP를 시도했습니다. 오직 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로 전달하기 때문에, GitHub은 어떤 사용자가 호출하는지 알고 있습니다.my repos나는 그것이 여러 사용자를 수용하는 일반적인 웹 응용 프로그램의 특이한 사용 사례라고 인정하지만 각각 하나의 인증 토큰을 사용합니다.


다른 일반적인 질문들,에이즈 GGitHub에서 가장 인기있는 저장소를 찾으십시오, 그들은 암시적인 맥락이 없기 때문에 웹 애플리케이션과 관련이 있습니다.

결론

이 게시물의 주요 초점은 LangChain4J 앱에 MCP 서버를 통합하는 것입니다.The configuration is straightforward thanks to the documentation, there are a few cautions.


첫째, MCP 서버가 귀하의 아키텍처에 어울리는 방법은 여전히 귀하에게 달려 있습니다.I had to be creative to make it disconnected, using the excellentmcp-proxy그런 다음 LangChain4J는 유출 된 추상적 인 것으로 보인다. 그것은 당신에게 강한 추상적 인 레이어를 제공하기 위해 모든 것을 할 수 있지만, 그 아래의 구현은 당신을 방어하지 않습니다.


나는 실제 세계에서 MCP에 대해 배웠고, 그것은 프로젝트 아이디어를위한 꽤 많은 문을 열었습니다.


이 게시물에 대한 전체 소스 코드는 여기에서 찾을 수 있습니다.The complete source code for this post can be found onGithub.


To go further:


  • 모델 컨텍스트 프로토콜(Model Context Protocol)
  • 훌륭한 MCP 서버 및 클라이언트 찾기
  • LangChain4J - 모델 컨텍스트 프로토콜 (MCP)



원래 A Java Geek 에 게시되었습니다 2027년 4월 27일

자바 Geek

Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks