A multi-agent content generation system built with LangGraph and Amazon Bedrock that creates high-quality, audience-specific content through iterative refinement.
This project implements a sophisticated multi-agent workflow using:
- LangGraph: Orchestrates the multi-agent workflow with conditional routing
- Amazon Bedrock: Powers Claude 3.7 Sonnet for content generation and analysis
- FastAPI: Serves the application with both HTTP and direct invocation support
- AWS Lambda: Serverless deployment with container images
- Amazon S3: Stores generated content with KMS encryption
The system follows a structured multi-agent workflow with conditional routing:
- Input Processing: User provides topic, audience, and format requirements
- Audience Analysis: Analyzes target audience demographics, knowledge level, and preferences
- Research Phase: Generates relevant research insights using Amazon Bedrock
- Content Planning: Creates structured outline based on research and audience analysis
- Content Generation: Writer agent creates initial draft following the plan
- Quality Evaluation: Quality gate assesses content against criteria:
- Audience appropriateness
- Factual accuracy
- Engagement level
- Format compliance
- Conditional Routing:
- If quality passes: Route to Synthesis Agent
- If quality fails: Route to Revision Agent β back to Writer
- Content Synthesis: Finalizes content, adds metadata, uploads to S3
- Output: Returns final content with workflow statistics
- Audience Analyzer: Analyzes target audience and creates detailed personas
- Research Agent: Generates relevant, up-to-date research insights using Amazon Bedrock
- Content Planner: Creates structured content outlines based on research
- Writer Agent: Generates initial content drafts
- Quality Gate: Evaluates content quality, relevance, and audience alignment
- Revision Agent: Improves content based on quality feedback
- Synthesis Agent: Finalizes content and handles output formatting
- Python 3.11+
- AWS CLI configured with appropriate permissions
- Access to Amazon Bedrock Claude models
For local development, you MUST create and configure Amazon Bedrock Guardrails:
-
Create Guardrails in AWS Console
- Go to Amazon Bedrock Console β Guardrails
- Create a new guardrail with your desired policies
- Note the Guardrail ID and Version
-
Set Required Environment Variables
export GUARDRAIL_ID=your-guardrail-id # REQUIRED export GUARDRAIL_VERSION=DRAFT # REQUIRED export AWS_PROFILE=your-profile # REQUIRED export AWS_REGION=us-east-1 # REQUIRED
-
Install dependencies
pip install -r requirements.txt
-
Run locally
cd src python main.py
Note: The application will not start without valid guardrail configuration. You are responsible for creating and managing your own guardrails for local development.
- Test the API
curl -X POST http://localhost:8080/generate \ -H "Content-Type: application/json" \ -d '{ "yaml": "topic: AI in healthcare\naudience: medical professionals\naudience_context: doctors and nurses\nformat: research summary" }'
- AWS Account with Bedrock access
- Terraform >= 1.5
- Docker for container builds
- Sufficient IAM permissions for Lambda, S3, ECR and KMS
-
Configure Terraform variables
cd terraform cp terraform.tfvars.example terraform.tfvars
Edit
terraform.tfvars
:project_name = "langgraph-adaptive-content" aws_region = "us-east-1"
-
Initialize and deploy
terraform init terraform plan terraform apply
-
Note the outputs
terraform output lambda_function_name terraform output s3_bucket_name
The Terraform deployment creates:
- Lambda Function: Containerized application with 15-minute timeout
- ECR Repository: Stores Docker images with KMS encryption and immutable tags
- S3 Bucket: Content storage with versioning and KMS encryption
- KMS Key: Single customer-managed key for all encryption needs
- IAM Roles: Least-privilege access for Lambda execution
- CloudWatch Logs: Encrypted log storage with 7-day retention
- Bedrock Guardrails: Automated content safety policies with comprehensive filtering
Asynchronous invocation:
aws lambda invoke \
--function-name langgraph-adaptive-content-content-generator \
--invocation-type Event \
--cli-binary-format raw-in-base64-out \
--payload '{"yaml":"topic: AI in marketing\naudience: beginners\nformat: blog post"}' \
response.json
Create payload.json
:
{
"yaml": "topic: Sustainable technology\naudience: executives\naudience_context: C-suite decision makers\nformat: executive summary"
}
Invoke with file:
aws lambda invoke \
--function-name langgraph-adaptive-content-content-generator \
--invocation-type Event \
--payload fileb://payload.json \
response.json
Check CloudWatch logs:
aws logs filter-log-events \
--log-group-name "/aws/lambda/langgraph-adaptive-content-content-generator" \
--start-time $(date -d '10 minutes ago' +%s)000
List generated content in S3:
aws s3 ls s3://langgraph-adaptive-content-content-<suffix>/generated-content/
The system accepts YAML-formatted input with the following parameters:
topic: "Your content topic" # Required
audience: "Target audience" # Required
audience_context: "Additional audience details" # Optional
format: "Content format (blog post, summary, etc.)" # Optional, defaults to "blog post"
Blog Post:
topic: "Machine Learning in Finance"
audience: "financial analysts"
audience_context: "professionals with basic technical knowledge"
format: "blog post"
Executive Summary:
topic: "Cloud Migration Strategy"
audience: "executives"
audience_context: "C-suite decision makers at mid-size companies"
format: "executive summary"
Technical Guide:
topic: "Kubernetes Security Best Practices"
audience: "DevOps engineers"
audience_context: "experienced with containerization"
format: "technical guide"
- KMS Encryption: All data encrypted with customer-managed keys
- IAM Least Privilege: Minimal required permissions
- VPC Isolation: Optional VPC deployment (disabled by default)
- Immutable Container Images: ECR tags cannot be overwritten
- Secure Parameter Storage: API keys stored in SSM Parameter Store
- Concurrency Limits: Prevents runaway executions
This implementation uses a private subnet + NAT Gateway architecture for secure AWS service access:
- NAT Gateway Dependency: Lambda functions in private subnets require internet access for AWS service calls (Bedrock, S3, KMS)
- NAT Gateway Placement: Must be deployed in a public subnet to route traffic to the Internet Gateway
- Security Isolation: Lambda remains isolated in private subnets while maintaining necessary connectivity
- Simplified Architecture: Reduces infrastructure complexity to focus on the core LangChain agents and Bedrock integration
- Demo Focus: Main objective is showcasing multi-agent workflows with Amazon Bedrock, not advanced networking patterns
- Sufficient Security: NAT Gateway provides secure internet access without compromising Lambda isolation
Lambda (Private Subnet) β NAT Gateway (Public Subnet) β Internet Gateway β AWS Services
- Security Groups: Restrictive egress rules (HTTPS + DNS only)
- Private Subnets: No direct internet access for Lambda functions
- S3 Bucket Policy: Explicit Lambda role permissions required
- IAM Permissions: Granular resource-level access controls
- Vulnerability Scanning: Trivy security scanning blocks deployment of vulnerable images
- Base Image: AWS Lambda Python runtime (regularly updated by AWS)
- Dependency Management: Pinned versions with security updates
- Build-time Scanning: Automated security checks in CI/CD pipeline
- Cold Start: 10-30 seconds (first invocation)
- Warm Execution: 4-6 minutes typical workflow
- Memory Usage: 3008 MB allocated for optimal performance
- Timeout: 15 minutes maximum execution time
- Concurrency: Limited to 10 concurrent executions
βββ src/
β βββ main.py # FastAPI application and Lambda handler
β βββ agents/ # Individual agent implementations
β β βββ audience_analyzer.py
β β βββ research_agent.py
β β βββ content_planner.py
β β βββ quality_gate.py
β β βββ writers/
β βββ workflow/
β βββ content_workflow.py # LangGraph workflow definition
β βββ state_management.py # Workflow state classes
βββ terraform/ # Infrastructure as Code
βββ requirements.txt # Python dependencies
βββ Dockerfile # Container definition
βββ README.md
- Create agent class in
src/agents/
- Implement required methods following existing patterns
- Add agent to workflow in
content_workflow.py
- Update state management if needed
Cold start issues:
- First invocation takes 10-30 seconds
- Subsequent calls within 15 minutes are faster
Permission errors:
- Verify IAM roles have required permissions
- Check KMS key policy allows Lambda role access
ECR image issues:
- Ensure Docker is running during deployment
- Check ECR repository exists and image is pushed
# Check Lambda function status
aws lambda get-function --function-name langgraph-adaptive-content-content-generator
# View recent logs
aws logs tail /aws/lambda/langgraph-adaptive-content-content-generator --follow
# Test Bedrock access
aws bedrock list-foundation-models --region us-east-1