--- id: research-agent-pipeline title: Research Agent Pipeline from Scratch code: RP subtitle: Generate hypotheses, retrieve papers, run sandboxed experiments, judge results, and publish a cited report. hue: 165 sources: phases/19-capstone-projects/05-autonomous-research-agent, phases/19-capstone-projects/50-hypothesis-generator, phases/19-capstone-projects/51-literature-retrieval, phases/19-capstone-projects/52-experiment-runner, phases/19-capstone-projects/53-result-evaluator, projects/research-report-agent source_hash: e3bed71e0634229b --- ## The research loop type: architecture from: phases/19-capstone-projects/50-hypothesis-generator/docs/en.md, phases/19-capstone-projects/51-literature-retrieval/docs/en.md, phases/19-capstone-projects/52-experiment-runner/docs/en.md, phases/19-capstone-projects/53-result-evaluator/docs/en.md, phases/19-capstone-projects/05-autonomous-research-agent/docs/en.md ```arch node | gen | 1,1 | HypothesisGenerator | lesson 50, ranked queue | model node | ret | 2,1 | RetrievalClient | lesson 51, BM25 + citation graph | store node | run | 3,1 | ExperimentRunner | lesson 52, subprocess limits | process node | eval | 4,1 | Evaluator | lesson 53, paired t test | process node | seed | 1,2 | Seed prompt | temperature ramp | client node | tree | 2,2 | Tree search | novelty, quality, budget | process node | write | 3,2 | LaTeX writer | vision critique | model node | rev | 4,2 | Reviewer ensemble | 5 judges | model edge | seed | gen | edge | gen | ret | queue head edge | ret | run | not settled edge | run | eval | ExperimentResult edge | eval | gen | verdict edge | tree | write | best branch edge | write | rev | draft ``` ## Run it type: command-table span: 2 from: phases/19-capstone-projects/50-hypothesis-generator/code/main.py, phases/19-capstone-projects/51-literature-retrieval/code/main.py, phases/19-capstone-projects/52-experiment-runner/code/main.py, phases/19-capstone-projects/53-result-evaluator/code/main.py, phases/19-capstone-projects/05-autonomous-research-agent/code/main.py, phases/19-capstone-projects/05-autonomous-research-agent/docs/en.md, projects/research-report-agent/README.md, projects/research-report-agent/solution/run_report.py | Command | What it does | |---|---| | `python3 code/main.py` | Lessons 50 to 53 demo. Prints JSON | | `python main.py` | Lesson 05 tree search, budget $30 | | `docker run --network=none --memory=8g --cpus=2 --pids-limit=256 --read-only` | Sandbox for one experiment | | `run_report.py "" --out out/ --code ` | Report, trace and evidence JSON | | `run_report.py --eval heldout/questions.json` | Score the public fixtures | | `run_report.py "" --model replay --cassette ` | Plan from recorded replies | | `run_report.py "" --corpus --compare /report.json` | Write `changes.json` | | `project_test.py research-report-agent --stage --path ` | Grade a stage and all earlier ones | ## Loop calls in code type: task-table span: 2 from: phases/19-capstone-projects/50-hypothesis-generator/code/main.py, phases/19-capstone-projects/51-literature-retrieval/code/main.py, phases/19-capstone-projects/52-experiment-runner/code/main.py, phases/19-capstone-projects/53-result-evaluator/code/main.py | Task | Code | |---|---| | Configure the ramp | `GeneratorConfig(n_passes=4, t_min=0.2, t_max=1.1)` | | Draft and rank | `queue, logs = generator.run(seed_prompt)` | | Build a retriever | `build_client(RetrievalConfig(top_k_lexical=5, max_hops=2))` | | Search papers | `result = client.search(query)` | | Run one spec | `ExperimentRunner().run(spec)` | | Sweep one knob | `AblationRunner(runner).sweep(base, "k", [4, 8, 16, 32])` | | Pick the metric | `MetricSpec(name="perplexity", direction=LOWER, scale=LOG)` | | Judge the runs | `evaluator.evaluate(1, metric_spec, candidates, baselines)` | ## Spec a sandboxed experiment type: annotated-code lang: python from: phases/19-capstone-projects/52-experiment-runner/code/main.py, phases/19-capstone-projects/52-experiment-runner/docs/en.md ```python base = ExperimentSpec( spec_id="demo_base", hypothesis_id=1, script_path=script, # prints one json line config={"k": 16, "steps": 4, "sleep_s": 0.0}, seed=7, # sent as config["__seed"] wall_timeout_s=15.0, # hard, killed on exceed memory_cap_mb=256, # soft, polled RSS metric_keys=["perplexity", "final_loss"], ) runner = ExperimentRunner() base_result = runner.run(base) # terminal: ok, timeout, oom, crash base_result.to_dict() # metrics, peak_rss_mb, stderr_tail ablate(base, "k", [4, 8]) # spec_id demo_base_k_4 ``` ## Report agent run type: flow from: projects/research-report-agent/solution/report_agent/pipeline.py, projects/research-report-agent/solution/report_agent/critic.py, projects/research-report-agent/solution/report_agent/writer.py, projects/research-report-agent/solution/report_agent/planner.py, projects/research-report-agent/README.md 1. **index**: `BM25Index(documents)` ranks the markdown corpus in Rust. 2. **plan**: `plan_research` splits the question into up to 4 facets. 3. **gather**: `gather_snippets` keeps 3 snippets per facet with offsets. 4. **write**: `write_report` composes sentences with `[S1]` markers. 5. **verify**: `review` scores each sentence. `apply_verdicts` drops the rest. 6. **state**: `decide_state` gives completed, needs_review or failed. 7. **publish**: `write_outputs` writes report.html, report.json and trace.json. ## Scores and formulas type: concepts from: phases/19-capstone-projects/50-hypothesis-generator/docs/en.md, phases/19-capstone-projects/51-literature-retrieval/docs/en.md, phases/19-capstone-projects/53-result-evaluator/docs/en.md, phases/19-capstone-projects/05-autonomous-research-agent/code/main.py, projects/research-report-agent/solution/report_agent/evaluate.py - **Cosine distance**: `1 - dot(a, b)` on unit vectors. - **rank_score**: 0.4 novelty + 0.3 specificity + 0.3 testability. - **final_score**: 0.5 normalized BM25 + 0.3 graph + 0.2 recency. - **graph_score**: 1 for a lexical hit, 0.6 at one hop, 0.3 at two hops. - **Node score**: novelty 0.4 + quality 0.5 + budget weight 0.1. - **Improvement**: (baseline - candidate) / abs(baseline) when lower is better. - **Paired t**: `t_stat = mean / sqrt(variance / n)`, df is n - 1. - **Report score**: 100 x (0.4 precision + 0.3 recall + 0.3 facts). ## Loop defaults type: defaults from: phases/19-capstone-projects/50-hypothesis-generator/code/main.py, phases/19-capstone-projects/51-literature-retrieval/code/main.py, phases/19-capstone-projects/52-experiment-runner/code/main.py, phases/19-capstone-projects/53-result-evaluator/code/main.py | Setting | Default | Note | |---|---|---| | `n_passes` | 6 | `t_min` 0.2 to `t_max` 1.2 | | `novelty_threshold` | 0.25 | Lower distance is a duplicate | | BM25 `k1`, `b` | 1.5 | `b` is 0.75 | | `top_k_lexical` | 10 | Seeds for the graph walk | | `max_hops` | 2 | Values above 2 are clamped | | `wall_timeout_s` | 30.0 | `memory_cap_mb` is 512 | | `improvement_threshold` | 0.02 | Smaller change is noise | | `significance_threshold` | 0.05 | Larger p value is noise | ## Report agent defaults type: defaults from: projects/research-report-agent/solution/report_agent/critic.py, projects/research-report-agent/solution/report_agent/evaluate.py, projects/research-report-agent/solution/report_agent/writer.py, projects/research-report-agent/solution/report_agent/planner.py, projects/research-report-agent/solution/run_report.py, projects/research-report-agent/README.md | Setting | Default | Note | |---|---|---| | `--model` | rules | Also replay or live | | Budget `max_steps` | 50 | `BudgetExceeded` gives failed | | Budget `max_tokens` | 20000 | `estimate_tokens` is len / 4 | | `review` threshold | 0.6 | Overlap needed to keep a sentence | | `citation_precision` threshold | 0.8 | Stricter than the critic | | `max_facets` | 4 | Overview, how, risks, when | | `max_sentences` | 3 | Per section | | Reference score | 87.5 | Six public questions, out of 100 | ## Failures and fixes type: troubleshooting from: phases/19-capstone-projects/50-hypothesis-generator/code/main.py, phases/19-capstone-projects/50-hypothesis-generator/docs/en.md, phases/19-capstone-projects/52-experiment-runner/docs/en.md, phases/19-capstone-projects/53-result-evaluator/docs/en.md, phases/19-capstone-projects/53-result-evaluator/code/main.py, phases/19-capstone-projects/05-autonomous-research-agent/code/main.py, projects/research-report-agent/solution/report_agent/critic.py, projects/research-report-agent/solution/report_agent/planner.py, projects/research-report-agent/README.md | Symptom | Cause | Fix | |---|---|---| | Log shows `parse:no hypothesis block found` | Reply has no tagged block | Keep temperature at or below 1.2 | | Every pass logs `duplicate` | Drafts share most nouns | Widen the seed prompt and run again | | `terminal` is `crash` with metrics | Non-zero exit code | Fix the script. Partial runs count as failed | | `PairingError` | Seeds differ between the lists | Rerun both arms on the same seeds | | Verdict `noise` with a big gain | Fewer than 2 pairs, no p value | Run more seeds | | Node fails `loss_diverged` | Loss above 4.0 | Drop that branch. Expand others | | Sentence dropped: names or numbers not in source | Swapped name or changed number | Keep writing extractive | | Plan `source` is `rules-fallback` | Bad model JSON or cassette miss | Read the plan note. Rerecord the cassette | ## Questions type: qa from: phases/19-capstone-projects/50-hypothesis-generator/docs/en.md, phases/19-capstone-projects/51-literature-retrieval/docs/en.md, phases/19-capstone-projects/52-experiment-runner/docs/en.md, phases/19-capstone-projects/53-result-evaluator/docs/en.md, projects/research-report-agent/stages/05-verify-every-claim/docs/en.md - **Why ramp the temperature?** Later drafts wander. Below 0.2 the model parrots the seed. - **Why walk the citation graph?** It finds papers that use other words than the query. - **Why only two hops?** Three hops blows up the result and drifts off topic. - **Why a subprocess?** Untrusted code must not crash the orchestrator. - **Why one knob at a time?** Full factorial sweeps grow exponentially. - **Why a paired test?** Each seed gives a difference. Noise floor is their standard error. - **Is needs_review a failure?** No. It tells a human exactly where to look.