KJ12124/GAREN

Python

0

3 commits

updated Sep 4, 2026

See the code

README

GAREN

This repository contains the official implementation for our EMNLP 2026 paper:

Group-Aware Adaptive Retrieval for Evidence Navigation June Park*, Jun Kwon*, Jonghyo Kim, Jongwuk Lee† (* : equal contribution) Sungkyunkwan University, Republic of Korea

Official paper: arXiv:2609.02188

Overview

GAREN Overview

Reasoning-intensive retrieval addresses queries whose relevance cannot be identified by surface-level matching, thereby requiring multi-step reasoning. Because relevant documents rarely appear in the initial candidate set, retrieval systems suffer from the bounded recall problem. Existing methods iteratively expand a candidate pool at the document level over a corpus graph, examining each neighbor in isolation and drifting toward a narrow region of the corpus. To address this problem, we propose Group-Aware Adaptive Retrieval for Evidence Navigation (GAREN), which explores the corpus graph through group-level expansion. GAREN organizes documents into semantically coherent and distinguishable groups based on their connections in the corpus graph. The information in each group indicates what can be accessed by expanding through it, providing guidance beyond individual document-level signals. At each iteration, GAREN uses a group-level navigator to identify promising expansion directions, retrieves documents from the selected groups, and applies a document-level Reranker to evaluate the updated candidate set. Extensive experiments show that GAREN achieves up to 8.0% improvement over the strongest baseline on BRIGHT.

Method at a glance

ComponentRoleModel
RerankerListwise document reranking over the current window (Step 1)Qwen/Qwen3-Next-80B-A3B-Instruct-FP8
NavigatorPointwise group scoring that picks expansion directions (Step 2)Qwen/Qwen3-Reranker-4B
Evidence PropagationCluster-coherent post-hoc rerank; lifts documents sharing a group with high-ranked evidence—

At each iteration the Navigator scores the top-K_g voted groups, GAREN pulls documents from the selected groups into the next window, and the Reranker re-evaluates it. The candidate picking policy follows an explore → exploit schedule: early iterations spread the expansion budget across groups (breadth-first), and after --pick_transition iterations it concentrates on the highest-scoring groups (depth-first).

Setup Environment

conda env create -f environment.yaml
conda activate GAREN

The group construction stage additionally needs graspologic (Leiden community detection) and faiss (exact-cosine k-NN):

conda install -c conda-forge graspologic faiss-gpu

How to Use

GAREN runs in two stages: (A) build the group structure once per corpus, then (B) run retrieval. Both stages talk to vLLM servers over an OpenAI-compatible API.

0. Launch the model servers

# Reranker (Step 1) — Qwen3-Next-80B on GPUs 0,1, port 9201
bash bash/server/start_qwen3next80b_server.sh 0,1 9201

# Navigator (Step 2) — Qwen3-Reranker-4B /score endpoint on GPU 2, port 9202
GPUS=2 PORT=9202 bash bash/server/start_start_qwen3re4b.sh

The Navigator is served in sequence-classification mode (/score, /v1/rerank) via --hf_overrides; the launch script sets this up.

A. Build the group structure

# 1. Corpus → document embeddings → doc-doc k-NN graph  (Qwen3-Embedding-4B)
bash bash/build_group/build_graph.sh

# 2. k-NN graph → Leiden L1 communities → LLM group summaries   (needs the Reranker server)
bash bash/build_group/build_group.sh

# 3. graph + communities → L0↔L1 anchors
bash bash/build_group/build_anchor.sh

Each step writes into data/ and skips work that already exists (FORCE=1 to rebuild):

data/corpus/<task>.jsonl                          input corpus
data/embed/<task>_corpus_embs.pt                  document embeddings
data/GRAPH/qwen3/graph/<task>/                    L0 doc-doc k-NN graph
data/GRAPH/qwen3/summary/<task>/                  L1 communities + group summaries
data/anchor/<task>/{l0_l1_anchor,l1_doc_ids}.json L0↔L1 anchors
data/first_stage/bm25/                            first-stage retrieval caches

If you already have a k-NN graph in this format, skip step 1.

B. Run GAREN

# Default: BM25 + original queries, all 12 BRIGHT categories
bash bash/run_ours.sh

# A subset of tasks
TASKS="biology earth_science" bash bash/run_ours.sh

# A different first-stage retriever / prompt
RETRIEVER=reasonir PROMPT_MODE=reasoning_and_ranking bash bash/run_ours.sh

Results land in results/main_table_<model>_<prompt>/ours_<navigator>_<retriever>_<query_type>/<task>/.

Ablations

ABL=eval_neigh            bash bash/run_ours_ablation.sh   # score graph neighbours, no groups
ABL=explore_full          bash bash/run_ours_ablation.sh   # explore every iteration
ABL=exploit_full          bash bash/run_ours_ablation.sh   # exploit every iteration
ABL=no_page_aware         bash bash/run_ours_ablation.sh   # w/o Evidence Propagation
ABL=topk10                bash bash/run_ours_ablation.sh   # Navigator budget K_g = 10
ABL=topk30                bash bash/run_ours_ablation.sh   # Navigator budget K_g = 30

The explore→exploit transition point is swept with PICK_TRANSITION:

PICK_TRANSITION=2 ABL=explore_then_exploit bash bash/run_ours_ablation.sh

Key Hyperparameters

Defaults match the main-table configuration; every knob is an environment variable for the bash scripts and a CLI flag for python -m scripts.run.

ParameterDefaultDescription
--n_iters9Expansion iterations
--window_size20Reranker window size
--top_keep10Documents carried over per iteration (expansion slots = 20 − 10)
--top_k_groups20Navigator budget K_g: groups scored per iteration
--top_k_docs1000First-stage candidate pool
--pick_modeexplore_then_exploitexplore | exploit | explore_then_exploit
--pick_transition4Iteration at which the schedule switches to exploit
--max_dlen512Document truncation length
--pa_p / --pa_alphaprompt-mode specificEvidence Propagation: RBP persistence / sibling-lift weight

Evidence Propagation is on by default (--no_page_aware disables it). Its two weights default per prompt mode: relevance → (p=0.60, α=0.01), reasoning_and_ranking → (p=0.50, α=0.01).

Repository Layout

GAREN/
├── scripts/                     # Retrieval pipeline
│   ├── run.py                   # Entry point (--task ours)
│   ├── parser.py                # CLI arguments
│   ├── pipeline.py              # run_ours: wiring, I/O, evaluation
│   ├── ours_pipeline.py         # GAREN loop (voting, expansion, EvalNeigh ablation)
│   ├── reranker.py              # Reranker — listwise document reranking (Step 1)
│   ├── navigator.py             # Navigator — pointwise group scoring (Step 2)
│   ├── evidence_propagation.py  # Cluster-coherent post-hoc rerank
│   └── llm.py / dataset.py      # vLLM client, dataset wrappers
├── hier_community/              # Group construction (preprocessing)
│   ├── embed_corpus.py          # Corpus → embeddings (Qwen3-Embedding-4B)
│   ├── build_knn_graph.py       # Embeddings → doc-doc k-NN graph (faiss, exact cosine)
│   ├── build_hierarchy.py       # Leiden communities + LLM group summaries
│   └── build_anchor.py          # L0↔L1 anchors
├── bash/
│   ├── build_group/             # build_graph.sh · build_group.sh · build_anchor.sh
│   ├── server/                  # vLLM launch scripts
│   ├── run_ours.sh              # Main runner
│   └── run_ours_ablation.sh     # Ablation sweeps
├── utils/                       # Prompts and shared helpers
└── environment.yaml

Dataset

All preprocessed artifacts are released on the Hub: Jun421/GAREN-data (6.7 GB).

hf download Jun421/GAREN-data --repo-type=dataset --local-dir data/

This gives you everything the runners expect — chunked corpora, queries, BM25 first-stage caches, L0 k-NN graphs, L1 group summaries, and L0↔L1 anchors — so you can skip bash/build_group/*.sh entirely and go straight to bash bash/run_ours.sh.

PathDescription
data/corpus/<task>.jsonChunked corpus (docno, content)
data/qa_data/<task>.jsonQueries with gold_ids, excluded_ids
data/GRAPH/qwen3/graph/<task>/L0 doc–doc k-NN graph (k=16)
data/GRAPH/qwen3/summary/<task>/L1 communities + group summaries
data/anchor/<task>/l0_l1_anchor.json, l1_doc_ids.json
data/first_stage/bm25/BM25 first-stage caches (top-1000)

Covers all 12 BRIGHT categories: 1,333,166 documents, 1,384 queries, 121,349 L1 groups. The artifacts are derived from BRIGHT (Su et al., 2024) — please cite it alongside our paper.

Citation

If you find our work useful for your research, please cite our paper:

@misc{park2026groupawareadaptiveretrievalevidence,
      title={Group-Aware Adaptive Retrieval for Evidence Navigation},
      author={June Park and Jun Kwon and Jonghyo Kim and Jongwuk Lee},
      year={2026},
      eprint={2609.02188},
      archivePrefix={arXiv},
      primaryClass={cs.IR},
      url={https://arxiv.org/abs/2609.02188},
}

KJ12124/GAREN

Python

0

3 commits

updated Sep 4, 2026

See the code

README

GAREN

This repository contains the official implementation for our EMNLP 2026 paper:

Group-Aware Adaptive Retrieval for Evidence Navigation June Park*, Jun Kwon*, Jonghyo Kim, Jongwuk Lee† (* : equal contribution) Sungkyunkwan University, Republic of Korea

Official paper: arXiv:2609.02188

Overview

GAREN Overview

Reasoning-intensive retrieval addresses queries whose relevance cannot be identified by surface-level matching, thereby requiring multi-step reasoning. Because relevant documents rarely appear in the initial candidate set, retrieval systems suffer from the bounded recall problem. Existing methods iteratively expand a candidate pool at the document level over a corpus graph, examining each neighbor in isolation and drifting toward a narrow region of the corpus. To address this problem, we propose Group-Aware Adaptive Retrieval for Evidence Navigation (GAREN), which explores the corpus graph through group-level expansion. GAREN organizes documents into semantically coherent and distinguishable groups based on their connections in the corpus graph. The information in each group indicates what can be accessed by expanding through it, providing guidance beyond individual document-level signals. At each iteration, GAREN uses a group-level navigator to identify promising expansion directions, retrieves documents from the selected groups, and applies a document-level Reranker to evaluate the updated candidate set. Extensive experiments show that GAREN achieves up to 8.0% improvement over the strongest baseline on BRIGHT.

Method at a glance

ComponentRoleModel
RerankerListwise document reranking over the current window (Step 1)Qwen/Qwen3-Next-80B-A3B-Instruct-FP8
NavigatorPointwise group scoring that picks expansion directions (Step 2)Qwen/Qwen3-Reranker-4B
Evidence PropagationCluster-coherent post-hoc rerank; lifts documents sharing a group with high-ranked evidence—

At each iteration the Navigator scores the top-K_g voted groups, GAREN pulls documents from the selected groups into the next window, and the Reranker re-evaluates it. The candidate picking policy follows an explore → exploit schedule: early iterations spread the expansion budget across groups (breadth-first), and after --pick_transition iterations it concentrates on the highest-scoring groups (depth-first).

Setup Environment

conda env create -f environment.yaml
conda activate GAREN

The group construction stage additionally needs graspologic (Leiden community detection) and faiss (exact-cosine k-NN):

conda install -c conda-forge graspologic faiss-gpu

How to Use

GAREN runs in two stages: (A) build the group structure once per corpus, then (B) run retrieval. Both stages talk to vLLM servers over an OpenAI-compatible API.

0. Launch the model servers

# Reranker (Step 1) — Qwen3-Next-80B on GPUs 0,1, port 9201
bash bash/server/start_qwen3next80b_server.sh 0,1 9201

# Navigator (Step 2) — Qwen3-Reranker-4B /score endpoint on GPU 2, port 9202
GPUS=2 PORT=9202 bash bash/server/start_start_qwen3re4b.sh

The Navigator is served in sequence-classification mode (/score, /v1/rerank) via --hf_overrides; the launch script sets this up.

A. Build the group structure

# 1. Corpus → document embeddings → doc-doc k-NN graph  (Qwen3-Embedding-4B)
bash bash/build_group/build_graph.sh

# 2. k-NN graph → Leiden L1 communities → LLM group summaries   (needs the Reranker server)
bash bash/build_group/build_group.sh

# 3. graph + communities → L0↔L1 anchors
bash bash/build_group/build_anchor.sh

Each step writes into data/ and skips work that already exists (FORCE=1 to rebuild):

data/corpus/<task>.jsonl                          input corpus
data/embed/<task>_corpus_embs.pt                  document embeddings
data/GRAPH/qwen3/graph/<task>/                    L0 doc-doc k-NN graph
data/GRAPH/qwen3/summary/<task>/                  L1 communities + group summaries
data/anchor/<task>/{l0_l1_anchor,l1_doc_ids}.json L0↔L1 anchors
data/first_stage/bm25/                            first-stage retrieval caches

If you already have a k-NN graph in this format, skip step 1.

B. Run GAREN

# Default: BM25 + original queries, all 12 BRIGHT categories
bash bash/run_ours.sh

# A subset of tasks
TASKS="biology earth_science" bash bash/run_ours.sh

# A different first-stage retriever / prompt
RETRIEVER=reasonir PROMPT_MODE=reasoning_and_ranking bash bash/run_ours.sh

Results land in results/main_table_<model>_<prompt>/ours_<navigator>_<retriever>_<query_type>/<task>/.

Ablations

ABL=eval_neigh            bash bash/run_ours_ablation.sh   # score graph neighbours, no groups
ABL=explore_full          bash bash/run_ours_ablation.sh   # explore every iteration
ABL=exploit_full          bash bash/run_ours_ablation.sh   # exploit every iteration
ABL=no_page_aware         bash bash/run_ours_ablation.sh   # w/o Evidence Propagation
ABL=topk10                bash bash/run_ours_ablation.sh   # Navigator budget K_g = 10
ABL=topk30                bash bash/run_ours_ablation.sh   # Navigator budget K_g = 30

The explore→exploit transition point is swept with PICK_TRANSITION:

PICK_TRANSITION=2 ABL=explore_then_exploit bash bash/run_ours_ablation.sh

Key Hyperparameters

Defaults match the main-table configuration; every knob is an environment variable for the bash scripts and a CLI flag for python -m scripts.run.

ParameterDefaultDescription
--n_iters9Expansion iterations
--window_size20Reranker window size
--top_keep10Documents carried over per iteration (expansion slots = 20 − 10)
--top_k_groups20Navigator budget K_g: groups scored per iteration
--top_k_docs1000First-stage candidate pool
--pick_modeexplore_then_exploitexplore | exploit | explore_then_exploit
--pick_transition4Iteration at which the schedule switches to exploit
--max_dlen512Document truncation length
--pa_p / --pa_alphaprompt-mode specificEvidence Propagation: RBP persistence / sibling-lift weight

Evidence Propagation is on by default (--no_page_aware disables it). Its two weights default per prompt mode: relevance → (p=0.60, α=0.01), reasoning_and_ranking → (p=0.50, α=0.01).

Repository Layout

GAREN/
├── scripts/                     # Retrieval pipeline
│   ├── run.py                   # Entry point (--task ours)
│   ├── parser.py                # CLI arguments
│   ├── pipeline.py              # run_ours: wiring, I/O, evaluation
│   ├── ours_pipeline.py         # GAREN loop (voting, expansion, EvalNeigh ablation)
│   ├── reranker.py              # Reranker — listwise document reranking (Step 1)
│   ├── navigator.py             # Navigator — pointwise group scoring (Step 2)
│   ├── evidence_propagation.py  # Cluster-coherent post-hoc rerank
│   └── llm.py / dataset.py      # vLLM client, dataset wrappers
├── hier_community/              # Group construction (preprocessing)
│   ├── embed_corpus.py          # Corpus → embeddings (Qwen3-Embedding-4B)
│   ├── build_knn_graph.py       # Embeddings → doc-doc k-NN graph (faiss, exact cosine)
│   ├── build_hierarchy.py       # Leiden communities + LLM group summaries
│   └── build_anchor.py          # L0↔L1 anchors
├── bash/
│   ├── build_group/             # build_graph.sh · build_group.sh · build_anchor.sh
│   ├── server/                  # vLLM launch scripts
│   ├── run_ours.sh              # Main runner
│   └── run_ours_ablation.sh     # Ablation sweeps
├── utils/                       # Prompts and shared helpers
└── environment.yaml

Dataset

All preprocessed artifacts are released on the Hub: Jun421/GAREN-data (6.7 GB).

hf download Jun421/GAREN-data --repo-type=dataset --local-dir data/

This gives you everything the runners expect — chunked corpora, queries, BM25 first-stage caches, L0 k-NN graphs, L1 group summaries, and L0↔L1 anchors — so you can skip bash/build_group/*.sh entirely and go straight to bash bash/run_ours.sh.

PathDescription
data/corpus/<task>.jsonChunked corpus (docno, content)
data/qa_data/<task>.jsonQueries with gold_ids, excluded_ids
data/GRAPH/qwen3/graph/<task>/L0 doc–doc k-NN graph (k=16)
data/GRAPH/qwen3/summary/<task>/L1 communities + group summaries
data/anchor/<task>/l0_l1_anchor.json, l1_doc_ids.json
data/first_stage/bm25/BM25 first-stage caches (top-1000)

Covers all 12 BRIGHT categories: 1,333,166 documents, 1,384 queries, 121,349 L1 groups. The artifacts are derived from BRIGHT (Su et al., 2024) — please cite it alongside our paper.

Citation

If you find our work useful for your research, please cite our paper:

@misc{park2026groupawareadaptiveretrievalevidence,
      title={Group-Aware Adaptive Retrieval for Evidence Navigation},
      author={June Park and Jun Kwon and Jonghyo Kim and Jongwuk Lee},
      year={2026},
      eprint={2609.02188},
      archivePrefix={arXiv},
      primaryClass={cs.IR},
      url={https://arxiv.org/abs/2609.02188},
}