В минулому році,Я почав трохинавколоЛангкайн4JЦе швидкозростаючий проект, і я хотів ознайомитися з оновленнями. я також хотів перевірити, як інтегрувати сервер Model Context Protocol в 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
0,35 0
22 грудня 2024
1.1 Альфа1
10 лютого, 2025
1.0.0 Бета1
13 березня 2025
1.0.0 Бета2
12 квітня, 2025
1.0.0 Бета3
Огляд LangChain4JСемероПідтримувачі скористалися цією можливістю, щоб внести зміни, що порушують API.У моєму випадку мені довелося оновити свій код, щоб врахувати зміни API, що порушують API.
v0.35 |
v1.0.0-beta3 |
---|---|
val s = Sinks.many() |
val s = Sinks.many() |
Валь s = Сінкс.багато()
. унікальний()
.onBackpressureБуфер <String>()
chatBot.talk (m.sessionId, m.text) — розмова
.onNext(s::трейЕмітNext)
.onПомилка(s::tryEmitError)
Повністю не
Скріншоти з посиланням()
}.Початок()
Попередня статтяПопередня статтяПопередня статтяПопередня статтяПопередня статтяПопередня статтяПопередня статтяПопередня статтяПопередня (
з.asFlux().asFlow()
)
Валь s = Сінкс.багато()
. унікальний()
.onBackpressureБуфер <String>()
chatBot.talk (m.sessionId, m.text) — розмова
.onВідповідь(s::tryEmitNext)
.onПомилка(s::tryEmitError)
.onПовний відповідь {
Скріншоти з посиланням()
}.Початок()
Попередня статтяПопередня статтяПопередня статтяПопередня статтяПопередня статтяПопередня статтяПопередня статтяПопередня статтяПопередня (
з.asFlux().asFlow()
)
Інтеграція реактора
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>
2 А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 незмінна.
Retrieval-Augmented Generation є двоступінчим процесом. У першому кроці інструмент аналізує дані, векторує їх відповідно до LLM, і зберігає їх у векторній базі даних; у другому, інструмент використовує базу даних як додаткові дані при запитуванні LLM.
Модель контекстного протоколу
Найновіший спосіб вирішення статичного характеру LLM є MCP.
MCP - це відкритий протокол, який стандартизує те, як програми надають контекст LLM. Подумайте про MCP як про порт USB-C для додатків AI. Так само, як USB-C забезпечує стандартизований спосіб підключення ваших пристроїв до різних периферій та аксесуарів, MCP забезпечує стандартизований спосіб підключення моделей AI до різних джерел даних та інструментів.
Почніть з протоколу Model Context Protocol
MCP - це відкритий протокол, який стандартизує те, як програми надають контекст LLM. Подумайте про MCP як про порт USB-C для додатків AI. Так само, як 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 з серверними подіями
Архітектура рішення
Після вищезазначеної теорії ми тепер готові до практичної частини. вона починається з вибору MCP-сервера.ТутЦе хороший початок, але я вибравОфіційний сервер GitHub MCPПро це йдеться в документації LangChain4J.
GitHub MCP сервер пропонуєСтадіонТранспорт. Це означає, що ми повинні отримати бінарний і почати його з програми. Він швидкий у порівнянні з HTTP-транспортом, але з огляду на загальний час, що складається з HTTP-розмови до моделі та обчислювального часу на його боці, це не має значення.
Після деяких досліджень я знайшовСтворення MCP-proxyПроект. Він дозволяє перемикатися між або від 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
- Завантажити архів
- Витягнути його
- Видалити архів
- Зробіть бінарний екзекутив
Зверніть увагу, що ми не можемо визначити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
- Нам потрібна змінна середовища GITHUB_PERSONAL_ACCESS_TOKEN з дійсним токеном для автентифікації на GitHub
- Передача всіх змінних середовища до підпроцесу
- Налаштуйте порт прослуховування
- Підключення до будь-якого IP
- Проксі "з'єднується" з сервером stdio MCP після
- Запустіть сервер з усіма ввімкненими опціями
Зображення надасть/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)
}
}
- Я додав клас ConfigurationProperty для параметризації URL SSE
- Протокол MCP забезпечує спосіб відправки журналів назад до клієнта
- Не потрібно, але це допомогло мені переконатися, що клієнт підключився до сервера і міг перерахувати надані інструменти
- Підключення до постачальника інструментів 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 та кілька інших інструментів штучного інтелекту без успіху. Більшість відповідей підтвердили, що це повинно працювати поза коробкою. Деякі згадали, що закликають інструмент безпосередньо, що перемагає мету; один згадав, що Ollama не підтримує інструменти.
Відключена архітектура вводить більше рухомих частин. Я підозрював, що щось може бути не так у всьому ланцюжку викликів. Я видалив проксі MCP, додав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, який передає його в API GitHub, останній знає, який користувач робить виклик.my reposЯ визнаю, що це незвичайний випадок використання для звичайних веб-додатків, які обслуговують декількох користувачів, але використовують один токен аутентифікації кожен.
Інші регулярні питання,Е. Дж, знайдіть найпопулярніші сховища на GitHub, які мають відношення до веб-додатків, оскільки вони не мають непрямого контексту – користувача.
Висновок
Основна увага цього повідомлення полягає в інтеграції MCP-сервера в програму LangChain4J. Хоча конфігурація проста завдяки документації, є кілька застережень.
По-перше, як сервер MCP вписується у вашу архітектуру, все ще залежить від вас.mcp-proxy
Тоді LangChain4J, здається, є виточною абстракцією. Він робить все можливе, щоб забезпечити вас сильним шаром абстракції, але реалізації під ним захищають вас від нерівності.
Я дізнався про MCP в реальному світі, і це відкрило кілька дверей для проектних ідей.
Повний вихідний код для цієї статті можна знайти наGitHub.
To go further:
- Почніть з протоколу Model Context Protocol
- Знайдіть чудові MCP-сервери та клієнти
- LangChain4J - протокол модельного контексту (MCP)
Оригінально опубліковано в A Java Geek 27 квітня, 2025
Наприклад, Java Geek