跳到主要内容

Notte 总览 — 这是什么 · 全景图 · 阅读地图

30 秒导读: Notte 是一个全栈 web 自动化 agent 框架——你用一句自然语言("去 Hacker News 抓前 5 条帖子")交给它,它就驱动一个真实浏览器,边看网页边推理,一步步把任务做完。它的设计目标是三个词:快(speed)、省(cost)、稳(reliability);秘诀是"能脚本化的部分就脚本、只在真正需要判断的地方才调 AI"的混合模式,官方称能省下 50%+ 的 LLM 成本。

本章是这套文档的顶层入口:读完你应该能讲清"Notte 是什么、大概怎么转、8 个包各管什么",并知道接下来该翻哪一章。任何单一机制的细节都留给后面各章,本章只给全局认知与路由。


1. 这是什么(零基础也能懂)

一句话定义

Notte 让 AI 像人一样操作真实网页:打开页面、看内容、点按钮、填表单、翻页、抓数据——你只需要用自然语言描述目标,它负责把目标翻译成一连串真实的浏览器操作。

解决谁的什么问题

假设你要做一件"网页上的重复活"——比如批量在某网站登录并导出报表、把一堆商品页的价格抓成表格、自动 RSVP 一个 Google 表单。传统做法有两条路,各有痛点:

  • 纯脚本(Playwright/Selenium):快且便宜,但——页面一改版、选择器一变,脚本就崩,而且写起来累。
  • 纯 AI agent(每步都问大模型):灵活、抗变化,但慢又贵——每一步点击都要烧一次 LLM 调用。

Notte 的立场是"两者混着来":确定的步骤用脚本(session.execute(type="goto", ...)),只有需要临场判断的地方才交给 agent 推理(agent.run(task=...))。这就是它主打 speed / cost / reliability 的根。

它能做什么(功能一览)

能力白话
跑 web agent给一句自然语言任务,AI 自己在网站上完成
结构化输出传一个 Pydantic 模型,AI 按你的字段格式返回数据
站点交互原语observe(看当前页)/ execute(点、填、跳)/ scrape(抓数据),与 Playwright 兼容
混合工作流脚本 + agent 混排,deterministic 部分脚本、reasoning 部分交给 AI
凭据保险库登录密码/MFA 存进 Vault,注入表单时不泄露给 LLM
数字身份 Persona生成带独立邮箱/手机号、能自动过 2FA 的身份,用于注册流程
隐身会话自动解 CAPTCHA、配代理、反检测(托管服务提供)

用起来什么样

最小的本地例子(开源特性,自带 LLM key 即可跑)——摘自 README.md:48-56

import notte
from dotenv import load_dotenv
load_dotenv()

# 开一个真实浏览器会话(headless=False 会弹出可见窗口)
with notte.Session(headless=False) as session:
# 挂一个 agent:选推理模型、限定最多 30 步
agent = notte.Agent(session=session, reasoning_model='gemini/gemini-2.5-flash', max_steps=30)
# 交一句自然语言任务,剩下它自己干
response = agent.run(task="doom scroll cat memes on google images")

想切到托管模式(浏览器跑在 Notte 云上,还带隐身/代理/保险库等高级特性)?几乎只需换个 import——README.md:62-71

from notte_sdk import NotteClient
import os

client = NotteClient(api_key=os.getenv("NOTTE_API_KEY"))
with client.Session(open_viewer=True) as session:
agent = client.Agent(session=session, reasoning_model='gemini/gemini-2.5-flash', max_steps=30)
response = agent.run(task="doom scroll cat memes on google images")

README.md:73 点破了这个设计意图:"先在本地实验,然后 drop-in 替换 import 就切到 SDK、拿到托管浏览器 + 高级特性"。本地的 notte.Session/notte.Agent 与托管的 client.Session/client.Agent 保持同构接口——这条主线在 05-sdk-deployment.md 细讲。

一句话直觉

把 Notte 想成"给 AI 装了一双能看网页、能动鼠标的手眼,再配一个只在迷路时才叫醒的向导"——大部分路它自己走脚本,遇到岔路口才点亮大模型。


2. 顶层全景(它大概怎么转)

一张顶层图

怎么读这张图:中间竖轴是一次 agent step 的四拍(观察→推理→执行→验证),左边是驱动它的 Agent 循环,右边是承载它的 Session 与真实网页;箭头是数据/控制流向,循环每步都会重置对话再喂给 LLM。

┌──────────────────────────────────────────────┐
一句自然语言 │ Agent 主循环 (_run) │
task="…" ───────▶│ while 步数 < max_steps: step() │
└───────────────────────┬──────────────────────┘
│ 每一步 step()

┌───────────────── 一次 STEP 的四拍 ─────────────────┐
│ │
│ ① 观察 session.aobserve() │ ┌──────────────┐
│ └─ 快照 DOM → 列出"带 ID 的动作空间" ◀────────┼──────│ NotteSession │
│ │ │ ├ Browser │
│ ② 推理 llm.structured_completion(messages) │ │ │ (Playwright)│
│ └─ LLM 读页面文本,只出【一个】动作 │ │ ├ 感知管线 │
│ (含 memory / state / 下一步 action) │ │ │ perception │
│ │ │ └ 控制器 │
│ ③ 执行 session.aexecute(action) ──────────────┼─────▶│ execute │──▶ 真实网页
│ └─ 把 action ID 落到 Playwright 点击/填表 │ └──────────────┘ │
│ │ │
│ ④ 验证 仅当 LLM 说"完成"时: │ 页面变化 ◀──────────┘
│ validator.validate() = LLM 当裁判 │
│ ├ 通过 → 结束,返回 answer │
│ └ 不通过 → 回灌"验证失败",继续下一步 │
└────────────────────────────────────────────────────┘
执行结果 / 观察结果 → 回灌进对话 → 进入下一 step

8 个 workspace 包各管什么

Notte 是 uv workspace 多包仓库,pyproject.toml:36-38 声明成员为 packages/* + 根。八个包按"从底层浏览器到对外形态"分层:

干什么
notte-core地基:数据模型(动作 BaseAction、观察 Observation、动作空间 ActionSpace)、配置 NotteConfig、凭据抽象 BaseVault、轨迹 Trajectory
notte-browser浏览器与会话:NotteSession——快照 DOM、感知成动作空间(observe)、把动作落到 Playwright(execute)、抓数据(scrape)
notte-agent大脑:NotteAgent 主循环、FalcoPrompt/FalcoPerceptionCompletionValidator(LLM 裁判);两种 agent 风格 falco(文本)/gufo(视觉)
notte-llm模型接入:LLMEngine、结构化补全、用量追踪 LlmUsageDictTracer(底层走 litellm,兼容各家模型)
notte-sdk对外 SDK:NotteClient——把 Session/Agent/Vault/scrape 映射到托管 REST API,接口与本地同构
notte-integrations第三方集成:外部浏览器 provider、通知器、存储等可插拔组件
notte-eval评测:跑 benchmark(对应 README 里那张 WebVoyager 排行榜)
notte-mcpMCP 服务:用 FastMCP 把 observe/execute/scrape/agent 暴露成 MCP 工具,供别的 LLM 客户端调用

顶层入口在 src/notte/__init__.py:1-18:它把 NotteSession 重命名为 notte.Session、把 notte_agent.Agent 暴露成 notte.Agent、把 NotteClient 暴露成 notte.Client——所以你 import notte 就能拿到本地/托管两套入口。

主线走一遍(高层,不进代码)

一次 agent.run(task=...) 的生命周期,端到端是这样(各环节的真源码见下方"代码地图",机制细节见对应章节):

  1. 进入循环agent.arun() 校验请求后交给 _run()while trajectory.num_steps < max_steps 反复调 step()packages/notte-agent/src/notte_agent/agent.py:390 _run:401 循环)。
  2. 观察step()observe_and_completion()session.aobserve(),把当前 DOM 快照成一份带 ID 的页面文本 + 动作空间agent.py:123 observe_and_completion;感知细节 → 01-perception.md)。
  3. 组消息 + 推理get_messages() 把系统提示、任务、历史轨迹、当前页面拼成对话,交给 llm.structured_completion(),LLM 只输出一个动作(含 memory/state/next action)(agent.py:273 get_messages:131 调用 LLM)。
  4. 执行 — 按动作类型分派:普通动作走 session.aexecute(action) 落到 Playwright(agent.py:248-262;动作与执行 → 03-actions-execution.md)。
  5. 验证 — 只有当 LLM 声称"任务完成"(CompletionAction(success=True))时,才叫 validator.validate() 让另一个 LLM 当裁判核对;通过才真结束,否则把"验证失败"写回轨迹继续跑(agent.py:207-247)。
  6. 回灌 — 每步的观察/执行/验证结果都 append 进 Trajectory,下一步 get_messages() 会把它们读回对话——这样 agent 才有"记忆"。整体主循环 → 02-agent-loop.md

3. 阅读地图(按 01→05 顺序)

建议从上到下顺读,每章由浅入深、彼此用相对链接互链、不重复内容:

章节讲什么建议谁读
01-perception.md感知层:DOM 怎么被快照、过滤、编号,变成 LLM 能读的"带 ID 的动作空间";fastdeep 两种感知的取舍想懂"AI 到底看到了什么"的人;所有人(这是理解全局的前提)
02-agent-loop.mdAgent 主循环的四拍、每步为什么重置对话、轨迹如何充当记忆、连续失败如何熔断想懂控制流/为什么这样省 token 的人
03-actions-execution.md动作体系(BaseAction 家族)与执行:从一个 action ID 怎么定位并落到 Playwright 的点击/填表要扩展动作、或调试"点错元素"的人
04-enterprise.md企业级增强:凭据保险库(不泄露给 LLM)、结构化抓取、表单填充、混合脚本与 AgentFallback 兜底要上生产、处理登录/敏感数据/成本的人
05-sdk-deployment.md对外两种形态:本地引擎 vs 托管 SDK(换个 import 即切换)、以及 MCP 服务把能力暴露给别的 LLM要部署、集成到别的 agent/IDE 的人

4. 巧妙之处速览

这是读者要带走的"精华",每条一句话点出妙在哪,并指向后续章节深挖:

  • ID 化的动作空间 — 感知层把可交互元素统一编号(* \click(id=B3)`: 登录按钮),LLM 只需吐一个 ID,不必生成脆弱的 CSS 选择器或坐标。真源码 packages/notte-core/src/notte_core/space.py:122id={action.id}`)。→ 01-perception.md
  • fast / deep 双感知PerceptionType = Literal["fast", "deep"]packages/notte-core/src/notte_core/common/config.py:266),便宜任务用 fast 文本感知、难任务才上 deep(含视觉),是省钱的第一道闸。→ 01-perception.md
  • 每步重置对话get_messages() 每个推理步都从头重建对话而非无限追加(agent.py:277 注释 "For every re[a]sonning model step, the conversation is reset"),用轨迹回放代替长上下文,控制 token 膨胀。→ 02-agent-loop.md
  • LLM 当裁判 — agent 说"我做完了"不算数,CompletionValidator 用另一次 LLM 调用核对任务是否真完成,不过则驳回继续跑(packages/notte-agent/src/notte_agent/common/validator.py:39 CompletionValidatoragent.py:207-247)。→ 02-agent-loop.md
  • Vault 不泄露凭据 — 密码/MFA 存 Vault,注入表单时才替换真值,并给 LLM 输入与截图都打码(agent.py:81-88 vault setup,:90 action_with_credentials)。→ 04-enterprise.md
  • 混合脚本 + 兜底 — 确定步骤 session.execute(...) 脚本、临场判断才 agent.run(...);脚本失败还能用 AgentFallback 让 agent 优雅补救(README.md:280-305)。→ 04-enterprise.md
  • 本地/托管同构 — 本地引擎与托管 SDK 共享同一套 Session/Agent 接口,README.md:73 明说 "drop-in replace the import"。→ 05-sdk-deployment.md

5. 顶层代码地图(导航索引)

给要跳进源码的人/agent 的入口表(相对克隆根;符号名比行号更抗漂移,可直接 grep):

主题文件符号
顶层入口(本地/托管别名)src/notte/__init__.pySessionAgentClientNotteClient
8 包 workspace 声明pyproject.toml[tool.uv.workspace] members(:36-38)
Agent 门面(选 falco/gufo、挂 vault/persona)packages/notte-agent/src/notte_agent/main.pyAgentAgentType(默认 FALCO,:41)
主循环packages/notte-agent/src/notte_agent/agent.pyNotteAgent._run(:390)、step(:144)
一步:观察+推理packages/notte-agent/src/notte_agent/agent.pyobserve_and_completion(:123)、get_messages(:273)
falco agent(文本风格)packages/notte-agent/src/notte_agent/falco/agent.pyFalcoAgent(:15)
会话:观察packages/notte-browser/src/notte_browser/session.pyaobserve(:362)、_aobserve_impl(:375)
会话:执行packages/notte-browser/src/notte_browser/session.pyaexecute(:555+ 一组重载)
感知渲染(带 ID 的动作空间)packages/notte-core/src/notte_core/space.pyActionSpace.render_actions(:105-129)
感知类型 fast/deeppackages/notte-core/src/notte_core/common/config.pyPerceptionType(:266)
LLM 裁判packages/notte-agent/src/notte_agent/common/validator.pyCompletionValidator.validate(:96)
SDK 客户端(托管)packages/notte-sdk/src/notte_sdk/client.pyNotteClient(:28)、Session/Agent/Vault/scrape(:84+)
MCP 服务packages/notte-mcp/src/notte_mcp/server.pyFastMCP(:94)

引用锚定的 commit:accc0bb38f7d35a499c408032cea2342ef50d73d(见 frontmatter sourceCommit)。各机制的深入走读,请进对应章节。