What each one is
LangGraph, from the LangChain team, builds stateful workflows as graphs. Nodes are functions, edges set the order (including conditional branches), a typed state object is passed from node to node, and checkpointers save that state so a run can pause, resume or wait for a person.
The OpenAI Agents SDK is a lightweight Python framework for agents. An Agent has instructions, a model, tools (plain Python functions), an optional output_type for structured results, and optional handoffs to other agents. Runner runs the agent loop, and tracing is built in.
Side by side
| LangGraph | OpenAI Agents SDK | |
|---|---|---|
| Core idea | A graph of steps over shared state | An agent with instructions, tools and a run loop |
| Who decides the next step | You, through edges and conditions | Mostly the model, through tool calls and handoffs |
| State | Typed state object with checkpoints | The conversation plus a context object you pass in |
| Multiple agents | Nodes or sub-graphs, wired explicitly | Handoffs, or agents used as tools |
| Pausing for a person | Built around checkpoints and interrupts | You build it around tool calls |
| Structured output | Via the model integration you use | output_type with a Pydantic model |
| Best fit | Multi-step pipelines and long-running jobs | Focused agents and conversational assistants |
When we reach for LangGraph
- The steps are known in advance: download, extract, merge, analyse, draft.
- A run takes minutes and must be able to resume after a failure.
- The workflow branches on validated results, not on what the model feels like doing next.
- A person must approve something in the middle of the run.
When we reach for the Agents SDK
- One agent with a handful of tools, such as a support or operations assistant.
- Structured extraction, where
output_typehands back a validated object. - A conversation that should pass between specialists (handoffs).
- A quick prototype that may later become a node in a bigger workflow.
Using both: agents inside a graph
In our multi-agent RFP pipeline, LangGraph runs the stages and each stage calls a focused Agents SDK agent. A minimal version of the pattern:
from typing import Literal, TypedDict
from pydantic import BaseModel
from agents import Agent, Runner
from langgraph.graph import StateGraph, START, END
class Requirement(BaseModel):
requirement: str
type: Literal["uploadable", "text"]
deadline: str | None = None
class Extraction(BaseModel):
requirements: list[Requirement]
extractor = Agent(
name="RequirementExtractor",
instructions=(
"Extract every requirement that needs a file, form or certification "
"(type 'uploadable') or a written answer (type 'text')."
),
model="gpt-4o-mini",
output_type=Extraction, # the SDK returns a validated Extraction object
)
class State(TypedDict):
chunks: list[str]
requirements: list[dict]
errors: list[str]
async def extract(state: State) -> dict:
found, errors = [], []
for i, chunk in enumerate(state["chunks"]):
try:
result = await Runner.run(extractor, chunk)
found += [r.model_dump() for r in result.final_output.requirements]
except Exception as error: # record it and keep going
errors.append(f"chunk {i}: {error}")
return {"requirements": found, "errors": state["errors"] + errors}
graph = StateGraph(State)
graph.add_node("extract", extract)
graph.add_edge(START, "extract")
graph.add_edge("extract", END)
app = graph.compile()Do you need either?
Not always. A simple agent is a loop around a model call with a few tools, and plain code is easier to debug than a framework you don't fully know. Our open-source agent harness template uses neither, to show what sits underneath: the loop, stop conditions, typed tools, approvals, tracing and evaluations. Whichever you choose, production reliability comes from that harness, not from the framework's name.