跳到内容

断点

断点会在特定点暂停图的执行,并允许逐步执行。断点由 LangGraph 的 持久化层 提供支持,该层在每个图步骤后保存状态。断点也可用于启用 人机环路 工作流程,但我们建议为此目的使用 interrupt 函数

要求

要使用断点,您需要

  1. 指定检查点 以在每个步骤后保存图状态。

  2. 设置断点 以指定执行应暂停的位置。

  3. 使用 线程 ID 运行图,以便在断点处暂停执行。

  4. 使用 invoke/stream 恢复执行(请参阅 Command 原语)。

设置断点

您可以在两个位置设置断点

  1. 通过在编译时运行时设置断点,在节点执行之前之后设置断点。我们称这些为 静态断点

  2. 使用 NodeInterrupt 错误在节点内部设置断点。

静态断点

静态断点在节点执行之前之后触发。您可以通过在“编译”时运行时指定 interruptBeforeinterruptAfter 来设置静态断点。

const graph = graphBuilder.compile({
    interruptBefore: ["nodeA"],
    interruptAfter: ["nodeB", "nodeC"],
    checkpointer: ..., // Specify a checkpointer
});

const threadConfig = {
    configurable: {
        thread_id: "someThread"
    }
};

// Run the graph until the breakpoint
await graph.invoke(inputs, threadConfig);

// Optionally update the graph state based on user input
await graph.updateState(update, threadConfig);

// Resume the graph
await graph.invoke(null, threadConfig);
await graph.invoke(
    inputs,
    { 
        configurable: { thread_id: "someThread" },
        interruptBefore: ["nodeA"],
        interruptAfter: ["nodeB", "nodeC"]
    }
);

const threadConfig = {
    configurable: {
        thread_id: "someThread"
    }
};

// Run the graph until the breakpoint
await graph.invoke(inputs, threadConfig);

// Optionally update the graph state based on user input
await graph.updateState(update, threadConfig);

// Resume the graph
await graph.invoke(null, threadConfig);

注意

您不能在运行时为子图设置静态断点。

如果您有子图,则必须在编译时设置断点。

如果您想单步执行图的执行,或者想在特定节点暂停图的执行,则静态断点对于调试尤其有用。

NodeInterrupt 错误

如果您尝试实现 人机环路 工作流程,我们建议您使用 interrupt 函数代替 NodeInterrupt 错误。interrupt 函数更易于使用且更灵活。

NodeInterrupt 错误

开发人员可以定义触发断点必须满足的条件。当开发人员想要在特定条件下停止图时,动态断点 的这个概念非常有用。这使用 NodeInterrupt,这是一种特殊类型的错误,可以根据某些条件从节点内部抛出。例如,我们可以定义一个动态断点,当 input 的长度超过 5 个字符时触发。

function myNode(state: typeof GraphAnnotation.State) {
    if (state.input.length > 5) {
        throw new NodeInterrupt(`Received input that is longer than 5 characters: ${state.input}`);
    }
    return state;
}

假设我们使用触发动态断点的输入运行图,然后尝试通过简单地传入 null 作为输入来恢复图的执行。

// Attempt to continue the graph execution with no change to state after we hit the dynamic breakpoint 
for await (const event of await graph.stream(null, threadConfig)) {
    console.log(event);
}

图将再次中断,因为此节点将使用相同的图状态重新运行。我们需要更改图状态,使触发动态断点的条件不再满足。因此,我们可以简单地将图状态编辑为满足动态断点条件(< 5 个字符)的输入,然后重新运行节点。

// Update the state to pass the dynamic breakpoint
await graph.updateState({ input: "foo" }, threadConfig);

for await (const event of await graph.stream(null, threadConfig)) {
    console.log(event);
}

或者,如果我们想保留当前输入并跳过执行检查的节点 (myNode) 怎么办?为此,我们可以简单地使用 "myNode"(节点名称)作为第三个位置参数执行图更新,并为值传入 null。这将不会对图状态进行任何更新,但会将更新作为 myNode 运行,从而有效地跳过该节点并绕过动态断点。

// This update will skip the node `myNode` altogether
await graph.updateState(null, threadConfig, "myNode");

for await (const event of await graph.stream(null, threadConfig)) {
    console.log(event);
}

其他资源 📚