Skip to content

✨ OpenClaw 最佳实践

来自真实项目的经验总结

适用版本: OpenClaw 2026.2+
最后更新: 2026-03-11


📋 目录

  1. 配置优化
  2. 性能优化
  3. 安全实践
  4. 部署建议
  5. 监控运维
  6. 常见问题

🔧 配置优化

模型选择策略

不同的任务适合不同的模型,合理选择可以平衡效果和成本。

场景推荐表

场景推荐模型原因成本
日常对话qwen2.5:7b响应快、成本低💰
复杂推理qwen3.5-plus推理能力强💰💰💰
代码生成qwen3-coder-plus代码专项优化💰💰💰
长文档分析qwen3-max256K 上下文💰💰💰💰
批量处理ollama 本地无 API 成本💰
多模态qwen3.5-plus支持图像输入💰💰💰

动态模型选择

在技能中实现智能路由:

javascript
// skills/smart-router.js
export async function route(task) {
  const config = {
    simple: 'ollama/qwen2.5:7b',      // 简单任务
    normal: 'bailian/qwen3.5-plus',   // 一般任务
    complex: 'bailian/qwen3-max',     // 复杂任务
    code: 'bailian/qwen3-coder-plus', // 代码任务
  };
  
  // 根据任务特征选择
  if (task.type === 'code') return config.code;
  if (task.tokens > 50000) return config.complex;
  if (task.priority === 'low') return config.simple;
  return config.normal;
}

记忆管理

记忆分类

memory/
├── MEMORY.md              # 长期记忆( curated )
├── memory/
│   ├── 2026-03-11.md     # 每日日志(raw)
│   ├── 2026-03-10.md
│   └── ...
└── tools.md               # 工具配置

记忆维护策略

每日:

  • 自动创建当日记忆文件
  • 记录重要对话和决策

每周:

  • 回顾本周记忆文件
  • 提炼重要内容到 MEMORY.md
  • 删除过期的临时记忆

每月:

  • 清理旧的记忆文件(保留最近 30 天)
  • 更新用户偏好和上下文
  • 归档项目相关记忆

记忆优化技巧

markdown
## ✅ 好的记忆条目

- 用户偏好: "喜欢简洁的回答,不需要过多解释"
- 项目上下文: "正在开发 AI 知识库网站,使用 VitePress"
- 重要决策: "决定使用飞书 API 直接发送文件"
- 技能配置: "TTS 默认使用 Nova 声音"

## ❌ 避免的记忆内容

- 临时信息: "用户问今天天气如何"(无需记录)
- 敏感数据:密码、密钥、个人信息
- 冗余内容:已经存在于配置文件的信息

工具调用优化

超时设置

json
{
  "tools": {
    "web_search": {
      "timeout": 10000,
      "retry": 2
    },
    "browser": {
      "timeout": 30000,
      "retry": 1
    },
    "exec": {
      "timeout": 60000,
      "yieldMs": 5000
    }
  }
}

错误重试策略

javascript
async function callWithRetry(tool, params, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await tool(params);
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      
      // 指数退避
      const delay = Math.pow(2, i) * 1000;
      console.log(`重试 ${i+1}/${maxRetries}, 等待 ${delay}ms`);
      await sleep(delay);
    }
  }
}

结果缓存

javascript
// 简单缓存实现
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 分钟

async function cachedSearch(query) {
  const key = `search:${query}`;
  const cached = cache.get(key);
  
  if (cached && Date.now() - cached.time < CACHE_TTL) {
    console.log('缓存命中');
    return cached.data;
  }
  
  const result = await web_search({ query });
  cache.set(key, { data: result, time: Date.now() });
  return result;
}

⚡ 性能优化

响应速度优化

并行调用

当任务可以拆分时,并行执行:

javascript
// ❌ 串行执行(慢)
const research = await web_search({ query: 'AI 趋势' });
const news = await web_search({ query: 'AI 新闻' });
const papers = await web_search({ query: 'AI 论文' });

// ✅ 并行执行(快)
const [research, news, papers] = await Promise.all([
  web_search({ query: 'AI 趋势' }),
  web_search({ query: 'AI 新闻' }),
  web_search({ query: 'AI 论文' }),
]);

流式输出

对于长内容,使用流式输出提升用户体验:

javascript
// 配置中启用流式
{
  "model": {
    "stream": true,
    "streamOptions": {
      "chunkSize": 100,
      "delayMs": 50
    }
  }
}

结果预加载

预测用户可能的下一步操作,提前加载:

javascript
// 用户询问天气后,可能想知道:
// 1. 未来几天预报
// 2. 穿衣建议
// 3. 出行建议

// 提前并行获取
const [current, forecast, suggestions] = await Promise.all([
  getWeather(location),
  getForecast(location, 7),
  generateSuggestions(weather),
]);

成本控制

Token 统计

javascript
// 技能中添加 token 统计
let tokenUsage = { input: 0, output: 0 };

export async function run(params) {
  const start = Date.now();
  const result = await callModel(params);
  
  tokenUsage.input += result.usage.input_tokens;
  tokenUsage.output += result.usage.output_tokens;
  
  console.log(`本次消耗:${result.usage.total_tokens} tokens`);
  console.log(`累计消耗:${tokenUsage.input + tokenUsage.output} tokens`);
  
  return result;
}

使用限额

javascript
// 每日限额检查
const DAILY_LIMIT = 100000; // tokens
let dailyUsage = 0;

function checkLimit(tokens) {
  if (dailyUsage + tokens > DAILY_LIMIT) {
    throw new Error('已达到每日 token 限额');
  }
  dailyUsage += tokens;
}

// 重置逻辑(每天零点)
function resetDaily() {
  const now = new Date();
  if (now.getHours() === 0 && now.getMinutes() === 0) {
    dailyUsage = 0;
  }
}

优化提示词

减少不必要的 token 消耗:

markdown
## ❌ 冗长的提示词

你好,AI 助手。我是一位软件工程师,目前正在开发一个网站项目。
我遇到了一个问题,就是不知道如何优化网站的加载速度。
我知道这个问题可能有很多方面,包括图片优化、代码压缩、CDN 使用等等。
但是我不太确定具体应该从哪里入手,也不知道哪些方法最有效。
你能不能帮我分析一下,给我一些建议和最佳实践?
最好是能够按照优先级排序,让我知道应该先做什么后做什么。
谢谢!

## ✅ 简洁的提示词

网站性能优化建议:
- 场景:VitePress 静态网站
- 目标:首屏加载 < 2s
- 要求:按优先级排序,给出具体方案

稳定性保障

异常处理

javascript
export async function run(params) {
  try {
    // 参数验证
    if (!params.query) {
      throw new Error('缺少必要参数:query');
    }
    
    // 主逻辑
    const result = await execute(params);
    
    // 结果验证
    if (!result || result.length === 0) {
      return { success: false, message: '未找到结果' };
    }
    
    return { success: true, data: result };
    
  } catch (error) {
    console.error('执行失败:', error);
    
    // 友好错误信息
    return {
      success: false,
      message: `处理失败:${error.message}`,
      suggestion: '请稍后重试或检查输入参数'
    };
  }
}

降级方案

javascript
// 多级降级策略
async function searchWithFallback(query) {
  const strategies = [
    () => web_search({ query, freshness: 'pd' }),  // 优先:最新结果
    () => web_search({ query }),                    // 备选:普通搜索
    () => memory_search({ query }),                 // 降级:本地记忆
    () => ({ results: [], message: '暂无相关信息' }) // 保底:友好提示
  ];
  
  for (const strategy of strategies) {
    try {
      const result = await strategy();
      if (result.results && result.results.length > 0) {
        return result;
      }
    } catch (error) {
      console.log('策略失败,尝试下一级');
    }
  }
}

监控告警

javascript
// 简单监控
const metrics = {
  calls: 0,
  errors: 0,
  latency: [],
};

function recordCall(latency, success) {
  metrics.calls++;
  metrics.latency.push(latency);
  if (!success) metrics.errors++;
  
  // 错误率告警
  const errorRate = metrics.errors / metrics.calls;
  if (errorRate > 0.1) {
    console.warn(`⚠️ 错误率过高:${(errorRate * 100).toFixed(1)}%`);
  }
  
  // 延迟告警
  const avgLatency = metrics.latency.reduce((a, b) => a + b) / metrics.latency.length;
  if (avgLatency > 5000) {
    console.warn(`⚠️ 平均延迟过高:${avgLatency.toFixed(0)}ms`);
  }
}

🔒 安全实践

数据安全

敏感信息脱敏

javascript
// 日志脱敏
function sanitizeLog(data) {
  const sensitive = ['password', 'secret', 'token', 'key', 'auth'];
  const sanitized = { ...data };
  
  for (const key of Object.keys(sanitized)) {
    if (sensitive.some(s => key.toLowerCase().includes(s))) {
      sanitized[key] = '***REDACTED***';
    }
  }
  
  return sanitized;
}

// 使用
console.log('处理数据:', sanitizeLog(userData));

本地存储加密

javascript
const crypto = require('crypto');

function encrypt(text, key) {
  const cipher = crypto.createCipher('aes-256-cbc', key);
  let encrypted = cipher.update(text, 'utf8', 'hex');
  encrypted += cipher.final('hex');
  return encrypted;
}

function decrypt(encrypted, key) {
  const decipher = crypto.createDecipher('aes-256-cbc', key);
  let decrypted = decipher.update(encrypted, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
  return decrypted;
}

// 存储敏感配置
const encryptedConfig = encrypt(JSON.stringify(config), process.env.ENCRYPTION_KEY);
fs.writeFileSync('config.enc', encryptedConfig);

访问权限控制

javascript
// 命令白名单
const ALLOWED_COMMANDS = [
  'ls', 'cat', 'grep', 'find',
  'npm', 'node', 'git',
  // ... 其他安全命令
];

const DENIED_COMMANDS = [
  'rm -rf', 'sudo', 'chmod', 'chown',
  'dd', 'mkfs', 'fdisk',
  // ... 危险命令
];

function validateCommand(cmd) {
  // 检查黑名单
  for (const denied of DENIED_COMMANDS) {
    if (cmd.includes(denied)) {
      throw new Error(`禁止执行命令:${denied}`);
    }
  }
  
  // 检查白名单(如果启用)
  const baseCmd = cmd.split(' ')[0];
  if (!ALLOWED_COMMANDS.includes(baseCmd)) {
    throw new Error(`命令未在白名单中:${baseCmd}`);
  }
  
  return true;
}

使用安全

操作确认

javascript
// 危险操作需要确认
const DANGEROUS_ACTIONS = ['delete', 'remove', 'drop', 'truncate'];

async function executeAction(action, params) {
  const isDangerous = DANGEROUS_ACTIONS.some(d => action.includes(d));
  
  if (isDangerous) {
    const confirmed = await askUser(
      `⚠️ 确认执行危险操作:${action}\n` +
      `影响范围:${params.scope}\n` +
      `确定要继续吗?(yes/no)`
    );
    
    if (confirmed !== 'yes') {
      throw new Error('用户取消操作');
    }
  }
  
  return await performAction(action, params);
}

审计日志

javascript
// 记录所有操作
function logAudit(action, params, result, user) {
  const entry = {
    timestamp: new Date().toISOString(),
    user: user.id,
    action,
    params: sanitizeLog(params),
    result: result.success ? 'success' : 'failure',
    duration: result.duration,
  };
  
  // 追加到审计日志文件
  fs.appendFileSync(
    'audit.log',
    JSON.stringify(entry) + '\n'
  );
}

// 定期归档
function archiveLogs() {
  const thirtyDaysAgo = new Date();
  thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
  
  // 移动旧日志到归档目录
  // ...
}

🚀 部署建议

开发环境

本地运行配置

json
{
  "dev": {
    "debug": true,
    "hotReload": true,
    "logLevel": "debug",
    "mockExternal": false
  }
}

调试技巧

javascript
// 启用详细日志
process.env.DEBUG = 'openclaw:*';

// 使用调试模式启动
openclaw start --debug

// 查看实时日志
openclaw logs --follow

生产环境

容器部署

dockerfile
FROM node:20-alpine

WORKDIR /app

# 安装依赖
COPY package*.json ./
RUN npm ci --only=production

# 复制代码
COPY . .

# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
USER nodejs

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget -q --spider http://localhost:18789/health || exit 1

CMD ["node", "server.js"]

负载均衡

yaml
# docker-compose.yml
version: '3'
services:
  openclaw-1:
    image: openclaw:latest
    ports:
      - "18789:18789"
    environment:
      - INSTANCE_ID=1
  
  openclaw-2:
    image: openclaw:latest
    ports:
      - "18790:18789"
    environment:
      - INSTANCE_ID=2
  
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf

自动扩展

yaml
# Kubernetes HPA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: openclaw-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: openclaw
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

监控运维

日志收集

javascript
// 结构化日志
const logger = {
  info: (msg, data) => {
    console.log(JSON.stringify({
      level: 'info',
      timestamp: new Date().toISOString(),
      message: msg,
      ...data
    }));
  },
  
  error: (msg, data) => {
    console.error(JSON.stringify({
      level: 'error',
      timestamp: new Date().toISOString(),
      message: msg,
      ...data
    }));
  },
  
  warn: (msg, data) => {
    console.warn(JSON.stringify({
      level: 'warn',
      timestamp: new Date().toISOString(),
      message: msg,
      ...data
    }));
  },
};

指标监控

javascript
// Prometheus 指标
const promClient = require('prom-client');

const httpRequestDuration = new promClient.Histogram({
  name: 'http_request_duration_seconds',
  help: 'Duration of HTTP requests in seconds',
  labelNames: ['method', 'route', 'status_code'],
  buckets: [0.1, 0.5, 1, 2, 5, 10]
});

const activeSessions = new promClient.Gauge({
  name: 'active_sessions',
  help: 'Number of active sessions'
});

// 暴露指标端点
app.get('/metrics', async (req, res) => {
  res.set('Content-Type', promClient.register.contentType);
  res.end(await promClient.register.metrics());
});

告警通知

javascript
// 告警配置
const alerts = {
  errorRate: {
    threshold: 0.1,
    window: '5m',
    action: 'notify'
  },
  latency: {
    threshold: 5000,
    window: '1m',
    action: 'notify'
  },
  diskUsage: {
    threshold: 0.8,
    window: '1h',
    action: 'notify'
  }
};

// 告警通知
async function sendAlert(type, value, threshold) {
  const message = `⚠️ 告警:${type} 超出阈值\n` +
    `当前值:${value}\n` +
    `阈值:${threshold}\n` +
    `时间:${new Date().toISOString()}`;
  
  // 发送到飞书/钉钉/Slack
  await notify(message);
}

❓ 常见问题

Q1: 如何选择合适的模型?

A: 根据任务复杂度选择:

  • 简单任务(问候、查询)→ 轻量模型
  • 中等任务(写作、分析)→ 标准模型
  • 复杂任务(推理、代码)→ 强模型

Q2: 记忆文件太大怎么办?

A:

  1. 定期清理旧文件(保留 30 天)
  2. 提炼重要内容到 MEMORY.md
  3. 压缩归档历史文件

Q3: 如何降低 API 成本?

A:

  1. 使用本地模型处理简单任务
  2. 优化提示词减少 token
  3. 缓存重复查询结果
  4. 设置使用限额

Q4: 技能开发的最佳实践?

A:

  1. 单一职责:每个技能只做一件事
  2. 错误处理:优雅处理异常
  3. 文档完整:清晰的使用说明
  4. 测试覆盖:单元测试 + 集成测试

Q5: 如何调试技能问题?

A:

  1. 启用 debug 日志
  2. 查看技能执行记录
  3. 使用单步调试
  4. 检查输入输出格式

📚 延伸阅读


➡️ 下一步


💬 评论讨论

⚠️ Giscus 尚未配置

请在 .vitepress/config.ts 中配置 repoIdcategoryId

配置指南:giscus.app/zh-CN

Released under the MIT License.