我用 OpenClaw 做了一个资讯推送,然后决定再做一遍

4 阅读8分钟

一篇关于 Agent 产品设计的思考:LLM 到底该在什么节点、以什么方式、多深地介入一个任务?

一、那个别扭

我用 OpenClaw 做了一个资讯推送。需求很简单——抓 AI 领域的热点,按我的偏好每天推给我。

它跑起来了,每天都能收到。但我决定再做一遍。

不是因为它坏了,是因为我看着它,心里别扭。

这篇文章是关于那个别扭是什么。

二、先说 OpenClaw 做对了什么

不然下面讲的东西就不公平。

它让我用很短的时间把一个模糊的想法跑通了。我没写多少代码,大部分是用自然语言描述需求,它自己组装 skill、拉数据、生成推送。作为原型开发环境,它非常强——它让“我要一个资讯推送”这句话在几个小时之内变成一个能跑的东西。

以前这种需求,光是选技术栈就要半天。这件事本身是新的。

所以 OpenClaw 最真实的定位,也许不是 Steinberger 说的“连我妈都能用的 agent”,而是开发者的需求探测器。你用龙虾孵出一个小东西,然后把小东西从龙虾里拿出来单独养。这个定位比官方叙事诚实得多。

三、别扭在哪

别扭在于:它跑起来了,但我说不清它到底在做什么。

我知道它每天会推几条给我。我不知道的是——

  • 它一共看了多少条?
  • 它为什么选了这几条、没选那几条?
  • 今天没推的那些,是因为没抓到,还是抓到了被过滤掉了?
  • 我觉得应该被推但没被推的那条,问题出在哪一环?

这些问题,我作为开发者都回答不上来。

那一个普通用户用这种产品,出了偏差时他能做什么?他只能说“这不是我要的”,然后换一个 app。换一个,还是一样。

这就是我们现在所有 AI 产品的处境——它们跑得很像那么回事,但你没法和它们讲理。出问题时你没有词汇描述问题,没有词汇就没有修复,没有修复就只能弃用。我们管这个叫“用户自由”,其实是一种更彻底的绑死。

OpenClaw 这类产品解决了一个真问题——数据自由、本地运行、不绑死云服务,这是巨大的进步。但它没解决另一个问题:可理解性自由。skills 摆在本地目录里你能看,但看了也没用,因为真正决定行为的是 LLM 在运行时的 prompt 组装,那部分你看不到。数据是开放的,因果链还是黑的

四、我怀疑真正的问题是什么

现在 Agent 产品最大的问题不是不够智能,而是一个没人认真谈的问题:

LLM 到底该在什么节点、以什么方式、多深地介入一个任务?

没人谈,是因为谈它意味着要承认——LLM 不是越多越好

这个问题有三个耦合的维度,得拆开看。

维度 1:介入节点(在哪里介入)

以资讯推送为例,可能的介入点至少有:

信源发现 → 原始抓取 → 去重合并 → 相关性判定 → 重要性判定 → 排序 → 呈现改写 → 解释生成 → 交互应答

关键观察:这里面只有最后两个(解释、交互)是 LLM

不得不

做的——因为输出形态就是自然语言。其他所有节点,LLM 都只是一个可选实现,不是唯一实现。

  • 去重可以用 SimHash + 编辑距离
  • 相关性可以用关键词 + embedding 相似度
  • 重要性可以用转发数、时间衰减、信源权重
  • 排序可以用加权公式
  • 抓取就是 HTTP 请求

这些传统方法有一个决定性优势:它们的行为是可讲清楚的。用户问“为什么这条排前面”,可以回答“因为综合得分 0.82,时效占 0.6、KOL 权重占 0.3、关键词命中占 0.1”。这不是 LLM 编出来的故事,这是机制本身。

维度 2:介入方式(怎么介入)

即使决定让 LLM 介入某个节点,还有三档不同的深度:

  • 浅介入 · LLM 作为分类器 —— 输入数据 + 固定 rubric,输出离散标签或分数。没有开放式生成。行为面接近传统 ML 模型,可重放、可回归测试。
  • 中介入 · LLM 作为判断者 —— 输入数据 + 上下文,输出带结构化 reasoning 的判断(强制 JSON schema)。可审计,但温度 > 0 就不完全可复现。
  • 深介入 · LLM 作为 agent —— LLM 自己决定下一步做什么,调哪个工具,怎么组合。OpenClaw 就是这一档。行为不可预测,debug 基本靠运气。

关键观察:绝大多数 Agent 产品默认走第三档,理由是“这样更智能、更通用”。但对于需求边界清晰的场景——比如资讯推送——第一档或第二档已经足够,代价小一个数量级。走第三档是设计者的偷懒,不是用户的需要。

维度 3:影响半径(错了会怎样)

这是最少被人谈、但最关键的一维。每个节点让 LLM 介入,如果它错了,错误会扩散到哪里?

  • 相关性判定错了 → 只影响一条数据推不推,下次轮询就能自愈
  • 去重合并错了 → 两条不同新闻被合并,永久丢失一条
  • 信源发现错了 → 整个池子分布被污染,所有下游模块都受影响
  • 交互应答错了 → 用户得到一个编造的解释,然后基于错误解释去调提示词,引入二阶错误

由此得到一条很少被人注意的规律——

越靠近上游的节点,LLM 介入的影响半径越大;越靠近下游(呈现、交互),影响半径越小。

但现实中大部分 Agent 产品反过来:上游放任 LLM(因为“智能”),下游反而上模板。这几乎是当前 Agent 产品集体犯的错。

五、所以我打算怎么重做

重做的版本想证明一件事:同一个需求,可以用一种更诚实的方式实现。

诚实不是“不用 LLM”,而是——LLM 只在它不得不出现的地方出现,其他地方老老实实用能讲清楚的方法

架构拆成三个解耦模块:

采集模块

Dumb 的轮询器。信源是明文配置,定时抓数据进池子。这一步完全不碰 LLM

为什么?因为这是上游,影响半径最大,而且这件事传统方法做得又快又准。让 LLM 决定“该抓哪些信源”比让它决定“摘要怎么写”危险得多。

池子本身是独立的

用户可以直接翻原始池子,不经过任何 LLM

这一点很重要——它给了用户一个不依赖 AI 的 ground truth 层。当你怀疑推送结果不对时,你有地方去核对“这条东西到底在不在池子里”。这个核对不需要和 AI 对话,就是肉眼看。池子是前 LLM 的,不会被 LLM 自己的叙事污染。

消费模块

这里 LLM 进来了,按提示词从池子里过滤、排序、推送。提示词是用户可见可改的。

每一次过滤判断都要留下 trace——不是 LLM 事后编的故事,是真实的输入输出记录。这是 LLM 解释和结构化 trace 的区别:前者是“事后合理化”,后者是“机制事实”。白盒的承诺必须 ground 在后者上。

交互模块

用户可以对任何一条推送追问“为什么推给我”、“为什么没推那条”。

这一步 LLM 的作用是翻译,不是判断——它把 trace 里已经存在的事实翻译成人话,不能现编

同时交互模块需要支持“反查池子”:用户可以贴一个 URL 或关键词问“这个东西进池子了吗?如果进了为什么没推我?”。因为对用户来说,“没收到”其实分三种情况——没进池子、进了没选中、选中了被截断——这三种情况只有能区分,白盒才不漏。

六、嵌在结构里的主张

这个重做版本不是答案,是一个样本。

我不觉得我解决了“LLM 应该在哪介入”这个问题,它太大了,一个资讯推送回答不了。但样本有一个好处:主张可以嵌在结构里,而不必嵌在宣传里

把 LLM 挡在采集之外,这是一个立场。让池子前置于 Agent,这是一个立场。把 trace 作为解释的底层事实、而不是让 LLM 现编,这也是一个立场。说没给答案,但代码已经在给答案了。

我想留给自己和读者的问题是:

我们是不是太快接受了“一切都交给 Agent”这个默认选项?

当一个产品宣传“全 Agent 驱动”,它到底是在说更智能,还是更不可问责?当我们说“让 AI 替你决定”,是在让用户省心,还是让用户失去描述问题的能力?

这个重做版本,可能会看起来“不够 AI”。宣传文案会比对手弱,开发速度会更慢,在那些“全 Agent” demo 面前会显得朴素得过分。

但如果它跑起来之后,用户能指着某一条结果说“这条不对,是因为第几步的什么环节”——那就值了。

我不要求你同意我的判断。我只希望下次你看到一个“全 Agent 驱动”的产品时,会多问一句:

这里面的 LLM,真的每一处都需要吗?