How to Integrate CrewAI for investment banking with FastAPI for AI agents

By Cyprian AaronsUpdated 2026-04-22
crewai-for-investment-bankingfastapiai-agents

Combining CrewAI for investment banking with FastAPI gives you a clean way to expose multi-agent financial workflows as production APIs. The pattern is simple: CrewAI handles the analyst/researcher/executor orchestration, and FastAPI turns those workflows into endpoints your internal systems can call.

This is useful when you need repeatable bank-grade tasks like deal screening, company comps, memo drafting, or market research. Instead of wiring agent logic directly into a UI or notebook, you wrap it in an API with auth, observability, and predictable request/response contracts.

Prerequisites

  • Python 3.10+
  • crewai
  • fastapi
  • uvicorn
  • pydantic
  • An LLM provider configured for CrewAI, such as OpenAI or Azure OpenAI
  • Basic familiarity with REST APIs and async Python
  • A project structure like:
    • app/main.py
    • app/agents.py
    • app/tasks.py

Install the packages:

pip install crewai fastapi uvicorn pydantic

Set your model key in the environment:

export OPENAI_API_KEY="your-key"

Integration Steps

  1. Define your investment banking agents

Start by creating agents with narrow responsibilities. In banking workflows, you want separation between research, analysis, and writing so the output is easier to validate.

# app/agents.py
from crewai import Agent

research_analyst = Agent(
    role="Investment Banking Research Analyst",
    goal="Gather relevant company and market information for transaction analysis",
    backstory="You analyze public company data, sector trends, and recent news.",
    verbose=True,
    allow_delegation=False,
)

financial_analyst = Agent(
    role="Investment Banking Financial Analyst",
    goal="Build concise financial analysis and valuation commentary",
    backstory="You focus on comps, multiples, margins, and transaction logic.",
    verbose=True,
    allow_delegation=False,
)

memo_writer = Agent(
    role="Investment Banking Associate",
    goal="Write a polished investment memo from analyst inputs",
    backstory="You turn analysis into client-ready banking language.",
    verbose=True,
    allow_delegation=False,
)
  1. Create tasks that map to the workflow

Tasks should be explicit. In production systems, vague prompts create inconsistent outputs; task boundaries reduce drift.

# app/tasks.py
from crewai import Task

def build_tasks(company_name: str):
    research_task = Task(
        description=f"Research {company_name}: business model, recent news, peers, and market context.",
        expected_output="A structured summary with bullets for business overview, recent developments, and peer set.",
        agent=None,
    )

    analysis_task = Task(
        description=f"Analyze {company_name} using the research summary. Focus on valuation drivers and risks.",
        expected_output="A short financial analysis with key risks and opportunities.",
        agent=None,
        context=[research_task],
    )

    memo_task = Task(
        description=f"Draft an investment banking memo for {company_name} using prior outputs.",
        expected_output="A client-ready memo section with clear recommendation language.",
        agent=None,
        context=[research_task, analysis_task],
    )

    return research_task, analysis_task, memo_task
  1. Wire agents and tasks into a Crew

This is where CrewAI does the orchestration. Use Crew and Process.sequential when you want deterministic execution order.

# app/crew_factory.py
from crewai import Crew, Process
from app.agents import research_analyst, financial_analyst, memo_writer
from app.tasks import build_tasks

def build_investment_banking_crew(company_name: str) -> Crew:
    research_task, analysis_task, memo_task = build_tasks(company_name)

    research_task.agent = research_analyst
    analysis_task.agent = financial_analyst
    memo_task.agent = memo_writer

    return Crew(
        agents=[research_analyst, financial_analyst, memo_writer],
        tasks=[research_task, analysis_task, memo_task],
        process=Process.sequential,
        verbose=True,
    )
  1. Expose the crew through a FastAPI endpoint

FastAPI becomes your service layer. You define request models with Pydantic and return the crew output as JSON.

# app/main.py
from fastapi import FastAPI
from pydantic import BaseModel
from app.crew_factory import build_investment_banking_crew

app = FastAPI(title="Investment Banking AI Agents")

class MemoRequest(BaseModel):
    company_name: str

@app.post("/memo")
def generate_memo(request: MemoRequest):
    crew = build_investment_banking_crew(request.company_name)
    result = crew.kickoff()
    return {
        "company_name": request.company_name,
        "memo": str(result),
    }

Run it locally:

uvicorn app.main:app --reload --port 8000
  1. Add async-friendly execution if requests may take time

CrewAI runs work that can take seconds or longer. If your API will serve multiple users concurrently, push execution into a threadpool or background job queue.

# app/main.py
from fastapi import FastAPI
from pydantic import BaseModel
from starlette.concurrency import run_in_threadpool
from app.crew_factory import build_investment_banking_crew

app = FastAPI(title="Investment Banking AI Agents")

class MemoRequest(BaseModel):
    company_name: str

@app.post("/memo-async")
async def generate_memo_async(request: MemoRequest):
    crew = build_investment_banking_crew(request.company_name)
    result = await run_in_threadpool(crew.kickoff)
    return {"company_name": request.company_name, "memo": str(result)}

Testing the Integration

Use FastAPI’s test client to verify the endpoint returns a response.

# tests/test_main.py
from fastapi.testclient import TestClient
from app.main import app

client = TestClient(app)

def test_generate_memo():
    response = client.post("/memo", json={"company_name": "Acme Corp"})
    assert response.status_code == 200

if __name__ == "__main__":
    resp = client.post("/memo", json={"company_name": "Acme Corp"})
    print(resp.json())

Expected output shape:

{
  "company_name": "Acme Corp",
  "memo": "..."
}

If everything is wired correctly, you should see a JSON payload containing the input company name and a generated memo string from the crew run.

Real-World Use Cases

  • Deal screening API: Submit a target company name and get back sector context, peer comps directionally relevant to bankers.
  • Investment committee memo drafting: Automate first-pass IC notes from research + analysis agents before human review.
  • Coverage workflow automation: Build endpoints that generate company briefs for analysts covering multiple sectors.

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