StopCondition(停止条件)
vercel/ai SDK 中控制 Agent 循环何时停止的可替换策略函数,接收全量 steps 执行历史,支持同步和异步求值,多个条件组成数组时为 OR 语义(任意一个满足即停止)。
类型签名
typescript
// stop-condition.ts:L14-L19
type StopCondition<TOOLS, RUNTIME_CONTEXT> = (options: {
steps: Array<StepResult<TOOLS, RUNTIME_CONTEXT>>;
}) => PromiseLike<boolean> | boolean;
入参是 { steps } 对象(预留扩展槽),接收全量历史步骤数组,返回 true 表示停止循环。支持异步求值(PromiseLike<boolean>),可以写"查数据库判断是否超出预算"等异步停止条件。
三个内置工厂函数
| 函数 | 语义 | 实现 |
|---|---|---|
isStepCount(n) | 完成 n 步后停止 | steps.length === n(精确匹配) |
isLoopFinished() | 不干预,依赖自然终止 | () => false(Null Object 模式) |
hasToolCall(...names) | 最后一步调用了指定工具时停止 | steps[-1].toolCalls.some(name) |
Arrayable 与 OR 语义
stopWhen 参数类型为 Arrayable<StopCondition>,传数组时:
typescript
// generate-text.ts
(await Promise.all(conditions.map(c => c({ steps })))).some(r => r)
⚠️ 重要:Promise.all 先并行求值所有条件,再 .some() 聚合——没有短路。即使第一个条件已返回 true,其余异步条件仍继续执行到完成。与 Array.some() 的短路语义不同。
设计原因:确保有副作用的异步条件(如记录日志、更新外部状态)在每轮检测时都被通知到,不被先完成的条件截断。
双终止机制
vercel/ai 的 do-while 循环有两条独立退出路径:
- 自然终止:LLM 返回
stopfinish reason,无新 tool calls,循环直接退出,stop condition 不会被检测 - 显式终止:stop condition 返回
true,强制退出
isStepCount(1) 和 isStepCount(20) 在 LLM 返回 stop 时行为完全相同——自然终止路径不经过 stop condition 检测。
两个默认值差异
| 调用方 | 默认 stopWhen | 含义 |
|---|---|---|
generateText() 直接调用 | isStepCount(1) | 单步完成即停 |
ToolLoopAgent(默认配置) | isStepCount(20) | 最多 20 步 |
容易踩坑:以为调用 generateText({ tools: ... }) 会自动多步循环,实际上默认只跑一步。
已知边界情况
isStepCount(0) 是静默的语义错误:do-while 保证至少执行一次,第一步完成后 steps.length === 1,isStepCount(0) 的 === 0 条件永远不满足,循环无法通过 stop condition 层面终止。参数类型未做运行时校验,传 0 不报错但行为完全不符合预期。
与 LangChain 的对比
vercel/ai stopWhen | LangChain maxIterations | |
|---|---|---|
| 类型 | 策略函数(可替换) | 整数(硬截断) |
| 可访问上下文 | 全量 steps 历史 | 无(框架内部计数) |
| 语义感知 | hasToolCall 可按工具名停止 | 只能按步数截断 |
| 组合 | 数组 OR 语义 | 不支持 |
引用本术语的文章