Use this file to discover all available pages before exploring further.
LangGraph is a framework for building stateful, multi-step agent workflows as graphs. It provides StateGraph for custom control flow, conditional routing, subgraph composition, and checkpointing.HoneyHive integrates with LangGraph via the OpenInference LangChain instrumentor (LangGraph builds on LangChain under the hood), automatically capturing graph execution, node transitions, and LLM calls.
Same instrumentor as LangChain. If you’ve already set up LangChain instrumentation, LangGraph graphs are automatically traced too. For the simpler create_agent pattern without custom graphs, see the LangChain integration.
LangGraph uses the same instrumentor as LangChain; versions are kept in sync across both pages. As of April 2026:
Package
Version
langgraph
1.1.6
langchain
1.2.15
openinference-instrumentation-langchain
0.1.62
Requires Python 3.11+. See the LangChain integration for the Traceloop alternative - the same opentelemetry-instrumentation-langchain package also traces LangGraph.
This example builds a coordinator StateGraph that classifies customer questions and delegates to specialist agents built with create_agent. This is the core LangGraph pattern: combining the graph API with agent subgraphs.
import osfrom typing import Literal, TypedDictfrom honeyhive import HoneyHiveTracerfrom openinference.instrumentation.langchain import LangChainInstrumentorfrom langchain.agents import create_agentfrom langchain_core.messages import HumanMessage, SystemMessagefrom langchain_core.tools import toolfrom langchain_openai import ChatOpenAIfrom langgraph.graph import END, START, StateGraphfrom pydantic import BaseModel, Fieldtracer = HoneyHiveTracer.init(api_key=os.getenv("HH_API_KEY"))LangChainInstrumentor().instrument(tracer_provider=tracer.provider)model = ChatOpenAI(model="gpt-4o-mini")@tooldef lookup_order_status(order_id: str) -> dict: """Look up the current status of a customer order.""" statuses = { "ORD-1001": {"state": "shipped", "eta_days": 2}, "ORD-1002": {"state": "processing", "eta_days": 5}, "ORD-1003": {"state": "delayed", "eta_days": 8}, } return statuses.get(order_id.upper(), {"state": "not_found"})@tooldef lookup_policy(topic: str) -> dict: """Look up company support policy on a given topic.""" policies = { "refund": {"summary": "Refunds within 30 days for undelivered or damaged items."}, "cancellation": {"summary": "Cancellation allowed before shipment."}, "shipping": {"summary": "Standard shipping 3-5 business days."}, } return policies.get(topic.lower().strip(), {"summary": "No policy found."})# Specialist agentsorder_specialist = create_agent( model, tools=[lookup_order_status], name="order_specialist", system_prompt="You are an order specialist. Return status and ETA in one sentence.",)policy_specialist = create_agent( model, tools=[lookup_policy], name="policy_specialist", system_prompt="You are a policy specialist. Answer refund, cancellation, and shipping questions concisely.",)# Coordinator graphclass CoordinatorState(TypedDict): question: str category: str answer: strclass RouteDecision(BaseModel): category: Literal["order", "policy", "general"] = Field( description="Route the question to the right specialist" )router_llm = model.with_structured_output(RouteDecision)def classify(state: CoordinatorState) -> dict: result = router_llm.invoke([ SystemMessage(content=( "Classify the customer question as 'order' (about a specific " "order status/delivery), 'policy' (about refund/cancellation/" "shipping rules), or 'general'." )), HumanMessage(content=state["question"]), ]) return {"category": result.category}def handle_order(state: CoordinatorState) -> dict: result = order_specialist.invoke( {"messages": [HumanMessage(content=state["question"])]} ) return {"answer": result["messages"][-1].content}def handle_policy(state: CoordinatorState) -> dict: result = policy_specialist.invoke( {"messages": [HumanMessage(content=state["question"])]} ) return {"answer": result["messages"][-1].content}def handle_general(state: CoordinatorState) -> dict: response = model.invoke([ SystemMessage(content="Answer concisely as a support agent."), HumanMessage(content=state["question"]), ]) return {"answer": response.content}coordinator = ( StateGraph(CoordinatorState) .add_node("classify", classify) .add_node("order", handle_order) .add_node("policy", handle_policy) .add_node("general", handle_general) .add_edge(START, "classify") .add_conditional_edges( "classify", lambda state: state["category"], {"order": "order", "policy": "policy", "general": "general"}, ) .add_edge("order", END) .add_edge("policy", END) .add_edge("general", END) .compile())result = coordinator.invoke({"question": "Where is my order ORD-1001?", "category": "", "answer": ""})print(result["answer"])
In HoneyHive, you’ll see the full execution hierarchy: coordinator graph, classify node, routing decision, specialist subgraph agent with tool calls, and LLM spans within each node.
Example: Multi-Turn Conversation with Checkpointing
LangGraph’s MemorySaver persists conversation state across turns with the same thread_id. The agent remembers context from previous turns without you managing history manually.
import osfrom honeyhive import HoneyHiveTracerfrom openinference.instrumentation.langchain import LangChainInstrumentorfrom langchain.agents import create_agentfrom langchain_core.messages import HumanMessagefrom langchain_core.tools import toolfrom langchain_openai import ChatOpenAIfrom langgraph.checkpoint.memory import MemorySavertracer = HoneyHiveTracer.init(api_key=os.getenv("HH_API_KEY"))LangChainInstrumentor().instrument(tracer_provider=tracer.provider)@tooldef lookup_order_status(order_id: str) -> dict: """Look up the current status of a customer order.""" statuses = { "ORD-1001": {"state": "shipped", "eta_days": 2}, "ORD-1003": {"state": "delayed", "eta_days": 8}, } return statuses.get(order_id.upper(), {"state": "not_found"})@tooldef lookup_policy(topic: str) -> dict: """Look up company support policy on a given topic.""" policies = { "cancellation": {"summary": "Cancellation allowed before shipment. Delayed orders can request assisted cancellation."}, } return policies.get(topic.lower().strip(), {"summary": "No policy found."})model = ChatOpenAI(model="gpt-4o-mini")memory = MemorySaver()agent = create_agent( model, tools=[lookup_order_status, lookup_policy], name="support_agent", system_prompt=( "You are a customer support agent with memory of the conversation. " "Use tools to look up orders and policies. Reference previous " "context when the customer follows up." ), checkpointer=memory,)thread = {"configurable": {"thread_id": "customer-session-001"}}# Turn 1: check order statusresult = agent.invoke( {"messages": [HumanMessage(content="Can you check the status of order ORD-1003?")]}, config=thread,)print(result["messages"][-1].content)# Turn 2: follow-up referencing previous contextresult = agent.invoke( {"messages": [HumanMessage(content="That order is delayed. What are my cancellation options?")]}, config=thread,)print(result["messages"][-1].content)
Each turn produces a separate trace in HoneyHive, but the agent maintains conversation history across turns via the shared thread_id.