A production-ready financial analysis agent built with LangGraph, featuring RAG over Amazon earnings reports, real-time stock data, AWS deployment with Terraform, and Cognito authentication.
- LangGraph Agent: Intelligent agent with tool calling and reasoning
- Stock Analysis Tools: Real-time and historical stock prices via yfinance
- RAG System: Semantic search over Amazon Q2 and Q3 2025 earnings reports
- Event Streaming: Responses streamed via
.astream() - AWS Cognito: Secure user authentication
- Langfuse Tracing: Complete observability of agent interactions
- Terraform Infrastructure: Automated AWS deployment
User Request
↓
AWS Cognito Authentication
↓
API Gateway (with Cognito Authorizer)
↓
AWS Lambda (Financial Agent)
↓
LangGraph Agent
├── retrieve_realtime_stock_price (yfinance)
├── retrieve_historical_stock_price (yfinance)
└── search_amazon_reports (RAG/FAISS)
↓
Langfuse Tracing
↓
Response
- Python 3.11+
- AWS Account with CLI configured
- Terraform >= 1.0
- OpenAI API Key
- Langfuse Account (free at https://cloud.langfuse.com)
cd teste
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txtCopy .env.example to .env and fill in your credentials:
cp .env.example .envEdit .env:
OPENAI_API_KEY=sk-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_HOST=https://cloud.langfuse.com
AWS_REGION=us-east-1python local_test.pyThis will:
- Download Amazon earnings PDFs
- Create FAISS vector store
- Run test queries locally
cd terraform
cp terraform.tfvars.example terraform.tfvarsEdit terraform.tfvars with your values:
aws_region = "us-east-1"
project_name = "financial-agent"
environment = "prod"
openai_api_key = "sk-..."
langfuse_secret_key = "sk-lf-..."
langfuse_public_key = "pk-lf-..."On Linux/Mac:
chmod +x scripts/*.sh
./scripts/deploy.shOn Windows:
.\scripts\deploy.ps1This will:
- Build Lambda deployment package
- Initialize Terraform
- Create AWS resources:
- Lambda function
- API Gateway with Cognito authorizer
- Cognito User Pool
- S3 bucket for deployment
- Output deployment details
After deployment, create a test user:
# Get outputs from Terraform
cd terraform
terraform output
# Create user
aws cognito-idp admin-create-user \
--user-pool-id <COGNITO_USER_POOL_ID> \
--username your-email@example.com \
--user-attributes Name=email,Value=your-email@example.com \
--message-action SUPPRESS
# Set permanent password
aws cognito-idp admin-set-user-password \
--user-pool-id <COGNITO_USER_POOL_ID> \
--username your-email@example.com \
--password YourSecurePassword123! \
--permanentAdd the deployment outputs to your .env:
API_ENDPOINT=https://xxxxx.execute-api.us-east-1.amazonaws.com/prod/query
COGNITO_USER_POOL_ID=us-east-1_xxxxx
COGNITO_CLIENT_ID=xxxxxxxxxxxxxjupyter notebook demo_notebook.ipynbThe notebook will:
- Authenticate with Cognito
- Execute all test queries
- Display responses
- Show Langfuse traces
The system handles these queries (as per requirements):
- Real-time Price: "What is the stock price for Amazon right now?"
- Historical Data: "What were the stock prices for Amazon in Q4 last year?"
- Performance Analysis: "Compare Amazon's recent stock performance to what analysts predicted in their reports"
- AI Business Research: "I'm researching AMZN give me the current price and any relevant information about their AI business"
- Office Space: "What is the total amount of office space Amazon owned in North America in 2024?"
teste/
├── src/
│ ├── __init__.py
│ ├── agent.py # LangGraph agent implementation
│ ├── tools.py # Stock price tools (yfinance)
│ ├── rag.py # RAG system for Amazon reports
│ └── lambda_handler.py # AWS Lambda handler
├── terraform/
│ ├── main.tf # Main infrastructure
│ ├── variables.tf # Input variables
│ ├── outputs.tf # Output values
│ └── terraform.tfvars # Your configuration
├── scripts/
│ ├── build_lambda.sh # Build Lambda package (Linux/Mac)
│ ├── build_lambda.ps1 # Build Lambda package (Windows)
│ ├── deploy.sh # Full deployment (Linux/Mac)
│ └── deploy.ps1 # Full deployment (Windows)
├── demo_notebook.ipynb # Demo with all test queries
├── local_test.py # Local testing script
├── requirements.txt # Python dependencies
├── .env.example # Environment template
└── README.md # This file
- Uses yfinance API
- Returns current price, market cap, day range, volume
- Example:
retrieve_realtime_stock_price("AMZN")
- Uses yfinance API
- Supports date ranges or periods (1mo, 3mo, 1y, ytd)
- Returns price statistics and changes
- Example:
retrieve_historical_stock_price("AMZN", period="3mo")
- Searches Amazon Q2 and Q3 2025 earnings reports
- Uses FAISS vector store with OpenAI embeddings
- Returns relevant document chunks with sources
All agent interactions are traced in Langfuse:
- Go to https://cloud.langfuse.com
- View your project
- See traces for:
- LLM calls
- Tool invocations
- Token usage
- Latency metrics
- Full conversation flow
- Lambda Function: Runs the financial agent (Python 3.11, 1GB RAM, 5min timeout)
- API Gateway: REST API with Cognito authorization
- Cognito User Pool: User authentication and management
- S3 Bucket: Stores Lambda deployment package
- IAM Roles: Lambda execution role with necessary permissions
- Lambda: ~$0.20 per 1M requests + compute time
- API Gateway: ~$3.50 per 1M requests
- Cognito: Free tier covers 50,000 MAUs
- S3: Minimal storage costs
The agent uses LangGraph's .astream() for event streaming:
async for event in agent.astream(query):
# Process streaming events
messages = event.get('messages', [])
# Handle each eventEvents are filtered by LLM invocation as per LangGraph documentation.
If the Lambda package exceeds 50MB:
- Use Lambda Layers for heavy dependencies
- Or deploy via S3 (already configured in Terraform)
If PDF download fails:
- Check internet connection
- Manually download PDFs to
pdfs/directory - Run
local_test.pyto create vector store
- Ensure user is confirmed
- Check password meets requirements (8+ chars, uppercase, lowercase, number, symbol)
- Verify client ID and user pool ID are correct
- Verify API keys in
.env - Check Langfuse project is active
- Ensure callbacks are passed to LLM initialization
- Define tool in
src/tools.py:
@tool
def my_new_tool(param: str) -> str:
"""Tool description"""
# Implementation
return result- Add to agent in
src/agent.py:
self.tools = [
retrieve_realtime_stock_price,
retrieve_historical_stock_price,
self.rag_tool,
my_new_tool # Add here
]- Add PDFs to
pdfs/directory - Update
src/rag.pyto include new sources - Rebuild vector store
To destroy all AWS resources:
cd terraform
terraform destroyMIT
For issues or questions:
- Check the troubleshooting section
- Review Langfuse traces for debugging
- Check CloudWatch logs for Lambda errors
- LangChain/LangGraph for agent framework
- OpenAI for LLM capabilities
- Langfuse for observability
- yfinance for stock data
- AWS for infrastructure