Watch an LLM grow a validated reasoning tree, refine each node with tools, and remember what works β live.
Demo Β· Mission Β· Why Β· How it works Β· Web UI Β· Quickstart Β· Results
demo.mp4
Two prompts, two domains β number theory (divisors of 196) and deep learning (the GELU formula) β each solved live: the agent plans a tree, expands candidate approaches, refines each with tools (
python_exec,calculator,arxiv_search,wikipediaβ¦), scores them, backtracks out of dead ends, and remembers what worked. Every step streams to the UI in real time.
Build an agent that learns. Most reasoning frameworks run each problem cold; ReTreVal accumulates what worked and what failed across runs and feeds it into every new attempt β one pipeline, any task, continuously improving, no fine-tuning.
ReTreVal treats reasoning as search with feedback β explore candidate paths as a tree, validate and prune them, then remember the outcome for next time. Concretely, that means:
- π³ Tree + validation, not just a chain β candidates are explored as a branching tree, each scored by self-eval and an external LLM critic; the best path advances.
- π οΈ Tools at every node β a ReAct loop lets the model call a calculator, equation solver,
python_exec, and web/Wikipedia/arXiv search to verify its reasoning instead of guessing. - π§ Memory that compounds β successful patterns and failure modes persist to disk and are injected into future problems; performance improves with scale, not just with a better model.
- π Backtracking β on a failed validation the agent navigates to an unexplored sibling with structured failure context, instead of giving up.
- π§© Task-agnostic β the same graph works across math, science, multiple-choice, and open-ended tasks; plug in a new evaluator, not a new agent.
- β‘ Four backends, one interface β Gemini, OpenAI, Ollama, and vLLM behind a provider-agnostic facade; swap with an env var.
- π Auditable β every node, score, tool call, and memory write is inspectable; the web UI renders the whole tree and trace.
ReTreVal is a compiled LangGraph state graph. For each problem it grows an adaptive reasoning tree whose depth/branching scale with estimated complexity. Each node self-improves through a tool-augmented ReAct loop, is scored by dual validation (0.6 Γ local self-eval + 0.4 Γ external critic), and on validation failure performs typed-failure backtracking. Hard problems are decomposed into sub-tasks. A persistent memory feeds past successes and failures into every new attempt.
| Step | What happens |
|---|---|
| Plan | Estimate complexity (1β5) and size the tree (depth/branching) adaptively; inject relevant memory. |
| Expand | Generate K candidate reasoning branches from the current node. |
| Tool-augmented refine | Each node runs a ReAct loop where the LLM calls tools (calculator, equation solver, python_exec, web/Wikipedia/arXiv) to verify and improve its reasoning. |
| Critique + dual score | Pairwise cross-critique plus local self-eval, combined as 0.6 Γ local + 0.4 Γ cross; the best branch advances. |
| Memory update | Insights and failure patterns are written back (de-duplicated, confidence-weighted) for future problems. |
| Decompose | Hard problems (complexity β₯ 4, low score) are split into dependency-ordered sub-tasks, solved, and aggregated. |
| Synthesize β Validate | Produce the final answer and validate it. By default the agent solves without seeing the reference answer; pass --oracle to let it use the reference (research only). |
| Backtrack | On validation failure, navigate to an unexplored sibling branch with structured failure context injected. |
The memory (src/utils/memory.py, class Memory) is a persistent buffer of structured entries β insights/successes (patterns that produced correct answers) and failures (what went wrong and why). Each entry carries a confidence score, and new entries are de-duplicated against existing ones by keyword (Jaccard) overlap rather than stored blindly. After every problem the outcome is written back, confidence is nudged up on success / down on failure, and the buffer is serialized to a human-readable memory.md (with an embedded JSON block for exact reload).
On the next problem the most relevant entries β ranked by keyword overlap Γ confidence β are injected into the prompts. The buffer persists across runs via that shared file, so a fresh batch picks up everything the previous batch learned. Memory is on by default; point it at a file with --memory-file <path> (or MEMORY_FILE), or disable it with --no-memory.
A chat where you can watch the agent think. Type a problem on the left; on the right the reasoning tree grows node-by-node and the trace streams live β then the validated answer (with rendered math/code) lands back in the chat.
%%{init: {'theme':'base', 'themeVariables': {'fontFamily':'Inter, sans-serif','lineColor':'#8b5cf6'}}}%%
flowchart LR
You([π§ You]) -->|"type a problem"| UI
UI["π₯οΈ Web UI Β· Next.js<br/>π¬ chat Β· π³ tree Β· π logs"] -->|"GET /api/solve"| API
API["βοΈ FastAPI bridge"] --> Agent["π€ LangGraphAgent<br/>plan β expand β refine β score β validate"]
Agent -. "live events stream back (SSE)" .-> UI
classDef pink fill:#fce7f3,stroke:#ec4899,color:#831843;
classDef violet fill:#ede9fe,stroke:#8b5cf6,color:#4c1d95;
class UI pink
class API,Agent violet
# 1 β backend bridge. Mock mode = no API key, streams a deterministic demo run.
cd retreval_oss && . .venv/bin/activate
pip install -r server/requirements.txt
RETREVAL_MOCK=1 uvicorn server.app:app --port 7373
# 2 β UI (in a second shell)
cd web && npm install && npm run dev # β http://localhost:7575Open http://localhost:7575. To drive the real agent instead of the mock,
configure a provider in .env (e.g. LLM_PROVIDER=gemini, GEMINI_API_KEY=β¦)
and start the backend without RETREVAL_MOCK. The UI auto-detects which
provider the backend is using.
- Ask anything β type a problem and press Enter, or click a suggested example. It's domain-general: math, science, coding, knowledge, or open-ended all work.
- Watch the tree (right, top) β every node is a candidate approach, colored by score; the β pink node is the current best and the highlighted edge is the active path. Drag to pan, scroll to zoom.
- Follow the trace (right, bottom) β
plan β expand β tool-refine β score β backtrack β synthesize β validate, with each tool call (calculator,python_exec,arxiv_search,wikipediaβ¦) and memory write streaming in. - Tune the run (top bar) β choose the provider, set iterations (how many tree passes), toggle memory, and switch π / βοΈ themes.
- Resize / focus β drag the divider to resize the panes, double-click it to reset to 50/50, or hit β to collapse the panel for a distraction-free chat.
Ports are chosen to be memorable and browser-safe: UI
7575, API7373.
Build a static bundle for deployment with npm run build (outputs web/out/, serve with any static host). More detail in web/README.md.
# 1 β clone and install
git clone https://github.com/qpiai/retreval.git && cd retreval
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# 2 β configure a provider
cp .env.example .env
# set LLM_PROVIDER and your API key in .env# 3 β solve a single problem
python -m src.agents.agent_main \
--provider gemini \
--prompt "How many positive whole-number divisors does 196 have?" \
--iterations 2 --verbose
# 4 β evaluate on MATH-500 (memory persists across runs)
python -m src.agents.math500_eval --provider gemini --limit 100 --iterations 1
# 5 β summarize a run
python analyze_results.py # newest run in results/math500/Results land in results/math500/math500_eval_YYYYMMDD_HHMMSS.jsonl. Run the evaluator again on the next batch β the memory from the first carries over automatically.
From the paper (arXiv 2601.02880).
π― 85.8% accuracy on MATH-500 (429/500), +7.2 pp over Self-Refine β and 54.4% on MMLU-Pro. Ablations confirm each component pulls its weight: removing memory drops accuracy to 76.8%, removing backtracking to 78.4%.
| Method | Accuracy |
|---|---|
| Zero-Shot CoT | 77.2% |
| ReAct | 73.2% |
| ToT | 77.4% |
| LATS | 77.6% |
| Self-Refine | 78.6% |
| ReTreVal | 85.8% |
Reproducibility note. The bundled
math500_eval.pyreports exact-match accuracy (the 85.8% metric β fast, deterministic, no extra API cost).
The OSS release ships a MATH-500 evaluator as the reference implementation; the agent itself is task-agnostic. The framework has been evaluated on MATH-500, GSM8K, GPQA, and creative writing. Adding a task needs two things: a loader (yields (question, expected_answer)) and an answer normalizer β everything else stays the same.
.
βββ src/
β βββ agents/ # LangGraph tree agent, per-node ReAct executor, CLI, MATH-500 eval
β βββ tools/ # planner, refiner+critique, dual scoring, feedback/backtrack,
β β # decomposition, synthesis, computation, search
β βββ clients/ # provider router + Gemini / OpenAI / Ollama / vLLM backends
β βββ utils/ # persistent Memory + vLLM KV-cache prompt structuring
βββ web/ # Next.js chat UI (chat Β· reasoning tree Β· live logs)
βββ server/ # FastAPI bridge β streams the agent to the UI over SSE
βββ scripts/ # headless-browser smoke test for the UI
βββ docs/ # demo.mp4 / demo.gif / screenshot.png
βββ data/math/ # bundled MATH-500 dataset
βββ results/math500/ # evaluation outputs (JSONL, timestamped)
βββ analyze_results.py # summarize a MATH-500 run (accuracy, by level/subject)
βββ run_math500_vllm.py
βββ .env.example
βββ requirements.txt
LLM provider β no code changes to switch backends
# Cloud
LLM_PROVIDER=gemini
GEMINI_API_KEY=...
GEMINI_MODEL=gemini-2.5-flash # or gemini-2.5-pro
LLM_PROVIDER=openai
OPENAI_API_KEY=...
OPENAI_MODEL=gpt-4o-mini # or gpt-4o
# Local
LLM_PROVIDER=ollama
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=qwen2.5:7b
LLM_PROVIDER=vllm
VLLM_BASE_URL=http://localhost:8000/v1
VLLM_MODEL=Qwen/Qwen2.5-7B-Instruct| Provider | Best for | Suggested models |
|---|---|---|
| Gemini | Free tier, strong reasoning | gemini-2.5-flash, gemini-2.5-pro |
| OpenAI | GPT-4o quality bar | gpt-4o-mini, gpt-4o |
| Ollama | On-premise, privacy | qwen2.5:7b, llama3.1:8b |
| vLLM | High-throughput local batch eval | Qwen/Qwen2.5-7B-Instruct, any HF repo |
Agent and memory settings
MAX_OUTPUT_TOKENS=2048
TEMPERATURE=0.7
MAX_DEPTH=5 # tree-depth cap (planner sets the adaptive value)
CHILDREN_PER_EXPANSION=3
MEMORY_FILE=memory.md # shared cross-problem memory file (default: <repo>/memory.md)Memory is enabled by default. Override the file per run with --memory-file <path>, or turn it off with --no-memory (both agent_main and math500_eval accept these flags).
vLLM KV-cache prefix optimization
Start vLLM with prefix caching, then run the convenience wrapper:
vllm serve Qwen/Qwen2.5-7B-Instruct --enable-prefix-caching
python run_math500_vllm.py --provider vllm --limit 100The vLLM client structures prompts so the system message and problem context are identical across calls within a problem, so vLLM's automatic prefix caching reuses those KV entries.
- Plug-in task interface β a formal
Task/Evaluatorprotocol so contributors can add GPQA and ARC without touching the agent. - Embedding-based memory retrieval β replace keyword (Jaccard) overlap with semantic search.
- Bundle the LLM-judge eval so the paper's judged scores are reproducible from the repo.
- Docker image β zero-setup container with Ollama + ReTreVal + the UI pre-wired.
Follow along β and please share ideas β in Issues.
Tree-of-Thoughts Β· ReAct Β· Reflexion Β· Self-Refine
ReTreVal stands on the shoulders of these wonderful projects β thank you to their authors and communities:
LangGraph Β· MATH-500 Β· Google Gemini Β· OpenAI Β· Ollama Β· vLLM Β· Next.js Β· React Flow.
Maintainers and contributors are listed in AUTHORS.md.
Contributions are very welcome β please see CONTRIBUTING.md to get started. The most helpful right now: new task evaluators (GPQA, ARC), the LLM-judge eval harness, and memory retrieval strategies. If ReTreVal is useful to you, a β would mean a lot β and thank you for taking a look.
Copyright 2026 QPIAI. Released under the Apache License 2.0.
