Кембриджский словарь: перевод с английского на русский

Spring перевод

С помощью PROMT.One наслаждайтесь точным переводом текстов любой тематики и сложности с английского на русский, а для слов и фраз смотрите английскую транскрипцию, произношение и варианты переводов с примерами употребления в разных контекстах. Бесплатный онлайн-переводчик PROMT.One — достойная альтернатива другим сервисам, предоставляющим перевод нового поколения с английского на русский и с русского на английский.

AI-ассистент со Spring AI (Часть I)

В новом переводе от команды Spring АйО показан процесс интеграции AI в немалоизвестное приложение Spring Petclinic.

В статье автор пошагово делится своим опытом внедрения Spring AI, чтобы сделать приложение более интерактивным.

Введение

В этой статье из двух частей я расскажу о модификациях, которые я внес в проект Spring Petclinic для интеграции AI-помощника, позволяющего пользователям взаимодействовать с приложением на естественном языке.

Введение в Spring Petclinic

Spring Petclinic служит основным референсным приложением в экосистеме Spring. Согласно GitHub, репозиторий был создан 9 января 2013 года. С тех пор он стал модельным приложением для написания простого, удобного кода с использованием Spring Boot. На момент написания этой статьи он получил более 7 600 звезд и 23 000 форков.

Приложение реализует систему управления ветеринарной клиникой для домашних животных. В приложении пользователи могут выполнять несколько действий:

  • Получение списка владельцев домашних животных
  • Добавление нового владельца
  • Добавление питомца к владельцу
  • Документирование визита для конкретного питомца
  • Получение списка ветеринаров в клинике
  • Симуляция ошибки на стороне сервера

Хотя приложение простое и понятное, оно эффективно демонстрирует удобство использования при разработке приложений Spring Boot.

Кроме того, команда Spring постоянно обновляет приложение для поддержки последних версий Spring Framework и Spring Boot.

Используемые технологии

Spring Petclinic разработан с использованием Spring Boot версии 3.3 на момент этой публикации.

UI фронтенда

Фронтенд построен с использованием Thymeleaf. Шаблонизатор Thymeleaf упрощает интеграцию вызовов API на стороне сервера прямо в HTML-код, делая его понятным. Ниже приведен код, который получает список ветеринаров:

 
Name Specialties
none

Ключевая строка здесь — $ , которая ссылается на модель в бэкенде Spring, содержащую данные для заполнения. Ниже приведен соответствующий блок кода из Spring @Controller , который заполняет эту модель:

private String addPaginationModel(int page, Page paginated, Model model) < ListlistVets = paginated.getContent(); model.addAttribute("currentPage", page); model.addAttribute("totalPages", paginated.getTotalPages()); model.addAttribute("totalItems", paginated.getTotalElements()); model.addAttribute("listVets", listVets); return "vets/vetList"; >

Spring Data JPA

Petclinic взаимодействует с базой данных, используя Java Persistence API (JPA). Проект поддерживает H2, PostgreSQL или MySQL, в зависимости от выбранного профиля. Общение с базой данных осуществляется через интерфейсы @Repository , такие как OwnerRepository. Вот пример одного из JPA-запросов внутри интерфейса:

/** * Returns all the owners from data store **/ @Query("SELECT owner FROM Owner owner") @Transactional(readOnly = true) Page findAll(Pageable pageable);

JPA значительно упрощает ваш код, автоматически реализуя стандартные запросы для ваших методов на основе соглашений об именовании. Он также позволяет вам указать JPQL-запрос с помощью аннотации @Query , когда это необходимо.

Привет, Spring AI

Spring AI — один из самых захватывающих новых проектов в экосистеме Spring за последнее время. Он позволяет взаимодействовать с популярными большими языковыми моделями (LLM), используя знакомые парадигмы и техники Spring. Подобно тому, как Spring Data предоставляет абстракцию, позволяющую вам писать код один раз, делегируя реализацию предоставленному зависимому spring-boot-starter и конфигурации свойств, Spring AI предлагает подобный подход для LLM. Вы пишете свой код один раз в интерфейсе, и @Bean внедряется во время выполнения для вашей конкретной реализации.

Spring AI поддерживает все основные большие языковые модели, включая OpenAI, Azure OpenAI, Google Gemini, Amazon Bedrock и многие другие.

Соображения по реализации AI в Spring Petclinic

Spring Petclinic существует более 10 лет и изначально не был разработан с учетом AI. Этот проект является классическим кандидатом для тестирования интеграции AI в легаси код. В процессе добавления AI-ассистента в Spring Petclinic мне пришлось учесть несколько важных факторов.

Выбор API модели

Первым делом нужно было определить тип API, который я хотел бы реализовать. Spring AI предлагает различные возможности, включая поддержку чата, распознавания и генерации изображений, транскрипции аудио, преобразования текста в речь и многое другое. Для Spring Petclinic наиболее подходящим оказался знакомый интерфейс «чатбота». Это позволит сотрудникам клиники общаться с системой на естественном языке, упрощая их взаимодействие вместо навигации по вкладкам и формам UI. Мне также понадобятся возможности встраивания, которые будут использоваться для Retrieval-Augmented Generation (RAG) позже в статье.

Возможные взаимодействия с AI-помощником могут включать:

  • Чем вы можете мне помочь?
  • Пожалуйста, перечислите владельцев, которые приходят в нашу клинику.
  • Какие ветеринары специализируются на радиологии?
  • Есть ли владелец питомца по имени Бетти?
  • У каких владельцев есть собаки?
  • Добавьте собаку для Бетти: ее зовут Мупси.

Эти примеры иллюстрируют диапазон запросов, с которыми AI может справиться. Преимущество LLM заключается в их способности понимать естественный язык и предоставлять значимые ответы.

Выбор поставщика большой языковой модели

Технический мир сейчас переживает настоящую «золотую лихорадку» с большими языковыми моделями (LLM), которые появляются каждые несколько дней, предлагая расширенные возможности, увеличенные контекстные окна и такие передовые функции, как улучшенная логика рассуждений.

Некоторые из популярных LLM включают:

  • OpenAI и его реализацию на Azure, Azure OpenAI
  • Google Gemini
  • Amazon Bedrock, управляемый сервис AWS, который может запускать различные LLM, включая Anthropic и Titan
  • Llama 3.1, а также многие другие модели с открытым исходным кодом, доступные через Hugging Face

Для пользователей из РФ также могут подойти GigaChat API и Bot hub

Для нашего приложения Petclinic мне нужна была модель, которая отлично справляется с возможностями чата, может быть адаптирована к специфическим потребностям моего приложения и поддерживает вызов функций (об этом позже!).

Одним из больших преимуществ Spring AI является простота проведения A/B-тестирования с различными LLM. Вы просто меняете зависимость и обновляете несколько свойств. Я протестировал несколько моделей, включая Llama 3.1, которую запускал локально. В конечном итоге я пришел к выводу, что OpenAI остается лидером в этой области, поскольку предоставляет наиболее естественные и плавные взаимодействия, избегая общих проблем, с которыми сталкиваются другие LLM.

Вот простой пример: при приветствии модели на базе OpenAI ответ следующий:

Отлично. Именно то, что я хотел. Просто, кратко, профессионально и удобно для пользователя.

Вот результат с использованием Llama 3.1:

Вы поняли суть. Он просто еще не на том уровне.

Установка желаемого поставщика LLM проста — просто установите его зависимость в pom.xml (или build.gradle ) и предоставьте необходимые свойства конфигурации в application.yaml или application.properties :

 org.springframework.ai spring-ai-azure-openai-spring-boot-starter 

Здесь я выбрал реализацию OpenAI от Azure, но я мог бы легко переключиться на OpenAI Сэма Альтмана, изменив зависимость:

 org.springframework.ai spring-ai-openai-spring-boot-starter 

Поскольку я использую общедоступного поставщика LLM, мне нужно предоставить URL и API-ключ для доступа к LLM. Это можно настроить в `application.yaml`:

spring: ai: #These parameters apply when using the spring-ai-azure-openai-spring-boot-starter dependency: azure: openai: api-key: "the-api-key" endpoint: "https://the-url/" chat: options: deployment-name: "gpt-4o" #These parameters apply when using the spring-ai-openai-spring-boot-starter dependency: openai: api-key: "" endpoint: "" chat: options: deployment-name: "gpt-4o"

Приступим к кодированию!

Наша цель — создать чат-клиент в стиле WhatsApp/iMessage, который интегрируется с существующим UI Spring Petclinic. UI фронтенда будет вызывать конечную точку API бэкенда, которая принимает строку в качестве входных данных и возвращает строку. Диалог будет открыт для любых вопросов пользователя, и если мы не сможем помочь с определенным запросом, мы предоставим соответствующий ответ.

Создание ChatClient

Вот реализация эндпоинта чата в классе PetclinicChatClient :

@PostMapping("/chatclient") public String exchange(@RequestBody String query) < //All chatbot messages go through this endpoint and are passed to the LLM return this.chatClient .prompt() .user( u ->u.text(query) ) .call() .content(); >

API принимает строковый запрос и передает его в Spring AI ChatClient в качестве пользовательского текста. ChatClient — это Spring Bean, предоставляемый Spring AI, который управляет отправкой пользовательского текста в LLM и возвращает результаты в content() .

Весь код Spring AI работает в рамках определенного @Profile под названием openai . Дополнительный класс PetclinicDisabledChatClient запускается при использовании профиля по умолчанию или любого другого профиля. Этот отключенный профиль просто возвращает сообщение, указывающее, что чат недоступен.

Наша реализация в основном делегирует ответственность ChatClient . Но как мы создаем сам bean ChatClient ? Существует несколько настраиваемых опций, которые могут повлиять на пользовательский опыт. Давайте рассмотрим их по очереди и изучим их влияние на конечное приложение.

Простой ChatClient

Вот минимальное, неизмененное определение bean ChatClient :

public PetclinicChatClient(ChatClient.Builder builder)

Здесь мы просто запрашиваем экземпляр ChatClient из билдера, основываясь на текущем доступном стартере Spring AI в зависимостях. Хотя такая настройка работает, наш чат-клиент ничего не знает о домене Petclinic или его сервисах:

Он, безусловно, вежлив, но ему не хватает понимания нашего бизнес-домена. Кроме того, кажется, что он страдает от серьезной амнезии — он не может даже вспомнить мое имя из предыдущего сообщения!

Когда я просматривал эту статью, я понял, что не следую совету моего хорошего друга и коллеги Джоша Лонга. Я должен быть более вежливым с нашими новыми AI-властителями!

Возможно, вы привыкли к отличной памяти ChatGPT, что делает его разговорчивым. Однако на самом деле API LLM полностью статичны и не сохраняют никаких прошлых сообщений, которые вы отправляете. Именно поэтому бот забыл мое имя так быстро.

Вы можете задаться вопросом, как ChatGPT сохраняет контекст разговора. Ответ прост: ChatGPT отправляет прошлые сообщения как контент вместе с каждым новым сообщением. Каждый раз, когда вы отправляете новое сообщение, оно включает предыдущие беседы, чтобы модель могла ссылаться на них. Хотя это может показаться расточительным, система работает именно так. Это также причина, по которой большие окна токенов становятся все более важными — пользователи ожидают вернуться к беседам прошлых дней и продолжить с того места, где они остановились.

ChatClient с лучшей памятью

Давайте реализуем подобную функцию «памяти чата» в нашем приложении. К счастью, Spring AI предоставляет для этого Advisor из коробки. Вы можете думать об advisors как о хуках, которые запускаются перед вызовом LLM. Полезно рассматривать их как напоминающие советы в аспекто-ориентированном программировании, даже если они не реализованы таким образом.

Вот наш обновленный код:

 public PetclinicChatClient(ChatClient.Builder builder, ChatMemory chatMemory) < // @formatter:off this.chatClient = builder .defaultAdvisors( // Chat memory helps us keep context when using the chatbot for up to 10 previous messages. new MessageChatMemoryAdvisor(chatMemory, DEFAULT_CHAT_MEMORY_CONVERSATION_ID, 10), // CHAT MEMORY new SimpleLoggerAdvisor() ) .build(); >

В этом обновленном коде мы добавили MessageChatMemoryAdvisor , который автоматически связывает последние 10 сообщений с любым новым исходящим сообщением, помогая LLM понимать контекст.

Мы также включили готовый SimpleLoggerAdvisor , который журналирует запросы и ответы в LLM и из него.

Наш новый чатбот имеет значительно лучшую память!

Однако он все еще не совсем понимает, что мы здесь делаем:

Этот ответ неплох для общей LLM с мировыми знаниями. Однако наша клиника очень специфична для домена, с определенными вариантами использования. Кроме того, наш чатбот должен сосредоточиться исключительно на помощи нам с нашей клиникой.

Например, он не должен пытаться ответить на такой вопрос:

Если мы позволим нашему чатботу отвечать на любые вопросы, пользователи могут начать использовать его в качестве бесплатной альтернативы таким сервисам, как ChatGPT, для доступа к более продвинутым моделям, таким как GPT-4. Очевидно, что нам нужно научить наш LLM «имитировать» конкретного поставщика услуг. Наш LLM должен сосредоточиться исключительно на помощи со Spring Petclinic: он должен знать о ветеринарах, владельцах, питомцах и визитах — и больше ни о чем.

ChatClient, связанный с определенным доменом

Spring AI предлагает решение и для этого. Большинство LLM различают пользовательский текст (сообщения чата, которые мы отправляем) и системный текст, который является общим текстом, инструктирующим LLM функционировать определенным образом. Давайте добавим системный текст в наш чат-клиент:

public PetclinicChatClient(ChatClient.Builder builder, ChatMemory chatMemory) < // @formatter:off this.chatClient = builder .defaultSystem(""" You are a friendly AI assistant designed to help with the management of a veterinarian pet clinic called Spring Petclinic. Your job is to answer questions about the existing veterinarians and to perform actions on the user's behalf, mainly around veterinarians, pet owners, their pets and their owner's visits. You are required to answer an a professional manner. If you don't know the answer, politely tell the user you don't know the answer, then ask the user a followup qusetion to try and clarify the question they are asking. If you do know the answer, provide the answer but do not provide any additional helpful followup questions. When dealing with vets, if the user is unsure about the returned results, explain that there may be additional data that was not returned. Only if the user is asking about the total number of all vets, answer that there are a lot and ask for some additional criteria. For owners, pets or visits - answer the correct data. """) .defaultAdvisors( // Chat memory helps us keep context when using the chatbot for up to 10 previous messages. new MessageChatMemoryAdvisor(chatMemory, DEFAULT_CHAT_MEMORY_CONVERSATION_ID, 10), // CHAT MEMORY new LoggingAdvisor() ) .build(); >

Это довольно объемный системный промпт по умолчанию! Но поверьте мне, это необходимо. На самом деле, это, вероятно, недостаточно, и по мере того, как система используется чаще, мне, вероятно, придется добавлять больше контекста. Процесс инженерии промптов включает в себя разработку и оптимизацию входных промптов, чтобы вызвать конкретные, точные ответы для данного варианта использования.

LLM довольно разговорчивы: они любят отвечать на естественном языке. Эта тенденция может затруднить получение ответов от машины к машине в форматах, таких как JSON. Чтобы решить эту проблему, Spring AI предлагает набор функций, посвященных структурированному выводу, известному как Structured Output Converter. Команда Spring должна была определить оптимальные методы инженерии промптов, чтобы гарантировать, что LLM отвечает без ненужной «разговорчивости». Вот пример из MapOutputConverter в Spring AI:

@Override public String getFormat()

Всякий раз, когда требуется ответ от LLM в формате JSON, Spring AI добавляет эту строку к запросу, призывая LLM соблюдать требования.

В последнее время в этой области произошли положительные сдвиги, особенно с инициативой OpenAI по Structured Outputs (ссылка от редакции Spring АйО: https://openai.com/index/introducing-structured-outputs-in-the-api/) . Как это часто бывает с такими достижениями, Spring AI принял их с энтузиазмом.

Теперь вернемся к нашему чатботу — давайте посмотрим, как он работает!

Это значительное улучшение! Теперь у нас есть чатбот, настроенный на наш домен, сосредоточенный на наших конкретных вариантах использования, запоминающий последние 10 сообщений, не предоставляющий никакой нерелевантной информации извне и избегающий галлюцинаций. Кроме того, наши логи выводят вызовы, которые мы делаем в LLM, что значительно упрощает отладку.

2024-09-21T21:55:08.888+03:00 DEBUG 85824 --- [nio-8080-exec-5] o.s.a.c.c.advisor.SimpleLoggerAdvisor : request: AdvisedRequest[chatModel=org.springframework.ai.azure.openai.AzureOpenAiChatModel@5cdd90c4, userText="Hi! My name is Oded.", systemText=You are a friendly AI assistant designed to help with the management of a veterinarian pet clinic called Spring Petclinic. Your job is to answer questions about the existing veterinarians and to perform actions on the user's behalf, mainly around veterinarians, pet owners, their pets and their owner's visits. You are required to answer an a professional manner. If you don't know the answer, politely tell the user you don't know the answer, then ask the user a followup qusetion to try and clarify the question they are asking. If you do know the answer, provide the answer but do not provide any additional helpful followup questions. When dealing with vets, if the user is unsure about the returned results, explain that there may be additional data that was not returned. Only if the user is asking about the total number of all vets, answer that there are a lot and ask for some additional criteria. For owners, pets or visits - answer the correct data. , chatOptions=org.springframework.ai.azure.openai.AzureOpenAiChatOptions@c4c74d4, media=[], functionNames=[], functionCallbacks=[], messages=[], userParams=<>, systemParams=<>, advisors=[org.springframework.ai.chat.client.advisor.observation.ObservableRequestResponseAdvisor@1e561f7, org.springframework.ai.chat.client.advisor.observation.ObservableRequestResponseAdvisor@79348b22], advisorParams=<>] 2024-09-21T21:55:10.594+03:00 DEBUG 85824 --- [nio-8080-exec-5] o.s.a.c.c.advisor.SimpleLoggerAdvisor : response: ,"violence":,"hate":,"selfHarm":,"profanity":null,"customBlocklists":null,"error":null,"protectedMaterialText":null,"protectedMaterialCode":null>,"finishReason":"stop">,"output":,"toolCalls":[],"content":"Hello, Oded! How can I assist you today at Spring Petclinic?">>,"metadata":,"usage":,"promptMetadata":[,"promptIndex":0>],"empty":false>,"results":[<"metadata":<"contentFilterMetadata":<"sexual":,"violence":,"hate":,"selfHarm":,"profanity":null,"customBlocklists":null,"error":null,"protectedMaterialText":null,"protectedMaterialCode":null>,"finishReason":"stop">,"output":,"toolCalls":[],"content":"Hello, Oded! How can I assist you today at Spring Petclinic?">>]>

Определение основной функциональности

Наш чатбот работает как и планировалось, но в настоящее время ему не хватает знаний о данных в нашем приложении. Давайте сосредоточимся на основных функциях, которые поддерживает Spring Petclinic, и сопоставим их с функциями, которые мы можем включить с помощью Spring AI:

Список владельцев

На вкладке Owners мы можем искать владельца по фамилии или просто вывести список всех владельцев. Мы можем получить подробную информацию о каждом владельце, включая их имя и фамилию, а также их питомцев и их типы:

Добавление владельца

Приложение позволяет добавить нового владельца, предоставив необходимые параметры, продиктованные системой. У владельца должны быть имя, фамилия, адрес и 10-значный номер телефона.

Добавление питомца существующему владельцу

Владелец может иметь нескольких питомцев. Типы питомцев ограничены следующими: кошка, собака, ящерица, змея, птица или хомяк.

Ветеринары

Вкладка Veterinarians (Ветеринары) отображает доступных ветеринаров в виде с пагинацией, вместе с их специализациями. В настоящее время в этой вкладке нет возможности поиска. В то время как в основной ветке main Spring Petclinic представлено несколько ветеринаров, я сгенерировал сотни фиктивных ветеринаров в ветке spring-ai , чтобы симулировать приложение, обрабатывающее значительный объем данных. Позже мы рассмотрим, как мы можем использовать генерацию с дополненным извлечением (RAG) для управления такими большими наборами данных.

Это основные операции, которые мы можем выполнять в системе. Мы сопоставили наше приложение с его базовыми функциями и хотели бы, чтобы OpenAI мог интерпретировать запросы на естественном языке, соответствующие этим операциям.

Вызов функций с помощью Spring AI

В предыдущем разделе мы описали четыре разные функции. Теперь давайте сопоставим их с функциями, которые мы можем использовать в Spring AI, указав определенные бины java.util.function.Function .

Список владельцев

Следующая функция java.util.function.Function отвечает за получение списка владельцев в Spring Petclinic:

@Configuration @Profile("openai") class AIFunctionConfiguration < // The @Description annotation helps the model understand when to call the function @Bean @Description("List the owners that the pet clinic has") public FunctionlistOwners(AIDataProvider petclinicAiProvider) < return request ->< return petclinicAiProvider.getAllOwners(); >; > > record OwnerRequest(Owner owner) < >; record OwnersResponse(List owners) < >;
  • Мы создаем класс @Configuration в профиле openai , где регистрируем стандартный Spring @Bean .
  • Бин должен возвращать java.util.function.Function .
  • Мы используем аннотацию @Description из Spring, чтобы объяснить, что делает эта функция. Примечательно, что Spring AI передаст это описание в LLM, чтобы помочь ему определить, когда вызывать эту конкретную функцию.
  • Функция принимает запись OwnerRequest , которая содержит существующий класс сущности Owner из Spring Petclinic. Это демонстрирует, как Spring AI может использовать компоненты, которые вы уже разработали в своем приложении, без необходимости полного переписывания. Комментарий от команды Spring АйО: для данного запроса не требуется Owner. Автор привел в пример функцию, которой фактически не нужны аргументы.
  • OpenAI решит, когда вызвать функцию с JSON-объектом, представляющим запись OwnerRequest . Spring AI автоматически конвертирует этот JSON в объект OwnerRequest и выполнит функцию. После получения ответа Spring AI конвертирует полученную запись OwnerResponse (которая содержит List ) обратно в формат JSON для обработки OpenAI. Когда OpenAI получит ответ, он сформирует ответ для пользователя на естественном языке.
  • Функция вызывает бин AIDataProvider с аннотацией @Service , который реализует фактическую логику. В нашем простом случае использования функция просто запрашивает данные с помощью JPA:
 public OwnersResponse getAllOwners() < Pageable pageable = PageRequest.of(0, 100); PageownerPage = ownerRepository.findAll(pageable); return new OwnersResponse(ownerPage.getContent()); >
  • Существующий легаси код Spring Petclinic возвращает данные с пагинацией, чтобы размер ответа оставался управляемым и облегчал обработку для представления с пагинацией в UI. В нашем случае мы ожидаем, что общее количество владельцев будет относительно небольшим, и OpenAI сможет обработать такой трафик в одном запросе. Поэтому мы возвращаем первые 100 владельцев в одном запросе JPA. Вы можете подумать, что этот подход не оптимален, и для реального приложения вы были бы правы. Если бы было большое количество данных, этот метод был бы неэффективен — вероятно, у нас было бы больше 100 владельцев в системе. Для таких сценариев нам нужно было бы реализовать другой шаблон, который мы рассмотрим в функции listVets . Однако для нашего демонстрационного варианта использования мы предположим, что в нашей системе содержится менее 100 владельцев.

Давайте воспроизведем настоящий пример вместе с SimpleLoggerAdvisor , чтобы посмотреть, что происходит «за кулисами»:

Что здесь произошло? Давайте рассмотрим вывод из лога SimpleLoggerAdvisor для исследования:

request: AdvisedRequest[chatModel=org.springframework.ai.azure.openai.AzureOpenAiChatModel@18e69455, userText= "List the owners that are called Betty.", systemText=You are a friendly AI assistant designed to help with the management of a veterinarian pet clinic called Spring Petclinic. Your job. chatOptions=org.springframework.ai.azure.openai.AzureOpenAiChatOptions@3d6f2674, media=[], functionNames=[], functionCallbacks=[], messages=[UserMessage, messageType=USER>, AssistantMessage [messageType=ASSISTANT, toolCalls=[], textContent=Hello! How can I assist you today at Spring Petclinic?, metadata=]], userParams=<>, systemParams=<>, advisors=[org.springframework.ai.chat.client.advisor.observation.ObservableRequestResponseAdvisor@1d04fb8f, org.springframework.ai.chat.client.advisor.observation.ObservableRequestResponseAdvisor@2fab47ce], advisorParams=<>]

Запрос содержит интересные нам данные о том, что отправляется в LLM, включая пользовательский текст, исторические сообщения, идентификатор, представляющий текущую сессию чата, список советников для запуска и системный текст.

Вы можете задаться вопросом, где функции в зафиксированном выше запросе. Функции не явно зафиксированы, они инкапсулированы в содержимом AzureOpenAiChatOptions . Изучение объекта в режиме отладки раскрывает список функций, доступных модели:

OpenAI обработает запрос, определит, что ему нужны данные из списка владельцев, и вернет JSON-ответ в Spring AI, запрашивая дополнительную информацию из функции listOwners . Затем Spring AI вызовет эту функцию, используя предоставленный объект OwnersRequest от OpenAI, и отправит ответ обратно в OpenAI, поддерживая идентификатор беседы для помощи в непрерывности сессии через статическое соединение. OpenAI сгенерирует окончательный ответ на основе предоставленных дополнительных данных. Давайте рассмотрим этот ответ, как он представлен в логе:

response: < "result": < "metadata": < "finishReason": "stop", "contentFilterMetadata": < "sexual": < "severity": "safe", "filtered": false >, "violence": < "severity": "safe", "filtered": false >, "hate": < "severity": "safe", "filtered": false >, "selfHarm": < "severity": "safe", "filtered": false >, "profanity": null, "customBlocklists": null, "error": null, "protectedMaterialText": null, "protectedMaterialCode": null > >, "output": < "messageType": "ASSISTANT", "metadata": < "choiceIndex": 0, "finishReason": "stop", "id": "chatcmpl-A9oKTs6162OTut1rkSKPH1hE2R08Y", "messageType": "ASSISTANT" >, "toolCalls": [], "content": "The owner named Betty in our records is:nn- **Betty Davis**n - **Address:** 638 Cardinal Ave., Sun Prairien - **Telephone:** 608-555-1749n - **Pet:** Basil (Hamster), born on 2012-08-06nnIf you need any more details or further assistance, please let me know!" > >, . ] >

Мы видим сам ответ в разделе content . Большая часть возвращенного JSON состоит из метаданных — таких как фильтры контента, используемая модель, идентификатор сессии чата в ответе, количество задействованных токенов, как завершился ответ и многое другое.

Это иллюстрирует, как система работает от начала до конца: она начинается в вашем браузере, достигает бэкенда Spring и включает взаимодействие типа B2B между Spring AI и LLM, пока ответ не будет отправлен обратно в JavaScript, который сынициировал вызов.

Теперь давайте рассмотрим оставшиеся три функции.

Добавление питомца владельцу

Метод addPetToOwner особенно интересен, потому что демонстрирует мощь вызова функций модели.

Когда пользователь хочет добавить питомца владельцу, не стоит ожидать, что он введет идентификатор типа питомца. Вместо этого они, скорее всего, скажут, что питомец — это «собака», а не просто предоставят числовой идентификатор, например «2».

Чтобы помочь LLM определить правильный тип питомца, я использовал аннотацию @Description , чтобы предоставить подсказки о наших требованиях. Поскольку наша ветеринарная клиника работает только с шестью типами питомцев, такой подход управляем и эффективен:

@Bean @Description("Add a pet with the specified petTypeId, " + "to an owner identified by the ownerId. " + "The allowed Pet types IDs are only: " + "1 - cat" + "2 - dog" + "3 - lizard" + "4 - snake" + "5 - bird" + "6 - hamster") public Function addPetToOwner(AIDataProvider petclinicAiProvider) < return request ->< return petclinicAiProvider.addPetToOwner(request); >; >

Запись AddPetRequest включает тип питомца в свободном тексте, отражая, как пользователь обычно предоставляет его, вместе с полной сущностью Pet и ссылочным ownerId .

record AddPetRequest(Pet pet, String petType, Integer ownerId) < >; record AddedPetResponse(Owner owner) < >;

Вот бизнес-реализация: мы получаем владельца по его ID, затем добавляем нового питомца к его существующему списку питомцев.

public AddedPetResponse addPetToOwner(AddPetRequest request)

При дебаге приложения для этого кейса я заметил интересное поведение: в некоторых случаях сущность Pet в запросе уже была предварительно заполнена правильным идентификатором типа питомца и именем.

Я также заметил, что на самом деле не использовал строку petType в своей бизнес-реализации. Возможно ли, что Spring AI просто «понял» правильное соответствие имени PetType правильному идентификатору самостоятельно?

Чтобы проверить это, я удалил petType из объекта запроса и упростил @Description :

@Bean @Description("Add a pet with the specified petTypeId, to an owner identified by the ownerId.") public Function addPetToOwner(AIDataProvider petclinicAiProvider) < return request ->< return petclinicAiProvider.addPetToOwner(request); >; > record AddPetRequest(Pet pet, Integer ownerId) < >; record AddedPetResponse(Owner owner) < >;

Я обнаружил, что в большинстве промптов LLM сам понял (что удивительно), как выполнить сопоставление. В конце концов, я сохранил оригинальное описание в PR, потому что заметил некоторые крайние случаи, когда LLM испытывал трудности и не мог сопоставить корреляцию.

Тем не менее, даже для 80% случаев использования это было очень впечатляюще. Такие вещи делают Spring AI и LLM почти волшебными. Взаимодействие между Spring AI и OpenAI помогло понять, что PetType в аннотации @Entity класса Pet нуждается в сопоставлении строки «lizard» с соответствующим значением ID в базе данных. Такой бесшовный интеграционный подход демонстрирует потенциал сочетания традиционного программирования с возможностями AI.

// Это оригинанальные insert`ы в data.sql INSERT INTO types VALUES (default, 'cat'); //1 INSERT INTO types VALUES (default, 'dog'); //2 INSERT INTO types VALUES (default, 'lizard'); //3 INSERT INTO types VALUES (default, 'snake'); //4 INSERT INTO types VALUES (default, 'bird'); //5 INSERT INTO types VALUES (default, 'hamster'); //6
@Entity @Table(name = "pets") public class Pet extends NamedEntity < private static final long serialVersionUID = 622048308893169889L; @Column(name = "birth_date") @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate birthDate; @ManyToOne @JoinColumn(name = "type_id") private PetType type; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinColumn(name = "pet_id") @OrderBy("visit_date ASC") private Setvisits = new LinkedHashSet<>();

Это работает, даже если вы делаете опечатки в запросе. В примере ниже LLM идентифицировал, что я написал «hamstr» вместо «hamster», исправил запрос и успешно сопоставил его с правильным идентификатором питомца:

Если вы углубитесь, вы найдете еще более впечатляющие вещи. AddPetRequest передает только ownerId в качестве параметра: я предоставил имя владельца вместо его ID, и LLM смог самостоятельно определить правильное соответствие. Это указывает на то, что LLM решил вызвать функцию listOwners перед вызовом функции addPetToOwner . Добавив несколько точек останова, мы можем подтвердить это поведение. Сначала мы попадаем на точку останова для получения владельцев:

Только после того, как данные владельца возвращены и обработаны, мы вызываем функцию addPetToOwner :

Мой вывод таков: с Spring AI начинайте с простого. Предоставьте основные данные, которые вы знаете, что они потребуются, и используйте короткие, лаконичные описания бинов. Вероятно, Spring AI и LLM «вычислят» остальное. Только когда возникнут проблемы, вы должны начать добавлять больше подсказок в систему.

Добавление владельца

Функция addOwner относительно проста. Она принимает владельца и добавляет его в систему. Однако в этом примере мы можем увидеть, как выполнять валидацию и задавать последующие вопросы с помощью нашего чат-помощника:

@Bean @Description("Add a new pet owner to the pet clinic. " + "The Owner must include first and last name, " + "an address and a 10-digit phone number") public Function addOwnerToPetclinic(AIDataProvider petclinicAiDataProvider) < return request ->< return petclinicAiDataProvider.addOwnerToPetclinic(request); >; > record OwnerRequest(Owner owner) < >; record OwnerResponse(Owner owner) < >;
public OwnerResponse addOwnerToPetclinic(OwnerRequest ownerRequest)

Здесь мы направляем модель, чтобы убедиться, что Owner внутри OwnerRequest соответствует определенным критериям валидации перед тем, как он будет добавлен. В частности, владелец должен включать имя, фамилию, адрес и 10-значный номер телефона. Если какая-либо из этой информации отсутствует, модель предложит нам предоставить необходимые детали перед продолжением добавления владельца.

Модель не создала нового владельца до запроса необходимых дополнительных данных, таких как адрес, город и номер телефона. Однако я не помню, чтобы предоставил требуемую фамилию. Будет ли это работать?

Мы выявили крайний случай в модели: она, кажется, не соблюдает требование о фамилии, даже несмотря на то, что @Description указывает, что это обязательно. Как мы можем решить эту проблему? На помощь приходит инженерия промптов!

@Bean @Description("Add a new pet owner to the pet clinic. " + "The Owner must include a first name and a last name as two separate words, " + "plus an address and a 10-digit phone number") public Function addOwnerToPetclinic(AIDataProvider petclinicAiDataProvider) < return request ->< return petclinicAiDataProvider.addOwnerToPetclinic(request); >; >

Добавив подсказку «как два отдельных слова» в наше описание, модель получила ясность о наших ожиданиях, что позволило ей правильно обеспечить требование о фамилии.

Следующие шаги

В первой части этой статьи мы рассмотрели, как использовать Spring AI для работы с большими языковыми моделями. Мы создали кастомный ChatClient, применили вызов функций и улучшили процесс формирования запросов для наших конкретных нужд.

Во второй части мы углубимся в возможности Retrieval-Augmented Generation (RAG), чтобы интегрировать модель с большими специализированными наборами данных, которые слишком объемны для подхода с вызовом функций.

Присоединяйтесь к русскоязычному сообществу разработчиков на Spring Boot в телеграм — Spring АйО, чтобы быть в курсе последних новостей из мира разработки на Spring Boot и всего, что с ним связано.

Основные характеристики

Английский словарь основан на оригинальном исследовании уникального Cambridge English Corpus и включает все слова уровней A1–C2 (CEFR) из English Vocabulary Profile. Он идеален для всех, кто готовится к Кембриджским экзаменам продвинутого уровня или IELTS.

Получение простых и ясных определений из британских, американских и бизнес-словарей посредством одного запроса!

Прослушивание слов, произносимых на британском и американском английском
Тысячи практических примеров, показывающих, как используются слова.
Справочные слова приведут Вас к точному значению, которое Вы ищете.
Smart Vocabulary поможет расширить ваш словарный запас благодаря родственным словам и фразам

Идеален для изучающих английский язык от среднего до продвинутого уровней (уровни A2–C2, классификация CEFR).

Основан на Cambridge English Corpus — база данных, содержащая более 2 миллиардов слов

Выражение признательности

Главный редактор
Stella O’Shea

Редакторы
Natalia Uvarova

October 02, 2024

to be very surprised

October 07, 2024
Cambridge Dictionary +Plus

Бесплатно создавайте, скачивайте и делитесь своими списками слов и викторинами!

Перейти к + Plus или Войти в систему

Вы вошли в систему. Начните создавать список слов или пройдите викторину!

© Cambridge University Press & Assessment 2024

Изучать
Программировать
О проекте

© Cambridge University Press & Assessment 2024

Cambridge Dictionary +Plus
Зарегистрируйтесь бесплатно и получите доступ к эксклюзивному контенту:
Бесплатные Кембриджские списки слов и викторины
Инструменты для создания списков слов и викторин
Списки слов, созданные пользователями словаря
Зарегистрироваться или Войти
Cambridge Dictionary +Plus
Создавайте списки слов и викторины бесплатно
Зарегистрироваться или Войти

  • Cambridge Dictionary +Plus
  • Мой профиль
  • +Plus помощь
  • Выйти

Русский Change
Подписывайтесь на нас
Выбрать словарь

  • Недавнее и рекомендуемое

Четкие объяснения реального письменного и устного английского языка
английский словарь для учащихся основной британский английский основной американский английский
Объяснения использования реального письменного и устного английского языка
грамматика тезаурус
British and American pronunciations with audio
English Pronunciation
Нажмите на стрелки, чтобы изменить направление перевода
Двуязычные словари

  • англо-китайский (упрощенный) Chinese (Simplified)–English
  • англо-китайский (традиционный) Chinese (Traditional)–English
  • англо-голландский нидерландско-английский
  • англо-французский франко-английский
  • англо-немецкий немецко-английский
  • англо-индонезийский индонезийско-английский
  • англо-итальянский итальянско-английский
  • англо-японский японско-английский
  • англо-норвежский норвежско-английский
  • англо-польский польско-английский
  • англо-португальский португальско-английский
  • англо-испанский испанско-английский
  • English–Swedish Swedish–English

Толково-переводные словари

англо-арабский англо-бенгальский англо-каталонский англо-чешский англо-датский English–Gujarati английский-хинди англо-корейский англо-малайский англо-маратхи англо-русский English–Tamil English–Telugu англо-тайский англо-турецкий английский-украинский English–Urdu англо-вьетнамский

«spring&amp» в словаре английский — русский

В настоящее время у нас нет переводов для spring&amp в словаре, может быть, вы можете добавить его? Обязательно проверьте автоматический перевод, память переводов или косвенные переводы.

Склонение Основа

It was hard to believe they were only a couple of miles from the edge of town, so still and dark was the spring evening.

Трудно было поверить, что они всего лишь в паре миль от города, до того тихо и темно было в этот весенний вечер.

Literature

Further training courses were planned for the West African region in December 2005 and for the Latin American and Caribbean region in the spring of 2006.

Кроме того, планируется провести учебные курсы для стран региона Западной Африки в декабре 2005 года и для стран региона Латинской Америки и Карибского бассейна весной 2006 года.

The prophecy regarding the destruction of Jerusalem clearly portrays Jehovah as a God who ‘causes his people to know new things before they begin to spring up.’ —Isaiah 42:9.

Пророчество о разрушении Иерусалима ясно показывает, что Иегова — это Бог, который возвещает своему народу новое, «прежде нежели оно произойдет» (Исаия 42:9).

jw2019
It was a lovely spring day, splashed with sunshine, filled with the scent of budding lilacs.

Стоял чудесный весенний день, залитый солнечным светом и наполненный благоуханием распускающихся лилий.

Literature
That’ s in spring!
Но это же весной
opensubtitles2
It was a false spring day, which, like Maureen, had pierced the shell of a deadening winter.

Этот день был похож на весенний — он, как и Морин, приоткрыл нам окошко в тепло среди мертвящей зимы.

Literature

The humanitarian crisis in the Horn of Africa, ecological disasters such as Fukushima, political developments like the Arab Spring and terrorist attacks such as the assault on the United Nations building in Abuja last August require concerted action by the United Nations and its Member States.

Гуманитарный кризис на Африканском Роге, экологические катастрофы, такие как Фукусимская, политические события, такие как «арабская весна», и террористические акты, как, например, нападение в августе на здание Организации Объединенных Наций в Абудже, — все это требует согласованных действий со стороны Организации Объединенных Наций и ее государств-членов.

Бот-переводчик

Placeholder
Николай Л. 4 декабря 2021 г.

Самый лучший сайт среди подобных. Пользуюсь только функцией «спряжение» (не один месяц), и она очень хорошо сделала — удобно очень. Самое лучшее — на опечатки внимания вообще не обращает.

Placeholder
Шамиль С. 3 ноября 2020 г.

С моим домашним заданием по фр. языку очень помогает! Сказали что можно в словаре смотреть, искала и вот нашла самый хороший сайт. Всё кратко — и род, и перевод. Короче, сайт ну суперский.

Placeholder
Termi0n 7 мая 2021 г.

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

Placeholder
A.N.G. 29 июля 2020 г.

По ряду текстов лучший переводчик технических текстов онлайн (более здравый, чем яндекс или гугл). Я всё же предпочитаю использовать все три основных переводчика, выбирая то, что лучше подходит

Placeholder
Irina T. 15 августа 2020 г.

Пользуюсь постоянно, проверяю грамматику, довольна. Удобно, четко с примерами, так что можно проверить то слово использовано или нет. Вариантов дается много.

Посмотреть в словаре основного американского английского

Посмотреть в буквенном указателе Cambridge Dictionary

Кембриджский словарь основного американского английского основан на оригинальном исследовании уникального Cambridge English Corpus и включает все слова уровней A1–В2 (CEFR) из English Vocabulary Profile.

Источники:

https://habr.com/ru/companies/spring_aio/articles/848016/&rut=fabc139be28ab117bb72cd477d4b4f7227902c9f30e1c7b72ad75677b85426e2
https://dictionary.cambridge.org/ru/%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D1%8C/%D0%B0%D0%BD%D0%B3%D0%BB%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9/spring&rut=502c7faeacd9ff334a9de2f15fce946415ae8bbf3ac2653a03c324b9bf42ec7f
https://dictionary.cambridge.org/ru/%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D1%8C/%D0%B0%D0%BD%D0%B3%D0%BB%D0%BE-%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9/spring&rut=53835d5c5f382324318f9fee67dcc372dced674009e2a352cb2c8d1db49e413b
https://ru.glosbe.com/%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D1%8C-%D0%B0%D0%BD%D0%B3%D0%BB%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9-%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9/spring&rut=5773bd49f18ca76a931cfd9dd9cb8f8526d5aabb85fe6c732faece2f9e195558
https://www.translate.ru/%D0%BF%D0%B5%D1%80%D0%B5%D0%B2%D0%BE%D0%B4/%D0%B0%D0%BD%D0%B3%D0%BB%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9-%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9/spring&rut=35a1d56d57020472b8f93c7aed82a88036e24aead5c1ca31da678f6593fed22c
https://dictionary.cambridge.org/ru/%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D1%80%D1%8C/%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D0%BE%D0%B9-%D0%B0%D0%BC%D0%B5%D1%80%D0%B8%D0%BA%D0%B0%D0%BD%D1%81%D0%BA%D0%B8%D0%B9-%D0%B0%D0%BD%D0%B3%D0%BB%D0%B8%D0%B9%D1%81%D0%BA%D0%B8%D0%B9/spring&rut=ab0262682edca655e793e83e17e0ac0f3618bf28540bd367837c6f73093524d9