[Перевод] Spring AI: оптимизация разработки AI-приложений с помощью Java и AI API
Во всём мире сейчас наблюдается ажиотаж вокруг темы искусственного интеллекта и разработки приложений с его использованием. Многие стремятся внедрить искусственный интеллект в свои продукты и воспользоваться всеми его преимуществами. Поэтому сообщество Spring создало модуль 'Spring AI' для упрощения интеграции AI API в приложения Spring. Spring AI — это молодой проект, призванный упростить для разработчиков интеграцию функций искусственного интеллекта в приложения Spring. И он достигает этой цели, предлагая набор абстракций и инструментов, которые упрощают взаимодействие с такими ИИ-моделями, как OpenAI и Azure OpenAI.
Spring AI черпает вдохновение в таких Python проектах, как LangChain и LlamaIndex, однако он специально разработан для экосистемы Spring. Это обеспечивает использование знакомых концепций и паттернов Spring, хорошо известных Java-разработчикам, что способствует лёгкому обучению и внедрению.
Необходимые условия:
Базовая осведомлённость о концепциях и терминологии искусственного интеллекта.
Практические навыки работы с Java и Spring Framework.
Рассмотрим несколько концепций, которые используются при работе со Spring AI.
Концепции искусственного интеллекта
Модели — это алгоритмы, предназначенные для обработки и генерирования информации, часто имитирующие когнитивные функции человека. Изучая закономерности и выводы из больших массивов данных, эти модели могут делать предсказания, создавать текст и изображения, улучшая приложения в разных отраслях.
Промпты — это запросы или вводные данные, которые пользователь или программа предоставляют ИИ-модели, чтобы получить от неё желаемый ответ. Промпты направляют вывод ИИ-модели и влияют на его тон, стиль и качество. Промпты могут включать инструкции, вопросы или любой другой тип ввода, в зависимости от предполагаемого использования модели.
Шаблоны промптов: создание эффективных промптов включает в себя определение контекста запроса и замену элементов запроса значениями, соответствующими введённым пользователем данным. В этом процессе используются традиционные текстовые шаблоны для создания и управления промптами. Spring AI использует для этой цели библиотеку OSS StringTemplate. Например: «Переведи следующий английский текст на испанский язык: {text}»
Эмбеддинги: преобразуют текст в числовые массивы или векторы, позволяя ИИ-моделям обрабатывать и интерпретировать языковые данные. Преобразование текста в числа и обратно является ключевой составляющей того, как искусственный интеллект взаимодействует с человеческим языком и понимает его.
Токены: служат строительными блоками для работы ИИ-модели. На входе модели преобразуют слова в токены, на выходе модели преобразуют токены обратно в слова. В контексте платных ИИ-моделей ваши расходы определяются количеством используемых токенов. И ввод, и вывод влияют на общее количество токенов. Кроме того, на модели распространяются лимиты токенов, которые ограничивают объём текста, обрабатываемого за один вызов API. Этот порог часто называют «контекстным окном». Модель не обрабатывает текст, превышающий этот лимит.
Создание ИИ-модели на основе данных
Если общедоступные модели не соответствуют потребностям вашей организации, потребуется настроить или адаптировать модель для работы с данными в соответствии с целями бизнеса.
Есть две широко распространенные концепции внедрения данных в ИИ-модели.
Тонкая настройка: этопроцесс корректировки или адаптации предварительно обученной модели к конкретной задаче или датасету. Вместо того чтобы обучать модель с нуля, тонкая настройка начинается с модели, которая уже была обучена на большом общем датасете. Тонкая настройка очень эффективна при ограниченном количестве помеченных данных для целевой задачи, поскольку предварительно обученная модель уже уловила общие черты, которые могут быть полезны для аналогичных задач.
Тонкая настройка может быть численно дорогой, особенно если предварительно обученная модель велика и требует значительных ресурсов для переобучения.
Промпт Stuffing: это техника, при которой большое количество релевантной информации помещается непосредственно в сам промпт. Этот подход направлен на то, чтобы модель лучше понимала контекст и смогла генерировать более точные и релевантные ответы.
Учитывая ограничения модели по количеству токенов, необходимы методы представления релевантных данных в контекстном окне модели.
Пример реализации с помощью Spring AI
Давайте начнём с примера приложения Spring Boot, которое взаимодействует с моделью Open AI, используя API, предоставляемые Open AI.
Ниже приведены необходимые шаги:
Шаг 1: Создайте приложение Spring Boot с помощью Spring Initializer
Шаг 2: Добавьте в приложение зависимость Open AI.
Поскольку версия Spring AI предварительная, вы не можете добавить её в только что созданный проект с помощью Spring Initializer. Вам нужно явно добавить сборку snapshot, чтобы поэкспериментировать с ним. Ниже приведён пример Gradle-файла, содержащего необходимые зависимости.
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.techmonks'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
maven {
url 'https://repo.spring.io/snapshot'
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter:0.8.0-SNAPSHOT'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
Если вы хотите интегрироваться с Azure Open AI, укажите нижеприведённую зависимость.
implementation 'org.springframework.ai:spring-ai-azure-openai-spring-boot-starter:0.8.0-SNAPSHOT'
Шаг 3: Включите Open AI Key
Добавьте Оpen AI API Key в конфигурацию YML. Создать Оpen AI API Key можно здесь: https://platform.openai.com/api-keys
spring:
ai:
openai:
api-key: {open AI API key goes here}
У нас готовы все необходимые конфигурации. Давайте создадим контроллер для создания REST API.
Шаг 4: Создайте REST-контроллер и инициализируйте ChatClient из Spring AI.
В приведённом ниже примере мы используем шаблон промпта для перевода текста с одного языка на другой с помощью открытых AI API.
Spring AI предоставляет ChatClient, который абстрагирует логику, необходимую для взаимодействия с открытыми API AI. ChatClient — это функциональный интерфейс, который упрощает взаимодействие с ИИ-моделями. Он облегчает подключение к различным ИИ-моделям. В настоящее время интерфейс поддерживает только ввод и вывод текста, но в будущих обновлениях можно ожидать появления дополнительных типов.
package com.techmonks.openai.controller;
import com.techmonks.openai.model.TranslationModel;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.prompt.PromptTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RequiredArgsConstructor
@RestController
@RequestMapping("v1")
public class OpenAiController {
private final ChatClient chatClient;
@PostMapping("translations")
public ResponseEntity translate(@RequestBody TranslationModel translationModel) {
PromptTemplate promptTemplate = new PromptTemplate("""
Translate the following {fromLanguage} text to {toLanguage}: {textToTranslate}""");
promptTemplate.add("fromLanguage", translationModel.getTranslateFrom());
promptTemplate.add("toLanguage", translationModel.getTranslateTo());
promptTemplate.add("textToTranslate", translationModel.getTextToTranslate());
ChatResponse chatResponse = this.chatClient.generate(promptTemplate.create());
return ResponseEntity.ok(chatResponse.getGeneration().getContent());
}
}
Приведённый выше код REST API возвращает ответ в строковом формате. Давайте изменим логику, чтобы возвращать ответ в формате JSON.
package com.techmonks.openai.controller;
import com.techmonks.openai.model.TranslationModel;
import com.techmonks.openai.model.TranslationResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.parser.BeanOutputParser;
import org.springframework.ai.prompt.PromptTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RequiredArgsConstructor
@RestController
@RequestMapping("v1")
public class OpenAiController {
private final ChatClient chatClient;
@PostMapping("translations")
public ResponseEntity translate(@RequestBody TranslationModel translationModel) {
BeanOutputParser beanOutputParser = new BeanOutputParser<>(TranslationResponse.class);
PromptTemplate promptTemplate = new PromptTemplate("""
Translate the following {fromLanguage} text to {toLanguage}: {textToTranslate} {format}""");
promptTemplate.add("fromLanguage", translationModel.getTranslateFrom());
promptTemplate.add("toLanguage", translationModel.getTranslateTo());
promptTemplate.add("textToTranslate", translationModel.getTextToTranslate());
promptTemplate.add("format", beanOutputParser.getFormat());
promptTemplate.setOutputParser(beanOutputParser);
ChatResponse chatResponse = this.chatClient.generate(promptTemplate.create());
return ResponseEntity.ok(beanOutputParser.parse(chatResponse.getGeneration().getContent()));
}
}
Ниже приведён пример коллекции Postman для проверки REST API.
{
"info": {
"_postman_id": "b3f73dc4-7eaf-4065-8b4c-5b28b469d744",
"name": "open-ai",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "3152420",
"_collection_link": "https://releasedashboard.postman.co/workspace/Anji~01fb9b44-0970-46dd-9195-56044a7ead66/collection/3152420-b3f73dc4-7eaf-4065-8b4c-5b28b469d744?action=share&source=collection_link&creator=3152420"
},
"item": [
{
"name": "translate-text",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"translateFrom\":\"English\",\r\n \"translateTo\":\"Hindi\",\r\n \"textToTranslate\":\"Hello, How are you doing today?\"\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/v1/translations",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"v1",
"translations"
]
}
},
"response": []
}
]
}
Весь исходный код лежит на github.
DTO, MapStruct и Spring. Что? Где? Зачем? И как?
На открытом уроке курса «Разработчик на Spring Framework» мы поднимем и разберем такую тему, как паттерн DTO (Data Transfer Object). На примере небольшого приложения на Spring Boot обсудим проблемы, которые решает паттерн, основные сценарии использования, а также инструмент MapStruct, который может помочь сделать данное использование удобным и сократить количество boilerplate кода. Записывайтесь на урок по ссылке.