Skip to content

Repository files navigation

AlphaAgents — Agentic Equity Research Analyst

A multi-agent LLM pipeline that produces cited, structured investment research notes in under 3 minutes, with a human-in-the-loop approval gate before any note is published.


Demo

TODO: Record a 3–5 min Loom walkthrough and paste the embed link here.
Live URL: TODO — add Render deployment URLs after first deploy.


Problem Statement

Equity research analysts spend 8–12 hours producing a single research note: gathering web data, pulling financial metrics, reading recent news, synthesising everything into a structured document, and getting it peer-reviewed. AlphaAgents compresses the first-draft stage to under 3 minutes using 6 coordinated LLM agents, a critic review pass, and a mandatory human-approval gate — so analysts spend their time on judgement, not data gathering.


Architecture

Architecture Diagram

See docs/architecture.md for the full C4 Level 2 narrative.

Pipeline topology:

Query → Orchestrator → [Web Researcher | Financial Data | News | Memory] (parallel)
→ Writer → Critic → Revision Router → (loop or) HITL → Done

Tech Stack

ComponentChoiceWhy
Agent frameworkLangGraph (StateGraph)Explicit state transitions, parallel fan-out, conditional revision loop, testable nodes
LLM providerHuggingFace Inference API (free)$0 cost; OpenAI-compatible; Llama-3.1-8B as primary
Web / news searchTavily APIStructured JSON results, news topic filter, free tier
Financial datayfinanceNo API key, covers major global exchanges
Vector memoryChromaDB + sentence-transformersLocal persistence, zero infra cost
API layerFastAPIAsync-native, automatic OpenAPI docs, background tasks
FrontendStreamlitRapid UI with polling, tabs, markdown rendering
ObservabilityLangFusePer-node spans, trace grouping, error tagging
Evaluationragas + custom citation_precisionFactuality scoring + citation density metric
StorageSQLite + aiosqliteZero-infra job tracking and HITL persistence
LintingruffFast, opinionated, replaces flake8 + isort
Type checkingmypy (strict)Catches type errors before runtime
Testingpytest + unittest.mockAll external APIs mocked; no test doubles touch real endpoints
CIGitHub ActionsLint + typecheck + test on every push to main
DeploymentRender free tierFastAPI + Streamlit as two separate web services
Package manageruvFast, lockfile-based, drop-in pip replacement

Quickstart

Prerequisites

  • Python 3.11+
  • uv (curl -LsSf https://astral.sh/uv/install.sh | sh)
  • A free HuggingFace token
  • A free Tavily API key
  • A free LangFuse account (public + secret key)

Install

git clone <your-repo-url>cd alpha-agents
cp .env.example .env
# Fill in your HF_TOKEN, TAVILY_API_KEY, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY
uv sync --all-extras

Run

# Terminal 1 — FastAPI backend
make run-api
# Terminal 2 — Streamlit frontend
make run-ui

Open http://localhost:8501 in your browser.

Test

make test# or individually:
make lint
make typecheck

Observability

LangFuse Tracing

Every pipeline run is traced end-to-end in LangFuse.

What is traced:

  • Each agent node is a named span (orchestrator_node, web_researcher_node, etc.)
  • Every LLM call logs: model used, prompt tokens, completion tokens, latency (ms)
  • Errors are tagged with level="ERROR" and include the exception message
  • The full pipeline run groups under a single trace ID stored in state["langfuse_trace_id"]

To view traces:

  1. Go to cloud.langfuse.com and sign in
  2. Open your project → Traces tab
  3. Each research job appears as one trace; click in to see per-node spans and token usage

Setup: Add these to your .env:

LANGFUSE_PUBLIC_KEY=pk_...
LANGFUSE_SECRET_KEY=sk_...
LANGFUSE_HOST=https://cloud.langfuse.com

Structured Logging

All logs are emitted as single-line JSON (configured in config/logging.py).

Log levels by module:

ModuleLevelWhat you see
llm.*DEBUGToken counts, raw model responses, retry attempts
agents.*INFONode start/end, extracted tickers, article counts, word counts
api.*INFORequest received, job created, pipeline completed
rootWARNINGThird-party library noise suppressed

Log output location:

  • Console — JSON lines on stdout (visible in make run-api terminal)
  • Filelogs/alpha_agents.log (rotating, 10 MB per file, 5 backups kept)

Example log line:

{"timestamp": "2026-07-14T10:23:01+00:00", "level": "INFO", "logger": "agents.writer",
"message": "Generated recommendation: Buy (confidence=Medium) for Infosys Limited. Note word count: 843. Revision=0. job=abc123"}

Debugging

Common errors and fixes

ErrorCauseFix
GROQ_API_KEY is not setMissing env varAdd GROQ_API_KEY=gsk_... to .env
TAVILY_API_KEY not setMissing env varAdd TAVILY_API_KEY=tvly_... to .env
Rate limit hit (attempt N/3)Groq free tier 6K TPMWait 60s or reduce MAX_NEWS_ITEMS in agents/news.py
Both models failed to return valid ... outputLLM returned malformed JSONCheck LangFuse trace for the raw response; usually a model glitch — retry
data_available=False in the noteyfinance returned empty data for the tickerVerify the ticker exists on Yahoo Finance; try the primary US exchange symbol
Pipeline crashed in job statusUnhandled exception in a nodeCheck logs/alpha_agents.log for the "level": "ERROR" line with exc_info
ChromaDB collection emptyFirst run, no approved notes yetRun and approve at least one research job; ChromaDB is populated on HITL approval

Reading logs

# Tail the log file (pretty-print JSON with jq)
tail -f logs/alpha_agents.log | jq .# Filter for errors only
cat logs/alpha_agents.log | jq 'select(.level == "ERROR")'# Filter for a specific job
cat logs/alpha_agents.log | jq 'select(.message | contains("job-id-here"))'

Data

See docs/data.md for schemas, sources, and field-level documentation for all data flowing through the pipeline.


Architecture Decision Records

ADRDecision
ADR-001LangGraph over CrewAI / AutoGen
ADR-002ChromaDB + local embeddings
ADR-003LLM-as-judge critic with revision loop
ADR-004Four-layer hallucination mitigation
ADR-005HuggingFace + Render free tier

Known Limitations

  • Cold starts: Render free tier spins down after 15 min inactivity; first request takes ~30s.
  • yfinance data gaps: Many international tickers return incomplete or empty data; data_available=False is set and the note will flag figures as "data unavailable".
  • Hallucination rate on financials: Llama-3.1-8B can still generate plausible but false financial figures; the critic pass and HITL gate are mitigations, not guarantees.
  • Small eval set: 20 hand-curated queries is sufficient for a prototype benchmark but not statistically rigorous.
  • HuggingFace rate limits: ~10 req/min on free tier; parallel agent calls can hit this; call_with_backoff() retries but adds latency.
  • Non-commercial yfinance: Yahoo Finance data is not licensed for commercial use; this system is for research/educational purposes only.

Roadmap

  • Debate agent — second LLM argues the bear case to stress-test the recommendation
  • Streaming UI — token-by-token writer output via Server-Sent Events
  • Real-time market data — replace yfinance with a paid data provider (Alpha Vantage, Polygon)
  • Fine-tuned extractor — 1B model for ticker/entity extraction, faster than 8B
  • PostgreSQL + Pinecone — production-grade storage replacing SQLite + ChromaDB

License

MIT License. See LICENSE for details.

Acknowledgements

Built during the LLM Systems & Applied GenAI internship segment (E1 — Agentic Research Analyst track).
Powered by: LangGraph, HuggingFace, Tavily, LangFuse, FastAPI, Streamlit.

About

Multi-agent LLM pipeline (LangGraph + Groq) that generates cited equity research notes in minutes, with a human-in-the-loop approval gate before publishing

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages