Skip to main content
This article walks you through integrating LangGraph with SambaNova, from setup to real-world use cases. LangGraph provides a low-level infrastructure framework for building stateful, long-running workflows and agents.

Prerequisites

Before you begin, ensure you have:
  • A SambaCloud account with an active API key
  • Python 3.10 or higher installed. langgraph and langchain-sambanova do not support Python 3.9 or earlier.
  • A model that supports function calling, if your graph calls tools. The examples on this page use Meta-Llama-3.3-70B-Instruct, which supports it. For the full list, see Function calling and JSON mode. A tool-calling graph on a model without function-calling support never emits a tool call, so the graph returns a plain text answer and skips your tool node entirely.
macOS ships with Python 3.9 and exposes it as python3 rather than python. Check your version with python3 --version. If it is below 3.10, install a supported version with pyenv, uv, or brew install python@3.12 before continuing.

Installation and setup

  1. Create a virtual environment:
  1. Install the required libraries:
  1. Set your API key:
Each package covers a different part of the examples on this page:
The examples on this page were verified against langchain-sambanova 1.1.1, langgraph 1.2.10, and langchain 1.3.14. To reproduce that exact set, pin them: pip install langchain-sambanova==1.1.1 langchain==1.3.14 langgraph==1.2.10.

Quickstart

Instantiate a SambaCloud chat model and send your first message:
You should see an output similar to the one below.
ChatSambaNova reads your key from the SAMBANOVA_API_KEY environment variable. invoke returns an AIMessage, so response.content is the reply text. Once this prints a response, you can wire the model into a graph.

Build a graph

Add the model to a single-node graph. The MessagesState schema uses the add_messages reducer, so each node’s return value is appended to the conversation instead of replacing it:
You should see an output similar to the one below.
graph.invoke returns the final state, not a single reply. Because MessagesState accumulates, result["messages"] holds the whole conversation: your input first, the model’s AIMessage last. That is why the example reads result["messages"][-1].content rather than result.content. If you print the whole state instead, you can see the shape you are indexing into:

Add a tool and a conditional edge

A single node is not yet an agent. To let the model decide when to call a tool, bind the tools to the model, add a ToolNode that runs them, and route between the two with a conditional edge. tools_condition inspects the last message: if it contains tool calls it returns "tools", otherwise it ends the graph. The edge from tools back to model is what makes the loop, so the model sees each tool result and can call another tool or answer:
The get_exchange_rate tool above returns hardcoded rates so the example runs without a second API key. Swap in a real rates API before you rely on the numbers.
pretty_print on each message is the fastest way to confirm the loop actually ran. You should see four messages: your question, the model’s tool call, the tool result, and the final answer.
If you only see two messages, your question, then a text answer, the model did not emit a tool call. Confirm the model supports function calling, and make the tool docstring describe clearly when to use it.
You do not have to build this graph by hand. from langchain.agents import create_agent returns an equivalent compiled ReAct agent in one call. Build the graph yourself when you need to add your own nodes, custom routing, or state fields.

Persist state across turns

Each graph.invoke call starts from a fresh state, so the graph above cannot remember anything. To keep a conversation, compile with a checkpointer and pass a thread_id. The checkpointer saves state per thread, and the thread_id selects which conversation you are continuing:
You should see an output similar to the one below.
The second call sends only the new question, but the checkpointer replays the saved messages for conversation-1, so the model still has the first turn. Change thread_id to a new value and the model no longer knows the name.
InMemorySaver keeps state in the process and loses it on exit, which is what you want for local development. MemorySaver is a backwards-compatible alias for the same class. For anything you deploy, use a durable checkpointer such as PostgresSaver from langgraph-checkpoint-postgres.

Example use cases

You can use LangGraph with SambaCloud to create multi-agent workflows such as web search, Retrieval-Augmented Generation (RAG), and SQL agents. The examples below are complete, runnable versions of those patterns.
  • Agentic Search: a notebook that builds a chatbot combining a web search tool with a SambaCloud model.
  • Agentic Graph RAG: a full application, not a notebook, that answers natural-language questions over a healthcare graph database using intelligent routing and generated Cypher queries. Built with LangGraph and FastAPI, with a web interface.

Troubleshooting

macOS does not provide a python executable, only python3. Use python3 -m venv .venv to create the environment. After you activate it with source .venv/bin/activate, python works as expected inside the environment.
ChatSambaNova builds its HTTP client while the object is being constructed, so an unset SAMBANOVA_API_KEY fails on the ChatSambaNova(...) line before any request is sent. Confirm the key is visible to the process with echo $SAMBANOVA_API_KEY. An export applies only to the shell it ran in, so a new terminal or a new editor session needs it again.
The key is set but is not valid. Copy it again from the SambaCloud portal.
The virtual environment is not active. Run source .venv/bin/activate again, confirm the prompt shows (.venv), then re-run the install command from step 2.
If you omit model=, ChatSambaNova falls back to its own default, Llama-4-Maverick-17B-128E-Instruct, which SambaCloud has retired and no longer serves, so the request fails rather than quietly running on a different model. Always pass model= explicitly, using an ID from SambaCloud models.
Older tutorials import ChatSambaNovaCloud. In langchain-sambanova 1.x that name is a deprecated placeholder with no implementation: the class is decorated @deprecated(since="0.2.0", removal="1.0.0") and has an empty body. Use ChatSambaNova, which serves both SambaCloud and SambaStack and selects between them from base_url.
You called .content on the graph result. graph.invoke returns the state dictionary, not a message, so read the last message out of the state first with result["messages"][-1].content. Only llm.invoke returns an AIMessage you can read .content from directly.
You compiled the graph with a checkpointer but invoked it without a config. A checkpointer needs to know which conversation to load, so pass a thread_id on every call: graph.invoke(payload, {"configurable": {"thread_id": "conversation-1"}}). Reuse the same value to continue a conversation and use a new value to start a fresh one.
The graph kept looping without reaching END. In a tool-calling graph this usually means the model calls a tool, dislikes the result, and calls it again. Print the messages with message.pretty_print() to see what is repeating. Fix the tool so it returns a usable answer or a clear error string rather than raising, and sharpen its docstring so the model knows when it is done. Raise the ceiling only once the loop itself is correct: graph.invoke(payload, {"recursion_limit": 50}).
In langgraph-prebuilt 1.1 and later, create_react_agent is deprecated. Replace from langgraph.prebuilt import create_react_agent with from langchain.agents import create_agent and call create_agent(model, tools). ToolNode and tools_condition are not deprecated, so the hand-built graph shown above stays valid.
Two common causes. First, the model does not support function calling, so it cannot emit a tool call at all. Check it against Function calling and JSON mode. Second, you built the graph but never bound the tools, so the model does not know they exist. ToolNode(tools) only runs tool calls, it does not advertise them. You need both ToolNode(tools) in the graph and .bind_tools(tools) on the model.

Additional resources