Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
LangChain, LangGraph, LlamaIndex, AutoGen, CrewAI — every month a new framework promises to make agents easier. Most of them are heavy and opinionated; few survive their first real production deployment. The honest assessment: for simple agents (1-3 tools, max 5 iterations, single workflow), raw SDK code wins on simplicity and debuggability. For complex agents (graph-based control flow, many tool combinations, multi-agent), LangGraph or similar pays for itself. Start raw; adopt only when the boilerplate starts hurting.
When raw wins: small tool surface, predictable control flow, debugging-by-print-statement, no team-coordination overhead. When LangGraph (or similar) wins: graph-based control flow that you'd otherwise code by hand, multi-agent orchestration with checkpointing, state persistence across long-running sessions. LangChain's main lib has grown so large it often hurts more than helps; LangGraph (smaller, focused on agent state) is the more defensible choice in 2026.
# --- Pick your provider (set the matching API key env var) ---
# Anthropic: from anthropic import Anthropic; client = Anthropic() # ANTHROPIC_API_KEY
# OpenAI: from openai import OpenAI; client = OpenAI() # OPENAI_API_KEY
# Gemini: from google import genai; client = genai.Client() # GEMINI_API_KEY
# Raw agent loop — best for simple agents (1-3 tools, <=5 steps).
def run_agent_raw(user_msg, tools, max_steps=6):
messages = [{"role": "user", "content": user_msg}]
for _ in range(max_steps):
resp = client.messages.create(
model="claude-sonnet-4-6", max_tokens=1024, tools=tools, messages=messages,
)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason != "tool_use":
return resp # model produced a final answer
results = []
for block in resp.content:
if block.type == "tool_use":
out = dispatch(block.name, block.input) # your tool router
results.append({"type": "tool_result", "tool_use_id": block.id, "content": out})
messages.append({"role": "user", "content": results})
return messages # ~50 lines, no deps, fully debuggablepython3 main.py