如何把 TinyFish Web Agent 集成到 HelloAgents 作为上网工具?
【免费下载链接】hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/GitHub_Trending/he/hello-agents
如果你的 HelloAgentsReActAgent目前只会"说话"而不会"上网"——查询实时价格、抓取没有 API 的网页内容都要靠模型凭训练记忆回答——这篇文章给出一个可执行的集成路径:把托管型 Web Agent 服务 TinyFish 包装成 HelloAgents 框架里的一个Tool,注册进ToolRegistry,让 ReAct 循环在运行时自主调用它浏览网页并拿回结构化 JSON。TinyFish 的调用方式是给它一个url和一段自然语言goal,它在远程启动真实 Chromium 浏览器完成任务并流式返回进度与结果。
适用的前提:
- Python 环境,能
pip install第三方包; - 一个 TinyFish API 密钥(在
agent.tinyfish.ai注册获取); - HelloAgents 框架已按 第七章 构建你的Agent框架.md 的要求准备好同级
.env中的大模型 API 配置(可参考code文件夹配套的.env.example)。
集成步骤与验证方式来自 Extra-Chapter/Extra11-WebAgent科普与实战.md 的 2.4 节"把 TinyFish 集成进 HelloAgents"。
准备:API 密钥与依赖安装
第 1 步,在agent.tinyfish.ai注册账号,进入 API Keys 页面点击Create API Key并复制密钥——密钥只显示一次。写进 shell:
export TINYFISH_API_KEY="sk-tinyfish-..." # 替换为你自己的密钥第 2 步,安装两侧依赖:
pip install tinyfish # TinyFish 的 Python SDK pip install hello-agents # HelloAgents 框架Extra11 正文提示:如果想要和教程正文完全对应的框架版本,可以切到 GitHub 上的learn_version分支。后文所有命令都依赖TINYFISH_API_KEY这个环境变量已导出。
第 1 步:定义TinyFishWebTool
把 Web 自动化暴露成一个能力:智能体用自然语言描述任务,工具负责调用 API 并返回结构化 JSON。创建tools/tinyfish_tool.py:
# tools/tinyfish_tool.py import json import os from typing import Any, Dict, List from tinyfish import ( TinyFish, BrowserProfile, ProxyConfig, ProxyCountryCode, ) from hello_agents.tools import Tool, ToolParameter class TinyFishWebTool(Tool): """让 ReAct 智能体通过自然语言驱动真实浏览器的工具。""" def __init__(self, api_key: str | None = None): super().__init__( name="web_automation", description=( "使用自然语言自动化任何网页。输入一个 JSON 字符串,包含两个必需字段:" "`url`(起始页面)和 `goal`(清晰具体的任务描述)。" "可选字段:`stealth`(布尔值,针对有反爬保护的站点)、" "`country`(US/GB/CA/DE/FR/JP/AU,用于地理路由)。" "返回智能体抽取的结构化 JSON,或错误描述。" ), ) self.client = TinyFish( api_key=api_key or os.environ["TINYFISH_API_KEY"], ) def run(self, parameters: Dict[str, Any]) -> str: # ToolRegistry 会把 ReAct 的输入文本包成 {"input": "..."} raw = parameters.get("input", "") try: params = json.loads(raw) except json.JSONDecodeError: return json.dumps( {"error": "输入必须是合法的 JSON 字符串"}, ensure_ascii=False, ) url = params.get("url") goal = params.get("goal") if not url or not goal: return json.dumps( {"error": "缺少必需字段 url 或 goal"}, ensure_ascii=False, ) kwargs: Dict[str, Any] = {"url": url, "goal": goal} if params.get("stealth"): kwargs["browser_profile"] = BrowserProfile.STEALTH if (country := params.get("country")): kwargs["proxy_config"] = ProxyConfig( enabled=True, country_code=ProxyCountryCode(country), ) # 用同步 run——ReAct 循环要拿到结果再继续。 # 长任务可以改用 queue + 轮询。 run = self.client.agent.run(**kwargs) if run.status.value != "COMPLETED" or run.result is None: err = run.error.message if run.error else "未知失败" return json.dumps( {"error": err, "status": run.status.value}, ensure_ascii=False, ) return json.dumps( {"data": run.result, "run_id": run.run_id}, ensure_ascii=False, ) def get_parameters(self) -> List[ToolParameter]: return [ ToolParameter( name="input", type="string", description=( "JSON 字符串,字段:url(必需)、goal(必需)、" "stealth(可选)、country(可选)" ), required=True, ) ]代码里有几处值得留意(均来自 Extra11 正文的说明):
- 工具的
description是 LLM 决定是否调用它时唯一看到的信息,要把输入、输出、何时使用讲清楚; - 工具永远返回字符串。ReAct 是文本进、文本出,所以结果被序列化成 JSON,让智能体在下一步 "Thought" 中继续推理;
stealth和country是可选参数,不开默认值,让 LLM 通过工具描述自行判断何时对反爬站点启用隐身。
这份代码与第七章框架的工具接口是一致的:第七章 7.5.1 节定义的Tool基类要求子类提供name、description、run(parameters) -> str和get_parameters() -> List[ToolParameter],ToolParameter的字段为name/type/description/required(见 第七章文档 及 code/chapter7/my_react_agent.py 中的框架用法)。
第 2 步:把工具接入 ReAct 智能体
创建main.py:
# main.py from hello_agents import ReActAgent, HelloAgentsLLM, ToolRegistry from tools.tinyfish_tool import TinyFishWebTool llm = HelloAgentsLLM() # 从 .env 读取 provider 配置 registry = ToolRegistry() registry.register_tool(TinyFishWebTool()) agent = ReActAgent( agent_name="research_assistant", llm=llm, tool_registry=registry, ) result = agent.run( "查询苹果官方商店和京东上 iPhone 17 Pro 的当前价格," "在考虑商品页面所标的运费后告诉我哪个更便宜。" ) print(result)agent.run(...)里的那段查询只是 Extra11 文档给出的示例任务,你可以替换成自己任意"需要访问外部网页才能回答"的问题——工具拿到的永远是url+goal形式的具体指令。注意HelloAgentsLLM()会从项目同级.env读取 provider 配置,没配置 API 密钥时这一步会直接失败,需要先把第七章要求的大模型配置补齐。
运行后如何验证集成生效
注册是否成功:ToolRegistry.register_tool在注册成功时会打印确认信息(第七章文档中展示的实际输出格式为✅ 工具 'web_automation' 已注册。)。如果没看到这条输出,说明工具对象没有正确进入 registry。
循环是否按预期工作:运行python main.py后,ReAct 循环大致会经历 Extra11 文档展示的这样一个过程(文档示例,实际站名与数值随你查询的站点变化):
- Thought:"我需要从两个不同的站点拿价格。我应该调用两次 web_automation。"
- Action:
web_automation({"url": "https://www.apple.com/.../iphone-17-pro", "goal": "提取 iPhone 17 Pro 起步价。返回 JSON: {price_cny: number, free_shipping: boolean}"}) - Observation:
{"data": {"price_cny": 9999, "free_shipping": true}} - Thought:"现在拿京东价格。京东有反爬——我应该启用 stealth。"
- Action:
web_automation({"url": "https://item.jd.com/...", "goal": "...", "stealth": true}) - Observation:
{"data": {"price_cny": 9799, "free_shipping": true}} - Final Answer:"京东目前比苹果官方便宜 200 元:京东 ¥9,799,苹果官方 ¥9,999,两家都免运费。"
结果是否可信:不要只看运行状态。COMPLETED的运行也可能返回垃圾——智能体可能撞上 Cloudflare 挑战页、验证码,或把 "访问被拒绝" 渲染成正文。Extra11 给出的生产做法是对结果内容做失败信号检查:
def is_real_success(result: dict | None) -> bool: if not result: return False s = json.dumps(result, ensure_ascii=False).lower() failure_signals = ["captcha", "blocked", "access denied", "could not", "unable to"] return not any(signal in s for signal in failure_signals)过程是否可观察:TinyFish 每次运行都会产生一个streaming_url,在浏览器打开它就能看到智能体正在驱动的真实浏览器会话(页面加载、鼠标移动、字段填写)。返回空结果或点错按钮时,打开直播 URL 是最直接的定位手段。
排查:空结果、拦截与失败
如果工具返回空数据或类似 403 的拦截,Extra11 给出的诊断流程是:
- 确认问题是不是反爬。打开失败那次运行的
streaming_url,对照文档给出的特征表:
| 你看到什么 | 大概率原因 |
|---|---|
| Cloudflare "Checking your browser" 页 | Cloudflare 机器人检测 |
| DataDome 弹窗或重定向 | DataDome |
| 空白页或永远转圈 | 基于 IP 或指纹的拦截 |
| 验证码(reCAPTCHA、hCaptcha) | 验证码——硬上限 |
| "Access Denied" / 403 | IP 或 User-Agent 拦截 |
| 该看到内容时却出现登录墙 | 基于会话的反爬 |
- 隐身和代理一起开。隐身改变浏览器指纹,代理改变 IP,反爬厂商会关联两个信号,只改一个往往不够:
run = client.agent.run( url="https://protected-site.com", goal="提取商品价格", browser_profile=BrowserProfile.STEALTH, proxy_config=ProxyConfig(enabled=True, country_code=ProxyCountryCode.US), )让智能体表现得更像人类:在 goal 里显式关闭 cookie 横幅、抽取前等页面加载完成、用视觉描述元素而不是选择器、多步流程用编号步骤。
实在不行就换打法:先花五分钟看该站点是否提供 RSS、sitemap 或公开 API——比硬闯反爬省事。
两个必须接受的边界:其一,包括 TinyFish 在内没有任何 Web Agent 能可靠解开 reCAPTCHA、hCaptcha 这类现代验证码,站点弹验证码时只能设计任务绕开它;其二,TinyFish 内部每次运行有 10 分钟超时,但 Extra11 建议在工具层设置更早的超时——多数有意义的任务在 10–60 秒内完成,超过多半是卡在挑战页上。
另外两条文档给出的生产建议:同一会话里智能体两次要求同一个 URL 时应返回缓存结果(第八章的记忆系统是合适的着力点);把每次运行的streaming_url记进日志,生产环境出问题时运行录像是定位故障最快的工具。
限制与下一步
托管型 Web Agent 按任务计费,文档给出的成本区间是每个任务 0.10–1.00 美元;站点有官方 API 时优先用 API,高频爬取无反爬站点用纯 Playwright 更便宜——这些场景下托管 API 不是正确选择(见 Extra11 的 3.1 节"什么时候不要用托管 Web Agent")。
文档明确给出的延伸方向:结合第八章(记忆)让 Web Agent 记住上次抓到的内容、只取增量;结合第十二章(评估)给 Web Agent 装上成功率追踪,弄清哪些站点需要 stealth、哪些 goal 需要再细化;以及结合第十三、十四章把旅行助手或 DeepResearch 智能体的动作空间扩展到真实浏览器。TinyFish 还提供 MCP 服务器,可让兼容 MCP 的助手直接获得run_web_automation等工具,那是另一条不经过 HelloAgents 框架的接入路径,本文不展开。
【免费下载链接】hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/GitHub_Trending/he/hello-agents
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考