jevbooks

← 全部设计模式

菜单

候选枚举 · Menu

只能点菜单上有的

代码把能选的东西列出来、编上号,模型只回答第几个。

1 候选2 候选3 候选4 候选选 3

问题

你在做一个浏览器 agent(自己在网页上操作的程序):给它一个目标,它一路点过去。第一版你让模型直接写一个 CSS 选择器 —— 那是一小段用来在页面上指认某个元素的代码 —— 告诉你该点哪里。

它回了一句「#login > button.primary」。这一页根本没有 login 这个 id;换一页,它写的 class 同时匹配三个按钮;再换一页,它给的选择器干脆有语法错。三次错法全不一样,而且没有一种能在点下去之前验出来。

你想加个校验,却发现没东西可校验:模型能写出来的字符串有无穷多种,你没法提前列出「哪些是对的」。错误空间没有边。

解决方案

菜单模式说:让代码把这一页上能选的东西列出来、编上号,模型只回答「第几个」。

40 个可见元素就是 40 个选项,每个配一句短标签 —— 按钮上写的那几个字。答案空间从无穷变成 40,而「12」这个答案一行代码就能验:它在不在 0 到 39 之间。

菜单上永远多留一项「都不是」。没有合适的候选时,让模型能明说,而不是在 40 个不对的里面挑个最不难看的。列表如果截过 —— 页面上有 300 个元素你只放了 240 个 —— 要在发过去的材料里写明,因为模型看不见的东西等于不存在。

问 · 答 · 拍

  1. 问把页面文字和 40 个编了号的元素放进去,问「下一步该点第几个」。
  2. 答12 号 0.71,7 号 0.12,「都不是」0.03。
  3. 拍12 号最高,而且它确实在这 40 个里面,代码就去点它。

名字从哪来

菜单。在餐馆你只能点菜单上印着的,厨房不会因为你说「来个店里没有的」就现做。菜单还替你把话说清楚了:服务员不用猜你说的「那个辣的」到底是哪一道。

什么时候用

候选能由代码列出来,数量在几百以内,每个都能用一句短标签说清楚。

什么时候别用

正确答案得有人写出来才存在 —— 搜索框里要填的词、提交信息的正文。或者候选超过 255 个,又没法切成几块分别问。

做这件事的项目

  • jev-ultrafast — 浏览器代理:Jev 决定每个动作和元素,仅在输入文本时调用语言模型。
  • jev-browser — 由 TypeSafe 的 Jev 模型驱动的快速、低成本浏览器自动化。
  • jev-review — 由 Jev 把关的分阶段代码审查工作流与本地仪表盘。

用这种模式的全部项目 →

看谁的代码
想看代码
const els = visibleElements(page).slice(0, 40);        // 代码来列,有上限
const menu = Object.fromEntries(els.map((e, i) => [String(i), label(e)]));
menu.none = "None of these";                           // 永远留这条后路
const { answers } = await jev(
  { goal, page: pageText, listWasCut: els.length === 40 },
  { target: choice("下一步该点哪个元素?", menu) },
);
const pick = answers.target.choice;
if (pick === "none" || !(pick in menu)) return escalate();
await els[Number(pick)].click();
jevbooks 怎么认出它

我们怎么知道一个项目用没用这一招?拿它的 README 问 Jev 一句话,Jev 给个百分比,数字越高说明越像。你要抄这道题,记住一点:别问「这个项目好不好」,要问「有没有讲到这一件具体的事」。

questions.json · 每份 README 都发这道题
{
  "candidate-enumeration": {
    "type": "noul",
    "instructions": {
      "what": "Does the text describe code listing the candidates such as DOM nodes, diff hunks, or files, and Jev choosing an index among them?",
      "not_for": "Asking the model to produce a selector, coordinate, or free-text answer."
    },
    "criteria": {
      "true": "The text explicitly describes this. One sentence is enough; other content does not cancel it.",
      "false": "The text does not describe this."
    }
  }
}

用 Jev 做一个 →