Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/projects/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ They're optional and ungraded. Browse them any time — each project's intro say

<ProjectChooser
projects={mergeProjectMeta([
{
id: 'multihop-wikipedia-qa',
title: 'Build a Multi-Hop QA Tool Over a Wikipedia Sample',
summary:
'Build a two-round RAG pipeline that answers questions whose facts live in two different articles — and audit every evidence chunk it used, where single-pass retrieval gets them wrong.',
},
{
id: '2027-dependency-freshness-checker',
title: 'Build a Dependency-Freshness Checker',
Expand Down
4 changes: 4 additions & 0 deletions docs/projects/multihop-wikipedia-qa/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "MultihopWikipediaQA",
"position": 25
}
652 changes: 652 additions & 0 deletions docs/projects/multihop-wikipedia-qa/index.md

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions examples/multihop-wikipedia-qa/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copy this file to .env (already gitignored) and fill in the key for
# whichever provider you choose -- you only need ONE of the keys below.
# Never commit a real key.

# Which provider to use: github (default), gemini, groq, mistral, cerebras,
# or openrouter. See main.py's PROVIDERS dict for what each one needs.
LLM_PROVIDER=github

# github (default) -- a GitHub personal access token with the "models: read"
# scope. Free, no separate signup: https://github.com/settings/tokens
GITHUB_TOKEN=

# gemini -- free-tier key from https://aistudio.google.com/
GOOGLE_API_KEY=

# groq -- free-tier key from https://console.groq.com/keys
GROQ_API_KEY=

# mistral -- free-tier key from https://console.mistral.ai/api-keys
MISTRAL_API_KEY=

# cerebras -- free-tier key from https://cloud.cerebras.ai/
CEREBRAS_API_KEY=

# openrouter -- free-tier key from https://openrouter.ai/keys
OPENROUTER_API_KEY=
6 changes: 6 additions & 0 deletions examples/multihop-wikipedia-qa/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.venv
__pycache__
*.pyc
.env
data/index.npy
data/chunks.json
1 change: 1 addition & 0 deletions examples/multihop-wikipedia-qa/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
69 changes: 69 additions & 0 deletions examples/multihop-wikipedia-qa/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Multi-Hop Wikipedia QA Example

The local companion to the course's [Build a Multi-Hop Question-Answering Tool Over a Small Wikipedia Sample](../../docs/projects/multihop-wikipedia-qa/index.md) project — a two-round retrieval pipeline that answers questions whose facts live in *two different* documents, and shows you the exact evidence chain it used to do it.

## What's here

- `data/articles/` — six short, plain-text Wikipedia-style articles (fictional but realistic: biographies, companies, cities, an event), committed so the retrieval steps run out of the box with no setup. They're *crafted* so a few questions genuinely need facts from two articles at once.
- `data/test_questions.json` — six bundled test questions, three of them genuinely multi-hop (the answer only exists once two articles' facts are combined), each with an `expected` answer so you can audit the tool's output against a known ground truth.
- `main.py` — the whole tool in one file:
- `build_index()` — splits the articles into chunks and embeds them locally with `sentence-transformers`, saving `data/index.npy` + `data/chunks.json` (both gitignored).
- `retrieve(question, ...)` — cosine-similarity search over the chunks with `numpy`.
- `single_hop(...)` — the baseline: retrieve the top-K chunks once and answer from only those.
- `multi_hop(...)` — the point of the project: retrieve, ask the model whether the evidence is enough, and if not retrieve a **second round** guided by the model's own follow-up query, then answer from the merged evidence.
- Side-by-side output — both answers printed as aligned columns with every evidence chunk each one used.
- `notebook.ipynb` — a Colab/Kaggle/Binder-ready notebook that mirrors the same pipeline with the articles embedded directly in it (no local files needed).

## Running it

```bash
uv sync
uv run python main.py --rebuild # embeds data/articles/ -- local, no API key
uv run python main.py # runs the six bundled test questions, single-hop vs multi-hop
```

Retrieval is fully local; only the answer generation calls a hosted model, which needs a free-tier API key:

1. **Get a free-tier API key** from your chosen provider — see the table in the [lesson's Setup section](../../docs/projects/multihop-wikipedia-qa/index.md#get-a-free-llm-api-key) for where to get one for each.
2. **Copy `.env.example` to `.env`** and fill in the key for your provider:
```bash
cp .env.example .env
# then edit .env
```
`.env` is already gitignored — never commit a real key.
3. **Run it**:
```bash
uv run python main.py # bundled test questions + scoreboard
uv run python main.py --question "Who founded the company that powered TransLisboa's electric buses?"
uv run python main.py --query # interactive mode
uv run python main.py --provider groq # pick a non-default provider
```

`uv` reads `pyproject.toml`/`uv.lock` and creates an isolated environment for this project automatically on first run. The embedding model (`all-MiniLM-L6-v2`, ~80MB) also downloads on first run.

## What the comparison is supposed to show

Run the default `uv run python main.py` and watch the three multi-hop questions: single-hop retrieves the *clue* article but not the *fact* article, so it either says "the context doesn't say" or guesses a plausible-sounding answer; multi-hop spots the gap, writes a follow-up search query, pulls the second article, and answers correctly. Every chunk is printed beside each answer so you can see exactly why.

Two honest caveats, spelled out in the lesson too: this is a deliberately minimal version of what researchers call **iterative retrieval** — real multi-hop QA systems do far more — and on such a small corpus single-hop will sometimes *accidentally* land the right chunks and get a multi-hop question right by luck. The scoreboard prints both pipelines' totals against the expected answers, so you can see the trend rather than trusting any single question.

## Running it in GitHub Codespaces

Click into a [Codespace for the whole repo](https://codespaces.new/abderrahim-lectures/python-data-analysis-course) (Node, Python, and `uv` are preinstalled per `.devcontainer/devcontainer.json`), then:

```bash
cd examples/multihop-wikipedia-qa
uv sync
uv run python main.py --rebuild
uv run python main.py
```

(add your API key as a [Codespaces secret](https://docs.github.com/en/codespaces/managing-your-codespaces/managing-encrypted-secrets-for-your-repository-and-organization#adding-secrets-for-a-repository) or `export` it for a one-off session before the answer-generation step).

## A note on staying current

Model names, provider free-tier terms, and library APIs change fast. `all-MiniLM-L6-v2` and the six provider endpoints in `main.py`'s `PROVIDERS` dict were verified against live runs while writing this example, but check each provider's own docs before relying on them — they may have drifted by the time you read this.

## Built your own version?

See [`examples/student-projects/`](../student-projects/) for how to share it with the class via a pull request — no git experience required, it walks through every step.
21 changes: 21 additions & 0 deletions examples/multihop-wikipedia-qa/data/articles/amina-rahman.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Amina Rahman

**Amina Rahman** (born 1975) is a Bangladeshi biochemist known for developing the industrial extraction process used to make protein from microalgae.

## Early life and education

Rahman was born in 1975 in Dhaka, the capital of Bangladesh. She studied chemistry at the University of Dhaka and earned a PhD in biochemistry from the same institution in 2001, writing her dissertation on protein recovery from single-celled organisms.

## Career

After a postdoctoral fellowship in Singapore, Rahman returned to the University of Dhaka as a lecturer. In 2011 she was recruited by a Swiss biotechnology startup as its chief scientist, where she led the development of a scalable method for extracting protein from cultivated microalgae.

Her extraction method, which uses a mild enzymatic treatment instead of harsh solvents, became the production process behind the company's flagship product. Industry analysts credited the method's low cost with making algae-based protein commercially viable for the first time.

## Recognition

In 2018 Rahman received the international Women in Biotechnology Award for her work on sustainable protein production. She has published more than forty peer-reviewed papers and holds three patents related to microalgae processing.

## Personal life

Rahman continues to live and work in Switzerland, but travels regularly to Bangladesh, where she mentors students at her alma mater and funds a small scholarship for women in the natural sciences.
21 changes: 21 additions & 0 deletions examples/multihop-wikipedia-qa/data/articles/basel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Basel

**Basel** is the third-largest city in Switzerland, located on the Rhine River where the Swiss, French, and German borders meet. It is a major center of the pharmaceutical and life-sciences industries.

## Geography and population

Basel sits at the point where Switzerland, France, and Germany come together, giving it the nickname "the three-country city". Its metropolitan population is just over 500,000, and the city is a major railway and freight hub for central Europe.

## Life sciences industry

Basel is home to some of the world's largest pharmaceutical companies, along with a dense cluster of smaller biotechnology startups. One such startup, the microalgae protein company Cereolabs, was founded in this city in 2009 by a group of researchers who had left a nearby university institute. The city's research hospitals and university labs are a major draw for young scientists.

## The Basel Climate Accord

In 2019, Basel hosted the signing of the **Basel Climate Accord**, an international agreement in which participating governments committed to cutting greenhouse-gas emissions from road transport. The accord's signing ceremony was held at the city's conference center, and the agreement is named after the city as a result.

Several transport and battery-industry firms later cited the accord as a driver of demand for electric vehicles, and analysts frequently referenced it when discussing the growth of the electric bus market in Europe.

## Tourism and culture

Basel is known for its art museums, including a prominent collection of modern and contemporary art, and for its annual carnival, one of the largest in Europe. The city's old town is a popular destination for weekend visitors from the neighboring countries.
21 changes: 21 additions & 0 deletions examples/multihop-wikipedia-qa/data/articles/cereolabs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Cereolabs

**Cereolabs** is a Swiss biotechnology company that produces protein from cultivated microalgae. It is best known for launching **AquaPro**, the first commercially available algae-based protein powder for human consumption.

## History

The company was founded in 2009 by a group of former university researchers, and built its first pilot facility two years later. It remained a small research firm for its early years, funding itself through government grants and a single early angel investment.

## Products

Cereolabs' flagship product, AquaPro, launched in 2017. It is a neutral-tasting protein powder made from microalgae grown in closed bioreactors, marketed as a sustainable alternative to soy and whey protein. The production process is built around a mild enzymatic extraction method developed by the company's chief scientist, who joined the firm in 2011.

The company also sells a concentrated algae paste, marketed under the name "Aqualift", to food manufacturers as an ingredient for plant-based meat products.

## Facilities

Cereolabs operates its headquarters and main production facility in an industrial district on the outskirts of its home city, along with a second laboratory opened in Lisbon in 2022. The Lisbon lab focuses on consumer product formulation.

## Business

In 2021, following strong sales of AquaPro in European supermarkets, Cereolabs raised a Series B funding round led by a London-based investment firm. The company has stated that it plans to open a production plant in North America by 2028.
21 changes: 21 additions & 0 deletions examples/multihop-wikipedia-qa/data/articles/elena-marchetti.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Elena Marchetti

**Elena Marchetti** (born 1963) is an Italian electrical engineer best known for founding one of Europe's earliest dedicated lithium-ion battery manufacturers.

## Early life and education

Marchetti was born in 1963 in the city of Naples, in southern Italy. She studied electrical engineering at the Polytechnic University of Turin, where she focused on electrochemical energy storage and wrote a thesis on the thermal management of rechargeable battery packs.

## Career

In 1992, at the age of 29, Marchetti founded a battery manufacturing company in the city of Turin and served as its first chief executive. The company grew slowly for a decade, surviving on small contracts from electric forklift makers and uninterruptible-power-supply vendors.

Her breakthrough came in 2009, when her battery-pack design won the European Energy Innovation Prize, a continental award recognizing engineering achievements in clean energy. The win raised her company's profile significantly and led to its first major public-transit contracts.

## Later life

Marchetti stepped down as chief executive in 2019 and retired in 2020, moving to Lisbon, Portugal, where she advises early-stage energy startups and writes occasional essays on battery recycling. She has no children and prefers to keep a low public profile.

## Legacy

Industry historians credit Marchetti with popularizing the practice of pairing battery chemistry research directly with vehicle-integration engineering — an approach that was unusual for a small firm in the 1990s. Her original company continues to operate today under a different name.
21 changes: 21 additions & 0 deletions examples/multihop-wikipedia-qa/data/articles/lisbon.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Lisbon

**Lisbon** is the capital and largest city of Portugal, located on the Atlantic coast of the Iberian Peninsula. It has been an important trading port since the Age of Discovery and remains the country's economic and cultural center.

## Geography and population

Lisbon sits on seven hills at the mouth of the Tagus River, facing the Atlantic Ocean. Its metropolitan area has a population of roughly 2.9 million, about a quarter of Portugal's total population. The city's mild, sunny climate makes it a popular destination for remote workers and retirees.

## Public transport

The city's public transport system is operated by **TransLisboa**, the municipal transit authority, which runs the city's trams, buses, and metro. TransLisboa is known for its historic yellow tram network, which climbs the city's steepest streets.

In 2016, TransLisboa launched Europe's first fully electric bus route, a single line connecting the city center to the airport, using battery packs supplied by an Italian battery manufacturer. The route's success led TransLisboa to expand electric buses to several more lines over the following years.

## Culture and events

Lisbon hosts the annual Lisbon Tech Summit, a three-day technology conference that draws startups and investors from across Europe. The event is held each October at the city's riverside convention center.

## Notable residents

The city has a growing community of tech entrepreneurs and retired engineers. Among its well-known residents is a celebrated Italian electrical engineer who moved to Lisbon after retiring, and who advises early-stage energy startups from her home in the Alfama district.
21 changes: 21 additions & 0 deletions examples/multihop-wikipedia-qa/data/articles/volta-dynamics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Volta Dynamics

**Volta Dynamics** was an Italian manufacturer of lithium-ion battery packs for electric commercial vehicles, headquartered in Turin. It was founded in the early 1990s by the winner of the 2009 European Energy Innovation Prize, and operated under this name until 2021.

## History

The company was founded in the early 1990s in Turin, Italy, growing out of a university research project on rechargeable battery systems. For its first fifteen years it supplied relatively small battery packs to electric forklift and delivery-vehicle makers across northern Italy.

The firm's first significant public-transit win came in 2015, when it won a contract to supply battery systems for the bus fleet of Lisbon's public transport operator. The following year, in 2016, that operator launched Europe's first fully electric bus route, powered by Volta Dynamics battery packs.

## Products

Volta Dynamics focused exclusively on stationary and vehicle-mounted battery packs, deliberately avoiding consumer electronics. Its core product line was the "TransPack" series of swappable battery modules, designed so that a depot could charge a fresh pack while a bus continued its route on another.

## Renaming and later years

In 2019 the company went public on the Milan Stock Exchange. In 2021 it merged with a German EV-grid startup and renamed itself Voltora. Under that name, the business shifted its focus toward grid-scale energy storage and battery reuse for renewable-power utilities.

## Recognition

Battery industry trade publications repeatedly cited Volta Dynamics in their annual rankings of European battery integrators, praising the reliability record of its TransPack modules in daily transit use.
41 changes: 41 additions & 0 deletions examples/multihop-wikipedia-qa/data/test_questions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"note": "Bundled test questions for the multi-hop QA example. Each question's answer can be found in the articles in data/articles/. The 'hops' field marks how many articles a fully-grounded answer requires: 1 means one article has everything, 2 means the fact is split across two articles. 'expected' and 'articles' are there so you can audit the tool's output against a known answer -- they are not used to stop the pipeline, just for your own comparison.",
"questions": [
{
"question": "What is the name of Lisbon's public transit authority?",
"hops": 1,
"expected": "TransLisboa",
"articles": ["lisbon.md"]
},
{
"question": "What product did Cereolabs launch in 2017?",
"hops": 1,
"expected": "AquaPro",
"articles": ["cereolabs.md"]
},
{
"question": "What international agreement was signed in Basel in 2019?",
"hops": 1,
"expected": "Basel Climate Accord",
"articles": ["basel.md"]
},
{
"question": "Who founded the company that powered TransLisboa's electric buses?",
"hops": 2,
"expected": "Elena Marchetti",
"articles": ["volta-dynamics.md", "elena-marchetti.md"]
},
{
"question": "In which city was the company that launched AquaPro founded?",
"hops": 2,
"expected": "Basel",
"articles": ["cereolabs.md", "basel.md"]
},
{
"question": "Where was the scientist who developed AquaPro's extraction method born?",
"hops": 2,
"expected": "Dhaka",
"articles": ["cereolabs.md", "amina-rahman.md"]
}
]
}
Loading
Loading