阅读视图
iOS 蓝牙开发基础知识梳理
什么是WebSocket ?ios 中如何使用?
Metal 进阶:读取可绘制对象的像素
iOS开发,runtime实现切片编程原理以及实战用例
SwiftUI-MLX本地大模型开发(二)
react组件间的通信有哪些?
Browser Use 原理解析-为一个小项目能融1700万美元
Browser Use 成为近期的明星项目,两个人的纯技术开源项目,核心代码 8000 行,融资 1700 万美元,让人好奇它具体做了什么,为什么这么值钱。
做了什么?
简单说 Browser Use 让大语言模型对网页的识别和操作的效率、准确度变高了,有利于 Agent 完成任务。
目前要让 AI Agent 完成任务,可以直接让 AI 浏览网页,像人一样去理解页面,执行操作,之前一般的做法主要靠截屏:
- 其他产品(Anthropic 的 Computer use、OpenAI 的 Operator 等)操作 GUI,主要靠 VLM 识别截屏,再输出要操作的坐标位置,Agent 执行操作。
- 在这过程中,web 的源码也可以加入上下文,让模型获得更多信息,但 web 源码内容太多,信息噪音太大,token 消耗也高。
而 Browser User 对 web 页面做了结构化处理,翻译成大模型友好的格式,再输入 LLM 识别。举例 Google 首页:
1.Browser use 会在页面上嵌入脚本,遍历 DOM 结构,找出页面上的元素,显式打上标记:

2. 转换为以下纯文本:
[Start of page]
[1]<a Gmail >Gmail/>
[2]<a 搜索图片 >图片/>
[3]<div />
[4]<a false;button;Google 应用/>
[5]<a 登录/>
[6]<img />
[7]<div />
[8]<textarea 搜索;false;q;combobox;Google 搜索/>
[9]<div />
[10]<div 按图搜索;button/>
[11]<input button;Google 搜索;btnK;submit/>
[12]<input btnI; 手气不错 ;submit/>
[13]<a English/>
[14]<a Bahasa Melayu/>
[15]<a தமிழ்/>
[16]<a 关于 Google/>
[17]<a 广告/>
[18]<a 商务/>
[19]<a Google 搜索的运作方式/>
[20]<a 隐私权/>
[21]<a 条款/>
[22]<div false;button/>
[23]<div 设置/>
[End of page]
内容格式极简,关键信息都有,提取了所有可交互元素,模型完全可以通过这些信息“看”和“操作”网页。
例如要执行搜索,模型很容易判断搜索框是索引为[8]的元素,Agent只需要把元素[8]对应的 XPath 拿出来,获取到页面上对应的元素,执行操作就可以。
所以 Browser Use 使用非多模态的模型例如 Deepseek 也可以跑起来,不依赖截图识别。但如果是多模态模型,截图也默认会一起输入模型,提升识别准确率。
Browser Use 核心就是做了这个点,剩下的就是怎样把流程串起来。
实现细节
核心代码包括四个部分:agent 负责决策和串流程,controller 负责转换决策为具体操作,dom 负责网页分析,browser 负责与实际浏览器交互。
-
agent:实现了个小型 AI Agent,负责串起流程,管理上下文信息,决策生成下一步指令,让 Browser Use 可以一步步完整执行一个任务(例如购买机票),这也让 Browser Use 变成易于集成为 Agent
- service.py 实现了典型的 Agent 的 ReAct 模式,推理 → 执行步骤 → 模型观察结果下一步。可单独配置 plan 模型。
- message_manager 管理消息历史,并做了一些类似敏感数据过滤、图片内容处理等。
- memory 实现记忆功能,基于mem0,但目前应该只实现了一半,只把每步存起来,没有调取使用。
-
controller:负责控制和执行浏览器操作的高级指令,是连接AI代理和浏览器操作的桥梁。
- registry/ 实现了 Action 的注册和管理能力
- service.py 定义和注册了所有可用的浏览器 Action,click/go_to_url/input_text等。
-
dom:对 web 页面的处理和分析,生成上述 AI 友好的文本结构。
- buildDomTree.js 是嵌入页面的 JS 脚本,遍历 dom 过滤出可交互元素,绘制高亮框等。
- service.py 操作 JS 注入、节点信息获取、跨域处理等能力,views.py 提供 DOM 节点在 python 的数据模型。
-
browser:对接 Playwright,在它上面封装了一些能力。
- context.py 管理浏览器上下文,以及一些细节功能处理,像标签页/导航管理、截图、定位和获取元素、URL白名单检测、文件下载处理等。
- browser.py 封装了浏览器实例的创建和配置。
它也用到了很多开源项目和服务:
- Playwright:微软开发的 web 自动化测试框架,核心是提供了用代码命令操作浏览器的能力,这能力刚好是 AI Agent 需要的,Browser Use 只需要基于它做上层开发。如果只需要浏览器的能力,官方也有封装的 MCP 服务(github.com/microsoft/playwright-mcp)
- LangChain:Agent 基于 LangChain 构造,主要用到模型调用和 message 管理。
- Laminar:trace / 评估 AI 产品的服务,Laminar 对 LangChain / OpenAISDK 等框架做好了适配,加一行代码就可以对 Browser Use 整个 Session 调用链路调用过程进行追踪和评估。Laminar 跟 Browser User 一样也是 YC 初创公司,开源→服务的打法。跟另一个项目 openllmetry 类似,都是基于 OpenTelemetry 做 AI 的监控分析工具,这个赛道也很卷。
- posthog:数据采集,让 Browser Use 的作者能更好知道项目被使用的情况,会收集一些使用数据上报到 posthog,Agent的执行过程都会上报,对数据敏感的可以关了。
- mem0:专为 LLM 提供的记忆层服务,分级存储用户信息、RAG 召回、易用的 API。也是开源+服务的模式。
- 浏览器服务:Browser Use 支持连接远程的 Browser 服务去执行任务(这也是 Playwright 支持的),官方文档里推荐的就有 browserbase.com、anchorbrowser.com、steel.dev、browserless.io 这几个服务。
其他就是一些配套实现了,gif 动图、多种模型调用的 example、test case 等。
为什么这么值钱
一个并不复杂的开源项目,得到市场这么大的认可,事后分析,可能是因为:
-
是 Agent 的核心基础设施
- Agent 跟现实世界交互,最优方案是通过 API,而不是 GUI 界面,所以基于 MCP 统一协议封装 API 是当下一大热门。
- 但绝大多数服务没有 API,只有给人类提供的 GUI,现阶段要让 Agent 用处更广泛,还是得让它能理解、使用 GUI,而 Browser 是 GUI 的主要容器,在现阶段就是最核心的基础设施之一。
-
有很高的上限
- Browser 足够复杂,需要持续迭代,优化识别率、上下文管理、新的评测机制、探索模型上限等,深耕能形成壁垒。
- Browser 一定有很强的云服务诉求,要各种上层 Agent 自己部署容器和 Browser 成本太高,商业化路径清晰。
-
在这个领域做到了 SOTA
- 据 Browser Use 自己的评测,在 WebVoyager Benchmark 上获得业界最好的效果:
- 从近期声量、github 的活跃上看,稳居头部。
有需求,有商业化,有流量,在这个时间点让它很值钱。
想法
- 长期看,模型直接理解截屏是更自然更能 scale up 的做法,所有信息截屏都有,大模型应该像人一样能准确识别和操作,模型公司应该会一直在这条路上尝试。
- Browser Use 是在模型能力不足时期的中间优化方案,如果这个时期足够长,它就价值很大,如果模型很快突破,它就会失去价值。
- 可以用同样的思路复刻 Mobile Use,iOS / Android 都有现成的 accessibility 能力,能拿到当前界面结构化的数据,只是会有沙盒的各种限制,这事很适合系统厂商去做。桌面端应该也可以。
- Agent 上下游相关配套基建都处于起步阶段,小团队很有机会把其中某个点做出彩。
切勿将辅助驾驶宣传成智能驾驶 - 肘子的 Swift 周报 #78
不久前,某个造成三人死亡的交通事故因为涉及某新锐电动汽车品牌再度引发了人们对“智能驾驶”功能的质疑。在目前披露的有限资料中,至少可以确认的是,“智能驾驶”系统未能在相当长的一段行驶距离中判断出当前的路段正在施工(沿途有施工警示标志),只在撞击前2-3秒前给予了警示。这意味着,在系统报警后,驾驶者只有极短的反应时间。
LLVM integrated assembler: Improving MCExpr and MCValue
In my previous post,
The LLVM integrated assembler handles fixups and relocatableexpressions as distinct entities. Relocatable expressions, inparticular, are encoded using the MCValue
class, whichoriginally looked like this:
1 |
class MCValue { |
In this structure:
-
RefKind
acts as an optional relocation specifier,though only a handful of targets actually use it. -
SymA
represents an optional symbol reference (theaddend). -
SymB
represents another optional symbol reference (thesubtrahend). -
Cst
holds a constant value.
While functional, this design had its flaws. For one, the wayrelocation specifiers were encoded varied across architectures:
- Targets like COFF, Mach-O, and ELF's PowerPC, SystemZ, and X86 embedthe relocation specifier within
MCSymbolRefExpr *SymA
aspart ofSubclassData
. - Conversely, ELF targets such as AArch64, MIPS, and RISC-V store itas a target-specific subclass of
MCTargetExpr
, and convertit toMCValue::RefKind
duringMCValue::evaluateAsRelocatable
.
Another issue was with SymB
. Despite being typed asconst MCSymbolRefExpr *
, itsMCSymbolRefExpr::VariantKind
field went unused. This isbecause expressions like add - sub@got
are notrelocatable.
Over the weekend, I tackled these inconsistencies and reworked therepresentation into something cleaner:
1 |
class MCValue { |
This updated design not only aligns more closely with the concept ofrelocatable expressions but also shaves off some compiler time in LLVM.The ambiguous RefKind
has been renamed toSpecifier
for clarity. Additionally, targets thatpreviously encoded the relocation specifier withinMCSymbolRefExpr
(rather than usingMCTargetExpr
) can now access it directly viaMCValue::Specifier
.
To support this change, I made a few adjustments:
Introduced getAddSym
andgetSubSym
methods, returningconst MCSymbol *
, as replacements forgetSymA
andgetSymB
.- Eliminated dependencies on the old accessors,
MCValue::getSymA
andMCValue::getSymB
. Reworkedthe expression folding code that handles + and - Storedthe const MCSymbolRefExpr *SymA
specifier atMCValue::Specifier
- Some targets relied on PC-relative fixups with explicit specifiersforcing relocations. I have
defined MCAsmBackend::shouldForceRelocation
for SystemZ andcleanedup ARM and PowerPC Changedthe type of SymA
andSymB
toconst MCSymbol *
Replacedthe temporary getSymSpecifier
withgetSpecifier
Replacedthe legacy getAccessVariant
withgetSpecifier
Streamlining Mach-O support
Mach-O assembler support in LLVM has accumulated significanttechnical debt, impacting both target-specific and generic code. Oneparticularly nagging issue was theconst SectionAddrMap *Addrs
parameter inMCExpr::evaluateAs*
functions. This parameter existed tohandle cross-section label differences, primarily for generating(compact) unwind information in Mach-O. A typical example of this can beseen in assembly like:
1 |
.section __TEXT,__text,regular,pure_instructions |
The SectionAddrMap *Addrs
parameter always felt like aclunky workaround to me. It wasn’t until I dug into the SectionAddrMap
for ARM and X86 and eliminatethe parameter:
[MC,MachO]Replace SectionAddrMap workaround with cleaner variablehandling MCExpr:Remove unused SectionAddrMap workaround
While I was at it, I also tidied up MCSymbolRefExpr
byHasSubsectionsViaSymbolsBit
, furthersimplifying the codebase.
注意,暂时不要升级 MacOS ,Flutter/RN 等构建 ipa 可能会因 「ITMS-90048」This bundle is invalid 被拒绝
老司机 iOS 周报 #330 | 2025-04-07
你也可以为这个项目出一份力,如果发现有价值的信息、文章、工具等可以到 Issues 里提给我们,我们会尽快处理。记得写上推荐的理由哦。有建议和意见也欢迎到 Issues 提出。
新闻
🐕 Swift 6.1 Released
@AidenRao:Swift 6.1 正式推出,核心更新:
-
并发优化:
nonisolated
支持类型和扩展,任务组子任务结果类型自动推断; -
OC 迁移: 新增
@implementation
支持,允许在 Swift 中实现 Objective-C 类型,便于逐步迁移; - 开发体验:尾随逗号支持扩展至参数列表、元组等场景;
-
包管理:新增
package traits
机制,适配跨平台条件编译; - 测试增强:支持自定义测试前后逻辑,异常处理更便捷;
- 文档工具:Swift-DocC 优化符号链接可读性。
推荐通过 Xcode 16.3 或 swiftly
工具链安装体验。
新手推荐
🐕 Modern URL construction in Swift
@阿权:本文介绍了 Swift 在 URL 构建方面的现代解决方案,通过类型扩展、宏和新 API 的结合,实现了更安全、简洁的 URL 处理方式。开发者可根据项目需求选择合适方案,提升代码质量。具体内容为:
- 静态字符串构建 URL 使用 Optional 方式显得冗余,应直接强制解包。
- 解法 1:添加 URL 扩展直接创建 URL 实例,内部解包为空时 fatallError,输出信息。
- 解法 2:通过自定义宏创建 URL 实例,实现解包并抛出错误的逻辑。
- 对于动态构建的 URL,应使用更结构的 URL、URLComponents 拼接、构建方法,甚至能够直接获取本地常见目录的 URL。
文章
🐕 Deploying a Swift Server App to Fly.io and Railway
@Kyle-Ye: 本文介绍了如何使用 Vapor 框架部署 Swift 服务端应用程序到 Fly.io 和 Railway 平台。文章涵盖了初始化 Vapor 项目、编写 Dockerfile、以及在两个平台上部署应用的具体步骤。此外 , 还提到了一些进阶主题 , 如自定义域名和添加数据库服务等。
🐢 AI 产品经理进阶:万字深析大模型的 MCP(上 & 下)
@EyreFree:这篇文章深度剖析了大模型的 MCP 技术。MCP 是 Anthropic 于 2024 年底开源的开放标准协议,旨在统一 AI 与外部数据源和工具的连接方式,降低集成成本。它采用客户端 - 服务器架构,基于 JSON-RPC 2.0 通信,定义多种原语规范交互。该技术已在智能问答、编程辅助、办公自动化等场景崭露头角。文章还全面分析了 MCP 的优势与局限,如标准统一、开源灵活,但也存在生态不完善、远程支持不足等问题。此外,还展望了其未来在完善远程云支持、构建 “应用商店” 式分发机制、拓展多模态应用等方面的演进方向,为 AI 从业者或对之感兴趣的同学提供了极具价值的参考。
🐕 Fast & Fluid: Integrating Rust egui into SwiftUI
@david-clang:作者在开发实时预览 SwiftData 和 CoreData 数据库的 Mac App DataScout 时,发现 SwiftUI 的 Table
性能相当差,尝试用 AppKit 的 NSTableView
也无法满足需求,最后用 Rust 的 UI 框架 egui
去优化性能。作者把 SwiftUI 中嵌入 egui
渲染视图的 Demo 整理成文章,还用代码示例展示如何在 SwiftUI 的 NavigationSplitView
中嵌入 egui
渲染的视图。以下是 egui
和传统 UI 框架的对比:
- 传统 UI 框架(如 SwiftUI、UIKit)多采用保留模式(Retained Mode),需显式管理 UI 组件状态(例如按钮状态、列表数据等),框架内部通过对比新旧状态差异来局部更新界面。
-
egui
的即时模式(Immediate Mode) 则相反:每帧完全丢弃旧 UI 状态,根据当前数据重新生成整个界面,通过高频重建实现“无状态化”。
虽然 Demo 中使用 egui_wgpu_backend
作为渲染后端,但它在 Metal 上渲染单帧需要 10 毫秒,作者在开发 DataScout 时,通过自定义渲染后端,把帧渲染时间缩短到仅 1-2 毫秒,最终才实现高性能需求,可见把 “ SwiftUI 中嵌入 egui
渲染视图” 封装成成熟框架会比较难,但本文优化 SwiftUI 性能的思路值得我们学习。
🐎 得物 iOS 启动优化之 Building Closure
@Smallfly:本文深入解析了 iOS 应用启动优化中常被忽视的 Building Closure 阶段(由 dyld 动态链接器负责),聚焦其耗时问题与优化实践。文章通过真实案例,揭示了某版本因 Building Closure 阶段耗时暴增 200ms 的根因定位过程,并最终通过 解决Perfect Hash 算法的哈希冲突,将关键函数耗时从 1200ms 降至 110ms。
文中详细剖析了 Building Closure 的工作原理(如首次启动生成缓存、Swift/ObjC 协议一致性处理),并提供了 文件结构解析、耗时定位方法(Instrument 工具)及优化方案,适合以下读者参考:
- iOS 开发工程师:需优化应用启动速度,尤其是冷启动场景;
- 性能调优团队:关注底层 dyld 机制,探索启动耗时优化新方向;
- 技术管理者:了解复杂问题排查流程与跨团队协作经验。
内推
重新开始更新「iOS 靠谱内推专题」,整理了最近明确在招人的岗位,供大家参考
具体信息请移步:https://www.yuque.com/iosalliance/article/bhutav 进行查看(如有招聘需求请联系 iTDriverr)
关注我们
我们是「老司机技术周报」,一个持续追求精品 iOS 内容的技术公众号,欢迎关注。
关注有礼,关注【老司机技术周报】,回复「2024」,领取 2024 及往年内参
同时也支持了 RSS 订阅:https://github.com/SwiftOldDriver/iOS-Weekly/releases.atom 。
说明
🚧 表示需某工具,🌟 表示编辑推荐
预计阅读时间:🐎 很快就能读完(1 - 10 mins);🐕 中等 (10 - 20 mins);🐢 慢(20+ mins)