Skip to main content
当智能体使用多个工具时,有时你会希望在调用模型之前检查用量,并记录每个步骤的响应。Laravel AI SDK 的中间件并不是只包裹整个智能体一次,而是在生成过程的每个步骤中执行。本页基于 Laravel 13 官方文档和 laravel/ai v1.3.0 的实现,在 AI SDK 基本操作的基础上更进一步,梳理执行顺序与停止条件。

中间件的执行单位

当智能体收到模型响应、执行工具后再次调用模型时,下一次模型调用就是一个新的步骤。在每个步骤开始前,会按声明顺序依次经过 HasMiddleware::middleware() 返回的中间件。 传给中间件 handle(PendingStep $step, Closure $next) 的 PendingStep 包含已执行步骤的数组 steps、这些步骤的累计用量 usage,以及当前从零开始的步骤编号 number。第一次时,usage 尚不包含本次模型调用的用量。 附加在 $next($step) 结果上的 then() 会在模型响应之后、工具调用执行之前运行。它并不是只在工具执行后才调用的钩子。此外,此时的 usage 是之前已完成步骤的合计,并不会预测进行中请求的 token 数。

注册每个步骤的处理

下面的示例只记录步骤编号以及到目前为止使用的输入 token 数。请避免无条件地将提示正文或模型输出保存到日志中。
在智能体上实现 HasMiddleware,并从 middleware() 返回实例。
在 middleware() 的排列顺序中,应将 Stop 放在前面。当超过上限而不开始下一个步骤时,后面的 LogAgentSteps 在该步骤中不会执行。如果顺序颠倒,可能只会记录“开始”日志,而不会记录“模型已响应”日志。需要从 handle() 返回 $next($step) 的结果,而 then() 的回调无需返回响应。

Stop 会阻止下一次模型调用

Stop::when(...) 在条件为 true 时、Stop::unless(...) 在条件为 false 时,会在该步骤之前结束处理。上面的示例在已完成步骤的累计输入 token 达到 50,000 以上时,不再进行下一次调用。它并不是在单次模型调用超过阈值之前强制停止的硬性限制。
Stop 不会中断正在进行的提供商请求。如果需要严格保证用量上限,请不要只依赖对下一个步骤的判断,也应考虑模型或提供商一侧的限制。
需要按自定义条件停止的中间件,也可以返回 Laravel\Ai\Gateway\StepResult::stop()。handle() 应返回 $next($step) 的结果、StepResponse 或 StepResult::stop()。返回无关的类型会抛出异常。

验证执行顺序

为避免混淆模型响应与工具执行,至少应确认以下情况。
  • 只有一个步骤的生成中,开始日志和模型响应日志各输出一次。
  • 在工具之后的追加步骤中,编号从 0 开始递增,后续步骤的 usage 包含前面步骤的用量。
  • 如果一开始就满足停止条件,则不会发生模型调用,也不会产生 LogAgentSteps 的日志。
  • 如果中途达到条件,此前的步骤会保留,下一个步骤的模型调用不会发生。
请将正常路径与停止路径分开,确认每个步骤的执行次数。即使 then() 需要产生副作用,也应以“在获得模型响应之前失败或停止的路径中不会调用它”为前提进行设计。

参考的一手资料

最后修改于 2026年10月21日