当你的AI Agent开始处理客户订单、分析财务报表、甚至生成营销文案时你是否想过它会不会“一不小心”就把用户的手机号、身份证号甚至银行卡信息原封不动地塞进给大模型的提示词里这不是危言耸听。一个未经安全加固的Agent就像一个没有安检的机场任何敏感数据都可能被“夹带”出境暴露在不可控的模型推理过程中。LangChain作为当前最流行的AI应用开发框架其强大的工具调用和链式编排能力在带来便利的同时也极大地扩展了潜在的攻击面和数据泄露风险。本文将彻底拆解一套基于LangChain的“银行级”AI Agent安全防护体系。我们不止步于理论而是聚焦于一个核心判断Agent安全的核心不是事后补救而是在每一次工具调用、每一次LLM交互的“数据流转管道”上建立层层拦截与清洗机制。我们将通过四层实战护栏输入过滤、过程监控、输出脱敏、人工审批手把手带你构建一个能自动识别、脱敏敏感信息并在高风险操作前自动触发人工审批的Agent系统。无论你是正在开发金融、医疗、客服场景的AI应用还是希望提升现有Agent的合规性这篇文章都将提供可直接落地的代码和架构思路。1. 为什么你的AI Agent需要一个“安检系统”在传统软件开发中我们对用户输入进行SQL注入过滤、XSS清洗对数据库连接进行加密和权限控制。但当开发对象变成AI Agent时很多开发者的安全意识却出现了“降级”。常见的误区是认为只要大模型本身“安全”或接入了所谓的“安全API”整个Agent应用就安全了。这种想法极其危险。一个典型的LangChain Agent工作流程如下用户输入一个问题如“帮我查一下张三身份证号110101199001011234最近的存款余额”。Agent的LLM根据问题决定调用“查询用户余额”的工具Tool。该工具可能连接内部数据库或API执行查询。查询结果包含敏感余额信息返回给LLM。LLM组织语言将结果返回给用户。风险潜伏在每一个环节环节1 2输入与决策原始用户输入中的身份证号直接作为Prompt的一部分送给了LLM。如果Prompt被恶意截获或模型服务商存在日志泄露信息即告失守。环节3工具执行工具调用时可能将敏感参数以明文形式传递给外部系统。环节4 5结果返回与输出数据库返回的完整敏感数据如余额、交易记录再次经过LLM处理并输出存在二次泄露风险。更糟糕的是Agent具备自主调用工具的能力。一个被恶意诱导或Prompt注入攻击的Agent可能会调用“删除用户”、“发送邮件”等高危工具。因此Agent安全的目标是双重的一是保护数据隐私不泄露二是管控行为操作不越权。LangChain本身提供了一些基础的安全组件但并未形成一个完整的、开箱即用的防御体系。这就需要我们借鉴“纵深防御”的思想在数据流的关键节点上部署我们的四层“安检护栏”。2. 核心概念LangChain中的安全护栏Guardrails是什么在LangChain的语境下“护栏”并非一个特定的官方模块而是一种设计模式和一系列组件的集合用于约束和规范AI应用的行为。我们可以将其理解为Agent工作流中的“过滤器”和“检查点”。主要的安全机制可以分为以下几类输入/输出过滤器RunnableLambda, CustomCallback在数据流入流出LLM或工具时进行清洗和脱敏。例如将“我的电话是13800138000”替换为“我的电话是[PHONE]”。工具执行控制器Tool Decorator, Agent Executor Hooks在Agent决定调用某个工具前、后插入钩子函数用于验证参数、记录日志、甚至阻断执行。人工审批回路Human-in-the-loop对于定义的高风险操作如转账、删除、发送外部邮件不直接执行而是暂停流程将操作详情提交给人工审核根据审核结果决定继续或终止。提示词安全模板Secure Prompt Templates设计Prompt时明确指令模型避免输出敏感信息或对特定类型的问题进行标准化、无害化回应。为了更清晰地理解这四层护栏如何嵌入Agent的工作流我们可以看下面这个简化的防御体系架构图[用户输入] ↓ [护栏层1: 输入过滤与脱敏] - 识别并替换敏感实体如手机号、身份证 ↓ [Agent核心: LLM决策] - 分析意图选择工具 ↓ [护栏层2: 工具调用审批] - 判断工具风险等级决定直接执行或转人工 ↓ ├── 低风险工具 - [执行工具] └── 高风险工具 - [护栏层3: 人工审批界面] - [批准/拒绝] - [继续/终止] ↓ [工具执行结果] ↓ [护栏层4: 输出内容二次脱敏] - 确保结果中无信息残留 ↓ [最终输出给用户]接下来我们将进入实战环节从零开始构建这个体系。3. 环境准备与项目初始化我们将使用Python和LangChain的最新稳定版进行演示。请确保你的环境满足以下条件Python版本3.10 或以上推荐3.11兼容性更好。包管理工具pip 或 conda。LLM模型本文使用OpenAI GPT-4o-mini作为推理模型你需要准备有效的OPENAI_API_KEY。你也可以替换为其他兼容OpenAI API的模型或本地模型。首先创建一个新的项目目录并安装核心依赖。# 创建项目目录 mkdir langchain-agent-security-demo cd langchain-agent-security-demo # 创建虚拟环境可选但推荐 python -m venv venv # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate # 安装核心依赖 pip install langchain langchain-openai langchain-community python-dotenv # 安装用于敏感信息识别的库我们使用一个简单的正则示例生产环境可考虑spaCy、Presidio等 pip install re2创建项目结构文件touch .env main.py guardrails.py tools.py approval_ui.py README.md在.env文件中配置你的API密钥OPENAI_API_KEYyour_openai_api_key_here4. 第一层护栏敏感信息输入过滤与脱敏在用户问题触达LLM之前我们必须先对其进行“消毒”。这里我们实现一个简单的基于正则表达式的脱敏器。在生产环境中你应该使用更鲁棒的NLP库如Microsoft的Presidio来识别实体。在guardrails.py中我们创建输入过滤器# guardrails.py import re from typing import Any, Dict from langchain_core.runnables import RunnableLambda class SensitiveInfoFilter: 敏感信息过滤与脱敏器 # 定义敏感模式的正则表达式示例 PATTERNS { phone: r(?:(?:\|00)86)?1[3-9]\d{9}, # 中国大陆手机号 id_card: r[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dXx], # 简易身份证号 email: r[a-zA-Z0-9._%-][a-zA-Z0-9.-]\.[a-zA-Z]{2,}, } REPLACEMENTS { phone: [PHONE_NUMBER], id_card: [ID_CARD], email: [EMAIL], } classmethod def desensitize_text(cls, text: str) - str: 对文本进行脱敏处理 desensitized_text text mapping {} # 记录被替换的原始值可用于审计日志 for entity_type, pattern in cls.PATTERNS.items(): matches list(re.finditer(pattern, text)) for i, match in enumerate(matches): original match.group() # 生成唯一标识符便于在后续环节需要时恢复如工具调用 placeholder f{cls.REPLACEMENTS[entity_type]}_{i} desensitized_text desensitized_text.replace(original, placeholder) mapping[placeholder] original return desensitized_text, mapping classmethod def get_input_filter_chain(cls): 返回一个可嵌入LangChain链的RunnableLambda def filter_input(input_dict: Dict[str, Any]) - Dict[str, Any]: # 假设输入是包含input键的字典这是LangChain Agent的常见格式 if input in input_dict: original_text input_dict[input] filtered_text, mapping cls.desensitize_text(original_text) print(f[输入过滤] 原始输入: {original_text}) print(f[输入过滤] 脱敏后: {filtered_text}) print(f[输入过滤] 映射关系: {mapping}) # 将映射关系存入上下文供后续环节如工具调用前恢复使用 input_dict[sensitive_mapping] mapping input_dict[input] filtered_text return input_dict return RunnableLambda(filter_input) # 示例测试脱敏功能 if __name__ __main__: filter SensitiveInfoFilter() test_text 用户张三手机13800138000邮箱zhangsancompany.com申请查询信息。 filtered, mapping filter.desensitize_text(test_text) print(f测试文本: {test_text}) print(f脱敏结果: {filtered}) print(f映射字典: {mapping})这个类将识别出的敏感信息替换为占位符并将原始信息的映射关系保存下来。关键点在于脱敏后的文本送给LLM保证了Prompt的清洁而映射关系被保留在上下文里当后续确实需要调用工具比如根据手机号查用户时我们可以在受控环境下将其恢复。5. 第二层护栏工具执行控制与风险分级不是所有工具都生而平等。我们需要对工具进行风险分级并植入审批逻辑。首先在tools.py中定义几个示例工具。# tools.py from langchain.tools import BaseTool from pydantic import BaseModel, Field from typing import Optional, Type class QueryBalanceInput(BaseModel): 查询余额工具的输入模型 user_id: str Field(description用户的唯一标识ID) account_type: Optional[str] Field(defaultsavings, description账户类型如 savings储蓄, checking支票) class QueryBalanceTool(BaseTool): name query_user_balance description 根据用户ID查询其银行账户余额。这是一个涉及敏感财务信息的操作。 args_schema: Type[BaseModel] QueryBalanceInput def _run(self, user_id: str, account_type: str savings) - str: # 模拟数据库查询 # 在生产环境中这里应该是加密的数据库调用 balance_data { user_001: {savings: 15000.50, checking: 3200.00}, user_002: {savings: 98000.00, checking: 1500.00}, } balance balance_data.get(user_id, {}).get(account_type, 用户或账户类型不存在) return f用户 {user_id} 的 {account_type} 账户余额为{balance} 元。 class TransferFundsInput(BaseModel): 转账工具的输入模型 from_account: str Field(description转出账户ID) to_account: str Field(description转入账户ID) amount: float Field(description转账金额必须大于0) class TransferFundsTool(BaseTool): name transfer_funds description 执行从一个账户到另一个账户的资金转账。这是一个高风险操作。 args_schema: Type[BaseModel] TransferFundsInput def _run(self, from_account: str, to_account: str, amount: float) - str: # 模拟转账操作 # 这是一个高风险操作必须经过审批 return f模拟执行从账户 {from_account} 向账户 {to_account} 转账 {amount} 元。操作已记录。 # 工具风险等级注册表 TOOL_RISK_REGISTRY { query_user_balance: medium, # 中风险涉及敏感信息查询 transfer_funds: high, # 高风险涉及资金变动 # 可以定义更多工具如send_email: medium, get_public_info: low }接下来在guardrails.py中扩展我们的工具调用拦截器。我们将修改LangChain Agent的执行流程在调用工具前进行拦截。# guardrails.py (续) from langchain.agents import AgentExecutor from langchain.agents.agent import AgentAction, AgentFinish from typing import Union, List, Tuple, Any from tools import TOOL_RISK_REGISTRY class ToolCallGuardrail: 工具调用护栏集成到AgentExecutor中 def __init__(self, approval_callbackNone): Args: approval_callback: 一个回调函数当遇到高风险工具时被调用。 应返回 (is_approved: bool, reason: str) self.approval_callback approval_callback def pre_tool_call(self, agent_action: AgentAction, **kwargs) - Union[AgentAction, AgentFinish]: 在工具执行前调用用于审批或修改参数 tool_name agent_action.tool tool_input agent_action.tool_input print(f[工具调用护栏] 准备执行工具: {tool_name}) print(f[工具调用护栏] 输入参数: {tool_input}) # 1. 风险等级检查 risk_level TOOL_RISK_REGISTRY.get(tool_name, low) print(f[工具调用护栏] 工具风险等级: {risk_level}) # 2. 根据风险等级处理 if risk_level high: print([工具调用护栏] 检测到高风险工具触发人工审批...) if self.approval_callback: # 这里可以构建更丰富的审批上下文如用户ID、操作时间等 context { tool: tool_name, input: tool_input, agent_scratchpad: kwargs.get(intermediate_steps, []) } is_approved, reason self.approval_callback(context) if not is_approved: print(f[工具调用护栏] 人工审批被拒绝。理由: {reason}) return AgentFinish( return_values{output: f操作已被人工审批拒绝。理由{reason}}, logfHigh-risk tool {tool_name} was rejected by human. Reason: {reason} ) print([工具调用护栏] 人工审批已通过继续执行。) else: print([工具调用护栏] 未配置审批回调默认阻止高风险工具。) return AgentFinish( return_values{output: 该操作风险较高需要人工审批但系统未配置审批流程已阻止。}, logfHigh-risk tool {tool_name} blocked due to missing approval callback. ) elif risk_level medium: print([工具调用护栏] 中风险工具记录日志并继续执行。) # 可以在这里添加详细的审计日志 else: print([工具调用护栏] 低风险工具直接执行。) # 3. 参数恢复如果之前被脱敏 # 从上下文中获取敏感信息映射并恢复工具参数中的占位符 sensitive_mapping kwargs.get(sensitive_mapping, {}) if sensitive_mapping and isinstance(tool_input, dict): for key, value in tool_input.items(): if isinstance(value, str) and value in sensitive_mapping: original_value sensitive_mapping[value] print(f[工具调用护栏] 恢复参数 {key}: {value} - {original_value}) tool_input[key] original_value # 恢复后可以从映射中移除避免重复使用 # del sensitive_mapping[value] # 返回修改后的AgentAction继续执行 return AgentAction(tooltool_name, tool_inputtool_input, logagent_action.log)这个ToolCallGuardrail类是一个核心控制器。它检查即将被调用的工具的风险等级对高风险工具触发审批流程并对所有工具的参数进行“脱敏恢复”——将之前过滤掉的真实敏感信息在受控的、即将执行具体工具的时刻还原回去。这确保了LLM看到的都是脱敏数据而真正执行操作的底层系统接收到的才是有效数据。6. 第三层护栏人工审批回路集成人工审批是阻止高风险操作的最终安全阀。我们需要一个简单的机制来模拟这个流程。在真实的Web应用中这可以是一个通知中心、一个审批工单系统或一个聊天机器人中的确认按钮。我们在approval_ui.py中创建一个模拟的审批服务# approval_ui.py import json from datetime import datetime from typing import Dict, Tuple class MockApprovalService: 模拟人工审批服务 def __init__(self): self.pending_requests [] self.decision_maker admin # 模拟审批人 def request_approval(self, context: Dict) - Tuple[bool, str]: 模拟发送审批请求并等待或立即返回结果 # 在实际系统中这里可能 # 1. 发送邮件/短信/钉钉/飞书消息给审批人 # 2. 将任务写入数据库等待Web界面操作 # 3. 调用工作流引擎API tool_name context.get(tool, unknown) tool_input json.dumps(context.get(input, {}), indent2, ensure_asciiFalse) print(\n *60) print(【人工审批请求】) print(f工具名称: {tool_name}) print(f操作参数:\n{tool_input}) print(f请求时间: {datetime.now().strftime(%Y-%m-%d %H:%M:%S)}) print(*60) # 模拟人工决策逻辑这里用简单的规则代替人工点击 # 规则示例转账金额超过10000元需要人工批准 if tool_name transfer_funds: amount context.get(input, {}).get(amount, 0) if amount 10000: print(f模拟审批人 {self.decision_maker} 正在审核...) # 模拟审批通过 print( 审批结果通过) return True, f审批人 {self.decision_maker} 已批准该笔转账。 else: print(f模拟审批人 {self.decision_maker} 自动批准小额转账...) return True, 小额转账自动批准。 else: # 对于其他高风险工具默认需要批准这里模拟自动批准 print(f模拟审批人 {self.decision_maker} 审核通过...) return True, f工具 {tool_name} 操作已批准。 # 可以扩展更多方法如查询审批状态、获取审批历史等 # 全局审批服务实例单例模式简单实现 approval_service MockApprovalService()现在我们将所有组件串联起来。在main.py中创建集成了完整四层护栏的Agent# main.py import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain.agents import create_openai_tools_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.memory import ConversationBufferMemory # 导入我们自定义的模块 from tools import QueryBalanceTool, TransferFundsTool from guardrails import SensitiveInfoFilter, ToolCallGuardrail from approval_ui import approval_service # 加载环境变量 load_dotenv() def build_secure_agent(): 构建一个带有安全护栏的LangChain Agent # 1. 初始化LLM llm ChatOpenAI( modelgpt-4o-mini, temperature0, api_keyos.getenv(OPENAI_API_KEY) ) # 2. 定义工具列表 tools [QueryBalanceTool(), TransferFundsTool()] # 3. 构建Prompt模板明确指示Agent注意安全 prompt ChatPromptTemplate.from_messages([ (system, 你是一个专业的银行助手AI必须严格遵守安全规范。 1. 用户可能提供包含手机号、身份证等敏感信息的问题这些信息在系统中已被安全处理。 2. 当你需要调用工具时请严格按照工具描述提供正确的参数。 3. 如果用户请求高风险操作如大额转账系统会启动人工审批流程请如实告知用户。 你的回答应当专业、清晰、安全。 ), MessagesPlaceholder(variable_namechat_history), (human, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), ]) # 4. 创建基础Agent agent create_openai_tools_agent(llm, tools, prompt) # 5. 创建内存用于多轮对话 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue) # 6. 创建工具调用护栏实例并传入审批回调函数 tool_guardrail ToolCallGuardrail( approval_callbacklambda ctx: approval_service.request_approval(ctx) ) # 7. 创建自定义的Agent执行器集成护栏 class SecuredAgentExecutor(AgentExecutor): 集成了安全护栏的Agent执行器 def _call(self, inputs: Dict[str, Any]) - Dict[str, Any]: # 第一层护栏输入过滤 input_filter SensitiveInfoFilter.get_input_filter_chain() filtered_inputs input_filter.invoke(inputs) # 将过滤后的输入和映射关系传递给原始执行流程 # 我们需要重写_intermediate_step来插入工具调用前的护栏 original_intermediate_step self._intermediate_step def guarded_intermediate_step(steps, **kwargs): # 调用父类方法获取下一步动作 next_action original_intermediate_step(steps, **kwargs) # 如果下一步是调用工具则经过护栏检查 if isinstance(next_action, AgentAction): # 将敏感信息映射表传入kwargs kwargs[sensitive_mapping] filtered_inputs.get(sensitive_mapping, {}) guarded_action tool_guardrail.pre_tool_call(next_action, **kwargs) return guarded_action return next_action # 临时替换执行器的方法 self._intermediate_step guarded_intermediate_step try: # 调用父类_call但使用的是过滤后的输入 result super()._call({k: v for k, v in filtered_inputs.items() if k ! sensitive_mapping}) finally: # 恢复原始方法 self._intermediate_step original_intermediate_step # 第四层护栏输出内容二次检查可选这里简单打印日志 if output in result: print(f[输出检查] 最终输出: {result[output]}) # 可以在这里添加额外的输出过滤逻辑例如再次脱敏或关键词屏蔽 return result # 8. 实例化安全的执行器 agent_executor SecuredAgentExecutor( agentagent, toolstools, memorymemory, verboseTrue, # 显示详细的执行步骤 handle_parsing_errorsTrue, # 优雅处理解析错误 max_iterations5, # 限制最大迭代次数防止死循环 early_stopping_methodgenerate # 提前停止策略 ) return agent_executor def main(): print(正在初始化安全增强型AI Agent...) agent build_secure_agent() # 测试用例 test_cases [ # 案例1包含敏感信息的查询中风险工具 我的身份证号是110101199001011234帮我查一下用户ID为user_001的储蓄账户余额。, # 案例2大额转账请求高风险工具应触发审批 我要从账户user_001转账15000元到账户user_002。, # 案例3小额转账高风险工具但可能自动批准 从user_001转500元到user_002。, ] for i, query in enumerate(test_cases, 1): print(f\n{#*40}) print(f测试案例 {i}: {query}) print(f{#*40}) try: response agent.invoke({input: query}) print(f\nAgent回复: {response[output]}) except Exception as e: print(f执行过程中出现错误: {e}) if __name__ __main__: main()7. 运行结果与效果验证运行python main.py你将看到类似以下的输出它清晰地展示了四层护栏的工作流程正在初始化安全增强型AI Agent... ######################################## 测试案例 1: 我的身份证号是110101199001011234帮我查一下用户ID为user_001的储蓄账户余额。 ######################################## [输入过滤] 原始输入: 我的身份证号是110101199001011234帮我查一下用户ID为user_001的储蓄账户余额。 [输入过滤] 脱敏后: 我的身份证号是[ID_CARD]_0帮我查一下用户ID为user_001的储蓄账户余额。 [输入过滤] 映射关系: {[ID_CARD]_0: 110101199001011234} 进入新的Agent执行链... ... [工具调用护栏] 准备执行工具: query_user_balance [工具调用护栏] 输入参数: {user_id: user_001, account_type: savings} [工具调用护栏] 工具风险等级: medium [工具调用护栏] 中风险工具记录日志并继续执行。 [工具调用护栏] 恢复参数 user_id: user_001 - user_001 (本例中user_id未脱敏) ... Agent回复: 用户 user_001 的 savings 账户余额为15000.5 元。对于第二个测试案例大额转账你会看到人工审批流程被触发######################################## 测试案例 2: 我要从账户user_001转账15000元到账户user_002。 ######################################## ... [工具调用护栏] 准备执行工具: transfer_funds [工具调用护栏] 输入参数: {from_account: user_001, to_account: user_002, amount: 15000.0} [工具调用护栏] 工具风险等级: high [工具调用护栏] 检测到高风险工具触发人工审批... 【人工审批请求】 工具名称: transfer_funds 操作参数: { from_account: user_001, to_account: user_002, amount: 15000.0 } 请求时间: 2024-01-01 10:30:00 模拟审批人 admin 正在审核... 审批结果通过 [工具调用护栏] 人工审批已通过继续执行。 ... Agent回复: 模拟执行从账户 user_001 向账户 user_002 转账 15000.0 元。操作已记录。效果验证要点输入脱敏有效身份证号在LLM的Prompt中被替换为[ID_CARD]_0。风险分级有效查询余额被识别为中风险仅记录转账被识别为高风险触发审批。审批回路有效大额转账触发了模拟的审批流程并展示了审批上下文。参数恢复有效虽然演示中user_id未脱敏但机制已就位。如果工具参数中包含[ID_CARD]_0它会被正确恢复为原始身份证号后再调用工具。流程完整Agent在安全约束下依然能完成其核心任务。8. 常见问题与排查思路在实际部署中你可能会遇到以下问题问题现象可能原因排查方式解决方案脱敏不准确正则表达式无法覆盖所有变体如带区号的电话。1. 使用更全面的正则库或NLP实体识别库如spaCypresidio。2. 增加测试用例覆盖边界情况。升级到工业级脱敏库并定期更新识别规则。工具调用被意外阻止工具名称未在TOOL_RISK_REGISTRY中注册默认被当作高风险。检查TOOL_RISK_REGISTRY字典确保所有使用的工具都已正确注册风险等级。为所有工具明确定义风险等级high/medium/low。人工审批回调未触发approval_callback函数未正确传递给ToolCallGuardrail或函数签名/返回值不符合预期。1. 在ToolCallGuardrail.pre_tool_call方法中添加调试打印。2. 检查回调函数是否返回(bool, str)元组。确保回调函数被正确绑定并处理其可能抛出的异常。敏感信息映射丢失sensitive_mapping在Agent执行过程中未正确传递。1. 检查SecuredAgentExecutor._call中如何将filtered_inputs[sensitive_mapping]传递给kwargs。2. 检查guarded_intermediate_step函数是否接收到了该参数。确保上下文kwargs在调用链中正确传递。可以考虑使用LangChain的RunnableConfig来传递自定义数据。Agent陷入死循环人工审批返回AgentFinish后Agent可能仍尝试其他动作。检查max_iterations和early_stopping_method参数设置。观察verbose日志看Agent在审批拒绝后的思考过程。在审批拒绝的AgentFinish中提供更明确的终止信号。确保handle_parsing_errors已开启。性能下降每步都进行正则匹配和上下文检查带来开销。对输入文本进行缓存或对确定不包含敏感信息的查询跳过脱敏步骤。对于内部、可信的数据源可以考虑旁路部分安全检查。优化正则表达式或使用更高效的字符串匹配算法。9. 最佳实践与工程建议将上述Demo转化为生产级应用你需要考虑更多审计与日志记录所有脱敏操作原始值-占位符映射。记录每一次工具调用的请求、参数、风险等级、审批结果和执行结果。使用结构化的日志如JSON格式便于后续分析和合规检查。# 示例审计日志条目 audit_log { timestamp: 2024-01-01T10:30:00Z, session_id: abc123, user_query: 原始查询已脱敏存储, tool_called: transfer_funds, parameters: {from_account: user_001, amount: 15000.0}, # 注意存储前可能也需要脱敏或哈希处理 risk_level: high, approval_required: True, approval_status: approved, approver: admin, action_taken: executed }更精细的权限控制风险分级不应只基于工具还应结合用户角色和操作上下文。例如客服角色可能只能查询不能转账。实现一个权限检查层在工具调用前验证(user_role, tool_name, parameters)三元组是否被允许。审批流程集成将MockApprovalService替换为真正的工单系统如Jira、自研审批中心的API调用。实现异步审批。Agent不应同步等待而是应挂起任务待审批通过后由另一个进程或回调函数触发后续操作。输出内容安全在最终回复给用户前增加一层输出过滤器防止LLM在组织语言时意外泄露信息例如将“他的余额是15000元”中的数字也进行模糊化处理。可以结合提示词工程在系统指令中明确要求模型不要输出原始敏感数据。配置化与可观测性将风险等级规则、脱敏规则、审批阈值等提取到配置文件如YAML或数据库中实现动态更新无需重启服务。为你的安全护栏系统添加监控指标如脱敏次数、高风险调用次数、审批平均耗时并集成到Prometheus/Grafana等监控体系中。测试编写单元测试覆盖各种敏感信息模式。进行渗透测试尝试通过Prompt注入、参数混淆等方式绕过护栏。定期进行红蓝对抗演练持续提升安全水位。AI Agent的安全不是一个可选项而是开发生命周期的核心组成部分。通过本文拆解的四层护栏架构——输入过滤、过程监控、输出脱敏、人工审批——你可以在LangChain框架上构建起一道有效的数据与行为防线。这套方案的价值在于其可插拔性和纵深防御思想你可以根据实际业务需求单独或组合使用这些护栏。真正的安全是“默认安全”的文化。在开始设计下一个Agent时不妨先问自己数据从哪里来经过哪里到哪里去在每个环节我是否都设置了必要的检查和平衡从今天起将安全护栏作为你AI应用的基础设施来建设而不仅仅是事后的补丁。