Advanced Patterns Tutorial
Learn how to combine agent patterns and create custom workflows for complex tasks.
Overview
While individual patterns are powerful, combining them unlocks even more capabilities:
- Pattern Composition - Use multiple patterns together
- Custom Workflows - Build tailored agent workflows
- Hybrid Approaches - Mix pattern strengths
- Advanced Techniques - Optimize for complex scenarios
Prerequisites
Before starting this tutorial, you should be familiar with:
- Your First Agent - Basic agent creation
- Agent Patterns Overview - Understanding each pattern
- ReAct Pattern - ReAct details
- Plan-Execute Pattern - Plan-Execute details
- Reflection Pattern - Reflection details
- Multi-Agent Pattern - Multi-Agent details
- Custom Tools - Creating tools
Pattern Combination Strategies
Strategy 1: Plan-Execute + ReAct
Use Plan-Execute for overall structure, ReAct for complex steps.
When to use:
- Tasks need structured planning
- Some steps require exploratory reasoning
- Mix of predictable and unpredictable sub-tasks
Example: Research and Analysis
import { createPlanExecuteAgent, createReActAgent } from '@agentforge/patterns';
import { ChatOpenAI } from '@langchain/openai';
import { toolBuilder, ToolCategory } from '@agentforge/core';
import { z } from 'zod';
const llm = new ChatOpenAI({ model: 'gpt-4' });
// Create a ReAct agent for complex research
const researchAgent = createReActAgent({
llm,
tools: [webSearchTool, scrapeTool, analyzeTool],
maxIterations: 10
});
// Wrap ReAct agent as a tool
const complexResearchTool = toolBuilder()
.name('complex-research')
.description('Perform complex research using exploratory reasoning')
.category(ToolCategory.SEARCH)
.schema(z.object({
topic: z.string().describe('Research topic'),
depth: z.enum(['shallow', 'deep']).describe('Research depth')
}))
.implement(async ({ topic, depth }) => {
const result = await researchAgent.invoke({
messages: [{ role: 'user', content: `Research: ${topic} (${depth})` }]
});
return result.response;
})
.build();
// Use in Plan-Execute agent
const agent = createPlanExecuteAgent({
planner: {
llm,
maxSteps: 5,
systemPrompt: 'Create a structured research and analysis plan'
},
executor: {
tools: [
complexResearchTool, // Uses ReAct internally
summarizeTool,
reportTool
],
parallel: false
}
});
// Execute
const result = await agent.invoke({
input: 'Research AI trends and create a comprehensive report'
});Strategy 2: Reflection + Plan-Execute
Use Plan-Execute for execution, Reflection for quality improvement.
When to use:
- Quality is critical
- Output needs iterative refinement
- Multiple execution attempts acceptable
Example: Content Creation Pipeline
import { createPlanExecuteAgent, createReflectionAgent } from '@agentforge/patterns';
// Step 1: Execute content creation plan
const executionAgent = createPlanExecuteAgent({
planner: {
llm,
maxSteps: 4,
systemPrompt: 'Plan content creation: research, outline, draft, format'
},
executor: {
tools: [researchTool, outlineTool, draftTool, formatTool]
}
});
// Step 2: Refine with reflection
const reflectionAgent = createReflectionAgent({
generator: { llm },
reflector: {
llm,
systemPrompt: 'Critique content for clarity, accuracy, and engagement'
},
reviser: { llm },
maxIterations: 3
});
// Combined workflow
async function createQualityContent(topic: string) {
// Execute plan
const draft = await executionAgent.invoke({
input: `Create content about: ${topic}`
});
// Refine with reflection
const refined = await reflectionAgent.invoke({
messages: [{ role: 'user', content: draft.response }]
});
return refined.response;
}
const content = await createQualityContent('AI in Healthcare');Strategy 3: Multi-Agent + Specialized Patterns
Use Multi-Agent for coordination, specialized patterns for workers.
When to use:
- Multiple specialized capabilities needed
- Tasks can be parallelized
- Different approaches for different sub-tasks
Example: Software Development Team
import { createMultiAgentSystem, registerWorkers } from '@agentforge/patterns';
// Create specialized worker agents
const codeReviewAgent = createReflectionAgent({
generator: { llm },
reflector: {
llm,
systemPrompt: 'Review code for bugs, style, and best practices'
},
maxIterations: 2
});
const testingAgent = createPlanExecuteAgent({
planner: {
llm,
systemPrompt: 'Plan comprehensive testing strategy'
},
executor: {
tools: [unitTestTool, integrationTestTool, e2eTestTool]
}
});
const documentationAgent = createReActAgent({
llm,
tools: [codeAnalysisTool, exampleGeneratorTool, markdownTool]
});
// Create multi-agent system
const system = createMultiAgentSystem({
supervisor: {
llm,
routingStrategy: 'skill-based'
},
workers: [],
aggregator: { llm }
});
// Register workers
registerWorkers(system, [
{
name: 'code-reviewer',
capabilities: ['code-review', 'quality-check'],
agent: codeReviewAgent
},
{
name: 'tester',
capabilities: ['testing', 'qa'],
agent: testingAgent
},
{
name: 'documenter',
capabilities: ['documentation', 'examples'],
agent: documentationAgent
}
]);
// Use the system
const result = await system.invoke({
input: 'Review, test, and document the authentication module'
});Custom Workflows
Building Custom LangGraph Workflows
Create completely custom workflows by composing nodes manually:
import { StateGraph, END } from '@langchain/langgraph';
import { createReasoningNode, createActionNode } from '@agentforge/patterns';
// Define custom state
interface CustomState {
input: string;
plan?: string[];
currentStep?: number;
results: string[];
finalOutput?: string;
}
// Create custom nodes
async function planningNode(state: CustomState): Promise<CustomState> {
const plan = await llm.invoke(`Create a plan for: ${state.input}`);
return {
...state,
plan: plan.split('\n'),
currentStep: 0
};
}
async function executionNode(state: CustomState): Promise<CustomState> {
const step = state.plan![state.currentStep!];
const result = await executeTool(step);
return {
...state,
results: [...state.results, result],
currentStep: state.currentStep! + 1
};
}
async function aggregationNode(state: CustomState): Promise<CustomState> {
const finalOutput = await llm.invoke(
`Summarize results: ${state.results.join('\n')}`
);
return { ...state, finalOutput };
}
// Build workflow
const workflow = new StateGraph<CustomState>({
channels: {
input: { value: (x, y) => y ?? x },
plan: { value: (x, y) => y ?? x },
currentStep: { value: (x, y) => y ?? x },
results: { value: (x, y) => y ?? x },
finalOutput: { value: (x, y) => y ?? x }
}
});
workflow
.addNode('planning', planningNode)
.addNode('execution', executionNode)
.addNode('aggregation', aggregationNode);
workflow.addEdge('__start__', 'planning');
workflow.addConditionalEdges(
'planning',
(state) => state.plan && state.plan.length > 0 ? 'execution' : END
);
workflow.addConditionalEdges(
'execution',
(state) => {
if (state.currentStep! < state.plan!.length) {
return 'execution'; // Continue executing
}
return 'aggregation'; // Done executing
}
);
workflow.addEdge('aggregation', END);
const agent = workflow.compile();Adding Validation and Error Handling
Enhance custom workflows with validation:
async function validationNode(state: CustomState): Promise<CustomState> {
const isValid = await validateResults(state.results);
if (!isValid) {
return {
...state,
currentStep: 0, // Restart
results: []
};
}
return state;
}
// Add to workflow
workflow.addNode('validation', validationNode);
workflow.addConditionalEdges(
'execution',
(state) => {
if (state.currentStep! < state.plan!.length) {
return 'execution';
}
return 'validation'; // Validate before aggregation
}
);
workflow.addConditionalEdges(
'validation',
(state) => state.results.length > 0 ? 'aggregation' : 'planning'
);Advanced Techniques
Technique 1: Dynamic Tool Selection
Dynamically select tools based on context:
import { ToolRegistry } from '@agentforge/core';
const registry = new ToolRegistry();
registry.registerMany([...allTools]);
async function selectTools(task: string): Promise<Tool[]> {
// Use LLM to select relevant tools
const selection = await llm.invoke(
`Which tools are needed for: ${task}?\nAvailable: ${registry.getAll().map(t => t.metadata.name).join(', ')}`
);
const toolNames = parseToolNames(selection);
return toolNames.map(name => registry.get(name));
}
// Use in agent
const tools = await selectTools('Research and analyze data');
const agent = createReActAgent({ llm, tools });Technique 2: Adaptive Iteration Limits
Adjust iteration limits based on task complexity:
function estimateComplexity(task: string): number {
const keywords = ['complex', 'comprehensive', 'detailed', 'thorough'];
const matches = keywords.filter(k => task.toLowerCase().includes(k));
return Math.min(5 + matches.length * 2, 15);
}
const maxIterations = estimateComplexity(userInput);
const agent = createReActAgent({
llm,
tools,
maxIterations
});Technique 3: Hierarchical Planning
Break complex tasks into hierarchical plans:
async function hierarchicalPlanning(task: string, depth: number = 0): Promise<Plan> {
if (depth > 2) return { steps: [task] }; // Max depth
const plan = await llm.invoke(`Break down: ${task}`);
const steps = parsePlan(plan);
const subPlans = await Promise.all(
steps.map(step =>
isComplex(step) ? hierarchicalPlanning(step, depth + 1) : { steps: [step] }
)
);
return { steps, subPlans };
}Technique 4: Result Caching and Reuse
Cache intermediate results for efficiency:
import { withCache } from '@agentforge/core/middleware';
const cachedResearchTool = withCache(researchTool, {
ttl: 3600000, // 1 hour
keyGenerator: (input) => `research:${input.topic}`
});
const agent = createPlanExecuteAgent({
executor: {
tools: [cachedResearchTool, ...otherTools]
}
});Best Practices
1. Start Simple, Then Compose
// ✅ Good - start with simple pattern
const simpleAgent = createReActAgent({ llm, tools });
// Then enhance if needed
const enhancedAgent = createPlanExecuteAgent({
executor: {
tools: [wrapAgentAsTool(simpleAgent), ...otherTools]
}
});
// ❌ Bad - over-engineering from the start
const overEngineered = createMultiAgentSystem({
workers: [
createReflectionAgent({
generator: createPlanExecuteAgent({...}),
// Too complex!
})
]
});2. Monitor and Debug
Add logging to understand workflow:
import { withLogging } from '@agentforge/core/middleware';
const loggedNode = withLogging(myNode, {
name: 'custom-node',
level: 'debug',
logInput: true,
logOutput: true
});3. Handle Failures Gracefully
import { withRetry, withErrorHandler } from '@agentforge/core/middleware';
const resilientNode = compose(
(n) => withRetry(n, { maxAttempts: 3 }),
(n) => withErrorHandler(n, {
onError: (error, state) => {
console.error('Node failed:', error);
return { ...state, error: error.message };
}
})
)(myNode);4. Test Each Component
Test patterns individually before combining:
import { testing } from '@agentforge/core/middleware';
// Test individual components
const testAgent = testing(myAgent, {
mockResponse: { result: 'test' },
trackInvocations: true
});
await testAgent.invoke({ input: 'test' });
console.log(testAgent.invocations); // Verify behaviorComplete Example: AI Research Assistant
Putting it all together:
import {
createPlanExecuteAgent,
createReActAgent,
createReflectionAgent,
createMultiAgentSystem
} from '@agentforge/patterns';
// 1. Create specialized agents
const webResearcher = createReActAgent({
llm,
tools: [webSearchTool, scrapeTool],
maxIterations: 10
});
const dataAnalyzer = createPlanExecuteAgent({
planner: { llm, maxSteps: 5 },
executor: { tools: [analyzeTool, visualizeTool] }
});
const reportWriter = createReflectionAgent({
generator: { llm },
reflector: { llm },
maxIterations: 3
});
// 2. Combine in multi-agent system
const researchSystem = createMultiAgentSystem({
supervisor: {
llm,
routingStrategy: 'skill-based'
},
workers: [
{ name: 'researcher', capabilities: ['search', 'gather'], agent: webResearcher },
{ name: 'analyzer', capabilities: ['analyze', 'visualize'], agent: dataAnalyzer },
{ name: 'writer', capabilities: ['write', 'report'], agent: reportWriter }
],
aggregator: { llm }
});
// 3. Use the system
const result = await researchSystem.invoke({
input: 'Research AI trends, analyze data, and create a comprehensive report'
});
console.log(result.finalOutput);Next Steps
- Production Deployment - Deploy your agents
- Testing Strategies - Test complex workflows
- Monitoring Guide - Monitor agent performance
- Pattern Guides - Deep dive into each pattern