Agents and the ReAct loop
An agent is an LLM in a loop over tools and state — what it is, how products use it, architecture, how to build one, today’s stacks, and failure modes.
What an agent is (plain English)
A chat completion answers once: you send messages, the model returns text (or a single tool call you execute yourself), and you are done.
An agent is different. It is a program that wraps an LLM in a loop: the model proposes the next action, your runtime executes tools or side effects, observations come back into the conversation, and the loop continues until a stop condition fires (final answer, max steps, budget, human deny, policy violation).
while not stopped:
model decides: tool_call(s) OR final_answer
if tool_call: execute → append observation
if final_answer: return to userThat loop — often called ReAct (Reason + Act) when the model interleaves short reasoning with tool use — is the mental model behind almost every “AI agent” product in 2025–2026: coding assistants, support bots that open tickets, research copilots that search then cite, ops bots that page on-call.
Analogy: a chat model is a consultant who answers from memory. An agent is that consultant with a phone, a browser, and a badge to your internal systems — and a manager (your code) who decides which calls are allowed and when to hang up.
Ship rule: the model proposes; your driver disposes. Never let the model run shell, payments, or email without your executor validating schemas, auth, and bounds.
One-sentence definition you can defend in an interview
An agent is an LLM-driven control loop over tools and state, with explicit stop and safety policy, whose runs are recorded as trajectories you can evaluate.
If any of those five words is missing (loop, tools, state, stop, trajectories), you probably have a chatbot with marketing, not an agent.
LLM vs agent vs workflow (do not confuse them)
| Pattern | Control flow | Who chooses the next step | When it fits |
|---|---|---|---|
| Single LLM call | One shot | N/A | Summarize, rewrite, classify with a schema |
| Prompt chain / DAG | You decide the steps | Your code / graph | Fixed pipeline: extract → validate → format |
| Agent (ReAct-style) | Model chooses tools each step | The model (bounded by policy) | Open-ended goals with a small tool set |
| Multi-agent | Several loops + a router/orchestrator | Router + specialists | Specialized roles (planner / researcher / critic) — see Multi-agent orchestration |
If the steps are known and stable, prefer a workflow (deterministic graph). Reach for an agent when the path is unknown — “figure out why this order failed” needs search, DB, and judgment, not a fixed three-step script.
flowchart TD
Goal[User goal] --> Choose{Path known?}
Choose -->|Yes| WF[Deterministic workflow / DAG]
Choose -->|No| Ag[Agent loop]
WF --> Out1[Result]
Ag --> Tools[Tool runtime]
Tools --> Ag
Ag --> Out2[Result or escalate]
Common mistake: calling a LangGraph workflow with fixed nodes an “agent” because it uses an LLM. Fixed graphs are valuable — they are just not ReAct. Name the control-flow honestly.
Mental model: five pieces every agent has
- Model — chat API (or local OpenAI-compatible server) that can emit text and/or structured tool calls.
- Tool registry — name → JSON schema → callable (search, SQL read, calendar, code runner, MCP tools).
- Loop driver — your code: call model → branch on tool vs final → execute → append → repeat.
- State / memory — at minimum the message list; later: durable session store, summaries, retrieval.
- Stop + safety policy — max steps, timeouts, cost budget, allow/deny lists, human-in-the-loop (HITL) for mutating tools.
flowchart TD
U[User goal] --> D[Loop driver]
D --> L[LLM]
L -->|tool call| T[Tool runtime]
T -->|observation| D
L -->|final answer| Out[Result]
D -->|max steps / deny / budget| Stop[Stop / escalate]
D --> Mem[(State / trajectory log)]
Mem --> D
Everything else — LangGraph graphs, Crew “crews,” OpenAI Assistants, Cursor-style coding agents — is packaging around these five pieces.
What the model sees each step
Typical context packed into one completion:
| Slot | Contents | Risk if wrong |
|---|---|---|
| System | Role, tool policy, output rules | Soft policies get ignored |
| Tools | JSON schemas for allowed tools | Vague schemas → wrong calls |
| History | Prior assistant/tool messages | Unbounded growth → cost + confusion |
| User goal | Current task | Ambiguous goals → tool spam |
| Optional RAG | Retrieved snippets | Noise dilutes attention |
Treat that pack as a scarce budget — same lesson as context engineering and tokenization.
How ReAct works step by step
Classic ReAct papers interleaved natural-language “Thought” with “Action.” Modern APIs often replace free-form Action text with native tool / function calling (JSON args). The loop is the same:
- Assemble context — system instructions, user goal, tool schemas, prior messages, optional retrieved docs.
- Model step — one completion with tools enabled.
- Branch
- Tool call(s) → validate args → execute with timeouts → append
tool/tool_resultmessages. - Final text → return (optionally require an explicit
final_answertool).
- Tool call(s) → validate args → execute with timeouts → append
- Record trajectory — step index, latency, tokens, tool name, success/fail — for debug and evals.
- Check stops — max steps, wall clock, consecutive tool errors, token/cost budget, policy.
sequenceDiagram
participant U as User
participant D as Driver
participant M as Model
participant T as Tools
U->>D: Goal
loop Until stop
D->>M: messages + tool schemas
alt Tool call
M-->>D: tool_call name args
D->>T: validate + execute
T-->>D: observation
D->>D: append + log trajectory
else Final answer
M-->>D: text
D-->>U: result
end
end
Minimal hand-rolled loop (shape)
MAX_STEPS = 8
messages = [system, user_goal]
for step in range(MAX_STEPS):
response = llm.chat(messages, tools=tool_schemas)
if response.tool_calls:
for call in response.tool_calls:
ok, result = execute_tool(call.name, call.arguments) # validate first
messages.append(tool_result_message(call.id, result))
log_trajectory(step, call, result, ok)
continue
if response.final_text:
return response.final_text
messages.append({"role": "user", "content": "Call a tool or give the final answer."})
raise MaxStepsExceeded("Agent hit MAX_STEPS without finishing")Adapt message shapes to OpenAI tools vs Anthropic tool_use — keep driver logic identical.
execute_tool sketch (validate → policy → run)
def execute_tool(name: str, arguments: dict, ctx: RunContext) -> tuple[bool, dict]:
spec = TOOL_REGISTRY.get(name)
if spec is None:
return False, {"error": "unknown_tool"}
try:
args = spec.schema.validate(arguments)
except ValidationError as e:
return False, {"error": "invalid_args", "detail": e.errors()}
if not ctx.authz.allows(name, args):
return False, {"error": "forbidden"}
if spec.mutating and not ctx.hitl.approved(name, args):
return False, {"error": "pending_human_approval"}
try:
result = spec.fn(args, timeout=spec.timeout_s)
return True, truncate(result, max_bytes=spec.max_obs_bytes)
except TimeoutError:
return False, {"error": "timeout"}The model never sees your credentials or raw exceptions you have not scrubbed.
Parallel tool calls
Many APIs allow multiple tool calls in one model step. Useful when the model can fetch order + shipment independently. Your driver must:
- Execute with a concurrency limit
- Timeout each call independently
- Append results in a deterministic order (or keyed by
tool_call_id) - Fail partial: decide whether one failed tool aborts the step or continues
Why require a final_answer tool sometimes
Free-form “I’m done” text is easy for the model to emit while still intending another tool. An explicit final_answer(summary) tool makes the stop condition machine-checkable — especially helpful for evals and for products that must never leave the loop hanging.
What agents are used for (concrete jobs)
| Job | Typical tools | Stop when | Watch out for |
|---|---|---|---|
| Support copilot | Order DB, knowledge RAG, ticket API | Answer + citation, or escalate | Writing refunds without HITL |
| Coding agent | Repo search, edit, terminal, tests | Tests pass or step budget | Unbounded shell; secret exfil |
| Research / briefing | Web/search, PDF extract, notes | Report with sources | Hallucinated citations |
| Ops / SRE assistant | Metrics, logs, runbooks (read-first) | Diagnosis + proposed change | Mutating prod without HITL |
| Internal workflow | CRM, calendar, Slack | Task completed or needs human | Duplicate messages / double-sends |
| Data analyst assist | SQL read, charting, warehouse catalog | Query + explanation | Unscoped SELECT * cost bombs |
Walkthrough: support “where is my order?”
- User asks about order
#A-1042. - Agent calls
get_order(id)→ statusshipped, tracking1Z…. - Agent calls
search_docs("shipping delays")→ policy snippet. - Agent returns a cited answer; no ticket write.
- Trajectory shows 2 tools, 1.8s, $0.01 — evals can replay.
If the product only needs “answer questions about our docs,” start with RAG (see RAG building blocks) — not a free-roaming agent.
Walkthrough: coding agent (shape only)
- Goal: “fix the flaky test in
checkout_test.py.” - Tools:
grep,read_file,edit_file,run_tests(sandboxed). - Loop: locate failure → edit → run tests → maybe revert → stop on green or budget.
- Policy: no network; no secrets files; max 20 edits; HITL before
git push.
Same five pieces. Higher blast radius → tighter sandbox and stop policy.
End-to-end mini design (support agent)
Goal: Answer “Where is order A-1042?” with a citation; escalate when unsure.
| Piece | Choice |
|---|---|
| Model | Hosted chat model with native tool calling |
| Tools | get_order, search_policy, create_ticket, final_answer |
| Policy | create_ticket requires HITL; others read-only |
| Stop | final_answer or max 6 steps or $0.05 budget |
| State | Thread id → message list in Redis (24h TTL) |
| Eval | 30 gold goals; must call get_order when an order id appears |
Happy path: user → get_order → search_policy → final_answer with tracking + citation → trajectory logged. Failure path: missing order → create_ticket → HITL card → ticket id observation → final answer with ticket link.
That single sketch forces every production layer: schemas, policy, stop, memory TTL, and eval invariants. If the product only needs “answer questions about our docs,” start with RAG (RAG building blocks) — not a free-roaming agent.
Architecture that survives production
Demos hide four hard layers. Production-shaped agents make them explicit:
flowchart TB
subgraph Client
UI[Chat / ticket UI]
end
subgraph ControlPlane
GW[API gateway]
Auth[Auth + tenant]
Bud[Budgets + rate limits]
end
subgraph AgentRuntime
Driver[Loop driver]
Policy[Tool policy / HITL]
Mem[(Session + memory)]
Trace[Trajectory + OTel]
end
subgraph Tools
Search[Search / RAG]
DB[(App DB)]
MCP[MCP servers]
Side[Mutating APIs]
end
UI --> GW --> Auth --> Driver
Bud --> Driver
Driver --> LLM[Model provider]
Driver --> Policy
Policy --> Search
Policy --> DB
Policy --> MCP
Policy --> Side
Driver --> Mem
Driver --> Trace
| Layer | Demo | Production-shaped |
|---|---|---|
| Tools | Fake stubs | Schema + validation + idempotency + side-effect policy |
| Stop | Hope the model says “done” | Max steps, budgets, HITL gates, deny lists |
| Memory | Chat buffer in RAM | Durable store + summarization + retrieval |
| Debug | print |
Trajectory traces, replay, per-hop latency |
| Multitenancy | None | Tenant isolation on tools, logs, and memory |
| Cost | Ignore | Per-run token + tool budget with hard kill |
Memory: three levels (do not skip straight to “vector memory”)
| Level | What | When |
|---|---|---|
| Working memory | Current message list / scratchpad | Every run |
| Session memory | Durable thread state across turns | Multi-turn products |
| Long-term memory | Summaries, preferences, retrieved facts | Only with retention + ACL policy |
Ship rule: do not invent a second brain before you can log and replay a single trajectory. Most “memory bugs” are context packing bugs.
Tool policy as a real component
flowchart LR
Call[Tool call] --> Schema[JSON Schema validate]
Schema --> AuthZ[AuthZ / tenant scope]
AuthZ --> Risk{Mutating?}
Risk -->|No| Exec[Execute + timeout]
Risk -->|Yes| HITL{Approved?}
HITL -->|Yes| Exec
HITL -->|No| Deny[Deny observation]
Exec --> Obs[Observation to model]
Deny --> Obs
Put policy outside the model. Prompt text like “never refund” is not a control.
How to build one (recommended path)
- Pick a single goal — e.g. “answer order status with citation.”
- Define 2–3 tools with tight JSON schemas (read-only first).
- Hand-roll the loop with
MAX_STEPSand trajectory logging — no framework yet. - Add stop + policy — deny write tools until HITL; timeout every tool.
- Golden-set evals — expected tool sequences + final answer rubrics (see Evals fundamentals).
- Only then adopt a framework if graphs, checkpoints, or multi-actor routing earn their complexity.
Tool design rules
- Prefer small, composable tools over one mega-“do_anything” tool.
- Return structured observations (JSON), not giant HTML dumps — protect the context window.
- Separate read vs write tools; require confirmation for writes.
- Treat tool output as untrusted data in the next prompt — delimit it; never let it override system policy (prompt injection via tool results is real).
- Cap observation size (truncate + “use a finer tool” hint).
- Make writes idempotent where possible (
Idempotency-Key, upsert by natural key).
Example tool schemas (tight vs vague)
{
"name": "get_order",
"description": "Fetch one order by exact id for the authenticated tenant.",
"parameters": {
"type": "object",
"required": ["order_id"],
"properties": {
"order_id": { "type": "string", "pattern": "^A-[0-9]{4,}$" }
},
"additionalProperties": false
}
}Vague alternative to avoid: "get_stuff": { "query": "string" } that can hit DB, Slack, and email.
Hand-rolled vs framework decision
| Stay hand-rolled when… | Adopt a framework when… |
|---|---|
| ≤5 tools, one loop | Need durable checkpoints / resumes |
| Teaching / interview clarity | Complex branching graphs |
| You own every stop policy line | Multi-actor routing is product-critical |
| Latency must stay minimal | Team already standardized on one stack |
Frameworks are accelerators, not architecture. If you cannot redraw the five pieces without the brand name, you do not understand your agent yet.
Framework map (what each actually buys)
| Stack | You still own | It helps with |
|---|---|---|
| Plain SDK loop | Everything | Clarity, interviews, tiny products |
| LangGraph | Tool policy, evals, tenancy | Graphs, checkpoints, durable state |
| LlamaIndex Workflows | Same | Event/workflow style orchestration |
| Crew / multi-actor kits | Same + role design | Role templates (easy to overuse) |
| MCP host/client | Loop + policy | Portable tool servers across apps |
| Product coding agents | Product UX around them | IDE/repo workflows (not your SaaS brain) |
Read Key Tech pages before adopting — LangGraph / LangChain, MCP.
Planner vs reactive (two control styles)
| Style | Behavior | Pros | Cons |
|---|---|---|---|
| Reactive ReAct | Choose next tool each step | Flexible; simple driver | Can wander; harder to budget |
| Plan-then-act | Model writes a plan, then executes | Clearer for long tasks | Stale plans; plan hallucinations |
| Hybrid | Short plan + reactive repair | Often best in practice | More moving parts |
Guided Build real AI agents walks planner vs reactive with code. Browse rule: start reactive with hard caps; add planning when trajectories show thrashing.
Agentic RAG (retrieval inside the loop)
Classic RAG: retrieve once → generate. Agentic RAG: retrieval is a tool the model may call zero or many times (rewrite query, fetch more, give up).
flowchart TD
Q[Question] --> A[Agent]
A -->|search_docs| R[Retriever]
R --> A
A -->|maybe search again| R
A -->|final_answer| Out[Cited answer]
Use when one-shot retrieval fails often (ambiguous queries, multi-hop facts). Do not start here — get one-shot RAG eval-gated first (RAG building blocks).
How to evaluate agents (not just answers)
Chatbots can be scored on final text. Agents need trajectory-aware evals:
| Signal | What it catches |
|---|---|
| Exact / rubric final answer | Outcome quality |
| Expected tool sequence (soft) | Wrong tool habits |
| Illegal tool calls | Policy holes |
| Step count / cost | Loops and waste |
| Faithfulness to tool observations | Ignoring evidence |
| Human preference on hard cases | UX / tone |
Build a golden set of goals → allowed tools → acceptable trajectories → answer rubrics. Wire it in CI the same way you would for prompts. Details: Evals fundamentals and guided Evals, guardrails, safety.
Soft vs hard trajectory checks
| Check type | Example | Notes |
|---|---|---|
| Hard | Must not call refund without HITL |
CI should fail the build |
| Hard | Must call get_order before answering status |
Structural |
| Soft | Prefer ≤4 steps | Warn; tune over time |
| Soft | Tool order may vary | Allow multiple valid paths |
Do not require a single exact tool sequence for every gold case — models are stochastic. Require invariants (must/must-not) plus answer quality.
Debugging playbook (first hour of an incident)
- Pull
run_idtrajectory; plot tools vs time. - Check stop reason: max steps, deny, timeout, final answer, user cancel.
- Diff schemas if you recently added overlapping tools.
- Inspect observation sizes — context blow-ups hide as “model got dumb.”
- Replay locally with temperature 0 for reproducibility.
- Add a golden case that would have caught this before closing the incident.
Tools and stacks today (2025–2026)
You do not need all of these. Learn the pattern first; pick one stack when shipping.
| Layer | Common choices | Role |
|---|---|---|
| Model APIs | OpenAI, Anthropic, Google, open-weight via vLLM/Ollama | Brain + native tool calling |
| Orchestration | LangGraph, LlamaIndex Workflows, Microsoft Agent Framework / Semantic Kernel, CrewAI, Autogen-style multi-agent | Graphs, state, multi-actor |
| Lightweight | smolagents, plain SDKs | Teaching / thin wrappers |
| Tool protocol | MCP (Model Context Protocol) servers/clients | Standardize tool I/O across apps |
| Product agents | Cursor / Claude Code / OpenAI Agents-style runtimes | Coding & computer-use patterns |
| Observability | OpenTelemetry, LangSmith, Helicone, custom trajectory stores | Debug loops and cost |
| Structured I/O | JSON Schema / Zod / Pydantic validators | Tool args + final objects |
Browse deeper in Key Tech: LangGraph / LangChain, MCP, OpenAI / Anthropic APIs. Advanced: Multi-agent orchestration, Guardrails.
MCP in one paragraph
Model Context Protocol standardizes how hosts discover and call tools/resources from servers (filesystem, DB, SaaS). Your agent driver still owns the loop; MCP is a tool transport and schema convention, not a replacement for stop policy. See Model Context Protocol and Skills, MCP, context engineering.
Failure modes (why agents feel “broken”)
| Symptom | Likely cause | Fix direction |
|---|---|---|
| Infinite search / tool spam | No max steps / weak stop | Hard caps + final_answer tool |
| Wrong tool, right vibe | Vague schemas / overlapping tools | Tighten schemas; fewer tools |
| Hallucinated args | Model invents IDs | Validate; fetch IDs via read tools first |
| Context blow-up | Huge tool dumps | Truncate, summarize, retrieve selectively |
| Surprise side effects | Writes without HITL | Policy gate; idempotency keys |
| Non-deterministic flakiness | Unstable planning | Lower temperature for tools; eval trajectories |
| Cost spike | Loops × expensive model | Step + token budgets; cheaper model for routing |
| Prompt injection via tools | Untrusted web/DB text treated as instructions | Delimit; strip; never elevate tool text to system |
| “Agent” that is just a chatbot | No tools / no loop | Either add tools or drop the label |
| Perfect demo, bad prod | No golden trajectories | Eval gates before launch |
flowchart TD
Fail[User says agent is broken] --> Trace[Open trajectory]
Trace --> Q1{Hit max steps?}
Q1 -->|Yes| Cap[Tune tools or raise cap with budget]
Q1 -->|No| Q2{Wrong tool?}
Q2 -->|Yes| Schema[Fix schemas / reduce tools]
Q2 -->|No| Q3{Bad observation?}
Q3 -->|Yes| Trunc[Truncate + structured returns]
Q3 -->|No| Eval[Add golden case + rubric]
Security and blast radius (non-optional)
Agents amplify whatever tools you expose.
- Least privilege — read-only credentials for research tools; separate write principals.
- Sandbox — code runners without network or secrets by default.
- Egress allowlists — especially for computer-use / browsing agents.
- Secret hygiene — never put API keys in tool observations or prompts.
- Audit — every mutating call attributable to user + agent run id.
- Human gates — refunds, deletes, prod deploys, outbound email.
Pair with Guardrails and safety and Privacy and data for AI.
Computer use and browsing agents (special case)
Some products give the model a desktop or browser: screenshots in, click/type actions out. Same five pieces — the “tools” are UI actions.
Extra constraints that ordinary tool agents need less of:
| Constraint | Why |
|---|---|
| Virtual display / sandbox VM | Contain malware and data exfil |
| Allowlisted domains | Stop unexpected navigations |
| Action rate limits | Prevent click storms |
| Screenshot redaction | Hide secrets on screen before model sees them |
| Stronger HITL | Purchases, posts, admin consoles |
Do not start here. Learn ReAct on typed APIs first; computer use is the same loop with a wider blast radius.
Observability: what to log every run
If you cannot answer “what did the agent do?”, you cannot debug or eval.
Minimum trajectory record (JSONL is fine):
{
"run_id": "r_01",
"step": 2,
"model": "…",
"tool": "get_order",
"args_digest": "sha256:…",
"ok": true,
"latency_ms": 120,
"tokens_in": 1800,
"tokens_out": 40,
"cost_usd": 0.012
}Add OpenTelemetry spans for gateway → model → each tool (OpenTelemetry for LLMs when you go deeper). Redact PII before export.
Cost model (back-of-envelope)
[ \text{cost} \approx \sum_{\text{steps}} (\text{prompt tokens} + \text{completion tokens})\cdot $/\text{token} + \sum_{\text{tools}} \text{tool cost} ]
Agent products die from steps × fat contexts, not from one clever prompt. Cap steps, truncate observations, and route easy turns to cheaper models.
From one agent to many (preview)
When one loop thrashes on huge tool sets, split roles:
flowchart TD
User --> Router
Router --> Support[Support agent]
Router --> Research[Research agent]
Support --> State[(Shared state)]
Research --> State
State --> User
Patterns (router, supervisor–worker, handoff) live in Multi-agent orchestration and guided Agentic workflows & multi-agent. Ship rule: earn multi-agent by failing single-agent with evidence from traces — do not start there for a portfolio demo.
Production readiness checklist
- Hard
MAX_STEPSand wall-clock deadline - Per-tool timeouts + schema validation
- Read vs write tools separated; HITL on writes
- Trajectory logging with replay
- Golden set with illegal-tool cases
- Token/cost budget kill switch
- Tenant isolation on tools and memory
- Prompt-injection handling for tool/web text
- User-visible escalate / “I don’t know” path
- Runbook: how to disable the agent without taking down the app
Tradeoffs and when to use an agent
Use an agent when:
- The goal is open-ended and tool choice depends on intermediate results.
- You can bound tools, steps, and blast radius.
- You will invest in trajectories + evals (not just a demo prompt).
Prefer a simpler system when:
- Steps are fixed → workflow / DAG.
- Need grounded Q&A only → RAG + citations.
- Need a machine-checkable object → structured outputs, not a 12-step loop.
- Risk of autonomous writes is unacceptable without heavy HITL.
- Latency budget cannot afford multi-hop tool RPCs (Networking for AI apps).
Interview / design cue: always name tools, state, stop conditions, and eval of trajectories — not just “we’ll add an agent.”
Interview prompts you should be able to answer
- Draw the agent loop and mark where authZ and HITL live.
- When is a deterministic workflow better than ReAct?
- How do you eval an agent differently from a chatbot?
- How do you prevent prompt injection via tool results?
- What do you log per step, and what do you redact?
Glossary
| Term | Meaning |
|---|---|
| ReAct | Pattern of interleaving reasoning and acting (tools) in a loop |
| Trajectory | Ordered record of thoughts/tool calls/observations for one run |
| Tool / function calling | Model emits structured call; runtime executes |
| HITL | Human-in-the-loop approval before sensitive actions |
| MCP | Protocol for exposing tools/resources to model clients |
| Planner vs reactive | Plan-all-then-act vs choose-next-action each step |
| Agentic RAG | Retrieval as a tool inside an agent loop, not a one-shot retrieve |
| Driver / runtime | Your code that owns the loop, policy, and logging |
| Observation | Tool result appended back into model context |
| Stop condition | Rule that ends the loop (final answer, max steps, deny, budget) |
Micro-project
Hand-roll a 3-tool ReAct loop (e.g. get_order, search_docs, final_answer) with:
- Hard
MAX_STEPS = 6 - Schema validation before execute
- Trajectory JSONL log you can replay
- A deliberate failure case that hits max steps cleanly
- One golden eval asserting “must call
get_orderbefore answering”
Related guided path and tracks
- Guided Build real AI agents — LLM vs agent; ReAct loop (start here to implement)
- Skills, MCP, context engineering · Agentic workflows & multi-agent · Evals, guardrails, safety
- Concepts: RAG building blocks, Evals fundamentals, Structured outputs, Prompt engineering
- Advanced: Multi-agent orchestration, Context engineering, Guardrails
- Tools: LangGraph, MCP
This browse article is the complete mental model. Build real AI agents is where you build the loop until frameworks stop feeling like magic.