Auto-Scholar is a full-stack system for generating structured literature reviews with citation validation and a human approval step.
- Backend: FastAPI + LangGraph + SQLite checkpoint persistence
- Frontend: Next.js 16 + React 19 + Zustand + next-intl
- Main flow:
plan -> retrieve -> approve(interrupt) -> extract -> write -> QA -> reflection(conditional)
backend/main.py: FastAPI app lifecycle, REST routes, SSE streaming, export/session APIsbackend/workflow.py: LangGraph construction, retry router, interrupt configurationbackend/nodes.py: 6 core agentsplanner_agent: query decomposition (CoT for complex queries) and keyword generationretriever_agent: multi-source academic search with plan-aware routing and deduplicationextractor_agent: contribution extraction and structured fieldswriter_agent: outline + parallel section draftingcritic_agent: citation QA and error detectionreflection_agent: structured error classification and retry routing
backend/state.py:AgentStateTypedDict with append reducers (logs,messages,agent_handoffs)backend/schemas.py: Pydantic v2 contracts for APIs and internal modelsbackend/utils/scholar_api.py: Semantic Scholar / arXiv / PubMed clientsllm_client.py: structured LLM callsevent_queue.py: SSE debouncing queueexporter.py: Markdown/DOCX exportclaim_verifier.py: citation claim verification
frontend/src/app/: app shell and page entryfrontend/src/components/console/: query input, status, logs, historyapproval/: candidate paper review modal/tableworkspace/: generated review renderer, citations, charts, comparison table
frontend/src/store/research.ts: global workflow state (thread, papers, draft, logs)frontend/src/lib/api/: backend API client wrappersfrontend/src/i18n/: en/zh message catalogs
POST /api/research/start
- Creates
thread_id - Initializes LangGraph state
- Runs until interrupt point (
extractor_agent) to wait for human paper approval
GET /api/research/stream/{thread_id}
- Streams per-node logs via SSE
- Uses
StreamingEventQueueto reduce network chatter through debounce + boundary flush
POST /api/research/approve
- Marks candidate papers as approved
- Resumes graph execution from interrupt
- Produces
final_draftif QA passes (or after retry limit)
POST /api/research/continue
- Supports follow-up modifications to an existing draft
- Sets
is_continuation=Trueand re-enters at writer path
GET /api/research/evaluate/{thread_id}: quality metrics and evaluation reportPOST /api/research/export: Markdown/DOCX export with citation style
- Graph compile option
interrupt_before=["extractor_agent"]enforces explicit user approval before extraction. critic_agentwritesqa_errors; routing goes throughreflection_agent:- no errors -> end
- errors ->
reflection_agentclassifies errors (5 categories) and decides retry target - reflection routes to
writer_agent(fixable errors) orretriever_agent(needs more papers) retry_count >= 3-> end with latest draft regardless
- Checkpointer:
AsyncSqliteSaver - Config key:
configurable.thread_id - State can be resumed using
ainvoke(None, config) - Session endpoints list and inspect persisted threads from checkpoint history
PaperMetadata: unified schema for all paper sources- Draft sections initially use
{cite:N}placeholders - Backend post-processes to
[N]and maps tocited_paper_ids - QA checks citation existence/coverage and optional claim verification summary
- Async-first external I/O (
aiohttp) - Timeout guard for long workflow operations (
WORKFLOW_TIMEOUT_SECONDS) - Retry strategy in API client layer (tenacity)
- Concurrency controls for LLM extraction and fulltext enrichment
- SSE debouncing to reduce request frequency and improve UI smoothness