# GraphTutor-基于 LangGraph 的多智能体智能辅导系统 **Repository Path**: git_bai/work ## Basic Information - **Project Name**: GraphTutor-基于 LangGraph 的多智能体智能辅导系统 - **Description**: 这是一个基于 LangGraph 和RAG的多智能体智能辅导系统 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 12 - **Forks**: 1 - **Created**: 2026-06-02 - **Last Updated**: 2026-10-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Gaokao Tutor
中文文档 · Architecture Diagrams · Changelog
## About Project A production-oriented, multi-agent conversational AI for Chinese Gaokao preparation. Built on **LangGraph** (stateful orchestration), **FastAPI** (SSE streaming), and **Next.js** (reactive frontend). A lightweight Qwen2.5-7B supervisor routes queries to three specialized agents — subject tutor, study planner, and emotional support — each backed by a fully observable, fault-tolerant pipeline. --- ## Project Purpose This project is primarily intended as an **exploratory attempt at multi-agent scenarios within the education sector**, while also serving as a **deep dive into the practical application of the LangGraph underlying framework**. > > Code maintenance and iterative exploration of the technology stack will be conducted **periodically during spare time**. --- ## Demo > The React frontend provided in this project is positioned as a **lightweight reference implementation**. Its main purpose is to intuitively demonstrate complex Agent interactions (the core focus of the project), and is therefore relatively simple in design. #### RAG + Search(Fan-out/Fan-in)
#### HIL Interrupt + System Change(give a new plan)
---
## What's New in v0.3.0
- **Adversarial Plan Generation**: Multi-agent review loop — Drafter generates a study plan, Academic Reviewer and Emotional Reviewer evaluate it in parallel, unanimous approval required or the draft is revised
- **Human-in-the-Loop (HIL) Plan Review**: Graph suspends via LangGraph `interrupt`, user can edit the plan directly or provide natural language feedback
- **Feedback Router**: Classifies user feedback as "tweak" (surgical edit, fast) or "rewrite" (clean slate with full adversarial loop)
- **Single Summary Anti-Bloat**: Only one compressed summary of all prior feedback rounds, preventing unbounded context growth
- **Interactive DAG View**: React Flow replaces static SVG — drag to pan, scroll to zoom, live status across 19 nodes
- **Plan Export**: One-click Markdown download of the study plan
- **`text` SSE Event**: Complete output from non-streaming nodes (plan output, unknown handler)
- **`done` SSE Event**: Stream completion marker for reliable frontend state management
- **Input Validation**: Pydantic `max_length` guards against oversized payloads
---
## Core Features
- **Academic Q&A** — Hybrid RAG (vector + BM25 + reranker) with parallel fan-out/fan-in, hallucination evaluation and automatic retry loop
- **Study Planner** — Adversarial multi-agent drafting + review loop, enriched with live Gaokao policy data, iterative human feedback
- **Emotional Support** — Warm, practical responses in the persona of an experienced homeroom teacher
- **Intent Routing** — Lightweight Qwen2.5-7B supervisor for low-latency intent classification
- **LLM Fallback** — Automatic failover to SiliconFlow (Qwen2.5-7B) when primary DeepSeek API is unavailable
- **Distributed Tracing** — OpenTelemetry across all graph nodes, exported to Jaeger (OTLP) with SQLite fallback
- **State Persistence** — PostgreSQL-backed LangGraph checkpointer for multi-turn memory + HIL interrupt/resume
- **Configuration-Driven** — YAML runtime parameters + XML prompt registry
- **Real-Time Observability** — SSE-driven reasoning path (interactive DAG or node trail), per-node timing, token usage
- **Markdown Rendering** — Full GFM support: tables, code blocks, LaTeX math, lists
---
## Architecture
```mermaid
graph TD
START([User Input]) --> supervisor[Intent Classification]
supervisor -->|academic| academic_router[Academic Router]
supervisor -->|planning| search_policy[Policy Search]
supervisor -->|emotional| emotional_response[Emotional Support]
supervisor -->|unknown| handle_unknown[Unknown Intent]
%% Academic branch
academic_router --> rag_retrieve[RAG Retrieval]
academic_router --> web_search[Web Search]
rag_retrieve --> generate_answer[Generate Answer]
web_search --> generate_answer
generate_answer --> evaluate_hallucination[Hallucination Eval]
evaluate_hallucination -->|Pass| END_A([End])
evaluate_hallucination -->|Retry| rewrite_query[Query Rewrite]
rewrite_query --> academic_router
%% Planning branch
search_policy --> gather_intel[Intel Gathering]
gather_intel --> drafter[Plan Drafter]
drafter --> reviewer_academic[Academic Reviewer]
drafter --> reviewer_emotional[Emotional Reviewer]
reviewer_academic --> consensus_check[Consensus Check]
reviewer_emotional --> consensus_check
consensus_check -->|Pass| plan_output[Plan Output + HIL]
consensus_check -->|Reject| adv_rewrite[Plan Revision]
adv_rewrite --> drafter
%% HIL feedback loop
plan_output -->|Confirm| END_P([End])
plan_output -->|Feedback| feedback_router[Feedback Classification]
feedback_router -->|Tweak| plan_tweak[Plan Fine-tuning]
feedback_router -->|Rewrite| drafter
plan_tweak --> plan_output
%% Terminal nodes
emotional_response --> END_E([End])
handle_unknown --> END_U([End])
%% Styling
style plan_output fill:#FFF9E6,stroke:#E8A87C
style feedback_router fill:#E8F4FD,stroke:#4A90D9
style plan_tweak fill:#E8F4FD,stroke:#4A90D9
```
Cross-cutting: `@traced_node` on every node → OpenTelemetry → Jaeger UI / SQLite.
See [`docs/architecture/v0.3.0/diagram_design.md`](docs/architecture/v0.3.0/diagram_design.md) for detailed Mermaid diagrams.
---
## Tech Stack
| Layer | Component | Detail |
| ----- | --------- | ------ |
| Frontend | Next.js 16 + Tailwind CSS 4 + React Flow | Reactive chat UI, SSE consumer, interactive DAG, Markdown renderer |
| Backend API | FastAPI + Uvicorn | SSE endpoints (`/stream`, `/resume`), CORS, OTel auto-instrumentation |
| Orchestration | LangGraph | StateGraph + `interrupt()` HIL + conditional edges + fan-out/fan-in |
| Routing LLM | Qwen2.5-7B (SiliconFlow) | Lightweight intent classifier + feedback router (temperature=0.0) |
| Generation LLM | DeepSeek-V3 | Academic answers, study plans, emotional support |
| LLM Fallback | Qwen2.5-7B (SiliconFlow) | Cross-provider failover on timeout / 5xx |
| Vector Store | ChromaDB | Local knowledge retrieval with L2→relevance normalization |
| Embedding | BAAI/bge-m3 (SiliconFlow) | Text vectorization for RAG |
| Keyword Search | rank-bm25 + jieba | Chinese-aware BM25 retrieval |
| Reranker | BAAI/bge-reranker-v2-m3 (SiliconFlow) | Cross-encoder reranking of merged candidates |
| Web Search | DuckDuckGo | Online retrieval for planner and academic fallback |
| State Persistence | PostgreSQL (psycopg) | Multi-turn memory + HIL interrupt/resume via LangGraph checkpointer |
| Observability | OpenTelemetry + Jaeger + SQLite | Distributed tracing across all graph nodes |
| Configuration | YAML + XML | Runtime settings and prompt templates |
---
## Quick Start
### Option A: Docker Compose (Recommended)
```bash
git clone https://github.com/chipfighter/gaokao_tutor.git
cd gaokao_tutor
cp .env.example .env
# Edit .env — fill in DEEPSEEK_API_KEY and SILICONFLOW_API_KEY
# Start (backend + frontend + PostgreSQL)
docker compose up -d
# Optional: enable Jaeger tracing
docker compose --profile observability up -d
```
Frontend: `http://localhost:3000` · Backend API: `http://localhost:8000` · Jaeger: `http://localhost:16686`
### Option B: Local Development
#### Prerequisites
- Python 3.11+
- Node.js 18+ and npm
- PostgreSQL (optional — state persistence + HIL; system runs stateless without it)
#### Backend
```bash
conda create -n gaokao_tutor python=3.11 -y
conda activate gaokao_tutor
pip install -e ".[dev]"
cp .env.example .env
# Fill in API keys
```
#### Build Knowledge Base
Place exam paper `.txt` / `.pdf` files under `data/chinese/` or `data/math/`, then:
```bash
python scripts/build_index.py
```
#### Frontend
```bash
cd frontend
npm install
```
#### Run
```bash
# Terminal 1 — Backend
uvicorn app:app --reload --port 8000
# Terminal 2 — Frontend
cd frontend
npm run dev
```
---
## Project Structure
```text
gaokao_tutor/
├── app.py # FastAPI SSE endpoints + lifespan
├── dockerfile # Multi-stage build (frontend + backend)
├── docker-compose.yml # One-command deploy (backend + PostgreSQL + Jaeger)
├── config/
│ ├── settings.yaml # Runtime parameters (temperatures, timeouts, retry limits)
│ └── prompts/ # XML prompt templates
├── src/
│ ├── graph/
│ │ ├── builder.py # Graph construction and compilation (19 nodes)
│ │ ├── state.py # TutorState TypedDict (26 fields)
│ │ ├── supervisor.py # Intent routing + keypoint extraction (Qwen2.5-7B)
│ │ ├── academic.py # Parallel retrieval, answer generation, hallucination eval
│ │ ├── planner.py # Policy search + intelligence gathering
│ │ ├── plan_adversarial.py # Adversarial drafting/review + HIL feedback router
│ │ ├── emotional.py # Emotional support
│ │ └── llm.py # Centralized LLM factory + failover
│ ├── rag/ # Hybrid retrieval: vector + BM25 + reranker
│ ├── config/ # YAML settings loader + XML prompt cache
│ ├── database/ # PostgreSQL checkpointer lifecycle
│ ├── tracing/ # OTel setup, @traced_node decorator, SQLite exporter
│ └── schemas.py # Pydantic request models
├── frontend/
│ ├── app/page.tsx # Main page: SSE consumer, HIL feedback
│ └── components/
│ ├── chat-area.tsx # Message bubbles with Markdown rendering
│ ├── plan-review.tsx # HIL plan review component (edit/feedback/export)
│ ├── right-panel.tsx # Interactive DAG + node trail + logs
│ └── left-sidebar.tsx # Chat history
├── data/ # Exam papers (Chinese, Math)
├── scripts/ # Index building script
└── tests/ # Test suite (fully mocked)
```
---
## SSE Event Protocol
| Event | Description | Example Payload |
| ----- | ----------- | --------------- |
| `thread_id` | Session ID (stream start) | `{"type":"thread_id","thread_id":"abc..."}` |
| `node_event` | Node lifecycle | `{"type":"node_event","node":"drafter","status":"start"}` |
| `token` | Streaming token | `{"type":"token","content":"..."}` |
| `text` | Non-streaming node output | `{"type":"text","content":"...","node":"plan_output"}` |
| `usage` | Token usage | `{"type":"usage","node":"drafter","input_tokens":500}` |
| `interrupt` | HIL interrupt | `{"type":"interrupt","draft":"...","thread_id":"..."}` |
| `done` | Stream complete | `{"type":"done"}` |
| `error` | Error | `{"type":"error","message":"..."}` |
---
## Testing
```bash
# Unit tests (no live API required)
OTEL_TRACING_ENABLED=false python -m pytest tests/ --ignore=tests/test_integration.py -v --tb=short
# Frontend build check
cd frontend && npm run build
```
---
## License
[MIT](./LICENSE)