Команда Spring АйО перевела статью, в которой рассказывается про разработку эффективных агентов с помощью Spring AI. Исследование Anthropic "Building effective agents" подчеркивает важность простоты и модульности в разработке LLM-агентов.
В статье рассматривается, как эти принципы реализуются в Spring AI через пять ключевых паттернов: Chain Workflow, Parallelization Workflow, Routing Workflow, Orchestrator-Workers и Evaluator-Optimizer.
В недавней публикации своего исследования: Building effective agents, Anthropic поделился ценными взглядами на разработку эффективных LLM агентов (Large Language Model - большая языковая модель). Что делает это исследование особенно интересным, так это то, что оно акцентирует простоту и пригодность к компоновке, ставя их в приоритет по отношению к комплексным фреймворкам. Давайте посмотрим на то, как эти принципы транслируются в практические реализации с использованием Spring AI.

В то время как описания паттернов и диаграмм взяты нами из оригинальной публикации от Anthropic, мы сосредоточимся на том, как реализовать эти паттерны с использованием возможностей Spring AI в части переносимости моделей и структурированного вывода. Мы рекомендуем сначала прочитать оригинальную публикацию.
Проект agentic-patterns реализует обсуждаемые ниже паттерны.
Агентные системы
Публикация исследования вводит важное архитектурное различие между двумя типами агентных систем:
Workflows: системы, в которых LLM и инструменты оркеструются через предварительно заданные пути в коде (например, директивная система)
Агенты (Agents): Системы, где LLM динамически направляют свои процессы и использование инструментов
Ключевой вывод состоит в том, что в то время как полностью автономные агенты могут казаться привлекательными, workflows часто предоставляют лучшую предсказуемость и стабильность для хорошо определенных задач. Это наилучшим образом сочетается с требованиями, предъявляемыми крупным бизнесом, где надежность и поддерживаемость являются решающими факторами.
Давайте посмотрим, как Spring AI реализует эти концепции через пять фундаментальных паттернов, каждый их которых помогает решению определенного набора кейсов:
Паттерн Chain Workflow является примером разбиения сложных задач на более простые, более управляемые, чтобы иметь возможность выполнять их по шагам.

Когда используется:
Задачи с четкими последовательными шагами
Когда вы готовы пожертвовать latency ради более высокой точности
Когда каждый шаг использует результаты предыдущего
Приведем практический пример из реализации Spring AI:
public class ChainWorkflow {
private final ChatClient chatClient;
private final String[] systemPrompts;
// Processes input through a series of prompts, where each step's output
// becomes input for the next step in the chain.
public String chain(String userInput) {
String response = userInput;
for (String prompt : systemPrompts) {
// Combine the system prompt with previous response
String input = String.format("{%s}\n {%s}", prompt, response);
// Process through the LLM and capture output
response = chatClient.prompt(input).call().content();
}
return response;
}
}
Эта реализация демонстрирует несколько ключевых принципов:
Каждый шаг фокусируется на своей зоне ответственности
Вывод одного шага становится вводом другого
Цепочка легко расширяется и поддерживается
LLM могут одновременно работать над задачами и агрегировать их вывод программным путем. Параллелизация workflow проявляется в двух ключевых вариантах:
Разбиенте на секции: задачи разбиваются на несколько независимых подзадач для параллельной обработки
Голосование: несколько инстансов одной и той же задачи запускаются одновременно ради консенсуса

Когда используется:
Обработка больших количеств похожих, но независимых объектов
Задачи, требующие многочисленных независимых подходов
Когда время обработки имеет решающее значение, а задачи можно выполнять параллельно
Паттерн Parallelization Workflow демонстрирует эффективную многопоточную обработку многочисленных LLM операций. Этот паттерн особенно полезен для сценариев, требующих параллельного выполнения вызовов LLM с автоматизированной агрегацией вывода.
Приведем базовый пример использования паттерна Parallelization Workflow:
List<String> parallelResponse = new ParallelizationWorkflow(chatClient)
.parallel(
"Analyze how market changes will impact this stakeholder group.",
List.of(
"Customers: ...",
"Employees: ...",
"Investors: ...",
"Suppliers: ..."
),
4
);
Этот пример демонстрирует параллельную обработку анализа ситуации с держателями акций, при этом каждая группа держателей акций анализируется отдельно в многопоточном режиме.
Паттерн Routing реализует умное распределение задач, позволяя обрабатывать различные типы входных данных по-разному.

Этот паттерн создан для сложных задач, в которых разные типы входных данных лучше обрабатывать различными, специально под них разработанными процессами. Он использует LLM, чтобы проанализировать содержимое ввода и перенаправить его на наиболее подходящее специализированное приглашение или обработчик.
Когда используется:
Сложные задачи с четко определенными категориями входных данных
Когда разные входные данные требуют специализированной обработки
Когда классификацию можно выполнить достаточно точно
Приведем базовый пример использования Routing Workflow:
@Autowired
private ChatClient chatClient;
// Create the workflow
RoutingWorkflow workflow = new RoutingWorkflow(chatClient);
// Define specialized prompts for different types of input
Map<String, String> routes = Map.of(
"billing", "You are a billing specialist. Help resolve billing issues...",
"technical", "You are a technical support engineer. Help solve technical problems...",
"general", "You are a customer service representative. Help with general inquiries..."
);
// Process input
String input = "My account was charged twice last week";
String response = workflow.route(input, routes);
4. Orchestrator-Workers
Этот паттерн демонстрирует, как реализовывать более сложное агентоподобное поведение, при этом полностью сохраняя контроль:
Центральная LLM оркестрирует декомпозицию задач
Специализированные обработчики обрабатывают специфические подзадачи
Четкие границы поддерживают надежность системы

Когда используется:
Сложные задачи, в которых подзадачи нельзя предсказать заранее
Задачи, требующие разных подходов или точек зрения
Ситуации, требующие адаптивного решения проблем
Реализация использует ChatClient от Spring AI's для интерактивного взаимодействия с LLM и состоит из:
public class OrchestratorWorkersWorkflow {
public WorkerResponse process(String taskDescription) {
// 1. Orchestrator analyzes task and determines subtasks
OrchestratorResponse orchestratorResponse = // ...
// 2. Workers process subtasks in parallel
List<String> workerResponses = // ...
// 3. Results are combined into final response
return new WorkerResponse(/*...*/);
}
}
Пример использования:
ChatClient chatClient = // ... initialize chat client
OrchestratorWorkersWorkflow workflow = new OrchestratorWorkersWorkflow(chatClient);
// Process a task
WorkerResponse response = workflow.process(
"Generate both technical and user-friendly documentation for a REST API endpoint"
);
// Access results
System.out.println("Analysis: " + response.analysis());
System.out.println("Worker Outputs: " + response.workerResponses());
5. Evaluator-Optimizer
Паттерн Evaluator-Optimizer реализует процесс dual-LLM (двойная LLM), где одна модель генерирует ответы, в то время как вторая предоставляет оценку и обратную связь в итерационном цикле, что напоминает процесс работы писателя над текстом. Паттерн состоит из двух главных компонентов:
Generator LLM (модель-генератор): Генерирует первоначальный ответ и улучшает его на базе обратной связи
Evaluator LLM (модель-оценщик): Анализирует ответы и предоставляет подробную обратную связь для улучшений

Когда используется:
Существуют четкие критерии оценки
Улучшение в цикле дает измеримое преимущество
Задачи выигрывают от нескольких раундов критической оценки
Реализация использует ChatClient от Spring AI's для интерактивного взаимодействия с LLM и состоит из:
public class EvaluatorOptimizerWorkflow {
public RefinedResponse loop(String task) {
// 1. Generate initial solution
Generation generation = generate(task, context);
// 2. Evaluate the solution
EvaluationResponse evaluation = evaluate(generation.response(), task);
// 3. If PASS, return solution
// 4. If NEEDS_IMPROVEMENT, incorporate feedback and generate new solution
// 5. Repeat until satisfactory
return new RefinedResponse(finalSolution, chainOfThought);
}
}
Пример использования:
ChatClient chatClient = // ... initialize chat client
EvaluatorOptimizerWorkflow workflow = new EvaluatorOptimizerWorkflow(chatClient);
// Process a task
RefinedResponse response = workflow.loop(
"Create a Java class implementing a thread-safe counter"
);
// Access results
System.out.println("Final Solution: " + response.solution());
System.out.println("Evolution: " + response.chainOfThought());
Преимущества реализаций в Spring AI
Реализации этих паттернов в Spring AI имеют несколько преимуществ, которые соответствуют рекомендациям Anthropic:
<!-- Easy model switching through dependencies -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
// Type-safe handling of LLM responses
EvaluationResponse response = chatClient.prompt(prompt)
.call()
.entity(EvaluationResponse.class);
Один и тот же интерфейс для разных LLM провайдеров
Встроенная обработка ошибок и повторные попытки
Гибкое управление подсказками
Best Practices и рекомендации
Базируясь как на исследовании от Anthropic, так и на реализациях от Spring AI, можно сформулировать следующие ключевые рекомендации для построения эффективных систем, базирующихся на LLM:
Начинайте с простого
Начинайте с простых workflows прежде чем добавить большую сложность
Используйте самый простой паттерн из тех, что соответствуют вашим требованиям
Добавляйте сложность только тогда, когда это необходимо
Надежность архитектуры
Реализуйте четкую систему обработки ошибок
Используйте типобезопасные ответы, где это возможно
Встраивайте валидацию на каждом шаге
Рассматривайте компромиссы
Балансируйте latency и точность
Проводите оценку целесообразности использования многопоточной обработки
Выбирайте между фиксированными workflows и динамическими агентами
Что дальше
В части 2 этой серии статей мы расскажем о том, как использовать Agents, которые сочетают в себе основные паттерны и более комплексные возможности:
Композиции паттернов
Комбинирование нескольких паттернов для создания более мощных workflows
Построение гибридных систем, которые используют силу каждого паттерна по максимуму
Создание гибких архитектур, которые могут адаптироваться к меняющимся требованиям
Усовершенствованное управление памятью в агенте
Реализация persistent памяти во всех диалогах
Эффективное управление контекстными окнами
Разработка стратегий по долговременному хранению знаний
Интеграция инструментов и протокола Model-Context (MCP)
Использование внешних инструментов через стандартные интерфейсы
Реализация MCP для расширенного взаимодействия с моделью
Построение расширяемых архитектур агента
В дальнейшем мы также расскажем о подробностях реализаций и best practices для этих усовершенствованных возможностей.
Заключение
Комбинация выводов исследования от Anthropic и практических реализаций Spring AI предоставляет мощный фреймворк для разработки эффективных систем использующих LLM. Следуя приведенным паттернам и принципам, разработчики могут создавать мощные, простые в поддержке и эффективные ИИ приложения, которые приносят реальную пользу, при этом избегая лишней сложности.
Главное — помнить, что иногда самое простое решение является самым эффективным. Начните с базовых паттернов, как следует разберитесь с тем, что подходит для решения вашего кейса и добавляйте сложность только тогда, когда это ощутимо улучшит производительность или возможности вашей системы.

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