# WebAgent — 完整文档(中文) --- # Web Agent Web Agent 是 SAK 的网页行动层,用于让 Agent 在开放 web 上完成搜索、抽取、浏览器动作、追踪和受控任务执行。读完本组文档后,你可以为自己的应用接入 Web Agent,创建 session,提交 task,并通过事件流获取执行结果。 Web Agent 不是传统爬虫 SDK。它面向的是 LLM agent 的任务执行链路:开发者给出 instruction,Web Agent 管理运行时资源、页面状态、重试、结构化结果和任务生命周期。Console 和 SDK 都只是同一组 API 的客户端。 ## 什么时候使用 Web Agent - 你的 Agent 需要访问实时网页数据,而不是只依赖模型训练数据或固定知识库。 - 你需要把搜索、网页抽取、浏览器动作和长程任务封装成可审计的 API。 - 你希望 Console、SDK 和后端服务都走同一份 REST API 契约。 - 你需要通过 session / task 模型保存运行状态、订阅事件流,或处理需要人工确认的步骤。 ## 什么时候不要使用 Web Agent - 任务只需要调用你自己的后端 API,不需要访问开放 web。 - 你需要的是大规模离线爬取、数据仓库同步或搜索引擎索引构建。 - 目标站点的使用条款不允许自动化访问,且你没有取得必要授权。 - 你还没有定义 API key、project scope、任务预算和失败重试策略。 ## 核心能力 | Capability | Description | | --- | --- | | DoAnything API | 给出自然语言 instruction,由 Web Agent 选择工具、执行步骤并返回结果。 | | Shaped APIs | 对 DeepResearch、WebSearch、Track 等固定产物形态提供更明确的 API 契约。 | | Session / Task model | 用 session 持有运行时资源,用 task 表达一次任务或后续动作。 | | Event stream | 通过 SSE 订阅任务状态、输出片段、错误和人工确认请求。 | | SDK and raw HTTP | Python、TypeScript 和 cURL 文档使用同一份 API 语义。 | ## 文档入口 - [什么是 WebAgent](/web-agent/getting-started/what-is-webagent):理解 Web Agent 的定位、边界和 API 形态。 - [Quickstart](/web-agent/getting-started/quickstart):用 Python、TypeScript 或 cURL 跑通第一个 task。 - [鉴权与 API key](/web-agent/getting-started/authentication):了解 `wa_` key、project scope 和轮换策略。 - [Sessions 与 Tasks](/web-agent/concepts/sessions-and-tasks):理解 session、task、event 和 profile 的生命周期。 - [错误与重试](/web-agent/concepts/errors-and-retries):查看错误码、重试策略和幂等处理。 - [API 参考](/web-agent/reference/):查看 base URL、鉴权、错误、限流和分页约定。 - [Vibecoding](/web-agent/guides/vibecoding):把文档和 OpenAPI 交给 IDE 中的 LLM,生成集成代码。 --- # 什么是 WebAgent WebAgent 是一个让 LLM agent 像人类开发者一样在网页上完成任务的 API。你给一句中文或英文 instruction,它挑工具(浏览器、沙箱、搜索……)、跑步骤、返回结果。 ## 你能拿到什么 WebAgent 暴露若干用户面 API,分两类: - **DoAnything API** —— 开放型;自由输入,agent 自己定路径。session/task 资源面 + 7 态状态机 + 长程任务 - **定型 API** —— 知道产物形态时直接走对应 API,给定型契约 + 质量承诺: - **DeepResearch** —— 研究 → 报告(final.md + citations + confidence) - **WebSearch** —— 查询 → 结果(结构化 search results + 可选摘要) - **Track** —— 监控 → snapshot 序列 + change notification 公共能力: - **Profiles** —— 跨 session 复用登录态。不用每次重新登录 - **Workspaces** —— 持久文件系统,agent 可读可写 - **Schedules** —— cron / interval / event / autonomous(让 agent 自己决定何时再跑) - **SSE 事件流** —— Console 用的同一套 `task.*` 事件,直接推到你代码里 ## 它不是什么 - 不是 low-code 自动化平台。没有可视化画布。任务是用代码(或 Console 当作原型工具)写出来的 - 不是托管 LLM API。你把任务给 WebAgent,它替你挑模型并按 credits 计费 ## 三种产品形态:Console / OpenAPI / SDK 这些 API 都通过同一组三种形态对外提供,三者能力 1:1 等价、共享同一份资源面 / 事件流 / 计费: | 你用 …… | 来做 …… | |---|---| | [REST API(OpenAPI)](/web-agent/reference/) | 任何事。Console 与 SDK 都只是它的客户端。`api.web-agent.asix.inc/v1/...` + `Authorization: Bearer wa_...` | | Python / TypeScript [SDK](/web-agent/sdk/python) | 同样的 API,更地道的类型 + 重试 + 流式 + `wait_for_done` | | [Console](https://console.web-agent.asix.inc) | 可视化原型;非开发者也能用;*Get Code* 对话框直接给可运行片段 | **API 开发者优先**——产品本质是一组 API;Console 是便利层,不是独立产品形态;不给 Console 特权端点。 ## 心智模型 ``` Session (一个容器;持有浏览器、profile、workspace) └── Task #1 status: completed (一条 instruction;生命周期 7 态) └── Task #2 status: running (在同 session 里追加一条 instruction) └── events: SSE 流 (status_changed, message, action.*, screenshot, …) ``` **Session** 持有运行时资源(浏览器、profile、workspace)。每个 **task** 是一条 instruction;同一 session 里追加 task 会共享前一条 task 留下的状态。Task 有 7 个状态:`pending` / `running` / `awaiting_input` / `paused` / `done` / `failed` / `canceled`,详见 [Sessions 与 Tasks](/web-agent/concepts/sessions-and-tasks)。 > Standalone API(DeepResearch)走 task 资源面但不暴露 session——一次性产出,不需要跨 task 复用浏览器状态。 ## 接下来读哪 - [Quickstart](/web-agent/getting-started/quickstart) —— 5 分钟从注册到看到第一个 SSE 事件 - [鉴权与 API key](/web-agent/getting-started/authentication) —— `wa_` key 怎么用、怎么轮换 - [Sessions 与 Tasks](/web-agent/concepts/sessions-and-tasks) —— 核心资源模型 --- # 5 分钟上手 5 分钟。注册账号、装 SDK、起一个 task、看到事件流回来。 ## Step 0 —— 拿到 API key(30 秒) 1. 在 [console.web-agent.asix.inc](https://console.web-agent.asix.inc) 注册 2. **Settings → API Keys → Create** 3. 复制 `wa_…`。**只显示一次。**丢了只能撤销重建 ```bash export WEBAGENT_API_KEY=wa_xxxxxxxxxxxxxxxxxxxxxxxx export WEBAGENT_PROJECT_ID=proj_xxxxxxxxxxxxxxxxxxxxxxxx ``` ::: tip Project ID 所有 project-scoped 路径都以 project 为隔离单位:`/v1/projects/{pid}/…`(DoAnything / WebSearch / Track)。在 Console URL 里**Project Switcher → 你的 project**就能找到。Standalone 端点(DeepResearch)的 project 由 Bearer token 解析。 ## Step 1 —— 装 SDK(30 秒) ```bash pip install web-agent-sdk ``` ```bash npm install @web-agent/sdk ``` ```bash # 不用装 ``` ## Step 2 —— 跑一个 task(90 秒) `Client` 起一个 DoAnything session,订阅事件流到终态。 ```python import asyncio from web_agent.v1 import Client from web_agent.v1.types import CreateSessionRequest async def main(): async with Client( api_key="wa_demo_xxxxxxxxxxxxxxxx", project_id="proj_demo_0001", ) as client: session = await client.sessions.create(CreateSessionRequest( instructions="搜 Hacker News 今天 Top 5 的故事,列成 list 返回。", )) task = session.tasks[0] async for event in client.events.stream(session.id, task.id): print(event.type, event.data) if event.type == "task.completed": break asyncio.run(main()) ``` ```typescript import { Client } from "@web-agent/sdk"; const client = new Client({ apiKey: "wa_demo_xxxxxxxxxxxxxxxx", projectId: "proj_demo_0001", }); const session = await client.sessions.create({ instructions: "搜 Hacker News 今天 Top 5 的故事,列成 list 返回。", }); const task = session.tasks[0]!; for await (const event of client.events.stream(session.id, task.id)) { console.log(event.type, event.data); if (event.type === "task.completed") break; } ``` ```bash curl https://api.web-agent.asix.inc/v1/projects/proj_demo_0001/do_anything/sessions \ -H "Authorization: Bearer wa_demo_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "instructions": "搜 Hacker News 今天 Top 5 的故事,列成 list 返回。" }' ``` ::: tip 同样的代码 Console 也能给你 Console 的 **Get Code** 对话框输出的就是这段——带你的真实 API key 和当前表单值。打开 `console.web-agent.asix.inc/new`,填表,点 **Get Code**,就省掉了打字。 ## Step 3 —— 知道产物形态时换走定型 API(60 秒) DoAnything 是开放型(产物形态不定)。如果你**知道**自己要的是研究报告 / 解题 / 搜索结果,走对应的定型 API 拿质量契约: ```python async with Client(api_key="wa_...", project_id="proj_demo") as client: task = await client.deep_research.run( topic="2026 年开源向量数据库格局", depth="deep", ) print(task["task_id"]) ``` ```python async with Client(api_key="wa_...", project_id="proj_demo") as client: # wait=true 默认,同步阻塞 ≤30s result = await client.web_search.run( queries=["best Python ORM 2026"], ) for hit in result["results"]["results"]: print(hit["title"], hit["url"]) ``` ```python async with Client(api_key="wa_...", project_id="proj_demo") as client: mon = await client.track.create( intent="苹果股价跌破 $200 时通知我", schedule={"kind": "interval", "every_seconds": 3600}, notify_channel={"kind": "callback_url", "url": "https://hooks.example.com/track"}, ) print(mon["id"]) ``` 定型 API 的端点 / 字段 / 错误信封都跟 DoAnything 走同一份契约——见 [Python SDK](/web-agent/sdk/python) / [TypeScript SDK](/web-agent/sdk/typescript)。 ## Step 4 —— 在 Console 看一眼(30 秒) 打开 `https://console.web-agent.asix.inc/sessions/`(用 step 2 打印的 id)。你会看到刚才那个 task 的 chat + Live Preview iframe——和 SSE 流里的内容一样,可视化呈现。 ## 接下来呢 - [让 task 中途问你确认](/web-agent/concepts/sessions-and-tasks#input-request) —— `task.input_request` - [跨 session 保存登录态](/web-agent/concepts/sessions-and-tasks#profiles) —— Profiles - [每天早上跑一次](/web-agent/reference/) —— Schedules - [翻完整 API](/web-agent/reference/) —— 每个端点每个字段 ## 排错 | 现象 | 原因 | 解 | |---|---|---| | `401 unauthorized` | key 错 / 过期 / 撤销 | **Settings → API Keys** 重建 | | `402 insufficient_credits` | 免费额度耗尽 | **Settings → Billing → Add credits** | | SSE 流卡 60s+ | 网络断 / proxy 缓冲 | 带 `Last-Event-ID` 重连,详见 [Events & SSE](/web-agent/concepts/sessions-and-tasks#events) | | `429 rate_limit_exceeded` | 短时间 burst | 退避重试;Dev plan 默认 5–10 并发 | --- # 鉴权与 API key 本页说明 WebAgent 的 API key 形态、每次请求如何携带、以及创建、撤销、轮换的流程。 每次请求带 bearer token: ```http Authorization: Bearer wa_xxxxxxxxxxxxxxxxxxxxxxxx ``` ## Key 形态 - **前缀** `wa_`,"web agent" 缩写(仿 Stripe `sk_*`) - **长度** 前缀后 28+ 字符。当作不透明 token - **范围** 单 project;多个 project 各创建一个 key - **可见性** 创建时**只显示一次**;丢了只能撤销重建 - **撤销** 软删除 + 1 小时 grace,不让在跑的 task 中途 401 ## Key 放哪 - **本地开发** 环境变量、`.env.local`(已在 `.gitignore` 里) - **生产** 用你的 secret manager(Vault / AWS Secrets Manager / GCP Secret Manager / ……) - **永远不要**提交进 git。Console 的 *Get Code* 对话框默认用占位符 ## 多 project 一个用户可以有多个 project。API path 把 project 直接编进去: ```http GET /v1/projects/{project_id}/do_anything/sessions ``` 没有 `X-Project-Id` header。path 把租户写明——一条 curl 打错 project ID 就是不同的 URL,不会静默跨租户。 ## 轮换 可以同时持有两个有效 key: 1. 在 **Settings → API Keys** 创建新 key 2. 用新 key 部署 3. 撤销旧 key。旧 key 还能用 1 小时;部署完成后自动 401 ## 错误 | 状态码 | code | 含义 | |---|---|---| | 401 | `unauthorized` | 缺失 / 错误 / 过期 / 撤销超 grace | | 403 | `forbidden` | key 有效但无权访问该 project | | 429 | `rate_limit_exceeded` | per-key 并发或频率上限 | ## 接下来 - [计费与额度](/web-agent/getting-started/pricing) —— 每个 task 多少钱 - [Sessions 与 Tasks](/web-agent/concepts/sessions-and-tasks) —— 一次请求实际创建什么 --- # 计费与额度 WebAgent 按 **credits**(预付 USD 余额)计费。每个 task 跑的时候余额会扣。Console 顶部 header 实时显示 `$X.XX`,hover 展开拆账。 ## 双桶 credits | 桶 | 来源 | 过期 | |---|---|---| | **Monthly** | 订阅自带的 monthly credits | 每个计费周期末重置 | | **Additional** | 一次性充值 + auto-recharge | **永不过期** | 每个 task 先扣 monthly,再扣 additional——这样月底重置不会吞掉你充的钱。 ## 四桶 cost 拆账 每个 task 单独记 4 个 cost 字段,方便你做仪表盘: - `llm_cost_usd` —— LLM token 消耗 - `browser_cost_usd` —— 浏览器池秒数 - `proxy_cost_usd` —— proxy 流量(用到时) - `total_cost_usd` —— 总和;扣余额按这个 `SessionResponse` 上能看到,每个 `task.cost_update` SSE 事件也带这四个。 ## Plans | Plan | 月费 | 包含 | 并发 | |---|---|---|---| | Free | $0 | 早期试用 $50–100 credits | 1–2 | | Dev | ~$29 | $30 credits | 5–10 | | Business | ~$299 | $400 credits + 多人席位 | 50–100 | | Scaleup | ~$999 | $1,400 credits + 独占队列 + 区域指定 | 250+ | ::: tip 实际数字保留 ±30% 调整空间 上面是 baseline;公开发布前最终敲定,早期用户锁定折扣价。 ## Auto-recharge 不想周日晚上的 cron 因为 402 挂掉?**Settings → Billing** 里开 auto-recharge: - **阈值** 余额低于 `$X` 触发 - **额度** 一次充 `$Y` - **月上限** 每个自然月最多 `$Z` 防失控 ## 单 task 上限 可以给 task 设硬上限,cron 这种宁愿 fail-fast 不要 runaway: ```python await client.sessions.create(CreateSessionRequest( instructions="...", max_cost_usd="2.00", max_duration_minutes=30, )) ``` 任一上限触发后 task 进 `failed`,`code: budget_exceeded`。已花掉的 credits 还是会扣。 ## 接下来 - [鉴权](/web-agent/getting-started/authentication) —— key 怎么放 - [Sessions 与 Tasks](/web-agent/concepts/sessions-and-tasks) —— 一个 task 究竟跑什么 --- # Sessions 与 Tasks **Session** 是一个运行时容器——它持有浏览器、profile(cookies / 登录态)、workspace(文件系统)。**Task** 是跑在 session 里的一条 instruction。同一 session 可以接连跑多个 task,它们共享前一个 task 留下的状态。 ## 资源形态 ```text project └── session id: sess_… ├── browser, profile, workspace └── task id: task_… ├── instructions "搜 Hacker News..." ├── status running | done | … └── events (SSE) task.status_changed, task.message, … ``` ## 生命周期(7 态) ```mermaid stateDiagram-v2 [*] --> pending pending --> running running --> awaiting_input : task.input_request awaiting_input --> running : POST /intervene running --> paused : POST /pause paused --> running : POST /resume running --> done running --> failed pending --> canceled running --> canceled : POST /cancel awaiting_input --> canceled paused --> canceled ``` | 状态 | 含义 | 下一步 | |---|---|---| | `pending` | 已接收,等 agent slot | → `running`、`canceled` | | `running` | agent 在跑 | → `done`、`failed`、`awaiting_input`、`paused`、`canceled` | | `awaiting_input` | agent 自己暂停了,等你回应 | → `running`(通过 `intervene`) | | `paused` | 你手动暂停 | → `running`(`resume`)、`canceled` | | `done` | 成功完成;`output` 已落 | 终态 | | `failed` | 报错;`error.code` `error.detail` 已落 | 终态 | | `canceled` | 你取消(或 max_duration 触发) | 终态 | 非终态都占 session 资源。用 `max_duration_minutes` 兜底。 ## 提交一个 task ```python from web_agent import Client from web_agent.v1.types import CreateSessionRequest, RecordingConfigRequest session = await client.sessions.create(CreateSessionRequest( instructions="找出 24 小时内 Show HN 上 Top 5 的帖子。", model="claude-sonnet-4.6", max_cost_usd="0.50", max_duration_minutes=10, recording=RecordingConfigRequest(enabled=True), keep_alive=True, )) task = session.tasks[0] ``` | 字段 | 类型 | 说明 | |---|---|---| | `instructions` | string | 一段中文 / 英文。最多 10 000 字符 | | `model` | string | 模型 id,如 `claude-sonnet-4.6` / `gemini-3-flash` | | `max_cost_usd` | string | decimal-as-string;硬上限 | | `max_duration_minutes` | int | 1–10 080(一周) | | `recording` | object | `{enabled, quality, capture_during_take_control}`;不传 = 关 | | `keep_alive` | bool | task 结束后保持 session 热度,方便接 follow-up task | | `allowed_actions` | string[] | 允许 agent 调的工具白名单。空数组 = 全允许 | | `profile_id` | string | 复用 profile 的 cookies / 登录态 | 完整 schema 见 [OpenAPI spec](/openapi/v1.json)。 ## Follow-up task ```python from web_agent.v1.types import CreateTaskRequest followup = await client.sessions.create_task( session.id, CreateTaskRequest(instructions="点进第一篇帖子,总结一下评论区。"), ) ``` 跑在同一个浏览器里,cookies 与上一条 task 留下的 DOM 都在。 ## 事件 {#events} 每个 task 有一条 SSE 流: ```http GET /v1/projects/{pid}/do_anything/sessions/{sid}/tasks/{tid}/events Authorization: Bearer wa_… ``` 11 种事件类型(envelope 一致;`data` 内容不同): | 类型 | 何时 emit | |---|---| | `task.status_changed` | 状态切换 | | `task.message` | chat 里多一条(agent 或 user) | | `task.action.started` | agent 调用某工具 | | `task.action.completed` | 工具返回 | | `task.action.failed` | 工具抛错 | | `task.screenshot` | 浏览器新 frame(`url` 短期签名) | | `task.input_request` | agent 暂停,需要你回应 | | `task.input_request_resolved` | 你的 intervene 已采纳 | | `task.cost_update` | 一步的 cost 增量 | | `task.completed` | 终态;`output` 已落 | | `stream.heartbeat` | 约 15 s 一次;可忽略 | 断线干净续传: ```http GET …/events Last-Event-ID: 142 ``` server 会重放 `id > 142` 的事件,不漏。 ## Input request(人在回路) {#input-request} agent 撞到 captcha、2FA、判断不准的事,会发 `task.input_request`: ```json { "type": "task.input_request", "data": { "input_request_id": "ir_01HXX…", "prompt": "我看到一个 'Verify you're human' 挑战,你帮我点过去?", "schema": { "type": "object", "properties": { "solved": { "type": "boolean" } } } } } ``` 你 `POST /intervene` 回: ```python await client.messages.intervene( session.id, task.id, input_request_id="ir_01HXX…", response={"solved": True}, ) ``` task 切回 `running`。整轮一次往返,无 polling。 ## Profiles {#profiles} **Profile** = 可复用的浏览器身份:cookies、localStorage、登录态。create session 时引用: ```python await client.sessions.create(CreateSessionRequest( instructions="打开 LinkedIn 收件箱,回复最新一条消息。", profile_id="prof_linkedin_main", )) ``` 第一次在 Console 里手动设置 profile(登录、点 cookies、做你想做的)。后续 session 直接复用。 ## Workspaces **Workspace** = 持久文件系统。agent 可读可写;task 跑完后用签名 URL 取文件。"抓这个站,写 CSV,丢回来"这种场景常用。 ## 接下来 - [API 参考](/web-agent/reference/) —— 每个字段 - [鉴权](/web-agent/getting-started/authentication) —— key、scope、轮换 - [Vibecoding](/web-agent/guides/vibecoding) —— 怎么把这些喂给 IDE --- # 错误码与重试 本页列出 WebAgent 的错误码矩阵,说明哪些可以重试、哪些要直接抛给用户、哪些要回去改代码。 所有错误返回结构一致: ```json { "code": "rate_limit_exceeded", "detail": "Per-key concurrency limit (10) reached.", "extra": { "limit": 10, "active": 10 } } ``` HTTP 状态码告诉你**类别**,`code` 字段是**稳定契约**——switch 在 `code` 上,不要在 `detail` 上(英文文案会随时间变)。 ## 错误码矩阵 | 状态 | code | 重试? | 怎么处理 | |---|---|---|---| | 400 | `bad_request` | ❌ | 改请求体。对照 OpenAPI 检查字段。 | | 401 | `unauthorized` | ❌ | key 缺失 / 格式错 / 过期 / 撤销超过 1 小时宽限期。新建一个。 | | 402 | `insufficient_credits` | ❌ | **Settings → Billing** 充值,或开自动续费。 | | 402 | `budget_exceeded` | ❌ | 任务级 `max_cost_usd` 上限触发。提高额度或拆分任务。 | | 403 | `forbidden` | ❌ | key 有效,但当前 project 不授权访问该资源。 | | 403 | `safety_boundary_violated` | ❌ | Agent 出于安全拒绝。读 `extra.reason`,改写指令。 | | 404 | `session_not_found`、`task_not_found`、`profile_not_found` 等 | ❌ | id 错了,或资源已删除。 | | 409 | `conflict` | ❌ | 状态不一致(如对终态 task 调 `cancel`)。重读状态再决定。 | | 422 | `validation_error` | ❌ | schema 校验失败——`extra.errors[]` 列出有问题的字段。 | | 429 | `rate_limit_exceeded` | ✅ | 遵守 `Retry-After`;没有就指数退避。 | | 429 | `too_many_concurrent_sessions` | ✅ | 等手头 session 释放,或升级套餐。 | | 5xx | `internal_error` | ✅ | 同样调用,指数退避,3–5 次封顶。 | | (网络错) | — | ✅ | 连接重置 / 超时——幂等重试。 | ✅ = 不需要思考就能重试。❌ = 不改东西继续报。 ## 推荐的重试策略 ```python import time, random def with_retries(fn, *, attempts=4, base=0.5, cap=8.0): for i in range(attempts): try: return fn() except WebAgentError as e: if e.code not in {"rate_limit_exceeded", "too_many_concurrent_sessions", "internal_error"}: raise # 不可重试 if i == attempts - 1: raise sleep_s = min(cap, base * 2**i) + random.uniform(0, 0.25) time.sleep(e.retry_after_seconds or sleep_s) ``` Python / TypeScript SDK 默认就内置了这套循环;上面的表是给你直接调 API 时用的。 ## 幂等键(Idempotency-Key){#idempotency} 所有写入接口(`POST /sessions`、`POST /sessions/{sid}/tasks`、`POST /messages` 等)都接受 `Idempotency-Key` 头: ```http POST /v1/projects/proj_demo_0001/do_anything/sessions Idempotency-Key: 9b2f7c1e-…-uuid ``` 24 小时内带同一个 UUID 重发,会拿到**完全相同的响应**(同样的 `session_id`、同样的状态码)——网络抖动也安全。**每个逻辑动作生成一个 UUID,不是每次重试生成一个**。 ## 任务执行期间的错误 Agent 执行过程中报错不一定让任务整个失败——很多是可恢复的: - **工具错误**——通过 `task.action.failed` 推送;agent 自己决定重试 / 换工具 / 整体失败。 - **Captcha / 2FA**——通过 `task.input_request` 推送;你用 `POST /intervene` 回答。 - **硬上限触发**——任务转 `failed`,`error.code = budget_exceeded` 或 `duration_exceeded`,已花的 credits 仍计费。 - **安全拒绝**——任务转 `failed`,`error.code = safety_boundary_violated`,被拒绝那一步不计费。 四种都通过 [SSE 流](/web-agent/concepts/sessions-and-tasks#events) 看得见。 ## SSE 专属故障 | 现象 | 原因 | 解决 | |---|---|---| | 流卡 60 s 以上 | 网络断 / 代理缓冲 | 带 `Last-Event-ID: <最后一个 id>` 重连。 | | `Last-Event-ID` 不生效 | 缓冲过期(> 1 小时) | `GET /sessions/{sid}/tasks/{tid}` 重读状态,从当前继续。 | | 重连后事件重复 | at-least-once 投递 | 按 `id` 去重(每个 task 内单调递增)。 | ## 下一步 - [API 概览](/web-agent/reference/)——所有接口都共享这套约定。 - [Sessions 与 Tasks](/web-agent/concepts/sessions-and-tasks)——上面的生命周期就是规范。 --- # Python SDK 本页说明如何安装、配置并使用官方 `web-agent-sdk` Python 包:起 session、跑 task、订阅事件。 ```bash pip install web-agent-sdk ``` 需要 Python 3.10+。SDK 是 async-first(`asyncio` / `anyio`)。 ## 一个入口:`Client` 用户面 API 都挂在同一个 `Client` 上: ```python from web_agent.v1 import Client ``` | 资源 | 对应产品 | 用法 | |---|---|---| | `client.sessions / messages / events` | DoAnything(开放型)| 自由输入,agent 自己定路径 | | `client.deep_research` | DeepResearch(定型 — 研究→报告)| Standalone API | | `client.web_search` | WebSearch(定型 — 查询→结果)| 默认 `wait=true` 同步糖 | | `client.track` | Track(监控 → snapshot)| 长寿命 monitor + webhook 通道 | > 包名是 `web-agent-sdk`(带连字符),但 import 名是 `web_agent`——同 `python-dateutil` → `dateutil` 的惯例。 ## DoAnything —— 开放型任务 ```python import asyncio from web_agent.v1 import Client from web_agent.v1.types import CreateSessionRequest async def main(): async with Client( api_key="wa_demo_xxxxxxxxxxxxxxxx", project_id="proj_demo_0001", ) as client: session = await client.sessions.create(CreateSessionRequest( instructions="找出 Hacker News 现在 Top 5 的故事,列表返回。", )) task = session.tasks[0] # session 创建会隐式排好首个 task async for event in client.events.stream(session.id, task.id): print(event.type, event.data) if event.type == "task.completed": break asyncio.run(main()) ``` 省略 `api_key` / `project_id` 时自动读 `$WEBAGENT_API_KEY` / `$WEBAGENT_PROJECT_ID`。 ### 「起新 task」 vs 「往运行中 task 塞消息」 ```python # 1. 往当前 task 的对话队列里塞一条消息 # (agent 在下个 ReAct 边界自己决定要不要消费) await client.messages.send( session.id, task.id, content="顺便把每条的评论数也带上。", ) # 2. 在同一个 session 里起一个新 task # (复用 browser / profile / workspace;上一个 task 必须已终态) from web_agent.v1.types import CreateTaskRequest new_task = await client.sessions.create_task( session.id, CreateTaskRequest(instructions="点进第一条,总结评论区。"), ) ``` ### 回应 input request ```python await client.messages.intervene( session.id, task.id, input_request_id="ir_01HXX", response={"solved": True}, ) ``` ### 取消 / 停止 / 列表 ```python await client.sessions.cancel_task(session.id, task.id, reason="user_cancelled") await client.sessions.stop(session.id, force=False) # 软停 session listing = await client.sessions.list(status="running", limit=20) for s in listing.items: print(s.id, s.status) ``` ### 心跳事件 `stream()` 默认过滤心跳事件;做连接健康 UI 时传 `include_heartbeats=True`。续传支持 `Last-Event-ID`: ```python client.events.stream(session.id, task.id, last_event_id="142") ``` ## DeepResearch —— 研究 → 报告 DR 是 Standalone API(pidless:`/v1/deep_research`),项目租户从 Bearer token 解析。 ```python async with Client(api_key="wa_...", project_id="proj_demo") as client: task = await client.deep_research.run( topic="2026 年开源向量数据库格局", depth="deep", # light / standard / deep require_outline_approval=True, # 默认开 outline HITL gate ) print(task["task_id"], task["status"]) ``` 订阅事件流(DR 走的是 DoAnything 的 SSE 通道)+ 响应 outline gate: ```python # task["task_id"] / task["session_id"] 都在创建响应里 async for event in client.events.stream( task["session_id"], task["task_id"], ): if event.type == "task.input_request": # outline 已生成,请求人工批准 await client.deep_research.intervene( task["task_id"], request_id=event.data["request_id"], response="approve", # 或 {"action": "approve_with_edits", "edits": [...]} ) if event.type == "task.completed": break # 拉取产物三件套(final.md / citations.json / confidence.json) artifacts = await client.deep_research.list_artifacts(task["task_id"]) final = await client.deep_research.get_artifact( task["task_id"], artifacts[0]["id"], ) ``` ## WebSearch —— 查询 → 结果 WS 是 project-scoped API。`run()` 默认 `wait=true`,服务器阻塞 ≤30s 后返回 done envelope;超时退化 202,调 `get(task_id)` 轮询。 ```python # 同步形态(默认) result = await client.web_search.run( queries=["best Python ORM 2026"], engines=["tavily"], summarize=True, ) for hit in result["results"]["results"]: print(hit["title"], hit["url"]) # 异步形态 pending = await client.web_search.run_async(queries=["best Python ORM 2026"]) detail = await client.web_search.get(pending["task_id"]) # Refine(同 task 内重搜) await client.web_search.refine( pending["task_id"], text="再加 site:reddit.com 限制重搜", ) ``` ## Track —— 长寿命监控 Track 是 project-scoped API。一个 **monitor** 是长寿命后台 job:cron / interval / event 调度 + 抽取目标 + 通知通道(webhook)。每次 tick 产生一行 `snapshot`;trigger DSL 判定 diff 值得通知时,绑定的通道发送 payload。 ```python mon = await client.track.create( intent="apple.com 上 iPhone 17 Pro 跌破 $999 时通知我", schedule={"kind": "interval", "every_seconds": 3600}, notify_channel={"kind": "callback_url", "url": "https://hooks.example.com/track"}, ) # 生命周期 —— 通过 patch 暂停 / 恢复 / refine: await client.track.pause(mon["id"], reason="人工核对") await client.track.resume(mon["id"]) await client.track.refine(mon["id"], trigger_dsl={"op": "lt", "field": "price", "value": 999}) # 手动触发一次 tick(绕开 schedule);返回 per-tick payload: outcome = await client.track.run_now(mon["id"]) # 拉 snapshot 历史(最新优先): snapshots = await client.track.list_snapshots(mon["id"]) snap = await client.track.get_snapshot(mon["id"], snapshots["items"][0]["id"]) # webhook outbox 历史 + 重投死行: deliveries = await client.track.list_deliveries(mon["id"], include_payload=True) await client.track.retry_delivery(mon["id"], deliveries["items"][0]["id"]) # 取消 monitor(终态): await client.track.cancel(mon["id"]) # 等价 await client.track.delete(mon["id"]) ``` ### Alignment HITL(可选) Supervisor 需要让你澄清意图(如 "你说的是 SKU A 还是 SKU B?")时,monitor 进入 `pending_clarification`,发出 `alignment.input_request` 事件。用 `intervene()` 回答: ```python await client.track.intervene( mon["id"], request_id="req_align_1", response="SKU A", ) ``` 也可以随时往 alignment 队列推自由文本:`client.track.message(mon_id, content="…")`。 ## 错误 SDK 用 typed exception,按类 catch: ```python from web_agent.v1 import ( UnauthorizedError, InsufficientCreditsError, RateLimitedError, ) try: await client.sessions.create(CreateSessionRequest(instructions="…")) except InsufficientCreditsError as e: print("top up:", e.detail, e.extra) ``` 每个 exception 都继承 `ApiError`,带 `code` / `detail` / `extra`,与 [API 错误信封](/web-agent/reference/#错误) 对应。 | 异常类 | HTTP | `code` | |---|---|---| | `UnauthorizedError` | 401 | `unauthorized` | | `ForbiddenError` | 403 | `forbidden`、`safety_boundary_violated` | | `NotFoundError` | 404 | `*_not_found` | | `ConflictError` | 409 | `conflict` | | `ValidationError` | 422 | `validation_error` | | `RateLimitedError` | 429 | `rate_limit_exceeded` | | `InsufficientCreditsError` | 402 | `insufficient_credits` | | `BudgetExceededError` | 402 | `budget_exceeded` | ## 类型 `Session`、`Task`、`Event` 等 DoAnything 资源都是 dataclass,从 `web_agent.v1` 重新导出: ```python from web_agent.v1 import Session, Task, Event, TaskStatus ``` DR / DS / WS 的响应直接是 `dict[str, Any]`(按 OpenAPI 信封原样回传),用键名访问即可(`task["task_id"]` / `task["status"]`)。`mypy --strict` 通过。 ## 接下来 - [TypeScript SDK](/web-agent/sdk/typescript) —— JS / TS 同样的接口 - [错误码与重试](/web-agent/concepts/errors-and-retries) —— 推荐重试策略 + 幂等键 - [Sessions 与 Tasks](/web-agent/concepts/sessions-and-tasks) —— 生命周期 / profile / workspace --- # TypeScript SDK 本页说明如何安装、配置并使用官方 `@web-agent/sdk` Node / 浏览器包:起 session、跑 task、订阅事件。 ```bash npm install @web-agent/sdk # 或 pnpm add @web-agent/sdk / yarn add @web-agent/sdk / bun add @web-agent/sdk ``` 支持 Node 20+ 与现代浏览器。 > **不要把 server 端 `wa_` key 塞进浏览器**——key 是 project 级权限,仅限 server-side 或可信运行时。 ## 一个入口:`Client` 用户面 API 都挂在同一个 `Client` 上: ```typescript import { Client } from "@web-agent/sdk"; ``` | 资源 | 对应产品 | 用法 | |---|---|---| | `client.sessions / messages / events` | DoAnything(开放型)| 自由输入,agent 自己定路径 | | `client.deepResearch` | DeepResearch(定型 — 研究→报告)| Standalone API | | `client.webSearch` | WebSearch(定型 — 查询→结果)| 默认 `wait=true` 同步糖 | | `client.track` | Track(监控 → snapshot)| 长寿命 monitor + webhook 通道 | ## DoAnything —— 开放型任务 ```typescript import { Client } from "@web-agent/sdk"; const client = new Client({ apiKey: process.env.WEBAGENT_API_KEY!, projectId: process.env.WEBAGENT_PROJECT_ID!, }); const session = await client.sessions.create({ instructions: "找出 Hacker News 现在 Top 5 的故事。", }); const task = session.tasks[0]; // session 创建会隐式排好首个 task for await (const event of client.events.stream(session.id, task.id)) { console.log(event.type, event.data); if (event.type === "task.completed") break; } ``` wire 字段一律 snake_case 与 API 对齐;方法名 camelCase。 ### 续传 + 心跳 ```typescript for await (const event of client.events.stream(session.id, task.id, { lastEventId: "142", includeHeartbeats: false, })) { if (event.type === "task.completed") break; } ``` 底层用 `fetch` + 手写 SSE parser——Node 20+ / Bun / Cloudflare Workers / 浏览器都跑得起来。 ### 「起新 task」 vs 「往运行中 task 塞消息」 ```typescript // 1. 塞消息进当前 task 的对话队列 await client.messages.send(session.id, task.id, { content: "顺便把每条的评论数也带上。", }); // 2. 在同一个 session 里起新 task const followup = await client.sessions.createTask(session.id, { instructions: "点进第一条,总结评论区。", }); ``` ### 回应 input request ```typescript await client.messages.intervene(session.id, task.id, { kind: "answer_input_request", input_request_id: "ir_01HXX", response: { solved: true }, }); ``` `kind` 是 discriminator,同一个端点也处理 `take_control` / `release_control`——见 [Take Control](/web-agent/concepts/sessions-and-tasks#input-request)。 ### 取消 / 停止 / 列表 ```typescript await client.sessions.cancelTask(session.id, task.id, { reason: "user_cancelled" }); await client.sessions.stop(session.id, { force: false }); const list = await client.sessions.list({ status: "running", limit: 20 }); list.items.forEach((s) => console.log(s.id, s.status)); ``` ## DeepResearch —— 研究 → 报告 DR 是 Standalone API(pidless:`/v1/deep_research`),项目租户从 Bearer token 解析。 ```typescript const task = await client.deepResearch.run({ topic: "2026 年开源向量数据库格局", depth: "deep", // light / standard / deep requireOutlineApproval: true, // 默认开 outline HITL gate }); // 订阅事件流(DR 走 DoAnything 的 SSE 通道)+ 响应 outline gate for await (const event of client.events.stream( task.session_id as string, task.task_id as string, )) { if (event.type === "task.input_request") { await client.deepResearch.intervene(task.task_id as string, { requestId: (event.data as { request_id: string }).request_id, response: "approve", // 或 { action: "approve_with_edits", edits: [...] } }); } if (event.type === "task.completed") break; } // 拉取产物三件套(final.md / citations.json / confidence.json) const artifacts = await client.deepResearch.listArtifacts(task.task_id as string); const final = await client.deepResearch.getArtifact( task.task_id as string, artifacts[0]!.id as string, ); ``` ## WebSearch —— 查询 → 结果 WS 是 project-scoped API。`run()` 默认 `wait: true`,服务器阻塞 ≤30s 后返回 done envelope;超时退化 202,调 `get(taskId)` 轮询。 ```typescript // 同步形态(默认) const result = await client.webSearch.run({ queries: ["best TypeScript ORM 2026"], engines: ["tavily"], summarize: true, }); // 异步形态 const pending = await client.webSearch.runAsync({ queries: ["best TypeScript ORM 2026"], }); const detail = await client.webSearch.get(pending.task_id as string); // Refine(同 task 内重搜) await client.webSearch.refine(pending.task_id as string, { text: "再加 site:reddit.com 限制重搜", }); ``` ## Track —— 长寿命监控 Track 是 project-scoped API。一个 **monitor** 是长寿命后台 job:cron / interval / event 调度 + 抽取目标 + 通知通道(webhook)。每次 tick 产生一行 `snapshot`;trigger DSL 判定 diff 值得通知时,通道发送 payload。 ```typescript const mon = await client.track.create({ intent: "apple.com 上 iPhone 17 Pro 跌破 $999 时通知我", schedule: { kind: "interval", every_seconds: 3600 }, notifyChannel: { kind: "callback_url", url: "https://hooks.example.com/track" }, }); // 生命周期 —— 通过 patch 暂停 / 恢复 / refine: await client.track.pause(mon.id as string, { reason: "人工核对" }); await client.track.resume(mon.id as string); await client.track.refine(mon.id as string, { triggerDsl: { op: "lt", field: "price", value: 999 }, }); // 手动触发一次 tick(绕开 schedule): const outcome = await client.track.runNow(mon.id as string); // snapshot 历史(最新优先): const snaps = await client.track.listSnapshots(mon.id as string); const snap = await client.track.getSnapshot( mon.id as string, snaps.items[0]!.id as string, ); // webhook outbox + 重投: const deliveries = await client.track.listDeliveries(mon.id as string, { includePayload: true, }); await client.track.retryDelivery( mon.id as string, deliveries.items[0]!.id as number, ); // 取消 monitor(终态): await client.track.cancel(mon.id as string); // 等价:client.track.delete(...) ``` ### Alignment HITL(可选) Supervisor 需要让你澄清意图时,monitor 进入 `pending_clarification`,发出 `alignment.input_request` 事件。用 `intervene()` 回答: ```typescript await client.track.intervene(mon.id as string, { requestId: "req_align_1", response: "SKU A", }); ``` 也可以随时往 alignment 队列推自由文本:`client.track.message(monId, { content: "…" })`。 ## 错误 ```typescript import { ApiError, InsufficientCreditsError, RateLimitedError, UnauthorizedError, } from "@web-agent/sdk"; try { await client.sessions.create({ instructions: "…" }); } catch (err) { if (err instanceof InsufficientCreditsError) { console.log("top up:", err.detail, err.extra); } else if (err instanceof ApiError) { console.log(err.code, err.statusCode, err.detail); } else { throw err; } } ``` 每个错误类都继承 `ApiError`,暴露 `code` / `statusCode` / `detail` / `extra`,对应 [API 错误信封](/web-agent/reference/#错误)。 ## 类型 DoAnything 的 request / response 类型都是顶层 export: ```typescript import type { Session, Task, Event, EventType, CreateSessionRequest, CreateTaskRequest, InterveneRequest, TaskStatus, SessionStatus, TerminalReason, } from "@web-agent/sdk"; ``` DR / DS / WS 的响应是 `Record`(按 OpenAPI 信封原样回传),用键名访问(`task.task_id` / `task.status`)。各资源也导出自己的 option 类型(`DRRunOptions` / `DSRunOptions` / `WSRunOptions`)。 ## 接下来 - [Python SDK](/web-agent/sdk/python) —— Python 同样的接口 - [错误码与重试](/web-agent/concepts/errors-and-retries) —— 推荐重试策略 + 幂等键 - [Sessions 与 Tasks](/web-agent/concepts/sessions-and-tasks) —— 生命周期 / profile / workspace --- # cURL 与原生 HTTP 本页给出 WebAgent 在原生 HTTP 上的常用调用模式——任何语言只要能发 HTTPS / JSON 就能用,不依赖官方 SDK。 ## 起 session ```bash curl https://api.web-agent.asix.inc/v1/projects/proj_demo_0001/do_anything/sessions \ -H "Authorization: Bearer wa_demo_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "instructions": "找出 Hacker News 现在 Top 5 的故事。", "model": "claude-sonnet-4.6", "max_cost_usd": "0.50" }' ``` ## 订阅事件流(SSE) ```bash curl -N \ -H "Authorization: Bearer wa_demo_xxxxxxxxxxxxxxxx" \ "https://api.web-agent.asix.inc/v1/projects/proj_demo_0001/do_anything/sessions/sess_demo_0001/tasks/task_demo_0001/events" ``` 断线续传: ```bash curl -N \ -H "Authorization: Bearer wa_demo_xxxxxxxxxxxxxxxx" \ -H "Last-Event-ID: 142" \ "…/events" ``` ## 追加消息 ```bash curl https://api.web-agent.asix.inc/v1/projects/proj_demo_0001/do_anything/sessions/sess_demo_0001/tasks/task_demo_0001/messages \ -H "Authorization: Bearer wa_demo_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "content": "顺便把每条的评论数也带上。" }' ``` ## 回应 input request ```bash curl https://api.web-agent.asix.inc/v1/projects/proj_demo_0001/do_anything/sessions/sess_demo_0001/tasks/task_demo_0001/intervene \ -H "Authorization: Bearer wa_demo_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "kind": "answer_input_request", "input_request_id": "ir_01HXX", "response": { "solved": true } }' ``` `kind` 是 discriminator——同一个端点也接受 `take_control` / `release_control`,见 [Take Control](/web-agent/concepts/sessions-and-tasks#input-request)。 ## 取消 task ```bash curl -X POST https://api.web-agent.asix.inc/v1/projects/proj_demo_0001/do_anything/sessions/sess_demo_0001/tasks/task_demo_0001/cancel \ -H "Authorization: Bearer wa_demo_xxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "reason": "user_cancelled" }' ``` ## 列 sessions ```bash curl "https://api.web-agent.asix.inc/v1/projects/proj_demo_0001/do_anything/sessions?status=running&limit=20" \ -H "Authorization: Bearer wa_demo_xxxxxxxxxxxxxxxx" ``` ## 错误 非 2xx 响应都是 JSON,带稳定 `code`: ```json { "code": "insufficient_credits", "detail": "Project balance below the minimum required ($0.50).", "extra": { "balance_usd": "0.12", "required_usd": "0.50" } } ``` 完整列表见 [API 概览 → 错误](/web-agent/reference/#错误)。 ## 幂等 ```bash curl … -H "Idempotency-Key: $(uuidgen)" ``` 同 key 重发返回同响应——网络异常时安全 retry。 --- # API 概览 本页讲 WebAgent 所有端点共享的约定。具体每个端点字段请直接看 [OpenAPI 3.1 spec](/openapi/v1.json)——SDK 和 Console 的 *Get Code* 对话框都是从这里生成。 ## Base URL ``` https://api.web-agent.asix.inc ``` 所有资源 path 以 project 为前缀: ``` /v1/projects/{project_id}/... ``` ## 鉴权 `Authorization` header 带 bearer token,详见 [鉴权与 API key](/web-agent/getting-started/authentication): ```http Authorization: Bearer wa_xxxxxxxxxxxxxxxxxxxxxxxx ``` ## 错误 JSON 响应体 + HTTP 状态 + 稳定的 `code` 字段(可程序判断): ```json { "code": "session_not_found", "detail": "Session sess_demo_0001 not found.", "extra": { "session_id": "sess_demo_0001" } } ``` | 状态 | 常见 code | |---|---| | 400 | `bad_request` | | 401 | `unauthorized` | | 402 | `insufficient_credits`、`budget_exceeded` | | 403 | `forbidden`、`safety_boundary_violated` | | 404 | `session_not_found`、`task_not_found`、`profile_not_found`…… | | 409 | `conflict` | | 422 | `validation_error` | | 429 | `rate_limit_exceeded`、`too_many_concurrent_sessions` | | 5xx | `internal_error` | ## 限流 - per-key 并发 session 数——按 plan - per-key 请求频率——滑动窗;超时返回 `429` + `Retry-After` - per-project 月额度——80% 软警告,100% 硬停 ## 分页 list 类端点全是 cursor 分页: ```http GET /v1/projects/{pid}/do_anything/sessions?limit=50&cursor=eyJ… ``` 响应里带 `next_cursor`(最后一页是 `null`)。`limit` 上限 100。 ## 幂等 变更类端点(`POST /sessions`、`POST /messages`……)支持 `Idempotency-Key` header。同 UUID 重发返回同响应——retry 安全。 ## SSE 约定 流式端点(`…/events`)发 JSON 编码 SSE 事件,带数字 `id`。断线后用 `Last-Event-ID: ` 续传,server 重放该 id 之后的全部事件。 ## 接下来 - [OpenAPI spec](/openapi/v1.json) —— 每个端点、每个字段,机器可读 - [Sessions 与 Tasks](/web-agent/concepts/sessions-and-tasks) —— 资源模型 - [错误码与重试](/web-agent/concepts/errors-and-retries) —— 完整错误码矩阵 --- # WebAgent Vibecoding 如果你正在 IDE 里用 LLM 写代码——Cursor、Claude Code、Aider、Continue……——你只需把 WebAgent 当作一组 URL 喂给它,它会替你写集成。 ## 三个 URL 必记 | URL | 是什么 | 喂给谁 | |---|---|---| | [`/web-agent/llms.txt`](/web-agent/llms.txt) | 全站每页 + 一句描述的目录 | 任何 LLM agent——快速扫一眼 | | [`/web-agent/llms-full.txt`](/web-agent/llms-full.txt) | 整站文档拼一个 markdown 文件(约 200 KB) | 长上下文模型——直接当 system prompt 粘贴 | | [`/openapi/v1.json`](/openapi/v1.json) | OpenAPI 3.1 spec(语言无关) | 代码生成型 agent——它能从这个生成强类型 client | 这三个 URL 永久稳定。即使内部页面改名也不会变。 ## 拿来即用 prompt 复制到你的 IDE 系统 prompt / 规则文件 / 第一条消息: ``` 你正在集成 WebAgent。参考文档: - https://docs.web-agent.asix.inc/zh/llms-full.txt (整站文档单文件,中文) - https://docs.web-agent.asix.inc/openapi/v1.json (OpenAPI 3.1 spec) API 约定: - Base URL:https://api.web-agent.asix.inc - Bearer 鉴权:header `Authorization: Bearer wa_…` - path 隔离 project:/v1/projects/{project_id}/... - wire 字段一律 snake_case;decimal 用 JSON 字符串("10.00" 不是 10.00) - 大多数变更端点支持 Idempotency-Key SDK 包: - Python: `pip install web-agent-sdk` - TypeScript: `npm install web-agent-sdk` 两边 SDK 都自带 Last-Event-ID SSE 重连。优先用 SDK,除非用户要求纯 HTTP。 写代码前一律先读 OpenAPI spec——绝不靠猜字段名。 ``` ## Cursor `.cursor/rules/webagent.md`: ```markdown --- description: WebAgent 集成约定 globs: ["**/*.{ts,tsx,py}"] --- 写 WebAgent 代码时遵循 https://docs.web-agent.asix.inc/zh/llms-full.txt 字段名以 https://docs.web-agent.asix.inc/openapi/v1.json 为准——不允许猜 默认用官方 SDK(`web-agent-sdk`),用户特别要求才用 raw HTTP ``` ## Claude Code 加到项目 `CLAUDE.md`: ```markdown ## WebAgent 集成 参考:https://docs.web-agent.asix.inc/zh/llms-full.txt OpenAPI:https://docs.web-agent.asix.inc/openapi/v1.json SDK:`web-agent-sdk`(Python 与 TypeScript) wire 字段全 snake_case。订阅 task 事件用 SDK 的 `.stream()`,自带 `Last-Event-ID` 重连。 ``` ## Console "Get Code" 对话框 最快拿到能跑的代码:打开 [Console](https://console.web-agent.asix.inc/new),填表,点 **Get Code**。四个 tab(给 LLM agent 的 Prompt / Python / TypeScript / cURL),全部带你的真实 key 和当前配置。粘贴进编辑器即可。 ## 为什么这套有效 - URL 由我们维护,跨大版本不会 404 - llms-full.txt 是 markdown 不是 HTML——每个 LLM 都能干净吃下 - OpenAPI spec 是 SDK / Console 共同的单一真相,没有漂移 ## 接下来 - [Quickstart](/web-agent/getting-started/quickstart) —— 5 分钟跑通第一个 task - [API 参考](/web-agent/reference/) —— 交互式 + Try-it