AI行动证明门:让Agent每次工具调用都先证明自己
2026/8/31 16:51:17 网站建设 项目流程

AI 现在真的会自己行动了。调用工具、读取文件、发送请求、执行脚本,这些事大模型都能做,而且做得越来越像一个“数字员工”。但问题也出在这里:模型会行动,不代表它该不该动。过去我们习惯用提示词约束模型“不要乱来”,可提示词是软约束,上下文一长、对抗性输入一多,模型很容易绕过规则直接调工具。

所以这次要看的不是又一个 Agent 框架,而是一道加在 Agent 和外部世界之间的“门”:AI 可以行动,但它必须先把“为什么这次行动是合理的”证明给门看,门放行后才允许执行。这个思路来自一个很直接的英文表述:AI learned to act. I built the gate that makes it prove it should。

这篇文章会从工程落地角度,拆解这道“行为证明门”应该怎么设计、怎么部署、怎么测试,以及怎么把它接到现有 Agent 的批量任务和 API 通道里。如果你正在做 AI Agent 开发、工具调用安全、企业级自动化流程控制,建议直接收藏。

1. 核心能力速览

在拆代码之前,先把这道“证明门”的能力边界拉一个清单。以下能力来自通用 Agent 安全工程实践,具体参数需要按你自己的部署环境验证。

能力项说明
项目定位Agent 工具调用前的行为校验与证明层,不是大模型本身
核心功能动作意图校验、参数合法性检查、风险评分、授权凭证验证、执行决策
决策结果allow / deny / needs_more_proof / human_approval_required
启动方式Python 服务启动,HTTP API 对外提供服务
接口能力单动作证明接口、动作执行接口、批量证明接口
批量任务支持批量提交动作证明请求,逐条返回决策结果
人工审批高风险动作可进入待审批队列,等待外部确认后放行
审计日志记录完整动作证明链,便于事后追溯
运行环境Linux / macOS / Windows,建议 Python 3.10+
GPU 要求不需要独立 GPU,纯 CPU 即可运行
部署复杂度低,无模型权重文件,依赖较少
适用场景Agent 工具调度、自动化操作审批、企业 RPA 安全网关

这里有一个关键点需要明确:这道门不负责让模型变聪明,它负责拦截“模型觉得可以做、但业务上不应该做”的动作。它更像一个安全网关,而不是推理引擎。

2. 适用场景与使用边界

先说你最关心的问题:这东西到底解决什么场景的问题。

现在很多 Agent 框架已经支持工具调用,比如让模型查询数据库、调用外部 API、写文件、执行命令。模型只要返回一个 tool call 的 JSON,框架就会解析并执行。流程很短,但问题很大:模型可能因为 prompt injection 被诱导调用危险工具,也可能因为上下文判断失误,对生产环境发出破坏性指令。

“证明门”就是插在“模型输出 tool call”和“框架执行 tool call”之间的一层。它强制模型提交一份动作证明,包含意图、动作名、参数摘要、预期影响、风险声明、授权凭证。门控层拿到这份证明后,用规则引擎做校验,匹配通过的才放行。

适合的使用场景包括:

  • Agent 工具调度:模型每调一次工具,都要经过白名单、参数校验和风险评分。
  • 企业自动化流程:涉及文件删除、数据修改、资金操作、对外发送消息时,必须提供更充分的证明。
  • 多租户 Agent 平台:不同租户有不同的权限范围,证明门按角色做授权检查。
  • 需要审计合规的场景:每次动作都有完整决策链路,出了问题可以回溯。
  • 批量任务:需要一次性校验大量动作,门控层可以作为批处理入口。

不适合的场景也要说清:

  • 不要用这道门替代模型能力评测,它只做行为控制,不提升模型理解能力。
  • 不要以为门控能免疫所有 prompt injection,它只能降低非法工具调用的概率。
  • 不要在没有人工审批通道的情况下,把高风险动作全部设为自动放行,那门就形同虚设。

合规方面需要额外强调:如果这套机制接入涉及人脸、声音、版权素材、个人隐私数据或真实资金操作的 Agent,必须确保有合法授权,并且在测试环境完成验证后再上线。门控层本身只是技术手段,不能替代业务层面的合规审查。

3. 环境准备与前置条件

这道证明门本身不需要 GPU,也不需要下载大模型权重,所以环境准备比部署一个本地大模型简单很多。建议按下面的清单检查一遍。

3.1 操作系统与运行时

建议使用 Linux 或 macOS 作为服务端,Windows 也可以跑,但进程管理和脚本路径需要多注意。核心运行时是 Python,建议使用 3.10 或更高版本。

python --version

如果你还没装 Python,建议用系统包管理器或官方安装包安装,不推荐直接改系统默认 Python。接下来创建独立虚拟环境,避免污染全局依赖。

# 创建项目目录 mkdir ai-action-gate-demo cd ai-action-gate-demo # 创建虚拟环境 python -m venv .venv # 激活虚拟环境 # Linux / macOS source .venv/bin/activate # Windows PowerShell .venv\Scripts\Activate.ps1

3.2 依赖清单

这个 demo 的核心依赖很少,主要是一个 Web 框架和一个 YAML 解析库。下面这份 requirements.txt 是演示用通用模板,实际项目可以按需增减。

fastapi>=0.110.0 uvicorn>=0.29.0 pydantic>=2.6.0 pyyaml>=6.0.1

安装依赖:

pip install -r requirements.txt

如果你希望门控决策结果能持久化,可以再加 SQLite 或者 PostgreSQL。演示阶段直接用 SQLite 就够了,零额外配置。

3.3 数据与策略文件准备

证明门需要一份策略配置,用来声明哪些动作合法、哪些动作危险、哪些参数不允许出现。建议把策略文件和代码分开,方便后续修改。下面的结构是通用部署模板:

ai-action-gate-demo/ ├── app.py ├── policy.yaml ├── requirements.txt └── logs/

其中 logs 目录存放运行日志。如果你要接入正式环境,还需要规划 Redis 之类的队列用于人工审批回调,但本文演示先从单机版本开始。

4. 安装部署与启动方式

这一节给出一个可直接运行的示例实现。为了不绑定某个具体项目,我用 FastAPI 写一个最小可运行版本,重点展示“证明门”的流程,而不是复杂业务逻辑。

4.1 策略文件示例

version: 1.0 default_policy: allow: false risk_level: unknown actions: - name: file.read allowed: true require_proof: true params: path: required: true forbidden_patterns: - "/etc/passwd" - ".env" - "~/.ssh/" risk_level: low - name: file.write allowed: true require_proof: true params: path: required: true content: required: true max_length: 10000 risk_level: medium - name: shell.exec allowed: false require_proof: true risk_level: high note: "默认禁止,必须人工审批" - name: database.query allowed: true require_proof: true params: sql: required: true forbidden_patterns: - "DROP TABLE" - "DELETE FROM" - "TRUNCATE" risk_level: medium approval_required_roles: - admin proof_required_fields: - action - intent - params - expected_impact - risk_declaration - role

4.2 门控服务示例代码

下面给出app.py的简化版实现。这里不需要把工程写得特别完整,但核心决策流程必须清晰。

import json from typing import Literal from fastapi import FastAPI, HTTPException from pydantic import BaseModel, Field import yaml app = FastAPI(title="AI Action Gate") class ActionProof(BaseModel): action: str = Field(..., description="工具/动作名称") intent: str = Field(..., description="模型声明的意图") params: dict = Field(..., description="动作参数") expected_impact: str = Field("", description="预期影响") risk_declaration: str = Field("", description="模型自评风险") role: str = Field("user", description="调用者角色") def load_policy(path: str = "policy.yaml") -> dict: with open(path, "r", encoding="utf-8") as f: return yaml.safe_load(f) def check_forbidden(params: dict, rule: dict) -> bool: forbidden = rule.get("params", {}).get("forbidden_patterns", []) for key, value in params.items(): if isinstance(value, str): for pattern in forbidden: if pattern in value: return True return False def evaluate_proof(proof: ActionProof, policy: dict): actions = {a["name"]: a for a in policy.get("actions", [])} action_rule = actions.get(proof.action) if action_rule is None: return { "decision": "deny", "reason": "action_not_in_policy", "risk_level": "unknown" } if not action_rule.get("allowed", False): return { "decision": "human_approval_required", "reason": "action_default_denied", "risk_level": action_rule.get("risk_level", "high") } if check_forbidden(proof.params, action_rule): return { "decision": "deny", "reason": "param_forbidden_pattern_matched", "risk_level": action_rule.get("risk_level", "medium") } required_params = action_rule.get("params", {}) for param_name, param_rule in required_params.items(): if param_rule.get("required", False) and param_name not in proof.params: return { "decision": "deny", "reason": f"missing_required_param:{param_name}", "risk_level": action_rule.get("risk_level", "medium") } return { "decision": "allow", "reason": "policy_check_passed", "risk_level": action_rule.get("risk_level", "low") } @app.get("/health") def health(): return {"status": "ok"} @app.post("/v1/prove") def prove(proof: ActionProof): policy = load_policy() result = evaluate_proof(proof, policy) result["action"] = proof.action result["proof_id"] = "demo-" + str(hash(json.dumps(proof.dict(), sort_keys=True)) & 0xFFFF) if result["decision"] == "allow": result["message"] = "action allowed, safe to execute" return result

这里有几个设计点值得注意。门控层收到证明后,不是直接执行工具,而是先做一次完整校验。校验结果返回给上层 Agent 框架,由框架决定是放行还是中断。如果 feedback 是human_approval_required,说明当前动作默认禁止,必须走人工审批队列。

4.3 启动服务

启动前先确保策略文件在项目根目录,然后执行:

uvicorn app:app --host 127.0.0.1 --port 8765

如果你希望自动重载,加--reload参数即可:

uvicorn app:app --host 127.0.0.1 --port 8765 --reload

启动后访问http://127.0.0.1:8765/docs可以打开 Swagger 调试页面。注意这只是演示服务,正式环境不要把服务直接暴露到公网,至少要用反向代理加认证。

5. 功能测试与效果验证

服务启动后,需要验证的不只是“能不能返回 200”,而是要验证门控逻辑是否真的拦截了危险动作。下面给出一套可直接执行的测试思路。

5.1 基础验证:允许一个低风险动作

用下面的请求测试file.read动作:

{ "action": "file.read", "intent": "读取项目配置文件", "params": { "path": "./config/app.yaml" }, "expected_impact": "读取本地配置文件,不做修改", "risk_declaration": "low", "role": "developer" }

预期结果是:

{ "decision": "allow", "reason": "policy_check_passed", "risk_level": "low" }

判断标准只有一个:返回decisionallow,且reason不是deny。如果返回deny,先检查策略文件里的动作名是否匹配。

5.2 拒绝测试:读取敏感文件

把参数改成/etc/passwd再试:

{ "action": "file.read", "intent": "读取系统用户信息", "params": { "path": "/etc/passwd" }, "expected_impact": "查看系统用户列表", "risk_declaration": "low", "role": "developer" }

预期结果是deny,原因应该包含param_forbidden_pattern_matched。到这里基本可以确认,关键词拦截生效了。

5.3 高风险动作测试:等待人工审批

提交shell.exec动作:

{ "action": "shell.exec", "intent": "在服务器上执行清理命令", "params": { "command": "rm -rf /tmp/cache" }, "expected_impact": "清理临时缓存目录", "risk_declaration": "medium", "role": "user" }

预期结果是human_approval_required,因为策略文件里shell.execallowedfalse。这一个测试很重要:如果门控层把所有非白名单动作都直接 deny,会太生硬;返回待审批,才能让业务方有机会确认。

5.4 批量动作验证

批量验证是工程化接入的重点。演示服务目前只写了单个接口,但只要请求量不大,循环调用即可。如果动作数量很大,建议把批量任务设计成独立队列,后面第 6 节会说接口形态。

5.5 失败场景怎么排查

先看响应里的reason字段,它是排查的第一线索:

响应 reason下一步动作
action_not_in_policy检查策略文件里是否配置了这个动作名
param_forbidden_pattern_matched检查参数里是否包含敏感路径或口令牌
missing_required_param:xxx检查模型返回的参数是否有缺失
action_default_denied确认这个动作是否真的需要人工审批

如果接口返回 422,说明请求体不符合 Pydantic 模型定义,优先检查字段名和类型。

6. 接口 API 与批量任务

上面只是最小演示版本,实际接入 Agent 时,还需要考虑批量任务和完整执行链路。下面给出一个更完整的 API 设计参考。

6.1 单动作证明接口

POST /v1/prove Content-Type: application/json

请求体就是第 5 节里的ActionProofJSON。这个接口只做决策,不负责执行。

6.2 执行接口

POST /v1/execute Content-Type: application/json

这个接口的语义是:证明通过后,真正执行动作。为了安全,官方更推荐的做法是“证明”和“执行”分离,由上层 Agent 框架自己决定要不要调用执行接口。如果确实要做统一执行入口,需要在响应里带上审计 ID。

curl -X POST http://127.0.0.1:8765/v1/prove \ -H "Content-Type: application/json" \ -d '{ "action": "file.read", "intent": "读取配置文件", "params": {"path": "./config/app.yaml"}, "expected_impact": "读取配置", "risk_declaration": "low", "role": "developer" }'

6.3 批量证明接口设计

批量接口建议使用异步任务模式,而不是同步长连接。你可以这样设计:

{ "batch_id": "batch-20250315-001", "items": [ { "action": "file.read", "intent": "读取配置", "params": {"path": "./config/app.yaml"}, "expected_impact": "读取配置", "risk_declaration": "low", "role": "developer" }, { "action": "database.query", "intent": "查询用户表", "params": {"sql": "SELECT id, name FROM users LIMIT 10"}, "expected_impact": "查看用户数据", "risk_declaration": "medium", "role": "analyst" } ] }

Python 调用批量接口的示例:

import requests url = "http://127.0.0.1:8765/v1/batch/prove" payload = { "batch_id": "batch-demo-001", "items": [ { "action": "file.read", "intent": "read config", "params": {"path": "./config/app.yaml"}, "expected_impact": "read config", "risk_declaration": "low", "role": "developer" }, { "action": "shell.exec", "intent": "run cleanup", "params": {"command": "rm -rf /tmp/test"}, "expected_impact": "clean temp directory", "risk_declaration": "medium", "role": "user" } ] } response = requests.post(url, json=payload, timeout=30) print(response.json())

批量任务需要注意重试机制。如果某个动作返回deny,不要因为一个失败就回滚整个批次,而是把每个动作的决策独立返回,交给上层业务决定。

7. 资源占用与性能观察

因为这道门不加载大模型,资源占用通常很低。但如果你在跑高并发的 Agent 调度,还是需要观察几个关键指标。

7.1 CPU 与内存

纯 Python + FastAPI 的服务,单机跑几百 QPS 的证明请求不成问题。每个请求主要是 YAML 策略加载、JSON 解析、字符串匹配,CPU 开销不大。真正的性能瓶颈在策略文件的加载方式:如果每次请求都用load_policy()读 YAML 文件,磁盘 IO 会影响吞吐。

建议策略文件只在启动时加载,或者加缓存。上面演示代码为了简单,每次请求都会重新读文件,生产环境要改成缓存加载。

7.2 是否需要 GPU

完全不需要 GPU。这道门本身不跑模型,也不做 embedding 计算。如果未来想引入“语义相似度”来判断证明文本是否匹配,才需要接一个 embedding 模型,那时才要考虑显存和推理延迟。

7.3 并发与超时设置

先启动服务,用下面的命令做一次简单的并发测试:

# 简单的并发请求测试 seq 1 100 | xargs -P 10 -I {} curl -s -o /dev/null -w "%{http_code}\n" \ http://127.0.0.1:8765/health

如果你的 Agent 框架对门控响应有时限要求,比如必须在 1 秒内返回决策,建议把策略规则做成纯内存匹配,不要在请求链路里做远程数据库查询。

7.4 如何降低资源消耗

优先减少不必要的日志输出。审计日志是必须的,但不要每个请求都打印完整参数。可以只打印actiondecisionreason,参数摘要单独存数据库。

8. 常见问题与排查方法

下面是长期使用过程中最可能碰到的几类问题。表格里给了排查方式和解决方案,按顺序操作即可。

问题现象可能原因排查方式解决方案
启动报模块找不到Python 环境未安装依赖执行pip list检查 fastapi 是否安装重新执行pip install -r requirements.txt
端口被占用之前的服务进程还在检查端口监听状态换端口或杀掉旧进程
所有动作都返回 deny策略文件动作名与请求不匹配打印策略文件实际加载内容统一动作命名规范
敏感参数仍然通过forbidden_patterns 写得不全检查策略配置里是否覆盖大小写变体增加正则匹配,不只做子串匹配
批量任务某条失败导致全部失败批量处理逻辑没有隔离错误检查批量接口是否在循环内抛出异常每条独立 try/except,单独返回结果
人工审批动作没有回调审批队列未实现检查是否有人工审批服务消费队列接入 Redis 队列并增加回调接口
API 调用返回 422请求体字段不匹配对比 OpenAPI 文档中字段名修正 JSON 字段名和类型

这里重点强调一个容易被忽略的问题:不同 Agent 框架输出的 tool call 格式不一样。有的框架字段叫tool_name,有的叫action,有的直接把参数放在arguments里。门控服务的入参应该做一次适配层,把各种格式统一成ActionProof,而不是要求所有 Agent 都改输出格式。

9. 最佳实践与使用建议

如果要把这道“证明门”真正落地到生产环境,下面这些建议值得直接抄作业。

9.1 证明字段别只要求一个 intent

很多 Agent 会输出intent: "读取文件",但门控层如果只校验这个字段,等于没校验。建议把expected_impactrisk_declarationparams都做成必填,并且对expected_impact做关键词校验,要求模型说明具体影响范围。

9.2 策略永远走白名单

默认策略建议设成allow: false,只有显式加入白名单的动作才允许通过。这是最核心的一条:宁可新动作被误拦,也不要默认放行。一旦新动作被误拦,会立刻暴露在审计日志里,开发人员可以及时加白名单策略。

9.3 参数校验要做两层

第一层是静态规则,比如路径黑名单、SQL 危险关键词。第二层是人工审批,如果动作本身属于高风险类别,不管参数看起来多安全,都要进审批队列。数据删除、资金操作、发送消息、写公开目录,这些动作默认不允许自动通过。

9.4 审计日志要能还原决策链路

门控层返回的proof_id一定要保存。后续排查问题时,根据proof_id查到模型提交的原始证明、策略版本、决策结果和审批人,才能对一次风险动作做完整复盘。建议日志至少包含以下字段:

{ "proof_id": "demo-1234", "timestamp": "2025-04-01T10:00:00Z", "action": "file.write", "decision": "allow", "reason": "policy_check_passed", "role": "developer", "params": { "path": "logs/app.log" } }

9.5 分目录管理模型输入、策略、输出和日志

一个典型的工程目录结构可以是:

policies/ ├── production.yaml └── staging.yaml inputs/ ├── agent_trace_01.json └── agent_trace_02.json outputs/ ├── decisions/ └── audit_logs/

这样上线前可以直接对比 staging 和 production 的策略差异,避免把测试环境的宽松策略带到生产环境。

9.6 接口服务要限制访问范围

门控服务只允许内网访问,不要直接对外开放。建议在 Nginx 层加 IP 白名单,并且为请求增加签名校验,防止攻击者直接伪造证明请求。这里还需要强调:如果有人能直接访问门控执行接口,门控就失去了意义。访问控制本身就是门控的一部分。

9.7 合规与授权提醒

如果 Agent 的动作涉及读取个人数据、生成人脸或声音相关内容、处理版权素材、操作线上资金,那么无论门控策略写得多么严格,都必须先确认业务侧已经取得合法授权。门控只能从技术层面降低误操作风险,不能替代业务合规判断。发布或商用前,建议对高风险动作做人工复核并保留授权记录。

10. 总结与下一步

这个项目的核心不是“让 AI 更聪明”,而是“让 AI 的行为可以被审计、被拦截、被控制”。AI learned to act,这句话说的正是当前 Agent 的能力现状;而 I built the gate that makes it prove it should,才是工程上真正需要补上的一环。

从实际操作看,最先要验证的并不是复杂 API,而是一个最小门控:一个策略文件加一个prove接口。先让低风险动作通过,再让高风险动作进入待审批,最后把审计日志接起来。三条路径都跑通,整套机制就立住了。

最容易踩的坑有三个:第一是把intent当作唯一的证明依据,导致门控形同虚设;第二是默认策略设成了allow: true,结果白名单反而成了摆设;第三是证明服务和执行服务不分离,导致门控只做记录、不做拦截。

后续可以继续扩展的方向包括:把human_approval_required接入企业微信或钉钉审批流;在策略引擎里增加正则表达式和语义相似度匹配;把决策结果回流到 Agent 训练数据,让模型自己学会避免高风险动作。建议先把本地最小验证跑通,再逐步把参数校验、批量任务、审计日志和生产策略补完整。

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

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

立即咨询