Laravel AI SDK v1.4.0 更改了工具抛出异常时的行为。现在模型将收到作为工具结果的失败信息,运行继续,因此代理可以解释问题或尝试其他操作。此次发布还允许模拟的代理恢复暂停的工具审批,为五种更多响应类型添加原始 HTTP 响应,并以正确的异常报告 OpenAI 计费错误。
- 抛出异常的工具不再结束代理运行
- 代理模拟运行已批准的工具并存储其结果
raw属性适用于分类、嵌入、转录、图像和重排序响应- OpenAI 配额和信用错误抛出
InsufficientCreditsException而不是RateLimitedException - 提供者流错误在固定的
error名称下广播 - 对话标题生成触发常规的代理事件
- 修复 Anthropic 和 OpenAI 兼容的工具调用
新增内容
代理从工具故障中恢复
在此版本之前,工具内部抛出的异常会结束运行并触发 AgentFailed。现在 SDK 捕获该异常并将其消息作为失败的工具结果发送回模型。如果 RefundOrder 工具抛出“订单 1234 无法再退款”,模型将收到:
The tool call failed: Order 1234 can no longer be refunded.
然后模型可以告诉用户出了什么问题或调用不同的工具。异常仍通过 report() 发送到您的异常处理程序,ToolFailed 仍然触发,流式运行将失败作为 ToolResult 事件发出,其中 successful 设置为 false。已批准的抛出异常的工具此前已按此方式处理,因此所有工具现在行为一致。
仅恢复工具自身的异常。由事件监听器抛出的异常仍会导致运行失败。
示例和注意事项,请参阅 Laravel AI SDK Agents 中的 Handle Tool Exceptions。
使用代理模拟测试工具审批流程
人机回环工具审批会暂停运行,直到有人批准或拒绝工具调用。在 Agent::fake() 下,恢复该运行会完全跳过工具:已批准的工具从未运行,也没有流式传输或存储结果。您无法从头到尾测试审批流程。
模拟的代理现在以与提供者相同的方式恢复暂停的调用。已批准的工具运行并存储其结果,被拒绝的工具获得拒绝的结果,然后模拟返回其下一个响应:
SupportAgent::fake([
new ToolCall('call-1', 'SendEmail', ['to' => 'john@example.com']),
'The email is on its way.',
]);
$paused = (new SupportAgent)->forUser($user)->prompt('Email John the release notes');
$response = (new SupportAgent)
->continue($paused->conversationId, as: $user)
->prompt(Decisions::from(['call-1' => Decision::approve()]));
$response->toolResults[0]->result; // "Email sent to john@example.com."
$response->text; // "The email is on its way."
涵盖批准、拒绝和编辑决策的完整测试示例,请参阅 Laravel AI SDK 中的 Test Tool Approval Flows。
更多响应类型的原始 HTTP 响应
文本响应自 0.10.3 版本起就拥有包含提供者 HTTP 响应的 raw 属性。分类、嵌入、转录、图像和重排序响应现在也拥有它,因此您可以读取 SDK 未映射的提供者字段,例如 OpenRouter 返回的 usage.cost 值:
$response = Classification::of($ticket)
->questions($questions)
->classify(provider: 'openrouter');
$cost = $response->raw->json('usage.cost');
序列化后该属性为 null。在嵌入中,当所有向量都来自缓存时,它也是 null。
OpenAI 计费错误抛出 InsufficientCreditsException
OpenAI 对速率限制和计费问题(如 insufficient_quota 和 credit_balance_exhausted)均返回 429 状态码。SDK 将每个 429 视为速率限制,因此计费错误抛出 RateLimitedException,并且当响应具有短 Retry-After 头时可以重试。
带有 OpenAI 计费代码之一的 429 现在抛出 InsufficientCreditsException 且不会重试。其他 429 响应仍抛出 RateLimitedException。故障转移保持不变,因为这两个异常都是可故障转移的。
流错误在固定名称下广播
广播流事件使用其类型作为事件名称,例如 text_delta 或 tool_call。提供者错误使用提供者的错误代码,例如 403 或 PERMISSION_DENIED,因此前端无法知道要监听哪个名称。提供者错误现在广播为 error。负载的 type 仍携带提供者的代码,作业失败仍广播为 stream_failed。
对话标题生成触发代理事件
生成对话标题会进行第二次模型调用,但它不触发任何事件,因此其令牌使用和故障不会出现在您的代理运行事件中。标题调用现在作为代理运行在轮次的提供者和最便宜的模型上运行。其代理是 AnonymousAgent,其 parentInvocationId 指向触发它的轮次。失败的标题调用仍回退到提示文本,永远不会导致轮次失败。
其他修复
- Anthropic 工具调用在消息以
end_turn结尾时运行(#1188),流式文本在pause_turn续传之间连接(#1186) - OpenAI 兼容的工具调用在未发送索引或以
stop结束时运行(#1192) - OpenAI 批量嵌入保持输入顺序(#1172),自定义语音作为对象发送(#1212)
- 存储的消息 ID 复制到
RUN_FINISHED元数据中,@ag-ui/client1.x 在其中保留它们(#1165) - 恢复轮次的内容从其合并的步骤重建(#1162)
- Mistral 模型更新为其最新版本(#1173)
升级说明
工具异常不再导致运行失败或触发 AgentFailed。如果您的代码依赖于旧行为,请从 ToolFailed 监听器重新抛出,因为监听器异常仍会结束运行:
use Illuminate\Support\Facades\Event; use Laravel\Ai\Events\ToolFailed; Event::listen(ToolFailed::class, fn (ToolFailed $event) => throw $event->exception);
在 Agent::fake() 下恢复审批的测试现在运行已批准的工具。没有原因的拒绝现在会结束轮次,就像真实提供者一样,因此期望在拒绝后收到回复的测试应传递一个原因,例如 Decision::reject('Not now.')。
捕获 RateLimitedException 以处理 OpenAI 配额或计费错误的代码需要改为捕获 InsufficientCreditsException。
通过其代码监听提供者错误的前端需要监听 error。
在 PromptingAgent、AgentPrompted、AgentFailed 和步骤事件上的监听器现在也会接收标题生成运行。如果需要区分它们与用户的轮次,请检查 parentInvocationId。
使用 composer update laravel/ai 进行升级,并查看官方文档了解配置。我们的 Laravel AI SDK 1.1 帖子涵盖了之前的次要版本。