FastGPT 辅助生成(Auxiliary Generation)机制解析:不经过 Workflow Dispatcher 的复用式 AI 生成架构
【免费下载链接】FastGPTFastGPT is a knowledge-based platform built on the LLMs, offers a comprehensive suite of out-of-the-box capabilities such as data processing, RAG retrieval, and visual AI workflow orchestration, letting you easily develop and deploy complex question-answering systems without the need for extensive setup or configuration.项目地址: https://gitcode.com/GitHub_Trending/fa/FastGPT
辅助生成(Auxiliary Generation)是 FastGPT 面向"不经过 Workflow Dispatcher、但需要复用 Chat 身份、SSE、计费、停止与 Agent Loop 语义"的一类 AI 生成场景提供的统一运行框架,目前的核心调用方是 Chat Agent Helper。阅读本文后,你将掌握该模块的模块划分、完整执行生命周期、Agent Loop 接入方式、SSE 断流续传协议、停止标记语义与用量计费规则,并能基于runAuxiliaryGeneration快速扩展新的辅助生成场景。
定位与适用范围
辅助生成的设计初衷是解决一类"复用基础设施、但绕开 Workflow 运行时"的场景。它复用的能力包括:
- Chat 身份:继承团队、成员、用户上下文以及鉴权后的用户信息;
- SSE 输出:统一的流式协议、心跳与断流续传(resume mirror);
- 计费:团队 AI points 余额检查与 chat usage 记录创建;
- 停止:识别
/v2/chat/stop写入的统一停止标记; - Agent Loop:无业务工具的生成可以接入统一的 Agent 模型循环协议。
同时,该模块有清晰的边界,它不是第二套 Workflow runtime,也不负责以下事项(源码注释与设计文档均明确声明):
- Workflow 节点调度、变量或 nodeResponse——辅助生成不产生 nodeResponse 语义;
- 默认注入业务工具、Sandbox 或 Agent Skill——这些能力必须由业务调用方显式注入;
- 资源鉴权与请求参数校验——API 路由必须在进入辅助生成之前完成这些工作,
runAuxiliaryGeneration接收的已是鉴权后的teamId/tmbId/userId; - 持久化业务响应——processor 返回标准响应后,由调用方决定如何保存。
模块结构
模块位于packages/service/core/ai/auxiliaryGeneration/,文件与职责对应如下:
| 文件 | 职责 |
|---|---|
service.ts | 编排一次辅助生成的完整生命周期(SSE、用量、停止、processor、结束事件) |
agentLoop.ts | 将无业务工具的生成接入统一 Agent Loop |
stream.ts | 创建 SSE、心跳、错误、结束事件和断流续传 mirror |
usage.ts | 余额检查、usage 记录创建和用量推送 |
stop.ts | 读取并清理统一停止标记 |
type.ts | processor、用户上下文和运行结果协议 |
从源码结构看,service.ts是唯一公共编排入口,stream/usage/stop三个文件分别封装基础设施,agentLoop.ts依赖packages/service/core/ai/llm/agentLoop/interface的runAgentLoop。
执行流程:一次辅助生成的完整生命周期
设计文档给出了清晰的执行流程图,结合 service.ts 的源码实现,实际运行顺序如下:
API route |-- parse input and auth source |-- load histories / files `-- runAuxiliaryGeneration |-- create SSE and resume mirror |-- check balance and create usage record |-- clear stale stop flag |-- call business processor | `-- optional runAuxiliaryGenerationAgentLoop |-- emit done `-- clear timer and stop flag源码层面的关键步骤依次为:
- 创建 SSE 上下文:
createAuxiliaryGenerationStream({ req, res, teamId, sourceType, sourceId, chatId })完成 SSE 初始化与断流续传 mirror 的装配,并立即调用可选的onStreamContextReady回调——路由层可借此在 processor 执行前后的异常路径上写 error 并 flush resume; - 创建用量上下文:
createAuxiliaryGenerationUsage(...)先执行checkTeamAIPoints余额校验,再创建一次 chat usage record; - 清理陈旧停止标记:
clearAuxiliaryGenerationStop(...)避免上一次运行的停止状态污染本次生成; - 监听连接关闭:
res.once('close', ...)将stopping置为 true,实现连接断开即本地停止; - 定时刷新停止状态:以 100ms 间隔轮询
shouldAuxiliaryGenerationStop(...),将 Redis 中的停止标记同步到本地stopping; - 调用业务 processor:传入 query、files、data、histories、streamWriter、停止检查、usage sink 与鉴权用户信息;processor 内部可选用
runAuxiliaryGenerationAgentLoop; - 结束事件:processor 返回后调用
streamContext.writeDone(),依次发送 finish delta 与[DONE]; - finally 清理:无论成功失败,都会清除轮询定时器并再次清理停止标记。
runAuxiliaryGeneration只编排公共生命周期,业务差异完全通过processor注入。返回结果除了 processor 的响应外,还附带durationSeconds(精确到两位小数的耗时)与streamContext,供调用方继续操作流或用于日志。
Processor 协议:业务差异的注入点
type.ts定义了完整的 processor 协议(见 type.ts):
输入参数AuxiliaryGenerationProcessorParams<T>:
| 字段 | 类型 | 说明 |
|---|---|---|
query | string | 用户本轮问题 |
userAnswer | string? | 恢复暂停时的用户回答 |
files | AuxiliaryGenerationChatFileType[] | 本轮关联文件 |
data | T | 业务自定义数据,泛型注入 |
histories | ChatItemDBSchemaType[] | 历史消息 |
streamWriter | AuxiliaryGenerationStreamWriter? | 写 SSE 事件 |
requestOrigin | string? | 请求来源 Origin |
maxFiles | number? | 文件数量上限 |
customPdfParse | boolean? | 是否自定义 PDF 解析 |
checkIsStopping | () => boolean | 同步停止检查 |
usageSink | (usages: ChatNodeUsageType[]) => void | 用量推送 |
user | AuxiliaryGenerationUser | 已鉴权用户信息(teamId/tmbId/userId/isRoot/lang) |
返回协议AuxiliaryGenerationProcessorResponse:
aiResponse: AIChatItemValueItemType[]——标准 AI 回复内容;memories?: Record<string, any>——需要持久化的 AI ChatItem 附加状态(如 providerState);usage: { modelId; inputTokens; outputTokens }——本次生成的基础用量摘要。
值得强调的是:鉴权与参数校验必须在 API 路由层完成,processor 收到的user已经是可信上下文,这保证了"资源鉴权前置、业务执行后置"的边界。
Agent Loop 接入:无业务工具的生成语义
runAuxiliaryGenerationAgentLoop(见 agentLoop.ts)是辅助生成复用 Agent Loop 的标准入口,其约束如下:
- 不启用
plan、Sandbox、文件读取或知识库系统工具:systemTools仅开启ask,toolCatalog.runtimeTools默认空数组; - 启用标准
ask_user系统工具:暂停与恢复完全遵循 Agent Loop 的providerState + userAnswer协议; - 业务工具显式注入:调用方通过
runtimeTools与executeTool显式提供;若未配置 executor,默认实现会抛出Auxiliary generation runtime tool executor is not configured,从源码可见该约束是强制性的; - reasoning delta 转换:
emitEvent将reasoning_delta事件转为辅助生成的 answer SSE(reasoningContent字段),将answer_delta转为text字段; - usage 直通:
usagePush直接绑定调用方的usageSink; - 结果保留原语义:返回结果保持 Agent Loop 标准的
status、pause和providerState,业务层只负责转换展示和持久化,不自行判断暂停条件。此外该入口会额外计算answerText与reasoningText(从无 tool_calls 的 assistant 消息中聚合),方便业务直接落库展示。
设计文档特别强调:如果新场景需要业务工具,必须通过 runtime tool catalog 和 executor 显式注入,不能依赖 processor 读取 Workflow runtime——这是该模块与 Workflow 运行时解耦的根本保证。
Chat Agent Helper 连续调用:生成配置表单的完整链路
当前唯一核心调用方是 Chat Agent Helper,其连续调用流程可概括为:
模型调用 ask_user -> Agent Loop 返回 paused + ask + providerState -> Chat Agent Helper 保存 interactive、ask tool call 和 providerState memory -> 用户提交与 Workflow Agent 相同的 { answers: string[] } 原始结构 -> 调用方传回 providerState + userAnswer -> Agent Loop 在原 ask tool call 后追加 tool response 并继续 -> 模型调用 generate_config -> executor 校验并生成表单配置,返回 "Generate config success" -> 模型自行结束,调用方清理 providerState memory几个关键实现细节:
- 历史读取使用
reserveTool: true:Chat Agent Helper 读取历史时除 interactive 外,还必须持久化对应的ask_user和generate_configtool call/response,否则历史转换无法恢复工具语义; generate_config是普通 runtime tool,不设置stop:工具参数直接使用配置生成业务结构,不包含旧 JSON 路由时代的phase和reasoning字段;- executor 使用 Zod 校验:先校验参数,再确认全部资源 ID 都在当前成员的可访问资源集合内,最后转换为最终表单结构;参数错误作为 tool error 返回给模型修正,不再额外调用模型修复 JSON——这是对旧"模型修复 JSON"链路的一次明显简化。
Provider State 持久化:暂停与恢复的可靠性
辅助生成在暂停/恢复态下的持久化规则非常明确:
- 暂停态:把 Agent Loop 返回的完整
providerState写入当前 AI ChatItem 的memories; - 恢复态:只从最后一条 AI history 读取该 memory,并把原始回答作为
userAnswer传入; - 清理规则:
done、error和aborted三种终态都会清除该 memory,避免后续普通消息恢复出陈旧暂停点; - 不破坏通用保存语义:FastGPT 通用
saveChat已支持 memories;辅助生成只扩展 processor 返回协议和 Chat Agent Helper 的保存调用,不修改通用保存逻辑。
这一设计保证了"暂停点只活在当前一轮对话上下文中",避免了跨会话的状态污染。
SSE 与断流续传
SSE 层(见 stream.ts)只处理通用协议,业务事件(answer/interactive/config 等)由调用方显式写入。要点如下:
- Stream key:使用
teamId/sourceType/sourceId/chatId组合,与标准 Chat source 隔离规则一致; - 心跳:发送空的 answer delta(
createChatCompletionDeltaResponse({ text: '' })),事件名为answer; - 错误事件:通过
AuxiliaryGenerationEventEnum.error返回,复用getSseErrorResponse生成响应并遵循统一的 cookie 清理规则(shouldClearCookie时调用clearCookie(res)); - 正常结束:依次发送 finishReason 为
stop的 answer delta 与[DONE]; - 断流续传:通过
getStreamResumeMirror装配 resume mirror,路由层可通过onStreamContextReady获取 stream context,在 processor 前后的异常路径写 error 并调用flushResume()。
事件枚举定义在packages/global/core/ai/auxiliaryGeneration/constants.ts,包含answer、error、status、interactive、chatAgentConfig五种标准事件,业务事件由 processor 自行写入。
停止语义:与 Workflow 停止信号的统一
辅助生成读取/v2/chat/stop使用的 Redis key(见 stop.ts):
agent_runtime_stopping:<sourceType>:<sourceId>:<chatId>底层实现通过@fastgpt/dal/redis/caches的WorkflowStopSignalCache读写该 key。需要说明的是:该 key 目前由 workflow status 模块写入,辅助生成不依赖 Workflow 执行器,但必须识别同一个停止信号,以保证 ChatBox 的停止按钮对 Chat Agent Helper 同样生效。
停止语义的执行特点:
- 运行期间每 100ms 刷新一次停止状态(
service.ts中的setInterval); - 连接关闭也会触发本地停止(
res.once('close')置stopping = true); - 开始和结束时都清理旧标记,避免一次停止污染下一次生成;
- 停止后 processor 内通过
checkIsStopping()同步感知,及时中断模型循环。
用量与计费
用量流程(见 usage.ts)遵循"单次记录、统一推送"原则:
- 开始生成前检查团队 AI points:
checkTeamAIPoints(teamId)前置校验余额; - 根据
sourceType将 sourceId 记为 appId 或 skillId:当sourceType为app或chatAgentHelper时记为appId = sourceId;为skillEdit时记为skillId = sourceId; - 创建一次 chat usage record:
createChatUsageRecord({ appName, appId, skillId, teamId, tmbId, source }); - processor 通过 usage sink 推入用量:
pushUsage(usages)内部调用pushChatItemUsage将各模型、工具或压缩用量写入同一 usageId。
设计文档特别强调:辅助生成不重新计算 Agent Loop 积分,也不重复调用用量写入。Agent Loop 内部(provider、工具、压缩模块)只通过runtime.usagePush上报真实 usage,辅助生成只是将这一回调透传给 usage sink,避免了双重计费。
扩展规则:新增辅助生成场景的指南
设计文档为后续扩展给出了四条明确约束:
- 优先复用
runAuxiliaryGeneration,只新增 processor:公共生命周期(SSE、用量、停止、结束事件)已被service.ts固化,新场景只需提供自己的业务 processor; - 业务事件由 processor 显式写入:不扩展通用 stream 层去理解业务配置,保持
stream.ts的业务无关性; - 公共生命周期需求放在本模块;单场景数据组装保留在调用方业务目录:职责归属清晰,避免模块膨胀;
- source 标识统一使用
sourceType/sourceId:不能恢复 App-only 的appId入口,保证未来 skill 等非 App source 的扩展能力。
源码导航与验证
若要深入阅读或验证,可沿以下路径展开:
- 核心编排:service.ts、type.ts
- Agent Loop 接入:agentLoop.ts
- 基础设施:
stream.ts、usage.ts、stop.ts - 事件协议:constants.ts
- 底层 Agent Loop 协议:Agent Loop 设计 与实现
packages/service/core/ai/llm/agentLoop - 测试验证:agentLoop.test.ts 覆盖了辅助生成 Agent Loop 的契约行为
总体上,辅助生成模块是 FastGPT"基础设施复用"思路的典型实践:把 Chat 场景的公共运行要素抽成可编排的公共生命周期,同时通过 processor 注入与显式工具注入两条通道保留业务扩展自由度。理解这一模块,也就理解了 Chat Agent Helper 如何在不进入 Workflow 运行时的情况下,依然获得与主链路一致的流式输出、计费与停止体验。
【免费下载链接】FastGPTFastGPT is a knowledge-based platform built on the LLMs, offers a comprehensive suite of out-of-the-box capabilities such as data processing, RAG retrieval, and visual AI workflow orchestration, letting you easily develop and deploy complex question-answering systems without the need for extensive setup or configuration.项目地址: https://gitcode.com/GitHub_Trending/fa/FastGPT
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考