LangGraph: using the VIDAI Control Plane as the backend¶
LangGraph builds on LangChain's BaseChatModel contract. You
configure a LangChain chat model pointed at the control plane (see
langchain.md) and pass it into your graph.
LangGraph itself needs no control-plane-specific configuration.
TL;DR¶
export OPENAI_API_BASE=https://your-vidaiserver.example.com/v1
export OPENAI_API_KEY=sk-your-vidai-key
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
model = ChatOpenAI(model="gpt-4o-mini") # reads env vars
agent = create_agent(model=model, tools=[])
result = agent.invoke(
{"messages": [{"role": "user", "content": "hello"}]}
)
for msg in result["messages"]:
print(msg.type, ":", getattr(msg, "content", "")[:80])
Prerequisites¶
langgraph >= 1.1+langchain >= 1.0(forlangchain.agents.create_agent)- One of:
langchain-openai,langchain-anthropic,langchain-google-genai - The control plane URL and an API key
API note: the ReAct-style prebuilt used to live at
langgraph.prebuilt.create_react_agent. As of LangGraph 1.0, the recommended import isfrom langchain.agents import create_agent. Both drive the same underlying state machine; use the new import in new code.
New project: LangGraph¶
- Install:
- Configure the ChatModel (per langchain.md).
- Build your graph:
from langchain_openai import ChatOpenAI from langchain.agents import create_agent from langchain_core.tools import tool @tool def get_weather(city: str) -> str: """Get current weather for a city.""" return f"{city}: 20C" model = ChatOpenAI(model="gpt-4o-mini") agent = create_agent(model=model, tools=[get_weather]) result = agent.invoke( {"messages": [{"role": "user", "content": "Weather in Paris?"}]} )
Existing project: LangGraph¶
LangGraph isn't where you wire the control plane; the LangChain ChatModel
you pass to create_agent(...) (or to a custom StateGraph node)
is. So:
- If your graph passes a
ChatOpenAI(...): see langchain.md "Existing project: ChatOpenAI". Usually just env-var changes. - If your graph passes a
ChatAnthropic(...): same, see the ChatAnthropic section. - If your graph passes a
ChatGoogleGenerativeAI(...): you need a constructorbase_url=kwarg; centralise it in a factory.
The rest of your graph (nodes, edges, state schema, conditional routing) is unchanged.
Multi-turn conversations¶
Carry state between turns by appending to the messages list:
turn1 = agent.invoke(
{"messages": [{"role": "user", "content": "say alpha"}]}
)
turn2 = agent.invoke(
{"messages": list(turn1["messages"]) + [
{"role": "user", "content": "now say beta"}
]}
)
For persistent state across process restarts, use LangGraph's
checkpointer (e.g. MemorySaver or a SQLite / Postgres backend);
that's a LangGraph concern, not a control plane one.
Streaming¶
Each event is a dict of {node_name: state_update}: exactly how
LangGraph streams state changes. The underlying ChatModel chunks
are merged by LangChain before LangGraph emits them.
Tool execution: graph-visible¶
When a tool fires inside the agent loop, the result shows up as a
ToolMessage in the state:
result = agent.invoke(
{"messages": [{"role": "user", "content": "Weather in Tokyo?"}]}
)
for m in result["messages"]:
if m.type == "tool":
print("tool output:", m.content)
Cross-provider routing¶
LangGraph inherits whichever cross-provider capabilities the underlying ChatModel has. See the cross-provider matrix in Client integrations; column rules apply to the LangChain wrapper you choose.
Reading the control plane's response headers¶
LangGraph inherits LangChain's visibility here; response headers
aren't surfaced through the graph's state updates. For debug
requests, either:
- Call the underlying vendor SDK directly (bypass LangGraph
briefly; see e.g. openai-sdk.md "Reading
the control plane's response headers").
- Check response_metadata on the AIMessages in the graph state
(may or may not be populated depending on the LangChain version).
See routing-and-headers.md for what the
x-vidai-* headers mean and when each one is set.
Verify it works: probe¶
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
model = ChatOpenAI(
model="gpt-4o-mini",
base_url="https://your-vidaiserver.example.com/v1",
api_key="sk-your-vidai-key",
)
agent = create_agent(model=model, tools=[])
result = agent.invoke({"messages": [{"role": "user", "content": "say: ok"}]})
last_ai = next(
(m for m in reversed(result["messages"]) if m.type == "ai"), None
)
print("final:", last_ai.content if last_ai else "<nothing>")
If this prints a response, your setup is correct. Any failure points at the underlying ChatModel configuration; go back to langchain.md and verify that first.