Skip to content

JHU-CDHAI/Final_Project_Sp26

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

112 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

3-Stage Strategy Agent

A LangGraph multi-agent system that takes a business question through three stages: Problem Intake & Topic Planning → Research & Debate → Synthesis & Action Plan. Designed to be approachable for prompt-tweakers and extensible for those who want to reshape the agent graphs.

The agent code lives in 3_stage_agent/. All paths below are relative to that folder unless noted.

The README is split into two tiers:

  • Tier 1 — runs in Colab via the provided notebook. No local install. You only edit prompt text files.
  • Tier 2 — for users running locally / from a terminal, or extending the graph itself. Local setup instructions are in this section.

Tier 1 — Context Engineering (prompts)

Who this is for: anyone who wants to change what the agent says or asks without touching the graph wiring.

Setup: none locally. The Colab notebook clones the repo and installs dependencies in its first cells; API keys go into Colab secrets / the notebook's setup cell. You only need to edit prompt .txt files in the Colab file browser.

Where prompts live

All eight LLM prompts are plain text files in 3_stage_agent/prompts/. Edit a .txt to change agent behavior — no Python edit needed.

A friendly map of which prompt drives which stage/node, with "common tweaks" recipes and warnings, is in 3_stage_agent/PROMPTS.md. Read that first.

File Stage / node What it shapes
prompts/intake_system.txt Stage 1 — intake Persona / tone of the intake agent
prompts/intake_parse.txt Stage 1 — intake Extraction of structured fields from question
prompts/clarify_instruction.txt Stage 1 — clarify_problem Problem statement + clarifying questions
prompts/plan_topics_instruction.txt Stage 1 — plan_research_topics How research topics are generated
prompts/research_propose.txt Stage 2 — research_and_propose Researcher's job: web findings + proposal
prompts/topic_critic.txt Stage 2 — topic_critic Critic's behavior + convergence rules
prompts/synth.txt Stage 3 — synthesizer 8-section recommendation report template
prompts/action_plan.txt Stage 3 — action_plan_90d 90-day action plan template

How prompts flow through the pipeline

Each stage runs one or more prompts in this order. Loops repeat until a human gate approves or a round limit is hit.

Stage 1 ─ Problem Intake & Topic Planning
   intake_system.txt ─┐
                      ├─► intake node            (parse the question)
   intake_parse.txt ──┘
   clarify_instruction.txt   ──► clarify_problem (loop, with human gate 1)
   plan_topics_instruction.txt ──► plan_research_topics (with human gate 2)

Stage 2 ─ Research & Debate    (runs once per research topic)
   research_propose.txt  ──► research_and_propose ◄┐
                                                   │ debate loop
   topic_critic.txt      ──► topic_critic ─────────┘
                              └─► human gate 3 (approve / revise)

Stage 3 ─ Synthesis & Action Plan
   synth.txt        ──► synthesizer              (final report)
   action_plan.txt  ──► action_plan_90d (with human gate 4)

How to change a prompt

  1. Open the .txt file in any editor (Colab's built-in editor works — double-click the file in the left-side file browser).
  2. Edit the text. Save.
  3. Re-run the agent. The next import of common.py picks up the change.

In Colab, expand the file browser on the left and navigate to Final_Project_Sp26 / 3_stage_agent / prompts / — every prompt is a plain .txt file you can double-click to edit:

Colab file browser showing the prompts folder with all 8 .txt files

You can drop these two lines at the end of your clone cell to print the path explicitly:

PROMPTS_DIR = f"{REPO_DIR}/3_stage_agent/prompts"
print(f"[Tier 1] Edit any .txt file in: {PROMPTS_DIR} to tweak prompts")

Simple example: to make the intake agent more concise, edit the first line of prompts/intake_system.txt from "a senior business strategy consultant" to "a brief, no-fluff strategy consultant who avoids long preambles".

Warnings before you edit prompts

  • Do not remove placeholders. Some prompts have runtime substitutions:
    • plan_topics_instruction.txt uses {n} (filled from stage1_intake.max_research_topics in config.yaml). Removing it will leave the literal string {n} in the prompt.
    • topic_critic.txt uses {{half_max}} (double braces) — this is substituted at runtime from max_debate_rounds. Keep the double braces.
  • Don't change what fields are requested. Stage 1 and Stage 2 use Pydantic structured outputs (IntakeOutput, TopicsOutput, TopicProposalOutput, CriticOutput — see common.py:71–111). If a prompt asks for a field that isn't in the Pydantic model — or stops asking for one that is — the parse step will fail or return empty values. To add a field, edit both the prompt and the Pydantic model.
  • Don't break the section structure of synth.txt. The numbered sections feed directly into the DOCX/PDF report. Renaming sections is fine; reordering or removing them changes the report shape.
  • Avoid markdown tables in synth.txt / action_plan.txt. The prompts explicitly forbid them because Word DOCX export renders tables poorly. Keep this constraint if you edit those prompts.
  • Don't delete a prompt file. common.py will fail at import with a clear FileNotFoundError pointing to the missing path. Restore it from git if this happens.
  • Test on one stage at a time. After editing, run only the affected stage (./run.sh --stage 1) before re-running the full pipeline.
  • Keep changes in version control. A bad prompt edit can be hard to undo by memory — git diff prompts/ is your friend.

Tier 2 — Agent Infrastructure Engineering

Who this is for: users who want to change graph structure, add nodes, swap models per-stage, change state shape, or add new tools — typically running locally rather than in Colab.

Setup (one time, local only)

Run the setup script — it installs Python dependencies and creates 3_stage_agent/.env from the committed template:

python 3_stage_agent/setup.py

Then open 3_stage_agent/.env and replace the placeholders with your real keys:

common.py auto-loads 3_stage_agent/.env at import time. The .env file is git-ignored (only 3_stage_agent/env.example.txt is tracked), so your real keys stay local. Re-running setup.py is safe — it never overwrites an existing .env.

Run from the terminal

cd 3_stage_agent

# Full pipeline (interactive — you'll approve / edit at each gate)
./run.sh

# Override the input question without editing config.yaml
./run.sh --question "How should I launch a coffee subscription in Japan?"

# Run a single stage
./run.sh --stage 1
./run.sh --stage 2 --input results/stage1_intake/<dir>
./run.sh --stage 3 --input results/stage2_research/<dir>

# Suffix output folders for easier comparison across runs
./run.sh --name v1

run.sh activates venv/ if present and forwards args to run_cli.py, which chains the three stage scripts via subprocess. Outputs land in 3_stage_agent/results/stage{1,2,3}_*/{timestamp}/.

If you don't want the bash wrapper, the stages also work standalone:

python stage1_intake.py
python stage2_research.py --input results/stage1_intake/<dir>
python stage3_synthesis.py --input results/stage2_research/<dir>

Stage settings (no code change needed)

Edit 3_stage_agent/config.yaml:

  • input_query — default business question
  • auto_approve — skip human gates (set true for unattended runs)
  • stage1_intake.model, stage2_research.model_researcher / model_critic, stage3_synthesis.model — pick a model per role. Any OpenRouter model id works (e.g. openai/gpt-5.2, anthropic/claude-opus-4.6, google/gemini-3-flash-preview).
  • Round limits: max_clarify_rounds, max_research_topics, max_debate_rounds, max_human_revision_on_proposal, max_human_revision_on_plan.

Where to change the graph

Each stage is a LangGraph compiled in build_graph():

Stage File build_graph line Nodes (line)
1 stage1_intake.py 352 intake (75), clarify_problem (133), human_gate_1 (197), plan_research_topics (247), human_gate_2 (305)
2 stage2_research.py 485 research_and_propose (89), topic_critic (228), human_gate_3 (370)
3 stage3_synthesis.py 286 synthesizer (76), action_plan_90d (149), human_gate_4 (232)

Common edits:

  • Add a new node — write a def my_node(state) -> dict: function in the stage file, then register it inside build_graph() with g.add_node(...) and connect it via g.add_edge(...) or g.add_conditional_edges(...).
  • Change routing logic — each stage has route_after_* functions that return the next node name based on state. Stage 1 routing is at stage1_intake.py:243 and :342; Stage 2 at :332 and :470; Stage 3 at :276.
  • Reshape state — state schemas extend MessagesState:
    • Stage1Statestage1_intake.py:50
    • Stage2Statestage2_research.py:55
    • Stage3Statestage3_synthesis.py:46 Add fields here when a node needs to pass new data downstream.
  • Add or remove a human gate — the gate nodes use interrupt(prompt_text) from langgraph.types. Look at human_gate_1 (stage1_intake.py:197) as the cleanest reference implementation — it shows how to display content, capture human feedback, and feed it back into state.

Where to change agent infrastructure

What Where Line
LLM factory (OpenRouter routing, retries) common.py make_llm at :58
Web search wrapper (Tavily) common.py web_search at :123
Pydantic output schemas common.py :71–111 (8 models)
Config loading common.py :39–50 (reads config.yaml at import time)
Per-stage logging / handoff I/O common.py set_output_dir (:200), save_handoff, load_handoff (:340–356)
Markdown → DOCX export report_export.py save_all (:85)

Stage handoffs

Stages communicate via handoff.json:

  • Stage 1 → 2: results/stage1_intake/<dir>/handoff.json contains the problem framing, constraints, and research topics list.
  • Stage 2 → 3: results/stage2_research/<dir>/handoff.json contains the approved per-topic proposals (with findings, citations, critic reviews).

If you change a stage's output shape, update the loader on the next stage (load_handoff calls in each __main__ block) and the orchestrator key list in run_stage.py:run_stage1 / run_stage2 if you also use the notebook flow.

Notebook vs. terminal

This repo supports both:

  • Notebook flow (Colab-friendly, widget UI): driven by run_stage.py + config_ui.py + stage1_runner.py. Used by the Multi_Agent_Stage1.ipynb / Multi_Agent_Stage2_3.ipynb notebooks.
  • Terminal flow (this README's Tier 2): driven by run_cli.py + run.sh, calling each stage's standalone __main__ block.

Both share the same agent code (stage{1,2,3}_*.py, common.py, config.yaml, prompts). Pick whichever fits your environment.


Output layout

3_stage_agent/results/
├── stage1_intake/<timestamp>[_<name>]/
│   ├── handoff.json          # input for Stage 2
│   ├── summary.md
│   ├── meta.txt
│   └── logs/
├── stage2_research/<timestamp>[_<name>]/
│   ├── handoff.json          # input for Stage 3
│   ├── summary.md
│   └── logs/
└── stage3_synthesis/<timestamp>[_<name>]/
    ├── recommendation.md
    ├── recommendation.docx
    ├── action_plan.md
    ├── action_plan.docx
    └── logs/

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors