LangGraph 20:部署上线

前言

本地写好的图要给别人用,得有服务:谁起线程、谁跑图、谁负责把 interrupt 的暂停结果吐出来。
LangGraph 把这件事包成了 LangGraph Server:项目里放一个 langgraph.json,本地 langgraph dev 就起 REST 服务;生产再换持久化与托管。
《LangGraph 16:Studio 接入》 已经讲了 langgraph dev 与浏览器 Studio 联调,本篇不重复界面操作,重点讲接口协议:线程、运行、流式、状态与 HITL resume。
示例图沿用短诗审批(《LangGraph 17:自建中断面板》 的同款图),先本地验证 REST,再配 Postgres 持久化,最后讲云上/自托管上线。
示例统一对接 火山方舟 Coding Plan,模型用 ark-code-latest
下文需要 Python 3.12+,依赖用 uv 管理。

概要

  1. 工程里写 langgraph.json:声明图入口、依赖、环境文件。
  2. langgraph dev 起本地服务,默认 http://127.0.0.1:2024
  3. REST 协议:POST /threads 建线程 → POST /threads/{id}/runs/wait 跑图 → POST /threads/{id}/runs/stream 流式 → GET /threads/{id}/state 查状态。
  4. HITL:runs/wait 里发 Command(resume=...) 续跑,协议与本地 invoke 一致。
  5. 持久化:langgraph.json 配 Postgres checkpointer;生产用 langgraph up 或自托管镜像。

依赖

建议使用 Python 3.12 及以上。

1
2
3
4
5
uv init langgraph-server
cd langgraph-server
uv venv --python 3.12
uv add "langgraph>=1.0,<2.0" "langchain>=1.0,<2.0" langchain-openai python-dotenv
uv add "langgraph-cli[inmem]"

在项目根目录创建 .env ,写入 Coding Plan 的 Key 与专用 Base URL。

1
2
OPENAI_API_KEY=你的火山方舟 API Key
OPENAI_BASE_URL=https://ark.cn-beijing.volces.com/api/coding/v3

请勿把 Base URL 写成普通方舟 .../api/v3 ,以免无法抵扣 Coding Plan 额度。
要连 Postgres 时再把 [inmem] 换成 [postgres] 或两者都装。

工程与配置

先写一张能被 Server 导入的图。沿用短诗审批:模型写两行短诗,interrupt 等人点「是 / 否」。
保存为 src/agent.py ,导出变量名必须是 graph ;另建空文件 src/__init__.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import os
from typing import TypedDict

from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
from langgraph.graph import END, START, StateGraph
from langgraph.types import interrupt

load_dotenv()

model = init_chat_model(
"openai:ark-code-latest",
temperature=0,
api_key=os.environ["OPENAI_API_KEY"],
base_url=os.environ["OPENAI_BASE_URL"],
)


class OverAllState(TypedDict):
topic: str
poem: str
approved: bool


def llm_node(state: OverAllState) -> dict:
text = model.invoke([HumanMessage(content=f"写一首关于 {state['topic']} 的两行短诗,只写诗句")]).content
return {"poem": text, "approved": False}


def review_node(state: OverAllState) -> dict:
decision = interrupt(
{
"instruction": "是否通过这首短诗?",
"poem": state["poem"],
"choices": ["是", "否"],
}
)
return {"approved": decision is True or str(decision).lower() in {"yes", "y", "true", "1", "是", "通过"}}


builder = StateGraph(state_schema=OverAllState)
builder.add_node("llm_node", llm_node)
builder.add_node("review_node", review_node)
builder.add_edge(START, "llm_node")
builder.add_edge("llm_node", "review_node")
builder.add_edge("review_node", END)

graph = builder.compile()

langgraph.json 声明图入口、依赖目录、环境文件。
路径相对项目根目录;env 指向 Coding Plan 的 .env

1
2
3
4
5
6
7
8
{
"dependencies": ["."],
"graphs": {
"agent": "./src/agent.py:graph"
},
"env": ".env",
"python_version": "3.12"
}

graphs 里的键 agent 是服务里的图名,值为「py 路径:导出变量」。
Server 会给图注入平台自己的 checkpointer,这里保持 compile() 不带参数。
先本地起服务验证接口(界面联调见 《LangGraph 16:Studio 接入》):

1
uv run langgraph dev

默认地址 http://127.0.0.1:2024 ,API 文档在 http://127.0.0.1:2024/docs
下文所有接口都对着这个地址敲。

REST 协议

建线程

线程 = 一条带 thread_id 的会话记录,图的状态都挂在它下面。

1
2
3
curl -X POST http://127.0.0.1:2024/threads \
-H 'Content-Type: application/json' \
-d '{"metadata": {}}'

响应里有 thread_id ,下面记作 THREAD_ID

跑图并等待结果

runs/wait 同步执行,跑完才返回。输入里传 topic 作为初始状态。

1
2
3
curl -X POST http://127.0.0.1:2024/threads/THREAD_ID/runs/wait \
-H 'Content-Type: application/json' \
-d '{"input": {"topic": "橘猫"}}'

图会在 review_node 暂停,响应 values 里有 __interrupt__ 数组,含 idvalueinstructionpoemchoices)。

续跑(HITL resume)

暂停后在同一线程发 Command(resume=...) 。协议与本地 Command(resume=True) 一致,序列化时包一层 Command 键。

1
2
3
curl -X POST http://127.0.0.1:2024/threads/THREAD_ID/runs/wait \
-H 'Content-Type: application/json' \
-d '{"input": {"Command": {"resume": true}}}'

返回 approved: true 与定稿状态。
多个中断时 resume 用 {"resume": {"id": 值}},规则与 《LangGraph 11:HITL 人机协同》 相同。

查状态

GET /threads/{id}/state 返回当前快照,联调时最常用。

1
curl http://127.0.0.1:2024/threads/THREAD_ID/state

异步运行与取消

不阻塞的 POST /threads/{id}/runs 返回 run_id,再用 GET /threads/{id}/runs/{run_id}/wait 等结果;要停就发取消。

1
2
3
4
5
curl -X POST http://127.0.0.1:2024/threads/THREAD_ID/runs \
-H 'Content-Type: application/json' \
-d '{"input": {"topic": "夜雨"}}'

curl -X POST http://127.0.0.1:2024/threads/THREAD_ID/runs/RUN_ID/cancel

流式

runs/stream 走 SSE,逐条吐事件。stream_mode 与本地 stream 对应:valuesupdatescustom

1
2
3
curl -N -X POST http://127.0.0.1:2024/threads/THREAD_ID/runs/stream \
-H 'Content-Type: application/json' \
-d '{"input": {"topic": "橘猫"}, "stream_mode": ["values", "updates"]}'

每行是 event: ... / data: {...} 的 SSE 消息。
前端接 SSE 渲染增量即可,协议与 《LangGraph 13:流式输出》 的 stream_mode 一一对应。

持久化

内存 checkpointer 重启即失。生产给 langgraph.jsoncheckpointer 段,让 Server 用 Postgres 落库。
先在本地起一个 Postgres(可用 Docker):

1
2
3
docker run -d --name lg-pg \
-e POSTGRES_USER=langgraph -e POSTGRES_PASSWORD=langgraph \
-e POSTGRES_DB=langgraph -p 5432:5432 postgres:16

再在 langgraph.json 里声明 Postgres checkpointer(连接串建议走环境变量,字段结构以你所装版本文档为准):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"dependencies": ["."],
"graphs": {
"agent": "./src/agent.py:graph"
},
"env": ".env",
"python_version": "3.12",
"checkpointer": {
"type": "postgres",
"module": "langgraph.checkpoint.postgres",
"config": {
"postgres_uri": "postgresql://langgraph:langgraph@localhost:5432/langgraph"
}
}
}

重启 langgraph dev 后,线程与状态都落在 Postgres,进程重启也能续跑。
应用里也可以直接用官方 Python 客户端 langgraph-sdk,把上面的 REST 调用包成 client.threads.getclient.runs.stream 等一行方法。

上线

协议不变,只换运行环境。

  1. LangGraph Cloud:登录后直接推送,Server 自动托管。

    1
    2
    langgraph auth login
    langgraph up
  2. 自托管:用官方镜像构建并跑服务,前端反代即可。

    1
    2
    langgraph build -t my-agent
    docker run -p 8123:8000 -e POSTGRES_URI=... -e OPENAI_API_KEY=... my-agent

    镜像内部仍是同一套 REST 协议,前端把 Base URL 换成线上地址即可。
    上线前记得把 InMemorySaver 换成 Postgres、langgraph.jsonenv 指到生产环境变量。

总结

  1. langgraph.json 声明 graphs 入口;给 Server 的图只 compile(),不要自带 InMemorySaver
  2. 核心接口:建线程、runs/wait 跑图、runs/stream 流式、state 查状态、runs/{id}/cancel 取消。
  3. HITL 走 Command.resume,序列化为 {"Command": {"resume": ...}},协议与本地一致。
  4. 持久化在 langgraph.json 配 Postgres checkpointer;生产用 langgraph up 或自托管镜像。
  5. 客户端可用 langgraph-sdk,把 REST 包成一行方法。