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 以上时,不再进行下一次调用。它并不是在单次模型调用超过阈值之前强制停止的硬性限制。
需要按自定义条件停止的中间件,也可以返回
Laravel\Ai\Gateway\StepResult::stop()。handle() 应返回 $next($step) 的结果、StepResponse 或 StepResult::stop()。返回无关的类型会抛出异常。
验证执行顺序
为避免混淆模型响应与工具执行,至少应确认以下情况。- 只有一个步骤的生成中,开始日志和模型响应日志各输出一次。
- 在工具之后的追加步骤中,编号从 0 开始递增,后续步骤的
usage包含前面步骤的用量。 - 如果一开始就满足停止条件,则不会发生模型调用,也不会产生
LogAgentSteps的日志。 - 如果中途达到条件,此前的步骤会保留,下一个步骤的模型调用不会发生。
then() 需要产生副作用,也应以“在获得模型响应之前失败或停止的路径中不会调用它”为前提进行设计。