构建
集群画布
一个集群就是一张由节点构成的有向图。输出沿着连边流动,共享状态则贯穿所有节点。本页逐一说明全部 18 种节点及其每一个字段。
打开 构建 → 智能体集群。从节点面板拖出一个节点,点击它即可在右侧打开 检视面板 进行配置。从一个连接点拖到另一个连接点即可连接节点。
流程状态与模板
每个节点都可以读写一份共享的键值 流程状态。正是这一点让图不只是一条链。
| 字段 | 出现位置 | 含义 |
|---|---|---|
outputVar | 所有节点 | 指定该节点把结果写入哪个变量。不填的话,结果只能被紧邻的下一个节点使用。 |
inputs | 所有节点 | 该节点要从状态中读取的变量名。合并节点靠它决定合并哪些内容。 |
凡是接受模板的字段,以下写法都会被解析:
| 模板 | 解析结果 |
|---|---|
{{input}} | 从入边传入的值 |
{{myVar}} | 流程状态中的一个具名变量 |
{{myVar.path.to.field}} | 状态中某个 JSON 值的嵌套字段 |
{{secret:NAME}} | 一个已存储的 密钥。它只在 服务端解析 ,其值绝不会到达浏览器。 |
为什么这样设计
{{secret:NAME}} 会被客户端插值器有意跳过,直到调用时才在服务端替换。正因如此,HTTP 节点才能在凭据从不发送到画布、也不在画布中可见的前提下,完成对第三方 API 的认证。全部 18 种节点
input
入口节点。可选择在运行面板中渲染一个带类型的表单,替代单一的自由文本框——每个字段的值都会以其字段名写入流程状态。
| 字段 | 取值 | 说明 |
|---|---|---|
inputFields[].name | string | 写入状态时使用的变量名 |
inputFields[].label | string | 显示在字段上方 |
inputFields[].type | 单行文本 / 多行文本 / 数字 / 下拉选择 | select 还需要填写 options |
inputFields[].options | string[] | 供下拉选择使用 |
inputFields[].placeholder | string | — |
inputFields[].required | boolean | 未填写时阻止运行 |
agent
最常用的节点:一次大模型调用,可选配工具、知识库和记忆。
| 字段 | 取值 | 说明 |
|---|---|---|
agentId | 已保存的智能体 | 关联一个已保存的智能体即可继承它的全部配置,下方字段会在此基础上覆盖。 |
systemPrompt | template | 支持 {{var}} 模板 |
provider | 提供商 ID | — |
model | 模型 ID | 逐节点设置——路由节点可以用便宜的模型,负责撰写的节点用强模型 |
temperature | 0 – 2 | 与智能体构建器中的建议一致:机械性任务一律设为 0 |
knowledgeBaseId | 知识库 ID | 为该节点的调用提供依据 |
reranker | {provider, model} | 可选的检索重排序器 |
enabledTools | 工具 ID | 一旦设置,该节点将只能看到这些工具 |
skillIds | 技能 ID | 在提示词前置一个“你可使用的技能”区块 |
toolConfigs | object | 逐工具配置:网页搜索提供商与密钥、n8n 的 ID、MCP 服务名称、SQL 表允许清单 |
guardrails | partial | 会覆盖式合并到所关联智能体的配置之上——节点只能更严格,不能更宽松 |
memory | object | 参见下方的记忆范围说明 |
节点记忆范围
| ltm_scope | 行为 |
|---|---|
agent | 默认值。与该智能体的常规会话共享长期记忆。 |
swarm | 仅限本次集群运行——以运行 ID 作为会话键。 |
none | 为该节点禁用长期记忆。 |
condition
二选一分支。由大模型回答一个是非问题,走向与答案匹配的那条边。
| 字段 | 说明 |
|---|---|
conditionPrompt | 一个用“是 / 否”来决定走哪条边的问题。请把它写得答案毫不含糊。 |
Does the customer's message describe a fault with a physical product
(as opposed to a billing, delivery or account question)?router
多选一分支。由大模型从 出边标签中选择一个;匹配的分支执行,其余标记为已跳过。
| 字段 | 说明 |
|---|---|
routerPrompt | 用于指导选择的说明。类别名称必须与你给连边打的标签完全一致。 |
记得给连边打标签
billing, technical, other.loop
| 字段 | 默认值 | 说明 |
|---|---|---|
maxIters | — | 迭代次数的硬性上限。请务必设置;不设上限的循环是最典型的成本失控来源。 |
foreach
把该节点的智能体主体逐个应用到数组的每个元素上。
| 字段 | 说明 |
|---|---|
foreachInput | 存放该数组的变量 |
foreachItemVar | 在主体内部,每个元素以此名称暴露 |
approval
暂停运行,直到有人做出决定。
| 字段 | 取值 | 说明 |
|---|---|---|
approvalTitle | string | 审批人看到的内容 |
approvalRisk | 低 / 中 / 高 | 作为上下文展示给审批人 |
approvalTimeoutMs | number | 0 = 一直等;否则超时仍无人决定时由调度器自动拒绝该关卡(每分钟检查一次) |
approverUserIds | 用户 ID | 谁会收到通知并有权决定 |
approverGroupIds | IAM 用户组 ID | 同上,按用户组指定 |
注意
evaluate
以大模型充当裁判进行打分。默认启用五项指标,权重如下:
| 度量 | 权重 | 检查内容 |
|---|---|---|
| 忠实度 | 0.30 | 所有论断是否都有所提供上下文作为依据?用于发现幻觉。 |
| 回答相关性 | 0.25 | 回答是否切中问题,还是答非所问? |
| 完整性 | 0.20 | 是否覆盖了问题的每一个部分? |
| 连贯性 | 0.15 | 逻辑结构是否清晰、条理是否分明? |
| 无害性 | 0.10 | 是否不含有害、带偏见或恶意的内容? |
| 字段 | 说明 |
|---|---|
evalMetrics | 可逐项启用或停用,并设置权重(0 到 1) |
evalRubric | 裁判必须遵循的自定义评分标准 |
evalCustomInstructions | 给裁判的额外说明 |
evalPassThreshold | 0 到 1。加权总分需达到该值才算通过 |
evalReferenceInput | 存放原始问题或上下文的变量,作为评判依据 |
function
沙箱化的 JavaScript。接收 ctx = { input, vars } ,并且必须 return 一个值。
// Normalise a messy list into the shape the next node expects.
const rows = ctx.input.items ?? [];
return rows
.filter((r) => r.status === "open")
.map((r) => ({ id: r.id, owner: r.assignee?.name ?? "unassigned" }));| 字段 | 默认值 | 说明 |
|---|---|---|
functionTimeoutMs | 2000 | 硬性超时。代码运行在隔离的 Worker 中,无法访问网络和 DOM。 |
set_var
把具名键写入流程状态。每个值都是模板,会基于当前状态解析。
| 字段 | 说明 |
|---|---|
stateAssignments | { key, value } 数组——value 支持 {{var}} 和 {{var.path}} |
http
一次确定性的对外请求,不涉及大模型。
| 字段 | 取值 | 说明 |
|---|---|---|
httpMethod | GET / POST / PUT / PATCH / DELETE | — |
httpUrl | template | 支持 {{var}} 和 {{secret:NAME}} |
httpHeaders | {key, value}[] | 同样支持模板——令牌请写成 {{secret:…}} |
httpBody | template | — |
httpResponsePath | JSON 路径 | 从响应中只提取一个字段向下传递,而不是整个响应体 |
httpTimeoutMs | number | — |
Method: POST
URL: https://api.example.com/v1/tickets
Headers: Authorization: Bearer {{secret:SUPPORT_API_TOKEN}}
Content-Type: application/json
Body: {"subject": "{{summary}}", "body": "{{input}}", "priority": "{{priority}}"}
Path: data.id小心
tool
以确定性方式运行一个内置工具,参数由你提供,不经大模型决策。
| 字段 | 说明 |
|---|---|
toolId | 十个集群工具 ID 之一(kb_search、sql_query、web_search 等) |
toolArgs | 参数名到模板的映射,基于流程状态解析 |
为什么这样设计
tool 节点,而不是 agent 节点。如果你每次都要跑同一个查询,让模型来决定是否执行它,纯粹是多花钱,还引入了不确定性。extract
大模型结构化输出。生成一个符合你所声明模式的 JSON 对象。
| 字段 | 说明 |
|---|---|
extractSchema | { name, type, description } 数组。type 可取 string、number、boolean 或 array。 |
name: customer_name type: string "Full name as written"
name: order_id type: string "Order reference, e.g. NW-10482"
name: refund_amount type: number "Amount in GBP, 0 if none requested"
name: is_urgent type: boolean "True if they mention a deadline"merge
把该节点声明的 inputs 合并成一个值。
| mergeMode | 结果 |
|---|---|
concat | 拼接后的文本,分隔符为 mergeSeparator (默认两个换行) |
array | 由各输入值组成的 JSON 数组 |
object | 以变量名为键的 JSON 对象 |
first | 第一个非空输入——在只有一条分支执行的路由节点之后特别有用 |
retrieve
独立的知识库检索,不发起大模型调用。
| 字段 | 默认值 | 说明 |
|---|---|---|
knowledgeBaseId | — | 要检索哪个集合 |
retrieveQuery | {{input}} | 检索查询的模板 |
retrieveTopK | — | 返回多少个分块 |
subswarm
把另一个已保存的集群当作单个节点运行,其最终输出即为该节点的输出。它在隔离环境中执行,输入由你为它准备。
| 字段 | 说明 |
|---|---|
subSwarmId | 要运行的已保存集群 |
a2a_remote
委派给一个使用 A2A 协议的远程智能体服务。
| 字段 | 说明 |
|---|---|
a2aEndpoint | 远程服务 URL |
a2aAgentCard | 拉取到的智能体能力卡,描述其具备的技能 |
a2aSkillId | 调用其对外声明的哪一项技能 |
a2aAuthHeader | 认证请求头的值——请使用 {{secret:NAME}} |
a2aStreaming | 流式接收远程响应 |
output
终止节点。它的值就是整个集群的结果——API 运行返回的内容,以及回调投递的内容。
错误处理
以下设置适用于 agent, http, tool, foreach, extract, evaluate, a2a_remote, function 和 loop:
| 字段 | 默认值 | 作用 |
|---|---|---|
retryCount | 0 | 瞬时故障时的重试次数 |
retryDelayMs | — | 两次重试之间的等待时间 |
onError | fail | fail 会中止整个运行。 continue 会写入 errorFallback 到输出变量,然后继续执行。 |
errorFallback | — | 当 onError 为 continue 时使用的值 |
nodeTimeoutMs | 0 表示默认 | 逐节点覆盖调用超时 |
注意
onError: continue 并配上兜底值——一次查不到不该让整个还能产出有用结果的运行就此中断。而对于后续流程依赖其结果的节点,请保持 fail 。完整示例:一个客服分诊集群
input ──▶ extract ──▶ router ─┬─[billing]──▶ agent(billing) ──┐
(customer, │ │
order_id, ├─[technical]▶ agent(tech KB) ────┤
refund_amount) │ │
└─[refund]───▶ approval ──▶ http ─┤
▼
merge ──▶ output
(mode: first)- 1
input
一个字段:message,类型为textarea,必填。 - 2
extract
结构如上所示。outputVar=ticket。此时{{ticket.refund_amount}}已可供下游使用。 - 3
router
三条出边,标签分别为billing,technical,refund。routerPrompt 设为: “把这条消息归类为账务、技术或退款。” 模型:选一个小而快的——这是分类任务,温度设为 0。 - 4
个智能体节点
每个各自关联一个已保存的智能体,并设置自己的knowledgeBaseId。三者都写入outputVar=reply. - 5
approval
标题填“批准退款”,风险等级为high,approverGroupIds 设为你的财务用户组。不设超时,因此会一直等待。 - 6
http
以 POST 方式调用你的退款 API,携带Authorization: Bearer {{secret:REFUND_API_TOKEN}}。onError 设为fail——一笔悄无声息失败的退款,比一次中止的运行糟糕得多。 - 7
合并 → 输出
mergeModefirst,因为恰好只有一条分支执行了。
运行与观测
- 运行面板 ——填写输入表单,实时流式展示各节点状态(空闲、运行中、已完成、错误、等待中、已跳过),并显示每个节点最近一次的输出。
- 最近运行 ——带输入与结果的历史记录。
- 追踪记录 ——逐节点的步骤明细,含提示词、工具调用、令牌数和成本。参见 日志与追踪.
- 版本 ——保存时会为整张图创建快照,可对比差异并恢复。
部署
部署 为集群签发一个 API 密钥,让你自己的系统可以调用它;而 对话 则把它开放为一个对话入口。定时任务可以让它无人值守地运行。完整说明见 API 与 Webhook 和 网页嵌入.
批量评估
一个集群在你试过的那条提示词上表现良好,在另外四十条上照样可能退步。 评估 (位于侧边栏的“实验工具”下)会把整个测试用例数据集无界面地跑一遍集群,并为每条输出打分,这样提示词的改动就是被度量出来的,而不是靠猜。
| 组成部分 | 它是什么 |
|---|---|
| 数据集 | 具名的用例集合。一条用例包含一个输入、可选的带类型起始表单值,以及可选的期望答案。可导入 CSV——除 name、input、expected 之外的列会成为起始表单值。 |
| 评分方式 | 决定本次运行中每条输出如何评分:可以是大模型裁判(加权指标,0 到 1,带通过阈值),也可以是确定性检查——包含、完全相等或正则匹配。 |
| 运行 | 一个数据集 × 一个集群 × 一个评估器。用例在与已部署 API 运行相同的无界面引擎上执行,每次并发两条;进度、通过率、平均分和模型花费都会被记录。 |
| 对比 | 选择同一数据集、同一评估器下的一次早前运行,每条用例都会两两配对:改进、退步或持平,并给出分数差值。 |
注意
运行可恢复也可取消:取消在服务端强制执行,已有结论的用例绝不会被重复评分,因此“运行剩余部分”会精确地从中断处继续。审批节点默认自动拒绝——除非该集群在批量场景下自动通过是安全的,否则请保持这一设置。每条结果都链接到它完整的执行追踪。
导出
| 目标 | 还原度 |
|---|---|
| LangGraph | 完整拓扑——分支、循环和条件边都能保留 |
| Strands | 使用 GraphBuilder 承载节点图 |
| OpenAI Agents SDK | 智能体,加上事后指派的交接关系 |
| CrewAI | 顺序流程 |
注意
问题排查
| 现象 | 原因 | 解决办法 |
|---|---|---|
| 路由节点总是选同一条分支 | 连边没有标签,或标签太相似 | 给每条出边一个简短且互不相同的标签;把路由节点的温度设为 0。 |
| 合并时某条分支的输出为空 | 只有一条分支执行了 | 把 mergeMode 设为 first. |
| 运行迟迟不结束 | 循环节点没设 maxIters,或审批节点没有指定审批人 | 设置 maxIters;检查 approverUserIds 与 approverGroupIds。 |
| 下游取到的变量是空的 | 产出该值的节点没有设置 outputVar | 设置 outputVar,并把它列进使用方的 inputs 中。 |
| HTTP 节点返回 401 | 密钥没有被解析 | 在做数据增补的步骤上,请使用 {{secret:NAME}} ,写法必须完全一致;直接写在请求头里的明文令牌会被原样当作字面文本发送。 |
| 函数节点超时 | 沙箱中存在循环或过重的计算 | 调高 functionTimeoutMs,或者把这部分工作挪到 HTTP 节点去做。 |
| 节点似乎没有遵守它的护栏 | 节点护栏只能收紧,不能放松 | 它们会覆盖式合并到所关联智能体的护栏之上,无法削弱智能体已强制执行的约束。 |