这篇适合谁,读完能做到什么
适合要把智能体用在客服、金融、医疗或企业内部等场景、需要先把关敏感信息和危险输出的开发者。读完你应该能分清规则护栏和模型护栏,用内置的 PII 检测过滤个人信息,给高风险工具加上人工审批,并写出执行前后的自定义护栏,再把它们按顺序组合起来。
护栏是什么,放在哪一步
护栏在智能体执行的关键节点校验和过滤内容。它能发现敏感信息、执行内容政策、校验输出,并在不安全的行为造成伤害之前拦住它[1]。常见用途包括防止个人信息泄露、识别并拦截提示词注入攻击、屏蔽不当或有害内容、落实业务规则和合规要求,以及校验输出的质量和准确性[1]。
护栏通过中间件(middleware)实现。中间件可以在智能体开始之前、结束之后,或者包住模型调用和工具调用的前后介入执行[1]。
规则护栏和模型护栏
两种护栏可以配合使用。规则护栏用正则、关键词匹配或显式检查,速度快、结果可预期、成本低,但可能漏掉语义上的违规[1]。模型护栏用 LLM 或分类器来判断内容,能捕捉规则抓不住的细微问题,代价是更慢、更贵[1]。
内置护栏一:PII 检测
PII(个人身份信息)中间件能检测对话里常见的几类个人信息,比如邮箱、信用卡号和 IP 地址[1]。内置的类型包括 email、credit_card(通过 Luhn 校验)、ip、mac_address 和 url[1]。
检测到之后怎么处理,由 strategy 决定:
redact:替换成[REDACTED_{PII_TYPE}]的形式,例如[REDACTED_EMAIL][1]。mask:部分遮盖,例如只保留后 4 位[1]。hash:替换成确定性的哈希值[1]。block:检测到就抛出异常[1]。
默认策略是 redact。默认只检查用户输入(apply_to_input 为 True),AI 消息和工具结果默认不检查,需要时用 apply_to_output 或 apply_to_tool_results 打开[1]。下面的例子只对用户输入里的邮箱做脱敏:
PIIMiddleware(
"email",
strategy="redact",
apply_to_input=True,
),如果要拦截特定格式的密钥,可以用自定义的正则 detector,并把 strategy 设为 block:
PIIMiddleware(
"api_key",
detector=r"sk-[a-zA-Z0-9]{32}",
strategy="block",
apply_to_input=True,
),把 apply_to_output=True 打开后,PIIMiddleware 还会对流式输出做脱敏,覆盖文本增量、工具调用参数、工具输出和状态快照,依靠的是注册到中间件上的流式转换器。这需要 langchain>=1.3.2[1]。这个转换器会把每个文本块、工具调用参数和工具输出的最后 128 个字符暂存起来,直到后面又来了文本或者这一块结束,再对暂存文本加上新增量运行检测器[1]。
内置护栏二:人工审批
人工审批中间件会在执行敏感操作之前要求人工批准。它适合的场景包括资金转账、删除或修改生产数据、对外发送消息,以及其他影响重大的操作[1]。
配置时,interrupt_on 决定哪些工具需要审批,哪些自动放行:
HumanInTheLoopMiddleware(
interrupt_on={
# Require approval for sensitive operations
"send_email": True,
"delete_database": True,
# Auto-approve safe operations
"search": False,
}
),人工审批需要持久化,所以要配上检查点,并为每次对话指定线程 ID。智能体会暂停,等待审批[1]:
# Human-in-the-loop requires a thread ID for persistence
config = {"configurable": {"thread_id": "some_id"}}人工给出决定后,用同一个线程 ID 恢复执行。决定通过 Command 传入,例如批准就写 {"type": "approve"}[1]:
result = agent.invoke(
Command(resume={"decisions": [{"type": "approve"}]}),
config=config # Same thread ID to resume the paused conversation
)自定义护栏:执行前和执行后
如果内置护栏不够用,可以写自定义中间件,在智能体执行前后运行。这样你能完全掌控校验逻辑、内容过滤和安全检查[1]。
执行前的钩子(before-agent hook)在每次调用开始时校验一次。它适合认证、限流,或者在处理开始前就拦下不当请求[1]。下面是一个按关键词拦截的类,初始化时接收禁用词列表:
class ContentFilterMiddleware(AgentMiddleware):
"""Deterministic guardrail: Block requests containing banned keywords."""
def __init__(self, banned_keywords: list[str]):
super().__init__()
self.banned_keywords = [kw.lower() for kw in banned_keywords]这样的护栏会在处理开始之前拦下请求。例如,包含禁用词的提问会在任何处理之前被挡住:
# This request will be blocked before any processing
result = agent.invoke({
"messages": [{"role": "user", "content": "How do I hack into a database?"}]
})执行后的钩子(after-agent hook)在结果返回给用户之前,对最终输出校验一次。它适合基于模型的安全判断、质量校验和合规扫描[1]。下面的例子让一个模型判断回答是否安全:
# Use a model to evaluate safety
safety_prompt = f"""Evaluate if this response is safe and appropriate.
Respond with only 'SAFE' or 'UNSAFE'.
Response: {last_message.content}"""
result = self.safety_model.invoke([{"role": "user", "content": safety_prompt}])组合多个护栏
护栏可以叠加,把它们放进 middleware 列表即可。它们按列表顺序依次执行,形成多层防护[1]。
限制与常见问题
- 规则护栏速度快,但可能漏掉语义层面的违规。关键场景通常要两种护栏配合[1]。
- 流式脱敏会暂存末尾 128 个字符,输出会有一点延迟,这是为了让跨增量的匹配也能被检测到[1]。
- 人工审批依赖检查点和线程 ID,缺了就无法在中断后恢复[1]。
下一步
想系统了解自定义中间件,可以读中间件文档和 API 参考。人工审批的完整流程见人工审批页面[1]。
来源
- 1GuardrailsLangChain docs (MIT)
引用本页: LangChain 护栏:过滤敏感信息与危险输出. TellWorld, https://www.tellworld.net/zh/practice/practice-langchain-guardrails. 更新于 2026-11-14