Spaces:
Running
Running
| kind: comparison | |
| compared: [agent/loop.py, agent/graph.py] | |
| date: 2026-07-06 | |
| verdict: manual loop for now; LangGraph when checkpointing / parallelism / human-in-the-loop arrives | |
| # Manual loop vs. LangGraph β same agent, two control flows | |
| Both implementations drive the **identical** three tools (`search_docs`, | |
| `read_page`, `ask_source`), the same planner prompt, the same budgets | |
| (6/2/1), and end in the same `answer_from_sections`. Only the control flow | |
| differs: a Python `while` loop vs. an explicit `StateGraph`. | |
| ## Numbers | |
| | | `agent/loop.py` | `agent/graph.py` | | |
| |---|---|---| | |
| | Code lines (non-comment) | **90** | 98 | | |
| | External dependency | none (stdlib) | `langgraph` | | |
| | State | local variables in one function | a `TypedDict` threaded through nodes | | |
| | Control flow | `for step in range(MAX_STEPS)` + `if/elif` | nodes + a conditional edge (`_route`) | | |
| LoC is nearly identical β the graph's node signatures and explicit state | |
| dict cost ~8 lines over plain locals. At this size the manual loop is | |
| slightly smaller and has zero dependency. | |
| ## Debuggability | |
| - **Manual loop**: a stack trace points at the exact line; you can drop a | |
| `print`/breakpoint anywhere and read the local `transcript`. Nothing | |
| between you and the code. Easiest to reason about at this scale. | |
| - **LangGraph**: the flow is *inspectable as data* β you can render the | |
| graph, and (with a checkpointer) replay a run node-by-node. That visibility | |
| is worth little for a 3-node graph but grows with complexity. | |
| ## Latency | |
| Both make the same LLM calls (one planner call per step + one final | |
| generation), so wall-clock is dominated by the network, not the framework. | |
| LangGraph's per-node overhead is microseconds β immeasurable next to a | |
| free-tier LLM call that can wait 30s on a rate limit. **No practical | |
| difference.** | |
| ## When LangGraph earns its dependency | |
| Nothing in *this* agent needs a graph β which is exactly why the manual loop | |
| is the default. LangGraph becomes the right tool the moment we add any of: | |
| - **Checkpointing** β pause a run and resume after a restart (multi-turn | |
| sessions, long jobs). The manual loop would have to serialize its locals | |
| by hand; LangGraph gives it for free. | |
| - **Human-in-the-loop** β interrupt before an action (e.g. approve running | |
| code) and continue. A native graph feature; a manual bolt-on otherwise. | |
| - **Parallel fan-out** β run several `search_docs` queries concurrently for a | |
| recipe question. Natural as parallel edges; awkward in a linear loop. | |
| ## Verdict | |
| Ship the **manual loop** (`agent/loop.py`): fewer lines, no dependency, | |
| trivially debuggable, same behavior. Keep `agent/graph.py` as the drop-in | |
| upgrade β identical tools and prompt β for when checkpointed sessions, | |
| approval steps, or parallel retrieval arrive. Building it twice proved the | |
| control flow is understood, not delegated to a framework on faith. | |