Back
AI Engineering··10 min

Building a Stock Prediction AI Agent with LangGraph: A Step-by-Step Guide

Learn how to build a production-ready AI agent for stock price prediction using LangGraph, LangChain, and OpenAI. Complete tutorial with code examples and real-world implementation.

Building a Stock Prediction AI Agent with LangGraph: A Step-by-Step Guide#

Want to build an AI agent that can search for stock data and make predictions? LangGraph makes it surprisingly straightforward to create sophisticated AI agents with custom tools and graph-based workflows.

In this tutorial, I'll walk you through building a stock prediction agent that:

  • 🔍 Searches for real stock data using Yahoo Finance
  • 📊 Analyzes historical trends
  • 🤖 Makes price predictions using LLM reasoning
  • 🔁 Chains multiple tools together intelligently

By the end, you'll have a working agent and understand how to build your own custom AI agents for any domain.


What is LangGraph?#

LangGraph is a framework from LangChain for building stateful, multi-actor applications with LLMs. Think of it as a way to create AI agents that can:

  • Use multiple tools sequentially or in parallel
  • Maintain state across interactions
  • Make decisions about which tools to use
  • Chain complex reasoning workflows

Why LangGraph over simple LLM calls?#

Traditional LLM CallLangGraph Agent
Single input → outputMulti-step reasoning
No tool useMultiple tool integrations
StatelessStateful conversations
Linear flowGraph-based workflows
Limited to textActions in real world

Perfect for: Financial analysis, research assistants, customer service bots, data analysis pipelines, and more.


What We're Building#

The Stock Prediction Agent Architecture#

User Input: "Predict AAPL stock price"
        ↓
    [LangGraph Agent]
        ↓
   Tool Selection
        ↓
    ┌───────────┬──────────────┐
    ↓           ↓              ↓
[Search Tool] [Predict Tool] [Analysis]
    ↓           ↓              ↓
Yahoo Finance  ML Model    GPT Reasoning
        ↓
  Final Prediction

Key Components#

  1. Agent Core (agent.py) - LangGraph workflow orchestration
  2. Tools (tools.py) - Stock search & prediction functions
  3. Model (model.py) - Prediction logic (easily extendable to ML models)
  4. LLM - GPT-4o for reasoning and tool selection

Prerequisites#

What you need:

  • Python 3.10+
  • OpenAI API key
  • Basic understanding of Python and APIs
  • 10 minutes to follow along

No prior LangGraph experience required! This tutorial assumes you're starting from scratch.


Step 1: Project Setup#

Install Dependencies#

I use uv for fast dependency management, but pip works too:

# Using uv (recommended - much faster!)
uv venv --python 3.10
uv sync

# Or using traditional pip
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install langgraph langchain openai yfinance python-dotenv

Project Structure#

stock-agent/
├── agent.py          # LangGraph agent definition
├── tools.py          # Custom tools (search, predict)
├── model.py          # Prediction logic
├── .env             # API keys
└── pyproject.toml   # Dependencies

Configure Environment#

Create .env:

OPENAI_API_KEY=your_openai_api_key_here

Security tip: Never commit .env to git! Add it to .gitignore.


Step 2: Building Custom Tools#

Tools are functions your agent can call. Let's create two tools:

File: tools.py

import yfinance as yf
from langchain.tools import tool

@tool
def search_stock_data(symbol: str) -> dict:
    """
    Fetch historical stock data for a given symbol.

    Args:
        symbol: Stock ticker symbol (e.g., 'AAPL', 'TSLA')

    Returns:
        Dictionary with historical prices and metadata
    """
    try:
        stock = yf.Ticker(symbol)
        # Get last 5 days of data
        hist = stock.history(period="5d")

        if hist.empty:
            return {"error": f"No data found for symbol {symbol}"}

        return {
            "symbol": symbol,
            "current_price": round(hist['Close'].iloc[-1], 2),
            "5d_high": round(hist['High'].max(), 2),
            "5d_low": round(hist['Low'].min(), 2),
            "5d_avg": round(hist['Close'].mean(), 2),
            "5d_prices": hist['Close'].tolist()
        }
    except Exception as e:
        return {"error": str(e)}

What's happening here:

  • @tool decorator makes this function callable by the agent
  • Uses yfinance to fetch real stock data from Yahoo Finance
  • Returns structured data the LLM can reason about
  • Includes error handling for invalid symbols

Tool 2: Price Prediction#

from model import predict_next_price

@tool
def predict_stock_price(symbol: str, historical_data: list) -> dict:
    """
    Predict next day's stock price using historical data.

    Args:
        symbol: Stock ticker symbol
        historical_data: List of recent closing prices

    Returns:
        Dictionary with prediction and confidence
    """
    try:
        if not historical_data or len(historical_data) < 2:
            return {"error": "Insufficient data for prediction"}

        predicted_price = predict_next_price(historical_data)

        return {
            "symbol": symbol,
            "predicted_price": round(predicted_price, 2),
            "method": "5-day moving average",
            "confidence": "medium"  # Can be enhanced with real ML model
        }
    except Exception as e:
        return {"error": str(e)}

Step 3: Simple Prediction Model#

For now, we'll use a simple moving average. You can replace this with LSTM, XGBoost, or any ML model!

File: model.py

def predict_next_price(prices: list[float]) -> float:
    """
    Predict next price using simple moving average.

    In production, replace with:
    - LSTM neural network
    - XGBoost model
    - Prophet for time series
    - Fine-tuned transformer
    """
    if not prices:
        return 0.0

    # Simple 5-day moving average
    return sum(prices[-5:]) / min(len(prices), 5)

💡 Pro Tip: This is intentionally simple to keep the tutorial focused on LangGraph. For real trading, use proper ML models with backtesting!


Step 4: Building the LangGraph Agent#

Here's where the magic happens! LangGraph orchestrates the tools and LLM.

File: agent.py

from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
from tools import search_stock_data, predict_stock_price
import os
from dotenv import load_dotenv

load_dotenv()

# Initialize LLM
llm = ChatOpenAI(
    model="gpt-4o",
    temperature=0.1,  # Low temperature for consistent predictions
    api_key=os.getenv("OPENAI_API_KEY")
)

# Create agent with tools
agent = create_react_agent(
    llm,
    tools=[search_stock_data, predict_stock_price],
    state_modifier="""You are a financial analysis agent.

When asked to predict a stock price:
1. First use search_stock_data to get historical data
2. Then use predict_stock_price with that data
3. Provide a clear summary with the prediction and reasoning

Always cite the data you used and explain your prediction."""
)

def run_agent(stock_symbol: str) -> dict:
    """
    Run the agent to predict stock price.

    Args:
        stock_symbol: Stock ticker (e.g., 'AAPL')

    Returns:
        Agent's response with prediction
    """
    query = f"Predict the next day's closing price for {stock_symbol}"

    result = agent.invoke({
        "messages": [("user", query)]
    })

    return result

if __name__ == "__main__":
    # Example usage
    result = run_agent("AAPL")
    print("\n=== Agent Response ===")
    print(result["messages"][-1].content)

Understanding the Code#

create_react_agent:

  • "ReAct" = Reasoning + Acting pattern
  • Agent reasons about what to do, then acts (uses tools)
  • Repeats until it has an answer

state_modifier:

  • System prompt that guides agent behavior
  • Tells agent which tools to use and when
  • Defines output format

invoke:

  • Sends user message to agent
  • Agent decides which tools to call
  • Returns final response

Step 5: Running Your Agent#

Basic Usage#

python agent.py

Example Output:

=== Agent Response ===
Based on my analysis of AAPL stock data:

Current Price: $172.35
5-Day Average: $171.80
5-Day Range: $169.50 - $174.20

Predicted Next-Day Price: $172.15

Reasoning: Using a 5-day moving average model, the predicted price is
slightly below current levels due to recent volatility. The stock has
been trading in a narrow range, suggesting consolidation.

Confidence: Medium
Method: 5-day moving average

Note: This is a simple prediction model. For trading decisions, consult
professional financial advice and use more sophisticated models.

Interactive Usage#

Create interactive.py:

from agent import run_agent

def main():
    print("🤖 Stock Prediction Agent")
    print("=" * 50)

    while True:
        symbol = input("\nEnter stock symbol (or 'quit'): ").strip().upper()

        if symbol == 'QUIT':
            break

        if not symbol:
            print("Please enter a valid symbol")
            continue

        print(f"\n🔍 Analyzing {symbol}...")
        result = run_agent(symbol)
        print("\n" + "="*50)
        print(result["messages"][-1].content)
        print("="*50)

if __name__ == "__main__":
    main()

Run it:

python interactive.py

Understanding How the Agent Works#

The ReAct Pattern#

  1. Thought: "I need stock data to make a prediction"
  2. Action: Call search_stock_data("AAPL")
  3. Observation: Receives historical data
  4. Thought: "Now I can predict using this data"
  5. Action: Call predict_stock_price("AAPL", prices)
  6. Observation: Gets prediction result
  7. Thought: "I have everything I need"
  8. Answer: Provides final response to user

Tool Selection Logic#

The LLM automatically decides:

  • Which tools to use (search vs predict)
  • When to use them (sequence matters!)
  • What arguments to pass (extracts from context)
  • When to stop (after getting complete answer)

This is much more powerful than hardcoded workflows!


Extending the Agent#

Add More Tools#

@tool
def get_company_news(symbol: str) -> dict:
    """Fetch latest news for a company."""
    # Use News API or similar
    pass

@tool
def calculate_technical_indicators(prices: list) -> dict:
    """Calculate RSI, MACD, moving averages."""
    import pandas as pd
    import talib
    # Technical analysis logic
    pass

@tool
def get_fundamental_data(symbol: str) -> dict:
    """Fetch P/E ratio, market cap, etc."""
    stock = yf.Ticker(symbol)
    return stock.info

Add to agent:

agent = create_react_agent(
    llm,
    tools=[
        search_stock_data,
        predict_stock_price,
        get_company_news,  # New!
        calculate_technical_indicators,  # New!
        get_fundamental_data  # New!
    ]
)

The agent will automatically use these tools when relevant!

Upgrade the Prediction Model#

Replace model.py with real ML:

import torch
from transformers import TimeSeriesTransformerForPrediction

def predict_next_price(prices: list[float]) -> float:
    """Use a proper ML model for prediction."""
    model = load_pretrained_model()  # Your trained model
    prediction = model.predict(prices)
    return prediction

Add LangSmith Tracing#

Monitor agent behavior in production:

import os
os.environ["LANGSMITH_API_KEY"] = "your_key"
os.environ["LANGSMITH_PROJECT"] = "stock-agent"
os.environ["LANGSMITH_TRACING"] = "true"

# Agent calls are now automatically logged to LangSmith!

Real-World Considerations#

⚠️ Important Disclaimers#

  1. Not Financial Advice: This is an educational project
  2. Simple Model: The moving average prediction is too basic for real trading
  3. No Backtesting: Real trading systems need rigorous testing
  4. Market Hours: Add checks for when markets are open
  5. Rate Limits: Yahoo Finance has usage limits

Production Enhancements#

For a real trading agent, add:

1. Error Handling

from tenacity import retry, stop_after_attempt, wait_exponential

@retry(stop=stop_after_attempt(3), wait=wait_exponential())
@tool
def search_stock_data(symbol: str) -> dict:
    # Retries on failure with exponential backoff
    pass

2. Caching

from functools import lru_cache

@lru_cache(maxsize=100)
def fetch_stock_data(symbol: str, date: str):
    # Cache expensive API calls
    pass

3. Validation

def validate_symbol(symbol: str) -> bool:
    """Check if symbol exists before querying."""
    valid_symbols = load_symbol_list()  # NYSE, NASDAQ lists
    return symbol.upper() in valid_symbols

4. Async Tools

from langchain.tools import AsyncTool

@tool
async def search_stock_data_async(symbol: str) -> dict:
    """Async version for better performance."""
    async with aiohttp.ClientSession() as session:
        # Fetch data asynchronously
        pass

Common Use Cases Beyond Stock Prediction#

The same LangGraph pattern works for:

1. Research Assistant#

tools = [
    web_search,
    arxiv_search,
    summarize_paper,
    extract_citations
]

2. Customer Support Bot#

tools = [
    search_knowledge_base,
    check_order_status,
    create_ticket,
    escalate_to_human
]

3. Data Analysis Agent#

tools = [
    load_dataset,
    run_sql_query,
    create_visualization,
    statistical_analysis
]

4. Code Review Agent#

tools = [
    analyze_code_quality,
    check_security_issues,
    run_tests,
    suggest_improvements
]

Debugging Tips#

View Agent's Reasoning#

Add verbose logging:

import logging
logging.basicConfig(level=logging.DEBUG)

# Now you'll see all agent thoughts and tool calls
result = run_agent("TSLA")

Check Tool Calls#

result = agent.invoke({"messages": [("user", query)]})

# Inspect all messages
for msg in result["messages"]:
    print(f"{msg.type}: {msg.content}")

Test Tools Individually#

# Test tool without agent
from tools import search_stock_data

data = search_stock_data("AAPL")
print(data)  # Should return stock data dict

Performance Optimization#

Parallel Tool Execution#

LangGraph can run independent tools in parallel:

# Agent automatically parallelizes when possible
# No code changes needed!

Reduce LLM Calls#

Use caching for repeated queries:

from langchain.cache import InMemoryCache
from langchain.globals import set_llm_cache

set_llm_cache(InMemoryCache())

Smaller Model for Tool Selection#

# Use cheaper model for tool routing
router_llm = ChatOpenAI(model="gpt-3.5-turbo")

# Use powerful model only for final answer
answer_llm = ChatOpenAI(model="gpt-4o")

Next Steps#

Beginner Projects#

  1. Add more stocks: Handle portfolio predictions
  2. Historical analysis: Compare predicted vs actual prices
  3. Alert system: Notify when prediction confidence is high

Advanced Projects#

  1. Replace with LSTM: Train deep learning model for better predictions
  2. Multi-agent system: Separate agents for research, analysis, trading
  3. Backtesting framework: Test strategies on historical data
  4. Real-time dashboard: Visualize predictions with Streamlit

Conclusion#

You've built a working AI agent with LangGraph! Here's what you learned:

Create custom tools for any functionality ✅ Build LangGraph agents that reason and act ✅ Chain multiple tools intelligently ✅ Integrate external APIs (Yahoo Finance) ✅ Structure production-ready agent code

The power of LangGraph: Once you understand this pattern, you can build agents for any domain just by swapping out the tools!


Resources#

git clone https://github.com/MinhQuanBuiSco/AI_CheatSheet.git
cd AI_CheatSheet/AI_agent_langGraph
# Follow setup instructions in README

Questions? The code is open source - issues and PRs welcome!

Happy building! 🚀📈