用botmux把Agent审批搬到飞书,告别电脑前等待
2026/8/30 17:53:30 网站建设 项目流程

你是不是也遇到过这种场景:Agent 任务在服务器上跑得好好的,突然卡住了。你看一眼手机里的日志推送,原来是 Agent 在执行一个高风险操作,需要人工确认。它等你授权,而你不在电脑旁边。你能想象这个画面吗?代码写完了、环境也配好了,Agent 到了“临门一脚”,却被一个权限点卡住,直到你赶回工位点一下回车或点击“允许”。

更让人难受的是,这种打断不是一次两次。跑一个大的 Agent 任务,可能在午休时弹一次,在通勤路上弹一次,在晚上下班后又弹一次。你反复被拉回电脑面前,只为点一个“确认继续”。

如果只看表面,很容易误以为这是“安全设计太啰嗦”。但深一层看,真正的瓶颈其实是:Agent 的执行流和人的审批流被绑在了同一个物理位置。明明已经可以用手机办公了,审批却还得回到电脑。这就是 botmux 这一类工具存在的意义:把 Agent 的权限交互,从电脑屏幕搬到飞书消息里。

这篇文章会讲清楚 botmux 是什么、它的核心架构、为什么选择飞书作为控制平面,然后直接给出一个可以跑通的示例:创建飞书应用、配置事件订阅、部署 botmux 服务、接入 Agent、用手机在飞书上点击“允许”或“拒绝”。

1. 被“回电脑点授权”打断的 Agent 工作流

先说一个真实的工作流困境。很多 Agent 框架为了安全,会在执行敏感指令前要求用户确认。比如:

  • 删除文件或清空目录;
  • 执行一条可能影响线上服务的命令;
  • 调用第三方的付费 API;
  • 修改生产环境的配置;
  • 发布代码。

当 Agent 遇到这些操作时,它会暂停执行,等待用户确认。这个设计的初衷没问题:避免机器在无人监督的情况下做出破坏性动作。真正的问题出在交互方式上。

大多数本地运行的 Agent 框架,确认交互是在终端里完成的。终端在电脑上,所以你必须在电脑前。一旦人不在电脑旁,整个 Agent 流程就被“卡死”。等待期间,Agent 不干活、不推进、不自己判断,因为设计上不允许它跳过授权。

这种模式有几类明显问题:

第一,响应及时性差。一个需要五分钟就能完成的审批,可能因为人不在电脑前,拖了半小时甚至更久。Agent 本来能帮你节省时间,结果反而因为等待审批变得更慢。

第二,中断率高。如果 Agent 任务涉及多个工具调用,每个工具调用都可能触发一次授权。次数一多,你很难一直守在电脑旁。

第三,多 Agent 场景更难管理。如果你同时跑五个 Agent,每个都可能在不同时间点请求授权。你需要在多个终端窗口之间来回切换,容易漏掉、误点。

第四,缺乏审计记录。终端里弹出的确认窗口,没有统一留痕。事后复盘某个 Agent 到底执行了什么,你只能翻历史日志,而且不一定找得到完整的授权链路。

我个人的判断是:Agent 发展的下一个关键,不再只是模型有多聪明,而是“人在环上”的交互设计有多顺滑。如果人的审批链路是顺畅的,Agent 就能长时间自主运行,只在真正需要的时候打断人。如果审批链路是笨重的,Agent 就会被“硬件设备”绑架,跑不远。

botmux 解决的正是这个问题。它不是一个 Agent 框架,也不是一个模型,而是一个连接层:把 Agent 的权限请求路由到飞书,把人通过飞书反馈的结果带回给 Agent。

2. botmux 是什么:一条连接飞书与 Agent 的消息总线

“botmux”这个名字,可以拆成两部分理解。“bot”指机器人或 Agent 进程,“mux”是多路复用(multiplex)的缩写。所以 botmux 本质上是一个机器人多路复用网关:它负责管理多个 Agent 与用户之间的通信、权限确认和指令路由。

你可以把它理解成 Agent 世界的“前台接线员”。Agent 不直接面对用户,它把请求发给 botmux,botmux 决定这条请求应该发给谁、用什么格式、需要什么审批级别。用户通过飞书做出的回应,也由 botmux 负责接收并转回给对应的 Agent。

从技术定位来看,botmux 属于控制平面(Control Plane)和执行平面(Execution Plane)之间的中间层。Agent 的运行环境,是执行平面,负责真正干活;飞书上的消息和卡片,是控制平面,负责人的决策。没有 botmux 时,控制平面和执行平面耦合在一起;有 botmux 后,两者通过 API 解耦。

那么,botmux 到底做了什么?

从功能上看,它至少包含四个核心模块。

第一个是消息路由模块。多个 Agent 可以注册到 botmux 上,每个 Agent 有一个自己的 ID。当 Agent 发起请求时,botmux 会根据 agent_id 找到对应的回调地址、审批人列表和审批渠道。

第二个是审批流模块。botmux 内部维护一个“待审批请求表”。Agent 的每个权限请求会生成一个唯一的 request_id,绑上 action、detail、callback 和超时时间。用户审批后,botmux 会根据 request_id 触发回调,把结果返回给 Agent。

第三个是渠道适配模块。botmux 不限定只能接飞书,理论上可以接钉钉、企业微信、Slack 等。微信公众号、钉钉、飞书的机器人接口各有差异,botmux 通过适配器屏蔽了这些差异。对于开发者来说,只需要关心业务层面的配置,不需要关心各个平台的 API 细节。

第四个是审计与日志模块。每一次审批请求、审批结果、超时情况都应该被记录。这样,当 Agent 执行出现问题时,可以回溯到具体的授权环节,判断是谁批准了什么操作。

用一句话概括:botmux 把“人确认 Agent 操作”这个动作,从靠位置的交互,变成了靠消息的交互。

它与远程桌面不同。远程桌面是把整个电脑画面搬到手机里,你看到的还是终端窗口,还是要去找那一个待确认的按钮。botmux 则把“是否允许执行”这个信息单独提炼出来,用结构化的卡片消息推送到飞书,把审批成本降到最低。

它与自动跳过审批也完全不同。自动跳过等于放弃安全边界,风险很高。botmux 不是让你取消审批,而是让审批更快、更便捷、更可控。人仍然是决策的主体。

3. 为什么控制平面选飞书

可能有人会问:为什么控制平面选飞书,而不是自己做一个 Web 管理后台?也不是不行,但飞书有几个实际优势。

第一,飞书本身就是高频办公工具。审批动作通常发生在工作间隙,而不是专门打开一个后台页面。如果审批入口在飞书里,你随时都能看到,不需要额外下载和登录一个独立系统。消息推送会主动通知你,比自己去刷后台高效得多。

第二,飞书机器人支持交互式卡片。这是非常关键的一点。一个授权确认不只包含“同意”和“拒绝”两个按钮,你可能还需要看到:Agent 要执行什么命令?涉及哪个文件?目标环境是什么?在飞书卡片上,这些信息可以结构化展示,按钮的动作值也可以携带 request_id、decision 等参数。用户点一下按钮,卡片回调就带着上下文回到 botmux,省略了一大堆解析工作。

第三,飞书开放平台的事件订阅机制比较成熟。机器人可以接收用户消息、卡片交互、加群事件等。botmux 通过飞书事件订阅,可以实时感知用户的操作并做出响应。相比轮询,这种机制更及时,也更省资源。

第四,飞书在团队协作中的渗透率比较高。如果你的 Agent 服务需要团队共用,飞书群本身就是一个天然的审批中心。你可以把某个 Agent 的审批人配置成群成员,或指定某个群为审批群。审批记录也能在群消息里留存,方便追溯。

有人会担心:如果团队不用飞书怎么办?这个顾虑很正常。botmux 的设计思路并不绑定某个特定平台。只要渠道适配器实现对应的接口,把飞书换成钉钉、企业微信,或者自研的消息系统,改动成本是可控的。你真正需要理解的是“审批消息化”这个模式,而不只是某一个平台的配置。

当然,飞书也有一些值得注意的边界。比如机器人应用需要企业管理员审批开通,权限范围需要合理配置。另外,飞书开放平台的部分能力需要企业认证后才能使用。这些问题不是 botmux 能替你解决的,属于使用飞书本身的成本。

4. 整体架构与消息流转模型

在动手写代码之前,先把架构讲清楚。下面这组组件是 botmux 模式的核心:

组件作用代表实现
Agent 执行进程运行实际任务,遇到敏感操作时发起审批请求本地 Python 进程、OpenClaw、自研 Agent
botmux 核心管理 Agent 注册、审批请求路由、超时和回调botmux 服务
渠道适配器对接具体消息平台,负责发送卡片、接收回调飞书适配器
消息平台把审批内容呈现给用户,收集用户决策飞书
审计存储记录审批请求、审批结果、超时事件MySQL、SQLite、飞书多维表格

一个典型的审批流转过程如下:

  1. Agent 执行到某一步,判断需要人工授权。
  2. Agent 调用 botmux API,传入请求内容,例如“执行 rm -rf /tmp/cache”。
  3. botmux 生成 request_id,并写入 pending_requests,将请求标记为“等待审批”。
  4. botmux 调用飞书适配器,向指定的用户或群发送一张审批卡片,卡片包含操作说明和两个按钮:“允许”和“拒绝”。
  5. 用户在飞书上点击“允许”。
  6. 飞书平台把卡片回调事件推送到 botmux。
  7. botmux 校验事件签名,解析出 request_id 和 decision。
  8. botmux 在 pending_requests 中找到对应的 Future 或等待对象,把决策结果写回。
  9. botmux 向 Agent 返回 HTTP 响应,内容包含 decision=allow。
  10. Agent 收到结果,继续执行后续逻辑。

从时序上看,Agent 侧发起的请求是同步等待的。也就是说,Agent 发送审批请求后,就保持连接挂起,直到 botmux 返回结果。如果用户在飞书上一直不点,那么这个请求会在超时时间之后返回“超时”状态,Agent 根据业务决定退出还是跳过。

这里真正容易踩坑的地方是:一个 Agent 任务可能在短时间内发起多个审批请求,如果只用 request_id 做标识,但要保证全局唯一。设计上不能用 agent_id + action 作为主键,因为同一个 action 可能被执行两次。更稳妥的做法是每次审批都生成一个 UUID。

另一个容易踩坑的地方是:飞书的回调事件可能由于网络抖动重复推送。botmux 在解析回调时必须做幂等处理。同一个 request_id 的回调,如果已经处理过一次,后续重复到达时需要直接忽略,不能重复触发 Agent 的同一段逻辑。

5. 环境准备与前置条件

下面进入实操阶段。为了让示例跑通,需要准备以下环境。

  • 操作系统:Linux 或 macOS,建议 Linux 云服务器,毕竟你的 Agent 很可能跑在服务器上。
  • 运行环境:Python 3.9 以上,用于跑 botmux 服务端和 Agent 示例。
  • 依赖管理:pip 或 Poetry,按你的习惯选择。
  • 消息平台:飞书开放平台账号,具备创建企业自建应用的权限。
  • Agent 框架:本文不限定具体框架,用简单 Python 脚本演示接入逻辑。如果你想接 OpenClaw,需要用类似的方式调用 botmux API。

关于版本,这里说明一下:不同项目的安装方式和依赖版本会有差异。下面演示的代码重点在于讲解实现思路,具体的版本号请以实际项目文档为准,不建议直接照搬。

建议先在一个隔离的测试环境中操作,避免影响已有的 Agent 服务。如果你打算在生产环境接入,最好先用一台独立的测试机器完成验证。

6. 飞书开放平台应用配置

botmux 要和飞书通信,第一步是创建飞书应用。

在飞书开放平台后台,选择“创建企业自建应用”,填写应用名称和描述。创建完成后,进入应用详情页,依次完成以下配置。

6.1 添加机器人能力

在“应用能力”中找到“机器人”,启用机器人能力。之后应用才具备在群聊或单聊中收发消息的权限。启用后,你会看到一个机器人,它可以被添加到群聊中。

6.2 配置事件订阅

这一步比较关键。botmux 需要接收两类事件:

  • 用户发送给机器人的消息事件;
  • 用户在卡片上点击按钮产生的交互回调。

在“事件订阅”页面,有两种接入模式:长连接模式和 Webhook 模式。

长连接模式的优势是不需要暴露公网 IP,botmux 通过 WebSocket 和飞书保持长连接。适合部署在私网环境、没有公网入口的服务器。Webhook 模式则需要一个公网可访问的 HTTPS 地址,飞书平台会把事件 POST 到这个地址。

从工程实践看,个人部署推荐长连接模式,省去公网和域名配置。企业级部署如果已经有网关,Webhook 模式会更灵活。本文示例用的是事件接收框架,你可以按自己的场景选择,代码逻辑差异不大。

6.3 配置权限范围

要让机器人发送消息,需要申请以下权限:

  • im:message读取用户发给机器人的消息;
  • im:message:send_as_bot以机器人身份发送消息;
  • 如果需要读取用户信息,可以追加contact:user.base:readonly

权限申请后需要发布版本并等待管理员审核。在测试阶段,也可以先使用企业内自建应用提供的测试权限,但要注意权限生效时间和范围。

6.4 获取密钥信息

完成以上配置后,在“凭证与基础信息”页面可以拿到:

  • App ID,格式类似cli_xxxx
  • App Secret;
  • 事件订阅中的 Encrypt Key 和 Verification Token。

这些信息需要在 botmux 配置文件中填写。实际操作中,App Secret 和 Encrypt Key 应该存在环境变量或密钥管理服务里,不要直接写死在代码仓库。

7. botmux 服务端搭建与授权流转实现

下面开始搭建 botmux 服务端。我用 FastAPI 作为示例框架,因为它写异步接口比较简洁。

在项目目录下创建虚拟环境,并安装依赖:

python -m venv venv source venv/bin/activate pip install fastapi uvicorn httpx python-dotenv

然后创建 botmux 的配置文件。这里用 YAML 保存 Agent 注册信息和飞书配置。如果项目提供了配置模板,以项目模板为准。

# config/botmux.yaml server: host: "0.0.0.0" port: 7080 feishu: app_id: "cli_xxxx" app_secret: "your_app_secret" encrypt_key: "your_encrypt_key" verification_token: "your_verification_token" # long_connection 表示长连接模式,webhook 表示接收飞书回调 mode: "long_connection" agents: - id: "code-agent" name: "代码 Agent" # 审批结果将发送到这个飞书用户 approver: "ou_xxxx" timeout_seconds: 300 - id: "data-agent" name: "数据 Agent" approver: "ou_yyyy" timeout_seconds: 600

这里解释一下配置项的含义。server.hostserver.port是 botmux 服务的监听地址。feishu部分存放飞书开放平台的应用凭证。agents列表声明了允许接入的 Agent,每个 Agent 都有独立的审批人。timeout_seconds表示用户如果长时间不操作,审批请求超过该时间后自动超时。

接下来是服务端主代码。我把 pending approval 的存储放在内存里,用 asyncio.Future 配合超时控制。

# app/main.py import asyncio import uuid from typing import Dict from fastapi import FastAPI, Request from pydantic import BaseModel app = FastAPI() # 存储待审批请求。key: request_id, value: asyncio.Future pending_requests: Dict[str, asyncio.Future] = {} class ApprovalRequest(BaseModel): agent_id: str action: str detail: str timeout: int = 300 callback_url: str class ApprovalResponse(BaseModel): request_id: str decision: str reason: str = "" async def push_to_feishu(msg_dict: dict): """ 向飞书发送审批卡片。 这里需要改成你的飞书适配器实现: 调用飞书开放平台接口,发送含审批按钮的卡片。 """ # 实际项目中,这里用飞书 SDK 或自己实现的 HTTP 调用 print("[feishu] send message:", msg_dict) @app.post("/botmux/v1/approval-request") async def create_approval_request(req: ApprovalRequest): request_id = uuid.uuid4().hex loop = asyncio.get_running_loop() future = loop.create_future() pending_requests[request_id] = future # 把审批请求推送到飞书 await push_to_feishu({ "request_id": request_id, "agent_id": req.agent_id, "action": req.action, "detail": req.detail, }) try: decision = await asyncio.wait_for(future, timeout=req.timeout) return { "request_id": request_id, "decision": decision, } except asyncio.TimeoutError: pending_requests.pop(request_id, None) return { "request_id": request_id, "decision": "timeout", } @app.post("/botmux/v1/callback") async def feishu_callback(request: Request): """ 接收飞书卡片交互回调。 飞书会 POST 一个 JSON 到这个地址,里面包含按钮动作。 在生产环境,必须校验飞书回调签名,防止伪造请求。 """ payload = await request.json() # 1. 校验签名,防止伪造回调查看下一节 # 2. 解析 action.value,从中取出 request_id 和 decision action_value = payload.get("action", {}).get("value", {}) request_id = action_value.get("request_id") decision = action_value.get("decision") if not request_id or not decision: return {"code": 400, "msg": "invalid payload"} # 3. 幂等处理:如果该请求已经被处理过,直接忽略 if request_id not in pending_requests: return {"code": 0, "msg": "already processed"} # 4. 把决策写入 Future,唤醒正在等待的 Agent 请求 future = pending_requests.pop(request_id) future.set_result(decision) return {"code": 0, "msg": "ok"}

这段代码的逻辑很清晰:Agent 调用审批接口后,请求会被挂起,等待飞书回调。当用户在飞书上点击“允许”或“拒绝”,回调接口会解析出 request_id 和 decision,唤醒对应的 Future,返回给 Agent。

有一个细节值得注意:飞书回调里按钮的 value 字段需要你在发送卡片时定义好。下面是一个简化的卡片构造示例,展示如何绑定动作值:

{ "msg_type": "interactive", "card": { "header": { "title": {"tag": "plain_text", "content": "Agent 审批请求"} }, "elements": [ { "tag": "div", "text": { "tag": "lark_md", "content": "Agent code-agent 请求执行:\nrm -rf /tmp/cache" } }, { "tag": "action", "actions": [ { "tag": "button", "text": {"tag": "plain_text", "content": "允许"}, "type": "primary", "value": { "request_id": "REPLACE_WITH_REQUEST_ID", "decision": "allow" } }, { "tag": "button", "text": {"tag": "plain_text", "content": "拒绝"}, "type": "danger", "value": { "request_id": "REPLACE_WITH_REQUEST_ID", "decision": "deny" } } ] } ] } }

这个卡片的 JSON 结构就是飞书交互卡片的标准格式。你在 botmux 的飞书适配器里,需要把REPLACE_WITH_REQUEST_ID替换成真实的 request_id。

8. Agent 侧接入与完整示例

Agent 侧要做的事情很简单:在需要人工确认的地方,调用 botmux 的审批 API,等待结果。

假设你有一个函数delete_cache(),正常情况下它会直接执行删除。现在需要包一层授权逻辑。

# agent_example.py import requests BOTMUX_URL = "http://127.0.0.1:7080" def request_approval(agent_id: str, action: str, detail: str, timeout: int = 60): """ 向 botmux 发起审批请求,等待用户决策。 返回 True 表示允许,False 表示拒绝或超时。 """ resp = requests.post( f"{BOTMUX_URL}/botmux/v1/approval-request", json={ "agent_id": agent_id, "action": action, "detail": detail, "timeout": timeout, }, timeout=timeout + 10, ) resp.raise_for_status() result = resp.json() return result.get("decision") == "allow" def delete_cache_with_approval(): approved = request_approval( agent_id="code-agent", action="execute_command", detail="rm -rf /tmp/cache", timeout=120, ) if not approved: print("未获得授权,跳过删除操作") return False # 这里是真正执行删除的代码 import shutil shutil.rmtree("/tmp/cache", ignore_errors=True) print("缓存已删除") return True if __name__ == "__main__": delete_cache_with_approval()

在这个示例里,Agent 在真正执行危险操作之前,会先通过 botmux 发起一次审批。审批通过后才执行,否则直接跳过。

在更复杂的 Agent 框架中,你可以把request_approval封装成一个工具函数,挂载到 Agent 的 Tool 调用链里。每次 Agent 准备调用高权限工具时,先在工具层触发一次审批。这样不用修改 Agent 的核心逻辑,侵入性会小很多。

最典型的封装方式是写一个装饰器,给需要审批的函数自动加一层授权检查。这样代码会更整洁,也更适合在团队内复用。

9. 运行验证与效果检查

现在把整个链路跑起来验证。

9.1 启动 botmux 服务

uvicorn app.main:app --host 0.0.0.0 --port 7080

看到类似Uvicorn running on http://0.0.0.0:7080的日志,说明服务启动成功。

9.2 模拟 Agent 发起审批请求

打开另一个终端,执行:

curl -X POST http://127.0.0.1:7080/botmux/v1/approval-request \ -H "Content-Type: application/json" \ -d '{ "agent_id": "code-agent", "action": "execute_command", "detail": "rm -rf /tmp/cache", "timeout": 60 }'

执行后,curl 会保持等待状态,因为 botmux 正在等待飞书回调。

9.3 在飞书上完成审批

打开飞书,你应该能收到 botmux 发送的审批卡片。点击“允许”后,观察 botmux 服务端日志。日志会打印出飞书回调的处理过程。

如果你在飞书上点击了“允许”,再回到终端,会发现 curl 返回了类似下面的 JSON:

{"request_id":"a1b2c3d4...","decision":"allow"}

如果你一直没有点击,超过 timeout 时间后,curl 会返回:

{"request_id":"a1b2c3d4...","decision":"timeout"}

9.4 判断链路是否走通

判断标准有三个:

  1. 飞书收到了卡片,并能看到操作详情;
  2. 点击按钮后,curl 能收到对应的决策结果;
  3. 重复点击同一个按钮,不会产生重复处理。

如果第 1 步失败,优先排查飞书应用的权限和事件订阅配置。如果第 2 步失败,优先检查回调地址是否可达、签名校验是否通过。如果第 3 步失败,说明幂等处理有 bug,需要检查pending_requests里的 request_id 是否在第一次处理时被正确移除。

10. 常见问题与排查思路

下面整理了一些常见问题,按“现象、可能原因、排查方式、解决方案”的顺序列出。

问题现象可能原因排查方式解决方案
飞书没有收到审批卡片飞书应用权限不足或机器人未启用检查应用权限列表;在飞书中确认应用是否已添加机器人添加im:message:send_as_bot权限,重新发布应用版本
卡片收到了,但点击按钮后 Agent 没反应回调地址无法访问,或签名校验失败查看 botmux 日志;用 curl 手动模拟回调确认回调 URL 能被飞书访问;检查签名算法和 token
点击按钮后收到 “invalid payload”action.value 里没有 request_id 或 decision打印飞书回调原始 JSON检查卡片 action.value 是否包含正确字段
重复点击按钮导致 Agent 执行两次幂等处理有缺陷观察 pending_requests 日志在第一次处理时立即 pop request_id,后续请求直接忽略
审批超时时间太短,用户来不及操作timeout 配置不合理查看请求参数设置更长的 timeout,或在配置层给定默认值
Agent 并发请求多个审批时,结果互相串request_id 生成冲突检查 request_id 是否唯一使用 uuid4 或雪花 ID 生成唯一标识
部署在私网环境,飞书 Webhook 推不进来没有公网入口检查网络拓扑改用飞书长连接模式,避免对外开放公网端口

排查的顺序建议是:先看飞书是否收到消息,再看按钮点击后是否触发回调,最后看 botmux 是否把结果返回给了 Agent。一层一层往后走,定位效率最高。

11. 最佳实践与工程建议

11.1 审批请求必须幂等

消息平台存在重试机制,飞书的回调可能重复推送。如果你在回调里直接执行 Agent 的任务,而不是只解除等待,很可能造成重复执行。正确做法是:回调只负责把 request_id 对应的 Future 设置为终态,真正的 Agent 任务由等待方执行。

11.2 回调必须验签

飞书的回调接口暴露在公网或内网中,如果不验签,任何人都可以伪造一个“允许”的请求,绕过人工审批。后果很严重:攻击者让 Agent 执行任意命令。所以,验签不是可选项,而是必须项。

验签逻辑建议放在依赖边界上。botmux 的飞书适配器收到回调后,第一步就是验证签名,验证不通过直接拒绝。如果需要二次校验,可以再用 verification_token 做一次轻量校验。

11.3 最小权限原则

Agent 不是什么东西都能执行的。在 botmux 配置里,可以为不同 Agent 设置不同的审批等级。比如:

  • 只读操作:可以自动执行,不需要审批;
  • 低风险写操作:记录日志即可;
  • 高风险操作:必须飞书审批;
  • 极端风险操作:必须到达指定审批人,且可能需要两个以上审批人。

审批等级不应该写死在 Agent 代码里,而应该由 botmux 统一管理。这样调整权限时不需要改动 Agent。

11.4 超时和降级策略

审批请求不能无限等待。应该为每个请求设置合理超时,并在超时后触发降级策略。降级策略可以是“跳过该操作”“回滚到上一个状态”“直接终止任务”。具体选哪种,取决于这个操作对任务的影响。

另一个建议是:不要在 Agent 的核心执行线程里等待审批过久,否则会阻塞其他任务。可以考虑把审批挂起的时间计入任务执行时间,超过一定阈值后切换到其它可独立运行的任务。

11.5 审计记录建议接入飞书多维表格

botmux 每次审批请求处理完成后,可以写一条审计记录,字段包括:request_id、agent_id、action、detail、决策人、决策时间、决策结果。这个记录除了写入本地日志,也可以写入飞书多维表格。多维表格天然适合做筛选和统计,团队复盘时可以直接看到审批链路。把审计数据和飞书消息放在同一平台,减少了取数成本。

11.6 环境区分与配置管理

开发环境、测试环境、生产环境应该使用不同的飞书应用。不要把生产环境的 App Secret 放在开发机里。配置信息用环境变量或专门的配置中心管理,不要在代码仓库里提交明文密钥。

12. 总结与后续学习方向

写到这里,本文的核心内容已经讲完了。我们围绕“Agent 授权卡在电脑上”这个痛点,拆解了 botmux 的架构:它作为消息总线,把 Agent 的权限请求路由到飞书,再把人在飞书上的决策返回给 Agent。

文中给出了一个基于 FastAPI 的最小实现,包含审批请求接口、飞书回调接口、Agent 侧工具函数和飞书交互卡片的 JSON 示例。这个最小实现能帮你理解整个链路,也能作为你自己项目的起点。

如果你正在做 Agent 开发,下一步可以沿着这几个方向继续深入:

  • 把审批请求从内存存储升级为 Redis 或数据库存储,解决多实例部署时的状态不一致问题;
  • 加入多级审批流,支持不同操作需要不同审批人的场景;
  • 把 Agent 的授权链路接到自己的日志系统或审计平台;
  • 研究飞书长连接模式的断线重连机制,提升长稳运行的可靠性;
  • 如果 Agent 框架支持 Tool Call 拦截,把 botmux 审批封装成通用的 Tool Wrapper,做到对上层无感。

最后提醒一句:任何安全设计都不能完全依赖某一个中间件。botmux 为人提供了更便捷的审批入口,但 Agent 本身的权限控制、文件系统隔离、网络访问策略仍然需要你配置好。审批只是最后一道防线,而不是唯一防线。建议保存这份流程清单,实际操作时对照检查,至少能帮你少踩一半的坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询