-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy path241930bf.html
More file actions
409 lines (300 loc) · 36 KB
/
241930bf.html
File metadata and controls
409 lines (300 loc) · 36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 6.3.0">
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon.png">
<link rel="mask-icon" href="/images/logo.svg" color="#222">
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha256-HtsXJanqjKTc8vVQjO4YMhiqFoXkfBsjBWcX91T1jr8=" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
<script class="next-config" data-name="main" type="application/json">{"hostname":"tallate.github.io","root":"/","images":"/images","scheme":"Gemini","darkmode":false,"version":"8.18.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"fold":{"enable":false,"height":500},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果:${query}","hits_time":"找到 ${hits} 个搜索结果(用时 ${time} 毫秒)","hits":"找到 ${hits} 个搜索结果"}}</script><script src="/js/config.js"></script>
<meta name="description" content="human-in-loop是指在agent的循环执行中,让人能够介入,从而让自动化流程中可以使用人这个工具来实现输入密码、授予权限等操作。实现human-in-loop主要取决于两个能力: 阻塞通知能力,原地阻塞,等待用户输入,用户输入将通过事件通知的方式来触发流程的继续执行,例如:LlamaIndex和ADK的实现 中断恢复能力,在关键执行节点保存执行上下文,让任务能恢复执行,例如:LangG">
<meta property="og:type" content="article">
<meta property="og:title" content="Human in Loop的几种实现方式">
<meta property="og:url" content="https://tallate.github.io/241930bf.html">
<meta property="og:site_name" content="Tallate">
<meta property="og:description" content="human-in-loop是指在agent的循环执行中,让人能够介入,从而让自动化流程中可以使用人这个工具来实现输入密码、授予权限等操作。实现human-in-loop主要取决于两个能力: 阻塞通知能力,原地阻塞,等待用户输入,用户输入将通过事件通知的方式来触发流程的继续执行,例如:LlamaIndex和ADK的实现 中断恢复能力,在关键执行节点保存执行上下文,让任务能恢复执行,例如:LangG">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://tallate.github.io/imgs/AI/%E4%B8%AD%E6%96%AD%E6%97%B6%E5%BA%8F%E5%9B%BE.png">
<meta property="og:image" content="https://tallate.github.io/imgs/AI/Node%E4%B8%AD%E6%96%AD%E6%89%A7%E8%A1%8C%E6%B5%81.png">
<meta property="og:image" content="https://tallate.github.io/imgs/AI/Tool%E4%B8%AD%E6%96%AD%E6%89%A7%E8%A1%8C%E6%B5%81.png">
<meta property="og:image" content="https://tallate.github.io/imgs/AI/llamaindex_humaninloop.png">
<meta property="og:image" content="https://tallate.github.io/imgs/AI/adk_humaninloop.png">
<meta property="og:image" content="https://tallate.github.io/imgs/AI/magentic_human_1.png">
<meta property="og:image" content="https://tallate.github.io/imgs/AI/magentic_human_2.png">
<meta property="og:image" content="https://tallate.github.io/imgs/AI/magentic_human_3.png">
<meta property="og:image" content="https://tallate.github.io/imgs/AI/magentic_human_4.png">
<meta property="article:published_time" content="2025-08-23T16:22:48.000Z">
<meta property="article:modified_time" content="2025-08-31T07:24:17.045Z">
<meta property="article:author" content="tallate">
<meta property="article:tag" content="Human-in-the-Loop">
<meta property="article:tag" content="LangGraph">
<meta property="article:tag" content="AI">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://tallate.github.io/imgs/AI/%E4%B8%AD%E6%96%AD%E6%97%B6%E5%BA%8F%E5%9B%BE.png">
<link rel="canonical" href="https://tallate.github.io/241930bf.html">
<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":false,"isPost":true,"lang":"zh-CN","comments":true,"permalink":"https://tallate.github.io/241930bf.html","path":"/241930bf.html","title":"Human in Loop的几种实现方式"}</script>
<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>Human in Loop的几种实现方式 | Tallate</title>
<noscript>
<link rel="stylesheet" href="/css/noscript.css">
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
<div class="headband"></div>
<main class="main">
<div class="column">
<header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
<div class="site-nav-toggle">
<div class="toggle" aria-label="切换导航栏" role="button">
<span class="toggle-line"></span>
<span class="toggle-line"></span>
<span class="toggle-line"></span>
</div>
</div>
<div class="site-meta">
<a href="/" class="brand" rel="start">
<i class="logo-line"></i>
<p class="site-title">Tallate</p>
<i class="logo-line"></i>
</a>
<p class="site-subtitle" itemprop="description">该吃吃该喝喝 啥事别往心里搁</p>
</div>
<div class="site-nav-right">
<div class="toggle popup-trigger" aria-label="搜索" role="button">
<i class="fa fa-search fa-fw fa-lg"></i>
</div>
</div>
</div>
<nav class="site-nav">
<ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="home fa-fw"></i>首页</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="user fa-fw"></i>关于</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="tags fa-fw"></i>标签<span class="badge">84</span></a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="th fa-fw"></i>分类<span class="badge">25</span></a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="archive fa-fw"></i>归档<span class="badge">192</span></a></li>
<li class="menu-item menu-item-search">
<a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
</a>
</li>
</ul>
</nav>
<div class="search-pop-overlay">
<div class="popup search-popup"><div class="search-header">
<span class="search-icon">
<i class="fa fa-search"></i>
</span>
<div class="search-input-container">
<input autocomplete="off" autocapitalize="off" maxlength="80"
placeholder="搜索..." spellcheck="false"
type="search" class="search-input">
</div>
<span class="popup-btn-close" role="button">
<i class="fa fa-times-circle"></i>
</span>
</div>
<div class="search-result-container no-result">
<div class="search-result-icon">
<i class="fa fa-spinner fa-pulse fa-5x"></i>
</div>
</div>
</div>
</div>
</header>
<aside class="sidebar">
<div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
<ul class="sidebar-nav">
<li class="sidebar-nav-toc">
文章目录
</li>
<li class="sidebar-nav-overview">
站点概览
</li>
</ul>
<div class="sidebar-panel-container">
<!--noindex-->
<div class="post-toc-wrap sidebar-panel">
<div class="post-toc animated"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#LangGraph%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%BC%8F"><span class="nav-number">1.</span> <span class="nav-text">LangGraph的实现模式</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%AD%E6%96%AD%E5%8E%9F%E8%AF%AD"><span class="nav-number">1.1.</span> <span class="nav-text">中断原语</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Common-Patterns%EF%BC%88%E5%B8%B8%E8%A7%81%E6%A8%A1%E5%BC%8F%EF%BC%89"><span class="nav-number">1.2.</span> <span class="nav-text">Common Patterns(常见模式)</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-%E5%AE%A1%E6%89%B9%E6%88%96%E6%8B%92%E7%BB%9D%E6%A8%A1%E5%BC%8F%EF%BC%88Approve-or-Reject%EF%BC%89"><span class="nav-number">1.2.1.</span> <span class="nav-text">1. 审批或拒绝模式(Approve or Reject)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-%E5%AE%A1%E6%9F%A5%E5%92%8C%E7%BC%96%E8%BE%91%E7%8A%B6%E6%80%81%E6%A8%A1%E5%BC%8F%EF%BC%88Review-and-Edit-State%EF%BC%89"><span class="nav-number">1.2.2.</span> <span class="nav-text">2. 审查和编辑状态模式(Review and Edit State)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-%E5%AE%A1%E6%9F%A5%E5%B7%A5%E5%85%B7%E8%B0%83%E7%94%A8%E6%A8%A1%E5%BC%8F%EF%BC%88Review-Tool-Calls%EF%BC%89"><span class="nav-number">1.2.3.</span> <span class="nav-text">3. 审查工具调用模式(Review Tool Calls)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-%E4%B8%BA%E4%BB%BB%E4%BD%95%E5%B7%A5%E5%85%B7%E6%B7%BB%E5%8A%A0%E4%B8%AD%E6%96%AD%E6%A8%A1%E5%BC%8F%EF%BC%88Add-Interrupts-to-Any-Tool%EF%BC%89"><span class="nav-number">1.2.4.</span> <span class="nav-text">4. 为任何工具添加中断模式(Add Interrupts to Any Tool)</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-%E9%AA%8C%E8%AF%81%E4%BA%BA%E5%B7%A5%E8%BE%93%E5%85%A5%E6%A8%A1%E5%BC%8F%EF%BC%88Validate-Human-Input%EF%BC%89"><span class="nav-number">1.2.5.</span> <span class="nav-text">5. 验证人工输入模式(Validate Human Input)</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9"><span class="nav-number">1.3.</span> <span class="nav-text">使用注意事项</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-%E5%89%AF%E4%BD%9C%E7%94%A8%E5%A4%84%E7%90%86"><span class="nav-number">1.3.1.</span> <span class="nav-text">1. 副作用处理</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-%E5%AD%90%E5%9B%BE%E8%B0%83%E7%94%A8"><span class="nav-number">1.3.2.</span> <span class="nav-text">2. 子图调用</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-%E5%8D%95%E8%8A%82%E7%82%B9%E5%A4%9A%E4%B8%AD%E6%96%AD"><span class="nav-number">1.3.3.</span> <span class="nav-text">3. 单节点多中断</span></a></li></ol></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#LlamaIndex"><span class="nav-number">2.</span> <span class="nav-text">LlamaIndex</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#ADK"><span class="nav-number">3.</span> <span class="nav-text">ADK</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#magentic-ui-human-in-loop"><span class="nav-number">4.</span> <span class="nav-text">magentic-ui human in loop</span></a></li></ol></div>
</div>
<!--/noindex-->
<div class="site-overview-wrap sidebar-panel">
<div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
<p class="site-author-name" itemprop="name">tallate</p>
<div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap animated">
<nav class="site-state">
<div class="site-state-item site-state-posts">
<a href="/archives/">
<span class="site-state-item-count">192</span>
<span class="site-state-item-name">日志</span>
</a>
</div>
<div class="site-state-item site-state-categories">
<a href="/categories/">
<span class="site-state-item-count">25</span>
<span class="site-state-item-name">分类</span></a>
</div>
<div class="site-state-item site-state-tags">
<a href="/tags/">
<span class="site-state-item-count">84</span>
<span class="site-state-item-name">标签</span></a>
</div>
</nav>
</div>
</div>
</div>
</div>
</aside>
</div>
<div class="main-inner post posts-expand">
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
<link itemprop="mainEntityOfPage" href="https://tallate.github.io/241930bf.html">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar.gif">
<meta itemprop="name" content="tallate">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="Tallate">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
<meta itemprop="name" content="Human in Loop的几种实现方式 | Tallate">
<meta itemprop="description" content="">
</span>
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
Human in Loop的几种实现方式
</h1>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2025-08-24 00:22:48" itemprop="dateCreated datePublished" datetime="2025-08-24T00:22:48+08:00">2025-08-24</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2025-08-31 15:24:17" itemprop="dateModified" datetime="2025-08-31T15:24:17+08:00">2025-08-31</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/categories/AI/" itemprop="url" rel="index"><span itemprop="name">AI</span></a>
</span>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody"><p>human-in-loop是指在agent的循环执行中,让人能够介入,从而让自动化流程中可以使用人这个工具来实现输入密码、授予权限等操作。<br>实现human-in-loop主要取决于两个能力:</p>
<ol>
<li>阻塞通知能力,原地阻塞,等待用户输入,用户输入将通过事件通知的方式来触发流程的继续执行,例如:LlamaIndex和ADK的实现</li>
<li>中断恢复能力,在关键执行节点保存执行上下文,让任务能恢复执行,例如:LangGraph的实现</li>
</ol>
<h1 id="LangGraph的实现模式"><a href="#LangGraph的实现模式" class="headerlink" title="LangGraph的实现模式"></a>LangGraph的实现模式</h1><p>LangGraph 中的人机循环工作流建立在 checkpoint 系统之上,使用检查点保存每一步的图形状态,并在人工干预后恢复。</p>
<h2 id="中断原语"><a href="#中断原语" class="headerlink" title="中断原语"></a>中断原语</h2><p><img src="/imgs/AI/%E4%B8%AD%E6%96%AD%E6%97%B6%E5%BA%8F%E5%9B%BE.png" alt="中断时序图.png"></p>
<h2 id="Common-Patterns(常见模式)"><a href="#Common-Patterns(常见模式)" class="headerlink" title="Common Patterns(常见模式)"></a>Common Patterns(常见模式)</h2><p>LangGraph中的人机循环实现提供了几种常见的模式,用于不同的应用场景:</p>
<h3 id="1-审批或拒绝模式(Approve-or-Reject)"><a href="#1-审批或拒绝模式(Approve-or-Reject)" class="headerlink" title="1. 审批或拒绝模式(Approve or Reject)"></a>1. 审批或拒绝模式(Approve or Reject)</h3><p><img src="/imgs/AI/Node%E4%B8%AD%E6%96%AD%E6%89%A7%E8%A1%8C%E6%B5%81.png" alt="Node中断执行流.png"><br>用于需要人工审批的场景,比如内容审核、决策确认等。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">approval_node</span>(<span class="params">state</span>):</span><br><span class="line"> <span class="comment"># 准备需要审批的内容</span></span><br><span class="line"> content_to_review = state[<span class="string">"generated_content"</span>]</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 中断等待人工审批</span></span><br><span class="line"> approval = interrupt({</span><br><span class="line"> <span class="string">"content"</span>: content_to_review,</span><br><span class="line"> <span class="string">"action"</span>: <span class="string">"approve_or_reject"</span></span><br><span class="line"> })</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">if</span> approval == <span class="string">"approve"</span>:</span><br><span class="line"> <span class="keyword">return</span> {<span class="string">"status"</span>: <span class="string">"approved"</span>, <span class="string">"content"</span>: content_to_review}</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">return</span> {<span class="string">"status"</span>: <span class="string">"rejected"</span>, <span class="string">"content"</span>: <span class="literal">None</span>}</span><br></pre></td></tr></table></figure>
<h3 id="2-审查和编辑状态模式(Review-and-Edit-State)"><a href="#2-审查和编辑状态模式(Review-and-Edit-State)" class="headerlink" title="2. 审查和编辑状态模式(Review and Edit State)"></a>2. 审查和编辑状态模式(Review and Edit State)</h3><p>允许人工审查当前状态并进行编辑修改。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">review_edit_node</span>(<span class="params">state</span>):</span><br><span class="line"> current_state = {</span><br><span class="line"> <span class="string">"text"</span>: state.get(<span class="string">"text"</span>, <span class="string">""</span>),</span><br><span class="line"> <span class="string">"metadata"</span>: state.get(<span class="string">"metadata"</span>, {})</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 中断等待人工编辑</span></span><br><span class="line"> edited_state = interrupt({</span><br><span class="line"> <span class="string">"current_state"</span>: current_state,</span><br><span class="line"> <span class="string">"instruction"</span>: <span class="string">"请审查并编辑当前状态"</span></span><br><span class="line"> })</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> edited_state</span><br></pre></td></tr></table></figure>
<h3 id="3-审查工具调用模式(Review-Tool-Calls)"><a href="#3-审查工具调用模式(Review-Tool-Calls)" class="headerlink" title="3. 审查工具调用模式(Review Tool Calls)"></a>3. 审查工具调用模式(Review Tool Calls)</h3><p><img src="/imgs/AI/Tool%E4%B8%AD%E6%96%AD%E6%89%A7%E8%A1%8C%E6%B5%81.png" alt="Tool中断执行流.png"><br>在工具执行前进行人工审查,确保工具调用的正确性。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">tool_review_node</span>(<span class="params">state</span>):</span><br><span class="line"> tool_calls = state[<span class="string">"proposed_tool_calls"</span>]</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 中断等待人工确认工具调用</span></span><br><span class="line"> approved_calls = interrupt({</span><br><span class="line"> <span class="string">"tool_calls"</span>: tool_calls,</span><br><span class="line"> <span class="string">"action"</span>: <span class="string">"review_tool_calls"</span></span><br><span class="line"> })</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> {<span class="string">"approved_tool_calls"</span>: approved_calls}</span><br></pre></td></tr></table></figure>
<h3 id="4-为任何工具添加中断模式(Add-Interrupts-to-Any-Tool)"><a href="#4-为任何工具添加中断模式(Add-Interrupts-to-Any-Tool)" class="headerlink" title="4. 为任何工具添加中断模式(Add Interrupts to Any Tool)"></a>4. 为任何工具添加中断模式(Add Interrupts to Any Tool)</h3><p>可以在任何工具执行前后添加人工干预点。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">tool_with_interrupt</span>(<span class="params">state</span>):</span><br><span class="line"> <span class="comment"># 工具执行前的确认</span></span><br><span class="line"> pre_confirmation = interrupt({</span><br><span class="line"> <span class="string">"message"</span>: <span class="string">"即将执行工具,请确认"</span>,</span><br><span class="line"> <span class="string">"tool_name"</span>: <span class="string">"api_call"</span></span><br><span class="line"> })</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 执行工具</span></span><br><span class="line"> result = execute_tool(state[<span class="string">"parameters"</span>])</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 工具执行后的审查</span></span><br><span class="line"> post_review = interrupt({</span><br><span class="line"> <span class="string">"result"</span>: result,</span><br><span class="line"> <span class="string">"action"</span>: <span class="string">"review_result"</span></span><br><span class="line"> })</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> {<span class="string">"final_result"</span>: post_review}</span><br></pre></td></tr></table></figure>
<h3 id="5-验证人工输入模式(Validate-Human-Input)"><a href="#5-验证人工输入模式(Validate-Human-Input)" class="headerlink" title="5. 验证人工输入模式(Validate Human Input)"></a>5. 验证人工输入模式(Validate Human Input)</h3><p>对人工输入进行验证,确保输入的正确性和完整性。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">validation_node</span>(<span class="params">state</span>):</span><br><span class="line"> <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line"> <span class="comment"># 获取人工输入</span></span><br><span class="line"> user_input = interrupt({</span><br><span class="line"> <span class="string">"message"</span>: <span class="string">"请输入数据"</span>,</span><br><span class="line"> <span class="string">"validation_rules"</span>: [<span class="string">"required"</span>, <span class="string">"email_format"</span>]</span><br><span class="line"> })</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 验证输入</span></span><br><span class="line"> <span class="keyword">if</span> validate_input(user_input):</span><br><span class="line"> <span class="keyword">return</span> {<span class="string">"validated_input"</span>: user_input}</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> <span class="comment"># 输入无效,继续循环</span></span><br><span class="line"> <span class="keyword">continue</span></span><br></pre></td></tr></table></figure>
<h2 id="使用注意事项"><a href="#使用注意事项" class="headerlink" title="使用注意事项"></a>使用注意事项</h2><h3 id="1-副作用处理"><a href="#1-副作用处理" class="headerlink" title="1. 副作用处理"></a>1. 副作用处理</h3><ul>
<li>将带有副作用的代码(如API调用)放在<code>interrupt</code>之后或单独的节点中</li>
<li>避免在中断点之前执行不可逆的操作</li>
</ul>
<h3 id="2-子图调用"><a href="#2-子图调用" class="headerlink" title="2. 子图调用"></a>2. 子图调用</h3><ul>
<li>当子图作为函数调用时,父图会从调用子图的节点开始重新执行</li>
<li>子图会从包含<code>interrupt</code>的节点开始重新执行</li>
</ul>
<h3 id="3-单节点多中断"><a href="#3-单节点多中断" class="headerlink" title="3. 单节点多中断"></a>3. 单节点多中断</h3><ul>
<li>在单个节点中使用多个中断时,需要注意执行顺序</li>
<li>中断的匹配是基于严格索引的,顺序很重要</li>
<li>避免动态改变节点结构,可能导致索引不匹配</li>
</ul>
<p><strong>参考文档</strong><br><a target="_blank" rel="noopener" href="https://deepwiki.com/langchain-ai/langgraph/4-human-in-the-loop-capabilities#common-hil-patterns">https://deepwiki.com/langchain-ai/langgraph/4-human-in-the-loop-capabilities#common-hil-patterns</a><br><a target="_blank" rel="noopener" href="https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/add-human-in-the-loop/#pause-using-interrupt">https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/add-human-in-the-loop/#pause-using-interrupt</a></p>
<h1 id="LlamaIndex"><a href="#LlamaIndex" class="headerlink" title="LlamaIndex"></a>LlamaIndex</h1><p><img src="/imgs/AI/llamaindex_humaninloop.png" alt="llamaindex_humaninloop.png"><br>LlamaIndex会向外发送一个消息InputRequiredEvent事件,然后等待外部处理事件后回馈一个回执事件HumanResponseEvent</p>
<ul>
<li>事件驱动:使用 InputRequiredEvent 和 HumanResponseEvent 进行异步通信</li>
<li>人工确认:危险操作需要用户明确确认(”yes” 或 “no”)</li>
<li>异步处理:使用 async/await 模式处理异步事件</li>
<li>流式处理:通过 stream_events() 实时处理事件流</li>
</ul>
<p><strong>参考文档</strong><br><a target="_blank" rel="noopener" href="https://github.com/run-llama/python-agents-tutorial/blob/main/5_human_in_the_loop.py">https://github.com/run-llama/python-agents-tutorial/blob/main/5_human_in_the_loop.py</a><br><a target="_blank" rel="noopener" href="https://docs.llamaindex.ai/en/stable/understanding/agent/human_in_the_loop/">https://docs.llamaindex.ai/en/stable/understanding/agent/human_in_the_loop/</a></p>
<h1 id="ADK"><a href="#ADK" class="headerlink" title="ADK"></a>ADK</h1><p>长时间运行工具(Long-Running Tools)<br>这是最直接的实现方式,使用LongRunningFunctionTool来处理需要人工干预的异步操作。<br>核心实现流程:</p>
<ol>
<li>初始调用:Agent调用长时间运行工具,工具立即返回pending状态和跟踪ID</li>
<li>等待人工干预:系统等待外部人工处理</li>
<li>更新工具响应:人工处理完成后,必须构造新的types.FunctionResponse并发送给Agent</li>
</ol>
<p><img src="/imgs/AI/adk_humaninloop.png" alt="adk_humaninloop.png"></p>
<p><strong>参考文档</strong><br><a target="_blank" rel="noopener" href="https://deepwiki.com/search/human-in-the-loop_c1195076-6732-4fa2-97fe-4a4d444faec6">https://deepwiki.com/search/human-in-the-loop_c1195076-6732-4fa2-97fe-4a4d444faec6</a></p>
<h1 id="magentic-ui-human-in-loop"><a href="#magentic-ui-human-in-loop" class="headerlink" title="magentic-ui human in loop"></a>magentic-ui human in loop</h1><p>connection.py定义用户输入函数:更新agent运行状态等待用户输入,然后阻塞等待用户输入<br><img src="/imgs/AI/magentic_human_1.png" alt="magentic_human_1.png"><br><img src="/imgs/AI/magentic_human_2.png" alt="magentic_human_2.png"></p>
<p>将user_input包装为Agent<br><img src="/imgs/AI/magentic_human_3.png" alt="magentic_human_3.png"></p>
<p>Agent作为team的参与者,被分发<br><img src="/imgs/AI/magentic_human_4.png" alt="magentic_human_4.png"></p>
<p><strong>参考文档</strong><br><a target="_blank" rel="noopener" href="https://github.com/microsoft/magentic-ui">https://github.com/microsoft/magentic-ui</a></p>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/kity@2.0.4/dist/kity.min.js"></script><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/kityminder-core@1.4.50/dist/kityminder.core.min.js"></script><script defer="true" type="text/javascript" src="https://cdn.jsdelivr.net/npm/hexo-simple-mindmap@0.6.0/dist/mindmap.min.js"></script><link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/hexo-simple-mindmap@0.6.0/dist/mindmap.min.css">
</div>
<footer class="post-footer">
<div class="post-tags">
<a href="/tags/Human-in-the-Loop/" rel="tag"># Human-in-the-Loop</a>
<a href="/tags/LangGraph/" rel="tag"># LangGraph</a>
<a href="/tags/AI/" rel="tag"># AI</a>
</div>
<div class="post-nav">
<div class="post-nav-item">
<a href="/a31a76f2.html" rel="prev" title="长期记忆的集成方式">
<i class="fa fa-angle-left"></i> 长期记忆的集成方式
</a>
</div>
<div class="post-nav-item">
</div>
</div>
</footer>
</article>
</div>
</div>
</main>
<footer class="footer">
<div class="footer-inner">
<div class="copyright">
©
<span itemprop="copyrightYear">2025</span>
<span class="with-love">
<i class="fa fa-heart"></i>
</span>
<span class="author" itemprop="copyrightHolder">tallate</span>
</div>
<div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
</div>
</div>
</footer>
<div class="back-to-top" role="button" aria-label="返回顶部">
<i class="fa fa-arrow-up fa-lg"></i>
<span>0%</span>
</div>
<a href="https://github.com/tallate" class="github-corner" title="在 GitHub 上关注我" aria-label="在 GitHub 上关注我" rel="noopener" target="_blank"><svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>
<noscript>
<div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/next-boot.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hexo-generator-searchdb/1.4.1/search.js" integrity="sha256-1kfA5uHPf65M5cphT2dvymhkuyHPQp5A53EGZOnOLmc=" crossorigin="anonymous"></script>
<script src="/js/third-party/search/local-search.js"></script>
<script class="next-config" data-name="mermaid" type="application/json">{"enable":true,"version":"7.1.2","options":null,"js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.3.0/mermaid.min.js","integrity":"sha256-9y71g5Lz/KLsHjB8uXwnkuWDtAMDSzD/HdIbqhJfTAI="}}</script>
<script src="/js/third-party/tags/mermaid.js"></script>
</body>
</html>