跳转到内容

Playbook

最自然的做法是让智能体按照技能逐步完成任务。这种方式很灵活,智能体可以随时选择需要的工具,但用于手机 App 时速度慢、成本高:一次误操作就可能进入陌生页面,需要好几步才能退回。如今的多模态大模型已能完成大多数 App 操作,真正的瓶颈是 token 成本。

App 里大多数页面的图标和布局固定,页面跳转也有规律,靠锚点文字就能识别当前页面、确定下一步动作。把这类确定性步骤交给大模型,既浪费 token,又增加延迟,遇到陌生页面还容易出错。

Playbook 把路径相对固定的高频操作写成声明式模板,只在需要语义理解的地方调用大模型,每次调用只给最少的上下文和工具。调用减少、上下文变小,成本大幅下降;可选工具更少,模型也更不容易选错。

由此带来三个好处:

  • 成本低。 token 消耗可降低 50 到 100 倍。
  • 速度快。 一次模型调用常常要 20 到 60 秒。调用减少后,任务速度可提高 3 到 5 倍。
  • 成功率高。 智能体不再随意探索,误操作更少。可选动作更少,判断也更准确。

生成 playbook 模板:

bash
physiclaw playbooks init taobao
  • 文件夹~/.physiclaw/playbooks/taobao/
    • APP.yml
    • 文件夹buy/
      • PLAYBOOK.yml

清单文件,存放这个 App 所有 playbook 共用的内容。

yaml
kind: manifest
schema: 1
app: taobao
description: 在淘宝购物:搜索、挑选、请用户确认、付款。
# 页面上常用按钮的位置。
landmarks:
close:
label: "促销弹窗下方的 ✕"
at: [0.44, 0.68, 0.56, 0.75]
# 淘宝的常用页面,通过 anchors 里的文字识别。
pages:
home:
description: "淘宝首页:标签栏(推荐 / 关注)在搜索栏上方"
anchors:
- {text: ["推荐", "关注"], within: top}
recover:
covered: {tap: app.landmarks.close}
results:
description: 搜索结果页,筛选栏(综合 / 销量)之下
anchors:
- {text: "综合", within: top}
- {text: "销量", within: top}
scrollable: true
recover:
covered: {tap: app.landmarks.close}
elsewhere: go_back
buysheet:
description: "下单页:付款按钮在实付金额那一行下方"
anchors:
- {text: ["免密支付", "提交订单", "立即支付"], within: bottom}
- {text: ["实付", "优惠后"], within: [0.0, 0.15, 1.0, 0.85]}
forbid: ["支付成功"]
recover:
covered: {tap: app.landmarks.close}
elsewhere: go_back
paid:
description: "支付成功页"
anchors:
- ["支付成功", "付款成功"]

执行路线。从上往下读:每步先写应处于哪个页面,再写在该页面执行的操作。

yaml
kind: entry
schema: 1
name: buy
# 大模型根据这一行决定是否使用这个 playbook。
description: 在淘宝购买商品
enabled: false
# 任务开始时填入;下面用 {inputs.name} 引用。
inputs:
user_said:
description: 用户的原话
route:
# 从用户消息中提取搜索关键词。
- agent: parse
context:
prompt: |
从用户消息中提取淘宝搜索关键词。
用户说:"{user_said}"
要求:只保留商品名和规格,例如"金典有机牛奶 250ml";
去掉数量词、动词和客套话。
如果消息没有提到具体商品,则上报。
given:
user_said: inputs.user_said
returns:
keyword: 搜索关键词
think: off
# 打开淘宝。
- start: app
macro:
steps:
- home_screen # 回到手机桌面
- tap: "淘宝图标" # 图标在你手机上的位置可能不同
at: [0.720, 0.425, 0.909, 0.551]
- wait: 5
# 冷启动可能停在全屏广告上。
- tap: "跳过"
at: [0.79, 0.030, 0.87, 0.065]
when: {text: "跳过", within: [0.70, 0.0, 1.0, 0.12]}
- wait: 2
- page: app.pages.home
# 搜索关键词。
- do: search
with: {keyword: "{parse.keyword}"}
macro:
inputs:
keyword:
description: 要搜索的内容
steps:
- tap: "首页搜索栏"
at: [0.30, 0.092, 0.70, 0.128]
- send_to_clipboard: "{keyword}"
- long_press: "搜索输入框"
at: [0.08, 0.115, 0.55, 0.148]
- tap: "粘贴"
at: [0.066, 0.070, 0.163, 0.098]
- tap: "搜索"
at: [0.811, 0.865, 0.923, 0.895]
- wait: 2
- page: app.pages.results
# 大模型选择商品,打开下单页,付款前停止。
- agent: pick
context:
prompt: |
你在淘宝替用户购买一件商品。从搜索结果开始,到下单页为止,不要付款。
用户说:"{user_said}"
搜索关键词:{keyword}
1. 在搜索结果里比较商品的标题、规格、价格和销量。优先选择规格与
关键词一致的单件装,销量高、价格低的更好。点击所选商品的标题
一次,进入详情页。
2. 在详情页点击"立即购买"或"领券购买"。弹出规格选择时,点击与
关键词一致的那一行,再点击底部按钮。
3. 下单页显示正确的规格和明确的实付金额后停止。付款由 playbook
完成,无需你操作。
促销弹窗可能遮住页面,点击它的 ✕({close})关闭,只点一次。
如果没有合适的商品,则上报。
given:
user_said: inputs.user_said
keyword: parse.keyword
close: app.landmarks.close
tools: [tap, scroll, back]
never_tap:
- {label: ["免密支付", "立即支付", "提交订单"], within: bottom}
returns:
summary: 一行文字,包含标题、规格、数量和实付金额
message: 一条简短的中文消息,请用户确认是否购买
limit: {calls: 12, scrolls: 4}
think: low
on_fail: stop
- page: app.pages.buysheet
# 请用户确认。
- ask: confirm-pay
approve: payment
total_label: ["实付", "优惠后"]
message: "{pick.message}(实付 ¥{ask.total})回复 好的 确认支付,或 不用 取消。"
yes: ["好的", "好", "可以", "确认"]
no: ["不用", "不要", "取消", "算了"]
denied: "好的,已取消,未付款。"
wait: 45
rounds: 3
think: off
on_fail: stop
# 用户回复后,切回淘宝的下单页。
resume:
steps:
- home_screen
- tap: "淘宝图标"
at: [0.720, 0.425, 0.909, 0.551]
- wait: 2
# 用户同意后,点击付款。
- do: pay
irreversible: payment
on_fail: handover
macro:
steps:
- tap: ["免密支付", "立即支付", "提交订单"]
at: [0.368, 0.923, 0.629, 0.948]
- wait: 4
- page: app.pages.paid
# 向用户报告结果。
- tell: report
message: "已下单并完成支付:{pick.summary}。"

启动 MCP 服务器:

bash
physiclaw mcp

检查 playbook,再逐步运行调试:

bash
physiclaw playbooks check
physiclaw playbooks step taobao/buy -i user_said="帮我买一箱金典有机牛奶"

先在本地调试,再启用。 每台手机的坐标框都不同,playbook 要在你自己的手机上逐步运行过才能正确执行。

锚点要稳定、准确。 playbook 靠锚点文字识别页面,所以要选择位置固定、App 改版后不易变动的文字。

让智能体来写。 把 claude 或 codex 连接到你的 MCP 服务器,让它替你编写和调试 playbook。