跳转到主要内容
LANGGRAPH集成

LangGraph支付集成。

不需要LangGraph包。一个普通节点调用真实的blockchain0x客户端,interrupt()挂起,直到支付webhook到达,然后图形恢复 - 在运行之间持久。

简短答案

没有 LangGraph package,而且你也不需要。你的 中的普通 node 调用真实的 client, 会暂停 graph,直到 payment webhook 到达,而 handler 会用 LangGraph 自己的 + 恢复它。支付在 Base 上结算。

为什么 LANGGRAPH 适合这个模式

持久执行使得支付后恢复模式变得自然。

代理驱动支付的难点在于异步间隙:您请求支付,买方在几分钟后(或从未)支付,而您必须在不丢失您所在状态的情况下恢复工作。大多数代理框架依赖于作业队列 + 手动状态存储来弥补这一差距。LangGraph已经内置了原语:interrupt()在节点处挂起图形,检查点将状态持久化到磁盘。恢复只需一次调用。

这个 recipe 并不依赖特殊机制。一个普通的 pay node 调用 blockchain0x.payments.create。await_settlement node 调用 interrupt() 进入挂起状态,而 checkpointer 会持久化 state。webhook handler 验证签名,在匹配的 thread 上通过 graph.updateState 将其设为 settled,然后调用 graph.invoke 从 interrupt 继续执行。graph 会精确从上次中断的位置恢复,包括 earlier nodes 中的任何 LLM context - 全部使用 LangGraph 自身的 APIs。

安装

安装LangGraph和核心SDK。无需额外包。

Node 18+和@langchain/langgraph 0.2+以及真实的@blockchain0x/node客户端。两种语言中都没有要添加的LangGraph适配器 - Python LangGraph用户安装langgraph和blockchain0x Python客户端,并编写相同的配方,Python端使用interrupt()和Command(resume=...)。

安装
npm install @langchain/langgraph @blockchain0x/node
环境变量
export BLOCKCHAIN0X_API_KEY=sk_test_...        # sk_test_ = Base Sepolia, sk_live_ = Base mainnet
export BLOCKCHAIN0X_WEBHOOK_SECRET=...          # for the webhook handler

BLOCKCHAIN0X_API_KEY 是你 dashboard 中的 sk_test_ testnet 或 sk_live_ mainnet key;client 会从环境变量读取它。处理 webhooks 的进程还需要 BLOCKCHAIN0X_WEBHOOK_SECRET(在创建或轮换 webhook 时仅返回一次)。如果你的 graph 运行在一个进程中,而 handler 运行在另一个进程中,那么两者都需要相同的 checkpointer(例如共享的 Postgres),这样 handler 才能找到被挂起的 thread。

完整图形示例

一个三节点图:支付、暂停、交付。

下面是一个完整的 LangGraph workflow,包含 typed State、一个调用真实 blockchain0x.payments.create 的 pay node、一个基于 interrupt 的 await_settlement node,以及一个在链上确认付款已转移后执行依赖工作的 deliver node。

GRAPH.TS
import { StateGraph, START, END, MemorySaver, interrupt, Annotation } from "@langchain/langgraph";
import { createClient } from "@blockchain0x/node";

const blockchain0x = createClient({ apiKey: process.env.BLOCKCHAIN0X_API_KEY! });

const State = Annotation.Root({
  agentId: Annotation<string>(),
  to: Annotation<string>(),
  amountWei: Annotation<string>(), // USDC base units: "10000" = 0.01 USDC
  settled: Annotation<boolean>(),
});

// A plain node that calls the real SDK. No dedicated package needed.
async function pay(state: typeof State.State) {
  await blockchain0x.payments.create({
    agentId: state.agentId,
    to: state.to,
    amountWei: state.amountWei,
  });
  return {};
}

// Suspend the graph until the payment.sent webhook resumes this thread.
function awaitSettlement() {
  interrupt("awaiting on-chain settlement");
  return {};
}

async function deliver() {
  // Funds have moved - do the work that depended on the payment.
  return {};
}

const graph = new StateGraph(State)
  .addNode("pay", pay)
  .addNode("await_settlement", awaitSettlement)
  .addNode("deliver", deliver)
  .addEdge(START, "pay")
  .addEdge("pay", "await_settlement")
  .addConditionalEdges("await_settlement", (s) => (s.settled ? "deliver" : END))
  .addEdge("deliver", END)
  .compile({ checkpointer: new MemorySaver() });

When the graph runs, the pay node submits the USDC transfer through the SDK. The await_settlement node calls interrupt(), which suspends the graph and persists state via the checkpointer. The conditional edge waits to be told settled=true before routing to deliver; if settlement never lands, a timeout sweep routes it to END. amountWei is base units, so 0.01 USDC is "10000".

WEBHOOK 处理

验证 webhook,然后恢复线程。

处理程序使用 Node SDK 的 webhooks.verify 验证签名,从您自己的映射中查找挂起的 LangGraph 线程,使用 graph.updateState 设置已结算,并调用 graph.invoke(null, config) 从中断继续。没有特殊的助手 - 这些是 LangGraph 自己的 API。

WEBHOOK.TS
import express from "express";
import { webhooks } from "@blockchain0x/node";
import { graph } from "./graph";

const app = express();
// Capture the RAW body. The HMAC is over the exact bytes on the wire.
app.use(express.raw({ type: "application/json" }));

app.post("/webhooks/payment", async (req, res) => {
  const result = webhooks.verify({
    headers: req.headers,
    rawBody: req.body, // Buffer, raw bytes
    secret: process.env.BLOCKCHAIN0X_WEBHOOK_SECRET!,
  });
  if (!result.ok) return res.status(400).json({ code: result.code });

  if (result.eventType === "payment.sent") {
    // You map the event to the suspended graph thread (your own store).
    const config = { configurable: { thread_id: threadFor(result.eventId) } };
    await graph.updateState(config, { settled: true });
    await graph.invoke(null, config); // resume from the interrupt
  }
  res.status(200).send("ok");
});

webhooks.verify 对原始主体进行恒定时间的 HMAC-SHA256,并返回一个区分联合 - 在 result.ok 上分支,无需 try/catch。将 result.eventId 映射到您挂起的线程,然后 graph.updateState + graph.invoke(null, config) 从持久化的检查点恢复,图形运行交付。已发送的事件包括 payment.received、payment.sent、wallet.deployed 和 webhook.test。

源代码和文档

您正在包装的客户端是开放的。阅读它。

没有可克隆的 LangGraph starter package - 上面的 recipe 就是集成方式。blockchain0x SDK 在 GitHub 上开源;这个 recipe 封装了 Python SDK (blockchain0x-python),完整的方法表面已记录在 docs 中。可将其作为 node bodies 和 webhook verify 的参考。

github.com/tosh-labs/blockchain0x-python

完整的 SDK method surface 和 webhook signature scheme 已记录在 the docs 中。先使用 sk_test_ key 对接 Base Sepolia 进行测试,然后在 graph 按预期恢复后切换到 sk_live_。

常见陷阱

五个需要避免的 LangGraph 特定陷阱。

LangGraph的持久执行模型强大,但在检查点、中断和状态更新方面有其自身的风险。

PITFALL 1

没有 LangGraph 包 - 一个普通节点调用 SDK

Blockchain0x 为 LangChain 和 CrewAI 以及 MCP 服务器提供适配器;没有专门的 LangGraph 包,无论是在 npm 还是 pip 中。上面的配方是路径:一个普通的图节点调用真实的 @blockchain0x/node 客户端,然后你继续使用 LangGraph 自己的 graph.updateState + graph.invoke。没有特殊的支付节点类,也没有需要导入的恢复助手 - 这些从未存在过。

PITFALL 2

缺少检查点

LangGraph的interrupt()仅在图形具有检查点时有效。没有检查点时,当您的进程退出时状态会消失,Webhook处理程序没有线程可以恢复。开发时使用MemorySaver,生产中使用SqliteSaver或PostgresSaver。如果您的图形和Webhook处理程序在不同的进程中运行,它们必须共享相同的检查点(例如一个Postgres),以便处理程序可以找到挂起的线程。

PITFALL 3

将webhook映射到正确的线程是你的工作

Webhook 告诉您支付已结算;它不知道您的 LangGraph thread_id。保持您自己的映射 - 当您启动图形时,存储由代理、接收者或您设置的幂等密钥键入的 thread_id,然后在处理程序中查找它。上面的 threadFor() 调用就是该查找。如果弄错了,graph.invoke 将恢复错误的线程或根本没有线程。

PITFALL 4

处理无结算路径,或永久暂停

来自 await_settlement 的条件边缘仅在 settled 为 true 时路由以进行交付。如果支付从未到达,线程将无限期挂起。添加超时:一个计划的清理,恢复 stale 线程,settled=false,以便边缘路由到 END,或者进行 payment.sent-versus-deadline 检查。挂起的线程不花费任何费用,但它也永远不会自行完成。

PITFALL 5

金额是USDC基本单位,以字符串形式表示

payments.create takes amountWei: a string of USDC base units (6 decimals), so 0.01 USDC is "10000" and 5 USDC is "5000000". It also does not retry by default and can answer 503 until the chain adapter is wired for your network. Handle that in the pay node - route to END or a retry node on error rather than letting the graph wedge.

常见问题

三个LangGraph特定问题。

是否有LangGraph包,在npm或pip中?

不。LangGraph已经为你提供了一切:节点只是一个函数,interrupt()挂起,一个检查点持久化,graph.updateState + graph.invoke恢复。因此诚实的路径是一个普通节点,调用真实的@blockchain0x/node客户端(或Python blockchain0x客户端),如上所示。唯一发布的框架包是blockchain0x-langchain和blockchain0x-crewai(均为Python)以及@blockchain0x/mcp服务器。

我可以在 Python LangGraph 中做到这一点吗?

可以,同样的 recipe。Python LangGraph 具有相同的 primitives - function node、interrupt()、checkpointer,以及 Command(resume=...) 或 update_state + invoke 用于继续。你的 node 调用 Python blockchain0x client(blockchain0x.payments.create(...)),而 webhook handler 验证签名并恢复 thread。除了 langgraph 和 blockchain0x 之外没有其他 pip package 需要安装;graph definition 与 TypeScript 版本几乎一致。

这是否可以与 LangGraph 平台和人机协作节点一起使用?

是的。配方是普通的 LangGraph,因此它在 LangGraph 平台上运行相同 - 将您的 Blockchain0x webhook 指向部署并在此处恢复线程。interrupt() 还支持一个图中的多个中断点:由 webhook 恢复的支付中断和由 UI 操作恢复的人类审核中断可以并存,只要每个恢复都更新其在状态上的字段。图形按顺序路由。

为您的图形添加持久支付。

在支付时暂停,在webhook上恢复,全部使用LangGraph自己的API。免费开始。