🔄 循环控制(Loop Control)
停止条件
Agent 循环在以下情况下停止:
- 返回的完成原因不是
tool-calls - 调用的工具没有
execute函数 - 工具调用需要审批
- 满足停止条件
默认情况下,Agent 在 20 步后停止(stepCountIs(20))。
内置停止条件
typescript
import { ToolLoopAgent, stepCountIs } from 'ai';
const agent = new ToolLoopAgent({
model: "anthropic/claude-sonnet-4.5",
tools: { /* your tools */ },
stopWhen: stepCountIs(20),
});组合多个条件
typescript
import { ToolLoopAgent, stepCountIs, hasToolCall } from 'ai';
const agent = new ToolLoopAgent({
model: "anthropic/claude-sonnet-4.5",
tools: { /* your tools */ },
stopWhen: [
stepCountIs(20), // 最多 20 步
hasToolCall('someTool'), // 调用特定工具后停止
],
});自定义停止条件
typescript
import { ToolLoopAgent, StopCondition, ToolSet } from 'ai';
const tools = { /* your tools */ } satisfies ToolSet;
const hasAnswer: StopCondition<typeof tools> = ({ steps }) => {
return steps.some(step => step.text?.includes('ANSWER:')) ?? false;
};
const agent = new ToolLoopAgent({
model: "anthropic/claude-sonnet-4.5",
tools,
stopWhen: hasAnswer,
});基于成本的停止条件
typescript
const budgetExceeded: StopCondition<typeof tools> = ({ steps }) => {
const totalUsage = steps.reduce(
(acc, step) => ({
inputTokens: acc.inputTokens + (step.usage?.inputTokens ?? 0),
outputTokens: acc.outputTokens + (step.usage?.outputTokens ?? 0),
}),
{ inputTokens: 0, outputTokens: 0 },
);
const costEstimate =
(totalUsage.inputTokens * 0.01 + totalUsage.outputTokens * 0.03) / 1000;
return costEstimate > 0.5; // 超过 $0.50 时停止
};prepareStep:每步执行前的钩子
prepareStep 回调在循环的每一步之前运行,可用于动态修改设置。
动态模型选择
typescript
const agent = new ToolLoopAgent({
model: 'openai/gpt-4o-mini',
tools: { /* your tools */ },
prepareStep: async ({ stepNumber, messages }) => {
if (stepNumber > 2 && messages.length > 10) {
return {
model: "anthropic/claude-sonnet-4.5",
};
}
return {};
},
});上下文管理
typescript
const agent = new ToolLoopAgent({
model: "anthropic/claude-sonnet-4.5",
tools: { /* your tools */ },
prepareStep: async ({ messages }) => {
if (messages.length > 20) {
return {
messages: [
messages[0], // 保留系统指令
...messages.slice(-10), // 保留最后 10 条消息
],
};
}
return {};
},
});工具阶段控制
typescript
const agent = new ToolLoopAgent({
model: "anthropic/claude-sonnet-4.5",
tools: {
search: searchTool,
analyze: analyzeTool,
summarize: summarizeTool,
},
prepareStep: async ({ stepNumber }) => {
// 搜索阶段 (步骤 0-2)
if (stepNumber <= 2) {
return {
activeTools: ['search'],
toolChoice: 'required',
};
}
// 分析阶段 (步骤 3-5)
if (stepNumber <= 5) {
return {
activeTools: ['analyze'],
};
}
// 总结阶段 (步骤 6+)
return {
activeTools: ['summarize'],
toolChoice: 'required',
};
},
});强制工具调用模式
结合 toolChoice: 'required' 和无 execute 函数的 done 工具:
typescript
import { ToolLoopAgent, tool } from 'ai';
import { z } from 'zod';
const agent = new ToolLoopAgent({
model: "anthropic/claude-sonnet-4.5",
tools: {
search: searchTool,
analyze: analyzeTool,
done: tool({
description: 'Signal that you have finished your work',
inputSchema: z.object({
answer: z.string().describe('The final answer'),
}),
// 无 execute 函数 - 调用时停止 Agent
}),
},
toolChoice: 'required',
});
const result = await agent.generate({
prompt: 'Research and analyze this topic, then provide your answer.',
});
const toolCall = result.staticToolCalls[0];
if (toolCall?.toolName === 'done') {
console.log(toolCall.input.answer);
}手动循环控制
对于需要完全控制的场景:
typescript
import { generateText, ModelMessage } from 'ai';
const messages: ModelMessage[] = [{ role: 'user', content: '...' }];
let step = 0;
const maxSteps = 10;
while (step < maxSteps) {
const result = await generateText({
model: "anthropic/claude-sonnet-4.5",
messages,
tools: { /* your tools */ },
});
messages.push(...result.response.messages);
if (result.text) {
break; // 模型生成文本时停止
}
step++;
}