返回事实,而非解释:为什么 LLM 工具应该比你想象的更笨

发布: (2025年12月11日 GMT+8 06:57)
6 min read
原文: Dev.to

Source: Dev.to

Part 1: The Problem

1.1 The Helpful Tool That Made Everything Worse

当我第一次为 Verdex 构建 resolve_container 时,我希望它能提供帮助。该工具会从目标元素向上遍历 DOM 树并返回祖先链。我加入了对结果的解释:

{
  "type": "product-card",           // 工具猜测语义含义
  "role": "list-item",              // 工具猜测结构用途
  "confidence": 0.85,               // 工具评估自己的猜测
  "recommendation": "Use this as your container scope"
}

起初这看起来还算合理——工具预先分析了结构并给出建议,这样 LLM 就不必再做判断了。

然而在生产环境中,一个包含用户资料卡片的页面被错误标记为 “product‑card”(置信度 0.85)。LLM 信任了工具的解释,生成了针对错误模式的选择器,导致边缘案例的测试失败。

问题不在于解释通常是错误的——它们大多数时候是正确的。根本问题在于:解释是依赖上下文的,而工具缺乏上下文。

1.2 The Core Problem: Interpretation Is Context‑Dependent

考虑一个 <div data-testid="product-card">。它到底意味着什么?

任务解释
选择器编写稳定的容器;使用 getByTestId("product-card") 作为作用域
可视化测试组件边界;对整个卡片进行截图
网络爬取数据结构;从子元素中提取商品信息
可访问性审计语义分组;检查 ARIA 标签

同一个 DOM 元素在四种任务中产生了完全不同的含义。当我的工具只选择了一种解释(“这是一个 product card,用它来做选择器作用域”),它把这个决定套用了到所有任务上,尽管它并不知道用户的查询、领域知识以及任务上下文。只有 LLM 才拥有这些信息。

1.3 The Insight: Capability vs. Interpretation

工具提供能力: 访问结构化事实,这些事实否则会被隐藏或获取成本高昂。
LLM 提供解释: 决定这些事实在特定查询、特定上下文中的含义。

工具的职责是遍历 DOM 并返回它找到的内容——标签、属性、深度、关系——而不是 猜测语义类型或规定使用方式。

之前(解释混在一起)

{
  "container": {
    "semanticType": "product-card",  // 工具在猜测
    "stability": "high",             // 工具在评估
    "recommended": true              // 工具在规定
  }
}

之后(纯粹事实)

{
  "ancestors": [
    {
      "level": 1,
      "tagName": "div",
      "attributes": { "data-testid": "product-card" },
      "childElements": 5
    }
  ]
}

第二种版本对人类来说似乎不那么“贴心”,但对 LLM 更有用,因为它保留了可选性。相同的原始事实可以根据用户的查询进行不同的解释:

  • 选择器编写: “第 1 层的 data-testid 是一个稳定的容器,我会用它来做作用域。”
  • 调试: “有 12 个元素使用了该 testid,可能是组件复制时忘记更新 ID。”
  • 重构: “这个模式出现在 47 个测试文件中,需要谨慎迁移。”

这种架构之所以有效,是因为能力层保持了解释的独立性。

Part 2: Why This Matters

2.1 The Composition Problem

当工具返回解释时,它们会做出难以逆转的决定。LLM 必须要么接受解释,要么与之抗争——两者都代价高昂。

例子:工具输出 "type": "product-card" 并附带 "confidence": 0.85。用户询问:“在此页面上找出所有用户资料卡片”。LLM 看到工具的解释后有两种选择:

  1. 信任它(错误): 为 product card 生成选择器。
  2. 与之抗争(尴尬、消耗 token、可靠性低): 解释为什么工具的解释与查询不匹配。

如果工具返回原始事实("data-testid": "product-card"),LLM 可以检查实际页面结构,发现 testid 具有误导性,并相应地进行调整。

原则: 返回事实的工具可以在不同任务之间组合使用;返回解释的工具只针对单一任务进行优化,容易在其他任务中失效。

2.2 The Human API Trap

面向人的 API 往往刻意高层且带有主观意见。像 page.selectDropdown("Country", "United States") 这样的方式对开发者来说很美好,因为它隐藏了繁琐细节。

然而 LLM 更适合使用低层原语:

page.click('select[name="country"]')
page.click('option:has-text("United States")')

低层操作让 LLM 能够将模式适配到新组件、定制框架或非标准实现上。高层抽象只能在它们被设计的特定场景中工作,会限制 LLM 的灵活性。

这就是为什么 resolve_container 应该返回带有原始属性的祖先链,而不是 “这是你的推荐容器”。这样 LLM 就可以自行决定如何在后续任务中使用这些信息。

Back to Blog

相关文章

阅读更多 »

揭秘检索增强生成 (RAG)

大型语言模型(LLMs)彻底改变了我们与信息交互的方式,但它们有一个根本性的限制:它们的知识在训练时点被冻结。