rcrewai 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +32 -0
- data/docs/api/agent.md +429 -0
- data/docs/api/task.md +494 -0
- data/docs/examples/api-integration.md +829 -0
- data/docs/examples/async-execution.md +893 -0
- data/docs/examples/code-review-crew.md +660 -0
- data/docs/examples/content-marketing-pipeline.md +681 -0
- data/docs/examples/custom-tools.md +1224 -0
- data/docs/examples/customer-support.md +717 -0
- data/docs/examples/data-analysis-team.md +677 -0
- data/docs/examples/database-operations.md +1298 -0
- data/docs/examples/ecommerce-operations.md +990 -0
- data/docs/examples/financial-analysis.md +857 -0
- data/docs/examples/hierarchical-crew.md +479 -0
- data/docs/examples/product-development.md +688 -0
- data/docs/examples/production-ready-crew.md +384 -408
- data/docs/examples/research-development.md +1225 -0
- data/docs/examples/social-media.md +1073 -0
- data/docs/examples/task-automation.md +527 -0
- data/docs/examples/tool-composition.md +1075 -0
- data/docs/examples/web-scraping.md +1201 -0
- data/docs/tutorials/advanced-agents.md +1014 -0
- data/docs/tutorials/custom-tools.md +1242 -0
- data/docs/tutorials/deployment.md +1836 -0
- data/docs/tutorials/index.md +184 -0
- data/docs/tutorials/multiple-crews.md +1692 -0
- data/lib/rcrewai/llm_clients/anthropic.rb +1 -1
- data/lib/rcrewai/version.rb +1 -1
- data/rcrewai.gemspec +21 -2
- metadata +47 -5
@@ -0,0 +1,1014 @@
|
|
1
|
+
---
|
2
|
+
layout: tutorial
|
3
|
+
title: Advanced Agent Configuration
|
4
|
+
description: Master advanced agent features including memory, custom reasoning, delegation, and performance optimization
|
5
|
+
---
|
6
|
+
|
7
|
+
# Advanced Agent Configuration
|
8
|
+
|
9
|
+
This tutorial covers advanced agent configuration techniques including memory systems, custom reasoning loops, delegation patterns, performance optimization, and specialized agent behaviors.
|
10
|
+
|
11
|
+
## Table of Contents
|
12
|
+
1. [Agent Memory Systems](#agent-memory-systems)
|
13
|
+
2. [Custom Reasoning Loops](#custom-reasoning-loops)
|
14
|
+
3. [Manager Agents and Delegation](#manager-agents-and-delegation)
|
15
|
+
4. [Performance Optimization](#performance-optimization)
|
16
|
+
5. [Specialized Agent Behaviors](#specialized-agent-behaviors)
|
17
|
+
6. [Agent Communication Patterns](#agent-communication-patterns)
|
18
|
+
7. [Error Handling and Recovery](#error-handling-and-recovery)
|
19
|
+
|
20
|
+
## Agent Memory Systems
|
21
|
+
|
22
|
+
Agents in RCrewAI have sophisticated memory systems that allow them to learn and improve over time.
|
23
|
+
|
24
|
+
### Short-term and Long-term Memory
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'rcrewai'
|
28
|
+
|
29
|
+
# Create agent with enhanced memory capabilities
|
30
|
+
analyst = RCrewAI::Agent.new(
|
31
|
+
name: "data_analyst",
|
32
|
+
role: "Senior Data Analyst",
|
33
|
+
goal: "Analyze data patterns and learn from past analyses",
|
34
|
+
backstory: "Expert analyst who improves with each analysis",
|
35
|
+
verbose: true
|
36
|
+
)
|
37
|
+
|
38
|
+
# Memory is automatically created and managed
|
39
|
+
memory = analyst.memory
|
40
|
+
|
41
|
+
# After task execution, memory stores:
|
42
|
+
# - Successful patterns and strategies
|
43
|
+
# - Tool usage that worked well
|
44
|
+
# - Context that led to good results
|
45
|
+
# - Failed approaches to avoid
|
46
|
+
|
47
|
+
# Access memory statistics
|
48
|
+
stats = memory.stats
|
49
|
+
puts "Total executions: #{stats[:total_executions]}"
|
50
|
+
puts "Success rate: #{stats[:success_rate]}%"
|
51
|
+
puts "Most used tools: #{stats[:top_tools]}"
|
52
|
+
puts "Average execution time: #{stats[:avg_execution_time]}s"
|
53
|
+
|
54
|
+
# Memory influences future reasoning
|
55
|
+
# Agent will prefer successful patterns from memory
|
56
|
+
```
|
57
|
+
|
58
|
+
### Custom Memory Persistence
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
class PersistentMemoryAgent < RCrewAI::Agent
|
62
|
+
def initialize(**options)
|
63
|
+
super
|
64
|
+
load_memory_from_storage
|
65
|
+
end
|
66
|
+
|
67
|
+
def execute_task(task)
|
68
|
+
result = super
|
69
|
+
save_memory_to_storage
|
70
|
+
result
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def load_memory_from_storage
|
76
|
+
if File.exist?("#{name}_memory.json")
|
77
|
+
memory_data = JSON.parse(File.read("#{name}_memory.json"))
|
78
|
+
@memory.restore(memory_data)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def save_memory_to_storage
|
83
|
+
File.write("#{name}_memory.json", @memory.to_json)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Agent that remembers across sessions
|
88
|
+
persistent_agent = PersistentMemoryAgent.new(
|
89
|
+
name: "persistent_researcher",
|
90
|
+
role: "Research Specialist",
|
91
|
+
goal: "Build knowledge over time"
|
92
|
+
)
|
93
|
+
```
|
94
|
+
|
95
|
+
### Memory-Enhanced Learning
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
# Create a learning agent that improves over time
|
99
|
+
learning_agent = RCrewAI::Agent.new(
|
100
|
+
name: "learning_assistant",
|
101
|
+
role: "Adaptive Assistant",
|
102
|
+
goal: "Learn from each interaction to provide better assistance",
|
103
|
+
backstory: "An AI that continuously improves through experience",
|
104
|
+
tools: [RCrewAI::Tools::WebSearch.new, RCrewAI::Tools::FileWriter.new]
|
105
|
+
)
|
106
|
+
|
107
|
+
# Track performance over multiple executions
|
108
|
+
10.times do |i|
|
109
|
+
task = RCrewAI::Task.new(
|
110
|
+
name: "research_task_#{i}",
|
111
|
+
description: "Research topic #{i}",
|
112
|
+
agent: learning_agent
|
113
|
+
)
|
114
|
+
|
115
|
+
result = task.execute
|
116
|
+
|
117
|
+
# Agent automatically learns:
|
118
|
+
# - Which search queries work best
|
119
|
+
# - How to structure research
|
120
|
+
# - Optimal tool usage patterns
|
121
|
+
|
122
|
+
puts "Iteration #{i}: Success=#{task.status == :completed}"
|
123
|
+
end
|
124
|
+
|
125
|
+
# Check improvement
|
126
|
+
puts "Learning progress: #{learning_agent.memory.learning_curve}"
|
127
|
+
```
|
128
|
+
|
129
|
+
## Custom Reasoning Loops
|
130
|
+
|
131
|
+
Advanced agents can have customized reasoning processes for specialized tasks.
|
132
|
+
|
133
|
+
### Custom Reasoning Agent
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
class AnalyticalReasoningAgent < RCrewAI::Agent
|
137
|
+
def reasoning_loop(task, context)
|
138
|
+
iteration = 0
|
139
|
+
hypotheses = []
|
140
|
+
|
141
|
+
loop do
|
142
|
+
iteration += 1
|
143
|
+
|
144
|
+
# Phase 1: Generate hypotheses
|
145
|
+
if iteration == 1
|
146
|
+
hypotheses = generate_hypotheses(task, context)
|
147
|
+
@logger.info "Generated #{hypotheses.length} hypotheses"
|
148
|
+
end
|
149
|
+
|
150
|
+
# Phase 2: Test hypotheses
|
151
|
+
if iteration > 1 && iteration <= hypotheses.length + 1
|
152
|
+
hypothesis = hypotheses[iteration - 2]
|
153
|
+
result = test_hypothesis(hypothesis, context)
|
154
|
+
|
155
|
+
if result[:valid]
|
156
|
+
return formulate_conclusion(hypothesis, result)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Phase 3: Synthesize findings
|
161
|
+
if iteration > hypotheses.length + 1
|
162
|
+
return synthesize_findings(hypotheses, context)
|
163
|
+
end
|
164
|
+
|
165
|
+
break if iteration > max_iterations
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
def generate_hypotheses(task, context)
|
172
|
+
prompt = build_hypothesis_prompt(task, context)
|
173
|
+
response = llm_client.chat(messages: [{ role: 'user', content: prompt }])
|
174
|
+
parse_hypotheses(response[:content])
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_hypothesis(hypothesis, context)
|
178
|
+
# Use tools to validate hypothesis
|
179
|
+
if tools.any? { |t| t.name == 'websearch' }
|
180
|
+
evidence = use_tool('websearch', query: hypothesis[:query])
|
181
|
+
{ valid: evidence.include?(hypothesis[:expected]), evidence: evidence }
|
182
|
+
else
|
183
|
+
{ valid: false, evidence: nil }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def formulate_conclusion(hypothesis, result)
|
188
|
+
"Conclusion: #{hypothesis[:statement]} is supported by evidence: #{result[:evidence]}"
|
189
|
+
end
|
190
|
+
|
191
|
+
def synthesize_findings(hypotheses, context)
|
192
|
+
"Unable to validate hypotheses. Best assessment based on available data..."
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
# Use the analytical reasoning agent
|
197
|
+
analyst = AnalyticalReasoningAgent.new(
|
198
|
+
name: "hypothesis_tester",
|
199
|
+
role: "Scientific Analyst",
|
200
|
+
goal: "Test hypotheses systematically",
|
201
|
+
tools: [RCrewAI::Tools::WebSearch.new]
|
202
|
+
)
|
203
|
+
```
|
204
|
+
|
205
|
+
### Multi-Stage Reasoning
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
class MultiStageReasoningAgent < RCrewAI::Agent
|
209
|
+
REASONING_STAGES = [
|
210
|
+
:understand,
|
211
|
+
:analyze,
|
212
|
+
:plan,
|
213
|
+
:execute,
|
214
|
+
:verify,
|
215
|
+
:conclude
|
216
|
+
]
|
217
|
+
|
218
|
+
def reasoning_loop(task, context)
|
219
|
+
current_stage_index = 0
|
220
|
+
stage_results = {}
|
221
|
+
|
222
|
+
while current_stage_index < REASONING_STAGES.length
|
223
|
+
stage = REASONING_STAGES[current_stage_index]
|
224
|
+
|
225
|
+
@logger.info "Reasoning stage: #{stage}"
|
226
|
+
|
227
|
+
result = case stage
|
228
|
+
when :understand
|
229
|
+
understand_requirements(task, context)
|
230
|
+
when :analyze
|
231
|
+
analyze_problem(task, context, stage_results[:understand])
|
232
|
+
when :plan
|
233
|
+
create_action_plan(stage_results[:analyze])
|
234
|
+
when :execute
|
235
|
+
execute_plan(stage_results[:plan])
|
236
|
+
when :verify
|
237
|
+
verify_results(stage_results[:execute])
|
238
|
+
when :conclude
|
239
|
+
formulate_conclusion(stage_results)
|
240
|
+
end
|
241
|
+
|
242
|
+
stage_results[stage] = result
|
243
|
+
|
244
|
+
# Allow stage retry on failure
|
245
|
+
if result[:success]
|
246
|
+
current_stage_index += 1
|
247
|
+
elsif result[:retry]
|
248
|
+
@logger.info "Retrying stage: #{stage}"
|
249
|
+
else
|
250
|
+
break
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
stage_results[:conclude] || "Reasoning incomplete"
|
255
|
+
end
|
256
|
+
end
|
257
|
+
```
|
258
|
+
|
259
|
+
## Manager Agents and Delegation
|
260
|
+
|
261
|
+
Manager agents coordinate teams and delegate tasks intelligently.
|
262
|
+
|
263
|
+
### Creating a Manager Agent
|
264
|
+
|
265
|
+
```ruby
|
266
|
+
# Create a manager with delegation capabilities
|
267
|
+
manager = RCrewAI::Agent.new(
|
268
|
+
name: "team_manager",
|
269
|
+
role: "Engineering Manager",
|
270
|
+
goal: "Coordinate team to deliver projects efficiently",
|
271
|
+
backstory: "Experienced manager who knows how to leverage team strengths",
|
272
|
+
manager: true, # Mark as manager
|
273
|
+
allow_delegation: true, # Enable delegation
|
274
|
+
tools: [RCrewAI::Tools::FileWriter.new], # Manager tools
|
275
|
+
verbose: true
|
276
|
+
)
|
277
|
+
|
278
|
+
# Create specialist team members
|
279
|
+
backend_dev = RCrewAI::Agent.new(
|
280
|
+
name: "backend_developer",
|
281
|
+
role: "Backend Engineer",
|
282
|
+
goal: "Build robust backend systems",
|
283
|
+
tools: [RCrewAI::Tools::FileWriter.new]
|
284
|
+
)
|
285
|
+
|
286
|
+
frontend_dev = RCrewAI::Agent.new(
|
287
|
+
name: "frontend_developer",
|
288
|
+
role: "Frontend Engineer",
|
289
|
+
goal: "Create excellent user interfaces",
|
290
|
+
tools: [RCrewAI::Tools::FileWriter.new]
|
291
|
+
)
|
292
|
+
|
293
|
+
qa_engineer = RCrewAI::Agent.new(
|
294
|
+
name: "qa_engineer",
|
295
|
+
role: "QA Engineer",
|
296
|
+
goal: "Ensure software quality",
|
297
|
+
tools: [RCrewAI::Tools::FileReader.new]
|
298
|
+
)
|
299
|
+
|
300
|
+
# Build team hierarchy
|
301
|
+
manager.add_subordinate(backend_dev)
|
302
|
+
manager.add_subordinate(frontend_dev)
|
303
|
+
manager.add_subordinate(qa_engineer)
|
304
|
+
|
305
|
+
# Manager will automatically delegate tasks to appropriate team members
|
306
|
+
```
|
307
|
+
|
308
|
+
### Advanced Delegation Strategies
|
309
|
+
|
310
|
+
```ruby
|
311
|
+
class StrategicManager < RCrewAI::Agent
|
312
|
+
def delegate_task(task, target_agent = nil)
|
313
|
+
if target_agent.nil?
|
314
|
+
# Intelligent agent selection based on multiple factors
|
315
|
+
target_agent = select_best_agent(task)
|
316
|
+
end
|
317
|
+
|
318
|
+
# Create delegation context with strategic guidance
|
319
|
+
delegation_context = {
|
320
|
+
priority: assess_priority(task),
|
321
|
+
deadline: calculate_deadline(task),
|
322
|
+
resources: allocate_resources(task),
|
323
|
+
success_criteria: define_success_criteria(task),
|
324
|
+
escalation_path: define_escalation(task)
|
325
|
+
}
|
326
|
+
|
327
|
+
# Enhanced delegation with context
|
328
|
+
@logger.info "Delegating #{task.name} to #{target_agent.name}"
|
329
|
+
@logger.info "Context: #{delegation_context}"
|
330
|
+
|
331
|
+
super(task, target_agent)
|
332
|
+
end
|
333
|
+
|
334
|
+
private
|
335
|
+
|
336
|
+
def select_best_agent(task)
|
337
|
+
# Score each subordinate for task fit
|
338
|
+
scores = subordinates.map do |agent|
|
339
|
+
score = 0
|
340
|
+
|
341
|
+
# Factor 1: Role match
|
342
|
+
role_match = calculate_role_match(task, agent)
|
343
|
+
score += role_match * 0.4
|
344
|
+
|
345
|
+
# Factor 2: Current workload
|
346
|
+
workload = assess_workload(agent)
|
347
|
+
score += (1.0 - workload) * 0.3
|
348
|
+
|
349
|
+
# Factor 3: Past performance
|
350
|
+
performance = agent.memory.stats[:success_rate] || 0.5
|
351
|
+
score += performance * 0.2
|
352
|
+
|
353
|
+
# Factor 4: Tool availability
|
354
|
+
tool_match = calculate_tool_match(task, agent)
|
355
|
+
score += tool_match * 0.1
|
356
|
+
|
357
|
+
{ agent: agent, score: score }
|
358
|
+
end
|
359
|
+
|
360
|
+
# Select highest scoring agent
|
361
|
+
best = scores.max_by { |s| s[:score] }
|
362
|
+
best[:agent]
|
363
|
+
end
|
364
|
+
|
365
|
+
def calculate_role_match(task, agent)
|
366
|
+
task_keywords = extract_keywords(task.description)
|
367
|
+
role_keywords = extract_keywords(agent.role)
|
368
|
+
|
369
|
+
common = (task_keywords & role_keywords).length
|
370
|
+
total = [task_keywords.length, role_keywords.length].max
|
371
|
+
|
372
|
+
common.to_f / total
|
373
|
+
end
|
374
|
+
|
375
|
+
def assess_workload(agent)
|
376
|
+
# Return workload between 0 (idle) and 1 (overloaded)
|
377
|
+
active_tasks = @delegated_tasks[agent.name] || []
|
378
|
+
active_tasks.count { |t| t.status == :running } / 5.0
|
379
|
+
end
|
380
|
+
end
|
381
|
+
```
|
382
|
+
|
383
|
+
### Cross-Team Coordination
|
384
|
+
|
385
|
+
```ruby
|
386
|
+
# Multiple managers coordinating
|
387
|
+
engineering_manager = RCrewAI::Agent.new(
|
388
|
+
name: "eng_manager",
|
389
|
+
role: "Engineering Manager",
|
390
|
+
manager: true,
|
391
|
+
allow_delegation: true
|
392
|
+
)
|
393
|
+
|
394
|
+
product_manager = RCrewAI::Agent.new(
|
395
|
+
name: "product_manager",
|
396
|
+
role: "Product Manager",
|
397
|
+
manager: true,
|
398
|
+
allow_delegation: true
|
399
|
+
)
|
400
|
+
|
401
|
+
# Managers can coordinate through shared context
|
402
|
+
shared_context = {
|
403
|
+
project_goals: "Launch new feature by Q2",
|
404
|
+
constraints: "Limited to 3 engineers",
|
405
|
+
priorities: ["Performance", "User Experience", "Security"]
|
406
|
+
}
|
407
|
+
|
408
|
+
# Create tasks that require cross-team coordination
|
409
|
+
feature_task = RCrewAI::Task.new(
|
410
|
+
name: "new_feature",
|
411
|
+
description: "Implement new dashboard feature",
|
412
|
+
context_data: shared_context
|
413
|
+
)
|
414
|
+
|
415
|
+
# Both managers will coordinate their teams
|
416
|
+
```
|
417
|
+
|
418
|
+
## Performance Optimization
|
419
|
+
|
420
|
+
Optimize agent performance for production workloads.
|
421
|
+
|
422
|
+
### Parallel Agent Execution
|
423
|
+
|
424
|
+
```ruby
|
425
|
+
# Configure agents for parallel execution
|
426
|
+
fast_researcher = RCrewAI::Agent.new(
|
427
|
+
name: "fast_researcher",
|
428
|
+
role: "Research Specialist",
|
429
|
+
goal: "Quickly gather information",
|
430
|
+
max_iterations: 3, # Limit iterations
|
431
|
+
max_execution_time: 60, # 1 minute timeout
|
432
|
+
tools: [RCrewAI::Tools::WebSearch.new(timeout: 10)] # Fast timeout
|
433
|
+
)
|
434
|
+
|
435
|
+
# Create parallel tasks
|
436
|
+
parallel_tasks = 5.times.map do |i|
|
437
|
+
RCrewAI::Task.new(
|
438
|
+
name: "research_#{i}",
|
439
|
+
description: "Research topic #{i}",
|
440
|
+
agent: fast_researcher,
|
441
|
+
async: true # Mark for async execution
|
442
|
+
)
|
443
|
+
end
|
444
|
+
|
445
|
+
# Execute in parallel
|
446
|
+
crew = RCrewAI::Crew.new("parallel_crew")
|
447
|
+
crew.add_agent(fast_researcher)
|
448
|
+
parallel_tasks.each { |t| crew.add_task(t) }
|
449
|
+
|
450
|
+
results = crew.execute(async: true, max_concurrency: 5)
|
451
|
+
```
|
452
|
+
|
453
|
+
### Resource-Optimized Agents
|
454
|
+
|
455
|
+
```ruby
|
456
|
+
class ResourceOptimizedAgent < RCrewAI::Agent
|
457
|
+
def initialize(**options)
|
458
|
+
super
|
459
|
+
@resource_monitor = ResourceMonitor.new
|
460
|
+
end
|
461
|
+
|
462
|
+
def execute_task(task)
|
463
|
+
# Check resources before execution
|
464
|
+
if @resource_monitor.memory_usage > 0.8
|
465
|
+
@logger.warn "High memory usage, optimizing..."
|
466
|
+
optimize_memory
|
467
|
+
end
|
468
|
+
|
469
|
+
# Use chunked processing for large tasks
|
470
|
+
if task.estimated_size > 1_000_000
|
471
|
+
execute_chunked(task)
|
472
|
+
else
|
473
|
+
super
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
private
|
478
|
+
|
479
|
+
def execute_chunked(task)
|
480
|
+
chunks = split_task(task)
|
481
|
+
results = []
|
482
|
+
|
483
|
+
chunks.each_with_index do |chunk, i|
|
484
|
+
@logger.info "Processing chunk #{i+1}/#{chunks.length}"
|
485
|
+
|
486
|
+
# Process chunk with resource limits
|
487
|
+
result = with_resource_limits do
|
488
|
+
process_chunk(chunk)
|
489
|
+
end
|
490
|
+
|
491
|
+
results << result
|
492
|
+
|
493
|
+
# Clear memory between chunks
|
494
|
+
GC.start if i % 5 == 0
|
495
|
+
end
|
496
|
+
|
497
|
+
merge_results(results)
|
498
|
+
end
|
499
|
+
|
500
|
+
def with_resource_limits(&block)
|
501
|
+
Thread.new do
|
502
|
+
Thread.current[:memory_limit] = 100_000_000 # 100MB
|
503
|
+
Thread.current[:time_limit] = 30 # 30 seconds
|
504
|
+
|
505
|
+
Timeout::timeout(Thread.current[:time_limit]) do
|
506
|
+
yield
|
507
|
+
end
|
508
|
+
end.value
|
509
|
+
end
|
510
|
+
end
|
511
|
+
```
|
512
|
+
|
513
|
+
### Caching and Memoization
|
514
|
+
|
515
|
+
```ruby
|
516
|
+
class CachedAgent < RCrewAI::Agent
|
517
|
+
def initialize(**options)
|
518
|
+
super
|
519
|
+
@cache = {}
|
520
|
+
@cache_ttl = options[:cache_ttl] || 3600 # 1 hour default
|
521
|
+
end
|
522
|
+
|
523
|
+
def use_tool(tool_name, **params)
|
524
|
+
cache_key = "#{tool_name}_#{params.hash}"
|
525
|
+
|
526
|
+
# Check cache first
|
527
|
+
if cached = get_cached(cache_key)
|
528
|
+
@logger.info "Cache hit for #{tool_name}"
|
529
|
+
return cached
|
530
|
+
end
|
531
|
+
|
532
|
+
# Execute and cache
|
533
|
+
result = super
|
534
|
+
set_cached(cache_key, result)
|
535
|
+
result
|
536
|
+
end
|
537
|
+
|
538
|
+
private
|
539
|
+
|
540
|
+
def get_cached(key)
|
541
|
+
return nil unless @cache[key]
|
542
|
+
|
543
|
+
entry = @cache[key]
|
544
|
+
if Time.now - entry[:time] < @cache_ttl
|
545
|
+
entry[:value]
|
546
|
+
else
|
547
|
+
@cache.delete(key)
|
548
|
+
nil
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
def set_cached(key, value)
|
553
|
+
@cache[key] = {
|
554
|
+
value: value,
|
555
|
+
time: Time.now
|
556
|
+
}
|
557
|
+
|
558
|
+
# Limit cache size
|
559
|
+
if @cache.size > 100
|
560
|
+
oldest = @cache.min_by { |k, v| v[:time] }
|
561
|
+
@cache.delete(oldest[0])
|
562
|
+
end
|
563
|
+
end
|
564
|
+
end
|
565
|
+
```
|
566
|
+
|
567
|
+
## Specialized Agent Behaviors
|
568
|
+
|
569
|
+
Create agents with specialized behaviors for specific use cases.
|
570
|
+
|
571
|
+
### Research Specialist Agent
|
572
|
+
|
573
|
+
```ruby
|
574
|
+
class ResearchSpecialistAgent < RCrewAI::Agent
|
575
|
+
def initialize(**options)
|
576
|
+
super(options.merge(
|
577
|
+
tools: [
|
578
|
+
RCrewAI::Tools::WebSearch.new(max_results: 20),
|
579
|
+
RCrewAI::Tools::FileWriter.new,
|
580
|
+
RCrewAI::Tools::FileReader.new
|
581
|
+
]
|
582
|
+
))
|
583
|
+
|
584
|
+
@research_depth = options[:research_depth] || 3
|
585
|
+
@citation_style = options[:citation_style] || :apa
|
586
|
+
end
|
587
|
+
|
588
|
+
def execute_task(task)
|
589
|
+
# Enhanced research methodology
|
590
|
+
research_plan = create_research_plan(task)
|
591
|
+
sources = gather_sources(research_plan)
|
592
|
+
validated_sources = validate_sources(sources)
|
593
|
+
synthesis = synthesize_findings(validated_sources)
|
594
|
+
|
595
|
+
# Format with citations
|
596
|
+
format_research_output(synthesis, validated_sources)
|
597
|
+
end
|
598
|
+
|
599
|
+
private
|
600
|
+
|
601
|
+
def create_research_plan(task)
|
602
|
+
{
|
603
|
+
primary_queries: extract_key_topics(task.description),
|
604
|
+
secondary_queries: generate_related_queries(task.description),
|
605
|
+
depth_level: @research_depth,
|
606
|
+
quality_threshold: 0.7
|
607
|
+
}
|
608
|
+
end
|
609
|
+
|
610
|
+
def gather_sources(plan)
|
611
|
+
sources = []
|
612
|
+
|
613
|
+
# Primary research
|
614
|
+
plan[:primary_queries].each do |query|
|
615
|
+
results = use_tool('websearch', query: query, max_results: 10)
|
616
|
+
sources.concat(parse_search_results(results))
|
617
|
+
end
|
618
|
+
|
619
|
+
# Deep research for important topics
|
620
|
+
if @research_depth > 1
|
621
|
+
plan[:secondary_queries].each do |query|
|
622
|
+
results = use_tool('websearch', query: query, max_results: 5)
|
623
|
+
sources.concat(parse_search_results(results))
|
624
|
+
end
|
625
|
+
end
|
626
|
+
|
627
|
+
sources
|
628
|
+
end
|
629
|
+
|
630
|
+
def validate_sources(sources)
|
631
|
+
sources.select do |source|
|
632
|
+
score = calculate_source_credibility(source)
|
633
|
+
score > 0.5
|
634
|
+
end
|
635
|
+
end
|
636
|
+
|
637
|
+
def format_research_output(content, sources)
|
638
|
+
output = "# Research Report\n\n"
|
639
|
+
output += content
|
640
|
+
output += "\n\n## References\n\n"
|
641
|
+
|
642
|
+
sources.each_with_index do |source, i|
|
643
|
+
output += format_citation(source, i + 1)
|
644
|
+
end
|
645
|
+
|
646
|
+
output
|
647
|
+
end
|
648
|
+
end
|
649
|
+
```
|
650
|
+
|
651
|
+
### Code Review Agent
|
652
|
+
|
653
|
+
```ruby
|
654
|
+
class CodeReviewAgent < RCrewAI::Agent
|
655
|
+
REVIEW_CATEGORIES = [
|
656
|
+
:syntax,
|
657
|
+
:style,
|
658
|
+
:security,
|
659
|
+
:performance,
|
660
|
+
:maintainability,
|
661
|
+
:testing
|
662
|
+
]
|
663
|
+
|
664
|
+
def initialize(**options)
|
665
|
+
super(options.merge(
|
666
|
+
role: "Senior Code Reviewer",
|
667
|
+
goal: "Ensure code quality and best practices"
|
668
|
+
))
|
669
|
+
|
670
|
+
@review_strictness = options[:strictness] || :medium
|
671
|
+
@languages = options[:languages] || [:ruby, :python, :javascript]
|
672
|
+
end
|
673
|
+
|
674
|
+
def review_code(code, language = :ruby)
|
675
|
+
review_results = {}
|
676
|
+
|
677
|
+
REVIEW_CATEGORIES.each do |category|
|
678
|
+
review_results[category] = review_category(code, category, language)
|
679
|
+
end
|
680
|
+
|
681
|
+
generate_review_report(review_results, code)
|
682
|
+
end
|
683
|
+
|
684
|
+
private
|
685
|
+
|
686
|
+
def review_category(code, category, language)
|
687
|
+
case category
|
688
|
+
when :syntax
|
689
|
+
check_syntax(code, language)
|
690
|
+
when :style
|
691
|
+
check_style_compliance(code, language)
|
692
|
+
when :security
|
693
|
+
security_scan(code)
|
694
|
+
when :performance
|
695
|
+
analyze_performance(code)
|
696
|
+
when :maintainability
|
697
|
+
assess_maintainability(code)
|
698
|
+
when :testing
|
699
|
+
check_test_coverage(code)
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
def generate_review_report(results, code)
|
704
|
+
report = "## Code Review Report\n\n"
|
705
|
+
|
706
|
+
# Overall score
|
707
|
+
overall_score = calculate_overall_score(results)
|
708
|
+
report += "**Overall Score: #{overall_score}/10**\n\n"
|
709
|
+
|
710
|
+
# Category breakdown
|
711
|
+
results.each do |category, findings|
|
712
|
+
report += "### #{category.to_s.capitalize}\n"
|
713
|
+
report += format_findings(findings)
|
714
|
+
report += "\n"
|
715
|
+
end
|
716
|
+
|
717
|
+
# Recommendations
|
718
|
+
report += "### Recommendations\n"
|
719
|
+
report += generate_recommendations(results)
|
720
|
+
|
721
|
+
report
|
722
|
+
end
|
723
|
+
end
|
724
|
+
```
|
725
|
+
|
726
|
+
## Agent Communication Patterns
|
727
|
+
|
728
|
+
Enable sophisticated communication between agents.
|
729
|
+
|
730
|
+
### Message Passing Between Agents
|
731
|
+
|
732
|
+
```ruby
|
733
|
+
class CommunicatingAgent < RCrewAI::Agent
|
734
|
+
attr_accessor :message_queue
|
735
|
+
|
736
|
+
def initialize(**options)
|
737
|
+
super
|
738
|
+
@message_queue = []
|
739
|
+
@subscribers = []
|
740
|
+
end
|
741
|
+
|
742
|
+
def send_message(recipient, message)
|
743
|
+
if recipient.respond_to?(:receive_message)
|
744
|
+
recipient.receive_message(self, message)
|
745
|
+
@logger.info "Sent message to #{recipient.name}: #{message[:type]}"
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
def receive_message(sender, message)
|
750
|
+
@message_queue << {
|
751
|
+
from: sender.name,
|
752
|
+
message: message,
|
753
|
+
timestamp: Time.now
|
754
|
+
}
|
755
|
+
|
756
|
+
# Process immediately if high priority
|
757
|
+
if message[:priority] == :high
|
758
|
+
process_message(message)
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
def broadcast(message)
|
763
|
+
@subscribers.each do |subscriber|
|
764
|
+
send_message(subscriber, message)
|
765
|
+
end
|
766
|
+
end
|
767
|
+
|
768
|
+
def subscribe(agent)
|
769
|
+
@subscribers << agent unless @subscribers.include?(agent)
|
770
|
+
end
|
771
|
+
|
772
|
+
private
|
773
|
+
|
774
|
+
def process_message(message)
|
775
|
+
case message[:type]
|
776
|
+
when :request_help
|
777
|
+
provide_assistance(message)
|
778
|
+
when :share_findings
|
779
|
+
incorporate_findings(message)
|
780
|
+
when :coordinate
|
781
|
+
coordinate_action(message)
|
782
|
+
end
|
783
|
+
end
|
784
|
+
end
|
785
|
+
|
786
|
+
# Create communicating agents
|
787
|
+
lead_analyst = CommunicatingAgent.new(
|
788
|
+
name: "lead_analyst",
|
789
|
+
role: "Lead Data Analyst"
|
790
|
+
)
|
791
|
+
|
792
|
+
junior_analyst = CommunicatingAgent.new(
|
793
|
+
name: "junior_analyst",
|
794
|
+
role: "Junior Analyst"
|
795
|
+
)
|
796
|
+
|
797
|
+
# Set up communication
|
798
|
+
junior_analyst.subscribe(lead_analyst)
|
799
|
+
|
800
|
+
# Agents can now communicate during execution
|
801
|
+
junior_analyst.send_message(lead_analyst, {
|
802
|
+
type: :request_help,
|
803
|
+
priority: :high,
|
804
|
+
content: "Need help with statistical analysis"
|
805
|
+
})
|
806
|
+
```
|
807
|
+
|
808
|
+
### Collaborative Decision Making
|
809
|
+
|
810
|
+
```ruby
|
811
|
+
class CollaborativeAgent < RCrewAI::Agent
|
812
|
+
def make_collaborative_decision(decision_context, collaborators)
|
813
|
+
# Gather input from all collaborators
|
814
|
+
inputs = collaborators.map do |agent|
|
815
|
+
{
|
816
|
+
agent: agent.name,
|
817
|
+
opinion: get_agent_opinion(agent, decision_context),
|
818
|
+
confidence: get_confidence_level(agent, decision_context)
|
819
|
+
}
|
820
|
+
end
|
821
|
+
|
822
|
+
# Synthesize decision
|
823
|
+
synthesize_collaborative_decision(inputs, decision_context)
|
824
|
+
end
|
825
|
+
|
826
|
+
private
|
827
|
+
|
828
|
+
def get_agent_opinion(agent, context)
|
829
|
+
# Request opinion from agent
|
830
|
+
prompt = "Given context: #{context}, what is your recommendation?"
|
831
|
+
|
832
|
+
# Simulate agent providing opinion based on expertise
|
833
|
+
if agent.respond_to?(:provide_opinion)
|
834
|
+
agent.provide_opinion(context)
|
835
|
+
else
|
836
|
+
"No opinion"
|
837
|
+
end
|
838
|
+
end
|
839
|
+
|
840
|
+
def synthesize_collaborative_decision(inputs, context)
|
841
|
+
# Weight opinions by confidence
|
842
|
+
weighted_opinions = inputs.map do |input|
|
843
|
+
{
|
844
|
+
opinion: input[:opinion],
|
845
|
+
weight: input[:confidence]
|
846
|
+
}
|
847
|
+
end
|
848
|
+
|
849
|
+
# Find consensus or synthesize
|
850
|
+
if unanimous?(weighted_opinions)
|
851
|
+
weighted_opinions.first[:opinion]
|
852
|
+
else
|
853
|
+
create_consensus(weighted_opinions, context)
|
854
|
+
end
|
855
|
+
end
|
856
|
+
end
|
857
|
+
```
|
858
|
+
|
859
|
+
## Error Handling and Recovery
|
860
|
+
|
861
|
+
Advanced error handling strategies for robust agent operation.
|
862
|
+
|
863
|
+
### Graceful Degradation
|
864
|
+
|
865
|
+
```ruby
|
866
|
+
class ResilientAgent < RCrewAI::Agent
|
867
|
+
def execute_task(task)
|
868
|
+
attempt_with_fallbacks(task)
|
869
|
+
end
|
870
|
+
|
871
|
+
private
|
872
|
+
|
873
|
+
def attempt_with_fallbacks(task)
|
874
|
+
strategies = [
|
875
|
+
-> { execute_with_all_tools(task) },
|
876
|
+
-> { execute_with_essential_tools(task) },
|
877
|
+
-> { execute_with_no_tools(task) },
|
878
|
+
-> { provide_best_effort_response(task) }
|
879
|
+
]
|
880
|
+
|
881
|
+
strategies.each_with_index do |strategy, i|
|
882
|
+
begin
|
883
|
+
@logger.info "Attempting strategy #{i + 1}"
|
884
|
+
return strategy.call
|
885
|
+
rescue => e
|
886
|
+
@logger.warn "Strategy #{i + 1} failed: #{e.message}"
|
887
|
+
next
|
888
|
+
end
|
889
|
+
end
|
890
|
+
|
891
|
+
"Unable to complete task after all strategies"
|
892
|
+
end
|
893
|
+
|
894
|
+
def execute_with_essential_tools(task)
|
895
|
+
# Disable non-essential tools
|
896
|
+
essential_tools = tools.select { |t| t.essential? }
|
897
|
+
with_tools(essential_tools) do
|
898
|
+
super(task)
|
899
|
+
end
|
900
|
+
end
|
901
|
+
|
902
|
+
def execute_with_no_tools(task)
|
903
|
+
# Pure reasoning without tools
|
904
|
+
with_tools([]) do
|
905
|
+
super(task)
|
906
|
+
end
|
907
|
+
end
|
908
|
+
end
|
909
|
+
```
|
910
|
+
|
911
|
+
### Self-Healing Agents
|
912
|
+
|
913
|
+
```ruby
|
914
|
+
class SelfHealingAgent < RCrewAI::Agent
|
915
|
+
def initialize(**options)
|
916
|
+
super
|
917
|
+
@health_monitor = HealthMonitor.new(self)
|
918
|
+
@recovery_strategies = {}
|
919
|
+
end
|
920
|
+
|
921
|
+
def execute_task(task)
|
922
|
+
@health_monitor.check_health
|
923
|
+
|
924
|
+
begin
|
925
|
+
result = super
|
926
|
+
@health_monitor.record_success
|
927
|
+
result
|
928
|
+
rescue => e
|
929
|
+
@health_monitor.record_failure(e)
|
930
|
+
|
931
|
+
if @health_monitor.needs_healing?
|
932
|
+
perform_self_healing
|
933
|
+
retry
|
934
|
+
else
|
935
|
+
raise
|
936
|
+
end
|
937
|
+
end
|
938
|
+
end
|
939
|
+
|
940
|
+
private
|
941
|
+
|
942
|
+
def perform_self_healing
|
943
|
+
@logger.info "Performing self-healing procedures"
|
944
|
+
|
945
|
+
# Clear corrupted memory
|
946
|
+
if @health_monitor.memory_corrupted?
|
947
|
+
@memory.clear_corrupted_entries
|
948
|
+
end
|
949
|
+
|
950
|
+
# Reset tool connections
|
951
|
+
if @health_monitor.tools_failing?
|
952
|
+
reset_tool_connections
|
953
|
+
end
|
954
|
+
|
955
|
+
# Adjust parameters
|
956
|
+
if @health_monitor.performance_degraded?
|
957
|
+
optimize_parameters
|
958
|
+
end
|
959
|
+
|
960
|
+
@health_monitor.reset
|
961
|
+
end
|
962
|
+
|
963
|
+
def optimize_parameters
|
964
|
+
# Dynamically adjust agent parameters
|
965
|
+
self.max_iterations = [max_iterations - 2, 3].max
|
966
|
+
self.max_execution_time = max_execution_time * 1.5
|
967
|
+
|
968
|
+
@logger.info "Adjusted parameters for better performance"
|
969
|
+
end
|
970
|
+
end
|
971
|
+
```
|
972
|
+
|
973
|
+
## Best Practices
|
974
|
+
|
975
|
+
### 1. **Agent Design Principles**
|
976
|
+
- Single Responsibility: Each agent should have one clear role
|
977
|
+
- Clear Goals: Define specific, measurable goals
|
978
|
+
- Rich Backstories: Provide context that guides behavior
|
979
|
+
- Appropriate Tools: Equip agents with necessary tools only
|
980
|
+
|
981
|
+
### 2. **Performance Guidelines**
|
982
|
+
- Set reasonable iteration limits (5-10 for most tasks)
|
983
|
+
- Use timeouts to prevent hanging (60-300 seconds typical)
|
984
|
+
- Cache expensive operations when possible
|
985
|
+
- Use async execution for independent tasks
|
986
|
+
|
987
|
+
### 3. **Memory Management**
|
988
|
+
- Implement memory cleanup for long-running agents
|
989
|
+
- Persist valuable memory across sessions
|
990
|
+
- Limit memory size to prevent bloat
|
991
|
+
- Use memory statistics for optimization
|
992
|
+
|
993
|
+
### 4. **Delegation Best Practices**
|
994
|
+
- Managers should have broad understanding, not deep expertise
|
995
|
+
- Delegate based on agent strengths and availability
|
996
|
+
- Provide clear context in delegations
|
997
|
+
- Monitor delegation success rates
|
998
|
+
|
999
|
+
### 5. **Error Handling**
|
1000
|
+
- Implement graceful degradation strategies
|
1001
|
+
- Log errors with context for debugging
|
1002
|
+
- Use retry logic with exponential backoff
|
1003
|
+
- Provide fallback responses
|
1004
|
+
|
1005
|
+
## Next Steps
|
1006
|
+
|
1007
|
+
Now that you understand advanced agent configuration:
|
1008
|
+
|
1009
|
+
1. Try the [Custom Tools Development]({{ site.baseurl }}/tutorials/custom-tools) tutorial
|
1010
|
+
2. Learn about [Working with Multiple Crews]({{ site.baseurl }}/tutorials/multiple-crews)
|
1011
|
+
3. Explore [Production Deployment]({{ site.baseurl }}/tutorials/deployment) strategies
|
1012
|
+
4. Review [API Documentation]({{ site.baseurl }}/api/) for detailed reference
|
1013
|
+
|
1014
|
+
Advanced agents are the key to building sophisticated AI systems that can handle complex, real-world tasks with reliability and efficiency.
|