首页
All Posts

前端智能体开发(三):AI 工作流编排:让多个智能体跑同一套流程

这张图把 AI 工作流画成一张节点编排面板:大纲节点先确定结构,内容节点分段展开,工具节点负责搜索、存储和处理,所有输出最终通过同一条事件通道传给前端。复杂 AI 应用很少只靠一个模型调用完成,真正的难点是把多个节点、多个工具、多...

AI 工作流节点编排

这张图把 AI 工作流画成一张节点编排面板:大纲节点先确定结构,内容节点分段展开,工具节点负责搜索、存储和处理,所有输出最终通过同一条事件通道传给前端。复杂 AI 应用很少只靠一个模型调用完成,真正的难点是把多个节点、多个工具、多个异步事件组织成稳定流程。

一、为什么单节点很快会不够用

一个简单问答页面可以只有一个模型节点:用户提问,模型回答。但只要需求稍微复杂,单节点就会遇到瓶颈。

例如要生成一篇儿童科普文章,单节点可以直接写全文,但效果通常不稳定:结构可能散,段落长度可能不均,插图提示词可能缺失,适读年龄也可能忽高忽低。

更稳的方式是拆成多个节点:

  1. 大纲节点:先生成标题、章节、每章目标。
  2. 内容节点:按章节分别展开。
  3. 改写节点:把成人化表达转成儿童语言。
  4. 图片节点:为每章生成插图提示词。
  5. 语音节点:把最终内容转换成适合朗读的文本。

这种拆法的价值是让每个节点任务更窄,提示词更清楚,输出更容易验证。它像流水线里的分工:大纲节点不负责写全文,工具节点不负责组织结构。每个节点只要做好自己的职责,整体效率反而更高。

二、工作流节点应该具备哪些能力

一个 AI 节点不是一个函数那么简单。它至少需要包含这些信息:

  • 输入:来自用户、上游节点或工具。
  • 提示词:节点的任务定义。
  • 模型配置:模型名、温度、最大 token、输出格式。
  • 输出事件:文本增量、对象完成、错误、取消。
  • 下游触发:哪些字段完成后触发哪些节点。
  • 运行记录:开始时间、结束时间、耗时、消耗和错误。

如果把节点抽象成 TypeScript 类型,可以这样理解:

type WorkflowNode<I, O> = {
  id: string;
  prompt: string;
  model: ModelConfig;
  run(input: I, ctx: WorkflowContext): AsyncIterable<NodeEvent<O>>;
  onResolve?: Array<{
    path: string;
    next: string;
  }>;
};

这里最关键的是 NodeEvent。AI 输出经常是流式的,如果节点只返回最终结果,下游就只能等待。如果节点能在某个字段完成时发出事件,下游就能提前启动。

例如大纲节点输出到 outline/0 时,第一个内容节点就可以开始写第一章;不必等四个章节全部生成完。

三、Ling 这类框架解决的核心问题

一个工作流框架需要把“模型调用、结构解析、事件分发、前端通信”放到统一模型里。可以把它拆成四层:

adapter:负责适配模型 API。不同平台的接口细节不完全一样,但工作流节点不应该关心这些差异。adapter 把 OpenAI 兼容接口、Coze 接口、本地模型接口整理成统一调用方式。

bot:负责单个 AI 节点。它维护提示词、消息、配置、事件回调和上下文。

parser:负责把流式输出解析成文本增量或结构化对象。前一篇文章提到的动态 JSON 解析器就在这里发挥作用。

tube:负责把事件推给前端。它像一条共享事件通道,所有节点都把结果投递到这里,前端按路径更新界面。

这种架构让复杂流程可组合。你可以先用一个节点验证大纲,再增加内容节点,再接图片节点,再接语音节点,而不是一开始写一个巨大函数。

四、事件驱动:字段完成就可以触发下一步

工作流编排最有价值的能力之一,是按字段触发下游。

假设大纲节点输出:

{
  "title": "天空为什么是蓝色的",
  "outline": [
    {
      "section": 1,
      "title": "太阳光里有很多颜色",
      "overview": "解释白光和颜色"
    },
    {
      "section": 2,
      "title": "空气会散射蓝光",
      "overview": "解释瑞利散射"
    }
  ]
}

当解析器发现 outline/0 这个对象完成时,就可以触发内容节点:

outlineBot.on("object-response", ({ uri, delta }) => {
  const match = uri.match(/outline\\/(\\d+)/);
  if (!match) return;

  const section = match[1];
  const contentBot = ling.createBot(`content/${section}`, {}, {
    response_format: { type: "text" }
  });

  contentBot.addPrompt(contentPrompt);
  contentBot.chat(JSON.stringify(delta));
});

这个设计有两个好处。

第一,响应更快。第一章可以在大纲还没完全结束时开始生成。

第二,失败影响更小。某个内容节点失败,可以只重试这一章,不必重跑整个流程。

五、低代码平台适合验证,代码框架适合沉淀

Coze、Dify 这类平台非常适合快速验证智能体和工作流。你可以很快配置提示词、插件、变量、分支和 API 调用,观察模型是否能完成任务。对于早期产品来说,这很重要,因为 AI 应用最先要解决的是“这条链路能不能跑通”。

低代码平台的优势:

  • 搭建快。
  • 插件生态现成。
  • 可视化调试直观。
  • 适合非纯工程人员参与。

但它也有局限:

  • 复杂版本管理不如代码仓库清晰。
  • 测试和回归能力有限。
  • 与自有业务系统深度集成时会遇到边界。
  • 性能、成本和错误处理不容易完全掌控。

因此,一个实用策略是:用低代码平台验证链路,用代码框架沉淀稳定能力。比如先在 Coze 里验证“星盘数据获取 + 图片存储 + 解读生成”的工作流,确认提示词、插件和数据结构有效后,再把稳定部分封装成后端 API 或内部工作流模块。

六、工作流调试要从一开始设计

复杂工作流最怕黑盒。一个节点失败时,如果你不知道它收到了什么、输出了什么、为什么触发下游,排查会非常困难。

建议每个节点都记录:

  • nodeId
  • 输入摘要
  • 模型配置
  • 开始与结束时间
  • 输出路径
  • token 消耗
  • 错误类型
  • 下游触发记录

可以建立这样的日志结构:

type WorkflowTrace = {
  workflowId: string;
  nodeId: string;
  inputPreview: string;
  outputPaths: string[];
  status: "running" | "done" | "failed" | "canceled";
  startedAt: number;
  endedAt?: number;
  usage?: {
    promptTokens: number;
    completionTokens: number;
  };
  error?: string;
};

前端也可以展示调试模式:当前运行到哪个节点、哪个节点完成、哪个节点失败。这对开发者和内部运营都很有帮助。

七、取消、超时和背压

AI 工作流不是普通同步函数。它可能很慢,也可能产生大量流式数据。工程上必须处理三类控制问题。

取消:用户关闭页面或点击停止时,工作流应该停止继续调用模型。否则费用会继续消耗,下游也可能写入过期数据。

超时:每个节点都应该有超时。比如大纲节点 20 秒无输出就失败,图片节点 60 秒无结果就进入重试或降级。

背压:如果模型输出太快,前端渲染太慢,不能每个字符都立即触发渲染。tube 层可以做节流,把多个小 delta 合并后再推送。

const queue: NodeEvent[] = [];
let timer: ReturnType<typeof setTimeout> | null = null;

function pushEvent(event: NodeEvent) {
  queue.push(event);
  if (timer) return;

  timer = setTimeout(() => {
    sendToClient(queue.splice(0));
    timer = null;
  }, 50);
}

这类细节决定了工作流在真实用户量下是否稳定。

八、一个完整用例:儿童科普文章生成

可以把“儿童科普文章生成”设计成五步。

第一步,问题理解。用户输入“为什么火会烫”,系统先判断问题是否具体。如果太短,可以改写出几个候选问题。

第二步,大纲生成。模型输出标题、章节、每章目标和适读年龄。

第三步,内容展开。每个章节独立生成,要求使用儿童能理解的类比,不使用过长句子。

第四步,可信补充。对涉及事实的内容,用搜索或知识库补充上下文,避免错误解释。

第五步,多模态增强。为每章生成插图提示词,最终可以合成插图和朗读音频。

这时前端不应该等全部结束才显示,而应该按阶段展示:

  • 标题出现后立即显示标题。
  • 第一章内容完成后立即可读。
  • 插图生成中显示占位图。
  • 音频生成中显示“准备朗读”。
  • 任一步失败时,允许单独重试。

这个用例展示了工作流框架的真正价值:不是让模型输出更长,而是让模型、工具和前端一起协作。

九、低代码与代码混合的实践建议

对于团队落地,可以按下面节奏推进。

第一阶段,用低代码平台验证智能体链路。重点看效果,而不是追求工程完美。

第二阶段,把稳定节点抽象成 API。比如搜索、图片存储、内容生成、语音合成。

第三阶段,用代码框架编排复杂流程。引入日志、测试、取消、重试和权限。

第四阶段,沉淀节点模板。常见节点如“问题改写”“RAG 检索”“结构化生成”“图片提示词生成”“语音脚本改写”都可以复用。

第五阶段,做回归评测。选一批真实输入,定期跑模型输出质量,避免提示词或模型升级后效果退化。

十、工作流的本质是把不确定性拆小

AI 模型本身有不确定性。工作流编排不是消除所有不确定性,而是把一个大不确定性拆成多个小不确定性:大纲是否合理、某章是否生成成功、搜索是否命中、图片是否合规、语音是否可播放。每个小问题都能被观察、重试、替换或降级。

工作流编排不是保证每个模型调用都完美,而是把失败面缩小,并且让错误可以观察、重试、替换或降级。节点分工创造稳定性,事件机制创造速度,可观测性创造可维护性。把这些做好,多个智能体才能真正跑同一套流程。