Spring AI чи LangChain4j: налаштування, перший ендпоінт і стиль проєктування
Порівнюємо Spring AI та LangChain4j за архітектурою, стартерами Spring Boot, конфігурацією і першим REST-ендпоінтом для чату та з'ясовуємо, який стиль пасує вашій команді.
Списки можливостей мало що кажуть. Насправді хочеться зрозуміти, як працюється з фреймворком після кількох тижнів розробки, а документація на це не відповідає. Тож уявімо команду, яка починає новий проєкт на Spring Boot і пробує і Spring AI, і LangChain4j. Нижче порівняємо архітектуру, налаштування проєкту, конфігурацію, перший ШІ-ендпоінт і щоденні враження розробника. Обидві бібліотеки розв'язують ту саму задачу, але підходять до неї зовсім по-різному.
Дві архітектурні філософії
Різниця в дизайні визначає майже всі подальші рішення, тож на неї варто подивитися ще до того, як писати код.
Архітектура Spring AI
Spring AI дотримується схеми, яку впізнає кожен, хто писав на Spring Boot.
Spring Boot Application
│
ChatClient API
│
Spring AI Abstractions
│
OpenAI | Gemini | Ollama | Claude | Azure
│
Large Language Model
Фреймворк стоїть між вашим застосунком і ШІ-провайдером. Код не звертається до OpenAI чи Gemini напряму, а працює з абстракціями Spring AI. Це окупається кількома способами. Перехід із Gemini на OpenAI зазвичай не зачіпає бізнес-код: змінюється лише конфігурація. Та сама ідея, що й у Spring Data, де можна змінити базу даних, не переписуючи логіку репозиторіїв.
Чому цей підхід здається знайомим
Тому, хто роками пише застосунки на Spring Boot, структура зрозуміла з першого погляду. У центрі — впровадження залежностей, біни налаштовуються автоматично, а налаштування лежать у application.yml. Відчуття таке, ніби ви опановуєте не ШІ-фреймворк, а ще один стартер Spring, і для корпоративних команд це великий плюс.
Архітектура LangChain4j
LangChain4j мислить інакше. Він не будує все навколо однієї центральної абстракції, а дає набір повторно використовуваних будівельних блоків.
Spring Boot Application
│
AI Service Interface
│
┌──────────┬─────────────┬──────────────┐
│ │ │ │
Chat Model Memory Tools Retriever
│
OpenAI / Gemini / Ollama
До того ж він не ховає ШІ-концепції, а виносить їх назовні. Працювати доведеться безпосередньо ось із такими компонентами:
- чат-моделі та моделі ембедингів
- пам'ять чату
- ШІ-сервіси
- ретривери контенту й провайдери інструментів
Кожен із них має одне зрозуміле завдання, а ви збираєте з них власний ШІ-конвеєр. Спершу це може здаватися зайвою роботою. Та коли застосунок розростається, модульний дизайн починає себе виправдовувати.
Налаштування Spring AI
Почати роботу зі Spring AI можна швидко. Усе як зі Spring Data JPA чи Spring Security: додаєте відповідний стартер.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-gemini</artifactId>
</dependency>
Потім вказуєте API-ключ у конфігурації.
spring:
ai:
vertex:
ai:
gemini:
project-id: your-project
location: us-central1
# OR
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
Далі Spring Boot сам створює потрібні біни. Жодних фабрик, ручного зв'язування й білдерів — усе готове до впровадження залежностей. Для Spring-розробника це виглядає цілком природно.
Налаштування LangChain4j
LangChain4j теж має стартери для Spring Boot, і налаштування відрізняється зовсім трохи.
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
</dependency>
Конфігурація виглядає майже так само.
langchain4j:
open-ai:
chat-model:
api-key: ${OPENAI_API_KEY}
model-name: gpt-4o-mini
І знову Spring Boot створює біни автоматично, тож в наявному проєкті на Spring Boot досвід майже не відрізняється від Spring AI. Але LangChain4j дає ще один варіант: можна взагалі обійтися без стартерів і зібрати все вручну.
ChatLanguageModel model = OpenAiChatModel.builder()
.apiKey(apiKey)
.modelName("gpt-4o-mini")
.build();
Така гнучкість — справжній плюс. У звичайному Java-застосунку чи в Quarkus нічого не змінюється, бо бібліотека не прив'язана до Spring.
Перший ШІ-ендпоінт
Тепер найцікавіше. Зберемо на кожному фреймворку той самий REST-ендпоінт: він приймає запитання і повертає згенеровану відповідь.
Версія на Spring AI
@RestController
@RequestMapping("/chat")
public class ChatController {
private final ChatClient chatClient;
public ChatController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@GetMapping
public String chat(@RequestParam String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
}
Вийшло напрочуд охайно. Fluent API нагадує WebClient зі Spring, і кожен крок читається природно.
prompt()
↓
user()
↓
call()
↓
content()
Хто працював із fluent API у Spring, найпевніше, зрозуміє ідею з першого погляду.
Версія на LangChain4j
@RestController
@RequestMapping("/chat")
public class ChatController {
private final ChatLanguageModel model;
public ChatController(ChatLanguageModel model) {
this.model = model;
}
@GetMapping
public String chat(@RequestParam String message) {
return model.generate(message);
}
}
Тут ще коротше. Замість того щоб збирати промпт через білдер, ви звертаєтеся до мовної моделі напряму. Церемоній менше, і код виглядає майже як виклик звичайного Java-сервісу.
Що простіше?
Розробники часто про це питають, і чесна відповідь така: обидва чудові. Для простого чат-застосунку явного переможця немає. Кожному потрібно лише кілька рядків, обидва вбудовуються в Spring Boot, самі налаштовують залежності й дають чистий, читабельний код.
Різниця не в обсязі коду, а в тому, як розвивається застосунок. Spring AI хоче, щоб усе йшло через ChatClient, і з ростом проєкту навколо цього клієнта з'являються Advisors, пам'ять, виклик інструментів, RAG і спостережуваність.
LangChain4j іде іншим шляхом. Він не нарощує один центральний клієнт, а підштовхує до спеціалізованих ШІ-сервісів, і застосунок зрештою виглядає так:
CustomerSupportAgent
DocumentAssistant
CodeReviewAgent
EmailGenerator
MeetingSummarizer
Кожен із них — окремий Java-інтерфейс із чітко визначеним завданням. Для великих ШІ-застосунків такий підхід дуже елегантний. Але якщо проєкт уже побудовано на звичних сервісних патернах Spring, Spring AI здасться ріднішим. Об'єктивно кращого немає: вони розраховані на різний спосіб мислення.
Чого вчить той самий чат-бот, зібраний двічі
Перший чат-бот на Spring AI пишеться як черговий застосунок на Spring Boot. Сюрпризів мало: усе лежить там, де очікуєш, впровадження залежностей працює як зазвичай, конфігурація лишається в application.yml, і робочий ШІ-ендпоінт можна підняти за годину.
Той самий чат-бот на LangChain4j справляє інше перше враження. Замість інтеграції з API ви починаєте думати про проєктування розумного асистента. Різниця тонка, але вона змінює те, як ви організовуєте код. LangChain4j із першого дня підштовхує виносити промпти, інструменти, пам'ять і пошук у повторно використовувані компоненти, а Spring AI дає змогу додавати ці можливості поступово, в міру розвитку застосунку. Жодна з філософій не хибна. Правильний вибір залежить від того, яке ПЗ ви робите і як ваша команда любить структурувати кодову базу.
Де шляхи справді розходяться
Поки що відмінності невеликі. Справжнє розходження починається, коли ви робите ШІ-функції продакшен-рівня: структурований вивід, виклик інструментів, генерацію з доповненим пошуком (RAG) і агентів. Саме там кожен фреймворк показує свої сильні сторони, і вибір між ними починає важити значно більше.