公司动态

MAF Agent中HITL机制的设计与实现:从安全阀到智能协作

📅 2026/8/26 1:42:44
MAF Agent中HITL机制的设计与实现:从安全阀到智能协作
1. 项目概述为什么HITL是MAF Agent的“安全阀”与“加速器”最近在折腾MAFMulti-Agent Framework项目特别是当Agent开始调用外部工具Function Tool去执行一些真实世界操作时比如发邮件、操作数据库、调用API修改订单状态一个绕不开的问题就摆在了面前如何确保Agent的行为是安全、可控且符合预期的直接把所有权限都交给AI让它“自由发挥”在绝大多数严肃的业务场景下这无异于一场豪赌。这时候“人工审核”Human-in-the-Loop, HITL机制就成了整个Agent系统的“安全阀”和“决策放大器”。简单来说HITL就是在Agent的自动化决策流程中巧妙地插入一个或多个需要人工确认或干预的节点。Agent可以分析、可以建议但最终是否执行某个关键操作由人来拍板。这听起来似乎降低了“智能”程度但实际应用中它带来的价值远超你的想象规避风险、注入领域知识、纠正模型幻觉、满足合规要求并且能通过人类的反馈持续优化Agent本身。无论是金融领域的交易审核、内容创作平台的敏感词过滤还是企业内部流程的审批HITL都是将AI从“玩具”升级为“生产工具”的关键一步。网上关于Agent框架如Hermes Agent、CrewAI、AutoGen的讨论很多但大多集中在如何组装Agent、如何定义工具Tool上对于“上线后怎么管”这个更实际的问题讨论的深度往往不够。今天我就结合在MAF项目中实现HITL的实战经验拆解其核心设计思路、几种典型的集成模式、具体的代码实现以及那些只有踩过坑才知道的注意事项。无论你是正在学习Agent开发的新手还是寻求将Agent项目落地的资深开发者相信这些内容都能给你带来直接的参考。2. HITL的核心价值与设计模式解析在深入代码之前我们必须先想清楚为什么需要HITL它到底解决了哪些纯自动化流程解决不了的问题理解了这些你才能设计出贴合业务需求的审核机制而不是生搬硬套一个“确认按钮”。2.1 HITL解决的四大核心问题第一风险控制与责任归属。这是最直接的驱动力。当Agent准备执行一个“删除数据库所有用户记录”或“向客户发送一份具有法律效力的合同”的操作时让机器自动执行的风险是不可接受的。HITL将最终执行权保留给人明确了责任边界——AI提供建议人类做出决策并承担责任。第二注入领域专业知识与上下文。大语言模型LLM再强大也缺乏只有企业内部人员才知晓的“潜规则”和最新动态。例如Agent根据公开信息判断某供应商可靠但采购经理知道该供应商近期有交货延迟的内部投诉。HITL环节允许人类审核者基于这些未公开的、动态的领域知识否决或修改Agent的提议。第三纠正模型幻觉与逻辑错误。LLM有时会产生“幻觉”生成看似合理实则错误的事实或逻辑。在链式复杂的Agent工作流中一个环节的微小错误可能被放大。人工审核可以作为一道纠错防线在错误产生实际影响前将其拦截。例如Agent在生成财报分析时可能错误地引用了过时的数据财务专家在审核时就能一眼发现。第四合规性与审计追踪。许多行业如金融、医疗的法规要求关键操作必须有明确的人工审核记录。HITL机制天然地产生了“谁、在什么时候、批准或拒绝了什么操作”的完整日志满足了合规审计的需求形成了可靠的数字证据链。2.2 三种常见的HITL集成模式根据审核介入的时机和粒度HITL主要有三种设计模式你可以根据业务场景的实时性要求和风险等级进行选择。模式一工具调用前审核Pre-execution Approval这是最严格、也是最常见的模式。当Agent决策链运行到某个节点准备调用一个被标记为“高风险”或“关键”的工具Function Tool时系统不会直接执行而是暂停工作流将工具的名称、参数以及Agent调用它的理由通常由LLM生成封装成一个审核任务推送给人或审批流。只有获得批准后系统才会真正调用该工具。适用场景所有具有不可逆性、高价值或高风险的操-作。例如“支付接口调用”、“数据删除操作”、“发布生产环境配置”、“发送重要外部邮件”。优点绝对安全能防止任何未经授权的自动执行。缺点引入延迟不适合需要秒级响应的交互场景。模式二执行结果后审核Post-execution Verification在这种模式下Agent可以自动执行工具调用但在执行完成后将工具的执行结果或基于结果Agent做出的下一步判断提交给人进行验证。人工可以确认结果正确也可以要求Agent重新执行或调整策略。适用场景操作本身风险较低但结果的正确性至关重要。例如“数据查询结果的解读”、“文本摘要的准确性判断”、“代码生成后的初步逻辑审查”。优点流程不中断体验更流畅。适合需要快速响应但容错率较高的场景。缺点如果操作本身具有副作用如发送了邮件那么审核发生在事后无法阻止副作用的发生。模式三周期性或抽样审核Periodic/Sampling Review不对每一条操作进行审核而是定期如每天或按一定比例随机抽取Agent的历史决策和操作记录由人工进行复盘和评估。审核结果不作为单次流程的干预而是用于生成反馈数据训练或微调Agent模型优化其未来的决策策略。适用场景大规模、低风险、高频次的自动化任务。例如“客服自动应答的质量检查”、“内容标签自动分类的准确性评估”。优点审核成本低不影响线上流程效率专注于长期系统优化。缺点无法实时阻止单次错误更侧重于宏观质量控制和模型迭代。在MAF项目中我们主要聚焦于模式一工具调用前审核因为它是构建可信、可控Agent系统的基石。接下来我们就看看如何在一个典型的MAF架构中实现它。3. 在MAF架构中实现工具调用前审核MAF框架通常包含几个核心组件Agent智能体、Tool工具、Workflow或Orchestrator工作流编排器。HITL机制需要作为一个中间件Middleware或拦截器Interceptor嵌入到Agent调用Tool的路径中。3.1 系统架构与数据流设计一个典型的集成HITL的MAF数据流如下用户请求用户向系统提出一个请求例如“帮我向客户张三发送一封关于项目延期的道歉邮件”。Agent规划与决策负责邮件处理的EmailAgent分析请求决定需要调用send_email这个工具并生成了工具调用参数收件人、主题、正文。HITL拦截在EmailAgent试图执行send_email工具前HITL中间件被触发。该中间件检查send_email工具的元数据例如标记了requires_approvalTrue。生成审核任务中间件暂停当前工作流将工具调用信息Agent ID, Tool Name, Parameters, Context/Reason序列化创建一个状态为PENDING的审核任务Approval Task并将其存储到数据库或消息队列中。同时生成一个唯一的任务ID和审核链接。通知审核者系统通过内部通讯工具如钉钉、飞书、企业微信机器人、邮件或站内信将审核链接发送给预设的审核人员或审批组。人工审核与决策审核者打开链接查看详情“谁”想“干什么”“为什么”然后做出批准Approve或拒绝Reject的决定。审核者也可以修改工具参数如修正邮件正文措辞。回调与流程恢复审核者提交决定后系统回调一个预设的Webhook。HITL服务根据任务ID找到被暂停的工作流实例注入审核结果。如果批准则使用可能被修改后的参数继续执行send_email工具。如果拒绝则向工作流抛出一个特定的异常或返回一个拒绝结果工作流可以根据设计进行后续处理如通知用户请求被驳回或让Agent尝试其他方案。日志记录整个过程的每一步包括创建、审核人、审核时间、审核决定、参数修改记录都被完整记录到审计日志中。3.2 核心代码实现拆解下面我们以Python伪代码的形式展示几个关键环节的实现。假设我们使用一个类HITLMiddleware来实现拦截逻辑。第一步定义工具元数据与审核状态首先我们需要扩展Tool的定义为其添加是否需要审核的标签。# tool_registry.py from enum import Enum from pydantic import BaseModel from typing import Any, Dict, Optional class ToolMetadata(BaseModel): name: str description: str requires_approval: bool False # 新增字段标记该工具是否需要人工审核 approval_group: Optional[str] None # 指定审核组如 “manager”, “finance” class ApprovalStatus(Enum): PENDING pending APPROVED approved REJECTED rejected CANCELLED cancelled class ApprovalTask(BaseModel): id: str tool_name: str tool_params: Dict[str, Any] agent_context: str # Agent调用工具的理由 status: ApprovalStatus created_at: datetime reviewed_by: Optional[str] reviewed_at: Optional[datetime] review_comment: Optional[str] modified_params: Optional[Dict[str, Any]] # 审核人修改后的参数第二步实现HITL中间件这个中间件将挂载在Agent调用工具的环节。# hitl_middleware.py import asyncio from abc import ABC, abstractmethod from .tool_registry import ToolMetadata, ApprovalStatus, ApprovalTask class ApprovalBackend(ABC): 审核后端抽象可以是数据库、Redis或消息队列 abstractmethod async def create_task(self, task: ApprovalTask) - str: pass abstractmethod async def get_task(self, task_id: str) - Optional[ApprovalTask]: pass abstractmethod async def update_task(self, task_id: str, updates: dict) - bool: pass class NotificationService(ABC): 通知服务抽象用于通知审核人 abstractmethod async def notify(self, task_id: str, task_summary: str, approvers: list): pass class HITLMiddleware: def __init__(self, approval_backend: ApprovalBackend, notifier: NotificationService): self.backend approval_backend self.notifier notifier self.pending_tasks {} # 用于关联任务ID和暂停的future async def intercept_tool_call(self, agent, tool_name: str, tool_args: dict, tool_metadata: ToolMetadata): 拦截工具调用的核心方法 # 1. 检查该工具是否需要审核 if not tool_metadata.requires_approval: # 无需审核直接返回继续执行 return await self._execute_tool(agent, tool_name, tool_args) # 2. 需要审核创建审核任务 agent_context agent.get_last_reasoning() # 假设Agent能提供调用理由 task ApprovalTask( idgenerate_uuid(), tool_nametool_name, tool_paramstool_args, agent_contextagent_context, statusApprovalStatus.PENDING, created_atdatetime.now() ) task_id await self.backend.create_task(task) # 3. 通知审核人 (这里简化实际可能根据approval_group查找) approvers [approvercompany.com] # 应从配置或工具元数据中获取 summary f待审核: Agent [{agent.id}] 请求执行工具 [{tool_name}] await self.notifier.notify(task_id, summary, approvers) # 4. 暂停当前工作流等待审核结果 # 这里使用一个Future来等待结果 loop asyncio.get_event_loop() future loop.create_future() self.pending_tasks[task_id] { future: future, agent: agent, tool_name: tool_name, original_args: tool_args } # 5. 等待审核结果异步等待 try: # 这里会挂起直到future被set_result result await asyncio.wait_for(future, timeout3600) # 设置超时例如1小时 if result[status] ApprovalStatus.APPROVED: # 使用审核人可能修改后的参数 final_args result.get(modified_params, tool_args) return await self._execute_tool(agent, tool_name, final_args) else: # 被拒绝抛出特定异常 raise ApprovalRejectedError(f工具 {tool_name} 的调用被审核人拒绝。理由{result.get(review_comment)}) except asyncio.TimeoutError: # 审核超时可以取消任务或执行默认策略如拒绝 await self.backend.update_task(task_id, {status: ApprovalStatus.CANCELLED}) raise ApprovalTimeoutError(f工具 {tool_name} 的审核超时。) finally: self.pending_tasks.pop(task_id, None) async def _execute_tool(self, agent, tool_name, args): # 实际执行工具的底层方法 tool_func getattr(agent, tool_name, None) if tool_func and callable(tool_func): return await tool_func(**args) else: raise ValueError(fTool {tool_name} not found or not callable.) async def handle_approval_callback(self, task_id: str, decision: ApprovalStatus, comment: str , modified_params: dict None): 处理来自审核界面的回调 if task_id not in self.pending_tasks: # 任务可能已超时被清理 return False task_info self.pending_tasks[task_id] future task_info[future] # 更新后端存储的任务状态 updates { status: decision, reviewed_at: datetime.now(), review_comment: comment, modified_params: modified_params } await self.backend.update_task(task_id, updates) # 唤醒被暂停的工作流 if not future.done(): future.set_result({ status: decision, review_comment: comment, modified_params: modified_params }) return True第三步集成到Agent工作流在你的主工作流或Orchestrator中在调用Agent的run或execute_tool方法前先经过中间件。# orchestrator.py class AgentOrchestrator: def __init__(self, hitl_middleware: HITLMiddleware): self.hitl_middleware hitl_middleware async def execute_agent_workflow(self, agent, initial_input): # ... Agent进行规划、思考 ... # 当Agent决定调用工具时 tool_to_call agent.decide_next_tool() tool_metadata self.get_tool_metadata(tool_to_call.name) try: # 通过HITL中间件来执行调用 result await self.hitl_middleware.intercept_tool_call( agentagent, tool_nametool_to_call.name, tool_argstool_to_call.arguments, tool_metadatatool_metadata ) agent.process_tool_result(result) except ApprovalRejectedError as e: # 处理被拒绝的情况例如让Agent重新规划 agent.handle_rejection(str(e)) except ApprovalTimeoutError as e: # 处理超时情况 agent.handle_timeout(str(e)) # ... 继续工作流 ...3.3 审核界面与回调接口你需要一个简单的Web界面供审核者使用。这个界面可以非常简洁核心是展示任务信息并提供“批准/拒绝”按钮。一个极简的审核API示例使用FastAPI# approval_api.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from .hitl_middleware import HITLMiddleware, ApprovalStatus app FastAPI() # 假设hitl_middleware已全局初始化 hitl_middleware: HITLMiddleware get_hitl_middleware() class ApprovalDecision(BaseModel): task_id: str decision: ApprovalStatus # approved or rejected comment: Optional[str] modified_params: Optional[dict] None app.post(/api/approval/decide) async def submit_approval_decision(decision: ApprovalDecision): success await hitl_middleware.handle_approval_callback( task_iddecision.task_id, decisiondecision.decision, commentdecision.comment, modified_paramsdecision.modified_params ) if not success: raise HTTPException(status_code404, detailApproval task not found or expired) return {status: success, message: fDecision {decision.decision} recorded.} app.get(/api/approval/task/{task_id}) async def get_approval_task(task_id: str): # 从后端存储获取任务详情用于前端展示 task await hitl_middleware.backend.get_task(task_id) if not task: raise HTTPException(status_code404, detailTask not found) return task前端界面就可以调用/api/approval/task/{task_id}获取详情并通过/api/approval/decide提交决定。审核链接可以直接嵌入到通知消息中。4. 实战中的关键细节与避坑指南理论架构和代码骨架看起来清晰但在实际部署和运营中你会遇到一系列具体问题。下面是我在项目中总结的几个关键点和避坑经验。4.1 审核任务的存储与生命周期管理存储选型对于任务量不大的场景使用关系型数据库如PostgreSQL即可便于查询和关联。如果任务量巨大且需要高并发可以考虑使用Redis存储短期任务或消息队列如RabbitMQ, Kafka的持久化功能。关键是要支持“查询-更新”的原子操作防止并发回调导致状态不一致。任务过期与清理一定要设置审核任务的超时时间如上面的wait_for。超时后任务状态应标记为CANCELLED或EXPIRED并释放相关资源。同时需要有一个后台清理进程定期删除过期很久的旧任务数据防止存储膨胀。上下文保存当工作流被暂停时整个Agent的会话状态Conversation Memory必须被完整保存下来以便在审核通过后能无缝恢复。这通常意味着你需要序列化整个Agent或工作流上下文并将其与审核任务ID关联存储。切忌只保存工具参数而丢失了对话历史否则恢复后Agent可能“失忆”。4.2 审核界面的用户体验设计信息呈现要清晰审核界面不应只是冰冷的JSON数据。应该将tool_name翻译成易懂的操作名称如“发送邮件”将tool_params格式化成友好的表单收件人、主题、正文分开显示并将agent_context调用理由突出显示。这能极大降低审核者的认知负担。支持参数修改这是HITL价值的重要体现。审核者不仅要说“不”更要说“这样改一下就可以”。界面应允许审核者直接编辑可修改的参数如邮件正文、金额数字并将修改后的版本传回。注意做好参数验证和转义防止注入攻击。操作记录与审计界面上应该清晰展示该任务的所有历史操作“何时创建”、“发送给谁”、“谁审核的”、“何时审核的”、“审核决定是什么”、“修改了什么”。这既是合规要求也能在出现争议时快速定位问题。4.3 通知策略与升级机制多渠道通知不要只依赖一种通知方式。结合邮件、即时通讯工具IM机器人、甚至短信进行通知。IM机器人通知适合需要快速响应的场景邮件则适合作为记录和备份。审批链与升级对于特别重要的操作可以设置多级审批。例如金额小于1000元直接主管审批大于1000元需要部门总监审批。当一级审批人超时未处理时系统应能自动升级到下一级或更高级别的审批人。特定人与群组在IM通知中使用功能直接提醒具体负责人比在群里发一个泛泛的通知有效得多。可以根据tool_metadata.approval_group动态决定谁。4.4 与现有审批流系统集成如果你的公司已经有成熟的OA或BPM业务流程管理系统如钉钉审批、飞书审批、企业微信审批强烈建议将HITL审核任务对接过去而不是自己重造轮子。这样做的好处是用户零学习成本审核者使用他们最熟悉的审批界面。利用现有权限体系审批人、抄送人、审批流都直接复用OA系统的配置。流程更强大可以天然支持会签、或签、条件分支等复杂审批逻辑。实现方式通常是当需要审核时调用OA系统的API创建一条审批实例并将审核详情作为表单内容。审批结束后OA系统回调你的HITL服务提供的Webhook。你只需要专注于“创建审批单”和“处理回调”这两端即可。5. 高级模式与优化策略当基础HITL稳定运行后可以考虑以下优化让系统更智能、更高效。5.1 基于LLM的预审核与建议完全依赖人工审核可能成为瓶颈。可以引入一个“预审核”Agent或称为“助理审核员”。它的工作流程是当主Agent产生一个待审核任务时先将其发送给“预审核Agent”。预审核Agent也是一个LLM它被赋予审核策略和公司知识库对任务进行初步分析。预审核Agent可以给出建议“建议批准因为参数合规且与历史成功案例相似度达95%”或者“建议拒绝因为收件人邮箱域名不在白名单内并提示审核人检查”。将这个建议连同原始任务一起呈现给人类审核者。人类审核者可以参考AI建议快速决策大大提升了审核效率。这本质上是将HITL从“人做决策”部分演进到了“人机协同决策”。5.2 审核反馈的闭环学习HITL过程中产生的人类决策批准/拒绝 修改是极其宝贵的训练数据。可以定期收集这些数据用于微调LLM让主Agent学会在什么情况下它的提议更容易被批准从而在未来减少不必要的审核触发。优化工具描述如果某个工具频繁因为参数含义模糊而被拒绝修改说明它的描述description需要更清晰。发现流程缺陷集中分析被拒绝的任务可能会发现业务流程本身的设计漏洞从而推动业务优化。5.3 动态审核策略不是所有调用同一工具的任务都需要审核。可以设计更精细化的策略基于参数的策略send_email工具只有当收件人是外部域名或邮件内容包含“合同”、“付款”等关键词时才触发审核。基于上下文的策略在同一个会话中如果用户已经明确说过“我确认请发送”那么后续的发送操作可以免审。基于置信度的策略如果Agent在调用工具时自身生成的“理由”置信度分数很低可以通过LLM自评或另一个验证模型评分则强制进入审核。实现动态策略需要在HITLMiddleware.intercept_tool_call中增加一个策略评估层根据工具、参数、上下文实时计算是否需要审核。6. 常见问题与故障排查实录在实际运行中你肯定会遇到各种意想不到的问题。这里记录了几个典型问题及其解决方法。问题一工作流暂停后如何保证服务重启后不丢失任务这是生产环境必须考虑的问题。我们的HITLMiddleware中使用了内存字典pending_tasks来关联任务ID和Future服务重启后这些内存状态会全部丢失。解决方案不能依赖内存状态。当创建审核任务时除了在ApprovalBackend中存储任务元数据还应将整个工作流引擎的检查点Checkpoint序列化后一并存储。检查点应包含所有Agent的状态、对话历史等。当审核回调回来时先从存储中加载检查点重新实例化工作流引擎并恢复到暂停点然后再执行后续操作。这要求你的工作流引擎支持序列化/反序列化。问题二审核人想和Agent“对话”以获取更多信息再做决定怎么办有时审核者光看参数和理由还不足以决策需要询问Agent“你为什么认为这个客户是高风险”解决方案在审核界面提供一个“询问Agent”的聊天窗口。当审核者提问时系统实际上是将问题作为新的用户输入注入到被暂停的那个工作流会话中让Agent基于当时的完整上下文进行回答并将答案返回给审核界面。这相当于在审核环节临时激活了被暂停的Agent进行一轮对话。实现此功能需要更复杂的上下文管理和状态恢复机制。问题三如何防止审核成为系统的单点故障或性能瓶颈如果所有关键操作都卡在人工审核且审核人响应慢整个系统吞吐量会急剧下降。解决方案设置超时与默认策略如前述每个审核任务必须有超时时间。超时后执行预设的“安全默认操作”通常是拒绝并通知相关人员。实现审核负载均衡根据工具类型或业务模块将审核任务路由给不同的审核组或人员避免任务堆积在个别人身上。提供批量审核功能对于低风险、模式化的任务如内容标签审核可以提供列表界面让审核者可以一键批准或拒绝多个相似任务。持续优化审核策略通过分析数据将那些通过率极高如99%且风险极低的操作从“强制审核”名单中移除改为“执行后抽查”或“免审”逐步扩大Agent的自主权。问题四审核日志如何有效查询和分析运营一段时间后你会需要回答“上个月哪个工具被拒绝最多”“平均审核时长是多少”解决方案在设计ApprovalTask数据模型时就要考虑到分析需求。除了基本字段可以记录业务类型、触发Agent、初始参数快照、最终参数快照、审核耗时等。将这些数据同步到数据仓库或ELK栈中便可以方便地制作报表和仪表盘用于监控HITL系统的健康度和优化审核策略。实现一个健壮、易用的HITL机制是MAF Agent项目从演示原型走向生产系统的关键里程碑。它不是在给AI套上枷锁而是在建立人机之间可靠的协作桥梁。通过合理的架构设计和细致的用户体验打磨HITL能让你的Agent系统既保持自动化效率又具备人类智慧的把关能力最终在真实的业务场景中创造稳定可靠的价值。