LangChain4j Guardrails:给你的 AI Service 装上输入输出双层卡口

发布时间:2026/7/1 18:20:25
LangChain4j Guardrails:给你的 AI Service 装上输入输出双层卡口 在做企业知识库问答或者客服 Agent 的时候有一个问题早晚都会碰到用户输入的内容你没法完全信任模型输出的内容也没法完全信任。用户可能提交包含 PII 的文本可能尝试绕过系统提示的限制模型可能返回格式错误的 JSON也可能在回答里顺手提到了竞品名字。处理这些问题的传统做法是在业务层手写 if 判断或者包一层 try-catch 加重试逻辑。LangChain4j 提供了一套更有结构的方案Guardrails一个专门绑定在 AI Service 上的输入输出校验机制。Guardrails 是什么Guardrails 是 LangChain4j 里专门针对 AI Service 的校验机制分为 Input Guardrails 和 Output Guardrails 两层。Input Guardrails 在用户消息发给模型之前执行可以拦截 Prompt 注入、PII 泄漏或不合规的内容。Output Guardrails 在模型返回响应之后执行校验输出格式是否正确、内容是否符合业务规则失败时可以触发重试或补充提示词后重发。重要的一点是Guardrails 只能在 AI Services 上使用它是一个高层抽象无法直接绑定到ChatModel或StreamingChatModel上。如果你的项目里直接操作底层ChatModel的接口这套机制用不上需要先迁移到AiServices的声明式风格。先跑起来一个最简场景假设你在做一个客服 Agent需要拦截用户输入里的敏感话题同时保证模型输出的内容一定是有效 JSON。Maven 依赖版本以实际发布为准请确认 Maven Central 最新稳定版本dependency groupIddev.langchain4j/groupId artifactIdlangchain4j/artifactId version1.1.0/version /dependency dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-open-ai/artifactId version1.1.0/version /dependency定义 AI Service 接口public interface CustomerSupportAgent { SystemMessage(你是一名客服助手只回答与订单和退款相关的问题回答必须是 JSON 格式。) String handleQuery(UserMessage String query); }实现一个 Input Guardrail拦截包含竞品名称的输入public class CompetitorMentionGuardrail implements InputGuardrail { private static final ListString BLOCKED_KEYWORDS List.of(竞品A, 竞品B); Override public InputGuardrailResult validate(UserMessage userMessage) { String text userMessage.singleText(); boolean hasBlockedWord BLOCKED_KEYWORDS.stream() .anyMatch(text::contains); if (hasBlockedWord) { return fatal(您的问题包含不支持讨论的内容请重新描述您的问题。); } return success(); } }实现一个 Output Guardrail校验模型输出是否是合法 JSONpublic class JsonFormatGuardrail implements OutputGuardrail { Override public OutputGuardrailResult validate(AiMessage aiMessage) { String content aiMessage.text(); if (content null || !content.trim().startsWith({)) { return reprompt( 输出格式不合法, 请严格以 JSON 格式返回以 { 开头不要包含 Markdown 标记。 ); } return success(); } }把两个 Guardrail 挂到AiServices上CustomerSupportAgent agent AiServices.builder(CustomerSupportAgent.class) .chatLanguageModel(model) .chatMemory(MessageWindowChatMemory.withMaxMessages(10)) .inputGuardrails(new CompetitorMentionGuardrail()) .outputGuardrails(new JsonFormatGuardrail()) .build();三个细节值得注意第一Input Guardrail 的fatal()和 Output Guardrail 的reprompt()语义不同。Input Guardrails 不支持重试或重新提示一旦fatal()触发整个请求就终止了这也意味着它能在发出 API 调用之前就把成本省下来。Output Guardrails 则可以通过reprompt()向原有上下文追加提示信息然后让模型重试直到达到最大重试次数上限。第二多个 Guardrail 可以叠加执行顺序按注册顺序走。可以在AiServicesbuilder 上直接注册实例或类名也可以通过InputGuardrails和OutputGuardrails注解放在接口方法或接口类上builder 上注册的优先级最高。这个设计很适合把通用 Guardrail放在 builder 上把针对某个方法的特殊校验放在注解上职责分层清晰。第三Output Guardrail 校验失败时会把失败原因和reprompt内容追加进对话历史触发下一次请求。这个机制在 JSON 格式校验、业务规则校验这类场景里很实用但要注意设置合理的maxRetries避免因为模型反复输出格式错误导致无限循环。实践中可以通过配置限制最大重试次数3 次是一个相对合理的起点。用更复杂的输入校验对于 PII 检测、Prompt 注入这类场景简单的关键词匹配往往不够用。LangChain4j 的文档里提到一种思路在 Input Guardrail 内部再建一个轻量的AiServices实例专门用于内容分类用一个更小、更快的模型来判断输入是否合规只有通过分类的请求才会继续往下走。这样做的好处是主流程用的模型不变分类任务可以选成本低得多的轻量模型两者互不影响// 在 Guardrail 内部使用独立的 AiService 做分类判断伪代码具体实现参考官方文档 public class PiiDetectionGuardrail implements InputGuardrail { private final TextClassifier classifier; // 内部轻量分类 AiService public PiiDetectionGuardrail(ChatLanguageModel fastModel) { this.classifier AiServices.create(TextClassifier.class, fastModel); } Override public InputGuardrailResult validate(UserMessage userMessage) { String verdict classifier.classify(userMessage.singleText()); if (UNSAFE.equalsIgnoreCase(verdict.trim())) { return fatal(输入包含敏感信息请重新描述。); } return success(); } }这个模式在企业场景里比较常见主模型做业务回答分类模型专注安全判断两条链路并行成本可控。工程化落地要想清楚的事Guardrails 机制本身并不复杂但在项目里真正用好它有几件事需要提前想清楚。Guardrail 的粒度要合理。不要把所有校验逻辑堆在一个 Guardrail 类里每个 Guardrail 专注一个职责叠加使用。这和 Filter 链、拦截器链的设计原则是一样的职责拆分清楚后测试也更容易写。Output Guardrail 的reprompt会消耗额外 Token。每一次重试都会把补充提示词追加进上下文再发一次请求在生产环境里要关注这部分的 Token 消耗必要时记录日志评估哪些输出校验频繁触发重试。对于流式响应场景Guardrails 的支持需要单独确认你当前使用的版本具体 API 行为可能和非流式场景有所不同实际接入前以官方文档和 Release Notes 为准。LangChain4j 的 Guardrails 把一类过去散落在业务层、各自为政的防御逻辑收拢成了框架层面有结构的能力。它不是万能的安全方案但它让这部分逻辑有了统一的接入点也有了可测试、可复用的结构。对于正在做企业 AI 应用的 Java 团队这是值得尽早了解的一个机制。