Skip to Content
FrameworksLangGraph + Curate-Me

LangGraph

LangGraph builds on langchain-openai’s ChatOpenAI, so the integration shape is identical to LangChain — configure the LLM with base_url + default_headers, then use it as any node’s LLM.

Minimal example

import os from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, END llm = ChatOpenAI( base_url=os.environ.get("CM_GATEWAY_URL", "https://api.curate-me.ai/v1/openai"), default_headers={"X-CM-API-Key": os.environ["CM_API_KEY"]}, model="gpt-4o", ) def respond(state): return {"messages": state["messages"] + [llm.invoke(state["messages"])]} graph = StateGraph(dict) graph.add_node("respond", respond) graph.set_entry_point("respond") graph.add_edge("respond", END) app = graph.compile()

Full single-node and multi-agent examples live at examples/integrations/langgraph/.

What’s traced

Each node’s LLM call shows up as its own trace row in the dashboard, keyed by X-CM-Request-Id. The trace carries the node name as a custom attribute when you set tags=["node:respond"] on the LLM invocation — this lets you slice cost by node.

Supported versions

LibraryTested range
langgraph>=0.2.40,<0.4.0
langchain-openai>=0.2.0,<0.4.0

Known limitations

  • Checkpointer: the gateway only sees per-node LLM calls. State snapshots persisted by MemorySaver / PostgresSaver / SqliteSaver run entirely on your infrastructure. We don’t yet store cross-step memory diffs.
  • Conditional routing: edges that don’t make LLM calls (pure-Python routers) don’t show up in the trace — that’s by design, the gateway is invoked only when an LLM call happens.
  • Subgraphs: each subgraph node is a separate trace. Use the W3C traceparent header on outer calls to link them.