Tonight I built two agents from scratch using raw OpenAI API calls — no frameworks — to understand the fundamental architecture patterns behind AI agents.
Approach 1: ReAct Agent (planner-agent)
The LLM does everything — it decides what step to run next, executes tools, observes results, and loops until done.
User goal → LLM plans → tool call → LLM observes → tool call → ... → done
The core is a single loop: send messages to the LLM, execute any tool calls it requests, feed results back, repeat. The system prompt tells it to “plan, execute, adapt, report” — but the LLM interprets that however it wants.
What I noticed:
- It finishes most tasks in 1-2 rounds — it’s too efficient, collapses steps together
- Completely generic — accepts any goal, which means it’s basically a ChatGPT wrapper with shell access
- The LLM handles both orchestration (workflow) and intelligence (judgment) — these are fundamentally different jobs
Approach 2: Structured Pipeline (publishing-agent)
I write notes in Obsidian daily — ideas, research, meeting notes, project logs. Some of them are worth publishing as blog posts, but it could be time consuming to review them. So I built an agent for this: it scans my vault for recently modified notes, ranks which ones are most ready to publish, drafts a polished version of the top pick, then self-reviews its own draft.
The point is that this workflow is known in advance — I don’t need an LLM to figure out the steps. I need it to provide judgment (which note is best?) and writing skill (turn rough notes into a blog post draft). So the code orchestrates a fixed pipeline, and the LLM is called only at specific points where intelligence is needed.
SCAN (code) → READ (code) → RANK (LLM) → DRAFT (LLM) → REVIEW (LLM)
Each step is a Python function. The LLM never decides “what’s next” — it only provides judgment and writing within a step it’s been assigned.
What I noticed:
- Predictable — always runs the same steps in the same order
- Debuggable — when something fails, I know exactly which step
- Focused prompts — each LLM call has a specific job, uses fewer tokens
- The LLM’s output quality is better because the prompt is narrower
The Key Insight
In a ReAct agent, the LLM is both the orchestrator and the intelligence engine. In a production agent, you separate these concerns:
| ReAct | Production | |
|---|---|---|
| Orchestration | LLM decides | Code decides |
| Intelligence | LLM provides | LLM provides |
| Workflow | Emergent | Explicit |
| Predictability | Low | High |
| Best for | Open-ended tasks | Known workflows |
In summary, ReAct still has its place — for truly open-ended tasks where you can’t predefine the steps. But for any domain-specific product (publishing, data analysis, code review), the structured pipeline is the way to go.
Repos
- planner-agent: ReAct pattern
- publishing-agent: Structured pipeline