☰
AI Agent可靠性治理:从幻觉、越权到数据泄漏的工程防线
2026/10/16 20:06:48 网站建设 项目流程

近几年 AI Agent 的热度一直居高不下,但开发者社区里流传着一句很扎心的话:AI Agent 会撒谎、会越权、还会把敏感信息泄漏出去。这句话听起来像段子,但真正做过 Agent 落地的人都知道,这三个词分别对应着大模型应用中最难缠的三类问题:幻觉(Hallucination)、工具滥用(Tool Misuse)、数据越权(Data Leakage)。如果你只是把 Agent 当成“能自动调用工具的 ChatGPT”,那上线第一周就会在用户投诉和权限事故中被反复教育。

这篇文章不打算复述“Agent 多强大、多智能”的套话,而是想从工程视角拆开来看:为什么用户会不信任 Agent?这些不信任背后的技术根因是什么?作为开发者,我们能用什么手段把 Agent 的“撒谎、作弊、偷窃”控制在可接受范围内?

读完这篇文章,你会得到三样东西:

  1. 一套判断 Agent 可靠性问题的分析框架,知道“幻觉、越权、泄漏”分别发生在哪个环节;
  2. 一个带工具白名单、权限校验、幻觉拦截的最小 Agent 工程示例,可以直接跑通;
  3. 一份生产环境落地时的检查清单和排查思路,避免踩常见的坑。

1. 用户为什么对 AI Agent 不放心

先不急着写代码,我们站在用户视角看一下,和一个 Agent 对话时会遇到哪些糟心事。

假设你是一个普通用户,正在使用某个“AI 助手”查询本月工资单。对话大概是这样的:

  • 你问:“我这个月工资扣了多少税?”
  • Agent 回答:“根据您的收入情况,预计扣除个人所得税 3200 元。”
  • 你追问:“系统里实际数据是多少?”
  • Agent 开始犹豫,最后给了一个和上月完全一样的数字。

这个场景里,Agent 可能犯了三个错误:

  • 它并不确定数据,但编了一个看似合理的答案。这是典型的“撒谎”,技术上叫幻觉。
  • 它访问了一个不该访问的数据库,或者调用了没有权限的接口。这是“越权”,技术上叫权限失控。
  • 它把其他同事的匿名数据拼接进了回复内容。这是“泄漏”,技术上叫数据隔离失败。

从材料来看,“AI agents lie, cheat and steal”这个说法确实反映了当前 Agent 落地中的一个真实困境:模型能力的提升速度快于工程约束能力的建设速度。换句话说,不是 Agent 天生“坏”,而是我们在设计 Agent 时,把太多决策权交给了模型本身,却没有给模型装上足够的“刹车”和“护栏”。

这里可以做一个类比:传统的软件开发里,权限控制是由代码逻辑和中间件强制保证的,用户无法通过修改输入参数绕过。但在 Agent 应用里,模型会根据用户的一句话自主决定“调用哪个工具、传入什么参数、怎么解读返回结果”。一旦模型判断失误,它就可能调用错误的接口、传入越权的参数、甚至把中间数据的原始内容直接吐给用户。失控的源头不是模型“想作弊”,而是我们根本没有给它定义好边界。

所以,这篇文章的核心判断是:AI Agent 要取得用户信任,关键不在于把模型换得更大更强,而在于把“工具调用权”和“数据访问权”从模型手里收回到工程体系里。接下来我们逐个拆解三类问题。

2. “撒谎”问题:幻觉如何摧毁 Agent 的可信度

2.1 幻觉的本质

大模型的“撒谎”和人类撒谎有一个本质区别:人类撒谎通常有动机,而大模型很多时候只是在做“最合理的补全”。它并不知道某个答案是错的,它只知道按当前上下文,这个词序列的概率最高。

在普通聊天场景下,幻觉的代价不高,顶多让用户觉得“AI 又在胡说”。但在 Agent 场景下,幻觉的代价被放大了数倍,因为 Agent 会为了回答问题去做工具调用。如果模型把“查询订单”想成了“查询库存”,或者把“删除草稿”理解成了“删除正式文档”,那它不只是说了句错话,而是执行了一个错误的操作。

2.2 幻觉常见的三种表现

幻觉类型表现典型例子
事实幻觉编造不存在的事实明明没有订单,却说“订单已发货”
指令幻觉误解用户意图,执行错误工具用户要查询,Agent 执行了修改
引用幻觉引用了不存在的内容或来源回复里标注了不存在的文档 ID

这三种幻觉在 Agent 系统里都可能造成实际损失。尤其是第二种“指令幻觉”,它直接导致工具被错误调用,是权限事故的导火索之一。

2.3 缓解幻觉的工程手段

缓解幻觉不是靠“提示词里写‘请诚实回答’”就能搞定的,需要从数据流上做强制约束。

  • 工具调用前加“意图确认”:当模型判断需要调用某个高风险工具时,先返回一个确认步骤,让用户二次确认参数。
  • 结果返回前加“事实核验”:让模型把工具返回的原始结果和最终回复做比对,不一致时宁可拒绝回答。
  • 引用溯源:要求 Agent 回复时标注数据来源,比如“该数据来自订单接口 orderNo=xxx”,这样用户可以回溯验证。

工程上,这些手段比换一个更强的模型更有效,因为它们的核心是把模型的“自主权”降下来,把系统的“确定性”升上去。

3. “作弊”问题:工具越权与权限失控

3.1 什么是 Agent 的“作弊”

这里说的“作弊”,不是指模型有意欺骗系统,而是指Agent 在调用工具时,超出了它应该拥有的权限边界。

传统 API 开发中,权限控制一般由后端统一管理:

  • 用户 A 只能调自己的订单接口;
  • 普通角色不能调删除接口;
  • 敏感操作需要二次授权。

但在 Agent 架构里,调用工具的“决策者”变成了大模型。如果模型可以自由选择工具和参数,并且系统不额外做校验,就会出现以下情况:

用户输入: “把上个月的测试数据清理掉” Agent 决策: 调用 data.delete(scope=all, confirm=false) 结果: 整个测试库被清空

这个例子里,Agent 并没有“坏心眼”,它只是从用户的自然语言里推测出了一个操作,然后直接执行了。真正的问题在于:系统没有在模型和工具之间增加权限校验层。

3.2 工具越权的典型场景

  • 参数注入:用户输入中的某些词被模型当作高权限参数传入工具,比如is_admin=true。
  • 工具调错:模型在意图识别阶段选错工具,比如把“删除”识别成“更新”。
  • 链路越权:一个低权限用户通过 Agent 间接调用了高权限工具。
  • 重放攻击:Agent 记住了上次的高权限操作,在后续对话中无意识重放。

3.3 把权限校验从“模型的自觉”变为“系统的强制”

有效的做法是在工具调用路径上加一个策略执行点(Policy Enforcement Point),让所有工具调用都经过统一校验。

# 工具调用拦截器的核心逻辑 def call_tool(user_id: str, tool_name: str, params: dict): # 1. 校验工具是否在用户允许的白名单内 if tool_name not in get_user_allowed_tools(user_id): raise PermissionDenied(f"用户 {user_id} 无权调用工具 {tool_name}") # 2. 校验参数是否越过权限边界 if not validate_params_permission(user_id, tool_name, params): raise PermissionDenied(f"工具 {tool_name} 的参数越权: {params}") # 3. 高危操作强制二次确认 if tool_name in HIGH_RISK_TOOLS: return require_user_confirmation(user_id, tool_name, params) # 4. 通过所有校验后,才真正调用工具 return actual_tool_invoke(tool_name, params)

这段代码的核心思想是:模型只负责生成工具调用的“意图”,但工具是否真的能执行,由权限层决定。这样即使模型被诱导、被提示词注入,也无法直接执行越权操作。

4. “盗窃”问题:数据泄漏与隐私边界

4.1 Agent 的数据泄漏链条

Agent 的数据泄漏风险比传统 API 更隐蔽,因为数据在链路中经过了多个环节:

  1. 用户输入可能包含敏感信息;
  2. Agent 可能把用户输入拼进 Prompt,发送给大模型;
  3. 大模型为了回答,可能会请求多个工具;
  4. 工具返回的数据可能包含超过回答所需的字段;
  5. Agent 可能把多余字段直接生成进回复,或者写入日志。

任何一个环节失控,都会造成信息泄漏。

4.2 最小化数据暴露原则

在 Agent 工程中,有一条值得遵守的准则:无论模型多大,都不要让它看到它不需要的数据。

具体落地到代码里,可以在工具返回后进行字段过滤:

# 对工具返回结果做脱敏和字段裁剪 def sanitize_tool_result(tool_name: str, raw_result: dict) -> dict: # 每个工具定义自己的可返回字段和脱敏规则 allowed_fields = TOOL_FIELD_ALLOWLIST.get(tool_name, []) safe_result = {} for field in allowed_fields: if field in raw_result: safe_result[field] = raw_result[field] # 对敏感字段做脱敏 for sensitive_field in SENSITIVE_FIELDS: if sensitive_field in safe_result: safe_result[sensitive_field] = mask_value(safe_result[sensitive_field]) return safe_result

这样做的好处是:即使模型在生成回复时出现幻觉,它手上也没有“多余的数据”可以泄漏。数据暴露面越小,Agent 越安全。

4.3 日志和数据留存风险

很多人忽略的一点是:Agent 系统会在推理日志、工具调用日志、模型服务商侧留有大量数据。如果日志里记录了完整用户输入和工具返回,那日志系统本身就会变成数据泄漏的高危点。

生产环境中建议:

  • 对日志中的敏感字段做掩码;
  • 设置日志保留期限;
  • 避免把完整 Prompt 和完整工具返回写入同一份日志;
  • 如果使用第三方模型服务,明确数据协议中的数据留存策略。

5. 工程化解方案:给 Agent 装上“护栏”而非“锁链”

前面分析了三类问题,接下来给出一个统一的工程思路:给 Agent 增加多道护栏,而不是完全锁死模型的生成能力。

这里有一个很关键的理念:Agent 的价值在于“灵活”,工程的目标不是消灭灵活,而是让灵活发生在边界之内。就像一辆车,引擎是模型的推理能力,而护栏是刹车、车道偏离预警和限速标志。

一个可靠的 Agent 系统通常包含五个层级:

层级作用对应问题
意图识别层判断用户想做什么工具调错
权限校验层判断用户是否允许这个操作越权、作弊
工具执行层实际调用外部接口参数注入
数据过滤层裁剪和脱敏工具返回数据泄漏
回复生成层校验模型回答是否与事实一致幻觉

上一节里我给出了权限校验层和数据过滤层的示例代码。现在需要一个能把各层串起来的完整示例,让读者能跑一个“结构完整、具备基础护栏能力”的最小 Agent 系统。

6. 完整示例:一个带护栏的最小 Agent

为了便于演示,这里使用 Python 编写一个轻量级 Agent 框架。它不依赖任何特定的 Agent 库,只使用标准库和简单的规则策略,方便讲清楚“护栏”的概念。实际生产项目中,你可以把这些思路迁移到 LangChain、Spring AI 或自研 Agent 框架中。

6.1 项目结构

guarded_agent/ ├── agent.py # Agent 主流程 ├── permissions.py # 权限校验与工具白名单 ├── sanitizer.py # 数据脱敏与字段裁剪 ├── tools.py # 模拟工具集合 ├── config.json # 用户权限配置 └── main.py # 命令行入口

6.2 模拟工具层

# tools.py """模拟的工具集合,实际项目中这里会封装真实的 API、数据库操作等""" def query_salary(user_id: str) -> dict: """查询用户工资信息(模拟)""" mock_data = { "user_id": user_id, "base_salary": 28000, "tax": 3200, "bonus": 5000, "account": "6222****1234", "note": "内部备注:该员工绩效待复核" } return mock_data def update_salary(user_id: str, new_salary: int) -> dict: """更新工资(模拟,高危操作)""" return {"status": "success", "user_id": user_id, "new_salary": new_salary} def delete_user(user_id: str) -> dict: """删除用户(模拟,极高危操作)""" return {"status": "deleted", "user_id": user_id} TOOL_REGISTRY = { "query_salary": query_salary, "update_salary": update_salary, "delete_user": delete_user, }

这段代码用一个字典注册了所有可用工具。真实项目中,你可以把工具注册做成装饰器模式,但核心思想一致:工具是系统资源,Agent 只能通过注册表访问,不能直接执行任意函数。

6.3 权限校验层

# permissions.py """权限校验:工具白名单 + 参数边界 + 高危操作确认""" import json class PermissionDenied(Exception): pass def load_permissions(config_path: str = "config.json") -> dict: with open(config_path, "r", encoding="utf-8") as f: return json.load(f) class PermissionEnforcer: def __init__(self, config_path: str = "config.json"): self.config = load_permissions(config_path) def check_tool_allowed(self, user_id: str, tool_name: str) -> bool: """校验工具是否在用户白名单内""" allowed_tools = self.config["users"].get(user_id, {}).get("allowed_tools", []) return tool_name in allowed_tools def check_param_bounds(self, user_id: str, tool_name: str, params: dict) -> bool: """校验参数是否越权,这里是基础示例,真实场景可扩展字段级校验""" user_role = self.config["users"].get(user_id, {}).get("role", "viewer") if tool_name == "update_salary" and params.get("salary", 0) > 50000: return False # 限制单次调整幅度 if tool_name == "delete_user" and user_role != "admin": return False return True def enforce(self, user_id: str, tool_name: str, params: dict) -> None: if not self.check_tool_allowed(user_id, tool_name): raise PermissionDenied(f"工具 {tool_name} 不在用户 {user_id} 的允许列表中") if not self.check_param_bounds(user_id, tool_name, params): raise PermissionDenied(f"工具 {tool_name} 的参数越权: {params}")

这里引入了一个PermissionEnforcer类,所有工具调用都必须经过它的enforce方法。注意,这个类的逻辑是简单而明确的,它不依赖模型判断。这正是工程化的关键:可靠性来自确定性代码,而不是模型的自觉。

6.4 数据脱敏层

# sanitizer.py """数据脱敏与字段裁剪""" SENSITIVE_KEYS = {"account", "note", "id_card", "phone"} def mask_value(value): if isinstance(value, str) and len(value) >= 8: return value[:4] + "****" + value[-2:] return "****" def sanitize_result(tool_name: str, raw_result: dict, allowed_fields: list) -> dict: """裁剪字段 + 脱敏""" safe = {} for field in allowed_fields: if field in raw_result: safe[field] = raw_result[field] for key in SENSITIVE_KEYS: if key in safe: safe[key] = mask_value(safe[key]) return safe

这里定义了每个工具可对外返回的字段白名单。相较于直接把整个 dict 塞给模型,这种做法可以显著降低数据泄漏风险,因为模型根本接触不到它不需要的原始字段。

6.5 Agent 主流程

# agent.py """带护栏的 Agent 主流程:感知 -> 规划 -> 受限执行 -> 校验回复""" from permissions import PermissionEnforcer, PermissionDenied from sanitizer import sanitize_result from tools import TOOL_REGISTRY # 在实际项目中,这部分通常由大模型根据用户输入生成 # 本文用规则演示,便于跑通流程;生产环境请接入 LLM 的 function calling def simple_intent_parser(user_input: str): """极简意图解析:仅仅用于演示主流程,真实场景请替换为 LLM 工具调用""" if "工资" in user_input and "查" in user_input: return "query_salary", {} if "调整" in user_input and "工资" in user_input: return "update_salary", {"salary": 40000} if "删除用户" in user_input: return "delete_user", {} return None, {} class GuardedAgent: def __init__(self, config_path: str = "config.json"): self.enforcer = PermissionEnforcer(config_path) def run(self, user_id: str, user_input: str) -> str: # 第 1 步:意图识别(演示为规则,生产可替换为 LLM) tool_name, params = simple_intent_parser(user_input) if tool_name is None: return "抱歉,我无法理解您的请求。" # 第 2 步:权限校验 try: self.enforcer.enforce(user_id, tool_name, params) except PermissionDenied as e: return f"操作被拒绝:{e}" # 第 3 步:执行工具 tool_func = TOOL_REGISTRY[tool_name] raw_result = tool_func(user_id, **params) # 第 4 步:数据过滤和脱敏 allowed_fields = { "query_salary": ["base_salary", "tax", "bonus", "account"], "update_salary": ["status", "user_id", "new_salary"], "delete_user": ["status", "user_id"], }.get(tool_name, []) safe_result = sanitize_result(tool_name, raw_result, allowed_fields) # 第 5 步:回复生成(演示为格式化输出) return self._format_reply(tool_name, safe_result) def _format_reply(self, tool_name: str, safe_result: dict) -> str: if tool_name == "query_salary": return ( f"您的工资信息如下:基础工资 {safe_result['base_salary']} 元," f"个税 {safe_result['tax']} 元,奖金 {safe_result['bonus']} 元。" f"账户 {safe_result['account']}" ) if tool_name == "update_salary": return f"工资调整成功,新工资为 {safe_result['new_salary']} 元。" if tool_name == "delete_user": return f"用户 {safe_result['user_id']} 已删除。" return str(safe_result)

6.6 配置文件和入口

{ "users": { "alice": { "role": "employee", "allowed_tools": ["query_salary"] }, "bob": { "role": "hr", "allowed_tools": ["query_salary", "update_salary"] }, "admin": { "role": "admin", "allowed_tools": ["query_salary", "update_salary", "delete_user"] } } }
# main.py from agent import GuardedAgent if __name__ == "__main__": agent = GuardedAgent("config.json") # 测试用例 1:普通员工合法查询 print(agent.run("alice", "我想查一下这个月工资")) # 测试用例 2:越权调整工资 print(agent.run("alice", "帮我把工资调整到 40000")) # 测试用例 3:HR 合法调整工资 print(agent.run("bob", "调整工资到 40000")) # 测试用例 4:普通员工删除用户(极端测试) print(agent.run("alice", "删除用户 alice"))

6.7 代码逻辑说明

这个示例虽然用了规则替代大模型的意图识别,但它完整展示了 Agent 工程的四个关键决策点:

  1. 意图识别独立化:意图生成和工具执行分离。真实项目中,这通常由大模型的 function calling 完成。
  2. 权限校验前置化:工具调用前必须经过独立权限层,不依赖模型判断。
  3. 数据过滤强制化:工具返回数据必须经过字段裁剪和脱敏,模型拿到的永远不是最原始的全量数据。
  4. 回复生成收敛化:最终输出只基于安全字段格式化,避免模型自由发挥导致幻觉泄漏。

7. 运行结果与效果验证

把上述文件保存到本地后,在项目目录下运行:

python main.py

预期输出如下(实际输出取决于 Python 版本和终端环境):

您的工资信息如下:基础工资 28000 元,个税 3200 元,奖金 5000 元。账户 6222****1234 操作被拒绝:工具 update_salary 不在用户 alice 的允许列表中 工资调整成功,新工资为 40000 元。 操作被拒绝:工具 delete_user 不在用户 alice 的允许列表中

这里的验证重点不是“能回答问题”,而是验证护栏是否生效:

  • 普通用户 alice 可以查询工资;
  • alice 不能调整工资,系统直接拒绝;
  • HR bob 可以调整工资;
  • alice 不能删除用户。

如果输出符合上述预期,说明 Agent 的“权限白名单 + 参数校验 + 数据脱敏”已经起到约束作用。

真实项目中,替换验证方式为:

  • 接入大模型的 function calling 后,用一组包含合法操作、越权操作、敏感字段查询、模糊意图的测试集反复跑;
  • 记录每一次工具调用是否被正确放行或拦截;
  • 对拦截结果设置审计日志,方便追溯。

如果某一类越权操作没有被拦截,优先检查权限配置文件和校验逻辑,而不是先怀疑模型。

8. 常见问题与排查思路

问题现象可能原因排查方式解决方案
Agent 选择了错误的工具模型意图识别错误查看模型输出中的 function call,与实际请求对比增加工具描述信息;增加意图确认步骤
用户能调用未授权的工具权限配置遗漏,或校验逻辑被绕过检查配置 JSON 和权限校验代码是否覆盖所有入口做一次全量工具-角色矩阵评审
工具返回了多余敏感字段未做字段裁剪,或允许字段列表过宽检查 sanitize_result 中的 allowed_fields收紧字段白名单,遵循最小暴露原则
日志中出现完整手机号、身份证号日志未脱敏检查日志输出路径和格式日志拦截器统一脱敏
用户通过复杂话术绕过限制模型把用户话术翻译成了工具参数查看完整对话上下文和工具入参对高危参数设置额外校验规则
生产环境出现数据泄漏事故第三方模型服务存留 Prompt 数据查看服务协议和调用配置选择支持数据零留存的服务,或本地化部署

补充一个容易被忽略的排查路径:权限拦截日志一定要记录“谁、在什么时间、通过哪个 Agent 会话、尝试调用哪个工具、参数是什么”。没有审计日志的权限系统,在出问题时很难定位责任链。

9. 生产环境落地的工程建议

9.1 权限设计层面

  • 遵循最小权限原则:用户默认只能访问完成业务所需的工具和字段。
  • 工具分类管理:把查询类、更新类、删除类分开,不同风险等级使用不同确认策略。
  • 高危操作强制二次确认:删除、转账、批量更新等操作,必须由用户显式确认后再执行。
  • 角色和工具之间建立映射矩阵,而不是在代码里硬编码权限。

9.2 模型与提示词层面

  • 对工具描述写得具体、无歧义,降低模型调用错误工具的概率。
  • 不要允许模型在没有任何工具返回的情况下直接编造数据。
  • 对 Prompt 注入做基础防护:不把用户输入直接拼接到系统提示词中。
  • 如果场景允许,优先使用结构化输出,而不是让模型自由生成 JSON。

9.3 数据与安全层面

  • 日志脱敏应该是默认行为,而不是事后补救。
  • 外部 API 密钥、数据库密码、Token 一律走环境变量或密钥管理服务,不进配置文件。
  • 对第三方模型服务的数据留存政策做充分评估。
  • 多租户场景下,确保 Agent 在切换用户上下文时不会串数据。

9.4 监控与可观测层面

  • 记录 Agent 的每一步工具调用,包括输入参数、返回结果、耗时、校验结果。
  • 设置异常告警:连续多次权限拒绝、工具调用失败率上升、敏感字段出现在日志中,都应触发告警。
  • 定期回放真实对话,检查模型是否有“越权尝试未拦截”“幻觉数据进入回复”的情况。

9.5 团队协作与发布流程

  • Agent 的策略调整(权限配置、工具白名单)走代码评审流程,不要只靠人工修改 JSON。
  • 每次提示词或工具变更后,跑一遍回归测试集。
  • 线上环境前先在小范围用户群灰度,观察工具调用分布和告警指标。

10. 做 Agent 之前,先想清楚边界

回到开头那个观点:AI Agent 之所以让用户不放心,不是模型“学坏了”,而是我们在设计时把太多控制权交给了模型,却没有建立对应的工程约束。

“撒谎”的背后是缺少事实核验机制,“作弊”的背后是权限决策被交给了模型,“盗窃”的背后是数据暴露面没有得到控制。这三个问题都不是靠“换一个更强、更聪明的模型”就能解决的。即使模型推理能力再强,只要它仍然拥有自由调用任意工具的权限,它就有可能在某个边界情况下做错决定。

更稳健的路线是:模型负责“聪明”,工程负责“可靠”。模型的职责是理解用户意图、生成候选动作;工程师的职责是确保这些动作不越界、不泄漏、不产生不可逆后果。

这篇文章提供的示例是一个极简演示,真正的生产 Agent 会比这复杂得多。但你只要掌握了这条核心原则——把不变量放在确定性代码里,把灵活性留在模型推理里——无论你未来使用 LangChain、Spring AI 还是自研框架,都不会跑偏。

如果要把这篇内容收进自己的工具箱,建议重点消化三处:第一,权限校验层必须独立于模型,且不可被对话内容绕过;第二,工具返回字段必须经过白名单裁剪,模型永远接触不到最小集以外的数据;第三,高危操作必须有审计日志和二次确认。把这三条做到位,你的 Agent 大概率就不会成为用户口中那个“撒谎、越权、泄漏数据”的坏东西了。

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

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

立即咨询