在 n8n 工作流里用 Jev:稳定的决策节点

更新于 适用版本 Jev 1.13

TL;DR: 在 n8n 里,Jev 就是你能信任的那个决策节点。一个 HTTP Request 节点调用 OpenAI 兼容的 OpenRouter 端点,一个小 Code 节点解析结构化的 {answer, confidence, rationale} 响应,IF 节点按 answer 加置信度阈值分支。失败走显式兜底路径,而不是让整次运行中断。下面按节点逐个说明配置。

工作流全貌

触发器(webhook / 定时 / 新记录)
   |
   v
Set 节点(把输入字段拼成问题文本)
   |
   v
HTTP Request 节点 -> OpenRouter chat/completions(模型:Jev)
   |
   +--> HTTP 错误 --> 重试(内置,2-3 次,指数退避)
   |                     |
   |                     +--> 仍失败 --> 兜底路径(通知 / 默认动作)
   |
   v
Code 节点(把 choices[0].message.content 按 JSON 解析)
   |
   +--> JSON 无效 --> 兜底路径
   |
   v
IF 节点(confidence >= 0.85 ?)
   |
   +--> 是 --> 按 answer 分支(如派单、打标签、审批)
   |
   +--> 否 --> 兜底路径(人工队列,附 rationale)

每条出口都有明确去处——这就是全部要点:决策节点要么有把握地决定,要么明确地交出去。

HTTP Request 节点配置

配置项值
方法POST
URLhttps://openrouter.ai/api/v1/chat/completions
认证Header 认证:Authorization: Bearer <OPENROUTER_API_KEY>(key 存在 n8n 凭据里,不要写死在节点上)
请求体(JSON){"model":"typesafe/jev-1.13","temperature":0,"messages":[{"role":"system","content":"Answer yes, no, or unclear."},{"role":"user","content":"{{ $json.question }}"}]}
失败重试开启,2-3 次,带退避
超时约 30 秒

本页用的模型 id 是 typesafe/jev-1.13——上线前请在 OpenRouter 模型页确认确切的模型 slug。

解析节点(Code 节点,JavaScript)

// 输入:HTTP Request 节点返回的 OpenRouter 响应
const raw = $input.first().json;
let parsed;
try {
  // 示例数据(example fixture):
  // {"answer":"yes","confidence":0.97,"rationale":"..."}
  parsed = JSON.parse(raw.choices[0].message.content);
} catch (e) {
  return [{ json: { branch: "fallback", reason: "invalid-json", raw } }];
}

const lowConfidence = parsed.confidence < 0.85;
if (lowConfidence) {
  return [{ json: { branch: "fallback", reason: "low-confidence", ...parsed } }];
}
return [{ json: { branch: parsed.answer, ...parsed } }];

下游 IF 节点从此只看 $json.branch——干净取值如 yes、no、fallback,再也不用对散文做字符串匹配。

兜底路径怎么接

兜底分支要做三件事:记录原始响应和 rationale、通知人(邮件、Slack、工单),可选执行一个安全默认动作让流程跑完。工单分诊与情感案例展示的就是这种接法——兜底直接接到客服队列。

渠道本身的取舍(OpenRouter 与官方 API)见 API 渠道(api-channels)指南,从零发起第一次调用见第一次 API 调用(first-api-call)指南。官方 API 的端点与字段请始终以 typesafe.ai 官方文档为准。

本文适用版本:Jev 1.13。

上线前用 n8n 测试工作流

真实流量接入决策节点之前,先在 n8n 里用固定样本数据(Pinned Data)跑一遍,每条分支都能检查清楚,而且完全不碰线上系统。

准备四类测试样本。 在 n8n 里打开 HTTP Request 节点,切到 Output 面板,用 Pin Data 功能冻结一条固定响应。为 Code 节点需要处理的每条逻辑路径各准备一个样本:

样本answerconfidence预期 branch
明确 yes"yes"0.97yes
明确 no"no"0.91no
低置信度"yes"0.72fallback(low-confidence)
非 JSON"not valid json"—fallback(invalid-json)

如何在 n8n 里固定数据。 点击 HTTP Request 节点,打开 Output 面板,粘贴一条与 OpenRouter 真实响应结构相符的样本(格式:{"choices":[{"message":{"content":"{...}"}}]}),再点击 Pin 图标。之后点击顶部栏的 Execute Workflow 手动执行时,n8n 会直接使用固定数据,不会真正请求 API——API 额度一点不消耗。

对每个样本分别做 Manual Execution。 固定数据后点击 Execute Workflow,检查所有下游节点的输出面板,确认:

在切换下一个样本之前记录预期路径。 一张简单的表格或直接写在工作流画布上的便签(n8n 支持 Sticky Note 节点)都可以。有了书面预期,以后修改 Code 节点时如果某条分支悄悄坏掉,一眼就能发现。

四个样本全部通过后,取消固定数据,用一个已知问题发起一次真实调用,把结果和记录的预期比对。确认一致后,节点才算准备好接受生产流量。关于模型返回字段和格式的说明,见置信度与兜底指南和第一次 API 调用指南。

在 n8n 里处理限流、超时与成本

把 Jev 放进自动化工作流意味着节点可能在短时间内连续触发很多次。实际运行中反复出现三个问题:API 返回 429 时的背压、长请求导致工作流挂住、以及每次调用的成本。

限流退避(HTTP 429)。 n8n HTTP Request 节点的 Settings 标签页里有内置的 Retry On Fail 开关。打开后把 Max Tries 设为 3,Wait Between Tries 至少设为 2000 ms。对于批量场景——比如逐行处理电子表格——在 HTTP Request 节点之前加一个 Split In Batches 节点,Batch Size 设为不超过 OpenRouter 控制台显示的每分钟请求配额的舒适值。Batch Size 设为 5 表示同时最多 5 个 HTTP Request 并发执行;如果还是看到 429,就继续调小。具体的请求限额取决于你的 OpenRouter 套餐,以 typesafe.ai 官方文档为准。

超时与重试配合使用。 在 HTTP Request 节点的 Settings 里,把 Timeout 设为 30 000 ms(30 秒)。请求超时后 n8n 视为错误,Retry On Fail 逻辑自动接管。三次尝试仍失败后,工作流路由到兜底分支——不会无限挂起。

n8n 控制项节点 / 字段推荐值
重试HTTP Request → Settings → Retry On Fail开启,3 次,间隔 2 秒
超时HTTP Request → Settings → Timeout30 000 ms
并发上限Split In Batches → Batch Size5(或更低)

降低成本的两个开关。 在 HTTP Request 的请求体里有两处可以减少每次调用的 token 消耗。第一,设置 "temperature": 0——本页示例已经这样配置;确定性采样还让你可以在工作流层对完全相同的问题做缓存。第二,保持 system 提示词简短直接(示例只用了 9 个英文词)。system prompt 越短,每次调用的输入 token 就越少,在数千次工作流执行中累计节省相当可观。完整的成本与延迟取舍分析见成本与延迟指南。

常见错误与如何避免

工作流本身搭起来并不难;在生产环境导致静默失败的问题,几乎都是容易忽略的小细节。

把 confidence 当字符串比较而非数字。 n8n 在节点之间传递 JSON 字段时,有时会把数值序列化成字符串,具体取决于数据如何到达。如果你在 IF 节点的 Value 1 里直接写 $json.confidence >= 0.85,而值以字符串 "0.97" 的形式传入,JavaScript 宽松比较下 "0.97" >= 0.85 为 true,但 "0.12" >= 0.85 也会是 true(字符串 "0" 的字典序在数字 0 之后)。正确做法是在 Code 节点里显式转换:

const confidence = Number(parsed.confidence);
const lowConfidence = isNaN(confidence) || confidence < 0.85;

这样阈值判断就不会受字符串强制转换和 undefined 的影响。

在 Code 节点里忘记写 try/catch。 如果 JSON.parse 抛出异常而没有 catch,n8n 会把整个节点执行标记为失败,运行就此中断。本页的 Code 节点示例把解析包在 try/catch 里并返回一个 fallback 条目——请原样复用这个写法。不加防护的裸 JSON.parse(raw.choices[0].message.content) 是处理 LLM 输出时最常见的工作流意外崩溃根源。

把 API key 直接写进节点而不是存在 n8n Credentials 里。 直接填入节点字段的 API key 以明文存储在工作流 JSON 里,会出现在导出文件、执行日志和团队共享的工作流模板中。正确做法:新建一个类型为 Header Auth 的 n8n Credential,名称填 Authorization,值填 Bearer <YOUR_KEY>,然后在 HTTP Request 节点的 Authentication 下拉菜单里选择这个凭据。key 就会加密存储,也不再出现在工作流导出文件里。

对兜底分支不做告警。 一条静默消化低置信度或失败响应的兜底路径,测试阶段看起来很稳,但在生产环境会掩盖真实问题。一定要在兜底分支里接上至少一个通知节点——Send Email 节点、Slack 节点,或一个发送到 Webhook 的 HTTP Request——这样当置信度持续走低或 API 不可达时,你能第一时间知道。如果兜底触发频率超出预期,故障排查模式见故障排查指南。

FAQ

常见问题

+ n8n 里怎么调用 Jev?

用 HTTP Request 节点请求 OpenAI 兼容端点 https://openrouter.ai/api/v1/chat/completions,请求头放 OpenRouter API key,请求体写模型 id,问题放在 messages 数组里。

+ 工作流里怎么读取结构化结果?

在 HTTP Request 之后加一个 Code 或 Set 节点,把 choices[0].message.content 当 JSON 解析,然后基于 answer 和 confidence 字段做分支,而不是对原始文本做字符串匹配。

+ 错误分支应该做什么?

瞬时 HTTP 失败用 n8n 内置重试;低置信度、JSON 解析失败或重试后仍失败的结果走兜底路径——人工队列或安全默认动作——而不是让整个工作流崩掉。

继续阅读