README.md

August 14, 2026 · View on GitHub

ThinkRetrieve

PyPI Python License arXiv

Paper · PDF · Project page · Code


ThinkRetrieve makes a reasoning model recall worked examples mid-thought. Instead of only "thinking longer" (which drifts and compounds errors), it pauses at each reasoning step, retrieves the most similar solved example from a bank, and injects it into the thinking trace — guidance on how to reason, not just what facts to use.

It works over any chat API (OpenAI-compatible, Anthropic, Amazon Bedrock, or a local model via Ollama / LM Studio / MLX / llama.cpp) — no GPU or vLLM required.

pip install "thinkretrieve[faiss]"

The local example below requires a running model. With Ollama, download the tutorial model first:

ollama pull qwen3:4b

To verify a cloned repository without downloading a model, dataset, or embedding encoder, install the core package and run examples/offline_dummy.py:

git clone https://github.com/itsvaibhav01/ThinkRetrieve.git
cd ThinkRetrieve/thinkretrieve
python -m pip install -e .
python examples/offline_dummy.py

The full tutorial explains local and hosted models, required downloads, small smoke runs, full dataset runs, and troubleshooting.

Quickstart

from thinkretrieve import ThinkRetrieve, FaissRetriever, OpenAICompatBackend

# 1. A bank of solved (question, worked-solution) pairs — a dataset, your docs, past tickets…
bank = FaissRetriever.from_examples([
    ("A jacket costs \$120 and is discounted 25%. Final price?",
     "Discount = 0.25*120 = 30. Final = 120-30 = 90. Answer: \$90"),
    ("What is 15% of 80?", "0.15*80 = 12. Answer: 12"),
])

# 2. Any chat model — local (shown) or hosted.
backend = OpenAICompatBackend(model="qwen3:4b", base_url="http://localhost:11434/v1")

# 3. Reason with mid-thought retrieval.
result = ThinkRetrieve(backend, bank).run(
    "A phone costs \$250 after a 20% discount. What was the original price?")
print(result.answer)          # the final answer
print(result.think_trace)     # full reasoning, with injected examples visible
print(result.retrievals)      # what was retrieved, when, and why

How it works

How ThinkRetrieve works

At each reasoning boundary the model elicits an interim answer, retrieves the most similar solved example (E5 + FAISS by default), injects it into the trace, and continues — repeating until the thinking budget is spent. Passing retriever=None gives you the plain "think longer" baseline for A/B comparison.

Results

Across 5 reasoning models × 4 benchmarks (paper), ThinkRetrieve beats standard thinking, sequential test-time scaling (TTS), static in-context ICL, and random per-step retrieval on every cell — and, because injected tokens count against the budget but aren't generated, it produces fewer model tokens than TTS at the same budget (~6% wall-clock overhead).

Wins every cell

Sequential TTS degrades or plateaus as the budget grows; ThinkRetrieve keeps improving — most dramatically on the hardest benchmark:

Scaling behavior

Best accuracy (%)GSM-8KMATH-500AIME 2025
TTS / OursTTS / OursTTS / Ours
Qwen3-1.7B90.3 / 92.191.0 / 92.522.2 / 35.6
Qwen3-4B95.1 / 96.893.7 / 96.164.4 / 66.7
Qwen3-8B96.4 / 97.294.0 / 94.868.9 / 71.1

Use cases

1 · Reason over a dataset (math, science QA, …)

Index any dataset with worked solutions and go. See examples/sciq_example.py for a full SciQ run (build bank from the train split → answer test questions → score):

python examples/sciq_example.py --limit 30

Ready-made banks: NuminaMath, MetaMathQA, GSM8K, MATH, SciQ — anything with (question, step-by-step solution) pairs.

2 · Procedural memory for agents

Most agent memory stores facts. A ThinkRetrieve bank stores procedures — solved tasks — and recalls them mid-reasoning. The bank grows as the agent works (examples/agent_memory.py):

result = agent.run(task)
if verified(result):            # tests pass / human approves
    memory.add(task, result.answer)   # the agent now remembers HOW
    memory.save("agent_memory")

A measured local example of this pattern is the science diagnosis → tool dispatch case study, including its runner, four controls, raw 4B/9B outputs, and limitations.

3 · Upgrade an existing RAG stack

Prompt-level RAG is ~neutral on reasoning tasks; injecting the same content inside the trace is what wins (paper §5). Keep your index — wrap it in a 5-line retriever (examples/rag_integration.py):

from thinkretrieve.types import Example

class MyStore:                              # pgvector / Pinecone / Chroma / …
    def retrieve(self, question, interim_answer="", k=1, exclude_ids=frozenset()):
        hits = my_index.search(f"{question}\n{interim_answer}", k + len(exclude_ids))
        return [Example(id=h.id, question=h.q, solution=h.body)
                for h in hits if h.id not in exclude_ids][:k]

ThinkRetrieve(backend, MyStore()).run(question)
Compare it yourself (one command)
python examples/compare_tts_vs_thinkretrieve.py --backend openai --model qwen3:4b

Runs plain / RAG / long-thinking / ThinkRetrieve at the same budget and prints the table. Add --backend bedrock --model qwen.qwen3-32b-v1:0 for Amazon Bedrock.

Backends

BackendImportUse for
OpenAI-compatibleOpenAICompatBackendOllama, LM Studio, MLX, llama.cpp, vLLM, OpenAI, Together, Groq, DeepSeek, OpenRouter
AnthropicAnthropicBackendClaude models (pip install "thinkretrieve[anthropic]")
Amazon BedrockBedrockConverseBackendBedrock models (pip install "thinkretrieve[bedrock]")

Or subclass ChatTranscriptBackend and implement one _chat() method.

Install options

pip install "thinkretrieve[faiss]"            # core + FAISS retrieval (recommended)
pip install "thinkretrieve[faiss,anthropic]"  # + Anthropic
pip install "thinkretrieve[all]"              # everything

No GPU needed: retrieval runs on CPU / Apple Silicon; generation runs wherever your model lives. Full walkthrough in TUTORIAL.md.

Citation

@article{thinkretrieve2026,
  title  = {ThinkRetrieve: Retrieval-Augmented Reasoning Traces for Test-Time Scaling},
  author = {Singh, Vaibhav and Ghosal, Soumya Suvra and Gharat, Sarvesh and
            Pal, Soumyabrata and Narayanam, Ramasuri and Manocha, Dinesh},
  journal = {arXiv preprint arXiv:2608.10928},
  year   = {2026},
  url    = {https://arxiv.org/abs/2608.10928}
}

License

MIT