Human in Loop的几种实现方式

human-in-loop是指在agent的循环执行中,让人能够介入,从而让自动化流程中可以使用人这个工具来实现输入密码、授予权限等操作。
实现human-in-loop主要取决于两个能力:

  1. 阻塞通知能力,原地阻塞,等待用户输入,用户输入将通过事件通知的方式来触发流程的继续执行,例如:LlamaIndex和ADK的实现
  2. 中断恢复能力,在关键执行节点保存执行上下文,让任务能恢复执行,例如:LangGraph的实现

LangGraph的实现模式

LangGraph 中的人机循环工作流建立在 checkpoint 系统之上,使用检查点保存每一步的图形状态,并在人工干预后恢复。

中断原语

中断时序图.png

Common Patterns(常见模式)

LangGraph中的人机循环实现提供了几种常见的模式,用于不同的应用场景:

1. 审批或拒绝模式(Approve or Reject)

Node中断执行流.png
用于需要人工审批的场景,比如内容审核、决策确认等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def approval_node(state):
# 准备需要审批的内容
content_to_review = state["generated_content"]

# 中断等待人工审批
approval = interrupt({
"content": content_to_review,
"action": "approve_or_reject"
})

if approval == "approve":
return {"status": "approved", "content": content_to_review}
else:
return {"status": "rejected", "content": None}

2. 审查和编辑状态模式(Review and Edit State)

允许人工审查当前状态并进行编辑修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
def review_edit_node(state):
current_state = {
"text": state.get("text", ""),
"metadata": state.get("metadata", {})
}

# 中断等待人工编辑
edited_state = interrupt({
"current_state": current_state,
"instruction": "请审查并编辑当前状态"
})

return edited_state

3. 审查工具调用模式(Review Tool Calls)

Tool中断执行流.png
在工具执行前进行人工审查,确保工具调用的正确性。

1
2
3
4
5
6
7
8
9
10
def tool_review_node(state):
tool_calls = state["proposed_tool_calls"]

# 中断等待人工确认工具调用
approved_calls = interrupt({
"tool_calls": tool_calls,
"action": "review_tool_calls"
})

return {"approved_tool_calls": approved_calls}

4. 为任何工具添加中断模式(Add Interrupts to Any Tool)

可以在任何工具执行前后添加人工干预点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def tool_with_interrupt(state):
# 工具执行前的确认
pre_confirmation = interrupt({
"message": "即将执行工具,请确认",
"tool_name": "api_call"
})

# 执行工具
result = execute_tool(state["parameters"])

# 工具执行后的审查
post_review = interrupt({
"result": result,
"action": "review_result"
})

return {"final_result": post_review}

5. 验证人工输入模式(Validate Human Input)

对人工输入进行验证,确保输入的正确性和完整性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def validation_node(state):
while True:
# 获取人工输入
user_input = interrupt({
"message": "请输入数据",
"validation_rules": ["required", "email_format"]
})

# 验证输入
if validate_input(user_input):
return {"validated_input": user_input}
else:
# 输入无效,继续循环
continue

使用注意事项

1. 副作用处理

  • 将带有副作用的代码(如API调用)放在interrupt之后或单独的节点中
  • 避免在中断点之前执行不可逆的操作

2. 子图调用

  • 当子图作为函数调用时,父图会从调用子图的节点开始重新执行
  • 子图会从包含interrupt的节点开始重新执行

3. 单节点多中断

  • 在单个节点中使用多个中断时,需要注意执行顺序
  • 中断的匹配是基于严格索引的,顺序很重要
  • 避免动态改变节点结构,可能导致索引不匹配

参考文档
https://deepwiki.com/langchain-ai/langgraph/4-human-in-the-loop-capabilities#common-hil-patterns
https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/add-human-in-the-loop/#pause-using-interrupt

LlamaIndex

llamaindex_humaninloop.png
LlamaIndex会向外发送一个消息InputRequiredEvent事件,然后等待外部处理事件后回馈一个回执事件HumanResponseEvent

  • 事件驱动:使用 InputRequiredEvent 和 HumanResponseEvent 进行异步通信
  • 人工确认:危险操作需要用户明确确认(”yes” 或 “no”)
  • 异步处理:使用 async/await 模式处理异步事件
  • 流式处理:通过 stream_events() 实时处理事件流

参考文档
https://github.com/run-llama/python-agents-tutorial/blob/main/5_human_in_the_loop.py
https://docs.llamaindex.ai/en/stable/understanding/agent/human_in_the_loop/

ADK

长时间运行工具(Long-Running Tools)
这是最直接的实现方式,使用LongRunningFunctionTool来处理需要人工干预的异步操作。
核心实现流程:

  1. 初始调用:Agent调用长时间运行工具,工具立即返回pending状态和跟踪ID
  2. 等待人工干预:系统等待外部人工处理
  3. 更新工具响应:人工处理完成后,必须构造新的types.FunctionResponse并发送给Agent

adk_humaninloop.png

参考文档
https://deepwiki.com/search/human-in-the-loop_c1195076-6732-4fa2-97fe-4a4d444faec6

magentic-ui human in loop

connection.py定义用户输入函数:更新agent运行状态等待用户输入,然后阻塞等待用户输入
magentic_human_1.png
magentic_human_2.png

将user_input包装为Agent
magentic_human_3.png

Agent作为team的参与者,被分发
magentic_human_4.png

参考文档
https://github.com/microsoft/magentic-ui