How to Integrate FastAPI for banking with LangChain for AI agents

By Cyprian AaronsUpdated 2026-04-21
fastapi-for-bankinglangchainai-agents

Combining FastAPI for banking with LangChain gives you a clean way to expose bank-grade operations as APIs while letting AI agents reason over them. The practical win is simple: your agent can answer customer questions, fetch account data, and trigger compliant workflows without hardcoding every branch into the model layer.

This pattern works well when you need controlled access to financial systems. FastAPI handles the service boundary and validation; LangChain handles tool selection, prompt orchestration, and multi-step agent behavior.

Prerequisites

  • Python 3.10+
  • A FastAPI app with banking endpoints already defined
  • A LangChain-compatible LLM provider configured
  • pip install fastapi uvicorn langchain langchain-openai httpx pydantic
  • An API key for your LLM provider set in environment variables
  • Basic knowledge of REST, Pydantic models, and async Python

Integration Steps

  1. Expose banking operations through FastAPI

    Start by defining explicit banking endpoints. Keep the API narrow: balance lookup, transaction history, and payment initiation are enough for most agent workflows.

    # banking_api.py
    from fastapi import FastAPI, HTTPException
    from pydantic import BaseModel
    from typing import List
    
    app = FastAPI(title="Banking API")
    
    class TransferRequest(BaseModel):
        from_account: str
        to_account: str
        amount: float
    
    class Transaction(BaseModel):
        id: str
        amount: float
        description: str
    
    MOCK_BALANCES = {"acct_001": 1250.75, "acct_002": 890.20}
    MOCK_TXNS = {
        "acct_001": [
            {"id": "tx_1", "amount": -25.0, "description": "Coffee"},
            {"id": "tx_2", "amount": 500.0, "description": "Salary"},
        ]
    }
    
    @app.get("/accounts/{account_id}/balance")
    async def get_balance(account_id: str):
        if account_id not in MOCK_BALANCES:
            raise HTTPException(status_code=404, detail="Account not found")
        return {"account_id": account_id, "balance": MOCK_BALANCES[account_id]}
    
    @app.get("/accounts/{account_id}/transactions", response_model=List[Transaction])
    async def get_transactions(account_id: str):
        return MOCK_TXNS.get(account_id, [])
    
    @app.post("/transfers")
    async def create_transfer(req: TransferRequest):
        if req.amount <= 0:
            raise HTTPException(status_code=400, detail="Amount must be positive")
        return {"status": "pending_review", "transfer": req.model_dump()}
    
  2. Run the banking API locally

    You want a stable base URL that LangChain tools can call. For local development, run FastAPI with Uvicorn.

    uvicorn banking_api:app --reload --port 8000
    
  3. Wrap FastAPI endpoints as LangChain tools

    LangChain agents work best when each external capability is a tool with a clear contract. Use @tool and call your FastAPI service through httpx.

    # tools.py
    import httpx
    from langchain_core.tools import tool
    
    BASE_URL = "http://localhost:8000"
    
    @tool
    def get_account_balance(account_id: str) -> dict:
        """Fetch an account balance from the banking API."""
        resp = httpx.get(f"{BASE_URL}/accounts/{account_id}/balance", timeout=10)
        resp.raise_for_status()
        return resp.json()
    
    @tool
    def get_account_transactions(account_id: str) -> dict:
        """Fetch recent transactions for an account."""
        resp = httpx.get(f"{BASE_URL}/accounts/{account_id}/transactions", timeout=10)
        resp.raise_for_status()
        return {"account_id": account_id, "transactions": resp.json()}
    
    @tool
    def initiate_transfer(from_account: str, to_account: str, amount: float) -> dict:
        """Create a transfer request in the banking API."""
        payload = {
            "from_account": from_account,
            "to_account": to_account,
            "amount": amount,
        }
        resp = httpx.post(f"{BASE_URL}/transfers", json=payload, timeout=10)
        resp.raise_for_status()
        return resp.json()
    
  4. Create a LangChain agent that uses those tools

    Use an agent executor so the model can decide when to call each bank tool. This is where the integration becomes useful: user intent gets mapped into API calls without manually wiring every path.

     # agent.py
     from langchain_openai import ChatOpenAI
     from langchain.agents import create_tool_calling_agent, AgentExecutor
     from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
    
     from tools import get_account_balance, get_account_transactions, initiate_transfer
    
     llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
    
     tools = [get_account_balance, get_account_transactions, initiate_transfer]
    
     prompt = ChatPromptTemplate.from_messages(
         [
             ("system", "You are a banking assistant. Use tools for any account or transfer action."),
             ("human", "{input}"),
             MessagesPlaceholder(variable_name="agent_scratchpad"),
         ]
     )
    
     agent = create_tool_calling_agent(llm=llm, tools=tools, prompt=prompt)
     executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
    
     result = executor.invoke(
         {"input": "Check the balance for acct_001 and then tell me if I can transfer 200 to acct_002."}
     )
     print(result["output"])
    
  5. Add guardrails before production

    Banking agents need policy checks outside the model. Validate amounts server-side in FastAPI and add business rules in your tool layer before any transfer executes.

    # guarded_tools.py
    import httpx
    from langchain_core.tools import tool
    
    BASE_URL = "http://localhost:8000"
    MAX_TRANSFER = 1000.00
    
    @tool
    def safe_initiate_transfer(from_account: str, to_account: str, amount: float) -> dict:
        """Initiate a transfer only if it passes policy checks."""
        if amount <= 0:
            return {"status": "rejected", "reason": "Amount must be positive"}
        if amount > MAX_TRANSFER:
            return {"status": "rejected", "reason": f"Amount exceeds limit of {MAX_TRANSFER}"}
    
        resp = httpx.post(
            f"{BASE_URL}/transfers",
            json={"from_account": from_account, "to_account": to_account, "amount": amount},
            timeout=10,
        )
        resp.raise_for_status()
        return resp.json()
    

Testing the Integration

Run the FastAPI service first, then execute this script to verify the tool call path works end to end.

from tools import get_account_balance

result = get_account_balance.invoke({"account_id": "acct_001"})
print(result)

Expected output:

{
  "account_id": "acct_001",
  "balance": 1250.75
}

If you want to test the full agent flow:

from agent import executor

response = executor.invoke({"input": "What is the balance of acct_001?"})
print(response["output"])

Expected output should mention the balance returned by the FastAPI endpoint and avoid inventing values.

Real-World Use Cases

  • Customer support assistants that answer balance questions, list recent transactions, and open transfer requests with approval gates.
  • Internal ops copilots that help bank staff query accounts faster without giving them direct database access.
  • Fraud triage agents that pull transaction history through FastAPI endpoints and summarize suspicious patterns for analysts.

Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides