Creating Agents - Detailed Guide
Complete Agent Guide
Learn how to create type-safe AI agents with Django integration. This guide covers everything from basic agents to advanced patterns with tools and error handling.
Agent Anatomy
Every agent consists of 4 parts:
agent = DjangoAgent[DepsT, OutputT](
name="my_agent", # 1. Name (unique)
deps_type=DjangoDeps, # 2. Dependencies type
output_type=MyResult, # 3. Result type
instructions="Do this..." # 4. Instructions for LLM
)
Type Safety
The DjangoAgent[DepsT, OutputT] pattern provides full type safety - your IDE will autocomplete and type-check all inputs and outputs.
1. Defining Types
Dependencies (DjangoDeps)
from dataclasses import dataclass
from django_cfg import DjangoDeps
# Basic dependencies (ready to use)
deps = DjangoDeps(user_id=123)
user = await deps.get_user() # Get User object
# Extended dependencies
@dataclass
class ContentDeps(DjangoDeps):
content_id: int
category: str = "general"
async def get_content(self):
return await Content.objects.aget(id=self.content_id)
Results (Pydantic Models)
from pydantic import BaseModel, Field
from typing import List, Optional
class ContentAnalysis(BaseModel):
sentiment: str = Field(..., description="positive/negative/neutral")
keywords: List[str] = Field(default_factory=list)
summary: str = Field(..., max_length=500)
confidence: float = Field(..., ge=0, le=1)
class ProcessingResult(BaseModel):
success: bool
message: str
data: Optional[dict] = None
errors: List[str] = Field(default_factory=list)
2. Creating Agent
- Simple Agent
- Advanced Agent
- Specialized Agents
Simple Agent
from django_cfg import DjangoAgent, DjangoDeps, RunContext
# Create agent
summarizer = DjangoAgent[DjangoDeps, ProcessingResult](
name="content_summarizer",
deps_type=DjangoDeps,
output_type=ProcessingResult,
instructions="""
You are a content summarizer.
Create concise, informative summaries of text content.
Always return success=True if summary was created.
"""
)
Simple Agent Use Cases
Simple agents are ideal for:
- Content summarization - Quick summaries
- Sentiment analysis - Basic text analysis
- Classification - Categorize content
- Translation - Simple text translation
When to use:
- Single-purpose tasks
- No database access needed
- Fast execution required
Agent with Settings
advanced_agent = DjangoAgent[ContentDeps, ContentAnalysis](
name="content_analyzer",
deps_type=ContentDeps,
output_type=ContentAnalysis,
instructions="Analyze content for sentiment and extract keywords",
model="openai:gpt-4o", # Specific model
timeout=120, # 2 minute timeout
max_retries=2, # Maximum 2 attempts
enable_caching=True # Enable caching
)
Advanced Agent Configuration
Configuration options:
model- Specific LLM model to usetimeout- Maximum execution time (seconds)max_retries- Retry failed executionsenable_caching- Cache responses (80% cost reduction)temperature- Creativity level (0-1)max_tokens- Response length limit
Best practices:
- ✅ Use GPT-4o for complex reasoning
- ✅ Use GPT-4o-mini for simple tasks (10x cheaper)
- ✅ Enable caching for repeated queries
- ✅ Set reasonable timeouts (30-120s)
Specialized Agent Types
Content Processing Agent:
content_processor = DjangoAgent[ContentDeps, ProcessingResult](
name="content_processor",
instructions="Process and transform content based on rules",
model="gpt-4o-mini", # Cost-effective for processing
timeout=60
)
Customer Support Agent:
support_agent = DjangoAgent[SupportDeps, SupportResponse](
name="support_agent",
instructions="Provide helpful customer support responses",
model="gpt-4o", # Better understanding for support
temperature=0.7, # More natural responses
timeout=90
)
Data Analysis Agent:
analyst_agent = DjangoAgent[AnalysisDeps, AnalysisReport](
name="data_analyst",
instructions="Analyze data and generate insights",
model="gpt-4o", # Complex reasoning needed
timeout=180, # Longer timeout for analysis
enable_caching=True
)
Choosing the Right Agent Type
By task complexity:
- Simple (summarize, classify) → gpt-4o-mini, 30s timeout
- Medium (analyze, extract) → gpt-4o-mini, 60s timeout
- Complex (reasoning, multi-step) → gpt-4o, 120s+ timeout
By cost priority:
- High volume, simple → gpt-4o-mini ($0.001/call)
- Low volume, complex → gpt-4o ($0.01/call)
- Balance → gpt-4o-mini with caching ($0.0002/call)
3. Adding Tools
Basic Tools
@summarizer.tool
async def get_content_by_id(ctx: RunContext[DjangoDeps], content_id: int) -> str:
"""Get content by ID."""
try:
content = await Content.objects.aget(id=content_id)
return content.text
except Content.DoesNotExist:
return f"Content with ID {content_id} not found"
@summarizer.tool
async def save_summary(ctx: RunContext[DjangoDeps], content_id: int, summary: str) -> str:
"""Save summary."""
content = await Content.objects.aget(id=content_id)
content.summary = summary
await content.asave()
return f"Summary saved for content {content_id}"
Tools with Permissions
@advanced_agent.tool
async def get_user_content(ctx: RunContext[ContentDeps]) -> str:
"""Get user content with permission check."""
user = await ctx.deps.get_user()
content = await ctx.deps.get_content()
# Permission check
if content.user != user and not content.is_public:
raise PermissionError("Access denied to private content")
return content.text
@advanced_agent.tool
async def update_content_metadata(
ctx: RunContext[ContentDeps],
keywords: List[str],
sentiment: str
) -> str:
"""Update content metadata."""
content = await ctx.deps.get_content()
user = await ctx.deps.get_user()
# Only owner can update
if content.user != user:
return "Permission denied"
content.keywords = keywords
content.sentiment = sentiment
content.analyzed_at = timezone.now()
await content.asave()
return f"Updated metadata for content {content.id}"
Tools for External APIs
@advanced_agent.tool
async def search_related_content(ctx: RunContext[ContentDeps], query: str) -> str:
"""Find related content."""
from django.db.models import Q
# Search by keywords
related = await Content.objects.filter(
Q(title__icontains=query) | Q(keywords__contains=[query])
).exclude(id=ctx.deps.content_id)[:5].aall()
if not related:
return "No related content found"
results = []
for content in related:
results.append(f"- {content.title} (ID: {content.id})")
return "Related content:\n" + "\n".join(results)
@advanced_agent.tool
async def call_external_api(ctx: RunContext[ContentDeps], endpoint: str) -> str:
"""Call external API."""
import httpx
async with httpx.AsyncClient() as client:
try:
response = await client.get(f"https://api.example.com/{endpoint}")
return response.text
except Exception as e:
return f"API call failed: {e}"
4. Using Agents
Simple Execution
async def analyze_content(request, content_id):
# Create dependencies
deps = ContentDeps(
user_id=request.user.id,
content_id=content_id,
category="article"
)
# Run agent
result = await advanced_agent.run(
prompt=f"Analyze content {content_id} for sentiment and keywords",
deps=deps
)
# Check result
if result.output.confidence > 0.8:
return JsonResponse({
'sentiment': result.output.sentiment,
'keywords': result.output.keywords,
'summary': result.output.summary
})
else:
return JsonResponse({'error': 'Low confidence analysis'}, status=400)
With Error Handling
from django_cfg.modules.django_orchestrator import ExecutionError
async def safe_content_analysis(request, content_id):
deps = ContentDeps(user_id=request.user.id, content_id=content_id)
try:
result = await advanced_agent.run(
prompt="Analyze this content thoroughly",
deps=deps
)
# Log successful execution
logger.info(f"Analysis completed for content {content_id}")
return JsonResponse({
'success': True,
'data': result.output.dict(),
'execution_time': result.execution_time,
'tokens_used': result.tokens_used
})
except ExecutionError as e:
logger.error(f"Agent execution failed: {e}")
return JsonResponse({
'success': False,
'error': str(e)
}, status=500)
except PermissionError as e:
return JsonResponse({
'success': False,
'error': 'Access denied'
}, status=403)
5. Metrics and Monitoring
Getting Agent Metrics
# Metrics for specific agent
metrics = advanced_agent.get_metrics()
print(f"Executions: {metrics['execution_count']}")
print(f"Avg time: {metrics['avg_execution_time']:.2f}s")
print(f"Error rate: {metrics['error_rate']:.1%}")
print(f"Cache hit rate: {metrics['cache_hit_rate']:.1%}")
Monitoring in Django Admin
- Go to
/admin/django_orchestrator/agentexecution/ - See all agent runs:
- Execution time
- Tokens used
- Cost
- Status (success/error)
- Input and output data
6. Best Practices
✅ Good
# Create agents at module level (once)
content_agent = DjangoAgent[ContentDeps, ContentAnalysis](...)
# Use typing
async def process_content(ctx: RunContext[ContentDeps]) -> str:
content = await ctx.deps.get_content()
return content.text
# Handle errors
try:
result = await agent.run(prompt, deps)
except ExecutionError:
# handle error
❌ Bad
# Create agents in view (every time)
def my_view(request):
agent = DjangoAgent(...) # Slow!
# Ignore types
def get_data(ctx) -> str: # No typing
return "data"
# Don't handle errors
result = await agent.run(prompt, deps) # Can crash
What's Next?
- Orchestration - Coordinating multiple agents
- Django Integration - Admin, signals, middleware
- Examples - Real-world use cases