Five core components, SDK call chain, local development process, and how to use a unified interface to seamlessly switch between local and cloud.
In the previous lectures, we built Simple Graph, Chain, Router, and Agent, all of which were passed in Jupyter Notebookgraph.invoke()Synchronous call. This is no problem in the learning stage, but you will encounter several serious problems in the production environment:
| question | Limitations of invoke() | LangGraph deployment system solution |
|---|---|---|
| blocking | invoke()It is synchronous. When the Agent runs for several minutes, the caller will wait |
LangGraph API provides an asynchronous task queue, the caller returns immediately, and the results are pushed through streaming |
| persistence | Requires manual configurationMemorySaver, and is only valid within a single process |
LangGraph API has a built-in persistence layer that maintains Thread State across processes and restarts. |
| accessibility | Can only be called from Python within the same process | HTTP API + SDK, can be called in any language and anywhere |
| Observability | Operation process is opaque | LangSmith monitors and tracks input and output at every step |
Understand the LangGraph deployment systemfive components, andThree core concepts of SDK(Assistant/Thread/Run). Mastering these, you can move the locally debugged Agent to the cloud with one click while maintaining the same calling code.
The LangGraph deployment system consists of five components, and their hierarchical relationship is as follows: from the lowest Python/JS library, to the API server, to three different access/hosting methods.
| components | essence | what do you use it for |
|---|---|---|
| LangGraph (library) | pip install langgraph Python/JS library |
Define StateGraph, add nodes and edges, this is where you write business logic |
| LangGraph API | HTTP server Can run locally/on the cloud |
Wrap your graph into a service that can be called remotely, providing persistence and queues |
| LangSmith Studio (formerly LangGraph Studio) |
Browser IDE | Visually view the structure of the graph, manually test the input, and observe the state changes at each step. |
| LangSmith Deployment (formerly LangGraph Cloud) |
Managed cloud services | Deploy with one click on the LangSmith platform, get a unique URL, and host the LangGraph API |
| LangGraph SDK | pip install langgraph-sdk Python client |
Call the graph programmatically in code (create Thread, initiate Run, obtain Stream) |
The LangGraph ecosystem is being deeply integrated with LangSmith. Originally calledLangGraph CloudThe cloud service is now calledLangSmith Deployment; originally calledLangGraph StudioThe IDE is now calledLangSmith Studio. The functions are essentially the same, but the branding is unified.
This is a key issue in understanding the entire deployment system. Use directlyinvoke()Isn't it simpler? Let's compare the two ways:
# 直接 invoke —— 简单,但在生产环境有严重问题
result = graph.invoke({"messages": [HumanMessage("帮我研究量子计算的最新进展")]})
# ^ 这里会阻塞 5~10 分钟,直到 Agent 完成所有工具调用
# Web 服务器的请求会超时,用户体验极差
The client returns run_id immediately after initiating the request without blocking. The API executes the graph asynchronously in the background, and the results are pushed to the listener through streaming. Suitable for long-running Agents.
API automatically providesThreadMaintain snapshots of state across interactions. No manual configuration requiredMemorySaver, restarting the service will not lose the conversation history. This is the underlying foundation of Memory in Module 2.
Regardless of whether the graph is run locally (langgraph dev) or the cloud (LangSmith Deployment), all exposed through the same HTTP API. The SDK encapsulates these HTTP calls and allows you to access them elegantly with Python.
# 通过 API 的异步方式 —— 立即返回,streaming 获取结果
async for chunk in client.runs.stream(thread_id, "agent", input=input):
# 每个图步骤完成后立即收到更新,不阻塞
print(chunk.data)
Before deploying the Agent to the cloud, you need to start the LangGraph API server locally so that you can use Studio for visual debugging and use the SDK for integration testing.
Each module has astudio/subdirectory, which is the root directory of the LangGraph API server. The structure is as follows:
// module-1/studio/langgraph.json
{
"dependencies": ["."], // 依赖当前目录(读取 requirements.txt)
"graphs": {
"agent": "./agent.py:graph", // 注册图:graph_id → 文件:变量名
"router": "./router.py:graph" // 可以注册多个图
},
"env": ".env" // 环境变量文件路径
}
langgraph.jsonofgraphsIn the field, the key name (such as"agent") isgraph_id. SDK callruns.stream()The second parameter passed in is this id. When registering multiple graphs, each has its own id.
# 在 studio/ 目录下运行
$ langgraph dev
# 成功启动后输出:
🚀 API: http://127.0.0.1:2024
🎨 Studio UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
Note that the Studio URL has parameters?baseUrl=http://127.0.0.1:2024. This means that Studio is a front-end application that runs on the LangSmith server, using thebaseUrlconnect youlocal machineAPI. Your graph code never leaves local - Studio is just a visual frontend.
LangGraph SDK(pip install langgraph-sdk) is a Python client library that lets you interact with the LangGraph API from code. The core entrance isget_client():
from langgraph_sdk import get_client
# 连接本地开发服务器
URL = "http://127.0.0.1:2024"
client = get_client(url=URL)
# 连接云端部署(切换一行代码即可)
# URL = "https://your-deployment-xxxx.us.langgraph.app"
# client = get_client(url=URL, api_key="lsv2_...")
clientIt is the operation entrance of the entire SDK, through which all resources are accessed:
from langgraph_sdk import get_client
from langchain_core.messages import HumanMessage
# 1. 建立连接
URL = "http://127.0.0.1:2024"
client = get_client(url=URL)
# 2. 查看已注册的图(对应 langgraph.json 里的 graphs)
assistants = await client.assistants.search()
print(assistants)
# [{'assistant_id': '...', 'graph_id': 'agent', ...},
# {'assistant_id': '...', 'graph_id': 'router', ...}]
# 3. 创建一个对话线程(对应一个持久化的 State 容器)
thread = await client.threads.create()
print(thread['thread_id']) # 类似 UUID 的字符串
# 4. 在这个线程上发起流式运行
input = {"messages": [HumanMessage(content="Multiply 3 by 2.")]}
async for chunk in client.runs.stream(
thread['thread_id'], # 线程 ID
"agent", # graph_id(对应 langgraph.json 中的键)
input=input,
stream_mode="values", # 每步后返回完整 State
):
if chunk.data and chunk.event != "metadata":
print(chunk.data['messages'][-1])
Understanding these three concepts is the basis for making good use of the SDK. They are the resource model of LangGraph API, similar to the three tables in the database.
Corresponds to oneRegistered pictures(graph_id). It can be understood as a "configuration instance" of the graph, which can have different versions or different system prompt words, but the underlying structure shares the same graph structure.
every timelanggraph devAfter starting,langgraph.jsonEach picture in it will automatically generate an Assistant.
Corresponds to onePersistent conversation sessions. There is only onethread_id, sharing the same State across multiple Runs.
Analogy: Thread is like a chat window in WeChat - every message (Run) is accumulated in the same context.
CorrespondA specific graph run. On a Thread, calling an Assistant with specific input generates a Run.
Run can stream (streaming) or wait (wait for completion). The results of each Run are automatically written back to the Thread's State.
| concept | analogy | Key attributes | life cycle |
|---|---|---|---|
| Assistant | A configured Agent service | assistant_id、graph_id |
Exists with the service and is valid for a long time |
| Thread | A conversation session/chat window | thread_id, State snapshot |
Manually created, can span multiple Runs |
| Run | A "send message" action | run_id, status, output chunks |
Single execution, ends after completion |
There can be multiple Runs in a Thread, and the State after each Run ends will be persisted. The next time Run starts, it will continue from the last ended State (this is the implementation principle of Memory). If you want to start a completely new conversation, you need to create a new Thread, not a new Run.
client.runs.stream()Returns an asynchronous iterator, each iteration gets achunkobject.chunkThere are two key fields:chunk.eventandchunk.data。
chunk.datacontainsrun_id. Usually skipped (chunk.event != "metadata")。chunk.dataIt is the complete State dictionary, such as{"messages": [...]}。chunk.datais empty. You can stop monitoring after receiving it.| stream_mode | Content pushed each time | Applicable scenarios |
|---|---|---|
"values" |
After each step is executed, pushComplete current State(includes all fields) | Need to display the complete conversation history and monitor the overall status |
"updates" |
After each step is executed, only pushState changes in this step(delta) | Reduce the amount of data transferred and only care about new content |
"messages" |
When LLM generates tokenToken by tokenPush (typing effect similar to ChatGPT) | Requires streaming display of LLM text output |
"debug" |
Detailed debugging information, pushed for every internal event | In-depth debugging and troubleshooting |
# chunk.event == "values" 时,chunk.data 就是完整 State:
chunk.data = {
"messages": [
HumanMessage(content="Multiply 3 by 2."),
AIMessage(content="", tool_calls=[{
"name": "multiply",
"args": {"a": 3, "b": 2}
}]),
ToolMessage(content="6"),
AIMessage(content="3 multiplied by 2 equals 6.")
]
}
# 每步执行后都会收到一次这样的 chunk,messages 列表逐步增长
# 所以用 chunk.data['messages'][-1] 只看最新的消息
use stream_mode="values", a complete State will be received at each step, and the message list will grow cumulatively. usechunk.data['messages'][-1]Get the latest news withchunk.event != "metadata"Filter out metadata frames, this is the most common processing mode.
The most important design concept of LangGraph SDK isLocal development and cloud production use the exact same API. The only difference is the URL and authentication key when connecting.
from langgraph_sdk import get_client
# 本地:只需 URL
client = get_client(
url="http://127.0.0.1:2024"
)
# 以下代码完全相同 ↓
thread = await client.threads.create()
async for chunk in client.runs.stream(
thread['thread_id'],
"agent",
input=input,
stream_mode="values",
):
...
from langgraph_sdk import get_client
# 云端:URL + API Key
client = get_client(
url="https://xxx.us.langgraph.app",
api_key="lsv2_pt_..."
)
# 以下代码完全相同 ↓
thread = await client.threads.create()
async for chunk in client.runs.stream(
thread['thread_id'],
"agent",
input=input,
stream_mode="values",
):
...
You can use it locallylanggraph devAfter development and debugging, after the code is written, you can switch to the cloud production environment by changing only one line of URL. All business logic code does not need to be modified. This is the essence of deployment system design.
| Dimensions | Local (langgraph dev) | Cloud (LangSmith Deployment) |
|---|---|---|
| URL format | http://127.0.0.1:2024 |
https://xxx.us.langgraph.app |
| Certification | No need (local development) | needapi_key(LangSmith API Key) |
| Code source | Local file system, modifications take effect immediately | GitHub repository, trigger deployment after push |
| persistence | Memory or local SQLite, will be lost on restart | Cloud persistent storage, permanent storage |
| Studio access | Requires local service to be running | Accessible at any time, no local environment required |
| SDK calling code | exactly the same(Only the URL and api_key are different) | |
After your Agent passes the local test, you can deploy it to the LangSmith cloud to obtain a stable online service address.
Push the project to GitHub. ensurestudio/Directory containslanggraph.json, graph definition file andrequirements.txt。Don'tput.envFile commit goes in.
Loginsmith.langchain.com, enter the Deployments page, click "New Deployment".
Connect to your GitHub account, select the warehouse, and specifylanggraph.jsonpath (such asmodule-1/studio/langgraph.json). The platform will automatically read the graph configuration.
Fill in the deployment interfaceOPENAI_API_KEYand other environment variables. This is equivalent to the cloud.envDocuments, securely stored on the LangSmith platform.
The platform automatically pulls code, builds the environment, and starts services. After completion, you will get a unique URL with a similar formathttps://xxx.us.langgraph.app. Replace the URL in the SDK with this URLhttp://127.0.0.1:2024That’s it.
Each Deployment has an independent and stable URL that will not change due to redeployment. LangSmith supports multiple parallel Deployments (such as staging, production), each environment has its own URL.
Connect all the knowledge points together and take a look at a complete LangGraph development to deployment process:
existstudio/agent.pyDefinitionStateGraph, add nodes and edges, and compile asgraphobject. This is the content of the first five lectures of Module 1.
Give the picture a name in the configuration filegraph_id(such as"agent"), pointing toagent.pyinsidegraphvariables.
Visually debug graphs in the browser and use Studio to manually test various inputs to ensure the graph behaves as expected.
Write Python code, connect to the local API through the SDK, and test Thread creation, Run initiation, and streaming reception. Confirm that the code logic is correct.
Push the code to GitHub, create a Deployment in LangSmith, and obtain the cloud URL. Only the URL and api_key are changed in the SDK code, and the rest of the business logic remains completely unchanged.
The core design of LangGraph deployment system isLayered decoupling: You are only responsible for writing graph logic (LangGraph library), LangGraph API is responsible for turning it into an accessible service, SDK is responsible for providing a unified access interface, Studio is responsible for visual debugging, and LangSmith Deployment is responsible for cloud hosting. Each layer has clear responsibilities and can be replaced independently, which greatly improves the Agent development experience.
| Knowledge points | What to remember |
|---|---|
| Start local service | langgraph dev, run in the studio/ directory |
| Local API address | http://127.0.0.1:2024 |
| Where to register pictures | langgraph.jsonofgraphsField, the key name is graph_id |
| SDK entrance | from langgraph_sdk import get_client |
| Three major resources | Assistants (graph instances) / Threads (dialog sessions) / Runs (single executions) |
| stream_mode recommended | "values": Return the complete State after each step, use[-1]Get the latest news |
| Skip metadata frame | chunk.event != "metadata"andchunk.dataNot empty |
| Switch to the cloud | Only changeurlandapi_key, the business code remains unchanged |