缓存 AI 规划和定位
Midscene 支持缓存 Plan 的步骤与匹配到的元素位置信息,减少 AI 模型的调用次数,从而大幅提升执行效率。请注意,DOM 元素缓存仅在 Web 自动化任务中支持,且存在一定局限性。
效果
当缓存命中时,脚本的执行时间会显著降低。例如在如下案例中,执行耗时从51秒降低到了28秒。


缓存文件和存储
Midscene 的缓存机制基于输入的稳定性和输出的可复用性。当相同的任务指令在相似的页面环境下重复执行时,Midscene 会优先使用已缓存的结果,避免重复调用 AI 模型, 从而显著提升执行效率。
缓存的核心机制包括:
- 任务指令缓存:对于规划类操作(如
ai、aiAct),Midscene 会将 prompt 指令作为缓存键,存储 AI 返回的执行计划
- 元素定位缓存:对于定位类操作(如
aiLocate、aiTap),系统会将定位 prompt 作为缓存键,存储元素的 XPath 信息,下次执行时先验证 XPath 是否仍然有效
- 失效机制:当缓存失效时,系统会自动回退到 AI 模型重新分析
- 永不缓存查询结果:查询类操作(如
aiBoolean、aiQuery、aiAssert)不会被缓存
缓存内容会保存到 ./midscene_run/cache 目录下,以 .cache.yaml 为扩展名。
如果缓存未命中,Midscene 将会重新调用 AI 模型,并更新缓存文件。
缓存策略
通过配置 cache 选项,你可以为 Agent 启用缓存。
禁用缓存
配置方式:cache: false 或不配置 cache 选项
完全禁用缓存功能,每次都重新调用 AI 模型。适合需要实时结果或调试时使用。默认情况下,如果不配置 cache 选项,缓存是禁用状态。
// 直接创建 Agent
const agent = new PuppeteerAgent(page, {
cache: false,
});
# YAML 配置
agent:
cache: false
读写模式
配置方式:cache: { id: "my-cache-id" } 或 cache: { strategy: "read-write", id: "my-cache-id" }
自动读取已有缓存,执行过程中自动更新缓存文件。strategy 的默认值是 read-write。
// 直接创建 Agent - 显式设置 cache ID
const agent = new PuppeteerAgent(page, {
cache: { id: "my-cache-id" },
});
// 显式指定 strategy
const agent = new PuppeteerAgent(page, {
cache: { strategy: "read-write", id: "my-cache-id" },
});
# YAML 配置 - 显式设置 cache ID
agent:
cache:
id: "my-cache-test"
# 显式指定 strategy
agent:
cache:
id: "my-cache-test"
strategy: "read-write"
YAML 模式还支持配置 cache: true,自动使用文件名作为 cache ID。
只读,手动写入
配置方式:cache: { strategy: "read-only", id: "my-cache-id" }
只读取缓存,不自动写入缓存文件,需要手动调用 agent.flushCache() 写入缓存文件,适合生产环境,确保缓存的一致性
// 直接创建 Agent
const agent = new PuppeteerAgent(page, {
cache: { strategy: "read-only", id: "my-cache-id" },
});
// 需要手动写入缓存
await agent.flushCache();
# YAML 配置
agent:
cache:
id: "my-cache-test"
strategy: "read-only"
只写模式
配置方式:cache: { strategy: "write-only", id: "my-cache-id" }
只写入缓存,不读取已有缓存内容。每次执行时都会调用 AI 模型,并将结果写入缓存文件。适合初次建立缓存或更新缓存时使用。
// 直接创建 Agent
const agent = new PuppeteerAgent(page, {
cache: { strategy: "write-only", id: "my-cache-id" },
});
# YAML 配置
agent:
cache:
id: "my-cache-test"
strategy: "write-only"
兼容方式(不推荐)
通过环境变量 MIDSCENE_CACHE=1 配合 cacheId 配置,等同于读写模式。
// 旧方式,需要 MIDSCENE_CACHE=1 环境变量和 cacheId
const agent = new PuppeteerAgent(originPage, {
cacheId: 'puppeteer-swag-sab'
});
MIDSCENE_CACHE=1 tsx demo.ts
使用 Midscene 的 Playwright AI Fixture
在使用 @midscene/web/playwright 中的 PlaywrightAiFixture 时,可以 通过相同的 cache 配置来管理缓存行为。
禁用缓存
// fixture.ts in sample code
export const test = base.extend<PlayWrightAiFixtureType>(
PlaywrightAiFixture({
cache: false,
}),
);
读写模式
// 对应样例代码中的 fixture.ts
// 自动生成 cache ID(基于测试信息)
export const test = base.extend<PlayWrightAiFixtureType>(
PlaywrightAiFixture({
cache: true,
}),
);
// 对应样例代码中的 fixture.ts
// 显式指定 cache ID
export const test = base.extend<PlayWrightAiFixtureType>(
PlaywrightAiFixture({
cache: { id: "my-fixture-cache" },
}),
);
只读,手动写入
// 对应样例代码中的 fixture.ts
export const test = base.extend<PlayWrightAiFixtureType>(
PlaywrightAiFixture({
cache: { strategy: "read-only", id: "readonly-cache" },
}),
);
在只读模式下,需要在测试步骤完成后手动将缓存写入文件。可以通过 fixture 提供的 agentForPage 方法获取底层 agent,然后在需要持久化的时刻调用 agent.flushCache():
test.afterEach(async ({ page, agentForPage }, testInfo) => {
// Only flush cache if the test passed
if (testInfo.status === 'passed') {
console.log('Test passed, flushing Midscene cache...');
const agent = await agentForPage(page);
await agent.flushCache();
} else {
console.log(`Test ${testInfo.status}, skipping Midscene cache flush.`);
}
});
test('manual cache flush', async ({ agentForPage, page, aiTap, aiWaitFor }) => {
const agent = await agentForPage(page);
await aiTap('first highlighted link in the hero section');
await aiWaitFor('the detail page loads completely');
await agent.flushCache();
});
只写模式
// 对应样例代码中的 fixture.ts
export const test = base.extend<PlayWrightAiFixtureType>(
PlaywrightAiFixture({
cache: { strategy: "write-only", id: "write-only-cache" },
}),
);
在只写模式下,每次测试都会调用 AI 模型,并将结果自动写入缓存文件,不会读取已有缓存。
缓存清理
Midscene 支持在写入缓存时清理未使用的缓存记录,确保缓存文件保持精简。这个功能是完全手动的,需要显式调用 agent.flushCache({ cleanUnused: true })。
手动清理机制
当调用 agent.flushCache({ cleanUnused: true }) 时,系统会:
- 保留使用过的缓存:本次运行中被匹配和使用的缓存记录会被保留
- 保留新增的缓存:本次运行中新生成的缓存记录会被保留
- 删除未使用的缓存:旧的、未被使用的缓存记录会被自动删除
- 写入文件:清理后的缓存会被写入 文件
使用方式
在测试的 afterEach 中统一调用:
describe('test suite', () => {
let resetFn: () => Promise<void>;
let agent: PuppeteerAgent;
afterEach(async () => {
// 清理缓存并写入文件
if (agent) {
await agent.flushCache({ cleanUnused: true });
}
// 再关闭页面
if (resetFn) {
await resetFn();
}
});
it('test case', async () => {
const { originPage, reset } = await launchPage('https://example.com/');
resetFn = reset;
agent = new PuppeteerAgent(originPage, {
cache: { id: 'my-cache-id' },
});
// ... test logic
});
});
Playwright AI Fixture 用户:
test.afterEach(async ({ page, agentForPage }) => {
const agent = await agentForPage(page);
await agent.flushCache({ cleanUnused: true });
});
清理行为说明
- read-write 模式:调用
flushCache({ cleanUnused: true }) 会清理并写入文件
- read-only 模式:调用
flushCache({ cleanUnused: true }) 也会清理并写入文件(手动 flush 覆盖 read-only 限制)
- write-only 模式:不执行清理(因为不读取缓存)
注意:如果不传 cleanUnused: true 参数,flushCache() 只会写入文件而不会清理未使用的缓存。
FAQ
没有生成缓存文件
请确认你已正确配置缓存: