扣子工作流踩坑花了3天?这10个隐藏坑,看完10分钟全避开

扣子工作流踩坑花了3天?这10个隐藏坑,看完10分钟全避开


一、你是不是也这样?

凌晨两点,你盯着扣子工作流的运行日志,第17次重跑,结果依然不对。

代码节点的输出格式没错,LLM节点的Prompt也没问题,条件分支逻辑检查了三遍——但工作流就是跑到一半静默终止了。没有任何报错,就像什么都没发生过。

更离谱的是,同一个工作流,测试环境跑得好好的,发布到生产环境就翻车。

如果你有过类似经历,这篇文章就是写给你的。过去几个月我在项目交付中踩遍了扣子工作流的坑,下面10个是隐藏最深、文档里几乎不提的。每个都附了排查思路和避坑方案。


二、10个隐藏坑逐一拆解

坑1:变量类型"隐式转换"——你以为传的是对象,其实是个字符串

场景还原

你用 LLM 节点生成了一段 JSON:

{"name": "张三", "score": 95}

然后把这个输出传给代码节点,写了一段 Python 想取 score 的值:

data = input_data # 从上游 LLM 节点传入 result = data["score"] # ❌ 这里就炸了

报错:TypeError: string indices must be integers

根因:LLM 节点输出的 JSON 在扣子工作流里默认是字符串类型,不是字典对象。你看着是 JSON,实际上只是一段文本。

排查思路:在代码节点开头加一行 print(type(input_data)),如果打出 <class 'str'> 就说明类型不对。

解决方案

import json data = json.loads(input_data) # 先转成字典 result = data["score"]

或者 — 更好的做法 — 在 LLM 节点的输出格式里直接定义字段,让扣子帮你做结构化解析:

字段类型说明
nameString姓名
scoreNumber分数

这样下游节点收到的就是已解析的结构化数据,不需要手动 json.loads。


坑2:条件分支的 else 为空 → 静默终止,零报错

场景还原

你做了一个审批工作流:如果审批通过 → 发通知;如果拒绝 → 发通知。两个分支都写了。上线后发现偶尔有人反馈"提交了但没收到通知",查日志也看不出问题。

根因:你的条件判断只覆盖了"通过"和"拒绝"两种情况。但审批人如果超时未处理,系统返回的状态不是"通过"也不是"拒绝",而是"待处理"。你的条件分支没有任何分支命中这个状态 —else 分支是空的,扣子不会报错,直接结束。

解决方案每条条件分支的 else 必须填内容,哪怕只是:

else → 输出节点 → "当前状态异常:{{status}},请人工介入"

或者用一个兜底消息通知自己:给管理员发一条"有工单状态异常"的提醒。

核心原则:永远假设你的工作流会收到你没预料到的输入


坑3:循环节点遇上空数组 → 整个工作流"跳过",后续节点收不到数据

场景还原

你用知识库节点查相关文档,返回结果列表,然后接一个循环节点逐条用 LLM 摘要。测试时知识库有数据,一切正常。上线后某天,用户问了一个知识库里完全没覆盖的问题,知识库返回空数组 []。

结果:循环节点因为数组为空,循环体一次都没执行,循环后面的节点收不到任何输出,整个流程断掉。

解决方案:在循环节点前加一个条件分支做"空数组守卫":

if 数组长度 > 0: → 进入循环 else: → 输出节点:"未找到相关内容,请换个方式提问"

一句话记住:循环前必做空判断,不做就是赌博


坑4:LLM 节点的 {{变量}} 嵌套陷阱

场景还原

你在 LLM 的 System Prompt 里写了一段示例代码:

请参考以下格式输出: {"title": "{{标题}}", "content": "{{内容}}"}

结果 LLM 输出了一堆乱七八糟的东西,完全没有按格式来。

根因:扣子会把 Prompt 里的 {{}} 解析为变量引用。你写的 "{{标题}}" 被当成了"引用名为「标题」的变量",而不是提示词中的示例占位符。如果变量不存在,可能被替换为空字符串或报错。

解决方案

  1. 用代码块包裹示例— 扣子通常不会解析代码块内的 {{}}
  2. 用其他占位符替代双花括号,如 <<标题>> 或 [TITLE]

坑5:API 节点超时不重试 → 整条工作流崩溃

场景还原

你接了一个第三方 API 做图片识别,测试时 API 返回正常。上线后某次高峰期,API 响应超时(30秒),整条工作流直接失败,用户看到一片空白。

解决方案 — 三层防护

API调用(超时 10s) ↓ 成功? ├─ 是 → 继续 └─ 否 → 重试1(等 2s) ↓ 成功? ├─ 是 → 继续 └─ 否 → 重试2(等 5s) ↓ 成功? ├─ 是 → 继续 └─ 否 → 输出:"服务繁忙,请稍后重试"

关键参数:超时时间 ≤ 10s(默认更久,但太长的超时会让用户等得不耐烦),重试次数 ≤ 3重试间隔递增(1s → 3s → 5s)。


坑6:代码节点里写了 return,但扣子不认

场景还原

def process(data): return data.upper() result = process(input_data) return result # ❌ 扣子代码节点不认 return

你习惯了 Python 的 return,但扣子的代码节点不走 return 机制。它需要你在节点配置面板里声明输出变量

解决方案:在代码节点的配置面板中,把 result 声明为输出变量。代码里只需赋值:

def process(data): return data.upper() result = process(input_data) # ✅ 赋值即可,无需 return

坑7:知识库检索为空时,LLM 开始"编造"答案

场景还原

你搭建了一个"企业制度问答"工作流,知识库里传了员工手册。测试时问"年假怎么请",回答正确。上线后有人问了一个知识库里没覆盖的问题:"团建经费怎么申请"。LLM 没有从知识库获得任何参考,但它没有说"不知道",而是直接编了一通。

解决方案:在 LLM 的 Prompt 里加硬约束:

如果知识库未检索到相关内容,请直接回复: "抱歉,我暂时无法回答这个问题。建议联系HR确认。" 严禁编造任何不存在的政策或流程。

坑8:并行分支的"时序竞态"——你以为谁先完成谁返回,但其实后完成的会覆盖

场景还原

你用了并行分支同时调两个 LLM,想比较两个模型的答案质量。两个分支都完成后,用一个代码节点合并结果。

测试时发现,有时候拿到的结果只有分支B的,分支A的丢了。

根因:如果两个并行分支输出到同一个变量名,后完成的分支会覆盖先完成的分支。这不是 bug,是设计如此——但没有显式文档说明。

解决方案

并行分支的输出必须用不同的变量名

并行分支A → 输出变量: result_a 并行分支B → 输出变量: result_b ↓ 代码节点合并两个变量

坑9:测试数据能跑 ≠ 生产能跑

场景还原

你在测试时用了一条标准数据:"帮我分析一下这个产品的优劣势"——工作流完美运行。发布后,第一个真实用户输入:"nb"——工作流直接炸了。

根因:测试数据太"干净"了,没有覆盖边界情况:

  • 超短输入("nb""666")
  • 超长输入(粘贴一篇文章)
  • 特殊字符(emoji、SQL注入字符)
  • 空输入

解决方案:发布前做一次"边界测试清单":

测试用例输入示例预期行为
正常输入"帮我分析这个产品"正常处理
超短输入"?"友好提示补充信息
超长输入粘贴3000字文章截断或分段处理
特殊字符"测<script>alert(1)</script>试"安全处理
空输入""提示不能为空

每次发布前至少跑一遍这张清单。


坑10:不设"观测点"——出问题只能靠猜

场景还原

工作流上线后用户反馈"有时候结果不对",你打开扣子后台翻了半天日志,只能看到"运行成功"或"运行失败",中间过程一片黑。

根因:你没有在工作流的关键节点加"输出"或"日志"节点。扣子不像传统开发有断点调试,你只能靠自己在关键位置埋点

解决方案

在工作流的关键节点之后加一个输出节点,输出关键中间变量。这些输出节点在发布时可以关闭对外展示,但日志里会保留。

推荐埋点位置:

开始节点 ↓ LLM节点(生成回答) ↓ 📌 埋点1:输出 → "原始LLM输出: {{llm_output}}" ↓ 代码节点(后处理) ↓ 📌 埋点2:输出 → "处理后结果: {{final_result}}" ↓ 结束节点

上线初期保留埋点,稳定后再移除。出问题时回看日志一眼定位。


三、避坑速查表

坑号一句话关键动作
1LLM输出的JSON是字符串先 json.loads 或配置输出格式
2else分支为空→静默终止所有else必须填内容
3循环前未判空→流程断掉循环前加条件分支做空判断
4Prompt中 {{}} 被误解析用代码块包裹或用其他占位符
5API超时不重试→整体崩三层防护:超时+重试+兜底
6代码节点忘记声明输出变量在配置面板声明,不是靠return
7知识库空→LLM开始编Prompt里加"严禁编造"约束
8并行分支同名变量覆盖每个分支用不同的输出变量名
9测试只测了理想数据发布前跑边界测试清单
10全流程无埋点关键节点后加输出节点

四、避坑心法:一个可复用的"三问"框架

每次搭完一个工作流节点,问自己三个问题:

  1. 如果上游给我空值/错值/超预期值,我会怎么处理?
  2. 如果这个节点失败了,整个工作流是优雅降级还是直接崩?
  3. 如果用户 10 天后反馈问题,我能从哪里开始排查?

能回答这三个问题,你的工作流就已经超过了 80% 的扣子用户。


五、行动建议(分阶段)

今天就能做的

  • 打开你现有的工作流,检查所有条件分支的 else 是否有内容
  • 给 LLM 节点的 Prompt 加上"无参考内容时的约束规则"
  • 在 3 个关键节点后加输出埋点

本周完成的

  • 跑一遍边界测试清单(见坑9),记录并修复发现的问题
  • 给所有 API 节点加超时+重试+兜底逻辑(见坑5)

逐步迭代的

  • 把"三问框架"套到每一个新搭的工作流上,形成肌肉记忆
  • 建立团队的避坑文档(就用上面的速查表当起点)

本文案例均为项目交付中实际遇到的问题,已做脱敏处理。

如果你有扣子工作流相关的踩坑经历或疑问,欢迎在评论区交流。

📌关于作者:米核AI易山联合创始人,专注AI自动化和智能体搭建。官网:miheaii.com

本文部分内容由 AI 辅助完成。