Appearance
stopWhen 参数用于控制 OpenRouter callModel 的多轮 tool 执行循环何时停止,是防止 agent 失控、控制成本的关键机制。提供 stepCountIs、maxCost、hasToolCall、maxTokensUsed 等内置条件,支持数组组合(任一满足即停),也支持自定义函数实现基于内容、质量、时间的复杂停止逻辑。
基本用法
typescript
import { OpenRouter, stepCountIs } from '@openrouter/agent';
const openrouter = new OpenRouter({
apiKey: process.env.OPENROUTER_API_KEY,
});
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Research this topic thoroughly',
tools: [searchTool, analysisTool],
stopWhen: stepCountIs(5), // 最多执行 5 步
});内置停止条件
stepCountIs(n) — 限制步骤数
typescript
import { stepCountIs } from '@openrouter/agent';
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Analyze this data',
tools: [analysisTool],
stopWhen: stepCountIs(10), // 执行 10 步后停止
});hasToolCall(name) — 等待特定 tool 被调用
typescript
import { hasToolCall } from '@openrouter/agent';
const finishTool = tool({
name: 'finish',
description: 'Call this when the task is complete',
inputSchema: z.object({ summary: z.string() }),
execute: async (params) => ({ done: true }),
});
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Research until you have enough information, then call finish',
tools: [searchTool, finishTool],
stopWhen: hasToolCall('finish'), // 调用 finish tool 时停止
});maxTokensUsed(n) — 限制 token 消耗
typescript
import { maxTokensUsed } from '@openrouter/agent';
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Generate content',
tools: [writingTool],
stopWhen: maxTokensUsed(5000), // 消耗 5000 token 后停止
});maxCost(amount) — 限制费用
typescript
import { maxCost } from '@openrouter/agent';
const result = openrouter.callModel({
model: 'openai/gpt-5.2',
input: 'Perform extensive analysis',
tools: [analysisTool],
stopWhen: maxCost(1.00), // 花费 $1.00 后停止
});finishReasonIs(reason) — 指定完成原因
typescript
import { finishReasonIs } from '@openrouter/agent';
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Complete this task',
tools: [taskTool],
stopWhen: finishReasonIs('stop'), // 模型自然完成时停止
});组合条件
传入数组,任一条件满足即停止:
typescript
import { stepCountIs, hasToolCall, maxCost } from '@openrouter/agent';
const result = openrouter.callModel({
model: 'openai/gpt-5.2',
input: 'Research thoroughly but stay within budget',
tools: [searchTool, finishTool],
stopWhen: [
stepCountIs(10), // 最多 10 步
maxCost(0.50), // 最多 $0.50
hasToolCall('finish'), // 或者 finish 被调用
],
});自定义停止条件
用函数实现任意停止逻辑:
typescript
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Process data',
tools: [processTool],
stopWhen: ({ steps }) => {
if (steps.length >= 20) return true;
// 最后一步没有 tool 调用时停止
const lastStep = steps[steps.length - 1];
if (lastStep && !lastStep.toolCalls?.length) return true;
return false;
},
});StopConditionContext 参数
自定义函数接收:
| 属性 | 类型 | 说明 |
|---|---|---|
steps | StepResult[] | 已完成的所有步骤,含结果和用量 |
StepResult 结构
typescript
interface StepResult {
response: Response;
toolCalls?: ParsedToolCall[];
toolResults?: ToolExecutionResult[];
tokens: {
input: number;
output: number;
cached: number;
};
cost: number;
}高级模式
基于时间停止
typescript
const startTime = Date.now();
const maxDuration = 30000; // 30 秒
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Work on this task',
tools: [workTool],
stopWhen: () => Date.now() - startTime > maxDuration,
});基于内容停止
typescript
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Search until you find the answer',
tools: [searchTool],
stopWhen: ({ steps }) => {
const lastStep = steps[steps.length - 1];
if (!lastStep) return false;
const content = JSON.stringify(lastStep.response);
return content.includes('ANSWER FOUND') || content.includes('TASK COMPLETE');
},
});基于质量停止
typescript
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Improve this text until it scores above 0.9',
tools: [improverTool, scorerTool],
stopWhen: ({ steps }) => {
for (const step of steps) {
for (const result of step.toolResults ?? []) {
if (result.toolName === 'scorer' && result.result?.score > 0.9) {
return true;
}
}
}
return false;
},
});从 maxToolRounds 迁移
typescript
// 旧写法
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Hello',
tools: [myTool],
maxToolRounds: 5,
});
// 新写法
import { stepCountIs } from '@openrouter/agent';
const result = openrouter.callModel({
model: 'openai/gpt-5-nano',
input: 'Hello',
tools: [myTool],
stopWhen: stepCountIs(5),
});不设置 stopWhen 时,默认行为等同于 stepCountIs(5)。
最佳实践
始终设置硬限制,防止失控执行:
typescript
stopWhen: [
stepCountIs(100), // 步骤上限
maxCost(10.00), // 费用上限
customCondition, // 业务逻辑
],常见问题
Q: stopWhen 数组中的条件是 AND 还是 OR 关系?
A: OR 关系。任一条件满足即停止。如果需要 AND,请使用自定义函数:stopWhen: ({ steps }) => conditionA(steps) && conditionB(steps)。
Q: 不设 stopWhen 会发生什么?
A: 默认等同于 stepCountIs(5),执行 5 步后停止。建议在生产环境显式设置,同时加上费用上限。
Q: 停止后还能获取到已完成步骤的结果吗?
A: 可以。通过 getResponse() 获取完整响应,其中包含所有已完成步骤的 tool 调用结果和 token 用量。