💾 OpenClaw 工具结果缓存

同一个问题问了三遍,API费用翻了三倍。我看着账单上的数字,突然明白了一个道理:AI不会偷懒,但我们可以教它。

为什么需要缓存

场景:你的Agent每天要回答"OpenClaw怎么安装"这个问题100次。

缓存不只是省钱,还有:

缓存类型

1. 精确缓存(Exact Cache)

输入完全相同,返回缓存结果。最简单,命中率可能不高。

// 精确缓存
const cache = new Map();

async function cachedToolCall(toolName, args) {
  const key = `${toolName}:${JSON.stringify(args)}`;
  
  if (cache.has(key)) {
    console.log('缓存命中!');
    return cache.get(key);
  }
  
  const result = await executeTool(toolName, args);
  cache.set(key, result);
  return result;
}

2. 语义缓存(Semantic Cache)

输入语义相似,返回缓存结果。比如"今天天气"和"现在天气怎样"视为相同。

// 语义缓存 - 使用embedding相似度
import { getEmbedding } from './embedding';

const semanticCache = [];

async function semanticCachedCall(query, threshold = 0.95) {
  const queryEmbedding = await getEmbedding(query);
  
  // 查找相似查询
  for (const cached of semanticCache) {
    const similarity = cosineSimilarity(queryEmbedding, cached.embedding);
    if (similarity > threshold) {
      console.log(`语义缓存命中!相似度: ${similarity}`);
      return cached.result;
    }
  }
  
  // 未命中,执行并缓存
  const result = await executeQuery(query);
  semanticCache.push({ embedding: queryEmbedding, result });
  return result;
}

3. TTL缓存(Time-based Cache)

缓存有时效性。天气数据缓存1小时,股票数据缓存1分钟。

// TTL缓存
class TTLCache {
  constructor(defaultTTL = 3600000) {  // 默认1小时
    this.cache = new Map();
    this.defaultTTL = defaultTTL;
  }
  
  set(key, value, ttl = this.defaultTTL) {
    this.cache.set(key, {
      value,
      expiresAt: Date.now() + ttl
    });
  }
  
  get(key) {
    const item = this.cache.get(key);
    if (!item) return null;
    
    if (Date.now() > item.expiresAt) {
      this.cache.delete(key);
      return null;  // 已过期
    }
    
    return item.value;
  }
}

OpenClaw 缓存配置

全局缓存配置

# openclaw.yaml
cache:
  enabled: true
  backend: redis  # memory | redis | file
  default_ttl: 3600  # 秒
  
  redis:
    host: localhost
    port: 6379
    prefix: 'openclaw:cache:'
    
  rules:
    # 工具特定缓存规则
    - tool: 'web_search'
      ttl: 1800  # 30分钟
      key_pattern: '${args.query}'
      
    - tool: 'weather_api'
      ttl: 3600  # 1小时
      key_pattern: '${args.location}:${args.date}'
      
    - tool: 'stock_price'
      ttl: 60  # 1分钟
      key_pattern: '${args.symbol}'

Skill级缓存

# skills/weather.yaml
name: weather
description: 获取天气信息

cache:
  enabled: true
  ttl: 3600
  key: '${location}:${date}'  # 缓存键模板
  
  invalidate_on:
    - time: '06:00'  # 每天6点失效
    - event: 'location_change'

缓存策略

LRU(最近最少使用)

缓存满了,踢掉最久没用的。适合内存有限的场景。

// LRU缓存实现
class LRUCache {
  constructor(maxSize = 1000) {
    this.maxSize = maxSize;
    this.cache = new Map();
  }
  
  get(key) {
    if (!this.cache.has(key)) return null;
    
    // 访问时移到末尾(最近使用)
    const value = this.cache.get(key);
    this.cache.delete(key);
    this.cache.set(key, value);
    return value;
  }
  
  set(key, value) {
    if (this.cache.has(key)) {
      this.cache.delete(key);
    } else if (this.cache.size >= this.maxSize) {
      // 删除最久未使用的(第一个)
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }
    this.cache.set(key, value);
  }
}

写穿透(Write-Through)

更新数据时同时更新缓存。保证缓存和源数据一致。

写回(Write-Back)

先更新缓存,异步更新源数据。更快,但有数据丢失风险。

缓存失效

主动失效

// 事件驱动的缓存失效
eventBus.on('data_updated', (dataType) => {
  cache.invalidatePattern(`${dataType}:*`);
});

// 示例:用户更新了配置
eventBus.emit('data_updated', 'user_config');

被动失效

// TTL + 惰性删除
async function getWithInvalidation(key) {
  const cached = await cache.get(key);
  
  if (cached && isStale(cached)) {
    // 后台异步刷新
    refreshCache(key).catch(console.error);
    // 先返回旧数据,不阻塞
    return cached.value;
  }
  
  return cached?.value || fetchFresh(key);
}

缓存监控

// 缓存统计
const cacheStats = {
  hits: 0,
  misses: 0,
  evictions: 0
};

function getCacheStats() {
  const hitRate = cacheStats.hits / (cacheStats.hits + cacheStats.misses);
  return {
    ...cacheStats,
    hitRate: `${(hitRate * 100).toFixed(2)}%`
  };
}

// 输出:{ hits: 850, misses: 150, evictions: 20, hitRate: '85.00%' }

最佳实践

费用节省案例

妙趣AI每日查询统计:

查询类型每日次数单次成本无缓存成本有缓存成本节省
天气查询500$0.001$0.50$0.0296%
翻译1000$0.002$2.00$0.2090%
知识问答2000$0.005$10.00$1.0090%

最后更新:2026-04-29 | 作者:妙趣AI