nraesalmi/n8n-agent-vulntest-lab
GitHub: nraesalmi/n8n-agent-vulntest-lab
一个针对 n8n AI agent 工作流的安全研究实验室,用于系统性评估 prompt injection 和平台特定执行漏洞如何通过基于节点的低代码系统传播。
Stars: 0 | Forks: 0
# AI 工作流安全研究实验室
**低代码 AI agent 工作流平台在 prompt-injection 和执行图操纵下的安全性**
一个受控的实验框架,用于研究 prompt-injection 类攻击和特定平台执行漏洞如何通过基于节点的 AI 工作流系统 传播,其中 LLM 的输出被编译为具有外部副作用的可执行工作流图。包含 **13 个攻击场景**(baseline / basic-guardrail / custom-guardrail 变体)和 **2 个可重用的安全子工作流脚手架**,并对照 OWASP LLM 应用程序 Top 10 和 OWASP Agentic 应用程序 Top 10 进行了映射。
## 研究背景
### 前提
诸如 n8n 这样的低代码自动化系统,暴露出与会话聊天机器人根本不同的攻击面。在这些系统中,LLM 的输出不仅仅是作为文本呈现——它们被编译成具有真实外部副作用的可执行工作流图:数据库写入、HTTP 调用、工具调用以及控制流决策。
虽然 prompt injection 在基于聊天的、code-first 的 agent 框架(如 LangChain、AutoGPT)中已被深入研究,但这些文献假设存在一个编排层,研究人员可以直接作为代码进行检查和探测,且工具调用以强类型的函数参数实现。n8n 的 AI Agent 节点封装了相同的 LangChain 工具调用接口,但其周围的执行环境是一个由独立配置的节点组成的可视化编排图,每个节点都有自己的凭证作用域。在这里,数据——包括 LLM 通过 `$fromAI()` 动态填充的值——在被路由到工具的可执行参数之前,会经过一种独立的服务器端表达式评估语言处理。已经为 code-first agent 记录的攻击类别是否在此处以相同方式表现,或者是否伴随着特定于这种节点图执行模型的故障模式,尚未得到系统性检验。
### 论点
Prompt-injection 类攻击可以通过基于工作流的 AI 系统传播,在这些系统中,信任边界是隐式的,并且通常跨越多个节点、凭证和外部集成。除此之外,n8n 自身的执行模型——其表达式评估器、其按节点的凭证作用域以及由 AI 填充的工具参数——引入了完全独立于 LLM 推理操纵的故障模式,而通用的 agent 安全基准并未对这些模式进行建模。
### 范围:两类故障
本实验室刻意区分了两类漏洞,因为将它们混为一谈会掩盖哪些缓解措施实际上适用于哪种故障:
| 类别 | 测试内容 | 示例 |
|---|---|---|
| **推理层** | 模型通过精心构造的输入被操纵,从而做出错误决定 | 注入的网页内容说服 agent 在其回复中泄露凭证 |
| **平台层** | n8n 执行引擎中的确定性机制发生失误,与模型决定的内容无关 | 以 `=` 开头的存储表单字段在下游被读回时被当作表达式评估 |
大多数已发表的 IPI 基准(InjecAgent、AgentDojo、Agent Security Bench)仅测试第一类,因为 code-first 的 agent 框架没有等效的平台层可供测试。下面十个场景中的三个(wf_03、wf_05、wf_ps_03)是专门为分离第二类而构建的。
### 攻击场景套件
场景现在按故障层分为两个套件,外加一个用于刻意跨越两层链式攻击的复合小
分类。如果场景具有
多个通道或后端变体,这些将作为
同一工作流的 payload/config 变体运行,而不是单独的工作流文件——有关
完整的变体矩阵,请参阅
`n8n/workflows/README.md`。
**关于以前混合的两个场景(旧 wf_03、wf_05):** 两者都需要
一个 AI 填充的(`$fromAI()`)值来*触发*故障,但故障
本身——表达式重新评估、通过凭证条件保护的 SSRF——
发生在平台层,与模型的推理是否被
操纵无关。基于此,它们被放置在平台套件中,并且
明确指出了触发机制,以免与 wf_ps_04/05
(见下文)混淆,后者完全不需要 AI 参与即可演示。
**关于复合场景(旧 wf_10):** 它不属于任何一个套件——
其全部目的是测试当只有完整链条需要成功时,来自*两个*套件的逐步缓解是否
有效。它被保留为单独的
单一条目分类,而不是强行塞入某一个套件中。
#### 推理套件 (wf_rs_xx)
| # | 场景 | 主要 OWASP 类别 | 备注 |
|---|---|---|---|
| **wf_rs_01** ✓ | 直接 Prompt Injection (baseline) | LLM01 | 校准控制——所有其他结果都相对于此进行解释 |
| **wf_rs_02** | 间接 Injection,多通道 | LLM01 | 变体:网页内容、数据库行、电子邮件正文 |
| **wf_rs_03** ✓ | 过度代理 / 工具劫持 + Guardrail 绕过 | ASI02 | 包括针对原生 Guardrails 节点自身人工审查门控的工具等效绕过测试 |
| **wf_rs_04** | System Prompt 提取 | LLM07 | 架构无关;与已发布的 LangChain/chatbot 基准数据进行对比 |
| **wf_rs_05** | 记忆和上下文投毒 | ASI06 | 变体:会话/缓冲区记忆,向量存储检索记忆 |
| **wf_rs_06** | 无限制消耗 / Agent 循环 | LLM10 | 架构无关;影响框架(计费的 API/执行成本)与 n8n 相关 |
评估方式为在 30 次试验批次中跨每个 payload 层级和每个 LLM 后端的
带有置信区间的成功率,
与现有的可重现性方法论保持一致。`basic_guardrail` 实验组 = n8n 的原生 Guardrails
节点。
#### 平台套件 (wf_ps_xx)
| # | 场景 | 主要 OWASP 类别 | 触发器 | 备注 |
|---|---|---|---|---|
| **wf_ps_01** | 不安全输出处理:代码/表达式注入 | LLM02 | AI 填充值 | 将通用的“LLM 输出到达 Code 节点”与 n8n 的二阶 `=` 前缀表达式重新评估模式进行对比;针对 CVE-2025-68613 系列进行修补前/后版本边界测试 |
| **wf_ps_02** | 通过 SSRF 链式 `$fromAI()` 窃取凭证 | LLM02 / ASI02 | AI 填充值 | 测试当 AI 填充的 URL 参数作为传递机制时,n8n 的凭证条件 SSRF 保护是否仍然有效 |
| **wf_ps_03** ✓ | 通过子工作流凭证交叉进行的 Agent 身份和权限滥用 | ASI03 | AI 填充值 | 测试注入的上下文是否可以将 AI 填充的 `Execute Sub-workflow` 目标重定向到更高权限的工作流 |
| **wf_ps_04** *(验证)* | 通过未经验证的恢复 Webhook 绕过人工审查门控 | ASI01 | 无——不涉及 AI | 纯控制平面绕过;auth-configuration 变体 而非 payload 层级 |
| **wf_ps_05** *(验证)* | 批量执行中的跨项批准恢复污染 | ASI02 | 演示时不需要 AI 参与;与注入的第二项配对以进行安全后果框架描述 | 每种批处理大小配置的确定性通过/失败,而非基于试验的成功率 |
| **wf_ps_06** *(验证)* | HITL 预览/执行内容不匹配 | ASI01 | AI 填充值 | AI 为人工批准对话框生成预览描述,然后在同一轮次中执行工具调用——注入可以使预览看起来无害,而实际工具参数却是恶意的;测试绑定预览的输出与绑定执行的输出是否会产生分歧 |
评估方式主要为跨配置变体(auth 模式、批处理大小、修补前/后版本)的确定性通过/失败,
而非基于试验的
成功率,因为这些属于平台机制故障,而非概率性的模型
行为。`custom_guardrail` 实验组 = 你的平台层强制执行节点
(§5),在适用的地方跨 n8n 版本边界进行测试。
#### 复合 / 链式 (wf_cc_xx)
| # | 场景 | 主要 OWASP 类别 | 备注 |
|---|---|---|---|
| **wf_cc_01** | 复合击杀链 | ASI01 + ASI02 + ASI03 | 串联 wf_rs_02 → wf_rs_03 → wf_ps_03 的 payload,以测试当只需整个链条成功时,逐步缓解措施(来自两个套件)是否仍然有效 |
一个核心研究问题是,当输出被解释为**结构化执行指令**而非自然语言回复时,
传统的 LLM 安全缓解措施
(system prompt、输出过滤、基本 guardrail)是否仍然有效
(推理套件,RQ1)——另外,应用程序层的
强制执行机制是否能够触及完全
发生在 n8n 平台层内的故障(平台套件,RQ2)。
## 架构
### Docker 服务
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ Docker Network │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ │ │ │ │ │ │
│ │ n8n │───▶│ PostgreSQL │ │ Ollama │ │
│ │ :5678 │ │ :5432 │ │ :11434 │ │
│ │ │◀───│ │ │ │ │
│ └───┬────┬─────┘ └──────────────┘ └──────────────┘ │
│ │ │ │
│ │ ├────────────────────────────┐ │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌──────────────────┐ ┌──────────────────┐ │
│ │ │ mock-server │ │attacker-listener │ │
│ │ │ :8080 │ │ :9999 │ │
│ │ └──────────────────┘ └──────────────────┘ │
│ │ ┌──────────────────┐ │
│ │ │ mockapi │ │
│ │ │ :3000 │ │
│ │ └──────────────────┘ │
│ │ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ AVISE → POST to webhook → agent executes │ │
│ │ HTTP response with tool calls for evaluation │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────┘
```
所有服务均作为 Docker 容器运行:
| 服务 | 端口 | 用途 |
|---|---|---|
| n8n | 5678 | 工作流编排引擎和 UI |
| PostgreSQL | 5432 | n8n 状态 + `agent_messages` 表 |
| Ollama | 11434 | 本地 LLM 推理(后备 / 气隙隔离模式) |
| mockapi | 3000 | `json-server` —— 提供模拟文档、常见问题解答、通知 |
| mock-server | 8080 | Flask 服务器 —— 包含 15 个以上用于间接注入实验的端点,包括用于 wf_05 SSRF 测试的内部/不可路由目标 |
| attacker-listener | 9999 | Flask 服务器 —— 捕获实验期间外泄的数据 |
### 多模型 LLM 后端
所有工作流均使用兼容 OpenAI 的 `lmChatOpenAi` 节点,该节点适用于任何提供兼容 OpenAI 的 API 的提供商:
| 提供商 | LLM_BASE_URL | LLM_MODEL |
|---|---|---|
| OpenAI | *(空——默认为 api.openai.com)* | gpt-4o, gpt-4o-mini, ... |
| OpenCode | https://api.opencode.ai/v1 | opencode/deepseek-v4-flash-free, ... |
| OpenRouter | https://openrouter.ai/api/v1 | openai/gpt-4o, anthropic/claude-3, ... |
| Ollama | http://ollama:11434/v1 | mistral, llama3, ... |
模型和 base URL 通过环境变量配置,并在运行时通过 n8n 表达式(`{{ $env.LLM_MODEL }}`、`{{ $env.LLM_BASE_URL }}`)注入。批处理修补程序脚本(`scripts/patch_workflow_models.py`)将这些表达式标记到所有工作流 JSON 中。不需要特定于模型的节点类型。
**关于确定性的说明:** temperature=0 会减少差异,但不能保证托管 API 上的输出位级相同——尤其是 OpenRouter,它可以将相同的请求路由到不同的后端实例。结果应报告为在 30 次试验批次中的带置信区间的成功率(见下文的*可重现性*),而不是单次运行的结果。
## 设置
### 前置条件
- Docker 和 Docker Compose v2
- 至少 8 GB RAM(推荐 16 GB)
- (可选)你选择的 LLM 提供商的 API 密钥
### 第 1 步:配置环境
```
cp .env.example .env
```
使用你的值编辑 `.env`:
```
# 必需:生成一个安全的随机 32 字符密钥
N8N_ENCRYPTION_KEY=
# 必需:设置一个强密码
POSTGRES_PASSWORD=
# LLM Backend 配置
# 取消注释并设置至少一个 API key:
OPENCODE_API_KEY=sk-... # or
#OPENAI_API_KEY=sk-... # or
#OPENROUTER_API_KEY=sk-... #
# 为你的 provider 设置模型和 base URL:
LLM_BASE_URL=https://api.opencode.ai/v1
LLM_MODEL=opencode/deepseek-v4-flash-free
# 固定 n8n image 版本。用于 CVE 边界比较 ——
# 请参阅下方的“Platform Version Testing”。不要保留为 'latest'。
N8N_VERSION=1.122.0
```
**重要提示:** 确保 `N8N_ENCRYPTION_KEY` 至少有 32 个字符。当使用 PostgreSQL 时,如果加密密钥较弱,n8n 将拒绝启动。
### 第 2 步:创建虚拟环境 + 安装依赖
```
# 创建虚拟环境
python -m venv .venv
# 激活 (Windows PowerShell)
.venv\Scripts\Activate.ps1
# 激活 (macOS/Linux)
source .venv/bin/activate
# 安装依赖
pip install -r requirements.txt
```
### 第 3 步:启动服务
```
docker compose up -d
```
这将启动 n8n(端口 5678)、PostgreSQL(端口 5432)、Ollama(端口 11434)、mockapi(端口 3000)、mock-server(端口 8080)和 attacker-listener(端口 9999)。
### 第 4 步:(可选)拉取 Ollama 模型
仅在将 Ollama 用作 LLM 后端(气隙隔离模式)时需要:
```
docker exec n8n-ollama ollama pull llama3.1:8b
```
在 `.env` 中设置 `OLLAMA_MODEL=llama3.1:8b`(或更小的模型,如 `phi3` 或 `mistral`)。
### 第 5 步:导入凭证和工作流
为你的操作系统运行相应的设置脚本:
**Linux/macOS**
```
./scripts/setup.sh
```
**Windows (PowerShell)**
```
.\scripts\setup.ps1
```
要临时绕过 Powershell 脚本执行策略,请运行:
## 研究背景
### 前提
诸如 n8n 这样的低代码自动化系统,暴露出与会话聊天机器人根本不同的攻击面。在这些系统中,LLM 的输出不仅仅是作为文本呈现——它们被编译成具有真实外部副作用的可执行工作流图:数据库写入、HTTP 调用、工具调用以及控制流决策。
虽然 prompt injection 在基于聊天的、code-first 的 agent 框架(如 LangChain、AutoGPT)中已被深入研究,但这些文献假设存在一个编排层,研究人员可以直接作为代码进行检查和探测,且工具调用以强类型的函数参数实现。n8n 的 AI Agent 节点封装了相同的 LangChain 工具调用接口,但其周围的执行环境是一个由独立配置的节点组成的可视化编排图,每个节点都有自己的凭证作用域。在这里,数据——包括 LLM 通过 `$fromAI()` 动态填充的值——在被路由到工具的可执行参数之前,会经过一种独立的服务器端表达式评估语言处理。已经为 code-first agent 记录的攻击类别是否在此处以相同方式表现,或者是否伴随着特定于这种节点图执行模型的故障模式,尚未得到系统性检验。
### 论点
Prompt-injection 类攻击可以通过基于工作流的 AI 系统传播,在这些系统中,信任边界是隐式的,并且通常跨越多个节点、凭证和外部集成。除此之外,n8n 自身的执行模型——其表达式评估器、其按节点的凭证作用域以及由 AI 填充的工具参数——引入了完全独立于 LLM 推理操纵的故障模式,而通用的 agent 安全基准并未对这些模式进行建模。
### 范围:两类故障
本实验室刻意区分了两类漏洞,因为将它们混为一谈会掩盖哪些缓解措施实际上适用于哪种故障:
| 类别 | 测试内容 | 示例 |
|---|---|---|
| **推理层** | 模型通过精心构造的输入被操纵,从而做出错误决定 | 注入的网页内容说服 agent 在其回复中泄露凭证 |
| **平台层** | n8n 执行引擎中的确定性机制发生失误,与模型决定的内容无关 | 以 `=` 开头的存储表单字段在下游被读回时被当作表达式评估 |
大多数已发表的 IPI 基准(InjecAgent、AgentDojo、Agent Security Bench)仅测试第一类,因为 code-first 的 agent 框架没有等效的平台层可供测试。下面十个场景中的三个(wf_03、wf_05、wf_ps_03)是专门为分离第二类而构建的。
### 攻击场景套件
场景现在按故障层分为两个套件,外加一个用于刻意跨越两层链式攻击的复合小
分类。如果场景具有
多个通道或后端变体,这些将作为
同一工作流的 payload/config 变体运行,而不是单独的工作流文件——有关
完整的变体矩阵,请参阅
`n8n/workflows/README.md`。
**关于以前混合的两个场景(旧 wf_03、wf_05):** 两者都需要
一个 AI 填充的(`$fromAI()`)值来*触发*故障,但故障
本身——表达式重新评估、通过凭证条件保护的 SSRF——
发生在平台层,与模型的推理是否被
操纵无关。基于此,它们被放置在平台套件中,并且
明确指出了触发机制,以免与 wf_ps_04/05
(见下文)混淆,后者完全不需要 AI 参与即可演示。
**关于复合场景(旧 wf_10):** 它不属于任何一个套件——
其全部目的是测试当只有完整链条需要成功时,来自*两个*套件的逐步缓解是否
有效。它被保留为单独的
单一条目分类,而不是强行塞入某一个套件中。
#### 推理套件 (wf_rs_xx)
| # | 场景 | 主要 OWASP 类别 | 备注 |
|---|---|---|---|
| **wf_rs_01** ✓ | 直接 Prompt Injection (baseline) | LLM01 | 校准控制——所有其他结果都相对于此进行解释 |
| **wf_rs_02** | 间接 Injection,多通道 | LLM01 | 变体:网页内容、数据库行、电子邮件正文 |
| **wf_rs_03** ✓ | 过度代理 / 工具劫持 + Guardrail 绕过 | ASI02 | 包括针对原生 Guardrails 节点自身人工审查门控的工具等效绕过测试 |
| **wf_rs_04** | System Prompt 提取 | LLM07 | 架构无关;与已发布的 LangChain/chatbot 基准数据进行对比 |
| **wf_rs_05** | 记忆和上下文投毒 | ASI06 | 变体:会话/缓冲区记忆,向量存储检索记忆 |
| **wf_rs_06** | 无限制消耗 / Agent 循环 | LLM10 | 架构无关;影响框架(计费的 API/执行成本)与 n8n 相关 |
评估方式为在 30 次试验批次中跨每个 payload 层级和每个 LLM 后端的
带有置信区间的成功率,
与现有的可重现性方法论保持一致。`basic_guardrail` 实验组 = n8n 的原生 Guardrails
节点。
#### 平台套件 (wf_ps_xx)
| # | 场景 | 主要 OWASP 类别 | 触发器 | 备注 |
|---|---|---|---|---|
| **wf_ps_01** | 不安全输出处理:代码/表达式注入 | LLM02 | AI 填充值 | 将通用的“LLM 输出到达 Code 节点”与 n8n 的二阶 `=` 前缀表达式重新评估模式进行对比;针对 CVE-2025-68613 系列进行修补前/后版本边界测试 |
| **wf_ps_02** | 通过 SSRF 链式 `$fromAI()` 窃取凭证 | LLM02 / ASI02 | AI 填充值 | 测试当 AI 填充的 URL 参数作为传递机制时,n8n 的凭证条件 SSRF 保护是否仍然有效 |
| **wf_ps_03** ✓ | 通过子工作流凭证交叉进行的 Agent 身份和权限滥用 | ASI03 | AI 填充值 | 测试注入的上下文是否可以将 AI 填充的 `Execute Sub-workflow` 目标重定向到更高权限的工作流 |
| **wf_ps_04** *(验证)* | 通过未经验证的恢复 Webhook 绕过人工审查门控 | ASI01 | 无——不涉及 AI | 纯控制平面绕过;auth-configuration 变体 而非 payload 层级 |
| **wf_ps_05** *(验证)* | 批量执行中的跨项批准恢复污染 | ASI02 | 演示时不需要 AI 参与;与注入的第二项配对以进行安全后果框架描述 | 每种批处理大小配置的确定性通过/失败,而非基于试验的成功率 |
| **wf_ps_06** *(验证)* | HITL 预览/执行内容不匹配 | ASI01 | AI 填充值 | AI 为人工批准对话框生成预览描述,然后在同一轮次中执行工具调用——注入可以使预览看起来无害,而实际工具参数却是恶意的;测试绑定预览的输出与绑定执行的输出是否会产生分歧 |
评估方式主要为跨配置变体(auth 模式、批处理大小、修补前/后版本)的确定性通过/失败,
而非基于试验的
成功率,因为这些属于平台机制故障,而非概率性的模型
行为。`custom_guardrail` 实验组 = 你的平台层强制执行节点
(§5),在适用的地方跨 n8n 版本边界进行测试。
#### 复合 / 链式 (wf_cc_xx)
| # | 场景 | 主要 OWASP 类别 | 备注 |
|---|---|---|---|
| **wf_cc_01** | 复合击杀链 | ASI01 + ASI02 + ASI03 | 串联 wf_rs_02 → wf_rs_03 → wf_ps_03 的 payload,以测试当只需整个链条成功时,逐步缓解措施(来自两个套件)是否仍然有效 |
一个核心研究问题是,当输出被解释为**结构化执行指令**而非自然语言回复时,
传统的 LLM 安全缓解措施
(system prompt、输出过滤、基本 guardrail)是否仍然有效
(推理套件,RQ1)——另外,应用程序层的
强制执行机制是否能够触及完全
发生在 n8n 平台层内的故障(平台套件,RQ2)。
## 架构
### Docker 服务
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ Docker Network │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ │ │ │ │ │ │
│ │ n8n │───▶│ PostgreSQL │ │ Ollama │ │
│ │ :5678 │ │ :5432 │ │ :11434 │ │
│ │ │◀───│ │ │ │ │
│ └───┬────┬─────┘ └──────────────┘ └──────────────┘ │
│ │ │ │
│ │ ├────────────────────────────┐ │
│ │ │ │ │
│ │ ▼ ▼ │
│ │ ┌──────────────────┐ ┌──────────────────┐ │
│ │ │ mock-server │ │attacker-listener │ │
│ │ │ :8080 │ │ :9999 │ │
│ │ └──────────────────┘ └──────────────────┘ │
│ │ ┌──────────────────┐ │
│ │ │ mockapi │ │
│ │ │ :3000 │ │
│ │ └──────────────────┘ │
│ │ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ AVISE → POST to webhook → agent executes │ │
│ │ HTTP response with tool calls for evaluation │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────┘
```
所有服务均作为 Docker 容器运行:
| 服务 | 端口 | 用途 |
|---|---|---|
| n8n | 5678 | 工作流编排引擎和 UI |
| PostgreSQL | 5432 | n8n 状态 + `agent_messages` 表 |
| Ollama | 11434 | 本地 LLM 推理(后备 / 气隙隔离模式) |
| mockapi | 3000 | `json-server` —— 提供模拟文档、常见问题解答、通知 |
| mock-server | 8080 | Flask 服务器 —— 包含 15 个以上用于间接注入实验的端点,包括用于 wf_05 SSRF 测试的内部/不可路由目标 |
| attacker-listener | 9999 | Flask 服务器 —— 捕获实验期间外泄的数据 |
### 多模型 LLM 后端
所有工作流均使用兼容 OpenAI 的 `lmChatOpenAi` 节点,该节点适用于任何提供兼容 OpenAI 的 API 的提供商:
| 提供商 | LLM_BASE_URL | LLM_MODEL |
|---|---|---|
| OpenAI | *(空——默认为 api.openai.com)* | gpt-4o, gpt-4o-mini, ... |
| OpenCode | https://api.opencode.ai/v1 | opencode/deepseek-v4-flash-free, ... |
| OpenRouter | https://openrouter.ai/api/v1 | openai/gpt-4o, anthropic/claude-3, ... |
| Ollama | http://ollama:11434/v1 | mistral, llama3, ... |
模型和 base URL 通过环境变量配置,并在运行时通过 n8n 表达式(`{{ $env.LLM_MODEL }}`、`{{ $env.LLM_BASE_URL }}`)注入。批处理修补程序脚本(`scripts/patch_workflow_models.py`)将这些表达式标记到所有工作流 JSON 中。不需要特定于模型的节点类型。
**关于确定性的说明:** temperature=0 会减少差异,但不能保证托管 API 上的输出位级相同——尤其是 OpenRouter,它可以将相同的请求路由到不同的后端实例。结果应报告为在 30 次试验批次中的带置信区间的成功率(见下文的*可重现性*),而不是单次运行的结果。
## 设置
### 前置条件
- Docker 和 Docker Compose v2
- 至少 8 GB RAM(推荐 16 GB)
- (可选)你选择的 LLM 提供商的 API 密钥
### 第 1 步:配置环境
```
cp .env.example .env
```
使用你的值编辑 `.env`:
```
# 必需:生成一个安全的随机 32 字符密钥
N8N_ENCRYPTION_KEY=标签:AI代理, AI安全, AI风险缓解, Chat Copilot, CISA项目, DLL 劫持, n8n, Web报告查看器, 反取证, 大语言模型, 安全评估, 测试用例, 请求拦截