中文 | English
A minimal LangGraph hands-on project: run the full loop of state graph → compile → async invoke with very little business code—ideal for getting started and sharing within a team.
This repository is a LangGraph learning and practice starter: it demonstrates core capabilities—state graphs, nodes and edges, reducers, checkpointing, conditional routing, ReAct agents, and more—with minimal business logic, plus a clear FastAPI layering (api / service / transport / schemas).
Future production projects can use this repo as a starting template—keep the layered structure and LangGraph integration patterns, then extend agents, workflows, and business logic without scaffolding from scratch.
A minimal FastAPI + LangGraph demo project with 5 simple agents:
qa_agent: General Q&A assistantsummary_agent: Text summarizertranslate_agent: Chinese to English translatorplanner_agent: Task plannertool_agent: Function-calling agent
Built-in function calls for tool_agent:
get_current_utc_timeadd_numberscount_wordsslugify_text
- Python 3.10+
- uv (package manager / runner)
- OpenAI API key
From the project root (uses uv.lock and creates .venv if needed):
uv synccp .env.example .envUpdate OPENAI_API_KEY in .env.
uv run uvicorn app.main:app --reloadAfter source .venv/bin/activate, you can run uvicorn app.main:app --reload instead if you prefer a classic venv workflow.
| Method & path | LangGraph feature |
|---|---|
POST /api/v1/agents/workflow |
Linear StateGraph, reducers (operator.add on steps), compile(), ainvoke(). |
POST /api/v1/agents/demo/checkpoint |
Checkpointing: compile(checkpointer=InMemorySaver()), multi-turn state keyed by thread_id in configurable. |
POST /api/v1/agents/demo/conditional-route |
Conditional edges: add_conditional_edges routes to different nodes (math vs general) without a checkpoint. |
POST /api/v1/agents/demo/react-agent |
Prebuilt ReAct: create_react_agent tool loop (same demo tools as tool_agent). |
Other routes (/run, /run-with-trace, /ws, /tools, etc.) use LangChain (langchain_core / langchain_openai) only; they do not run a LangGraph CompiledStateGraph (except the demo routes above).
- State — A
TypedDict(WorkflowStateinapp/transport/collaborative_workflow_graph.py) describes the data carried through the graph: user input, routing metadata, primary agent id, mergedsteps, and finaloutput_text. - Graph —
StateGraph(WorkflowState)registers async nodes (route→primary→ optional summarize → optional translate) and edges fromSTART…END. - Reducers — Fields like
stepsuseAnnotated[list[str], operator.add]so multiple nodes can append trace entries without overwriting each other; that is LangGraph’s channel/reducer pattern on the state schema. - Compile & run —
graph.compile()returns a runnable. The service callsawait graph.ainvoke({"input_text": ..., "steps": []}), which walks the fixed pipeline, merges partial node returns into state, and returns the final state (used to buildsteps+output_textin the JSON response).
- Checkpoint —
app/transport/checkpoint_chat_graph.py: message list usesadd_messages; the process-wideInMemorySaverfromapp/transport/checkpoint_store.pykeeps history perthread_idacross requests until the server restarts. - Conditional route —
app/transport/conditional_branch_graph.py: a router node plusadd_conditional_edgespicks the next node from user text heuristics. - ReAct —
app/transport/react_prebuilt_graph.py: wrapscreate_react_agent;LangGraphDemoServiceinapp/service/langgraph_demo_service.pyrunsainvokeand shapes the JSON response.
For the collaborative workflow node logic, open app/transport/collaborative_workflow_graph.py.
This project ships 3 stdio MCP server modules, wired through langchain-mcp-adapters MultiServerMCPClient for tool discovery and invocation:
| MCP Server | Tools |
|---|---|
math |
add_numbers, multiply_numbers |
time |
get_current_utc_time |
text |
count_words, slugify_text |
Layering:
app/transport/mcp/servers/— standalone MCP server scripts (runnable viapython ..._server.pywith stdio)app/transport/mcp/registry.py— server registry and stdio connection configapp/transport/mcp_client.py— MCP client transportapp/service/mcp_service.py— discovery, invocation, full-flow orchestrationapp/api/mcp_router.py— HTTP test endpoints
With default MCP_TOOL_NAME_PREFIX=true, tool names are prefixed by server (e.g. math_add_numbers) to avoid collisions across servers.
POST /api/v1/mcp/demo/full-flow runs:
- Resolve and connect all (or selected) MCP servers
- Discover tools
- Invoke sample tools per server
- Return
stepstrace andinvocationsresults
Per-server test: POST /api/v1/mcp/demo/server/{server_name}
GET /healthGET /api/v1/agentsPOST /api/v1/agents/runPOST /api/v1/agents/run-with-trace(tool agent with tool_calls trace)POST /api/v1/agents/workflow(LangGraph collaborative workflow)POST /api/v1/agents/demo/checkpoint(LangGraph checkpoint +add_messages)POST /api/v1/agents/demo/conditional-route(LangGraph conditional edges)POST /api/v1/agents/demo/react-agent(LangGraphcreate_react_agent)WS /api/v1/agents/wsGET /api/v1/toolsPOST /api/v1/toolsGET /api/v1/mcp/serversGET /api/v1/mcp/toolsPOST /api/v1/mcp/tools/invokePOST /api/v1/mcp/demo/full-flow(MCP full-flow test)POST /api/v1/mcp/demo/server/{server_name}(single MCP server full-flow test)
Example request:
curl -X POST "http://127.0.0.1:8000/api/v1/agents/run" \
-H "Content-Type: application/json" \
-d '{
"agent_type": "summary_agent",
"input_text": "LangGraph helps you build stateful, multi-step LLM workflows."
}'Function call request example:
curl -X POST "http://127.0.0.1:8000/api/v1/agents/run" \
-H "Content-Type: application/json" \
-d '{
"agent_type": "tool_agent",
"input_text": "Please add 12.5 and 7.3, then generate a slug for: LangGraph Tool Calling Demo"
}'Function call with LLM trace example:
curl -X POST "http://127.0.0.1:8000/api/v1/agents/run-with-trace" \
-H "Content-Type: application/json" \
-d '{
"agent_type": "tool_agent",
"input_text": "What time is it in UTC? Also count words in: LangGraph tool call demo"
}'Direct tool call (without LLM) example:
curl -X POST "http://127.0.0.1:8000/api/v1/tools" \
-H "Content-Type: application/json" \
-d '{
"tool_name": "add_numbers",
"arguments": {"a": 12.5, "b": 7.3}
}'Workflow request:
curl -X POST "http://127.0.0.1:8000/api/v1/agents/workflow" \
-H "Content-Type: application/json" \
-d '{
"input_text": "Please create a short launch plan for an AI chatbot and output in English."
}'LangGraph checkpoint demo (call twice with the same thread_id to continue the thread):
curl -X POST "http://127.0.0.1:8000/api/v1/agents/demo/checkpoint" \
-H "Content-Type: application/json" \
-d '{"thread_id": "demo-user-1", "input_text": "My name is Alex. Remember it in one short sentence."}'
curl -X POST "http://127.0.0.1:8000/api/v1/agents/demo/checkpoint" \
-H "Content-Type: application/json" \
-d '{"thread_id": "demo-user-1", "input_text": "What is my name?"}'Conditional-route demo (math branch if the text looks like a calculation):
curl -X POST "http://127.0.0.1:8000/api/v1/agents/demo/conditional-route" \
-H "Content-Type: application/json" \
-d '{"input_text": "Calculate 12.5 + 7.3 and explain briefly."}'Prebuilt ReAct demo:
curl -X POST "http://127.0.0.1:8000/api/v1/agents/demo/react-agent" \
-H "Content-Type: application/json" \
-d '{"input_text": "What UTC time is it? Then add 10 and 32."}'MCP full-flow test (connect → discover tools → sample invocations):
curl -X POST "http://127.0.0.1:8000/api/v1/mcp/demo/full-flow" \
-H "Content-Type: application/json" \
-d '{"include_tool_invocations": true}'MCP single tool invocation (prefixed name by default):
curl -X POST "http://127.0.0.1:8000/api/v1/mcp/tools/invoke" \
-H "Content-Type: application/json" \
-d '{
"tool_name": "math_add_numbers",
"arguments": {"a": 12.5, "b": 7.3}
}'WebSocket stream payload example:
{
"agent_type": "qa_agent",
"input_text": "Explain what LangGraph is in simple words."
}app/
api/ # FastAPI routers
service/ # Business services
transport/ # LLM / MCP communication layer
mcp/ # MCP server modules and registry
schemas/ # Request/response models
utils/ # Utility helpers