What is @after_llm_call_crew?
After the provider returns, CrewAI invokes @after_llm_call_crew handlers with an LLMCallHookContext that now includes the assistant text (and usage metadata when available). Use this stage to strip secrets accidentally echoed by the model, clamp JSON to a schema-friendly subset, append citations, or stream derived metrics to your observability stack. Returning a string replaces the response agents and tasks see; returning None preserves the original.
Because this runs on every completion — including tool-planning calls — keep transformations deterministic and fast. Heavy moderation models should be routed to asynchronous review queues instead of blocking the next agent step. Combine with sanitize_llm_response utilities when you want shared redaction logic across crews.
When guardrails already fail a task, after hooks may still see partial output depending on failure mode; never assume success purely because the hook fired.
When to Use
Output filtering, response transformation, token accounting.
Use Cases
- • Output sanitization
- • Telemetry
- • Token tracking
Key Features
- ✓ Crew-scoped
- ✓ Receives full response
- ✓ Composable with sanitize_llm_response()
When NOT to Use
Per-task validation — use Task.guardrail instead.
Notes
Streaming
Streaming completions may invoke hooks with partial buffers. Gate expensive logic on final chunks or inspect framework flags when available.
Double transforms
Stacking multiple after hooks can distort text unexpectedly. Document ordering and add golden-file tests for critical prompts.
Error swallowing
Throwing here can mask upstream failures. Prefer log-and-return-original when sanitization cannot parse the payload.
Import
from crewai.hooks import after_llm_call_crew
How to Apply
@after_llm_call_crew
def log(ctx):
tracer.log(ctx.response)
What It Enables
- ✓ Response scrubbing
- ✓ Metric collection
Code Examples
Sanitize
@after_llm_call_crew
def clean(ctx):
return scrub(ctx.response)
Structured JSON repair
@after_llm_call_crew
def coerce(ctx):
try:
json.loads(ctx.response)
return None
except Exception:
return '{"error":"invalid_json"}'
Token metrics
@after_llm_call_crew
def usage(ctx):
u = getattr(ctx, 'usage', None)
if u:
meter.record(u.total_tokens)
return None
Integration Patterns
Pairs with @before_llm_call_crew
Common Mistakes
❌ Throwing on unparseable JSON
✅ Log + return the original string so downstream guardrails can retry.
Related: Task class reference, Agent class reference, and the first Crew tutorial.
@after_llm_call_crew FAQ
What is @after_llm_call_crew in CrewAI?
Runs after every LLM call within the crew — transform, validate, or log the response. After the provider returns, CrewAI invokes @after_llm_call_crew handlers with an LLMCallHookContext that now includes the assistant text (and usage metadata when available). Use this stage to strip secrets accidentally echoed by the model, clamp JSON to a schema-friendly subset, append citations, or stream derived metrics to your observability stack. Returning a string replaces the response agents and tasks see; returning None preserves the original. Because this runs on eve…
Which module defines the CrewAI decorator @after_llm_call_crew?
DevShelfHub maps @after_llm_call_crew to Python module crewai.hooks. Pin your installed crewai version and match imports to the import snippet on this page.
When should I use @after_llm_call_crew?
Output filtering, response transformation, token accounting.
When should I avoid @after_llm_call_crew?
Per-task validation — use Task.guardrail instead.
How do I apply @after_llm_call_crew in Python?
@after_llm_call_crew def log(ctx): tracer.log(ctx.response)
Where can I explore more CrewAI API reference pages?
Open the CrewAI API reference index on DevShelfHub to search classes, methods, and decorators, each with runnable examples, parameters, common mistakes, and cross-links.