Exercise 1: Same Agent, Two Frameworks (LangGraph + CrewAI)¶
Pairs with Stage 4 — Agent Frameworks Exercise 1.
Task¶
A minimal search + summarize agent:
- Given a query (e.g. "summarize Taipei")
- Agent uses a
searchtool to hit a knowledge base - LLM summarizes the result in 1-2 sentences
Built once in LangGraph and once in CrewAI — compare styles.
How to run — two paths + two frameworks¶
Path A (default, free, local)¶
pip install -r requirements.txt
ollama pull qwen2.5:3b
ollama serve
python starter.py # LangGraph + Ollama
python starter_crewai.py # CrewAI + Ollama (comparison)
Budget: $0.
Path B (Anthropic, cloud-quality)¶
pip install -r requirements.txt
export ANTHROPIC_API_KEY=sk-ant-...
python starter_anthropic.py # LangGraph + Claude
Budget: ~$0.001 per run (claude-haiku-4-5).
Validate the logic (mock-based)¶
python test.py # LangGraph + mock LLM
python test_anthropic.py # starter_anthropic loads + ChatAnthropic constructs
python test_crewai.py # CrewAI tool + module loads
Side-by-side framework comparison¶
| Dimension | LangGraph | CrewAI |
|---|---|---|
| Core abstraction | StateGraph + node + edge |
Agent + Task + Crew |
| Mental model | "How does state flow?" | "Who plays what role?" |
| Loop control | Explicit conditional edges | Hidden inside Crew.kickoff() |
| Lines of code (this task) | ~50 | ~25 |
| Debug path | Inspect graph state, time-travel | Verbose logs, hard to step |
| Best for | Complex branching, production, audit | Multi-agent prototypes, role-based tasks |
| Learning curve | Medium-high | Low |
LangGraph style (condensed)¶
g = StateGraph(State)
g.add_node("agent", agent_node)
g.add_node("tools", tool_node)
g.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
g.add_edge("tools", "agent")
"I tell the system explicitly: state shape, nodes, edges, branching via should_continue."
CrewAI style (condensed)¶
researcher = Agent(role="Researcher", goal="...", tools=[search], llm=MODEL)
task = Task(description=query, expected_output="...", agent=researcher)
crew = Crew(agents=[researcher], tasks=[task])
crew.kickoff()
"I describe: who plays this role, what task, what tools. Framework decides how to run."
What to observe¶
- Abstraction cost: CrewAI hides more, writes less code; but stack depth grows when debugging
- Small-model friendliness: LangGraph is more stable with qwen2.5:3b; CrewAI's denser prompts can confuse small models
- Controllability: LangGraph exposes state transitions; CrewAI is "result-oriented"
- When to pick: production / audit → LangGraph. Multi-agent prototypes / role-based → CrewAI
Common pitfalls¶
- LangGraph
bind_tools: mustllm.bind_tools([search])to expose tool schema. Without it the model doesn't know the tool exists - CrewAI model spec: needs LiteLLM format (
"ollama/qwen2.5:3b", not"qwen2.5:3b"). Misspell and framework silently falls back to OpenAI default - CrewAI return type:
crew.kickoff()returns aCrewOutputobject;str(result)to get text. Bareprint(result)may show repr
Want smarter answers?¶
MODEL=claude-sonnet-4-6 python starter_anthropic.py # more stable
MODEL=qwen2.5:7b python starter.py # larger local model
Extensions¶
- Streaming: LangGraph
graph.stream(...), CrewAIcrew.kickoff(stream=True) - Checkpointing: LangGraph +
MemorySaverfor time-travel debug - Human-in-the-loop: see Exercise 3