И снова AI агенты...
AI агент по определению должен делать что-то полезное, делать это с использованием AI, автономно и недетерминировано.
Сейчас я хочу рассмотреть свойство полезности.
AI агент в чем-то похож на умный proxy. Ум обеспечивает LLM (или не обеспечивает, тут идут споры))) ). А далее агент вызывает некую существующую функцию. Или несколько функций.
В терминологии AI это tool:
1) https://python.langchain.com/docs/concepts/tools/
2) https://docs.spring.io/spring-ai/reference/api/tools.html
tool - вообще говоря это просто метод Java, Python или любого другого языка, аннотированый соответствующим образом.
Как агент понимает, что умеет tool? Аннотации с описанием назначения тула, входных и выходных параметров.
Но если подумать - мы же живем в REST мире, в нем победил OpenAPI, а там вся необходимая информация есть. И текстовые описания, и граничные значения, и примеры. Даже адреса серверов на разных средах можно в спеке указать.
Нельзя ли это как-то переиспользовать? DRY все таки!
Можно. https://python.langchain.com/docs/integrations/tools/openapi/ на примере Python
Загружаем спеку, преобразуем в формат, понятный AI и создаем агента:
with open("spotify_openapi.yaml") as f:
raw_spotify_api_spec = yaml.load(f, Loader=yaml.Loader)
spotify_api_spec = reduce_openapi_spec(raw_spotify_api_spec)
...
spotify_agent = planner.create_openapi_agent(
spotify_api_spec,
requests_wrapper,
llm,
allow_dangerous_requests=ALLOW_DANGEROUS_REQUEST,
)
Почему не Java?
https://github.com/langchain4j/langchain4j/issues/1307
Ждем-с.
Что-то делается и для Spring AI, но пока сторонними разработчиками https://readmedium.com/connect-existing-openapis-to-llms-with-spring-ai-039ccabde406
Это самый простой способ вызвать существующий функционал.
Если он не подходит по одной следующих причин:
1) нет готового адаптера OpenAPI
2) нет OpenAPI спецификации, или она сделана криво, а доработка ее другой командой требует времени
3) хочется объединить несколько запросов в один tool или обогатить ответ tool-а локальной информацией
4) нужно убрать лишнее из ответа
то можно вернуться к исходному варианту - написать свой кастомный tool, возвращающий только то, что нужно и документированный так, как нужно.
Ну и третий вариант - отдельный MCP сервер https://t.me/javaKotlinDevOps/376.
У него два плюса:
1) MCP API - это специализированное API, адаптированное для использования LLM
2) tool-ом в виде MCP сервера может в теории воспользоваться любой AI агент
#ai #llm #spring #python
AI агент по определению должен делать что-то полезное, делать это с использованием AI, автономно и недетерминировано.
Сейчас я хочу рассмотреть свойство полезности.
AI агент в чем-то похож на умный proxy. Ум обеспечивает LLM (или не обеспечивает, тут идут споры))) ). А далее агент вызывает некую существующую функцию. Или несколько функций.
В терминологии AI это tool:
1) https://python.langchain.com/docs/concepts/tools/
2) https://docs.spring.io/spring-ai/reference/api/tools.html
tool - вообще говоря это просто метод Java, Python или любого другого языка, аннотированый соответствующим образом.
Как агент понимает, что умеет tool? Аннотации с описанием назначения тула, входных и выходных параметров.
Но если подумать - мы же живем в REST мире, в нем победил OpenAPI, а там вся необходимая информация есть. И текстовые описания, и граничные значения, и примеры. Даже адреса серверов на разных средах можно в спеке указать.
Нельзя ли это как-то переиспользовать? DRY все таки!
Можно. https://python.langchain.com/docs/integrations/tools/openapi/ на примере Python
Загружаем спеку, преобразуем в формат, понятный AI и создаем агента:
with open("spotify_openapi.yaml") as f:
raw_spotify_api_spec = yaml.load(f, Loader=yaml.Loader)
spotify_api_spec = reduce_openapi_spec(raw_spotify_api_spec)
...
spotify_agent = planner.create_openapi_agent(
spotify_api_spec,
requests_wrapper,
llm,
allow_dangerous_requests=ALLOW_DANGEROUS_REQUEST,
)
Почему не Java?
https://github.com/langchain4j/langchain4j/issues/1307
Ждем-с.
Что-то делается и для Spring AI, но пока сторонними разработчиками https://readmedium.com/connect-existing-openapis-to-llms-with-spring-ai-039ccabde406
Это самый простой способ вызвать существующий функционал.
Если он не подходит по одной следующих причин:
1) нет готового адаптера OpenAPI
2) нет OpenAPI спецификации, или она сделана криво, а доработка ее другой командой требует времени
3) хочется объединить несколько запросов в один tool или обогатить ответ tool-а локальной информацией
4) нужно убрать лишнее из ответа
то можно вернуться к исходному варианту - написать свой кастомный tool, возвращающий только то, что нужно и документированный так, как нужно.
Ну и третий вариант - отдельный MCP сервер https://t.me/javaKotlinDevOps/376.
У него два плюса:
1) MCP API - это специализированное API, адаптированное для использования LLM
2) tool-ом в виде MCP сервера может в теории воспользоваться любой AI агент
#ai #llm #spring #python
Langchain
Tools | 🦜️🔗 LangChain
- Chat models
👍1
RestTemplate is dead, baby)))
Spring наконец-то решили задепрекейтить RestTemplate.
Пруф: https://spring.io/blog/2025/09/30/the-state-of-http-clients-in-spring
Его замены в fluent стиле: RestClient для синхронного и WebCLient для асинхронного взаимодействия.
Видимо, команда Spring таки выпилила его из компонентов фреймворка и теперь предлагает это сделать всем остальным)
На самом деле я немного добавил сенсационности в пост.
А реальная хронология событий планируется такая:
- в ноябре этого года (Spring 7.0) будет объявлено о том, что компонент deprecated
- формально deprecated он станет в ноябре 2026 года (Spring 7.1)
- выпилят в Spring 8.0 где-то в 27 году.
Это мир Java == мир обратной совместимости)
#spring #web
Spring наконец-то решили задепрекейтить RestTemplate.
Пруф: https://spring.io/blog/2025/09/30/the-state-of-http-clients-in-spring
Его замены в fluent стиле: RestClient для синхронного и WebCLient для асинхронного взаимодействия.
Видимо, команда Spring таки выпилила его из компонентов фреймворка и теперь предлагает это сделать всем остальным)
На самом деле я немного добавил сенсационности в пост.
А реальная хронология событий планируется такая:
- в ноябре этого года (Spring 7.0) будет объявлено о том, что компонент deprecated
- формально deprecated он станет в ноябре 2026 года (Spring 7.1)
- выпилят в Spring 8.0 где-то в 27 году.
Это мир Java == мир обратной совместимости)
#spring #web
The state of HTTP clients in Spring
Level up your Java code and explore what Spring can do for you.
👍2
Версионирование для REST в Java - оно как бы есть, и его как бы нет)
Основная проблема с версионированием - которую многие, в т.ч. и я, не замечают - следующая.
Версионирование нужно и его почти везде используют, но при этом Spring, который также везде используют, не делает ничего для его поддержки.
Точнее не делал.
Начиная со Spring 7, который уже вышел, данный функционал наконец таки появился: https://habr.com/ru/companies/spring_aio/articles/967454/
Что добавили:
1) определение способа передачи версии:
2) указание версию по умолчанию:
3) указание списка поддерживаемых версий и, соответственно, их валидацию:
или
Естественно, все это можно сделать через код.
4) Стандартный парсер версий - по стандарту семантического версионирования
5) Само собой есть возможность определить нестандартный механизм передачи и формата версий через создание ApiVersionResolver и ApiVersionParser
6) Есть даже ApiVersionDeprecationHandler - стандартизация уведомления клиента об устаревших версиях и автоматическая 400-ка для неподдерживаемых
7) И конечно механизм маршрутизации по версиям, который автоматически разрешает вот такую конструкцию:
8) аналогично для endpoint в функциональном стиле:
9) плюс все поддерживается для reactive stack
10) и на клиенте (для тестовых клиентов тоже):
Еще одна важная фича, которая должна была появиться раньше.
#spring #versioning
Основная проблема с версионированием - которую многие, в т.ч. и я, не замечают - следующая.
Версионирование нужно и его почти везде используют, но при этом Spring, который также везде используют, не делает ничего для его поддержки.
Точнее не делал.
Начиная со Spring 7, который уже вышел, данный функционал наконец таки появился: https://habr.com/ru/companies/spring_aio/articles/967454/
Что добавили:
1) определение способа передачи версии:
# Path segment versioning (e.g., /api/v1/users)
spring.mvc.apiversion.use.path-segment=1
# Request header versioning (e.g., X-API-Version: 1.0)
spring.mvc.apiversion.use.header=X-API-Version
# Query parameter versioning (e.g., ?version=1.0)
spring.mvc.apiversion.use.query-parameter=version
# Media type parameter versioning (e.g., Accept: application/json;version=1.0)
spring.mvc.apiversion.use.media-type-parameter[application/json]=version
2) указание версию по умолчанию:
# Basic versioning configuration
spring.mvc.apiversion.default=1.0
3) указание списка поддерживаемых версий и, соответственно, их валидацию:
spring.mvc.apiversion.supported=1.0,2.0
или
# автоматическое детектирование по содержимому контроллеров
spring.mvc.apiversion.detect-supported = true
Естественно, все это можно сделать через код.
4) Стандартный парсер версий - по стандарту семантического версионирования
5) Само собой есть возможность определить нестандартный механизм передачи и формата версий через создание ApiVersionResolver и ApiVersionParser
6) Есть даже ApiVersionDeprecationHandler - стандартизация уведомления клиента об устаревших версиях и автоматическая 400-ка для неподдерживаемых
7) И конечно механизм маршрутизации по версиям, который автоматически разрешает вот такую конструкцию:
public class AccountController {
@GetMapping
public Account getAccount() {
}
@GetMapping(version = "1.1")
public Account getAccount1_1() {
}
@GetMapping(version = "1.2+")
public Account getAccount1_2() {
}
@GetMapping(version = "1.5")
public Account getAccount1_5() {
}
}8) аналогично для endpoint в функциональном стиле:
RouterFunction<ServerResponse> route = RouterFunctions.route()
.GET("/hello-world", version("1.2"),
request -> ServerResponse.ok().body("Hello World")).build();
9) плюс все поддерживается для reactive stack
10) и на клиенте (для тестовых клиентов тоже):
RestClient client = RestClient.builder()
.baseUrl("http://localhost:8080")
.apiVersionInserter(ApiVersionInserter.useHeader("API-Version"))
.build();
...
Account account = client.get().uri("/accounts/1")
.apiVersion(1.1)
.retrieve()
.body(Account.class);
Еще одна важная фича, которая должна была появиться раньше.
#spring #versioning
Хабр
Нативный API Versioning в Spring 7: долгожданная официальная поддержка
Команда Spring АйО подготовила перевод статьи о том, как Spring Framework 7 приносит нативную поддержку API-версионирования — темы, которая годами оставалась на разработчиках и собирала тонны...