File size: 7,965 Bytes
4b24546
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bdc5edd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
---
title: Template Final Assignment
emoji: ๐Ÿ•ต๐Ÿปโ€โ™‚๏ธ
colorFrom: indigo
colorTo: indigo
sdk: gradio
sdk_version: 6.14.0
app_file: app.py
pinned: false
hf_oauth: true
hf_oauth_expiration_minutes: 480
---

Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference


# ๐ŸŒ GAIA Benchmark Agent

**An autonomous, multi-modal agent that tackles the GAIA reasoning benchmark.**

![Python](https://img.shields.io/badge/Python-3.13-blue.svg)
![LangGraph](https://img.shields.io/badge/LangGraph-Orchestration-orange.svg)
![HuggingFace](https://img.shields.io/badge/HuggingFace-Inference-yellow.svg)
![Supabase](https://img.shields.io/badge/Supabase-Vector_Store-green.svg)

> [!NOTE]
> Developed as part of the **Hugging Face Agents Course (Unit 4: GAIA)**.

## ๐Ÿ“– Overview

GAIA tasks require multi-step reasoning, tool use, and the ability to process diverse file types (documents, spreadsheets, audio, images, code). This agent uses a **LangGraph** state machine to plan, retrieve few-shot context, call tools, and produce a strictly-formatted answer.

The solver model is **`Qwen/Qwen3-32B`** via Hugging Face Inference Providers; the formatter (separate node) reuses the same model bound to a single `emit_final_answer` tool to enforce the strict GAIA output contract. A Supabase + BM25 hybrid retriever surfaces similar past tasks as few-shot exemplars.

## ๐Ÿš€ Key Features

- **๐Ÿง  Plan-Execute-Observe-Refine loop** driven by LangGraph.
- **๐Ÿชœ Two-stage output**: a solver node reasons freely, then a dedicated formatter node returns the GAIA-compliant answer via a Pydantic-shaped tool call โ€” eliminating regex parsing of the LLM's free text.
- **๐Ÿ“‚ Multi-modal file processing**:
  - **Documents**: PDF, Word (`.docx`), PowerPoint (`.pptx`), Text
  - **Data**: Excel (`.xlsx`, multi-sheet), CSV, JSON-LD, PDB (Protein Data Bank)
  - **Media**: Audio transcription (`openai/whisper-large-v3` via HF), image analysis (`Qwen/Qwen3-VL-32B-Instruct`)
  - **Code**: Python source files (read & execute)
  - **Archives**: ZIP extraction + inspection
- **๐Ÿ” Hybrid RAG**: Vector search (Supabase RPC over `Alibaba-NLP/gte-modernbert-base`) **+** BM25 over a local 165-question corpus, fused with Reciprocal Rank Fusion, then reranked with a ModernBERT cross-encoder.
- **๐ŸŒ Web tooling**: DuckDuckGo, Tavily, Wikipedia, ArXiv, full-page extraction (Trafilatura), YouTube transcripts.
- **๐Ÿ› ๏ธ Modular tool layout**: tools are organised by domain in `gaia/tools/` (basic, web, files, media, dispatcher) so adding a new capability is a single-file change.

## ๐Ÿ—๏ธ Architecture

```mermaid
graph TD
    START --> FileDL["File Downloader<br/>(fetches /files/{task_id})"]
    FileDL --> Retriever["Retriever<br/>(Vector + BM25 + RRF)"]
    Retriever --> Reranker["Reranker<br/>(ModernBERT cross-encoder)"]
    Reranker --> Processor["Solver<br/>(Qwen3-32B + tools)"]
    Processor -->|tool call| Tools["Tool Node"]
    Tools --> Processor
    Processor -->|done| Formatter["Formatter<br/>(emit_final_answer tool)"]
    Formatter --> END
```

| Node | Role |
| :--- | :--- |
| **`file_downloader_node`** | If the question has an associated file, download from `{api.base_url}/files/{task_id}` and cache on disk under `data/task_files/{task_id}/`. |
| **`retriever_node`** | Hybrid search: Supabase vector RPC + local BM25 over `data/metadata.jsonl`, fused with RRF. Returns up to 20 candidate task IDs. |
| **`reranker_node`** | `Alibaba-NLP/gte-reranker-modernbert-base` re-scores candidates and injects the top-K as few-shot examples (Question + Final Answer + Solution Steps). |
| **`processor_node`** | Qwen3-32B with all tools bound. Reasons, calls tools, loops until satisfied. |
| **`tools`** | LangGraph `ToolNode` executing the chosen tool, then returning control to the processor. |
| **`formatter_node`** | A second Qwen3-32B call bound to a single `emit_final_answer(answer: str)` tool โ€” produces the strictly-formatted value the GAIA scorer compares against. |

## ๐Ÿ› ๏ธ Stack

| Category | Libraries | Purpose |
| :--- | :--- | :--- |
| **Orchestration** | `langgraph`, `langchain`, `langchain-huggingface` | State graph, tool binding, structured output. |
| **LLM / VLM / ASR** | `huggingface_hub` Inference API | `Qwen/Qwen3-32B`, `Qwen/Qwen3-VL-32B-Instruct`, `openai/whisper-large-v3`. |
| **Embeddings & Vector Store** | `sentence-transformers`, `supabase` | Semantic search via `Alibaba-NLP/gte-modernbert-base`. |
| **Keyword search** | `bm25s` | Local BM25 index over the 165-question GAIA corpus. |
| **Documents** | `pypdf`, `python-docx`, `python-pptx`, `openpyxl` | Office formats. |
| **Data** | `polars`, `biopython` | Tabular and PDB structural analysis. |
| **Media** | `pillow`, `librosa`, `soundfile` | Image + audio I/O. |
| **Web** | `ddgs`, `tavily-python`, `wikipedia`, `arxiv`, `trafilatura`, `youtube-transcript-api` | Search, page extraction, captions. |
| **UI** | `gradio` | Evaluation runner (HF Space entry point). |

## ๐Ÿ’ป Installation & Setup

```bash
git clone <repo_url>
cd gaia
uv sync                            # or: pip install -r requirements.txt
cp .env.example .env               # populate the keys below
```

Required environment variables (place in `.env` or set as HF Space Secrets):

| Variable | Required? | Purpose |
| :--- | :--- | :--- |
| `HF_INFERENCE_KEY` | yes | Hugging Face token โ€” must have **"Make calls to Inference Providers"** permission. |
| `SUPABASE_URL` | yes (if `retrievers.enable_vector_search: true`) | Supabase project URL. |
| `SUPABASE_SERVICE_KEY` | yes (same) | Supabase `service_role` key. |
| `TAVILY_API_KEY` | optional | Only needed when the agent picks `tavily_web_search`. |

## ๐ŸŽฎ Usage

Start the Gradio interface:

```bash
python app.py
```

The UI requires a Hugging Face login. Click **"Run Evaluation & Submit All Answers"** to fetch the GAIA question set, run the agent on each, and submit to the scoring API.

To (re)populate the Supabase vector store from the local corpus:

```bash
python scripts/create_vector_database.py
```

## ๐Ÿ“‚ Project Structure

```
.
โ”œโ”€โ”€ app.py                              # HF Space entry point (Gradio)
โ”œโ”€โ”€ config.yaml                         # All tunable parameters
โ”œโ”€โ”€ pyproject.toml / requirements.txt   # Dependencies (uv + pip parity)
โ”œโ”€โ”€ gaia/                               # Application package
โ”‚   โ”œโ”€โ”€ agent.py                        # LangGraph nodes, graph, formatter
โ”‚   โ”œโ”€โ”€ states.py                       # AgentState TypedDict
โ”‚   โ”œโ”€โ”€ utils.py                        # config / prompt loaders, BM25, RRF, answer + youtube helpers
โ”‚   โ”œโ”€โ”€ prompts/
โ”‚   โ”‚   โ”œโ”€โ”€ prompt.yaml                 # Solver system prompt
โ”‚   โ”‚   โ””โ”€โ”€ vlm_prompt.yaml             # analyze_image system prompt
โ”‚   โ””โ”€โ”€ tools/
โ”‚       โ”œโ”€โ”€ __init__.py                 # Aggregates tools_list
โ”‚       โ”œโ”€โ”€ basic.py                    # calculator, python_eval
โ”‚       โ”œโ”€โ”€ web.py                      # ddg / tavily / wiki / arxiv / fetch_webpage / youtube_transcript
โ”‚       โ”œโ”€โ”€ files.py                    # PDF, DOCX, PPTX, TXT, CSV, XLSX, JSON-LD, PDB, Python, ZIP
โ”‚       โ”œโ”€โ”€ media.py                    # analyze_image (VLM), transcribe_audio (ASR), shared HF client
โ”‚       โ””โ”€โ”€ dispatcher.py               # read_file extension router
โ”œโ”€โ”€ scripts/
โ”‚   โ””โ”€โ”€ create_vector_database.py       # One-shot embedder for Supabase
โ”œโ”€โ”€ notebooks/                          # Exploratory work
โ”œโ”€โ”€ data/
โ”‚   โ””โ”€โ”€ metadata.jsonl                  # Local GAIA corpus (165 examples)
โ””โ”€โ”€ models/                             # HF model cache (gitignored)
```

All tunable knobs โ€” model IDs, retrieval depth, thinking mode, recursion limit โ€” live in `config.yaml`; no code change required to swap models or tweak retrieval.