以一个简单任务为例看AI落地的关键决策

今天我用AI完成了一个小任务。感觉这个案例特别适合用来介绍AI的实战原则,所以写了这篇文章来分享一下。

任务本身是给这个blog里的每一篇文章都加一行summary,这样可以帮助搜索引擎理解这个网站的内容,从而提升这个网站的排名(SEO)。这个任务看起来简单,其实有很多坑,一不小心就会陷入AI鬼打墙、不可靠、使用繁琐的陷阱。下面主要分享在这个过程中我做了哪五个重要的决策,来让整个流程变得稳定可靠。

决策一:用本地Coding Agent,而不是ChatGPT

我做的第一个决策是:用Cursor/OpenCode作为讨论的平台,而不是ChatGPT。这件事其实并不显然,因为整个项目的开始来自于我想给这个网站做SEO。直观上看,这是个更适合ChatGPT的聊天性质的任务。但是我仍然坚持用了OpenCode。这里面最根本的原因是摩擦。

具体地说,摩擦在两个方面。第一是上下文传递的摩擦。用ChatGPT我需要把我的博客的内容甚至代码复制粘贴给它,或者让它去写代码抓取这些文章的内容。但在OpenCode里,我只要用@指定我的博客所在的文件夹就好了,摩擦小很多。

另一个方面是落地的摩擦。比如我们在ChatGPT里面通过聊天得出了结论:这个网站需要增加Summary元数据。为了把这个想法落地,我需要把我和ChatGPT来回几轮的聊天记录全部复制粘贴到Cursor/OpenCode里面去,然后再调用另一个AI来改文章的内容。相比之下,如果从头就在OpenCode里面做讨论的话,讨论之后立刻就能落地。

所以我做了这第一个决策:对几乎所有任务,抛弃基于聊天的AI环境,选择能执行的Agentic环境。为什么把这个决策放在第一个,是因为这是有和无的区别。摩擦一大,我们就懒得做下去了,整个项目花了时间,交付是0,纯浪费时间。只有摩擦小了,项目能继续下去,才有必要继续聊具体的方法和技巧。

决策二:动手之前,先定义成功,提供测试

我做的第二个决策是:在让AI动手生成任何summary之前,先让它写一个测试。这个测试做的事情很简单,就是检查所有.md文件,看有没有summary字段。如果不是100%的文件都有这个字段就fail,并且打印是哪些文件有问题。

为什么要先写测试?因为如果没有这个测试,AI说做完了,我也不知道它到底做完了没有。我确实可以抽查几篇,但300多篇文章,抽查没法覆盖全部。最后的局面就是我也不知道、AI也不知道,两个人都在wishful thinking。

但有了测试就不一样了。AI做完一轮,测试fail了,它自己就知道还有20篇没覆盖,下面就会重新看这些文章。测试通过了,就是100%完成了。不需要人工抽查,不需要猜,一切100%都是确定的。

这就是我们一直强调的feedback loop。很多人用AI陷入踢一脚动一下、动完了发现不对,再踢再动的循环,觉得AI好难用,根本原因就是没有建立反馈机制。AI不知道什么叫"做完",你也不知道AI做到什么程度了。这是要首先解决的核心问题。确定性的测试就是一个非常有效的解决方法。事实上,只要这种测试到位了,后面三个决策都是锦上添花的东西。

所以在开始任何任务之前,我都会先问自己:我/AI有没有一个确定性的方式来判断任务完成了没有?如果没有,先把这个机制建起来。

决策三:让Agent自己去干,而不是我来写程序调用API

第三个决策是:我没有写程序去调用LLM API来生成summary,而是让coding agent自己去做这件事。

更详细的原因在这篇文章中有解释。虽然让AI做概括听起来调个API就搞定了。但仔细想想,这里有很多corner case:有的文章已经有summary了不要重复加,有的metadata格式不一致,有的位置需要调整。如果写程序处理这些情况,代码会特别复杂,调试成本高,进展速度慢。最后可能AI会花大量的精力去调怎么处理这些细节。

另一种思路是用自然语言直接给Cursor/OpenCode布置任务:"你去看一下XX.md,保证它有个面向SEO的summary元数据域"。这时候完成任务的主题就不是一个机械的程序,而是一个真的有智能,知变通的Agent。它会自己看情况处理——有summary就跳过,格式不对就调整,遇到特殊情况自己判断。

这就是把AI当agent用和把AI当工具用的区别。调用API的模式是:你写程序,AI是其中一个组件。这种模式确定性高,但灵活性低,遇到复杂情况反而更慢。而用Agentic AI,确定性从过程移到了结果上,你只需要讲清楚要什么结果。剩下的事,AI发挥自己的能动性和判断力自己搞定。

所以在我的工作流里,调用API是最后手段。能交给agent去做的,尽量交给agent。

决策四:用Divide and Conquer应对认知饱和

第四个决策是:我没有给一个agent一股脑布置300篇文章的任务,而是让它开了8个sub-agent,分配任务以后并行处理。

这里面的原因和context window saturation有关。一个agent一下处理300篇,前面可能还好,读了十几篇文章以后context window 会被占满,后面就开始偷懒、跳文章、或者忘了前面踩过的坑。这和人有点像,认知负荷一高就会丢三落四,或者开始敷衍。

另一个原因是sub-agent是coding agent原生支持的功能。我不用自己写并发逻辑、分配任务、汇总结果。这些plumbing work都被外包出去了。我只要用一两句话描述一下这个工作流就好。

很多人用AI的时候没有意识到这个问题。他们没有针对AI的缺陷思考,预测到里面的坑,就用最符合直觉的方法去布置任务。但像我们管理下属的时候要知人善任一样,我们要意识到AI的认知资源尤其有限,context window是一种需要管理的稀缺资源。任务量太大,质量必然下降。所以任务量大的时候,我会主动考虑拆分,而不是让一个agent扛所有东西。

这个决策和前面几个的关系是:决策二保证结果是对的(测试通过),决策三保证过程是灵活的(agent自己处理corner case),决策四更进一步通过规避一个必然出现的坑,保证处理得又快又好。

决策五:保证Prompt Self Contained(自举)并且结果导向

第五个决策是:给AI的指令讲清楚所有的信息(不指望它读心),而且着重说acceptance criteria是什么,而不是每一个步骤怎么做。

我的prompt大概是这样:

对于blog/content下面每一篇.md文件,从SEO的角度写一个summary域放到metadata里。你可以用sub-agent来做。先看几篇文章找到感觉,然后想一个prompt,让不同的sub-agent分别处理不同的文章。开8个agent并行处理,每个agent负责写summary并直接编辑.md文件。另外,我希望有个测试能check summary coverage,如果coverage不到100%测试就fail。你的目标就是把这个测试搞到100%让它能过。

注意我没有告诉它具体怎么写这个测试程序、怎么处理各种corner case。

这是很多人容易搞反的地方。他们给AI写指令的时候,事无巨细地规定每一步怎么做。这其实是在把AI当程序用,浪费了Agentic AI的主观能动性。AI不是一个只会照本宣科的乙方,它有很强的判断力和执行力。我们要发挥它的主观能动性,但同时给它一个足够清晰的边界。

我总结写prompt有两个原则。第一,context要给足,不要指望AI能读心。它不知道metadata结构是什么样的。这些信息要么直接给,要么要保证它自己能搞清楚(比如这里我们给了具体路径,它可以通过读文件搞清楚)。第二,从结果出发,而不是从过程出发。你告诉AI你要什么,让它自己想怎么做。除非你预测到某个环节不给具体指导它会出问题——比如前面的context window问题——否则不用讲那么细。

这个决策和决策三是一体两面:决策三是说把执行交给agent,决策五是说把指令也写成适合agent的形式。

总结:AI是一种杠杆

最后说一点感受。

这个任务,我用语音识别花了大概两分钟把指令讲给AI。然后AI自己折腾了45分钟:并行开8个sub-agent,处理各种边界条件,写测试,返工,跑通,commit。全程我就没再管了。这就是一种leverage。用两分钟的时间,撬动了AI 45分钟的工作量。更准确地说,用5%的时间控制了100%的工程产出。

而且现在的Agentic AI能力已经足够强,可以长时间自主工作。我们不需要盯着它干活。只要讲清楚deliverable是什么、acceptance criteria是什么,就可以去干其他事了。这就带来了一种新的可能:scalable agentic workflow。比如我们用两分钟撬动一个Agent A,让他忙45分钟。然后这个时间我们再去指挥Agent B,C,D,... 同时启动多个AI并行推进。这样脑力负担确实会很高,但这是在单Agentic workflow的基础上,再进一步实现10倍生产力的切实可行的途径。

说完了10倍生产力的一面,这个项目的另一面是,有用AI的意识,但是方法不对——在ChatGPT里讨论、没有测试机制、让一个AI包办所有。这些决策做错了,我们可能要折腾几个小时才能做完,甚至鬼打墙做不出来。同一个任务,甚至同一个LLM,会用和不会用,决策做的质量高低,就是从从容容游刃有余和吃力不讨好,比人工做更慢的差别。

Comments