跳到主要内容

数据截至 (上游 commit 2689884a6257)

OpenAdapt — 架构与原理

30 秒导读: OpenAdapt 想解决的是「有些活只能在别人的图形界面里干,没有 API 可调」。它的做法是:让人演示一遍,把这次演示变成一段能重复跑的程序。本仓库(OpenAdaptAI/OpenAdapt)在这个 commit 上已经不再包含那个编译器/运行时——它是安装入口和统一命令行;真正的引擎在 openadapt-flow;而 2023–2025 那套完整的「录屏 + 录输入 → 大模型改写 → 注入回放」单体代码被原样冻结在 legacy/


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

一句话定义

OpenAdapt 是一个 GUI 流程自动化框架:你用鼠标键盘把一件事做一遍,它录下来,之后它能自己再做一遍。

解决谁的什么问题

设想你在一家诊所做行政:每天要在一个十年前的桌面病历系统里,把二十个病人的随访记录挨个敲进去。这个系统没有 API,没有导入按钮,厂商也不会为你开一个。

能选的路只有三条:

路子做法卡在哪
传统 RPA人工写脚本,写死坐标或控件 ID界面一改就全崩,脚本自己不知道自己错了
通用 computer-use agent每一步都让大模型看截图、决定点哪慢、贵、不确定,同一个输入两次结果可能不同
OpenAdapt演示一次 → 编译成程序 → 之后按程序跑需要先「演示」,且只在被演示过的流程上可靠

它能做什么(功能清单)

  • :同时录鼠标键盘动作、屏幕截图/视频、当前活动窗口的无障碍树(accessibility tree,操作系统暴露给读屏软件的那棵控件树),浏览器里还能额外录 DOM 事件。
  • :把原始事件流降噪——两次快速点击合成一个 doubleclick,几百个鼠标移动事件压成几个。
  • :按策略重新执行。策略从「原样重放坐标」到「让多模态模型按自然语言指令改写这次流程」都有。
  • :回放/分享前把截图和文本里的个人信息(PII/PHI)打码。
  • :仓库自己的一套发布纪律——防止把客户专属内容泄漏进开源仓库、防止版本清单和真实发布漂移。

用起来什么样

今天的入口(引擎在另一个包里,本克隆只有转发壳):

pip install 'openadapt[browser]'
openadapt quickstart # 跑一遍内置合成教程:录 → 编译 → 回放 → 验证

冻结的 legacy 单体用起来是这样(见 legacy/openadapt/record.py:1-7legacy/openadapt/strategies/visual.py:42-45):

python -m openadapt.record "把这三个病人的随访记录填进去"
python -m openadapt.replay VisualReplayStrategy --instructions "改成填另外两个病人"

注意第二条命令的形状:录一遍 + 一句自然语言修改意图 = 一次新的执行。这是 OpenAdapt 最初的核心主张。

一句话直觉

把它想成会看屏幕的宏录制器

  • 老式宏录的是「在 (832, 419) 点一下」——窗口一挪就点空。
  • OpenAdapt 录的是「在那个叫『保存』的按钮上点一下」——下次它重新在屏幕上找这个按钮。

再加一层今天产品才强调的东西:点击成功不等于事情办成。所以运行时会用另一条独立通道(比如一个只读 API)去确认那条记录真的写进去了,确认不了就停下来,而不是接着往下点。


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

先看清楚:这个仓库现在装的是什么

这是读这份文档最容易踩空的一步。仓库根目录下的 openadapt/ 只有 3 个 Python 文件、1327 行,里面没有任何录制或回放实现

pip install openadapt


┌───────────────────────────────┐
│ ① 启动器(本仓库 openadapt/) │ openadapt/cli.py
│ 统一命令入口 │ openadapt/__init__.py
│ 未包装的命令原样转发 │
└───────────────┬───────────────┘
│ 进程内调用 flow_main(argv)

┌───────────────────────────────┐
│ ② openadapt-flow(PyPI 依赖, │ ← 编译器 + 受管运行时
│ 不在本克隆里) │ 录制/编译/回放/验证都在这
└───────────────────────────────┘

同一个仓库里另外两块,和上面这条链是并列的:

┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ ③ legacy/(冻结的单体 v0.46.0) │ │ ④ scripts/ + .github/ │
│ 录制/回放/脱敏的全部实现 │ │ 发布治理与开源边界守卫 │
└─────────────────────────────────┘ └─────────────────────────────────┘

部件一句话职责

部件干什么在哪个文件
统一 CLIopenadapt <verb> 转成引擎的 argv 再调用openadapt/cli.py
懒加载导出from openadapt import Recorder 时才去 import 重依赖openadapt/__init__.py:21-110(__getattr__)
版本单一来源从已安装分发元数据读版本,不硬编码openadapt/version.py:13-19
legacy 录制多线程采集 + 多进程写库legacy/openadapt/record.py:1269(record)
legacy 事件处理归并降噪成干净动作序列legacy/openadapt/events.py:878(merge_events)
legacy 回放抽象策略基类 + 六种具体策略legacy/openadapt/strategies/base.py:17(BaseReplayStrategy)
legacy 数据模型SQLAlchemy 表:录制/动作/截图/窗口/浏览器事件legacy/openadapt/models.py:46,129,629,755,924
边界守卫客户专属内容进公开仓库就让 CI 红scripts/check_source_boundary.py:243(scan)
平台清单从 PyPI 真实数据生成版本/哈希清单scripts/generate_platform_manifest.py:963(generate)
发布健康探测「已合并但没发版」「有标签没发布」scripts/check_release_health.py:265(evaluate)

主线 A:今天跑一条命令会发生什么

一句话:壳不做事,壳只负责把参数原样递给引擎,并保住引擎的退出码。

openadapt flow replay bundle --backend rdp --rdp-host 10.0.0.7

│ click 解析到 `flow` 组;`replay` 不是本仓库显式包装的子命令

_FlowPassthroughGroup.get_command ← 现造一个「吞掉所有未知选项」的命令


_run_flow(["replay", "bundle", "--backend", "rdp", ...])


openadapt_flow.__main__.main(argv) ← 引擎(不在本克隆)


sys.exit(引擎退出码)

为什么要这么绕,以及这个设计避开了什么坑,见 01-launcher-and-cli.md

主线 B:legacy 里一次「录制 → 回放」的完整旅程

这条线才是 computer-use 的正题。怎么读这张图:从上往下是时间顺序,上半段是录制期,下半段是回放期。

【录制期】人操作 GUI

├─ pynput 键鼠钩子 ──┐
├─ 循环截屏 ─────────┼──→ event_q(单一有序队列)
└─ 轮询活动窗口+a11y ┘ │

process_events:给每个「动作」贴上
「它发生时最近的那张截图 + 那个窗口」


每种事件一个独立写进程 ──→ SQLite

【回放期】
events.get_events:归并降噪 ──→ 干净的动作序列


策略:把「坐标」换成「元素描述」,在**当前**屏幕上重新定位


playback.play_action_event ──→ pynput 注入鼠标/键盘

每一段的原理分别在 020304 三章。


3. 诚实边界(先说清楚,免得白读)

这份文档只写这个克隆里真实存在的代码。以下内容在本 commit 的克隆里看不到实现:

  • openadapt-flow 的编译器、确定性回放、效果验证、失败即停、受管修复——README 和 CLI 帮助文本描述了它们的契约,但代码在另一个仓库。凡是本文档引用 README 的地方,都会标明「这是声明,不是本克隆里的实现」。
  • openadapt-capture / openadapt-ml / openadapt-evals 等兄弟包同理:本仓库只有对它们的导入和 CLI 包装。
  • 桌面应用 openadapt-desktop 不在此仓库。

所以:想学 GUI 自动化的真实工程细节,读 legacy/;想学一个开源项目怎么管发布边界,读 scripts/;想学一个薄壳 CLI 怎么不给自己挖坑,读 openadapt/cli.py


4. 阅读地图

你想弄明白读这一章
这个包为什么这么薄,壳怎么写才不拖累引擎01-launcher-and-cli.md
怎么在桌面上同时录下动作、画面和控件树,还不互相拖慢02-legacy-recording.md
原始事件流噪声怎么消,双击怎么从两次按下里认出来03-legacy-event-processing.md
界面挪了位置,怎么还能点对地方04-legacy-replay-strategies.md
截图和输入里的隐私怎么擦05-privacy-and-scrubbing.md
一个多仓库开源项目怎么防止版本谎报和内容泄漏06-release-governance.md
有什么值得抄走的、它在哪会崩、和别的 GUI agent 比如何07-takeaways-and-boundaries.md

建议顺序:

  • 完全没接触过 GUI agent 的人:02 → 03 → 04 → 07。03 不能跳——04 章讲回放时会直接用到 03 章建立的父子事件树,05 章的脱敏编排也要用到它。
  • 做工程/发布的人:01 → 06。这两章讲的是薄壳设计和 CI 守卫,和 GUI 自动化本身无关。

5. 代码地图(全局入口)

主题文件路径符号名
CLI 根命令组openadapt/cli.pymain_FlowFirstGroup
引擎转发openadapt/cli.py_FlowPassthroughGroup_run_flow_invoke_flow
可选包懒加载openadapt/__init__.py__getattr__
legacy 录制主函数legacy/openadapt/record.pyrecordprocess_events
legacy 事件降噪legacy/openadapt/events.pymerge_eventsget_events
legacy 回放基类legacy/openadapt/strategies/base.pyBaseReplayStrategy
legacy 视觉定位策略legacy/openadapt/strategies/visual.pyVisualReplayStrategyget_window_segmentation
legacy DOM 分割策略legacy/openadapt/strategies/visual_browser.pyVisualBrowserReplayStrategy
legacy 数据模型legacy/openadapt/models.pyRecordingActionEventScreenshotWindowEvent
开源边界守卫scripts/check_source_boundary.pySourcePolicyscan
发布健康探测scripts/check_release_health.pyevaluatebump_level