用途
ai-core/middleware 是 TanStack AI 生态中构建于 ai-core 之上的中间件技能,用于在聊天(chat)生命周期中插入自定义逻辑。它通过一组钩子(hooks)让开发者在模型调用、流式输出、工具执行、用量统计、结束或出错等关键节点进行拦截、观测和修改。典型用途包括分析埋点、日志记录、工具调用守卫、结构化输出配置调整等。
依赖说明:该技能建立在 ai-core 之上,使用前应先阅读 ai-core 以了解关键规则。
主要能力
中间件通过实现 ChatMiddleware 接口中的可选钩子来工作。每个钩子第一个参数都是 ChatMiddlewareContext,提供 requestId、streamId、phase、iteration、chunkIndex、model、provider、signal、abort()、defer() 等字段。parentRunId 表示当前运行延续的 run,subagentRunId 仅在子智能体内部设置。
可用钩子包括:
- onConfig:在启动时(init)、每次迭代前(beforeModel)以及独立终结边界各触发一次,接收 ChatMiddlewareConfig,可返回部分配置进行合并。
- onStructuredOutputConfig:仅在独立终结边界触发,接收 StructuredOutputMiddlewareConfig,可返回部分配置。
- onStart:在初始 onConfig 之后触发一次。
- onIteration:每次智能体循环迭代开始时触发,接收 IterationInfo。
- onShouldContinue:决定是否开始下一次智能体循环迭代,接收 AgentLoopState,返回 false 可停止。
- onChunk:每个流式分块触发,接收 StreamChunk,可返回 void、chunk、chunk[] 或 null。
- onBeforeToolCall:每个工具执行前触发,接收 ToolCallHookContext,可返回决策或 void。
- onAfterToolCall:每个工具执行后触发,接收 AfterToolCallInfo。
- onToolPhaseComplete:一次迭代中所有工具调用完成后触发,接收 ToolPhaseCompleteInfo。
- onUsage:当 RUN_FINISHED 包含用量数据时触发,接收 UsageInfo。
- onFinish:运行正常完成时触发,接收 FinishInfo。
- onAbort:运行被中止时触发,接收 AbortInfo。
- onError:发生未处理错误时触发,接收 ErrorInfo。
终结类钩子(onFinish、onAbort、onError)互斥,每次 chat() 调用只会触发其中一个。
关于采样参数:temperature、topP、maxTokens 不是 ChatMiddlewareConfig 的一等字段。若要在中间件中调整采样,需返回一个修改 config.modelOptions 的部分对象,并使用提供方原生键名(如 OpenAI 的 temperature / max_output_tokens、Anthropic 的 max_tokens、Ollama 的嵌套 options.num_predict)。返回顶层 temperature/maxTokens 不会生效。
阶段(phase)
ctx.phase 可能取值:
- 'init':初始设置,在第一个 onConfig 快照构建之前。
- 'beforeModel':每次智能体循环适配器调用之前(onConfig 在此重新触发)。
- 'modelStream':智能体循环内模型流式分块期间。
- 'beforeTools':工具执行阶段之前。
- 'afterTools':工具执行阶段之后。
- 'structuredOutput':独立终结适配器调用期间(对来自 adapter.structuredOutputStream 或合成回退的所有分块设置)。原生合并输出不会出现此阶段。
独立终结路径(不支持原生合并的适配器):
- onStructuredOutputConfig 在结构化输出边界先于 onConfig 触发。
- onConfig 在同一边界以 ctx.phase === 'structuredOutput' 重新触发,接收经过 onStructuredOutputConfig 处理后的配置视图(不含 outputSchema)。
- onChunk 和 onUsage 对结构化输出调用发出的每个分块和用量事件触发,ctx.phase === 'structuredOutput'。
- onIteration 不会为终结触发,它仅用于智能体循环。
- 终结 info 与结构化输出:info.usage / info.finishReason / info.content 反映智能体循环的终结状态,而非终结步骤。对于无工具的 chat({ outputSchema }) 运行,info.usage 为 undefined,info.finishReason 为 null。要捕获终结 token,应使用 onUsage。结构化输出结果本身可通过 onChunk 中的 structured-output.complete CUSTOM 事件观察。
原生合并输出:
- 受 schema 约束的 JSON 由普通智能体循环迭代产生。onStructuredOutputConfig 不触发,ctx.phase 保持 'modelStream',onIteration 为该迭代触发。
- info.content 包含结构化 JSON,因为它是智能体循环文本。中间件在同一阶段的 onChunk 中观察 structured-output.complete 事件。
两种路径共同点:
- 成功完成时,onFinish 在结构化结果完成后触发一次。终结钩子互斥仍然成立。
- 到 onFinish 时,ctx.messages 包含已完成的终结助手消息。
onStructuredOutputConfig
这是一个专用配置钩子,仅在独立终结边界触发。可用于转换发送给提供方的 JSON Schema(注入 $defs、剥离供应商不兼容的关键字),或应用不应影响智能体循环适配器调用的结构化输出专属配置。
其签名接收 ChatMiddlewareContext 和 StructuredOutputMiddlewareConfig,可返回 void、null、部分配置或它们的 Promise。StructuredOutputMiddlewareConfig 继承自 ChatMiddlewareConfig 但省略了 tools,并新增 outputSchema(发送给提供方的 JSON Schema)。注意此处没有 config.tools,结构化输出调用是最终的无工具调用,在此读取或返回 tools 会导致编译错误。
顺序规则:onStructuredOutputConfig 在结构化输出边界先于 onConfig 触发;onConfig 随后以 ctx.phase === 'structuredOutput' 重新触发,接收处理后的配置(不含 outputSchema)。通用转换用 onConfig,需要转换 JSON Schema 或应用结构化输出专属行为时用 onStructuredOutputConfig。
核心模式
模式 1:分析与日志中间件。使用 onStart、onFinish、onUsage 和 onError 实现全面可观测性。使用 ctx.defer() 执行非阻塞异步副作用,避免阻塞流。
模式 2:工具拦截中间件。使用 onBeforeToolCall 在执行前校验、门控或转换工具参数;使用 onAfterToolCall 记录结果和耗时。第一个从 onBeforeToolCall 返回非 void 决策的中间件会短路该调用剩余的中间件。决策类型包括:void/undefined 继续正常执行;{ type: 'transformArgs', args } 替换参数;{ type: 'skip', result } 跳过执行并使用给定结果;{ type: 'abort', reason? } 中止整个聊天运行。
模式 3:结构化输出中间件。在独立终结路径上,最终结构化输出适配器调用与智能体循环流经同一中间件链,ctx.phase === 'structuredOutput'。原生合并输出没有单独的提供方调用,中间件在 modelStream 期间观察其分块,onStructuredOutputConfig 不触发,中间件无法转换原生合并的 schema。可用于追踪每个分块,或通过 onStructuredOutputConfig 改写 schema(如注入共享 $defs)。
模式 4:多中间件组合。中间件按数组顺序从左到右执行,顺序对管道或短路类钩子很重要。
使用方式
在 chat() 调用的 middleware 数组中传入中间件对象。每个中间件可实现 name 以及所需的钩子。示例中通过 openaiText('gpt-5.5') 作为适配器,将 middleware 数组传入 chat(),再用 toServerSentEventsResponse(stream) 返回响应。
适用场景
- 分析埋点与用量统计(onStart、onUsage、onFinish)。
- 错误上报(onError)。
- 工具调用安全守卫与参数默认值注入(onBeforeToolCall)。
- 工具执行结果与耗时日志(onAfterToolCall)。
- 结构化输出 schema 改写与追踪(onStructuredOutputConfig、onChunk)。
- 多中间件按顺序组合实现可观测性与控制逻辑。
限制
- 依赖 ai-core,需先阅读其关键规则。
- 终结钩子互斥,每次 chat() 只触发一个。
- 采样参数需通过 config.modelOptions 使用提供方原生键名设置,顶层字段无效。
- onStructuredOutputConfig 仅在独立终结路径触发,原生合并输出无法通过中间件转换 schema。
- 该钩子配置中不含 tools,读取或返回 tools 会导致编译错误。
- onIteration 仅用于智能体循环,不为终结触发。
- 无工具的 chat({ outputSchema }) 运行中 info.usage 为 undefined、info.finishReason 为 null。
关于收费、价格、平台支持范围等信息,资料中暂未提供。