1. OpenClaw Agent 为什么需要 Google AI Mode 实时搜索能力
如果你正在用 OpenClaw 构建 Agent,并且希望它能回答「今天有什么新变化」「这个库最新版本怎么用」这类需要实时信息的问题,你会发现一个很尴尬的现实:Agent 的推理能力很强,但它对世界的认知停留在训练数据截止的那一天。OpenClaw Agent 本身是一个编排框架,它能把工具调用、多轮对话、技能注册串起来,但「实时搜索」这个能力需要外部数据源来补。
Google AI Mode 是 Google 搜索在 AI 摘要方向上的产品形态,它会在搜索结果页顶部动态生成一段由模型推理产出的摘要内容,并附带引用来源。对 Agent 来说,这段摘要比传统十条蓝色链接更有价值——它是已经过一轮信息整合的结构化文本,可以直接塞进上下文让 Agent 继续推理。问题在于,这段内容不在静态 HTML 里,普通 HTTP 请求拿到的页面根本没有它,无头浏览器也要面对渲染时序和反检测的双重麻烦。
我试过直接用 requests 抓udm=50参数的页面,返回的 HTML 里搜不到任何摘要文本,因为内容是页面加载后由 JavaScript 动态注入的。换成无头浏览器,又要处理等待策略、指纹轮换、住宅 IP 池这一整套基础设施,维护成本远超一个搜索技能本身该有的复杂度。
所以这篇要解决的问题很具体:让 OpenClaw Agent 通过一条统一的 API 通道,稳定拿到 Google AI Mode 的摘要内容和引用来源,并且把这条通道封装成一个可注册、可复用、可批量调用的 Agent 技能。整条链路走 TaoToken 的统一 Key 和 API 通道,你不需要在 Agent 里维护多套鉴权逻辑,一个 Base URL 加一个 Key 就能把搜索能力接进来。
适合谁看:已经在用 OpenClaw 搭 Agent、需要给 Agent 加实时搜索技能的开发者;或者你还没开始搭,但想先跑通一条「Agent 调用外部搜索 API 并消费结构化结果」的最小闭环。下面从环境准备开始,每一步都给可复制的配置和命令。
2. TaoToken 统一通道前置准备与 Key 获取
在写任何 Agent 技能代码之前,先把通道打通。TaoToken 在这里扮演的角色是统一入口:你的 OpenClaw Agent 不需要分别对接搜索服务、模型服务、编码服务,而是通过同一个 Base URL 和同一个 Key 去访问。这样做的好处是 Agent 的配置层只需要维护一份鉴权信息,技能注册时引用同一个环境变量即可。
第一步是拿到 API Key。访问控制台页面创建密钥:
https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=openclaw_google_ai_mode&utm_campaign=rewrite创建完成后你会得到一串以sk-开头的 Key。把它写进环境变量,不要硬编码在技能代码里:
export TAOTOKEN_API_KEY="sk-你的实际密钥"验证环境变量是否生效:
echo $TAOTOKEN_API_KEY如果输出的是你的 Key 而不是空行,说明设置成功。Windows 下用 PowerShell 的话是$env:TAOTOKEN_API_KEY="sk-...",设置完用echo $env:TAOTOKEN_API_KEY检查。
第二步是确认 Base URL。TaoToken 的 API 入口是:
https://taotoken.net/api注意这个地址不带任何查询参数,是纯粹的 API 根路径。你的 OpenClaw 技能在构造请求时,把具体的能力路径拼在这个根路径后面。比如搜索能力、模型对话能力,都是同一个根路径下的不同端点。
第三步是确认你要用的模型 ID。在 OpenClaw Agent 里,搜索技能负责取回实时数据,但 Agent 本身还需要一个模型来做推理和摘要整合。你可以在模型对话页面确认当前可用的模型标识:
https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=openclaw_google_ai_mode&utm_campaign=rewrite把这三个东西记下来:Base URL、API Key、Model ID。后面配置 OpenClaw 的 settings 文件时,这三件套会同时出现。如果你用的是 Claude Code 类的编码 Agent,配置逻辑是一样的,Base URL 填https://taotoken.net/api,Key 填环境变量引用,Model ID 填你选定的模型。
这里有个容易踩的坑:有人会把 Base URL 写成带/v1后缀的形式,结果请求 404。TaoToken 的根路径就是https://taotoken.net/api,具体版本路径由各能力端点自己定义,不要自己拼。另一个坑是 Key 复制时带了首尾空格,导致 401,创建后建议用echo检查一遍。
前置准备做完,你应该有:一个可用的 Key、一个确认过的 Base URL、一个选定的 Model ID。接下来进入 OpenClaw 的配置文件环节。
3. OpenClaw 技能注册与可复制配置片段
OpenClaw 的技能注册分两层:一层是 Agent 运行时的模型通道配置,一层是搜索技能本身的注册。先把模型通道配好,再挂搜索技能。
模型通道配置写在 OpenClaw 的 settings 文件里。如果你用的是 JSON 格式的配置,路径通常是项目根目录下的settings.json或config/settings.json,具体以你的 OpenClaw 版本为准。内容如下:
{ "model_providers": { "taotoken": { "base_url": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "models": { "default": "你的Model ID" } } }, "agent": { "default_provider": "taotoken", "default_model": "你的Model ID" } }如果你更习惯 TOML 格式,等价写法是:
[model_providers.taotoken] base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" [model_providers.taotoken.models] default = "你的Model ID" [agent] default_provider = "taotoken" default_model = "你的Model ID"注意api_key_env字段填的是环境变量名,不是 Key 本身。这样你的配置文件可以安全地提交到版本库,Key 留在本地环境变量里。这是三件套里的前两件:Base URL 和 Key 的引用方式。第三件 Model ID 填在models.default和agent.default_model两处。
接下来注册搜索技能。OpenClaw 的技能注册通常在config.yaml的skills字段下,每个技能声明名称、入口模块、触发描述和参数。搜索技能的注册片段:
skills: - name: google_ai_mode_search module: skills.google_ai_mode class: GoogleAIModeSkill description: "当用户需要实时信息、最新动态、事实核查时调用此技能,返回 Google AI Mode 摘要与引用来源" params: api_base: "https://taotoken.net/api" api_key_env: "TAOTOKEN_API_KEY" timeout: 30 max_follow_up: 5 triggers: - "最新" - "今天" - "实时" - "查一下" - "搜索"description字段很关键,Agent 靠它判断什么时候该调用这个技能。写得太窄,Agent 该搜的时候不搜;写得太宽,Agent 什么都去搜。上面这段描述把触发场景限定在「实时信息、最新动态、事实核查」三类,配合triggers里的关键词,基本能覆盖大多数需要联网的场景。
技能模块本身放在skills/google_ai_mode.py,核心是一个类,负责构造请求、解析响应、把结果格式化成 Agent 能消费的上下文。这个类的完整实现放在下一节,因为它同时承担了「验证请求」的职责。
配置写完后,用 OpenClaw 的配置校验命令检查一遍:
openclaw config validate如果输出config is valid或类似提示,说明 JSON/TOML/YAML 语法和字段引用都没问题。如果报unknown field或missing required field,对照上面的片段逐字段核对。常见错误是把api_key_env写成了api_key,或者base_url末尾多了斜杠。
到这里,三件套已经全部落到配置文件里:Base URL 在model_providers.taotoken.base_url和技能的api_base,Key 通过api_key_env引用环境变量,Model ID 在agent.default_model。下一步写技能实现并跑通一次真实搜索。
4. 搜索技能实现与一次请求的验证结果
技能类的职责很清晰:接收查询词,构造带udm=50参数的搜索 URL,通过 TaoToken 通道发出请求,解析返回的摘要内容和引用来源,最后格式化成 Agent 可读的文本。下面是一个可以直接用的实现,路径skills/google_ai_mode.py:
import os import time import requests from dataclasses import dataclass, field from urllib.parse import quote @dataclass class SearchResult: query: str has_ai_overview: bool ai_content: list = field(default_factory=list) references: list = field(default_factory=list) task_id: str = "" def to_agent_context(self) -> str: if not self.has_ai_overview: return f"查询 '{self.query}' 未返回 AI 摘要,可尝试换用更具体的信息型问法。" lines = [f"## Google AI Mode 摘要:{self.query}", ""] for i, text in enumerate(self.ai_content, 1): lines.append(f"{i}. {text}") if self.references: lines.append("") lines.append("### 引用来源") for ref in self.references: lines.append(f"- [{ref.get('domain', '')}] {ref.get('title', '')}: {ref.get('url', '')}") return "\n".join(lines) class GoogleAIModeSkill: def __init__(self, api_base: str = None, api_key_env: str = "TAOTOKEN_API_KEY", timeout: int = 30, max_follow_up: int = 5): self.api_base = (api_base or "https://taotoken.net/api").rstrip("/") self.api_key = os.environ.get(api_key_env, "") if not self.api_key: raise RuntimeError(f"环境变量 {api_key_env} 未设置") self.timeout = timeout self.max_follow_up = max_follow_up self._last_call = 0.0 def _rate_limit(self, min_interval: float = 0.5): elapsed = time.time() - self._last_call if elapsed < min_interval: time.sleep(min_interval - elapsed) self._last_call = time.time() def search(self, query: str, follow_up: list = None) -> SearchResult: self._rate_limit() search_url = f"https://www.google.com/search?num=10&udm=50&q={quote(query)}" payload = { "url": search_url, "parserName": "googleAISearch", "screenshot": False, } if follow_up: payload["param"] = follow_up[: self.max_follow_up] headers = { "Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}", } resp = requests.post( f"{self.api_base}/v2/scrape", headers=headers, json=payload, timeout=self.timeout, ) resp.raise_for_status() body = resp.json() if body.get("code") != 0: raise ValueError(f"接口返回错误 [{body.get('code')}]: {body.get('message')}") return self._parse(query, body.get("data", {})) def _parse(self, query: str, data: dict) -> SearchResult: result = SearchResult( query=query, has_ai_overview=bool(data.get("ai_overview", 0)), task_id=data.get("taskId", ""), ) for item in data.get("json", {}).get("items", []): if item.get("type") != "ai_overview": continue for sub in item.get("items", []): if sub.get("type") == "ai_overview_elem": result.ai_content.extend(sub.get("content", [])) for ref in item.get("references", []): result.references.append({ "title": ref.get("title", ""), "url": ref.get("url", ""), "domain": ref.get("domain", ""), }) return result跑一次验证请求:
python -c " from skills.google_ai_mode import GoogleAIModeSkill skill = GoogleAIModeSkill() r = skill.search('Python asyncio 最新特性') print(r.to_agent_context()) print('has_ai_overview:', r.has_ai_overview) print('task_id:', r.task_id) "预期返回结构分三层。第一层是has_ai_overview布尔值,为True时表示这次查询命中了 AI 摘要。第二层是ai_content列表,每个元素是一段摘要文本,通常 2 到 5 段。第三层是references列表,每项包含title、url、domain三个字段,对应摘要里引用的来源页面。
如果has_ai_overview为False,不代表请求失败,而是这次查询没有触发 AI 摘要。信息型问法(「是什么」「怎么做」「对比」)触发率高,导航型或纯品牌词触发率低。这是 Google 侧的触发策略,不是通道问题。
验证通过后,把技能挂到 Agent 上,在对话里问一句「帮我查一下 OpenClaw 最新版本有什么变化」,观察 Agent 是否自动调用google_ai_mode_search技能,并把摘要内容整合进回答。如果 Agent 没有触发技能,检查description和triggers是否覆盖了你的问法。
5. 常见报错排查:401、local proxy failed 与 choices 解析异常
接入过程中最容易撞上的几类报错,这里逐个对照。
401 Unauthorized。返回体通常是{"error": {"message": "invalid api key"}}或类似结构。原因有三个:Key 没设置进环境变量、Key 复制时带了空格、Key 已失效。排查顺序是先echo $TAOTOKEN_API_KEY确认非空,再用echo -n $TAOTOKEN_API_KEY | wc -c看长度是否和创建时一致,最后去控制台确认 Key 状态。注意api_key_env字段填的是变量名,如果你误填成 Key 本身,代码里os.environ.get会取不到值,直接抛环境变量未设置。
local proxy failed / connection refused。这类报错出现在请求根本没发出去的时候。检查api_base是否写成了https://taotoken.net/api/带尾斜杠,代码里rstrip("/")会处理,但如果你在配置文件里手写了完整端点路径,可能拼出//v2/scrape这种双斜杠。另一个原因是本机网络环境有额外的代理设置,导致请求被拦截。确认你的运行环境能直接访问https://taotoken.net/api,用curl -I https://taotoken.net/api看是否返回 HTTP 状态码。
reading choices 解析异常。这个报错通常出现在模型对话通道,而不是搜索通道。当你用 TaoToken 的模型能力时,如果返回体里没有choices字段,代码解析会抛KeyError: 'choices'或reading 'choices'类错误。原因一般是 Model ID 填错了,请求打到了不存在的模型上,返回的是错误结构而不是正常的对话结构。回到settings.json检查agent.default_model和models.default是否一致,并且这个 Model ID 在模型列表里确实存在。
OAuth 相关报错。如果你用的是 Claude Code 类需要 OAuth 的客户端,报错可能是OAuth token expired或invalid_grant。这类客户端在配置 TaoToken 通道时,鉴权方式要选 API Key 而不是 OAuth。检查客户端的鉴权配置项,把auth_type设为api_key,Key 来源指向TAOTOKEN_API_KEY。如果客户端强制走 OAuth 流程,说明它的配置模板没切过来,需要手动改配置文件里的 provider 段。
技能不触发。Agent 收到了实时性问题但没有调用搜索技能。先看description是否描述了触发场景,再看triggers关键词是否覆盖。一个实用技巧是在 Agent 的 system prompt 里加一句「涉及实时信息时优先调用 google_ai_mode_search 技能」,给 Agent 一个明确的调用倾向。
返回结果为空但 code 为 0。has_ai_overview为False,ai_content为空列表。这不是错误,是这次查询没有 AI 摘要。换一个信息型问法重试,比如把「OpenClaw」改成「OpenClaw 怎么配置搜索技能」,触发率会明显上升。
排查时建议打开请求日志,把payload和resp.status_code、resp.text[:500]打出来。大部分问题看这两行就能定位:状态码告诉你鉴权和网络层有没有过,返回体前 500 字符告诉你业务层返回了什么结构。
6. 把搜索技能接进长期 Agent 工作流
单次搜索跑通只是起点。真正让 Agent 有价值的是把搜索能力嵌进长期工作流:定时抓取行业动态、批量核查事实、给编码 Agent 补充最新库文档。这些场景对通道的稳定性和调用方式有不同要求。
如果你要做的是长期运行的编码 Agent 或自动化 Agent,建议走 Coding Plan 通道,它针对持续调用做了配额和稳定性优化:
https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=openclaw_google_ai_mode&utm_campaign=rewrite批量搜索场景下,把技能类扩展成异步版本,用aiohttp并发发出请求,并发数控制在 5 左右。并发太高会导致超时集中爆发,反而拖慢整体。对热词加一层本地缓存,相同查询一小时内直接返回缓存结果,既省调用量又提速。
多轮追问场景要注意param字段的长度限制。超过 5 条上下文会让响应变慢,建议把长对话拆成多次独立请求,每次带 3 到 4 条上下文。这样既保持了追问的连贯性,又不会让单次请求过重。
如果你需要确认某个模型在搜索摘要整合上的表现,可以先去模型对话页面手动试几轮,对比不同模型对同一段摘要的整合质量:
https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=openclaw_google_ai_mode&utm_campaign=rewrite接入文档里有各能力端点的完整参数说明和返回结构定义,遇到字段含义不清楚的时候对照查:
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=openclaw_google_ai_mode&utm_campaign=rewrite最后给一个实用建议:把搜索技能的调用结果和 Agent 的最终回答分开记录。搜索返回的是原始摘要和引用,Agent 回答是整合后的输出。分开记录后,当 Agent 回答出现事实偏差时,你能快速定位是搜索数据本身的问题,还是 Agent 整合环节的问题。这个习惯在调试复杂 Agent 工作流时能省下大量时间。