首页 › AI Agent › Agent学习路径 › WebAgent 实战教程

WebAgent 实战教程

2.1 极速上手:5 分钟内你的第一个 Web Agent​

TinyFish 是一个托管型的 Web Agent API。你给它一个 URL 和一段自然语言 目标(goal),它返回结构化 JSON。​

第 1 步:获取 API 密钥​

在 agent.tinyfish.ai 注册账号​

进入 API Keys 页面,点击 Create API Key​

复制密钥——它只显示一次​

写进你的 shell:​

​

export TINYFISH_API_KEY="sk-tinyfish-..."​

​

第 2 步:安装 SDK​

​

代码块​

JavaScript

# Python​

pip install tinyfish​

​

# 或 TypeScript​

npm install @tiny-fish/sdk​

​

第 3 步:你的第一个自动化任务​

Python:​

​

代码块​

Python

from tinyfish import TinyFish, CompleteEvent​

​

client = TinyFish() # 自动从环境变量读取 TINYFISH_API_KEY​

​

with client.agent.stream(​

url="https://scrapeme.live/shop",​

goal="提取前 2 个产品的名称和价格,以 JSON 形式返回。",​

) as stream:​

for event in stream:​

if isinstance(event, CompleteEvent):​

print(event.result_json)​

​

TypeScript:​

​

代码块​

JavaScript

import { TinyFish, EventType } from "@tiny-fish/sdk";​

​

const client = new TinyFish();​

​

const stream = await client.agent.stream({​

url: "https://scrapeme.live/shop",​

goal: "提取前 2 个产品的名称和价格,以 JSON 形式返回。",​

});​

​

for await (const event of stream) {​

if (event.type === EventType.COMPLETE) {​

​

原始 HTTP(不用 SDK):​

​

代码块​

C++

curl -N -X POST https://agent.tinyfish.ai/v1/automation/run-sse \​

-H "X-API-Key: $TINYFISH_API_KEY" \​

-H "Content-Type: application/json" \​

-d '{​

"url": "https://scrapeme.live/shop",​

"goal": "提取前 2 个产品的名称和价格"​

}'​

​

运行起来,你会看到 Server-Sent Events 实时流进终端:​

​

代码块​

Bash

​

就这样——你刚刚跑完了一个 Web Agent。这一次调用背后发生的事:数据中心里启动了一个真实的 Chromium 浏览器,导航到目标页面,解析布局,识别出商品卡片,提取数据,并把进度流式返回给你。​

请求的解剖​

TinyFish 的 /run-sse 端点接收的 JSON 字段(重点字段已加粗):​

​

#esRGGFocBWoa text{white-space:pre}.fb0{stroke:var(--N900-FG, 0.15)}.fx0{stroke-miterlimit:10}.fa1{fill:#bbbfc4}.fx1{font:normal 400 12px MonospacedNumber,LarkHackSafariFont,LarkEmojiFont,LarkChineseQuote,-apple-system,BlinkMacSystemFont,Helvetica Neue,Tahoma,PingFang SC,Microsoft Yahei,Arial,Hiragino Sans GB,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.fx2{text-anchor:middle}.fx3{dominant-baseline:central}.fx4{stroke:none}.fc0{fill:var(--text-caption)}.fa2{fill:var(--text-link-disabled)}.fx5{font:400 normal 13px MonospacedNumber, LarkHackSafariFont, LarkEmojiFont, LarkChineseQuote, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma, "PingFang SC", "Microsoft Yahei", Arial, "Hiragino Sans GB", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"}.fx6{text-anchor:start}.fx7{dominant-baseline:alphabetic}.fc1{fill:rgb(0, 0, 0)}.fx8{font:400 normal 13px LarkHackSafariFont, LarkEmojiFont, "ui-monospace", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, "Noto Sans", Tahoma, "Nimbus Sans L", Arial, "Liberation Sans", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Source Han Sans SC", "Source Han Sans CN", "Microsoft YaHei", "Wenquanyi Micro Hei", "WenQuanYi Zen Hei", STHeiti, SimHei, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", system-ui}.fb1{fill:var(--N900-FG, 0.15)}.fb2{fill:rgb(209, 217, 224)}.fa3{fill:var(--bg-body)}ABC12345678字段类型stringstringobject | objectbooleanstring[]说明起始页面自然语言指令可选的 JSON Schema 子集,约束返回结构默认 可选 是否使用保存的凭据完成登录限定 vault 中的具体凭据urlgoaloutput_schemabrowser_profileproxy_configuse_vaultcredential_item_ids"lite""stealth"lite{enabled, type, country_code}

​

三个端点,三种模式:​

•

POST /v1/automation/run——同步,阻塞到完成,返回最终结果​

•

POST /v1/automation/run-async——发后即忘,立即返回 run_id​

•

POST /v1/automation/run-sse——流式,实时把进度事件推回给你​

短任务(< 30 秒)用同步;批量作业用异步;要在 UI 上实时显示进度时用 SSE。​

2.2 观察智能体工作——直播 URL​

TinyFish 在教学上最有用的一个功能是 streaming_url:每次运行都会产生一个 URL,让你 实时观看浏览器。你可以把它嵌进自己产品的 iframe 里,也可以直接在浏览器开个 Tab 边调试边看。​

​

代码块​

Python

from tinyfish import TinyFish, CompleteEvent​

​

client = TinyFish()​

​

with client.agent.stream(​

url="https://scrapeme.live/shop",​

goal="提取前 3 个产品的名称和价格",​

on_streaming_url=lambda e: print(f"\n实时观看:{e.streaming_url}\n"),​

on_progress=lambda e: print(f" → {e.purpose}"),​

) as stream:​

​

跑起来几乎瞬间就拿到一个可点击 URL。在浏览器里打开它——你看到的就是 智能体正在驱动的真实浏览器会话。页面在加载、鼠标在移动、字段在填写。这是大多数读者会发出 "卧槽,它真的在做" 的瞬间。​

而且这不只是个演示噱头。直播流是调试 Web Agent 最好用 的工具:​

•

一次运行返回了空结果?打开直播——很可能你会看到一个 Cloudflare "Checking your browser" 拦截页,或者一个意料之外的弹窗​

•

智能体点错了按钮?看直播、改 goal​

•

在做面向用户的产品?把直播 URL 嵌进 iframe,让用户看着工作发生​

2.3 怎么写好 goal​

goal 这一个字段几乎就是 TinyFish 的全部 API 表面——写好它,是 90% 成功率和 30% 成功率的分水岭。​

TinyFish 官方推荐的心智模型:把智能体当成一个 "字面执行" 的助理,坐在浏览器前。它能看到屏幕上的一切、能动手——但它没法猜你的意思。​

一个出色的 goal 最多包含七个组件:​

​

表格加载中...

​

从最差到最好的演变:​

​

"提取产品名称、价格和库存状态"​

​

模糊(必然失败):​

生产级品质:​

​

"获取这个页面的定价"​

​

​

代码块​

TypeScript

1. 等待页面完全加载。​

2. 如果有 cookie 同意横幅,点击"全部接受"。​

3. 定位定价区。​

4. 对每个套餐,提取:套餐名称、月费(数字)、包含功能(字符串数组)。​

​

不要点击任何购买或结账按钮。​

如果套餐显示"联系我们",monthly_price 置为 null。​

​

返回 JSON:[{"plan": string, "monthly_price": number | null, "features": string[]}]​

​

好一些(可能能跑):​

TinyFish 自己的测试里,相同任务下具体的 goal 完成速度快 4.9 倍、返回的多余数据少 16 倍。Goal 写作就是新的 Prompt 工程,并且和所有 Prompt 工程一样,复利明显。​

2.4 主菜:把 TinyFish 集成进 HelloAgents​

这一节是本章的核心。直接调 API 当然可以——但本书,尤其是第四章和第七章,一直在传达的核心信息是:当外部服务变成你自己框架里的工具,真正的力量才出现。这就是 "使用 AI" 和 "用 AI 构建" 之间的分水岭。​

我们要把 TinyFish 包装成一个 HelloAgents 的 Tool,接入 ReActAgent。​

​

提示:HelloAgents 是你在第七章构建的配套框架。如果还没装:pip install hello-agents。想要和正文完全对应的版本,可以切到 GitHub 上的 learn_version 分支。​

​

第 1 步:定义 TinyFishWebTool​

我们写一个工具,把 Web 自动化暴露成单一能力。智能体用自然语言描述自己想做什么,工具负责调用 API 并返回结构化 JSON。​

​

代码块​

Python

# 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):​

​

代码里有几处值得特别留意:​

工具的 description 是 LLM 决定是否调用它时唯一看到的信息。要像在跟一个从没读过你代码的初级开发者交代一样写描述——把输入、输出、何时使用都讲清楚。​

工具永远返回字符串。ReAct 是文本进、文本出。我们把结果序列化成 JSON,让智能体在下一步 "Thought" 中能继续推理。​

stealth 和 country 不是默认开启而是可选参数。让 LLM 自己决定——通过工具描述告诉它什么时候该开。​

第 2 步:把工具接入 ReAct 智能体​

​

代码块​

Python

​

运行起来,ReAct 循环大致会经历这样的过程:​

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}}​

Thought:"两边都包邮。京东便宜 200 元。"​

Final Answer:"京东目前比苹果官方便宜 200 元:京东 ¥9,799,苹果官方 ¥9,999,两家都免运费。"​

刚刚发生的事,正是第七章希望传达的核心:外部服务作为一等公民进入你自己的框架。ReAct 循环没变,LLM 也没变。我们只是加了一个工具,你的智能体就具备了在公开网络上行动的能力。这就是 可组合性。​

第 3 步:把它做到生产级​

上面的版本演示足够了。真实生产环境还要再加几样:​

验证内容,不要只看状态​

COMPLETED 的运行也可能返回垃圾,如果智能体撞上了软拦截(Cloudflare 挑战页、验证码、把 "访问被拒绝" 渲染成正文)。永远要检查 结果内容:​

​

代码块​

SQL

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)​

​

能缓存就缓存​

一次 30 秒的网页自动化是昂贵的。如果同一会话里 ReAct 智能体两次要求同一个 URL,应该返回缓存结果。(第八章的记忆系统是个合适的着力点。)​

设置超时​

TinyFish 内部每次运行有 10 分钟超时,但你的工具应该更早失败——多数有意义的任务在 10–60 秒内完成。超过这个时间,多半是卡在挑战页上了。​

用直播流做可观测​

把每次运行的 streaming_url 记下来,写日志。生产环境出问题时,运行录像是定位故障最快的工具。​

2.5 应对反爬​

你的智能体迟早会撞上一个返回空结果或 403 的站点。这是诊断流程:​

第 1 步——确认问题就是反爬。打开失败那次运行的 streaming_url,找以下几种特征:​

​

​

第 2 步——隐身和代理一起开。隐身改变浏览器指纹,代理改变 IP。反爬厂商会关联两个信号——只改一个往往不够:​

​

代码块​

JavaScript

run = client.agent.run(​

url="https://protected-site.com",​

goal="提取商品价格",​

browser_profile=BrowserProfile.STEALTH,​

proxy_config=ProxyConfig(enabled=True, country_code=ProxyCountryCode.US),​

)​

​

第 3 步——让智能体表现得更像人类。有些站点关注行为而不只是指纹。在 goal 里加上:​

•

显式关闭 cookie 横幅​

•

抽取前等页面加载完成​

•

用视觉描述元素("蓝色的'加入购物车'按钮"),不要用选择器​

•

多步流程用编号步骤,让智能体自己慢下来​

第 4 步——实在不行就换打法。有些站点死命拦爬虫,但会大方提供 RSS、sitemap、公开 API。花五分钟翻一翻,省下几天试错时间。如果数据真的只在付费墙后的格式化页面里,问问自己:底层信息源(公告、新闻稿、厂商页面)是不是在防守更弱的地方也有。​

一段完整的、加固过的范例:​

​

代码块​

Python

from tinyfish import (​

TinyFish, BrowserProfile, ProxyConfig, ProxyCountryCode,​

CompleteEvent, RunStatus,​

)​

​

​

重要的诚实声明:包括 TinyFish 在内,没有任何 Web Agent 能可靠地解开现代验证码(reCAPTCHA v2/v3、hCaptcha)。如果一个站点向你弹出验证码,那目前就是一道硬墙。正确的做法是把你的运行设计得不去触发它,而不是硬扛。​

​

2.6 加餐:通过 MCP 调用 TinyFish(对应第十章)​

第十章介绍了 MCP(Model Context Protocol)——Anthropic 提出的、让 AI 助手连接外部工具和数据的开放协议。TinyFish 暴露了一个 MCP 服务器。这意味着,你可以让任何兼容 MCP 的助手(Claude Desktop、Cursor、Windsurf、Claude Code)具备驱动浏览器的能力——你自己一行代码都不用写。​

一行命令安装:​

​

代码块​

SQL

​

或者手动在 claude_desktop_config.json 里加:​

​

代码块​

JavaScript

{​

"mcpServers": {​

"tinyfish": {​

"url": "https://agent.tinyfish.ai/mcp"​

}​

​

重启后,你的助手会多出 run_web_automation、search、fetch_content、create_browser_session 等工具。然后你就可以直接对 Claude 说:​

​

"并行抓取以下 5 个竞品的定价页,把结果整理成表格。"​

​

Claude 就会用 TinyFish 在背后完成这件事,批量执行,实时反馈进度。​

这正是第十章预告的 一次构建、处处可用 的回报。MCP 作为分发协议,把每一个工具都变成了 每个 AI 助手都能直接使用 的能力。​

​

​

第三部分:综合思考​

3.1 什么时候 不要 用托管 Web Agent​

为了诚实:托管 Web Agent 并不总是正确选择。​

•

有官方 API——用 API。API 更快、更便宜、更可靠​

•

高频率爬取无反爬站点——纯 Playwright 就够了,便宜几个数量级​

•

错误代价高的关键工作流——不管你用什么工具,永远要在关键步骤加上人类在环检查点​

•

你完全可控的内部工具——干脆加一个 API 端点​

什么时候用托管 Web Agent:目标站点在外部、没有 API、有反爬保护、流程是多步的,而且工程时间比任务级单价更值钱。​

3.2 Web Agent 接下来的方向​

这个领域走得很快。未来 12–24 个月值得关注的几件事:​

•

更小、更快、专为 Web 微调的模型。前沿模型对 "点击蓝色按钮" 是杀鸡用牛刀。下一代 OS 专家智能体——例如 Qwen-VL-2.5-VL 之后的模型——会大幅压低单步动作的延迟和成本。​

•

认证会话成为一等公民。Vault 集成(加密的密码管理器桥接)开始落地。这将解锁下一波智能体应用——银行、医疗、内部工具,这些场景登录是入口。​

•

学术基准向生产水位靠拢。常见业务流上的生产成功率已经稳定在 90% 左右;WebArena 这类对抗性基准上的分数也在快速攀升,差距正在被工程和模型两端同时压缩。​

•

本地 Web Agent。隐私敏感任务(医疗记录、税务)需要本地运行的智能体。本地 VLM 配合本地 Chromium 已经看起来可行。​

•

Web Agent 评测成熟化。第十二章讲的评测方法学正好适用——很快会看到面向生产 Web Agent 的标准化评测套件。​

3.3 接下来该往哪走​

如果这一章勾起了你的兴趣,下面几条路可以继续:​

•

结合第八章(记忆):让你的 Web Agent 记住昨天爬到了什么,今天只取增量​

•

结合第十二章(评估):给你的 Web Agent 装上成功率追踪。你会很快摸清楚哪些站点需要 stealth、哪些 goal 需要再细化​

•

结合第十三章和第十四章:旅行助手和 DeepResearch 智能体一旦把动作空间扩展到 "真实浏览器",会发生质变。试试用 Web Agent 做后端重写其中一个​

•

可以研究的开源替代品:Browser-Use(Python)、Skyvern(Python)、WebVoyager(研究基准)、AgentE(开源智能体基础设施)​

•

基准:WebArena、VisualWebArena、Mind2Web、WebVoyager-2024——把论文读一遍,你就会清楚 2026 年的 Web Agent 在哪个水位​