本质原因:每分钟调用一次/open-apis/bot/v3/info接口,24小时调用1440次,导致飞书API额度消耗殆尽
飞书API调用次数耗尽
根据飞书开放平台文档,企业自建应用API额度1W/月,每月1日重置
官方文档地址: https://open.feishu.cn/document/platform-notices/platform-updates-/custom-app-api-call-limit
原因
OpenClaw Gateway
↓ 每分钟健康检查
调用插件的 status.probeAccount()
↓ (在 channel.ts 中定义)
probeAccount() { return await probeFeishu(cfg) }
↓ (在 probe.ts 中定义)
probeFeishu() {
// 没有缓存 → 调用飞书 API /open-apis/bot/v3/info
}
↓
HTTP 请求到飞书服务器
排查你的情况
如下图所示
处理办法
- 推荐做法:修改.openclaw/extensions/feishu/src/probe.ts增加缓存
- 再次查看你飞书后台日志检索,查看是否频繁调用/open-apis/bot/v3/info
import type { FeishuConfig, FeishuProbeResult } from "./types.js";
import { createFeishuClient } from "./client.js";
import { resolveFeishuCredentials } from "./accounts.js";
// Cache probe results to avoid hitting API rate limits
// Cache for 24 hours (86400 seconds)
const PROBE_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
const probeCache = new Map();
function getCacheKey(cfg?: FeishuConfig): string {
if (!cfg?.appId) return "no-creds";
return `${cfg.appId}:${cfg.domain ?? "feishu"}`;
}
export async function probeFeishu(cfg?: FeishuConfig): Promise {
const creds = resolveFeishuCredentials(cfg);
if (!creds) {
return {
ok: false,
error: "missing credentials (appId, appSecret)",
};
}
// Check cache first
const cacheKey = getCacheKey(cfg);
const cached = probeCache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < PROBE_CACHE_TTL_MS) {
return cached.result;
}
try {
const client = createFeishuClient(cfg!);
// Use im.chat.list as a simple connectivity test
// The bot info API path varies by SDK version
const response = await (client as any).request({
method: "GET",
url: "/open-apis/bot/v3/info",
data: {},
});
if (response.code !== 0) {
const result = {
ok: false,
appId: creds.appId,
error: `API error: ${response.msg || `code ${response.code}`}`,
};
probeCache.set(cacheKey, { result, timestamp: Date.now() });
return result;
}
const bot = response.bot || response.data?.bot;
const result = {
ok: true,
appId: creds.appId,
botName: bot?.bot_name,
botOpenId: bot?.open_id,
};
probeCache.set(cacheKey, { result, timestamp: Date.now() });
return result;
} catch (err) {
const result = {
ok: false,
appId: creds.appId,
error: err instanceof Error ? err.message : String(err),
};
probeCache.set(cacheKey, { result, timestamp: Date.now() });
return result;
}
}
// Clear the probe cache (useful for testing or when credentials change)
export function clearProbeCache(): void {
probeCache.clear();
}
// Export for testing
export { PROBE_CACHE_TTL_MS };