ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

办公Agent旁路接管机制:从全自动到人工审核的工程实践

办公Agent旁路接管机制:从全自动到人工审核的工程实践 最近一年办公 agent 从“能聊天的玩具”变成了“能替你发邮件、订会议、写周报、走审批”的干活助手。但真把它放进企业流程里很多人会发现一个尴尬时刻agent 在处理 80% 的常规任务时表现不错剩下的 20% 却可能让一封邀请函群发给全公司或者把报销单据错误地打回三次。这个问题的根源不是模型不够聪明而是我们把它设计成了“一条路走到黑”。正确做法是给 agent 装上旁路接管机制当它遇到低置信度、高影响、权限模糊的任务时自动把控制权交还给人工。今天这篇文章就把这套“自动执行 旁路接管 人工审核 审计回滚”的设计方法完整拆开讲。本文以“小龙”作为示例办公 agent 的代称重点不是评价某个具体产品而是讲清楚一套可以直接落地的工程方案为什么 agent 需要被“绕过”、旁路系统怎么设计、最小原型怎么写、上线前要盯哪些坑。1. 先厘清办公 agent 的边界在哪很多人对办公 agent 的理解还停留在“RPA 换个名字”。两者确实都做自动化但有一个关键差异RPA 按照固定脚本执行每一步都是人预先定义好的办公 agent 则有自主决策能力它可以根据当前输入动态选择调用哪个工具、生成什么内容、发给谁、什么时候发。自主决策带来灵活性也带来责任问题当 agent 自作主张做了一件错事谁来负责这个问题的答案决定了办公 agent 不能做成“全自动无人值守”必须留人类可接管的口子。我把办公 agent 和传统自动化的边界整理成一张表对比维度RPA 脚本传统 BPM 工作流办公 agent决策来源规则写死流程节点固定模型根据上下文动态决策处理异常报错停机流转到人工节点自己尝试换工具 / 换策略风险本质逻辑写错流程设计问题决策不可完全预测可控性高高中需要旁路兜底适合任务高频固定操作跨部门流程非结构化文本处理、判断、生成理解这张表是理解“绕过办公 agent”的前提我们要绕过的是 agent 的“全自动自主决策”这条默认路径而不是绕过整个自动化能力。2. 办公 agent 最典型的四个“翻车现场”先说场景再讲方案。否则你很难体会为什么要费劲做旁路接管。2.1 邮件群发失误agent 拿到了“给相关同事同步项目进展”的任务结果它从通讯录里选了所有带“项目”关键词的人把内部讨论草稿发出去了。影响范围可能是几十人也可能是几百人。旁路触发条件收件人数超过阈值、邮件包含内部敏感词、发送时间在非工作时间、正文置信度低。2.2 日程冲突反复修改agent 帮你订会议但它看不到某些同事的忙闲细节或者只读到日历摘要。它连续三天重复安排同一个会议被参会人当成了 bug。旁路触发条件同一主题会议重复出现、被邀请人数量大、会议室资源冲突、用户没有明确授权改日历。2.3 报销审批误判报销流程里agent 依据“金额超过 5000 需要总监审批”这条规则来做判断。但发票里存在一张 50000 的发票和一张 500 的发票时它可能只检查了总数就通过了审批。旁路触发条件单笔金额超限、发票数量异常、发票抬头与提交人不一致、规则引擎产出低置信度结果。2.4 纪要内容越权分发会议纪要是 agent 自动整理的它可以准确总结出“这个项目预算还有 20% 余量”这样略带敏感的信息。如果纪要分发范围判断错误这条内容可能被发给普通协作组。旁路触发条件文档权限不可见、纪要含预算/人名/未公开数据、分发列表与实际参会人不匹配。这四个场景的共同点是错误不是“程序崩溃”式的而是“看起正确的错误”。这也是办公 agent 比普通自动化更危险的地方也是旁路接管必须存在的原因。3. 所谓“绕过”其实是双通道架构回到标题小龙“绕过”办公 agent。这里必须澄清一个理解误区不是攻击意义上的绕过不是去破解 agent 的限制而是在工程上设计一条旁路路由当 agent 的默认主路径不适用时流程自动切换到人工接管通道。完整的系统由三个层次组成。第一层是策略前置在 agent 接收任务之后、调用外部工具之前插入一个规则判断层。这个层不看模型输出内容而是看任务本身的属性影响范围、操作类型、历史相似任务的处理结果、当前模型置信度。第二层是人工接管当任务被标记为“需要人工确认”系统把上下文、候选动作、风险说明打包发给审核人。审核人可以选择通过、修改后通过、拒绝。拒绝后可以触发回滚动作。第三层是审计与回滚所有 agent 操作、旁路触发原因、人工审核结果、执行结果都要记录。关键操作用例提供“撤销”入口例如邮件撤回、日程删除、审批重置。下面用一张 ASCII 流程图来表示整体结构方便后面对照代码看任务输入 | v [策略前置判断] ---- 低风险 高置信度 ------- [agent 自动执行] - [记录审计日志] - 结束 | | 高风险 / 低置信度 / 权限模糊 v [旁路接管调度器] | v [人工审核工作台] |-- 通过继续执行 / 或修改后执行 |-- 拒绝终止操作必要时执行回滚 |-- 修改人工修改参数后再交给 agent | v [审计日志 监控指标]这套架构在开发上的成本并不高但它能把 agent 事故从“出了事到处救火”变成“出事前被拦下来”。4. 最小原型给“小龙”装上旁路接管下面用一个最小可运行原型的 Python 代码演示旁路接管怎么落地。这里不依赖任何特定大模型 SDK只模拟 office agent 的核心调度逻辑接口调用处留好替换位置。版本以实际环境为准本示例用 Python 3.10。4.1 目录结构xiaolong_agent/ ├── config.json ├── agent_core.py ├── main.py └── audit.log4.2 配置旁路规则任务是否有风险可以通过一个配置 JSON 来表达。风险等级按高high、中medium、低low划分。{ agent_name: xiaolong, bypass_rules: { email_send: { max_recipients: 10, allowed_hours: [9, 18], risk_if_contains: [预算, 内部, 机密, 未公开] }, meeting_create: { max_attendees: 20, max_duplicate_count: 1 }, expense_approve: { single_amount_limit: 5000, invoice_count_limit: 5 } } }config.json 里的规则会在 agent 执行动作前被加载用于计算旁路触发结果。这个文件的价值在于调整规则不需要改代码运营或安全团队可以直接改配置改完生效。4.3 核心调度逻辑把旁路判断封装成一个独立模块方便以后接真实的 LLM 调用。# 文件路径xiaolong_agent/agent_core.py import json import logging from dataclasses import dataclass, field from datetime import datetime from typing import Any logging.basicConfig(levellogging.INFO, format%(asctime)s %(message)s) logger logging.getLogger(xiaolong) dataclass class TaskContext: task_id: str action: str params: dict[str, Any] confidence: float 0.8 created_at: str field(default_factorylambda: datetime.now().isoformat()) class BypassDecision: AUTO_EXECUTE auto_execute MANUAL_REVIEW manual_review BLOCKED blocked class RuleEngine: def __init__(self, config_path: str config.json): with open(config_path, r, encodingutf-8) as f: self.config json.load(f) self.rules self.config.get(bypass_rules, {}) def evaluate(self, ctx: TaskContext) - dict: 根据任务动作匹配对应的旁路规则返回风险等级和建议动作。 rule self.rules.get(ctx.action, {}) if not rule: # 未配置规则的动作默认走人工审核宁可慢一点不可乱来 return {risk: medium, decision: BypassDecision.MANUAL_REVIEW, reason: no_rule} risk_points [] # 邮件发送规则 if ctx.action email_send: recipients ctx.params.get(recipients, []) if len(recipients) rule.get(max_recipients, 10): risk_points.append(recipient_count_exceeded) content ctx.params.get(content, ) for keyword in rule.get(risk_if_contains, []): if keyword in content: risk_points.append(frisk_keyword_{keyword}) break hour datetime.now().hour allowed rule.get(allowed_hours, [0, 23]) if hour allowed[0] or hour allowed[1]: risk_points.append(outside_allowed_hours) # 会议创建规则 elif ctx.action meeting_create: attendees ctx.params.get(attendees, []) if len(attendees) rule.get(max_attendees, 20): risk_points.append(attendee_count_exceeded) # 报销审批规则 elif ctx.action expense_approve: amount ctx.params.get(amount, 0) if amount rule.get(single_amount_limit, 5000): risk_points.append(amount_over_limit) if risk_points: return {risk: high, decision: BypassDecision.MANUAL_REVIEW, reason: ;.join(risk_points)} if ctx.confidence 0.5: return {risk: medium, decision: BypassDecision.MANUAL_REVIEW, reason: low_confidence} return {risk: low, decision: BypassDecision.AUTO_EXECUTE, reason: pass} # 下面的函数只是示例占位真实项目中替换为邮件 API、日历 API 等 def send_email(params: dict) - None: logger.info(模拟发送邮件收件人%s 主题%s, params.get(recipients), params.get(subject)) def create_meeting(params: dict) - None: logger.info(模拟创建会议主题%s 时间%s, params.get(subject), params.get(time)) def approve_expense(params: dict) - None: logger.info(模拟审批报销单据号%s, params.get(expense_id)) ACTION_MAP { email_send: send_email, meeting_create: create_meeting, expense_approve: approve_expense, } class AgentRunner: def __init__(self): self.engine RuleEngine() def submit(self, ctx: TaskContext) - dict: result self.engine.evaluate(ctx) decision result[decision] reason result[reason] logger.info(task_id%s action%s decision%s reason%s, ctx.task_id, ctx.action, decision, reason) if decision BypassDecision.AUTO_EXECUTE: ACTION_MAP.get(ctx.action)(ctx.params) self._write_audit(ctx, result, statusauto_executed) elif decision BypassDecision.MANUAL_REVIEW: # 真实系统中这里会推送一条消息到审批工作台 logger.warning(task_id%s 需要人工审核请处理, ctx.task_id) self._write_audit(ctx, result, statuswaiting_manual_review) else: self._write_audit(ctx, result, statusblocked) return result def manual_review(self, ctx: TaskContext, approved: bool) - None: if approved: ACTION_MAP.get(ctx.action)(ctx.params) self._write_audit(ctx, {decision: BypassDecision.AUTO_EXECUTE, reason: manual_approve}, statusmanual_approved) else: self._write_audit(ctx, {decision: BypassDecision.BLOCKED, reason: manual_reject}, statusmanual_rejected) def _write_audit(self, ctx: TaskContext, result: dict, status: str) - None: with open(audit.log, a, encodingutf-8) as f: f.write(f{datetime.now().isoformat()} | {ctx.task_id} | {ctx.action} | {status} | {result.get(reason)}\n)核心逻辑不复杂先跑规则引擎根据风险点返回决策自动执行就调用对应动作需要审核就走人工接管并在最后写审计日志。4.4 主程序入口主程序用于模拟任务提交和人工审核方便直接在终端跑通完整链路。# 文件路径xiaolong_agent/main.py from agent_core import AgentRunner, TaskContext def main(): runner AgentRunner() # 场景一低风险自动执行 task1 TaskContext( task_idTASK-001, actionemail_send, params{recipients: [zhangexample.com, liexample.com], subject: 周报同步, content: 本周进度正常无敏感信息}, confidence0.9, ) runner.submit(task1) # 场景二超过收件人数阈值触发旁路接管 task2 TaskContext( task_idTASK-002, actionemail_send, params{recipients: [fuser{i}example.com for i in range(50)], subject: 全员通知, content: 请大家关注项目进展某些数据还未公开}, confidence0.7, ) result2 runner.submit(task2) print(TASK-002 决策结果, result2) if __name__ __main__: main()5. 运行与验证如何判断旁路生效在xiaolong_agent目录下执行python3 main.py预期输出应该包含类似下面的内容INFO ... task_idTASK-001 actionemail_send decisionauto_execute reasonpass INFO ... 模拟发送邮件收件人[zhangexample.com, liexample.com] 主题周报同步 WARNING ... task_idTASK-002 需要人工审核请处理 TASK-002 决策结果 {risk: high, decision: manual_review, reason: recipient_count_exceeded}判断旁路系统是否生效主要看三点TASK-001 正常自动执行说明规则没有把所有任务都拦下来。TASK-002 被判定为manual_review说明超过收件人数阈值时旁路成功触发。audit.log文件里有两行记录说明审计链路正常。如果 TASK-002 没有被拦下来优先检查config.json的max_recipients是否被正确读取以及任务里的recipients是否以列表形式传入。人工接管流程验证可以采用下面代码独立跑一遍python3 -c from agent_core import AgentRunner, TaskContext; r AgentRunner(); t TaskContext(TASK-003, expense_approve, {amount: 80000, expense_id: EXP-888}); r.submit(t); r.manual_review(t, approvedTrue)这会先触发报销超限的旁路再模拟人工同意后执行。能看到审计日志出现manual_approved说明人工接管这条链路没有问题。6. 常见问题与排查思路问题现象可能原因排查方式解决方案所有任务都被拦下规则里allowed_hours配置过窄或默认规则缺失查看audit.log的reason是否集中在no_rule为高频动作补充明确规则校准阈值危险任务未被拦下params结构变化规则取不到关键字段在RuleEngine.evaluate中打印ctx.params对入参做 schema 校验统一字段命名人工审核后操作重复执行同一 task 在审批前后被重复提交给 task_id 增加幂等表或内存去重集合在操作执行前检查 task_id 是否已被处理规则改了不生效进程启动时加载了旧配置确认是重新加载还是常驻进程将配置文件改为外部配置中心或监听文件变更审计日志缺少回滚信息回滚动作没有走统一写日志入口检查回滚函数是否只做了 action 调用所有动作回滚统一由 AuditManager 记录7. 生产环境最佳实践原型可以跑通不代表可以直接上生产。下面几条是我认为必须提前想清楚的工程建议。7.1 权限最小化agent 的 API 密钥不应该拥有“删除全部邮件”“修改所有日历”这类权限。给 agent 的权限应该比普通员工还小宁可运行时报错也不要拿到过度权限。旁路接管的目的就是让人在权限边缘介入而不是让 agent 在权限边缘自由发挥。7.2 旁路阈值不能拍脑袋阈值要来自历史任务分布。比如过去一个月邮件发送人数平均是 5 人P95 是 12 人那max_recipients可以设置为 15。不要一开始就设 100否则旁路形同虚设。阈值上线后要统计“旁路触发率”触发率太低说明规则太松太高说明 agent 处理能力太弱。7.3 审计日志必须是追加型审计不是调试日志不能被随意覆盖。生产环境建议把审计日志写到独立的存储例如对象存储或者日志系统只允许追加不允许修改。它记录的不仅是 “agent 做了什么事”还有 “为什么做这件事谁批准了这件事”。7.4 关键操作要支持回滚旁路接管可以拦住一部分问题但人工审核也可能出错。因此邮件撤回、日程删除、审批状态重置这类回滚接口要提前实现。实现回滚比实现主流程麻烦但不能省略。7.5 灰度上线不要第一天就让 agent 自动发全员邮件。建议分三个阶段影子模式agent 产出建议但不执行真实操作。半接管模式低风险任务自动执行高风险任务走人工审核。正式模式观察两周旁路触发率和误操作率后逐步放开。7.6 监控指标建议至少监控以下指标指标含义正常参考范围以实际业务为准旁路触发率需要人工审核的任务占比5% - 20%人工审核通过率人工同意 agent 决策的比例60% - 90%自动执行成功率未触发旁路的任务执行成功率95% 以上平均审核时长人工响应速度视业务要求回滚率操作后被回滚的比例控制在 1% 以下旁路触发率太高说明模型能力或规则配置有问题太低则说明存在漏网风险。通过监控看趋势比看单日绝对值更有意义。8. 总结与后续方向办公 agent 的核心问题从来不是“能不能自动完成”而是“在自动化过程中人还有没有机会在关键决策点参与”。本文以“小龙”为例解释了旁路接管的必要性给出了策略前置、人工接管、审计回滚三层架构并用一个最小 Python 原型跑通了自动执行、旁路触发、人工审批和审计记录四条链路。如果你想继续深入有三个方向值得关注第一个是规则引擎升级。本文用的是静态 JSON 规则实际项目里建议用支持表达式和优先级冲突检测的规则服务例如 Drools 或自研 Rule DSL。第二个是置信度校准。真实 LLM 返回置信度不能直接用需要结合任务历史成功率做校准。agent 在“上一次类似任务失败过”的情况下即使模型置信度很高也要提高旁路触发概率。第三个是审批工作台集成。人工接管不能只停留在日志里需要和企业微信、钉钉、飞书等审批流打通。审核人看到的不只是一个“是否通过”的按钮而是任务的完整上下文agent 想做什么、为什么触发旁路、历史类似任务结果如何。回到标题小龙真正要“绕过”的不是 agent 里的某个规则而是“全自动无人值守”这个隐患。在 agent 越来越强的时代给人留一条可控的、能随时介入的旁路才是自动化系统真正成熟的样子。建议把今天的原型代码收藏起来下个项目里加一个旁路开关试试。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进