PaiFlow 的 LLM 节点执行器:把多模型调用做成统一的工作流能力
在 AI 工作流里,LLM 节点不只是调用一次模型接口。它还要处理提示词模板、上下文历史、流式输出、超时重试和异常分支,同时兼容 DeepSeek、智谱、OpenAI、Claude 等不同模型。
PaiFlow 的核心思路是:工作流层只负责业务语义,模型差异全部收敛到适配层。
LLM 节点的职责
LLMNodeExecutor 是专门执行大模型节点的执行器,它继承 AbstractNodeExecutor,复用输入解析、超时控制、失败重试、结果存储和节点事件通知等通用能力。
它只需要负责 LLM 特有逻辑:
- 解析上游节点输入。
- 渲染系统提示词和用户提示词。
- 加载对话历史。
- 调用模型服务。
- 将流式内容实时推送给前端。
- 汇总完整回答,作为节点输出传给下游。
用配置描述模型调用
一个 LLM 节点主要包含五类配置:模型、输入、提示词、输出和异常策略。
输入既可以是固定值,也可以引用前面节点的输出;提示词支持 {{变量名}} 模板;输出通常定义为字符串;异常策略则控制超时、重试次数和失败兜底内容。
这种配置驱动的设计,让前端编排和后端执行形成统一契约,而不需要为每个模型单独写一套节点逻辑。
提示词与上下文
模型请求的消息顺序通常是:
当前系统提示词 → 历史对话 → 当前用户消息
系统提示词和用户提示词都会根据节点输入完成变量替换。
需要注意的是,历史中的旧系统提示词不应该再次带入,否则可能与当前节点配置冲突。历史只保留用户问题和模型回答,系统规则始终以当前节点为准。
对话历史管理
PaiFlow 使用 chatId + nodeId 作为历史缓存键,让同一个会话中的不同 LLM 节点各自维护上下文。
每轮对话由 ChatItem 保存用户输入、模型推理内容和最终回答。这样即使在流式场景中,推理过程和正式回答分段返回,也能正确归入同一轮。
同时,缓存必须设置最大轮数、最大会话数和过期时间,避免上下文无限增长造成内存压力。
流式输出的处理
流式响应到达时,执行器会通过回调把每一小段文本实时推送给前端,用户可以边生成边查看结果。
服务端同时累积完整回答和推理内容。流结束后,再将完整结果封装为节点输出,供后续节点继续使用。
也就是说:流式输出解决实时体验,完整结果保证工作流能够继续执行。
模型适配层
LLMNodeExecutor 不直接关心底层调用的是哪家模型,而是统一交给 ModelServiceClient。
例如 OpenAI 兼容接口可以由 Spring AI 的集成实现处理;未来接入 Claude、Gemini、豆包等原生接口时,只需要新增对应的适配策略,无需修改工作流执行器。
这就是“稳定核心 + 可扩展边界”的设计:执行器负责稳定的工作流语义,适配层负责变化的模型协议。
结语
一个成熟的 LLM 节点,本质上是工作流语义与模型能力之间的翻译器:它把上游数据、提示词和历史上下文变成模型请求,再把流式生成转化为实时事件和标准节点输出。
把 LLM 节点设计成“统一工作流语义 + 可插拔模型适配 + 流式事件回传”的执行器,才能让模型可替换、上下文可继承、结果可实时抵达。