Projects/ReAct Research Agent/Part 1
Overview and Architecture
Map ReAct: interleaved thoughts, actions, and observations over a closed web of documents, with citations as a first-class output.
A ReAct agent (Reason + Act) interleaves thoughts the user may or may not see, actions that hit tools, and observations that come back from the world. It is the default pattern behind "the model decided to search." This project builds one that researches a question against a fake web — a dict of pages — so you can test citations and abstention without a search API bill.
Research is the right second project because the weather agent had a known three-step plan. Research does not. The policy must decide whether to search again, open a URL, or stop. That is real branching. It is also how agents leak: they invent URLs, quote pages they never opened, or answer from parametric memory when the corpus is empty.
The product
User goal: a factual question, e.g. Who founded Acme Robotics and in what year?. The agent may use:
search(query)→ list of{url, title, snippet}open(url)→ page text (truncated)finish(answer, citations)→ final report
Citations are URLs that were actually opened (or at least returned by search — pick a rule and test it). This project requires: every citation URL must appear in an open observation. No decorative bibliography.
If the corpus cannot support an answer, the agent must finish with cannot_answer: true and a short reason. Inventing founders is a failed eval, not a creative bonus.
ReAct vs JSON-only weather
The weather agent used {"tool", "args"}. ReAct classically uses a text protocol:
Thought: I should search for the founder.
Action: search
Action Input: Acme Robotics founder
Observation: ...You will parse that text into the same underlying dict your weather loop used. Do not build two runtimes. ReAct is a skin on the tool loop. Thoughts are extra keys you store in the transcript for debugging; they are not tools.
| Weather project | Research project |
|---|---|
| 3 tools, known order | 3 tools, unknown order and count |
| Goal is a forecast sentence | Goal is a cited answer or abstention |
| Failure = unknown city | Failure = no supporting page |
| JSON from turn one | Thought/Action text, parsed to JSON |
Architecture boxes
- Corpus —
WEB: dict[url, {title, body, tags}]. This is the internet. - Search index — naive token overlap is enough (part 2).
- ReAct parser — turns model text into
{thought, tool, args}. - Loop — same as weather, plus a max_steps that is small (6–8). Research agents love to search forever.
- Citation checker — finish is invalid if citations ⊈ opened URLs.
- Cannot-answer path — a first-class finish shape, not an afterthought.
Why a fake web beats live search for learning
Live search is non-deterministic, expensive, and full of prompt injection in the pages. A 6-page corpus lets you write:
- Question whose answer is in one page
- Question that needs two pages (join)
- Question whose words appear in a snippet but the fact is absent (temptation to hallucinate)
- Question with conflicting pages (part 5)
That is an eval set. Google cannot give you that stability.
Run to execute this in your browser. Nothing is sent to a server.
Stop conditions
finishwithcannot_answer: false, non-empty answer, citations ⊆ opened URLs, and at least one citation if the answer is positive.finishwithcannot_answer: trueand empty or unused citations (do not cite a page you did not use; do not fake a URL).max_steps→ synthetic cannot-answer: budget.
Positive answers without citations fail the product even if the string is correct. The user asked a research agent, not a trivia model.
Thoughts are not safety
A thought that says "I will not hallucinate" is not a citation check. You will enforce citations in code in part 4. The thought is for the model's chain-of-thought (and for your traces). Never execute a thought.
Tip:If you display thoughts in a UI, users will trust them too much. Prefer showing actions, observations, and the cited quote.
Exercise
Write three questions on paper: (1) answerable from one page, (2) needs two pages (founder + current CEO), (3) not in the corpus (What is Ada Ortiz's favorite food?). Those are your eval rows for the rest of the project.
Check your understanding