Головна / Статті / Java як мова для розробки AI-систем у промислових умовах: Spring Boot, RAG та pgvector

Java як мова для розробки AI-систем у промислових умовах: Spring Boot, RAG та pgvector

Практична інструкція зі створення сервісів RAG на JVM за допомогою Spring AI або LangChain4j, вибору сховища векторів, а також керування орендою, витратами, оцінкою та альтернативними рішеннями.

2624 слів

Python використовується для навчання моделей, тоді як Java поступово стає мовою, за допомогою якої їх реалізують у продакшені. Протягом приблизно трьох років сфера ШІ нагадувала конференцію з Python із більшим бюджетом: демонстрації в ноутбуках, навчальні матеріали, які починалися з команди pip install, та діаграми архітектури, де невелика коробочка під назвою „Python LLM service“ знаходилася окремо від справжнього бекенду. Цим справжнім бекендом зазвичай був Spring Boot, який вже керував автентифікацією, обліком коштів, журналами аудиту та базою даних.

Ця невелика коробочка більше не є обов’язковою. Spring AI вже перевищив версію 1.0 та зараз знаходиться на рівні 2.0. LangChain4j — це повноцінна бібліотека для JVM із понад двадцятьма постачальниками моделей та понад тридцятьма сховищами векторів. PostgreSQL зберігає ембеддинги за допомогою модуля pgvector. Сервіс Spring Boot, який ви вже запускаєте, може викликати LLM, отримувати необхідний контекст, використовувати інструменти, передавати токени та публікувати метрики Micrometer — усе це всередині JVM.

Чи робить це Java новим королем ШІ? Не у сенсі звичайних „війн мов“. Ніхто не починає використовувати Java замість PyTorch. Java перемагає там, де знаходяться гроші: у бізнес-додатках, які мають бути точними, прозорими та при цьому максимально простими у використанні. Якщо ви працюєте в цій сфері, переможцем є те, що вже працює у вашому продакшн-кластері, і все частіше це Java.

Решта цієї статті описує цю трансформацію. У ній розглядається, чому це сталося, як виглядає сервіс RAG у Spring Boot, як обрати сховище векторів та які деталі продакшну роблять демо-версію чимось, що можна використовувати з даними клієнтів, та чимось більш надійним.

Перевага Python завжди полягала у дослідженнях

Python залишився основним інструментом для досліджень з вагомих причин, які досі актуальні: NumPy, PyTorch, Hugging Face, Jupyter та ціла генерація інженерів, які володіють навичками роботи з тензорами. Налаштування моделі, тестування нової архітектури ембеддингів чи навчання на GPU все ще відбувається у Python.

Впровадження продукту — це зовсім інша справа. Більшість компаній ніколи не тренують базові моделі. Вони викликають їх, і тоді починається справжня робота: завантаження документів, застосування правил, розділення користувачів, облік запитів, контроль витрат та переконання у тому, що ніхто не вигадає суму для повернення грошей. Це проектування API, доступ до даних, безпека та операції, якими з 2014 року займається Spring Boot.

Популярний швидкий спосіб розміщення моделі за допомогою FastAPI мав постійні витрати:

  • два мовних середовища в одному продукті
  • окремі процеси розгортання
  • окремі системи моніторингу
  • контракт інтерфейсу, який трохи змінювався з кожного спринту
  • перевірки безпеки, які раптово включали Python-сервіс із власними секретами
  • Люди погоджувалися на це через відсутність серйозних інструментів для роботи з LLM у Java. До 2025 року це вже не було правдою. Spring AI 1.0 став загальнодоступним у травні 2025 року, а версія 2.0 з’явилася у червні 2026 року разом із Spring Boot 4. LangChain4j досяг версії 1.0 у той самий період. Тепер стек JVM більше не відстає. Для команд, які вже використовують Spring, це розумний стандарт.

    Що означає „додавання AI“ у додатку на Spring

    Не потрібно переписувати код — достатньо лише трьох функцій.

    1. Шар чату. ChatClient у Spring AI або AiService у LangChain4j перетворюють запит та історію повідомлень на відповідь моделі. Потоковий формат є стандартним, а структурований вихід може зберігатися у Java record, що дозволяє уникнути обробки JSON із тексту за допомогою регулярних виразів.
    2. Доступ до ваших власних даних. Ви обчислюєте ембеддинги та зберігаєте їх у сховищі векторів, тож відповіді походять з ваших правил, рахунків-фактур, посібників та документації до продукту, а не з того, що модель напівпам’ятає. Це і є технологія Retrieval-Augmented Generation (RAG).
    3. Виклики інструментів. Модель може викликати методи Java відповідно до ваших правил авторизації, наприклад для пошуку замовлення, відкриття справи чи перегляду балансу. Тут корисні система типів та існуючі сервіси. Модель не є джерелом істини — вона робить висновки на основі існуючих даних.

    З наявністю Spring Security, Spring Data, Actuator та PostgreSQL це ще один тип клієнта, схожий на ті, що з’явилися з Redis чи Kafka.

    RAG, пояснено для розробника на Java

    Якщо позбутися всієї таємничості, RAG — це потік пошуку, який завершується використанням мовної моделі. Кроки:

    1. Розділити документи на фрагменти.
    2. Перетворити кожен фрагмент на ембеддинг — вектор дійсних чисел, який кодує його зміст.
    3. Зберегти ці вектори разом із метаданими, такими як ідентифікатор користувача, ID документа, вихідний URI та дата запису.
    4. Коли надходить запит, його також перетворюють на ембеддинг та знаходять найближчі фрагменти.
    5. Вставити ці фрагменти до запиту.
    6. Наказати моделі відповісти лише на основі цих фрагментів та визнати, якщо вони не містять відповіді.

    База даних векторів — це не заміна вашій транзакційній базі даних. Це семантичний індекс, щось на кшталт Elasticsearch, але з більш розширеним словниковим запасом.

    Для проектів на Spring Boot зазвичай починають із PostgreSQL разом із pgvector. Postgres вже налаштований, має резервні копії та пулі, тому використання одного розширення коштує дешевше, ніж негайне впровадження Pinecone, Weaviate чи Qdrant. Спеціалізовані двигуни справді мають переваги у випадках екстремального масштабування чи потреби у гібридному пошуку, проте більшість внутрішніх додатків типу RAG залишаються далеко від таких умов.

    Основа для роботи

    У наведеній нижче налаштовці використовується Spring AI 2.0 разом із Boot 4; для версій Boot 3.4 чи 3.5 слід використовувати лінійку 1.1.x. Спочатку встановіть BOM, щоб усі стартові компоненти були на одній версії:

    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>org.springframework.ai</groupId>
          <artifactId>spring-ai-bom</artifactId>
          <version>1.1.8</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
      </dependencies>
    </dependencyManagement>
    

    Далі вкажіть лише ті залежності, які вам потрібні:

    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    

    JDBC вказаний навмисно. Стартовий пакет pgvector працює через JdbcTemplate, і забування про цю залежність є дивовижно поширеною причиною невдачного запуску.

    Налаштування знаходяться у файлі application.yml. Саме в цьому полягає сенс Spring AI: модель має налаштовуватися так само, як джерело даних.

    spring:
      datasource:
        url: jdbc:postgresql://localhost:5432/app
        username: app
        password: ${DB_PASSWORD}
      ai:
        openai:
          api-key: ${OPENAI_API_KEY}
          chat:
            options:
              model: gpt-4o-mini
              temperature: 0.2
          embedding:
            options:
              model: text-embedding-3-small
        vectorstore:
          pgvector:
            initialize-schema: true
            index-type: HNSW
            distance-type: COSINE_DISTANCE
            dimensions: 1536
    

    Два аспекти в цьому файлі мають більше значення, ніж здається. Розмір ембеддингу має дорівнювати значенню, яке генерує модель ембеддингів, а text-embedding-3-small створює 1536. Якщо змінити модель та забути це число, пошук за схожістю буде працювати гірше, хоча помилок не буде. Другий аспект — це низька температура для RAG, адже потрібно, щоб результат наближався до отриманого тексту, а не був творчою переробкою звіту.

    Розглядайте процес вхідних даних як окрему послугу, а не просто однорядкову команду контролера. VectorStore.add(...) приймає фрагменти Document, і кожен фрагмент має містити метадані, за якими ви будете фільтрувати пізніше, такі як tenantId, source, docType та effectiveDate. Без фільтрів семантичний пошук може показати контракт одного клієнта у відповіді іншого клієнта.

    Запитування також є досить простим. QuestionAnswerAdvisor у Spring AI — це заздалегідь визначена версія цього циклу: отримання даних, додавання контексту, виклик моделі. Якщо вам потрібні фільтри, переранжування чи посилання, використовуйте similaritySearch самостійно та розглядайте filterExpression як клозу WHERE, адже саме для цього він і призначений.

    Вибір сховища векторів без догм

    Існує чотири варіанти:

    • Postgres з pgvector. Це розумний стандарт, який добре зрозумілий у практичному застосуванні. За допомогою індексування HNSW, моніторингу точності та компактних блоків він справляється з десятками мільйонів векторів. Однак він не підходить, якщо потрібен розширений гібридний пошук чи команда, яка буде керувати інфраструктурою для апроксимованого пошуку найближчих сусідів.
  • Redis. Швидкий, часто вже присутній у стеках Spring, підходить для зберігання інформації сеансів та невеликих баз знань. Основною проблемою є витрати на оперативну пам’ять.
  • Спеціалізовані двигуни пошуку (Qdrant, Weaviate, Milvus, Pinecone). Вони є доцільними, коли сам продукт полягає у пошуку: великі корпуси даних, гібридні запити на основі лексичних та векторних даних, кілька індексів або коли команда хоче програмне забезпечення, розроблене спеціально для ANN. Spring AI безпосередньо підтримує найпопулярніші з них.
  • Існуючий у вас двигун пошуку. Elasticsearch та OpenSearch підтримують алгоритм kNN, і якщо ваші документи знаходяться там, використання щільного векторного поля може бути кращим рішенням, ніж додавання ще однієї системи зберігання даних.
  • Метод прийняття рішень простий, і саме в цьому його сила. Почніть з pgvector, якщо Postgres вже працює у продакшені. Змініть підхід, коли функції повернення даних, затримка чи гібридний пошук не відповідають реальним критеріям якості, а не тому, що хтось стверджує, ніби серйозні AI-застосунки використовують певний продукт. Також зберігайте посилання на оригінальний запис поруч із кожним вектором, щоб можна було знову його включити при зміні правил.

    Саме цей останній момент ігнорують навчальні матеріали. Моделі для включення даних замінюються, методи розбиття на частини стають більш ефективними, а юридичні документи — оновлюються. Ідемпотентна операція завантаження даних із ключем, заснованим на версії документа, допоможе вам уникнути чверті проблем із з’ясуванням причин, чому бот використовує тарифну схему минулого року.

    Spring AI проти LangChain4j

    Обидва готові до використання у продакшені. Вибір залежить від того, на якому етапі зараз знаходиться ваша команда.

    Spring AI бере знайому ідею Spring щодо портативних абстракцій та застосовує її до моделей. Якщо уявити це як Spring Data для LLM, все здасться природним — автоконфігурація, ChatClient, консультанти, Actuator та Micrometer також вписуються в цю структуру. Використовуйте версію 2.0 з Boot 4. З Boot 3 залишайтеся на версії 1.1.x, оскільки 2.0 не можна просто так встановити.

    LangChain4j спочатку написаний для Java та додає до цього Spring starter. Він підтримує більше постачальників, його типовані AiServices нагадують клієнтів Feign, спрямованих на моделі, і підходить командам, які також використовують Quarkus або звичайний Java. Люди, які хочуть повного контролю над циклом агента, зазвичай обирають саме його.

    Ніщо не заважає вам використовувати обидва рішення. Одним з можливих підходів є використання Spring AI для чату та RAG у сервісі, орієнтованому на клієнтів, при цьому LangChain4j заповнює прогалини для певного постачальника чи шаблону агента. Тримайте їхні компоненти окремо та ніколи не дозволяйте двом різним моделям ембеддингу записувати несумісні вектори в одну таблицю.

    Система, повністю побудована на Spring-Boot та здатна до оновлення до версії 4, має використовувати Spring AI. У змішаному середовищі JVM або у системі, яка вже рік застрягла на версії Boot 3, ймовірно, LangChain4j буде менш залежним від версійних оновлень фреймворку.

    У продакшені JVM має перевагу

    Будь-хто може продемонструвати функціонал рішення. Продукт ж мусить витримати аудит. Ось ті аспекти, які потрібно врахувати:

    • Обмеження та відмови. Обмежте роботу моделі отриманим контекстом та наводьте посилання. Коли показники схожості опускаються нижче певного порогу, відповідь має бути „цього немає в базі знань“, а не припущенням. У сферах фінансів, операцій та охорони здоров’я помилка, висловлена впевнено, коштує дорожче, ніж проста відмова.
    • Аренда та конфіденційність. Фільтруйте вектори за кожним користувачем та усувайте конфіденційну інформацію з запитів. Не включайте номери карток, рахунків та медичні дані до необроблених записів запитів. Якщо для дебаггінгу необхідно їх записати, спочатку токенізуйте їх та зберігайте відповідно до правил зберігання даних вихідної системи.
    • Бюджети на витрати та затримки. Кожен токен коштує грошей, тому фіксуйте кількість вхідних та вихідних токенів, час отримання даних та час роботи моделі. Встановіть ліміт максимальної кількості токенів для кожного запиту, кешуйте ембеддинги документів, які повторюються, та використовуйте меншу модель для класифікації чи маршрутизації, застосовуючи більшу лише у разі необхідності.
  • Таймаути та ізоляція. Виклик моделі — це віддалений ввод-вивід із довгим часом обробки. Обмежені пули потоків, пристрої захисту від збоїв та альтернативні шляхи обробки (пошук за ключовими словами чи черга людей) запобігають тому, щоб збої моделі поглинали всі потоки Tomcat чи Netty, що призводить до затримок у обробці замовлень.
  • Оцінка. Пrompt не можна тестувати як окрему одиницю, як розрахунок податку, але набір з тридцяти запитань із відомими відповідями допомагає виявити проблеми при недостатній числовій точності. Також необхідно перевіряти отримання оцінок у системах типу RAG, з’ясовуючи, чи потрібний фрагмент тексту взагалі потрапив у prompt. Багато проблем, які вважаються пов’язаними з якістю моделі, насправді є помилками у отриманні інформації.
  • Людський огляд. У корпоративному програмному забезпеченні найціннішою функцією ШІ часто є проектний варіант, а не чат-бот: пропозиція примітки до справи, заздалегідь заповнена причина виникнення винятку чи короткий огляд довгої 40-сторінкової звітності. Необхідно залишати людину на етапі схвалення, поки помилки не стануть рідкістю.
  • Усе це — звичайна робота з Spring: обгортання віддаленого виклику, позначення метрики, відхилення неперевірених запитів. LLM є новою залежністю із гіршими умовами SLA, тому її потрібно керувати як такою.

    Де правдива фраза „Java — король“

    Java є кращою відправною точкою, коли система зберігання даних вже працює на JVM, коли функція ШІ мусить ділитися ідентичністю, тенантством та аудитом із існуючими API, коли їй потрібно викликати внутрішні Java-сервіси як інструменти, коли вимоги до конформності не дозволяють використовувати Python, та коли люди, які працюють у ніч на 2 годину, вже знають Spring Boot.

    Python все ще залишається лідером, коли ви тренуєте чи налаштовуєте моделі, коли вам потрібна дослідницька бібліотека вже через тиждень після її випуску, або коли сама модель є продуктом, а не лише однією з функцій у більшій програмі.

    Це окремі завдання, але протягом двох років індустрія поводилась так, ніби вони є одним цілим. У результаті з’явилась купа архітектур із використанням Python-компонентів у супроводі надії на те, що їхні умови залишаться незмінними. Тренд, який виглядає перспективним для 2026 року, є змішаним: Python або хостована лабораторія моделей відповідають за навчання та оцінку, Java виконує функції обслуговування, векторний пошук працює разом із операційними даними, модель надається постачальником, а логіка домену залишається у ваших руках.

    Розумний перший проект

    Не починайте з безмежного корпоративного чат-бота. Виберіть вузьку, цінну нішу контенту та запитання, яке можна оцінити. Ось кілька прикладів, що працюють:

    • Книга інструкцій з питань та відповідей для інженерів, які працюють у режимі 24/7, з посиланням на вихідну сторінку
    • Асистент з політиками, який наводить точну формулювання
    • Питання та відповіді щодо рахунку чи звіту, які користувач щойно завантажив
  • Резюме квитків записуються у запис справи, а не в окремий чат.
  • Розмістіть це за захищеним API, яке ви вже маєте, фіксуйте кожне отримання даних, відображайте посилання у інтерфейсі користувача, додайте функцію вимкнення через налаштування та з’ясуйте вартість за запит перед розширенням корпусу даних. Перший проект навчає розділенню на частини, метаданим, оцінці та контролю змін запитів, і ці навички залишаються корисними, на відміну від бренду фреймворку.

    Середовище виконання, якому ви вже довіряєте

    Фраза „Java — новий король ШІ“ підходить як заголовок, але не є достатньою як теза. Java не виграла у сфері машинного навчання; вона просто ввела застосоване ШІ у платформу, яка вже обробляє світові транзакційні системи.

    Інженеру Spring Boot не потрібен дозвіл когось, щоб працювати тут, ані диплом з науки про дані спочатку. Необхідні лише постачальник моделей, модель ембеддингу, векторний індекс та такий самий рівень операційного обслуговування, як і у випадку з платежами та повідомленнями. Python продовжує тренувати ключові інструменти лабораторії. Java стає лідером на шляху від лабораторії до системи обліку, де потрібні підстави для відповідей, авторизація для викликів інструментів та пояснення до кожного рахунку. Для більшості команд це єдиний „коронний“ приз, який варто мати.

    Якщо ваш сервіс Spring Boot вже контролює ідентичність, гроші та історію аудиту, немає причин чекати на додаткові інструменти. Оберіть цього тижня один вузький набір даних, розмістіть ChatClient перед pgvector та вимагайте посилань на модель у всіх результатах.