速度
缓存后的 Agent 工作流会跳过后续运行中的 LLM 推理,因此执行速度可提升 10 到 100 倍。
文档索引
可在此获取完整文档索引:https://docs.stagehand.dev/llms.txt
在进一步浏览前,可使用该文件发现所有可用页面。
使用自动缓存将 Agent 工作流转换为快速、确定性的脚本。
Agent 工作流非常适合探索和自动化复杂任务,但它们也可能比较慢,并且不具备确定性。本指南将展示如何使用 Stagehand 内置的自动缓存,把由 Agent 发现的工作流转换为快速、确定性的脚本,执行速度可提升 10 到 100 倍。
速度
缓存后的 Agent 工作流会跳过后续运行中的 LLM 推理,因此执行速度可提升 10 到 100 倍。
成本
消除重复的 LLM 调用——首次运行使用推理,后续运行直接使用缓存。
可靠性
缓存后的动作具有确定性,相比每次重新探索的 Agent 流程更可预测。
简单性
开箱即用——只需指定 cacheDir,其余事情由 Stagehand 自动处理。
当你指定 cacheDir 时:
缓存键会基于以下内容自动生成:
只需在初始化 Stagehand 时添加 cacheDir:
import { Stagehand } from "@browserbasehq/stagehand";
// 启用自动缓存const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "agent-cache" // 自动缓存已启用});
await stagehand.init();const page = stagehand.context.pages()[0];
await page.goto("https://example.com");
const agent = stagehand.agent({ mode: "cua", model: "google/gemini-3-flash-preview", systemPrompt: "You are a helpful assistant that can use a web browser.",});
// 首次运行:使用 LLM 推理(约 20-30 秒,约 50,000 tokens)// 后续运行:使用缓存动作(约 2-3 秒,0 tokens)const result = await agent.execute({ instruction: "Find the login form, fill in username 'demo' and password 'test123', then click submit", maxSteps: 10});
console.log("Completed:", result.success);console.log("Actions taken:", result.actions.length);
await stagehand.close();就是这么简单!当你第二次运行这段脚本时,它会自动复用已缓存的 Agent 动作。
为不同工作流使用具有描述性的缓存目录:
// 登录工作流const loginStagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/login-workflow"});
// 结账工作流const checkoutStagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/checkout-workflow"});
// 数据提取工作流const extractStagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/extraction-workflow"});import { Stagehand } from "@browserbasehq/stagehand";
const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/github-search" // 启用缓存});
await stagehand.init();const page = stagehand.context.pages()[0];
await page.goto("https://github.com");
const agent = stagehand.agent({ mode: "cua", model: "google/gemini-3-flash-preview", systemPrompt: "You are a helpful assistant that can use a web browser.",});
console.log("首次运行:使用 Agent 进行探索...");const startTime = Date.now();
const result = await agent.execute({ instruction: "Search for 'stagehand' and click the first repository result", maxSteps: 10});
const duration = Date.now() - startTime;console.log(`首次运行完成,用时 ${duration}ms`);console.log(`动作数:${result.actions.length}`);console.log(`状态:${result.success}`);
await stagehand.close();
// 输出(示例):// 首次运行完成,用时 25000ms// 动作数:8// 状态:true再次运行完全相同的脚本:
import { Stagehand } from "@browserbasehq/stagehand";
const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/github-search" // 相同的缓存目录});
await stagehand.init();const page = stagehand.context.pages()[0];
await page.goto("https://github.com");
const agent = stagehand.agent({ mode: "cua", model: "google/gemini-3-flash-preview", systemPrompt: "You are a helpful assistant that can use a web browser.",});
console.log("后续运行:使用缓存动作...");const startTime = Date.now();
const result = await agent.execute({ instruction: "Search for 'stagehand' and click the first repository result", maxSteps: 10});
const duration = Date.now() - startTime;console.log(`后续运行完成,用时 ${duration}ms`);console.log(`动作数:${result.actions.length}`);console.log(`状态:${result.success}`);
await stagehand.close();
// 输出(示例):// 后续运行完成,用时 2500ms ← 快了 10 倍!// 动作数:8// 状态:true虽然缓存会自动处理执行过程,但你仍然可以使用 stagehand.history 来分析发生了什么:
import { Stagehand } from "@browserbasehq/stagehand";import fs from "fs/promises";
const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/workflow"});
await stagehand.init();const page = stagehand.context.pages()[0];
await page.goto("https://example.com");
const agent = stagehand.agent({ mode: "cua", model: "google/gemini-3-flash-preview", systemPrompt: "You are a helpful assistant that can use a web browser.",});
await agent.execute({ instruction: "Complete the login process", maxSteps: 10});
// 分析 Agent 执行了什么const history = await stagehand.history;
console.log(`\n工作流分析:`);console.log(`总操作数:${history.length}`);
const agentOps = history.filter(e => e.method === 'agent');const actOps = history.filter(e => e.method === 'act');const navOps = history.filter(e => e.method === 'navigate');
console.log(`- Agent 执行次数:${agentOps.length}`);console.log(`- Act 操作数:${actOps.length}`);console.log(`- Navigate 操作数:${navOps.length}`);
// 保存分析结果供文档或调试使用await fs.writeFile( 'workflow-analysis.json', JSON.stringify(history, null, 2));
await stagehand.close();如果网站结构发生变化,请清除缓存以强制重新探索:
import { rmSync } from 'fs';
// 清除特定工作流缓存rmSync('cache/login-workflow', { recursive: true, force: true });
// 然后重新运行,让 Agent 从头探索const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/login-workflow" // 将重新构建缓存});import { rmSync, existsSync } from 'fs';
function clearCacheIfNeeded(cacheDir: string, maxAge: number = 7 * 24 * 60 * 60 * 1000) { if (!existsSync(cacheDir)) { return; // 没有可清理的缓存 }
const stats = statSync(cacheDir); const age = Date.now() - stats.mtimeMs;
if (age > maxAge) { console.log(`缓存已超过 ${maxAge}ms,正在清理...`); rmSync(cacheDir, { recursive: true, force: true }); }}
// 如果缓存超过 7 天则清除clearCacheIfNeeded('cache/workflow');
const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/workflow"});将缓存与回退机制结合使用,以提高韧性:
async function executeWithFallback() { const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/workflow", selfHeal: true // 启用自愈 });
await stagehand.init(); const page = stagehand.context.pages()[0];
await page.goto("https://example.com");
const agent = stagehand.agent({ model: "anthropic/claude-sonnet-4-6" });
try { // 先尝试使用缓存 const result = await agent.execute({ instruction: "Complete the checkout process", maxSteps: 15 });
console.log("执行成功:", result.success); } catch (error) { console.error("缓存工作流执行失败:", error);
// 清除缓存并重新探索 rmSync('cache/workflow', { recursive: true, force: true });
console.log("正在使用全新探索重试..."); const retryResult = await agent.execute({ instruction: "Complete the checkout process", maxSteps: 15 });
console.log("重试成功:", retryResult.success); }
await stagehand.close();}将缓存目录提交到仓库中,以确保在不同环境下行为一致:
# 为了实现确定性的 CI/CD,可提交缓存目录!cache/!cache/**/*.json// CI/CD 流水线将使用预先生成的缓存const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/production-workflow" // 已提交到仓库});按工作流或功能组织缓存:
// 推荐:具有描述性的缓存名称cacheDir: "cache/user-registration"cacheDir: "cache/product-search"cacheDir: "cache/checkout-flow"
// 避免:过于泛化的名称cacheDir: "cache"cacheDir: "my-cache"为缓存刷新制定明确策略:
// 方案 1:基于时间的失效if (isCacheOlderThan('cache/workflow', 7)) { clearCache('cache/workflow');}
// 方案 2:基于版本的失效const CACHE_VERSION = 'v2';const cacheDir = `cache/workflow-${CACHE_VERSION}`;
// 方案 3:手动失效标记if (process.env.CLEAR_CACHE === 'true') { clearCache('cache/workflow');}在生产环境使用前,始终先在 staging 中验证缓存工作流:
const env = process.env.NODE_ENV === 'production' ? 'production' : 'staging';
const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: `cache/${env}-workflow`});追踪缓存使用情况以便优化:
const cacheHit = existsSync('cache/workflow') && statSync('cache/workflow').mtimeMs < Date.now();
if (cacheHit) { console.log("缓存命中 - 使用缓存工作流");} else { console.log("缓存未命中 - 使用 Agent 重新探索");}
// 记录指标metrics.recordCacheHit(cacheHit);不使用缓存(每次运行都重新推理):
const stagehand = new Stagehand({ env: "BROWSERBASE" });// 未指定 cacheDir
const result = await agent.execute({ instruction: "Complete workflow", maxSteps: 10});
// 每次运行:约 20-30 秒,约 50,000 tokens使用自动缓存(首次运行):
const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/workflow"});
const result = await agent.execute({ instruction: "Complete workflow", maxSteps: 10});
// 首次运行:约 20-30 秒,约 50,000 tokens(并为下次缓存)使用自动缓存(后续运行):
const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/workflow" // 复用缓存});
const result = await agent.execute({ instruction: "Complete workflow", maxSteps: 10});
// 后续运行:约 2-3 秒,0 tokens ← 快了 10-100 倍!问题:后续运行仍然很慢。
解决方案:
cacheDir 路径正确,并且每次运行保持一致。const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/workflow", verbose: 2 // 启用调试日志});问题:缓存动作在后续运行中失败。
解决方案:
const stagehand = new Stagehand({ env: "BROWSERBASE", cacheDir: "cache/workflow", selfHeal: true // 适应变化});问题:缓存目录数量持续增长,难以管理。
解决方案:
// 带版本号的缓存const CACHE_VERSION = '2024-01';const cacheDir = `cache/workflow-${CACHE_VERSION}`;
// 清理旧版本rmSync('cache/workflow-2023-12', { recursive: true, force: true });Agent 指南
进一步了解 Agent 的能力与配置。
缓存指南
查看 act() 与 agent() 自动缓存的完整说明。
可观测性
监控并追踪历史记录、指标与执行过程。
速度优化
了解更多提升自动化速度的技巧。