# Agentic Patterns
This project demonstrates practical implementations of the workflow patterns for building effective LLM-based systems, as described in [Anthropic's research on building effective agents](https://www.anthropic.com/research/building-effective-agents).
## Overview
The project provides concrete implementations of five fundamental workflow patterns that can be used to build effective LLM-based systems. Each pattern is implemented as a separate module with its own specific use cases and benefits.
## Workflow Patterns
### 1. Chain Workflow
[chain-workflow/](chain-workflow/)
Implements prompt chaining to decompose tasks into a sequence of LLM calls where each step processes the output of the previous one. Ideal for tasks that can be cleanly broken down into fixed subtasks.
**When to Use:**
- Tasks with clear sequential steps
- When you want to trade latency for higher accuracy
- When each step builds on the previous step's output
**Example Applications:**
- Data transformation pipelines
- Multi-step text processing
- Document generation with structured steps
### 2. Parallelization Workflow
[parallelization-worflow/](parallelization-worflow/)
Enables concurrent processing of multiple LLM operations with two key variations:
- **Sectioning**: Breaking tasks into independent subtasks run in parallel
- **Voting**: Running the same task multiple times to get diverse outputs
**When to Use:**
- Processing large volumes of similar but independent items
- Tasks requiring multiple independent perspectives
- When processing time is critical and tasks are parallelizable
**Example Applications:**
- Batch processing of documents
- Multi-perspective content analysis
- Parallel validation checks
### 3. Routing Workflow
[routing-workflow/](routing-workflow/)
Implements a classification system that directs input to specialized followup tasks, enabling separation of concerns and optimized processing for different types of input.
**When to Use:**
- Complex tasks with distinct categories of input
- When different inputs require specialized processing
- When classification can be handled accurately
**Example Applications:**
- Customer support ticket routing
- Content moderation systems
- Query optimization based on complexity
### 4. Orchestrator-Workers
[orchestrator-workers/](orchestrator-workers/)
Implements a flexible system where a central LLM orchestrates task decomposition and delegates to specialized worker LLMs.
**When to Use:**
- Complex tasks where subtasks can't be predicted upfront
- Tasks requiring different approaches or perspectives
- Situations needing adaptive problem-solving
**Example Applications:**
- Complex code generation tasks
- Multi-source research tasks
- Adaptive content creation
### 5. Evaluator-Optimizer
[evaluator-optimizer/](evaluator-optimizer/)
Implements an iterative refinement process where one LLM generates solutions while another provides evaluation and feedback.
**When to Use:**
- Clear evaluation criteria exist
- Iterative refinement provides measurable value
- Tasks benefit from multiple rounds of critique
**Example Applications:**
- Code review and improvement
- Content quality optimization
- Translation refinement
- Complex search tasks
## Implementation Details
All workflows are implemented using:
- Spring AI for LLM interactions
- Spring Boot for application framework
- Java 17+ for modern language features
Each workflow module contains:
- Core workflow implementation
- Usage examples
- Customization options
- Unit tests
## Getting Started
1. Clone the repository
2. Choose the appropriate workflow pattern for your use case
3. See the individual module's README for specific implementation details
## Spring AI Features
This project leverages several key features from Spring AI to implement the workflow patterns effectively:
1. **ChatClient Interface**: Core abstraction for interacting with LLM models
- Consistent API across different LLM providers
- Fluent interface for prompt construction
- Built-in retry and error handling
2. **Model Support**: Wide range of supported LLM providers
- OpenAI (GPT models)
- Azure OpenAI
- Anthropic (Claude models)
- Ollama (local models)
- And more...
3. **Structured Output**: Type-safe handling of LLM responses
- Convert JSON responses to Java objects
- Strongly-typed response handling
- Validation and error handling
4. **Prompt Management**: Flexible prompt handling
- Template-based prompts
- System and user message separation
- Context management
These features provide a robust foundation for building reliable and maintainable LLM-based applications.
### Spring AI Model Portability
The workflows in this project are model-agnostic and can work with any of the [chat models supported by Spring AI](https://docs.spring.io/spring-ai/reference/1.0/api/chat/comparison.html). To switch between different models:
1. Replace the model-specific starter dependency in your `pom.xml`:
```xml
org.springframework.ai
spring-ai-openai-spring-boot-starter
org.springframework.ai
spring-ai-azure-openai-spring-boot-starter
org.springframework.ai
spring-ai-anthropic-spring-boot-starter
org.springframework.ai
spring-ai-ollama-spring-boot-starter
```
2. Configure the model-specific properties in your `application.properties`:
```properties
# OpenAI Configuration
spring.ai.openai.api-key=your-api-key
spring.ai.openai.model=gpt-3.5-turbo
# Azure OpenAI Configuration
spring.ai.azure.openai.api-key=your-api-key
spring.ai.azure.openai.endpoint=your-endpoint
spring.ai.azure.openai.model=gpt-35-turbo
# Anthropic Configuration
spring.ai.anthropic.api-key=your-api-key
spring.ai.anthropic.model=claude-3-opus-20240229
# Ollama Configuration
spring.ai.ollama.base-url=http://localhost:11434
spring.ai.ollama.model=llama3.2:latest
```
Detailed configuration options for each model can be found in the [Spring AI Chat Models documentation](https://docs.spring.io/spring-ai/reference/1.0/api/chatmodel.html).
### Spring AI Structured Output
Several patterns in this project use Spring AI's [Structured Output Converter](https://docs.spring.io/spring-ai/reference/1.0/api/structured-output-converter.html) to handle structured responses from LLMs. This feature allows for:
- Converting LLM responses into strongly-typed Java objects
- Ensuring consistent response formats
- Type-safe handling of LLM outputs
#### Example Usage
```java
// Define a record for structured output
public record EvaluationResponse(Evaluation evaluation, String feedback) {
public enum Evaluation {
PASS, NEEDS_IMPROVEMENT, FAIL
}
}
// Use the entity() method to convert response to your type
EvaluationResponse response = chatClient.prompt(prompt)
.call()
.entity(EvaluationResponse.class);
// Access typed fields
if (response.evaluation() == Evaluation.PASS) {
// Handle passing evaluation
}
```
#### Implementation Examples
The feature is used in several workflow patterns:
1. **Evaluator-Optimizer Workflow**: Structures evaluation responses with pass/fail status and feedback
```java
record EvaluationResponse(Evaluation evaluation, String feedback)
```
2. **Routing Workflow**: Structures routing decisions with reasoning and selection
```java
record RoutingResponse(String reasoning, String selection)
```
3. **Chain Workflow**: Structures intermediate transformation results
```java
record TransformationResult(String output, List steps)
```
## References
- [Building Effective Agents (Anthropic Research)](https://www.anthropic.com/research/building-effective-agents)
- [Spring AI Documentation](https://docs.spring.io/spring-ai/reference/1.0/api/chatclient.html)
- [Spring AI Chat Models](https://docs.spring.io/spring-ai/reference/1.0/api/chatmodel.html)
- [Spring AI Structured Output](https://docs.spring.io/spring-ai/reference/1.0/api/structured-output-converter.html)