Minimal LangGraph agent with FastAPI — clone, configure your LLM key, run.
A production-minimal LangGraph agent skeleton. Four nodes (router → rag / tool → reply), FastAPI endpoints (/chat + /chat/stream), and just enough scaffolding to start building real agents — not another "hello world" that needs a rewrite before going anywhere.
# 1. Clone
git clone https://github.com/pingxin403/langgraph-agent-template.git
cd langgraph-agent-template
# 2. Configure LLM
cp .env.example .env
# Edit .env — set your LLM_API_KEY and LLM_MODEL
# 3. Run
docker compose up # or `pip install -e ".[dev]" && uvicorn app.main:app`
# 4. Test
curl -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{"message": "查一下退货政策"}'
# Response: { "response": "According to the policy, returns are accepted..." }POST /chat → [app/main.py]
│
▼
┌──────────────┐
│ router │ ← classify intent: "rag" / "tool" / "chat"
└──┬───┬───┬──┘
│ │ │
┌────────┘ │ └──────────┐
▼ ▼ ▼
┌──────┐ ┌──────────┐ ┌─────────┐
│ RAG │ │ Tool │ │ Reply │
│ node │ │ node │ │ node │
└──┬───┘ └────┬─────┘ └────┬────┘
│ │ │
└────────────┴──────┬───────┘
▼
LLM (OpenAI-compatible)
│
▼
Streaming response
Each node is a single-function module. The AgentState TypedDict is the shared memory. Add a node → wire it into the graph → done.
app/
├── main.py ← FastAPI entrypoint (/chat, /chat/stream, /health)
├── config.py ← Pydantic Settings (reads .env)
├── agent/
│ ├── graph.py ← LangGraph StateGraph + agent singleton
│ ├── state.py ← AgentState TypedDict
│ └── nodes.py ← router, rag, tool, reply nodes
├── rag/
│ └── retriever.py ← keyword-based retriever (swap for embedding + vector DB)
└── tools/
└── search.py ← mock search tool (swap for real API call)
tests/
└── test_agent.py ← node-level tests (router intent, state contract)
Everything marked # TODO: is a customization point. To make it yours:
grep -rn "TODO" app/ # shows every hook you need to replace| What | Where | What to do |
|---|---|---|
| LLM provider | .env |
Set your API key + model |
| Intent classifier | app/agent/nodes.py:router_node |
Replace keyword match with LLM classifier |
| Knowledge base | app/rag/retriever.py |
Swap _DOCS for real ingestion pipeline + vector DB |
| Tools | app/tools/ |
Add real API calls (search, DB lookup, webhook post) |
| Checkpointer | app/agent/graph.py |
Replace MemorySaver with PostgresSaver for persistence |
| HITL (human-in-the-loop) | app/agent/graph.py |
Add interrupt_before=["reply"] for approval gates |
pytest tests/ -vNode-level tests validate routing logic and state contract. Add integration tests once you swap in real LLM + tools.
docker compose up -d# Replace <image> with your built image and apply
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: agent
spec:
replicas: 2
template:
spec:
containers:
- name: app
image: <your-registry>/agent:latest
envFrom:
- secretRef:
name: agent-env
EOF| This template | Scratch from LangGraph docs | |
|---|---|---|
| Runs out of the box | ✅ docker compose up |
❌ Missing wiring |
| Intent routing | ✅ keyword → easy swap to LLM | ❌ Need to build |
| RAG stub | ✅ replace _DOCS with real data |
❌ From scratch |
| SSE streaming | ✅ /chat/stream endpoint |
❌ Manual |
| Tests | ✅ router + state contract | ❌ None |
| Customization hooks | ✅ grep -rn TODO |
❌ Guesswork |
- Real-world agent with full RAG + HITL: see cuckoo-echo-showcase (architecture docs, source private)
- FastAPI backend starter: fastapi-backend-template — JWT + DB + Redis + Celery + Docker
- CI/CD workflow templates: cicd-platform-showcase