跳到内容

人机协作

LangGraph 支持强大而稳定的**人机协作 (HIL)** 工作流,允许在自动化过程中的任何时点进行人工干预。这在大型语言模型 (LLM) 驱动的应用中特别有用,因为模型输出可能需要验证、纠正或额外的上下文。

有关更多信息,请参阅LangGraph 人机协作功能概述

interrupt

LangGraph 中的 interrupt 功能通过在特定节点暂停图、向人类呈现信息并根据其输入恢复图,从而实现人机协作工作流。这对于审批、编辑或收集额外上下文等任务非常有用。

该图通过提供人类响应的 Command(resume=...) 对象恢复。

interrupt 的图节点

from langgraph.types import interrupt, Command

def human_node(state: State):
    value = interrupt( # (1)!
        {
            "text_to_revise": state["some_text"] # (2)!
        }
    )
    return {
        "some_text": value # (3)!
    }
  1. interrupt(...)human_node 处暂停执行,将给定负载呈现给人类。
  2. 任何 JSON 可序列化值都可以传递给 interrupt 函数。这里是一个包含待修改文本的字典。
  3. 一旦恢复,interrupt(...) 的返回值是人类提供的输入,该输入用于更新状态。

LangGraph API 调用与恢复

from langgraph_sdk import get_client
from langgraph_sdk.schema import Command
client = get_client(url=<DEPLOYMENT_URL>)

# Using the graph deployed with the name "agent"
assistant_id = "agent"

# create a thread
thread = await client.threads.create()
thread_id = thread["thread_id"]

# Run the graph until the interrupt is hit.
result = await client.runs.wait(
    thread_id,
    assistant_id,
    input={"some_text": "original text"}   # (1)!
)

print(result['__interrupt__']) # (2)!
# > [
# >     {
# >         'value': {'text_to_revise': 'original text'},
# >         'resumable': True,
# >         'ns': ['human_node:fc722478-2f21-0578-c572-d9fc4dd07c3b'],
# >         'when': 'during'
# >     }
# > ]


# Resume the graph
print(await client.runs.wait(
    thread_id,
    assistant_id,
    command=Command(resume="Edited text")   # (3)!
))
# > {'some_text': 'Edited text'}
  1. 图以某个初始状态被调用。
  2. 当图遇到中断时,它返回一个包含负载和元数据的中断对象。
  3. 该图通过一个 Command(resume=...) 命令恢复,注入人类的输入并继续执行。
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });

// Using the graph deployed with the name "agent"
const assistantID = "agent";

// create a thread
const thread = await client.threads.create();
const threadID = thread["thread_id"];

// Run the graph until the interrupt is hit.
const result = await client.runs.wait(
  threadID,
  assistantID,
  { input: { "some_text": "original text" } }   // (1)!
);

console.log(result['__interrupt__']); // (2)!
// > [
// >     {
// >         'value': {'text_to_revise': 'original text'},
// >         'resumable': True,
// >         'ns': ['human_node:fc722478-2f21-0578-c572-d9fc4dd07c3b'],
// >         'when': 'during'
// >     }
// > ]

// Resume the graph
console.log(await client.runs.wait(
    threadID,
    assistantID,
    { command: { resume: "Edited text" }}   // (3)!
));
// > {'some_text': 'Edited text'}
  1. 图以某个初始状态被调用。
  2. 当图遇到中断时,它返回一个包含负载和元数据的中断对象。
  3. 该图通过一个 { resume: ... } 命令对象恢复,注入人类的输入并继续执行。

创建一个线程

curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'

运行图直到遇到中断。

curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
  \"assistant_id\": \"agent\",
  \"input\": {\"some_text\": \"original text\"}
}"

恢复图

curl --request POST \
 --url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
 --header 'Content-Type: application/json' \
 --data "{
   \"assistant_id\": \"agent\",
   \"command\": {
     \"resume\": \"Edited text\"
   }
 }"
扩展示例:使用 interrupt

这是一个可以在 LangGraph API 服务器中运行的示例图。有关更多详细信息,请参阅LangGraph 平台快速入门

from typing import TypedDict
import uuid

from langgraph.checkpoint.memory import InMemorySaver
from langgraph.constants import START
from langgraph.graph import StateGraph
from langgraph.types import interrupt, Command

class State(TypedDict):
    some_text: str

def human_node(state: State):
    value = interrupt( # (1)!
        {
            "text_to_revise": state["some_text"] # (2)!
        }
    )
    return {
        "some_text": value # (3)!
    }


# Build the graph
graph_builder = StateGraph(State)
graph_builder.add_node("human_node", human_node)
graph_builder.add_edge(START, "human_node")

graph = graph_builder.compile()
  1. interrupt(...)human_node 处暂停执行,将给定负载呈现给人类。
  2. 任何 JSON 可序列化值都可以传递给 interrupt 函数。这里是一个包含待修改文本的字典。
  3. 一旦恢复,interrupt(...) 的返回值是人类提供的输入,该输入用于更新状态。

一旦您拥有一个正在运行的 LangGraph API 服务器,您就可以使用 LangGraph SDK 与其交互。

from langgraph_sdk import get_client
from langgraph_sdk.schema import Command
client = get_client(url=<DEPLOYMENT_URL>)

# Using the graph deployed with the name "agent"
assistant_id = "agent"

# create a thread
thread = await client.threads.create()
thread_id = thread["thread_id"]

# Run the graph until the interrupt is hit.
result = await client.runs.wait(
    thread_id,
    assistant_id,
    input={"some_text": "original text"}   # (1)!
)

print(result['__interrupt__']) # (2)!
# > [
# >     {
# >         'value': {'text_to_revise': 'original text'},
# >         'resumable': True,
# >         'ns': ['human_node:fc722478-2f21-0578-c572-d9fc4dd07c3b'],
# >         'when': 'during'
# >     }
# > ]


# Resume the graph
print(await client.runs.wait(
    thread_id,
    assistant_id,
    command=Command(resume="Edited text")   # (3)!
))
# > {'some_text': 'Edited text'}
  1. 图以某个初始状态被调用。
  2. 当图遇到中断时,它返回一个包含负载和元数据的中断对象。
  3. 该图通过一个 Command(resume=...) 命令恢复,注入人类的输入并继续执行。
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });

// Using the graph deployed with the name "agent"
const assistantID = "agent";

// create a thread
const thread = await client.threads.create();
const threadID = thread["thread_id"];

// Run the graph until the interrupt is hit.
const result = await client.runs.wait(
  threadID,
  assistantID,
  { input: { "some_text": "original text" } }   // (1)!
);

console.log(result['__interrupt__']); // (2)!
// > [
// >     {
// >         'value': {'text_to_revise': 'original text'},
// >         'resumable': True,
// >         'ns': ['human_node:fc722478-2f21-0578-c572-d9fc4dd07c3b'],
// >         'when': 'during'
// >     }
// > ]

// Resume the graph
console.log(await client.runs.wait(
    threadID,
    assistantID,
    { command: { resume: "Edited text" }}   // (3)!
));
// > {'some_text': 'Edited text'}
  1. 图以某个初始状态被调用。
  2. 当图遇到中断时,它返回一个包含负载和元数据的中断对象。
  3. 该图通过一个 { resume: ... } 命令对象恢复,注入人类的输入并继续执行。

创建一个线程

curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'

运行图直到遇到中断

curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
  \"assistant_id\": \"agent\",
  \"input\": {\"some_text\": \"original text\"}
}"

恢复图

curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/wait \
--header 'Content-Type: application/json' \
--data "{
  \"assistant_id\": \"agent\",
  \"command\": {
    \"resume\": \"Edited text\"
  }
}"

了解更多