Gemini API 时间戳精度修复:如何解决 web_search 的 400 错误
——
Gemini API 时间戳精度修复:如何解决 web_search 的 400 错误
OpenClaw 最新更新解决了 Gemini API 中 google_search.time_range_filter 因毫秒级时间戳导致的 400 错误,该问题自 2026.5.19 版本起影响所有使用 freshness 参数的实时搜索调用。本文详解故障根因、修复方案及开发者应对策略。
—
问题背景:为什么你的 AI 搜索突然报错?
自 OpenClaw 2026.5.19 版本发布以来,部分开发者反馈 Gemini API 的 web_search 工具在启用 freshness(时效性)过滤时频繁返回 400 错误:
[FIELD_INVALID] Granularity of nano is not supported
矛盾的是,该错误仅出现在生产环境,测试环境却完全正常。经过深入排查,团队发现问题根源在于 JavaScript 时间戳的亚秒精度处理。
核心矛盾点
| 场景 | 时间戳格式 | Gemini 响应 |
|:—|:—|:—|
| 测试环境(固定时间) | 2026-04-15T12:00:00.000Z | ✅ 正常 |
| 生产环境(实时时间) | 2026-04-15T12:00:00.123Z | ❌ 400 错误 |
根本原因:Gemini 的 google_search.time_range_filter 端点对 google.protobuf.Timestamp 类型的限制比官方规范更严格——拒绝任何非零的分数秒,即使底层类型理论上支持 3/6/9 位小数精度。
—
技术深潜:时间戳精度陷阱
JavaScript 的 toISOString() 行为
JavaScript 的 Date.prototype.toISOString() 始终输出毫秒级精度(3 位小数),这是语言规范决定的:
const now = new Date();
console.log(now.toISOString());
// 输出: "2026-06-15T08:30:45.789Z" ← 总是带 .xxxZ
// 即使是整秒时刻,也是 .000Z 而非无小数
const exact = new Date("2026-01-01T00:00:00Z");
console.log(exact.toISOString());
// 输出: "2026-01-01T00:00:00.000Z"
Gemini API 的实际限制
通过实测验证,Gemini 的 time_range_filter 仅接受以下两种格式:
| 格式 | 示例 | 结果 |
|:—|:—|:—|
| 无分数秒 | 2026-06-15T08:30:45Z | ✅ 通过 |
| 全零毫秒 | 2026-06-15T08:30:45.000Z | ✅ 通过 |
| 非零毫秒 | 2026-06-15T08:30:45.123Z | ❌ 400 错误 |
—
修复方案:toGeminiTimeRangeTimestamp() 实现
OpenClaw 团队引入了专用工具函数,统一处理所有时间范围过滤器的时间戳序列化:
/**
* 将 Date 转换为 Gemini 兼容的时间戳字符串
* 关键:移除所有分数秒精度,仅保留秒级精度
*
* @param {Date} date - 输入日期
* @returns {string} - ISO 8601 格式,无分数秒(如 "2026-06-15T08:30:45Z")
*/
function toGeminiTimeRangeTimestamp(date) {
// 创建副本避免修改原对象
const d = new Date(date);
// 关键步骤:将毫秒设为 0,然后使用 toISOString()
d.setMilliseconds(0);
// 替换 ".000Z" 为 "Z",确保完全无分数秒表示
return d.toISOString().replace('.000Z', 'Z');
}
// 使用示例
const freshnessStart = toGeminiTimeRangeTimestamp(new Date());
// 输出: "2026-06-15T08:30:45Z" (无 .000Z)
const dateAfter = toGeminiTimeRangeTimestamp(new Date("2026-01-01"));
// 输出: "2026-01-01T00:00:00Z"
修复覆盖的四个关键位置
该函数被应用于所有 timeRangeFilter 时间戳生成点:
1. freshness 参数的起始时间(startTime)
2. date_after 过滤的起始时间
3. date_before 过滤的结束时间(含 “now” 回退逻辑)
4. isoDateExclusiveEnd 生成的结束时间(虽本身为 .000Z,统一处理以增强鲁棒性)
—
测试策略:为什么 CI 没能提前捕获?
原始测试的盲点
// ❌ 问题测试代码(修复前)
vi.setSystemTime(new Date("2026-04-15T12:00:00Z"));
// toISOString() → "2026-04-15T12:00:00.000Z"
// Gemini 接受 .000Z,测试通过,但生产环境失败
关键问题:固定时间字符串 "2026-04-15T12:00:00Z" 被解析后,毫秒恰好为 0,导致 toISOString() 输出 .000Z——这是 Gemini 唯一接受的分数秒形式。
修复后的真实场景测试
// ✅ 修正后的测试代码
vi.setSystemTime(new Date("2026-04-15T12:00:00.123Z"));
// toISOString() → "2026-04-15T12:00:00.123Z"
// 触发真实的 400 错误场景,验证修复有效性
—
开发者实践指南
如果你直接调用 Gemini API
若你的项目直接构造 time_range_filter,务必确保时间戳格式:
// ❌ 错误:直接使用 toISOString()
const filter = {
startTime: new Date().toISOString(), // "2026-...T12:00:00.123Z" → 400 错误
endTime: "2026-12-31T23:59:59Z"
};
// ✅ 正确:移除分数秒
function toGeminiTimestamp(date) {
return date.toISOString().split('.')[0] + 'Z';
}
const filter = {
startTime: toGeminiTimestamp(new Date()), // "2026-...T12:00:00Z"
endTime: "2026-12-31T23:59:59Z"
};
OpenClaw 用户无需操作
已升级至 OpenClaw 最新版本 的用户,所有 Gemini web_search 调用已自动应用修复。可通过以下命令验证版本:
检查 OpenClaw 版本
openclaw --version
建议升级到最新版
npm update -g @openclaw/cli
或
pip install --upgrade openclaw
—
FAQ:常见问题解答
Q1: 这个 bug 会影响哪些 OpenClaw 功能?
A: 主要影响使用 Gemini 模型 且启用 web_search 工具的 AI Agent,特别是配置了 freshness 时效性过滤或 date_after/date_before 时间范围过滤的场景。其他模型(如 GPT-4、Claude)不受影响。
Q2: 为什么 Gemini 的限制与 protobuf 规范不一致?
A: google.protobuf.Timestamp 官方规范允许 0/3/6/9 位小数精度,但 Gemini 的 grounding 服务端 实施了更严格的校验策略。这是服务端实现细节,非协议层面问题。建议开发者始终遵循”无分数秒”的最小公分母策略。
Q3: 如何验证我的时间戳格式是否正确?
A: 使用以下快速检测方法:
function isGeminiCompatible(isoString) {
// 正确格式:以 Z 结尾,不含小数点
return isoString.endsWith('Z') && !isoString.includes('.');
}
// 测试
console.log(isGeminiCompatible("2026-06-15T08:30:45Z")); // true
console.log(isGeminiCompatible("2026-06-15T08:30:45.000Z")); // false(虽 Gemini 接受,但不建议)
console.log(isGeminiCompatible("2026-06-15T08:30:45.123Z")); // false
Q4: 这个修复是否向后兼容?
A: 完全兼容。.000Z 和 Z 两种格式均被 Gemini 接受,修复仅将前者统一转换为后者,不改变语义,仅增强兼容性。
Q5: 除 Gemini 外,其他 Google API 是否有类似限制?
A: 经测试,Vertex AI 的部分时间戳字段也存在类似限制。建议对所有 Google Cloud API 的时间戳参数采用相同的”无分数秒”处理策略,除非文档明确说明支持更高精度。
—
总结与下一步
本次 OpenClaw 更新解决了 Gemini API web_search 因时间戳精度导致的 400 错误,核心要点:
| 要点 | 说明 |
|:—|:—|
| 根因 | Gemini time_range_filter 拒绝非零分数秒 |
| 修复 | 引入 toGeminiTimeRangeTimestamp() 统一处理 |
| 影响 | 2026.5.19 后所有 freshness 调用 |
| 行动 | 升级 OpenClaw 即可,无需代码改动 |
推荐下一步:
- 升级至 OpenClaw 最新版本 获取自动修复
- 查阅 Gemini API 官方文档 了解
google_search工具完整配置 - 关注 OpenClaw 更新日志 获取实时功能更新
—
相关阅读
—