If you plan to build research assistant crewai autogen langgraph implementations, you need code that goes beyond marketing demos. This tutorial constructs a three-agent research pipeline in each framework against the same LLM endpoint, so you can judge orchestration tradeoffs with real runnable snippets.
Prerequisites
- Python 3.10 or newer
- Install the frameworks:
pip install crewai pyautogen langgraph langchain-openai python-dotenv - An LLM API key. We route all three frameworks through n4n.ai’s OpenAI-compatible endpoint (
https://api.n4n.ai/v1), which exposes 240+ models behind one key and fails over automatically when a provider is rate-limited. SetOPENAI_API_KEYandOPENAI_API_BASEin a.envfile.
All examples share a mock search tool to keep the focus on agent orchestration:
# tools.py
def web_search(query: str) -> str:
"""Mock search. Swap for Tavily/SerpAPI in production."""
return f"Result for '{query}': Multi-agent systems improve task decomposition."
The pipeline has three roles: a planner that emits sub-questions, a researcher that calls web_search, and a writer that produces a markdown report.
CrewAI: declarative roles and tasks
CrewAI asks you to describe agents and tasks, then wires them sequentially or hierarchically. It is the fastest way to build research assistant crewai autogen langgraph variants when you think in job descriptions.
from crewai import Agent, Task, Crew, Process
from tools import web_search
import os
from dotenv import load_dotenv
load_dotenv()
planner = Agent(
role="Planner",
goal="Break the topic into 3 research sub-questions",
backstory="Senior analyst who scopes inquiries precisely",
allow_delegation=False,
)
researcher = Agent(
role="Researcher",
goal="Answer each sub-question using web_search",
backstory="Diligent investigator",
tools=[web_search],
)
writer = Agent(
role="Writer",
goal="Synthesize findings into a markdown report",
backstory="Technical writer with clarity bias",
)
task_plan = Task(
description="Topic: multi-agent LLM frameworks",
agent=planner,
expected_output="Three numbered questions",
)
task_research = Task(
description="Research the questions from the prior step",
agent=researcher,
expected_output="Concise findings per question",
)
task_write = Task(
description="Write the final report",
agent=writer,
expected_output="Markdown report with sections",
)
crew = Crew(
agents=[planner, researcher, writer],
tasks=[task_plan, task_research, task_write],
process=Process.sequential,
)
result = crew.kickoff()
print(result)
Expected checkpoint output
CrewAI prints a formatted result. The writer node typically emits:
# Multi-Agent LLM Frameworks
## Question 1
Result for '...': Multi-agent systems improve task decomposition.
## Question 2
...
## Conclusion
Frameworks differ in control granularity.
CrewAI hides the message-passing internals. If you need to inspect intermediate handoffs, you must add callbacks.
AutoGen: conversational group chat
AutoGen models agents as chat participants. To build research assistant crewai autogen langgraph style with AutoGen, you spin up assistants and a proxy that owns the tools, then let a GroupChatManager mediate.
import os
from autogen import AssistantAgent, UserProxyAgent, GroupChat, GroupChatManager
from tools import web_search
from dotenv import load_dotenv
load_dotenv()
llm_config = {
"model": "gpt-4o-mini",
"api_key": os.environ["OPENAI_API_KEY"],
"base_url": os.environ["OPENAI_API_BASE"],
}
planner = AssistantAgent(
"planner",
llm_config=llm_config,
system_message="You output exactly 3 research questions, nothing else.",
)
researcher = AssistantAgent(
"researcher",
llm_config=llm_config,
system_message="You call web_search for each question and summarize.",
)
writer = AssistantAgent(
"writer",
llm_config=llm_config,
system_message="You compile the summaries into a markdown report.",
)
user_proxy = UserProxyAgent(
"user_proxy",
human_input_mode="NEVER",
code_execution_config=False,
function_map={"web_search": web_search},
)
group = GroupChat(
agents=[user_proxy, planner, researcher, writer],
messages=[],
max_round=12,
)
manager = GroupChatManager(group, llm_config=llm_config)
user_proxy.initiate_chat(manager, message="Topic: multi-agent LLM frameworks")
Expected checkpoint output
AutoGen streams the conversation. You will see the planner speak, the researcher invoke web_search via the proxy, and the writer finalize:
user_proxy (to chat_manager):
Topic: multi-agent LLM frameworks
planner: 1. How does CrewAI handle delegation? 2. ...
researcher (to user_proxy): web_search('How does CrewAI handle delegation?')
user_proxy: Result for '...': Multi-agent systems improve task decomposition.
writer: # Report ...
AutoGen shines when agents must negotiate or iterate through dialogue. The cost is non-deterministic flow unless you cap rounds tightly.
LangGraph: explicit state machine
LangGraph forces you to define a typed state and pure transition nodes. This is the most verbose way to build research assistant crewai autogen langgraph, but it gives you full control over retries, branching, and observability.
import os
from typing import TypedDict, List
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from tools import web_search
from dotenv import load_dotenv
load_dotenv()
llm = ChatOpenAI(
model="gpt-4o-mini",
api_key=os.environ["OPENAI_API_KEY"],
base_url=os.environ["OPENAI_API_BASE"],
)
class State(TypedDict):
topic: str
questions: List[str]
findings: List[str]
report: str
def plan(state: State):
resp = llm.invoke(f"Give 3 research questions about {state['topic']}. Numbered list.")
qs = [l.strip() for l in resp.content.split("\n") if l.strip()][:3]
return {"questions": qs}
def research(state: State):
findings = [web_search(q) for q in state["questions"]]
return {"findings": findings}
def write(state: State):
resp = llm.invoke(f"Write a markdown report from: {state['findings']}")
return {"report": resp.content}
graph = StateGraph(State)
graph.add_node("plan", plan)
graph.add_node("research", research)
graph.add_node("write", write)
graph.add_edge("plan", "research")
graph.add_edge("research", "write")
graph.add_edge("write", END)
graph.set_entry_point("plan")
app = graph.compile()
out = app.invoke({
"topic": "multi-agent LLM frameworks",
"questions": [],
"findings": [],
"report": "",
})
print(out["report"])
Expected checkpoint output
The compiled graph returns a dict. out["report"] contains:
# Multi-Agent LLM Frameworks Research
- **Question 1**: Result for '...': Multi-agent systems improve task decomposition.
- **Question 2**: ...
LangGraph’s advantage is debuggability: every node input/output is logged, and you can add conditional edges (e.g., loop back to plan if len(questions) < 3).
Comparison notes from the trenches
All three can build research assistant crewai autogen langgraph pipelines against the same endpoint. The differences are architectural:
- CrewAI optimizes for declarative speed. You lose fine-grained control over message routing, but you ship in minutes. Use it when roles are stable and you do not need dynamic re-planning.
- AutoGen treats orchestration as conversation. That is powerful for open-ended tasks, but token usage spikes because agents talk in natural language. Set
max_roundaggressively. - LangGraph is the right call when you need guardrails, human-in-the-loop, or complex branching. The boilerplate is real, but the graph compiles to something you can unit test.
One practical tip: because we pointed every framework at a single OpenAI-compatible gateway, model swaps are a one-line config change. If a provider behind the gateway degrades, the fallback keeps the crew running without code changes.
Pick the framework that matches your control needs, not the hype cycle. The agent logic above transfers cleanly; only the scaffolding differs.