mehmandarov/llm-security-and-predictability

GitHub: mehmandarov/llm-security-and-predictability

一个以发票提取为示例场景的 LLM 应用工程教学项目,演示如何通过多层 Guardrails、确定性验证、自我纠正和多模型共识等模式,在概率性 LLM 之上构建安全、可预测的生产级系统。

Stars: 6 | Forks: 0

# 驯服混沌:LLM 驱动应用中的安全性与可预测性 此代码库包含了演讲 **“Taming the Chaos”** 的演示代码和示例。它演示了在概率性 LLM 之上构建安全、可预测系统的实用模式。 ## 概述 LLM 本质上是概率性的 —— 非常适合发挥创造力,但用于业务逻辑却很危险。它们可能会泄露敏感数据、服从注入的指令、产生幻觉值,并且每次都给出不同的答案。本项目逐步介绍了“LLM 悲痛的 5 个阶段”,展示了如何从天真幼稚的实现走向经过生产环境加固的韧性系统 —— 保护输入和输出、使用确定性代码进行验证、通过反馈循环进行自我纠正,以及通过多模型共识建立信心。附加章节演示了通过“镜像测试”进行合成验证。 ## 前置条件 * **Java 25+** * **Maven** * **Ollama**(可选 —— 用于端到端集成测试) # 安装:https://ollama.com ollama pull gemma4:e2b ollama pull llama3.2:1b # 可选 —— 启用真正的多模型共识演示 ## 快速开始 1. **克隆代码库:** git clone cd llm-security-and-predictability 2. **运行单元测试(无需 LLM):** 核心逻辑通过带有模拟模型的 JUnit 测试进行演示。 mvn test 3. **运行端到端测试(需要 Ollama):** 这些测试会访问真实的本地 Ollama 实例 —— 非常适合现场演示。 ollama serve # 在单独的终端中,如果尚未运行 mvn verify 如果无法连接到 Ollama,集成测试将被自动跳过。 ## 项目结构 代码按 **章节** 进行组织,与演讲的叙述相对应: * **第 1 章:基础(天真实现)** * `SimpleInvoiceExtractor.java`:基本的 LangChain4j 服务接口。 * *经验教训:* 结构化输出并不等于验证。 * **第 2 章:攻击(安全与 Guardrails)** * **第 1 层 —— 简单的 Guardrails:** `PromptInjectionGuardrail.java`(关键字黑名单 + 分隔符突破检测)、`InputLengthGuardrail.java`(阻止 prompt 填充)、`PiiGuardrail.java`(从输出中脱敏敏感数据)。 * **第 2 层 —— 金丝雀陷阱:** `CanaryTokenGuardrail.java` + `CanaryInvoiceExtractor.java` —— 嵌入一个秘密的“金丝雀” token 作为注入绊线。 * **第 3 层 —— 输出格式:** `OutputFormatGuardrail.java` —— 拒绝非 JSON 响应。 * **第 4 层 —— 分隔符三明治:** `SandwichedInvoiceExtractor.java` —— 将用户输入包裹在 `` / `` 分隔符中(OWASP 推荐)。测试表明,仅靠三明治并 **不能** 阻止突破 —— 这只是一种提示,而非强制执行。 * **第 5 层 —— 保安:** `IntentClassifier.java` —— 一个廉价的模型,在调用昂贵模型之前预先筛查恶意意图。 * **第 6 层 —— 坚固城堡:** `FortifiedInvoiceExtractor.java` —— 结合所有 guardrails。通过简单三明治提取器的同一个 `SANDWICH_BREAKOUT` 在这里会被捕获。 * *此外:* `SecureInvoiceExtractor.java`(连接了注入 + PII guardrails 的提取器)。 * *经验教训:* 永远不要相信输入;永远不要相信输出。纵深防御。 * **第 3 章:幻觉(确定性验证)** * `StrictValidator.java`:*确定性地* 验证 schema(Jakarta Beans)和业务逻辑(数学、日期)。 * `OutputNormalizer.java`:规范化 LLM 输出(金额 → 2 位小数,货币 → 大写,字符串修剪空白),从而使“足够接近”变为完全相同。纯 Java,无 LLM。 * `InvoiceCalculatorTool.java`:带有 `@Tool` 注解的方法(`calculateTotal`、`calculateTax`)—— LLM 决定 *何时* 计算,但数学运算本身是确定性的 Java 代码。 * `ToolAwareInvoiceExtractor.java`:通过 `AiServices.builder().tools()` 连接了工具的提取器。 * `ExpressionEvaluator.java`:安全的算术计算器 —— LLM 生成公式,Java 执行它。拒绝代码注入尝试。 * `FormulaGenerator.java`:要求 LLM 输出算术表达式,而不是计算好的答案。 * *经验教训:* 相信代码,而不是模型。不要让 LLM 做数学运算 —— 给它一个计算器,或者让它编写公式并由你自己执行。 * **第 4 章:讨价还价(自我纠正)** * `CorrectiveExtractor.java`:将验证错误反馈给 LLM 以进行第二次尝试。 * *经验教训:* 将运行时异常转化为成功的交易。 * **第 5 章:委员会(共识与确定性)** * `MultiModelConsensus.java`:查询多个模型并使用多数投票来确保准确性。 * `StabilityAnalyzer.java`:运行 N 次提取并计算每个字段的同意百分比。 * `SafeExtractionPipeline.java`:顶点之作 —— 串联 提取 → 验证 → 自我纠正,并返回类型化的裁决:`ACCEPTED`、`NEEDS_REVIEW` 或 `REJECTED`。 * *经验教训:* 使用 Seeds、共识和稳定性度量将概率转化为可预测性。 * *附加内容:* 基于 Seed 的可重现性测试(`OllamaEndToEndIT.java`)验证 `temperature=0` + `seed=42` 是否产生相同结果。 * **附加内容:大结局(镜像测试)** * `MirrorVerifier.java`:执行往返“重构”(JSON → 文本)以检测静默遗漏。 * *经验教训:* 当没有“黄金标准答案”时,根据原始事实验证提取结果。 ## 关键技术 * **LangChain4j**:用于 LLM 集成和 AI Service 接口。 * **Ollama**:用于端到端测试的本地 LLM 推理(gemma4:e2b、llama3.2:1b)。 * **Jakarta Validation**:用于 schema 和约束验证。 * **JUnit 5 & Mockito**:用于对模式进行单元测试。 * **Maven Failsafe**:用于集成测试(`mvn verify`)。 ## 测试结构 * `Chapter1Test` – `Chapter6Test`:每个章节的单元测试,模拟模型,速度快。 * `LLMValidationTalkTest.java`:整个演讲的单文件演练(按顺序包含所有章节)。 * `OllamaEndToEndIT.java`:针对真实 Ollama 实例的实时集成测试(23 个测试,`mvn verify`)。 * `InvoiceTestData.java`:共享测试数据 —— 干净的发票、注入攻击、`SANDWICH_BREAKOUT`、`PROMPT_STUFFING`、`MESSY_OCR`、`AMBIGUOUS_DATE`、PII 泄露等。 *注意:通用模型和共享代码位于 `com.mehmandarov.llmvalidation.model` 中。* ## 重要提示 代码、幻灯片和文本内容归 Rustam Mehmandarov 所有,未经事先同意不得复制。
标签:AI工程, AI风险缓解, API密钥检测, DLL 劫持, LangChain4j, 域名枚举, 大语言模型, 示例代码, 输入验证