L02 练习
练习 1:截断与预算策略(方法练习)
真实网站一个搜索结果页可能有 50+ 可交互元素,元素编号列表也会膨胀。实现一个 page_to_obs_with_budget(session, max_tokens=500):
- 提取所有可交互元素后,按「与当前任务的语义相关性」排序(简化:按文本是否含查询关键词排序),截断到预算内。
- 被截断的元素用一个
[... 还有 N 个元素未显示]汇总行代替。 - 对比:有预算 vs 无预算时,agent 还能不能找到目标元素(如果目标被截断了怎么办)。
验收:page_to_obs_with_budget 输出 token 不超预算;能说出「截断是上下文工程的必然——窗口有限,必须取舍,但取舍可能丢掉关键元素,这是文本派的固有张力」。
练习 2:元素编号列表 vs 可访问性树(设计实验类)
Playwright 自带 page.accessibility.snapshot() 能拿到完整的可访问性树。对比本课手写的元素编号列表:
- 假设:手写版更省 token(只留可交互元素 + 编号),可访问性树更完整但更大。
- 实验:对 L00 的 search.html,分别用手写版和
accessibility.snapshot()生成表示,对比 token 数和「目标元素(如第 1 条结果链接)在不在表示里」。 - 预期:手写版 token 少;可访问性树信息更全但大;两者都能定位目标。
验收:输出对照表(token / 是否含目标 / 信息完整度),诚实标注手写版的简化代价(漏了哪些可访问性树有的信息)。
提示:可访问性树快照
snap = page.accessibility.snapshot()
# snap 是嵌套 dict:{role, name, value, children: [...]}
# 递归遍历可打印整棵树
def walk(node, depth=0):
print(" "*depth + f'{node.get("role")}: {node.get("name","")[:40]}')
for c in node.get("children", []):
walk(c, depth+1)
walk(snap)
练习 3:编号歧义场景(理解类)
本课的稳定性测试证明了「重扫一致、操作后重分配」。但有一种场景没测:同一页上有两个文本完全一样的元素(如两个「下一页」链接,一个在顶部一个在底部)。回答:
- 这时元素编号列表里会出现两条
[N] link "下一页",agent 点哪个?编号能区分吗? - 本课的
selector字段(id 后备)能解决吗?如果两个都没 id 呢? - L06 可靠性课会怎么处理「误点相似元素」?本课埋下了什么伏笔?
验收:能说出「编号能区分位置(不同编号),但语义上 agent 分不清哪个是想要的——需要 L06 的相似元素检测 + 上下文锚定(如『页面底部的下一页』)」。
练习 4:思考题——纯文本什么时候够用(取舍类)
本课贬低了纯文本表示(丢交互性)。但有些任务纯文本就够了。回答:
- 举一个纯文本表示就够的 GUI agent 任务(提示:只提取信息不操作的场景)。
- 这时用元素编号列表是不是浪费?为什么?
- research-assistant 的 researcher 节点(L09 落地)什么时候该用纯文本观察、什么时候必须用元素编号列表?
验收:能区分「阅读型任务(纯文本够)」和「操作型任务(必须编号列表)」,并指出 research-assistant 的 browse 工具应支持两种模式按任务路由——这是 L09 工具分层设计的伏笔。