Langgraph Command 的妙用
场景
做了一个支付的 Agent :
主要功能是用户选产品、下单、付款、交付的一系列功能。
环节:
用户与 Agent 交互后创建订单环节,
通过 interrupt 返回订单信息,等待用户支付,支付消息(data)通过回调返回,agent 在此暂停等待回调数据;
用户输入了信息,继续正常对话;
收到回调则去交付相关产品信息
问题在于:
用户继续聊天后支付了,回调需要走到支付信息对应的 interrupt 的节点,去执行对应的流程
解决方法
我一开始想到是的 checkpoint 恢复,后来发现恢复就是再跑一次,传参进去压根没啥影响
command 我一直用,我以为必须要先触发 interrupt 才能去 resume
后面我直接尝试都传,嘿,您瞧怎么着,真行嘿
关键代码:
Command(
goto="interrupt_node", # 直接去对应的节点
resume={"data": "我付完款了,哥们,真不赖!"} # 带上 resume 这样就不会 interrupt 了, 会按照顺序执行了
)
直接看代码吧!
代码
from pprint import pprint
from langchain_core.language_models import FakeListChatModel
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.types import interrupt, Command
class State(MessagesState):
interrupt: int
chat: int
def mock_llm(state: State):
return {"messages": [{"role": "ai", "content": "下单成功,请支付..."}]}
def interrupt_node(state: State):
payload = interrupt("订单创建完成,等待哥们你的支付...")
data = payload.get("data") # 支付回调
message = payload.get("message") # 用户继续沟通
if data:
return Command(
goto="data_node",
update={
"interrupt": state.get("interrupt", 0) + 1,
"messages": [{"role": "ai", "content": data}]
}
)
if message:
return {
"chat": state.get("chat", 0) + 1,
"messages": [
{"role": "human", "content": message},
{"role": "ai", "content": "包有的,哥们!"}
]
}
# Error
return {"messages": [{"role": "human", "content": "不是哥们,传参呢?胡闹!"}, ]}
def data_node(state: State):
fake_message = FakeListChatModel(responses=["哥们已经在 🫵 给你发货了"]).invoke("")
return {"messages": [fake_message]}
graph = StateGraph(State)
graph.add_node(mock_llm)
graph.add_node(interrupt_node)
graph.add_node(data_node)
graph.add_edge(START, "mock_llm")
graph.add_edge("mock_llm", "interrupt_node")
graph.add_edge("interrupt_node", END)
graph.add_edge("data_node", END)
checkpointer = InMemorySaver()
graph = graph.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "1"}}
for model, value in graph.stream(
{"messages": [{"role": "user", "content": "哥们,我来买一张方大同的黑胶唱片"}]},
stream_mode=["updates", "checkpoints"],
config=config
):
print("*" * 100)
print("model: ", model)
print("value: ")
pprint(value, sort_dicts=False, width=40)
print()
print("=" * 100)
print("state: ", graph.get_state(config=config))
print()
# 恢复中断
for model, value in graph.stream(
Command(resume={"message": "你真有啊?"}),
stream_mode=["updates", "checkpoints"],
config=config
):
print("*" * 100)
print("model: ", model)
print("value: ")
pprint(value, sort_dicts=False, width=40)
print()
print("=" * 100)
print("state: ", graph.get_state(config=config))
print()
for model, value in graph.stream(
Command(
goto="interrupt_node",
resume={"data": "我付完款了,哥们,真不赖!"}
),
stream_mode=["updates", "checkpoints"],
config=config
):
print("*" * 100)
print("model: ", model)
print("value: ")
pprint(value, sort_dicts=False, width=40)
print()
输出:
****************************************************************************************************
model: checkpoints
value:
{'config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c2b-68ee-bfff-e57d121d9c93'}},
'parent_config': None,
'values': {'messages': []},
'metadata': {'source': 'input',
'step': -1,
'parents': {}},
'next': ['__start__'],
'tasks': [{'id': '03ce38ff-7777-e58f-3803-d697e595fe8d',
'name': '__start__',
'interrupts': (),
'state': None}]}
****************************************************************************************************
model: checkpoints
value:
{'config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c2d-640a-8000-4458b9da1ba0'}},
'parent_config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c2b-68ee-bfff-e57d121d9c93'}},
'values': {'messages': [HumanMessage(content='哥们,我来买一张方大同的黑胶唱片', additional_kwargs={}, response_metadata={}, id='543ef59c-4258-415f-be19-2ace2f1fc3c5')]},
'metadata': {'source': 'loop',
'step': 0,
'parents': {}},
'next': ['mock_llm'],
'tasks': [{'id': '7e2a12db-50d7-7328-4344-7cef5ad24630',
'name': 'mock_llm',
'interrupts': (),
'state': None}]}
****************************************************************************************************
model: updates
value:
{'mock_llm': {'messages': [{'role': 'ai',
'content': '下单成功,请支付...'}]}}
****************************************************************************************************
model: checkpoints
value:
{'config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c2e-644a-8001-b7a54ac1e594'}},
'parent_config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c2d-640a-8000-4458b9da1ba0'}},
'values': {'messages': [HumanMessage(content='哥们,我来买一张方大同的黑胶唱片', additional_kwargs={}, response_metadata={}, id='543ef59c-4258-415f-be19-2ace2f1fc3c5'),
AIMessage(content='下单成功,请支付...', additional_kwargs={}, response_metadata={}, id='4536ca70-bce2-4e75-8aa4-12882baa369b')]},
'metadata': {'source': 'loop',
'step': 1,
'parents': {}},
'next': ['interrupt_node'],
'tasks': [{'id': '2ff3e45a-a474-fb08-a15d-631aac7ea187',
'name': 'interrupt_node',
'interrupts': (),
'state': None}]}
****************************************************************************************************
model: updates
value:
{'__interrupt__': (Interrupt(value='订单创建完成,等待哥们你的支付...',
id='b63ac8c675718737076485b99fa18474'),)}
====================================================================================================
state: StateSnapshot(values={'messages': [HumanMessage(content='哥们,我来买一张方大同的黑胶唱片', additional_kwargs={}, response_metadata={}, id='543ef59c-4258-415f-be19-2ace2f1fc3c5'), AIMessage(content='下单成功,请支付...', additional_kwargs={}, response_metadata={}, id='4536ca70-bce2-4e75-8aa4-12882baa369b')]}, next=('interrupt_node',), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f0c9f18-3c2e-644a-8001-b7a54ac1e594'}}, metadata={'source': 'loop', 'step': 1, 'parents': {}}, created_at='2025-11-25T11:25:58.337438+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f0c9f18-3c2d-640a-8000-4458b9da1ba0'}}, tasks=(PregelTask(id='2ff3e45a-a474-fb08-a15d-631aac7ea187', name='interrupt_node', path=('__pregel_pull', 'interrupt_node'), error=None, interrupts=(Interrupt(value='订单创建完成,等待哥们你的支付...', id='b63ac8c675718737076485b99fa18474'),), state=None, result=None),), interrupts=(Interrupt(value='订单创建完成,等待哥们你的支付...', id='b63ac8c675718737076485b99fa18474'),))
****************************************************************************************************
model: checkpoints
value:
{'config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c2e-644a-8001-b7a54ac1e594'}},
'parent_config': {'configurable': {'thread_id': '1',
'checkpoint_ns': '',
'checkpoint_id': '1f0c9f18-3c2d-640a-8000-4458b9da1ba0'}},
'values': {'messages': [HumanMessage(content='哥们,我来买一张方大同的黑胶唱片', additional_kwargs={}, response_metadata={}, id='543ef59c-4258-415f-be19-2ace2f1fc3c5'),
AIMessage(content='下单成功,请支付...', additional_kwargs={}, response_metadata={}, id='4536ca70-bce2-4e75-8aa4-12882baa369b')]},
'metadata': {'source': 'loop',
'step': 1,
'parents': {}},
'next': ['interrupt_node'],
'tasks': [{'id': '2ff3e45a-a474-fb08-a15d-631aac7ea187',
'name': 'interrupt_node',
'interrupts': ({'value': '订单创建完成,等待哥们你的支付...',
'id': 'b63ac8c675718737076485b99fa18474'},),
'state': None}]}
****************************************************************************************************
model: updates
value:
{'interrupt_node': {'chat': 1,
'messages': [{'role': 'human',
'content': '你真有啊?'},
{'role': 'ai',
'content': '包有的,哥们!'}]}}
****************************************************************************************************
model: checkpoints
value:
{'config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c31-685c-8002-6a11cc8bc171'}},
'parent_config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c2e-644a-8001-b7a54ac1e594'}},
'values': {'messages': [HumanMessage(content='哥们,我来买一张方大同的黑胶唱片', additional_kwargs={}, response_metadata={}, id='543ef59c-4258-415f-be19-2ace2f1fc3c5'),
AIMessage(content='下单成功,请支付...', additional_kwargs={}, response_metadata={}, id='4536ca70-bce2-4e75-8aa4-12882baa369b'),
HumanMessage(content='你真有啊?', additional_kwargs={}, response_metadata={}, id='ae1bf489-b931-47b0-8f36-aa6801677cbf'),
AIMessage(content='包有的,哥们!', additional_kwargs={}, response_metadata={}, id='d6a22cfc-754d-474d-9678-7bbd321d4a75')],
'chat': 1},
'metadata': {'source': 'loop',
'step': 2,
'parents': {}},
'next': [],
'tasks': []}
====================================================================================================
state: StateSnapshot(values={'messages': [HumanMessage(content='哥们,我来买一张方大同的黑胶唱片', additional_kwargs={}, response_metadata={}, id='543ef59c-4258-415f-be19-2ace2f1fc3c5'), AIMessage(content='下单成功,请支付...', additional_kwargs={}, response_metadata={}, id='4536ca70-bce2-4e75-8aa4-12882baa369b'), HumanMessage(content='你真有啊?', additional_kwargs={}, response_metadata={}, id='ae1bf489-b931-47b0-8f36-aa6801677cbf'), AIMessage(content='包有的,哥们!', additional_kwargs={}, response_metadata={}, id='d6a22cfc-754d-474d-9678-7bbd321d4a75')], 'chat': 1}, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f0c9f18-3c31-685c-8002-6a11cc8bc171'}}, metadata={'source': 'loop', 'step': 2, 'parents': {}}, created_at='2025-11-25T11:25:58.338770+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f0c9f18-3c2e-644a-8001-b7a54ac1e594'}}, tasks=(), interrupts=())
****************************************************************************************************
model: checkpoints
value:
{'config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c31-685c-8002-6a11cc8bc171'}},
'parent_config': {'configurable': {'thread_id': '1',
'checkpoint_ns': '',
'checkpoint_id': '1f0c9f18-3c2e-644a-8001-b7a54ac1e594'}},
'values': {'messages': [HumanMessage(content='哥们,我来买一张方大同的黑胶唱片', additional_kwargs={}, response_metadata={}, id='543ef59c-4258-415f-be19-2ace2f1fc3c5'),
AIMessage(content='下单成功,请支付...', additional_kwargs={}, response_metadata={}, id='4536ca70-bce2-4e75-8aa4-12882baa369b'),
HumanMessage(content='你真有啊?', additional_kwargs={}, response_metadata={}, id='ae1bf489-b931-47b0-8f36-aa6801677cbf'),
AIMessage(content='包有的,哥们!', additional_kwargs={}, response_metadata={}, id='d6a22cfc-754d-474d-9678-7bbd321d4a75')],
'chat': 1},
'metadata': {'source': 'loop',
'step': 2,
'parents': {}},
'next': ['interrupt_node'],
'tasks': [{'id': '672d0452-4f2d-cf6b-5499-3fb9c79845b8',
'name': 'interrupt_node',
'interrupts': (),
'state': None}]}
****************************************************************************************************
model: updates
value:
{'interrupt_node': {'interrupt': 1,
'messages': [{'role': 'ai',
'content': '我付完款了,哥们,真不赖!'}]}}
****************************************************************************************************
model: checkpoints
value:
{'config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c34-64da-8003-a7facb4cab51'}},
'parent_config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c31-685c-8002-6a11cc8bc171'}},
'values': {'messages': [HumanMessage(content='哥们,我来买一张方大同的黑胶唱片', additional_kwargs={}, response_metadata={}, id='543ef59c-4258-415f-be19-2ace2f1fc3c5'),
AIMessage(content='下单成功,请支付...', additional_kwargs={}, response_metadata={}, id='4536ca70-bce2-4e75-8aa4-12882baa369b'),
HumanMessage(content='你真有啊?', additional_kwargs={}, response_metadata={}, id='ae1bf489-b931-47b0-8f36-aa6801677cbf'),
AIMessage(content='包有的,哥们!', additional_kwargs={}, response_metadata={}, id='d6a22cfc-754d-474d-9678-7bbd321d4a75'),
AIMessage(content='我付完款了,哥们,真不赖!', additional_kwargs={}, response_metadata={}, id='d3797fd1-c200-45dc-b19a-b92ef187f06e')],
'interrupt': 1,
'chat': 1},
'metadata': {'source': 'loop',
'step': 3,
'parents': {}},
'next': ['data_node'],
'tasks': [{'id': '07eb0f07-5c1f-58f5-e985-33092ee626a9',
'name': 'data_node',
'interrupts': (),
'state': None}]}
****************************************************************************************************
model: updates
value:
{'data_node': {'messages': [AIMessage(content='哥们已经在 🫵 给你发货了', additional_kwargs={}, response_metadata={}, id='run--50c0d268-00c9-4c7f-b076-663988e10803-0')]}}
****************************************************************************************************
model: checkpoints
value:
{'config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c36-6212-8004-acae72ab008d'}},
'parent_config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0c9f18-3c34-64da-8003-a7facb4cab51'}},
'values': {'messages': [HumanMessage(content='哥们,我来买一张方大同的黑胶唱片', additional_kwargs={}, response_metadata={}, id='543ef59c-4258-415f-be19-2ace2f1fc3c5'),
AIMessage(content='下单成功,请支付...', additional_kwargs={}, response_metadata={}, id='4536ca70-bce2-4e75-8aa4-12882baa369b'),
HumanMessage(content='你真有啊?', additional_kwargs={}, response_metadata={}, id='ae1bf489-b931-47b0-8f36-aa6801677cbf'),
AIMessage(content='包有的,哥们!', additional_kwargs={}, response_metadata={}, id='d6a22cfc-754d-474d-9678-7bbd321d4a75'),
AIMessage(content='我付完款了,哥们,真不赖!', additional_kwargs={}, response_metadata={}, id='d3797fd1-c200-45dc-b19a-b92ef187f06e'),
AIMessage(content='哥们已经在 🫵 给你发货了', additional_kwargs={}, response_metadata={}, id='run--50c0d268-00c9-4c7f-b076-663988e10803-0')],
'interrupt': 1,
'chat': 1},
'metadata': {'source': 'loop',
'step': 4,
'parents': {}},
'next': [],
'tasks': []}
问题
如果已经有了一个中断 Interrupt ,那么 command 跳转后执行就会出现问题
具体看代码吧
提了一个 issue
from pprint import pprint
from langchain_core.language_models import FakeListChatModel
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.types import interrupt, Command
class State(MessagesState):
interrupt: int
chat: int
def payment_interrupt_node(state: State):
message_list = []
fake_message = FakeListChatModel(responses=["Order creation successful!"]).invoke("")
message_list.append(fake_message)
payload = interrupt("Payment Link...")
data = payload.get("data") # payment data
message = payload.get("message") # human message
if data:
message_list.append({"role": "ai", "content": data})
return Command(
goto="delivery",
update={
"interrupt": state.get("interrupt", 0) + 1,
"messages": message_list
}
)
if message:
message_list.append({"role": "human", "content": message})
if message == "normal conversation":
message_list.append({"role": "ai", "content": "relpy message"})
return {
"chat": state.get("chat", 0) + 1,
"messages": message_list
}
message_list.append({"role": "ai", "content": "some interrupt"})
return Command(
goto="another_interrupt_node",
update={
"chat": state.get("chat", 0) + 1,
"messages": message_list
}
)
# Error
message_list.append({"role": "ai", "content": "Error!!!"})
return {"messages": message_list}
def delivery(state: State):
return {"messages": [{"role": "ai", "content": "Delivery message."}]}
def another_interrupt_node(state: State):
# ...
payload = interrupt("Send another interrupt(for some reason)")
return {"messages": [
{"role": "human", "content": str(payload)},
{"role": "ai", "content": "never mind"},
]}
# build graph
graph = StateGraph(State)
graph.add_node(payment_interrupt_node)
graph.add_node(delivery)
graph.add_node(another_interrupt_node)
graph.add_edge(START, "payment_interrupt_node")
graph.add_edge("another_interrupt_node", END)
graph.add_edge("delivery", END)
checkpointer = InMemorySaver()
graph = graph.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "1"}}
# create order and need payment
for model, value in graph.stream(
{"messages": [{"role": "user", "content": "buy something"}]},
stream_mode=["messages", "updates", "checkpoints"],
config=config,
debug=True,
):
pass
# print("model: ", model)
# print("value: ")
# pprint(value, sort_dicts=False, width=40)
print("+" * 100)
################################ Case: Pay Now ##########################################
# #
# # There is no problem with this case, so let's ignore it
# for model, value in graph.stream(
# Command(resume={"data": "pay success"}),
# stream_mode=["messages", "updates", "checkpoints"],
# config=config,
# debug=True,
# ):
# pass
# # print("model: ", model)
# # print("value: ")
# # pprint(value, sort_dicts=False, width=40)
################################ Case: Pay Later (without interrupt) ##########################################
# for model, value in graph.stream(
# Command(resume={"message": "normal conversation"}),
# stream_mode=["messages", "updates", "checkpoints"],
# config=config,
# debug=True,
# ):
# pass
# # print("model: ", model)
# # print("value: ")
# # pprint(value, sort_dicts=False, width=40)
#
# print("+" * 100)
#
# # then the user paid for the order
# for model, value in graph.stream(
# Command(
# goto="payment_interrupt_node",
# resume={"data": "30$"}
# ),
# stream_mode=["messages", "updates", "checkpoints"],
# config=config,
# debug=True,
# ):
# pass
# # print("model: ", model)
# # print("value: ")
# # pprint(value, sort_dicts=False, width=40)
################################ Case: Pay Later (with interrupt) ##########################################
for model, value in graph.stream(
Command(resume={"message": "ask some information"}),
stream_mode=["messages", "updates", "checkpoints"],
config=config,
debug=True,
):
pass
# print("model: ", model)
# print("value: ")
# pprint(value, sort_dicts=False, width=40)
print("+" * 100)
# there have an interrupt
# at same time
# then the user paid for the order
for model, value in graph.stream(
Command(
goto="payment_interrupt_node",
resume={"data": "30$"}
),
stream_mode=["checkpoints"],
config=config,
debug=True,
):
# pass
print("model: ", model)
print("value: ")
pprint(value, sort_dicts=False, width=40)
print("+" * 100)
# here not go to the delivery node, i don't know why
state = graph.get_state(config=config)
print("state: ", state)
输出
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='098cc5e6-70d0-49ee-be9d-81e56bda1b9f')]}
[updates] {'__interrupt__': (Interrupt(value='Payment Link...', id='c0fb60800beeed446c93ad2b8bf6664a'),)}
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='098cc5e6-70d0-49ee-be9d-81e56bda1b9f')], '__interrupt__': (Interrupt(value='Payment Link...', id='c0fb60800beeed446c93ad2b8bf6664a'),)}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='098cc5e6-70d0-49ee-be9d-81e56bda1b9f')]}
[updates] {'payment_interrupt_node': {'chat': 1, 'messages': [AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--4167de44-b228-47b7-9b46-264abd1417a4'), {'role': 'human', 'content': 'ask some information'}, {'role': 'ai', 'content': 'some interrupt'}]}}
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='098cc5e6-70d0-49ee-be9d-81e56bda1b9f'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--4167de44-b228-47b7-9b46-264abd1417a4'), HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='cf6ed29b-0595-4de6-ba9a-10bb537d7584'), AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d79434ae-2225-49d8-b371-598c7869f92b')], 'chat': 1}
[updates] {'__interrupt__': (Interrupt(value='Send another interrupt(for some reason)', id='b51ab1eac2e8c57092a14fc1bce1e4b5'),)}
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='098cc5e6-70d0-49ee-be9d-81e56bda1b9f'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--4167de44-b228-47b7-9b46-264abd1417a4'), HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='cf6ed29b-0595-4de6-ba9a-10bb537d7584'), AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d79434ae-2225-49d8-b371-598c7869f92b')], 'chat': 1, '__interrupt__': (Interrupt(value='Send another interrupt(for some reason)', id='b51ab1eac2e8c57092a14fc1bce1e4b5'),)}
# CASE_1: another_interrupt_node
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='098cc5e6-70d0-49ee-be9d-81e56bda1b9f'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--4167de44-b228-47b7-9b46-264abd1417a4'), HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='cf6ed29b-0595-4de6-ba9a-10bb537d7584'), AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d79434ae-2225-49d8-b371-598c7869f92b')], 'chat': 1}
model: checkpoints
value:
{'config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0d0de5-3edf-6edc-8001-cfb96672d6aa'}},
'parent_config': {'configurable': {'thread_id': '1',
'checkpoint_ns': '',
'checkpoint_id': '1f0d0de5-3ed1-6760-8000-d80192f02970'}},
'values': {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='098cc5e6-70d0-49ee-be9d-81e56bda1b9f'),
AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--4167de44-b228-47b7-9b46-264abd1417a4'),
HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='cf6ed29b-0595-4de6-ba9a-10bb537d7584'),
AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d79434ae-2225-49d8-b371-598c7869f92b')],
'chat': 1},
'metadata': {'source': 'loop',
'step': 1,
'parents': {}},
'next': ['another_interrupt_node',
'payment_interrupt_node'],
'tasks': [{'id': '082e1f9e-955b-fd99-852f-f6bb62d3c174',
'name': 'another_interrupt_node',
'interrupts': ({'value': 'Send '
'another '
'interrupt(for '
'some '
'reason)',
'id': 'b51ab1eac2e8c57092a14fc1bce1e4b5'},),
'state': None},
{'id': '36f1a7d2-f471-a97b-536c-a54d7e2862b2',
'name': 'payment_interrupt_node',
'interrupts': (),
'state': None}]}
[updates] {'another_interrupt_node': {'messages': [{'role': 'human', 'content': "{'data': '30$'}"}, {'role': 'ai', 'content': 'never mind'}]}}
[updates] {'__interrupt__': (Interrupt(value='Payment Link...', id='bc79a0ab272d5ba9d239043028d345cd'),)}
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='098cc5e6-70d0-49ee-be9d-81e56bda1b9f'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--4167de44-b228-47b7-9b46-264abd1417a4'), HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='cf6ed29b-0595-4de6-ba9a-10bb537d7584'), AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d79434ae-2225-49d8-b371-598c7869f92b')], 'chat': 1, '__interrupt__': (Interrupt(value='Payment Link...', id='bc79a0ab272d5ba9d239043028d345cd'),)}
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='098cc5e6-70d0-49ee-be9d-81e56bda1b9f'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--4167de44-b228-47b7-9b46-264abd1417a4'), HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='cf6ed29b-0595-4de6-ba9a-10bb537d7584'), AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d79434ae-2225-49d8-b371-598c7869f92b'), HumanMessage(content="{'data': '30$'}", additional_kwargs={}, response_metadata={}, id='1a5a6f70-e3f0-4145-a3ac-5627616ecaa4'), AIMessage(content='never mind', additional_kwargs={}, response_metadata={}, id='2605030a-4040-4fbf-aa06-6497ef5123ae')], 'chat': 1}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
state: StateSnapshot(values={'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='098cc5e6-70d0-49ee-be9d-81e56bda1b9f'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--4167de44-b228-47b7-9b46-264abd1417a4'), HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='cf6ed29b-0595-4de6-ba9a-10bb537d7584'), AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d79434ae-2225-49d8-b371-598c7869f92b'), HumanMessage(content="{'data': '30$'}", additional_kwargs={}, response_metadata={}, id='180dc6ad-0733-4c92-92a2-cec63db41c42'), AIMessage(content='never mind', additional_kwargs={}, response_metadata={}, id='11da48f9-fe67-4b0f-ae4c-7a5db0bf4263')], 'chat': 1}, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f0d0de5-3edf-6edc-8001-cfb96672d6aa'}}, metadata={'source': 'loop', 'step': 1, 'parents': {}}, created_at='2025-12-04T06:56:15.790857+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f0d0de5-3ed1-6760-8000-d80192f02970'}}, tasks=(PregelTask(id='082e1f9e-955b-fd99-852f-f6bb62d3c174', name='another_interrupt_node', path=('__pregel_pull', 'another_interrupt_node'), error=None, interrupts=(Interrupt(value='Send another interrupt(for some reason)', id='b51ab1eac2e8c57092a14fc1bce1e4b5'),), state=None, result={'messages': [{'role': 'human', 'content': "{'data': '30$'}"}, {'role': 'ai', 'content': 'never mind'}]}),), interrupts=(Interrupt(value='Send another interrupt(for some reason)', id='b51ab1eac2e8c57092a14fc1bce1e4b5'),))
# CASE_2: payment_interrupt_node
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='a50e744d-b5e8-4d95-9388-4e0598481a10'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--24a43d8e-20ea-4b1c-b6c4-0ef060565f53'), HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='506df1b9-42c4-4265-ac56-0b68979f3b41'), AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d8ff3231-dfb1-44af-b433-1ca237e4e7d7')], 'chat': 1}
model: checkpoints
value:
{'config': {'configurable': {'checkpoint_ns': '',
'thread_id': '1',
'checkpoint_id': '1f0d17d6-c2fc-6f1c-8001-ed3f54d18cdc'}},
'parent_config': {'configurable': {'thread_id': '1',
'checkpoint_ns': '',
'checkpoint_id': '1f0d17d6-c2f4-6146-8000-26fe9ef64f93'}},
'values': {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='a50e744d-b5e8-4d95-9388-4e0598481a10'),
AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--24a43d8e-20ea-4b1c-b6c4-0ef060565f53'),
HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='506df1b9-42c4-4265-ac56-0b68979f3b41'),
AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d8ff3231-dfb1-44af-b433-1ca237e4e7d7')],
'chat': 1},
'metadata': {'source': 'loop',
'step': 1,
'parents': {}},
'next': ['another_interrupt_node',
'payment_interrupt_node'],
'tasks': [{'id': 'fcf8b6bc-0c4a-d439-88f2-f0bf6f160ced',
'name': 'another_interrupt_node',
'interrupts': ({'value': 'Send '
'another '
'interrupt(for '
'some '
'reason)',
'id': '1635cfd14c3a5b289c981707c2255da7'},),
'state': None},
{'id': '34ffbfb5-bd9c-7dae-c41b-6ffc01ac64c6',
'name': 'payment_interrupt_node',
'interrupts': (),
'state': None}]}
[updates] {'payment_interrupt_node': {'interrupt': 1, 'messages': [AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--10a67ac2-ce12-447d-89c6-f04222b74c6d-0'), {'role': 'ai', 'content': '30$'}]}}
[updates] {'__interrupt__': (Interrupt(value='Send another interrupt(for some reason)', id='1635cfd14c3a5b289c981707c2255da7'),)}
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='a50e744d-b5e8-4d95-9388-4e0598481a10'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--24a43d8e-20ea-4b1c-b6c4-0ef060565f53'), HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='506df1b9-42c4-4265-ac56-0b68979f3b41'), AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d8ff3231-dfb1-44af-b433-1ca237e4e7d7')], 'chat': 1, '__interrupt__': (Interrupt(value='Send another interrupt(for some reason)', id='1635cfd14c3a5b289c981707c2255da7'),)}
[values] {'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='a50e744d-b5e8-4d95-9388-4e0598481a10'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--24a43d8e-20ea-4b1c-b6c4-0ef060565f53'), HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='506df1b9-42c4-4265-ac56-0b68979f3b41'), AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d8ff3231-dfb1-44af-b433-1ca237e4e7d7'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--10a67ac2-ce12-447d-89c6-f04222b74c6d-0'), AIMessage(content='30$', additional_kwargs={}, response_metadata={}, id='83414148-d903-41f9-a726-9853cd82ff3e')], 'interrupt': 1, 'chat': 1}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
state: StateSnapshot(values={'messages': [HumanMessage(content='buy something', additional_kwargs={}, response_metadata={}, id='a50e744d-b5e8-4d95-9388-4e0598481a10'), AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--24a43d8e-20ea-4b1c-b6c4-0ef060565f53'), HumanMessage(content='ask some information', additional_kwargs={}, response_metadata={}, id='506df1b9-42c4-4265-ac56-0b68979f3b41'), AIMessage(content='some interrupt', additional_kwargs={}, response_metadata={}, id='d8ff3231-dfb1-44af-b433-1ca237e4e7d7')], 'chat': 1}, next=('another_interrupt_node',), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f0d17d6-c2fc-6f1c-8001-ed3f54d18cdc'}}, metadata={'source': 'loop', 'step': 1, 'parents': {}}, created_at='2025-12-05T01:55:06.467500+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f0d17d6-c2f4-6146-8000-26fe9ef64f93'}}, tasks=(PregelTask(id='fcf8b6bc-0c4a-d439-88f2-f0bf6f160ced', name='another_interrupt_node', path=('__pregel_pull', 'another_interrupt_node'), error=None, interrupts=(Interrupt(value='Send another interrupt(for some reason)', id='1635cfd14c3a5b289c981707c2255da7'),), state=None, result=None),), interrupts=(Interrupt(value='Send another interrupt(for some reason)', id='1635cfd14c3a5b289c981707c2255da7'),))
分析
# 关键在最后的这里会出现两个情况
Command(
goto="payment_interrupt_node",
resume={"data": "30$"}
)
CASE_1: another_interrupt_node
# 这里 another_interrupt_node 消耗了 resume 的 {"data": "30$"}
[updates] {'another_interrupt_node': {'messages': [{'role': 'human', 'content': "{'data': '30$'}"}, {'role': 'ai', 'content': 'never mind'}]}}
# 这里的 Interrupt 在 StateSnapshot 中不存在
[updates] {'__interrupt__': (Interrupt(value='Payment Link...', id='bc79a0ab272d5ba9d239043028d345cd'),)}
CASE_2: payment_interrupt_node
# 这里 payment_interrupt_node 消耗了 resume 的 {"data": "30$"}
[updates] {'payment_interrupt_node': {'interrupt': 1, 'messages': [AIMessage(content='Order creation successful!', additional_kwargs={}, response_metadata={}, id='lc_run--10a67ac2-ce12-447d-89c6-f04222b74c6d-0'), {'role': 'ai', 'content': '30$'}]}}
# 这里应该去 delivery node
[updates] {'__interrupt__': (Interrupt(value='Send another interrupt(for some reason)', id='1635cfd14c3a5b289c981707c2255da7'),)}
# 'interrupt': 1 也不存在与 StateSnapshot 中