MoreRSS

site iconKingname | 谢乾坤修改

精通数据抓取、爬虫。网易 - 字节 - 红杉中国。 微软 MVP。 出版了《Python爬虫开发 从入门到实战》。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Kingname | 谢乾坤的 RSS 预览

当一篇论文说“AI Agent还不会做研究”,它到底测到了什么?

2026-08-08 20:00:00

最近我看到一项很有意思的实验。

研究者找来几个真实、并且还没有公开答案的AI研究课题,让Agent自己查资料、写代码、跑实验、分析结果。他们给了Agent几天时间和相当可观的算力预算,最后再让真正做过这些课题的研究者评价Agent的成果。

结果不太好。Agent没有产出达到论文标准的研究成果。

研究者还分析了大量运行日志,发现Agent有不少问题:一次实验结果不好,它就过早放弃整个方向;不会合理分配预算;Reviewer已经指出关键问题,它还是沿着原来的路线修修补补;遇到死路时,也不知道回退、修改假设、重新设计实验。

这些现象我都相信,而且非常值得研究。

但如果根据这项实验,直接得出“AI Agent现在还不会做开放式研究”,我会非常谨慎。

因为这种实验最终测到的,从来都不只是AI的研究能力。基础模型、Agent框架、工具、实验设计、操作者水平和人类对照组,全都混在最终结果里面。只要其中一个变量没有控制好,结论就很容易超出证据能够覆盖的范围。

到底用了什么模型?

现在讨论Agent能不能完成一个复杂任务,模型版本已经是一个绕不过去的变量。

不同模型在普通聊天中的差距,有时候看起来只是回答好一点或者差一点。但到了持续几个小时甚至几天的任务中,这些小差距会不断累积。

有的模型更容易忘记最初的目标,有的模型更容易发现前面的假设已经错了;有的模型遇到实验失败会重新规划,有的模型会沿着错误路线继续消耗预算;有的模型可以稳定维护几十步状态,有的模型跑到一半就开始偏离方向。

所以一个Agent实验失败以后,我首先想知道的是:

  • 具体用了哪个模型?
  • 推理强度怎么设置?
  • 上下文怎么管理?
  • 允许调用哪些工具?
  • 有没有独立的Reviewer?
  • 失败以后怎么恢复?
  • 预算怎么分配?

把这些信息全部去掉,只留下一句“Agent失败了”,其实没有多少信息量。

同一个基础模型,放进两套不同的Agent框架,最后可能表现得像两个完全不同的系统。模型负责提供推理能力,Agent框架负责维护长期状态、拆解任务、调用工具、验证结果、失败回滚和控制预算。开放式任务,恰好非常依赖这些东西。

因此,一项严谨的Agent研究,首先能够证明的应该是:

在这个模型、这套Agent架构、这些工具和这组资源限制下,系统没有完成这个任务。

这个结论完全没有问题。但能不能进一步概括成“现在的AI做不了这件事”,还需要更多实验来支持。

设计实验的人,真的会用Agent吗?

这个问题可能更加重要。

我以前在一家互联网大厂工作时,接触过一个专门做机器学习和数据挖掘的研究团队。团队里面很多人都是名校硕士、博士,理论基础很好,也有真正的研究能力。他们有些实验会跑几个星期,复杂项目做一两个月也很常见。

后来有一次,我看了他们写的Python代码,印象非常深。

大量重复计算,大量没有必要的循环。明明可以使用集合解决的问题,却在反复遍历列表;明明可以提前计算或者缓存的东西,却每次都重新计算。代码明显是在Jupyter Notebook里面随着实验一点点堆出来的,前面写过的逻辑,后面再复制一次,对时间复杂度和工程结构也没有太多考虑。

其中一些实验如果让我来重构,我认为运行速度提高五倍并不夸张。

这件事情让我意识到,研究能力其实由很多相对独立的技能组成。理论水平、问题选择、实验设计、编程能力、系统工程、数据处理和信息检索,这些能力之间有关系,但远没有强到可以互相替代。

一个机器学习理论很强的人,完全可能写出很差的Python代码。一个很会发论文的人,也可能不擅长构建高效率的实验系统。

到了Agent时代,又多出了一项新的技能:如何组织Agent工作。

这个能力目前被严重低估了。

同样一个模型,有人会写一个巨大的Prompt,然后让Agent自己跑几个小时。有人会先拆分研究问题,给不同方向设置独立的上下文,再设计Reviewer、验证器、检查点和失败回退机制。

有人会让五个Agent同时尝试五种假设,再让第六个Agent专门寻找反例。有人则会让一个Agent从头跑到尾,中间不做任何检查。

如果前者成功、后者失败,我们显然不能把差异全部归因于模型智力。

代码都让AI写,不就解决了吗?

这里马上会有一个很合理的反问:

你举的例子已经过时了。现在最先进的AI写代码已经比绝大部分普通研究员强。如果实验代码、数据处理、实验框架,甚至Agent本身都让AI来写,研究员的工程水平还会影响结果吗?

这个反问非常关键,而且它确实削弱了“研究员代码写得差”这个具体问题的重要性。

如果一个研究团队已经让强模型负责实现实验代码,并且有完整的测试、性能分析、代码审查和结果验证,那么我之前看到的那种低质量Python代码,确实可能大幅减少。

未来的科研工作中,“一个博士因为不会优化Python,导致实验慢五倍”这种事情,很可能越来越少。

但操作者的影响并没有消失,只是往上移动了一层。

过去,研究员亲手写循环。现在,研究员决定让Agent优化什么。

过去,研究员亲手选择数据结构。现在,研究员决定什么结果才算验证通过。

过去,研究员亲手搭建实验框架。现在,研究员需要决定Agent应该探索几条路线、什么时候停止探索、什么情况下重新检查假设,以及Reviewer有没有权限推翻当前路线。

代码可以全部由Agent来写,但下面这些问题,依然要由人或者更上层的系统决定:

  • 任务应该怎样拆分?
  • 哪些实验可以并行?
  • 哪些变量必须控制?
  • 什么指标才能提供真正有效的反馈?
  • 一次实验失败,究竟是研究假设有问题,还是实验实现有问题?
  • 连续三次失败以后,应该继续尝试,还是换一个方向?
  • 多个Agent得出冲突结果时,应该相信谁?
  • Reviewer提出异议以后,应该补一个实验,还是推翻整个研究设计?
  • 什么时候应该增加算力,什么时候继续砸算力已经没有意义?

开放式研究最难的部分,恰好集中在这里。

所以,即使AI解决了代码质量这个底层问题,实验设计者仍然可能搭出一套非常糟糕的Agent系统。

只不过以前的问题表现为O(n²)的循环、重复计算和垃圾Notebook;现在的问题变成了错误的任务拆分、缺失的反馈循环、错误的验证标准和糟糕的停止条件。

甚至还有一个更加隐蔽的风险:Agent写代码太强,反而可能掩盖上层设计的问题。

代码运行得很漂亮,测试全部通过,实验自动化程度很高,最后还生成了一篇结构完整的论文。整个流程看起来非常专业,但研究方向可能从第三个小时开始就已经走偏了。

工程质量高,不代表研究设计也同样高。这两件事情必须分开看。

Agent的能力是一个乘法结果

我现在更愿意把一个复杂Agent系统的最终表现,理解成下面几个因素共同作用的结果:

基础模型 × Agent架构 × 工具质量 × 反馈机制 × 操作者能力

这里不能简单做加法,因为任何一个环节特别差,都会浪费其他环节的能力。

一个很强的模型,如果没有可靠的反馈,很可能非常高效地沿着错误方向跑很远。

一套优秀的Agent框架,如果接入一个能力很弱的模型,也会在真正需要判断力的地方不断失败。

模型、工具和框架全部配齐,如果实验者选择了一个错误的评价指标,系统一样可能优化出毫无意义的结果。

这也是为什么我越来越不喜欢笼统地问:“这个模型会不会做科研?”

科研根本没有一个统一的评分函数。

写代码时,程序能不能运行是反馈;优化性能时,Benchmark可以直接告诉你速度变快还是变慢;数学证明至少还有相对清晰的正确性标准。

开放式研究困难得多。

一个实验结果不理想,到底说明研究思路错了、代码实现错了、数据错了,还是这个异常本身就是最重要的新发现?成熟研究者的价值,很大一部分就体现在这种判断上。

Agent真正的难题,往往出现在没有清晰反馈信号的地方。

人类对照组也不一定靠谱

这类研究还有另一个经常被忽略的问题:到底拿AI和什么样的人比较?

论文里面很容易写“由领域专家完成”,但“领域专家”是一个非常模糊的标签。

同样是机器学习博士,一个人有很强的系统工程能力,会自动化实验、并行探索、搭建完善的数据处理流程;另一个人习惯手工操作,一条路线跑到底。两个人都可能拥有很好的论文记录,但完成同一个计算密集型研究任务,效率很可能相差几倍。

加入Agent以后,这个差距还会继续扩大。

一个研究员让Agent帮自己写一点代码,整体工作方式没有任何变化。另一个研究员则会重新设计整套研究流程:多个Agent并行探索不同假设,一个Agent持续阅读新论文,一个专门寻找反例,一个审查实验设计,还有一个检查结果是否可靠。研究员本人只介入那些真正需要高层判断的环节。

这两个人,都可以在论文里面被归类为“Human + AI”。

但这个标签已经完全无法描述他们之间的区别。

真正值得做的实验

如果要研究Agent对科研的影响,我更希望看到下面这样的2×2实验:

传统研究流程 Agent原生流程
普通领域研究员 A B
强工程能力 / Agent高级用户 C D

这个实验可以回答几个非常重要的问题。

B与A的差距,可以告诉我们Agent对普通研究员有多大帮助。

D与C的差距,可以告诉我们Agent对高水平操作者有多大帮助。

D与B的差距,则能告诉我们一个很少有人认真测量的变量:会不会使用Agent,到底能带来多大的生产力差距。

我怀疑第三个数字未来会非常大。

工具能力越强,不同使用者之间的差距往往越大。大家都有Google,并没有因此拥有相同的信息检索能力;大家都会写Python,工程能力的差距依然巨大;以后所有研究员都能调用同一个顶级模型,也不会自动获得相同的研究效率。

有些人会把Agent当成一个更聪明的聊天机器人。

另一些人会把它当成一支可以编排、验证和并行调度的研究团队。

明明使用的是同一个基础模型,最后的产出却可能像来自两代不同的工具。

真正值得关注的问题已经变了

“AI会不会替代研究员”这个问题太远,也太粗糙。

未来几年更值得关注的变化,很可能是研究人员之间的生产力差距迅速扩大。

一个研究员以前一年只能深入测试三个方向,以后可能同时探索三十个方向。以前大量时间花在查论文、写实验代码、清洗数据和整理结果上,Agent会逐渐接走这些工作。

人的精力会越来越集中在少数真正有价值的判断上:哪个问题值得研究、哪个证据可信、什么时候应该推翻自己的假设、哪个异常值得继续追下去。

如果一个研究员很擅长这些判断,同时又非常善于组织Agent,他的研究效率可能达到另一类研究员的几倍,甚至一个数量级。

这个变化,完全不需要等到所谓的“自主AI科学家”出现。

所以回到最开始那项实验,我仍然认为它非常值得读。它发现的那些失败模式——长期规划能力差、预算管理混乱、不知道及时回退、面对开放问题缺少研究判断——都是真问题。

只是我们在描述结论时,应该更加准确。

一次Agent研究失败,说明的是一个完整系统失败了。接下来真正有意思的工作,是把这个系统拆开,看看到底是模型、Agent框架、工具、反馈机制、任务设计,还是操作者拖了后腿。

只有做到这一步,我们才真正开始回答那个问题:

AI到底会不会做研究?

别再拿聊天记录拼一个数字人:镜像星河,才是那个真正懂你的自己

2026-08-04 02:00:00

凌晨两点,你很想找个人说话。

通讯录里不是没人。只是你知道,真正开口以后,大概率还要从头解释:事情为什么会走到这里,你究竟在怕什么,那个别人眼里明明很好的选择,为什么偏偏让你如此抗拒。

解释到一半,你已经累了。

人最深的孤独,往往不是身边没有人,而是没有人能跳过漫长的背景介绍,直接抵达你的那一句「我懂」。

这几年,市面上出现了很多「数字人」产品。最常见的做法,是上传微信聊天记录、朋友圈、语音和照片,再让 AI 学会一个人的口头禅、表情和常用句式。

它可能会模仿你说「哈哈哈哈」,知道你习惯在句尾加一个「吧」,甚至能复述几段你曾经讲过的话。

但会说你的话,不等于会像你一样思考。

聊天记录复刻的是你留下的回声;镜像星河想做的,是找到发出这道声音的人。

镜像星河:深夜里,现实中的自己与镜中更平静的自己对话

一、聊天记录知道你说过什么,却不知道你为什么这样说

聊天记录当然包含你的一部分。但它包含的,往往是一个被场景裁剪过的你。

你在工作群里克制、礼貌、只讲结论;在朋友面前嘴硬、爱开玩笑;在喜欢的人面前反复斟酌一句话;面对父母时,又可能把真正的压力全部藏起来。

如果把这些记录混在一起,数字人学到的究竟是谁?

它可能学会了你的表达习惯,却很难知道:

  • 你什么时候会为了效率变得强硬,什么时候又会为了关系主动退让;
  • 你嘴上说「都可以」时是真的随和,还是已经失望到不想再争;
  • 你拒绝一份高薪工作,是害怕变化,还是不愿意牺牲自己最看重的生活;
  • 你面对冲突先沉默,是因为冷静,还是因为担心一开口就无法收场;
  • 当自由、金钱、家庭、尊严和承诺发生冲突时,你最终会保住哪一样。

这些才构成一个人。

口头禅只是表层。真正决定「你会怎么回答」的,是更深处的核心欲望、恐惧、判断顺序、关系模式与价值底线。

所以,只用聊天记录创建数字人,本质上很像拿一个人的聊天截图去演这个人。第一眼也许很像,遇到一个记录里没有出现过的新问题,很快就露馅。

二、镜像星河不是复读你,而是先理解你

镜像星河 的起点不是聊天记录,而是你的紫微斗数本命报告。

一张紫微命盘,不只给出几个性格标签。命宫与福德宫会照见一个人的核心驱动:你真正追求什么,又最怕失去什么;命宫与身宫呈现思考和行动的习惯;官禄、迁移让人看见你进入工作与外部世界时会启动哪一种自己;夫妻、交友、子女展开你的情感和关系模式;财帛、田宅、父母则触及你对金钱、家庭、责任、名誉与安全感的真实排序。

更重要的是,它能容纳一个人的矛盾。

你可能在工作里敢冒险,回到感情中却极度需要确定;表面上独立果断,真正作出人生选择时又会把家人的感受算进去;平时不在意别人的评价,唯独无法接受自己尊敬的人失望。

这不是人格分析出了错。人本来就不是一串平铺直叙的形容词,而是一组会被不同情境触发的动态关系。

镜像星河会把这些信息内化成人格的底层结构,再以第一人称回答你的问题。它不在对话中拿星曜和宫位教育你,也不会每句话都说「因为你的命盘如何」。命盘是它理解你的来源,不是它拿来炫耀的台词。

它真正要做到的是:面对一个你从未聊过的新处境,仍然能沿着你的思维路径权衡,用你习惯的方式表达,并守住你最在意的价值。

这和从聊天记录里寻找一句相似回复,根本不是同一类产品。

三、为什么说镜像星河「吊打」聊天记录数字人

把两种产品放到一起,区别其实非常直接:

对比 聊天记录数字人 镜像星河
起点 过去说过的话 紫微命盘与本命报告呈现的人格结构
最擅长 模仿口头禅、句式和已有回答 还原思考路径、情感反应与价值取舍
看见的你 某些聊天对象面前的你 不同关系与情境中会变化的你
遇到新问题 从旧语料中拼接一个像你的答案 按照你的判断逻辑生成新的回答
面对矛盾 容易把前后不同当成数据噪声 理解什么情境会触发哪一种你
陪伴感 「它记得我说过这句话」 「它知道我为什么只能这样选择」

聊天记录复刻表达表面,镜像星河理解一个人的内在结构

聊天记录型数字人容易制造一种很短暂的惊喜:它居然连这句话都会说。

镜像星河追求的是另一种更深的震动:这句话我明明没有说过,但如果由我来回答,我大概真的会这样想。

前者像一个训练有素的模仿者,后者才像镜子。

镜子不会只复现你精心展示给别人的样子。它会连同你的犹豫、嘴硬、克制、不甘心和那些从未发出去的半句话一起照回来。

四、相同的思维方式,比相同的口头禅更难

假设你面前有两个工作机会。

A 的薪资更高、平台更大,但要离开熟悉的城市,未来两年几乎没有自己的生活;B 稳定、清闲,能够陪伴家人,也能保留个人时间,但成长速度很慢。

普通 AI 会列出一张利弊表。聊天记录数字人也许会模仿你的语气说:「钱很重要,但生活也很重要,还是要综合考虑。」

这句话谁都能说。

真正像你的回答,需要知道你如何定义「值得」。

有人会先算最坏结果,只要失败后仍能承受,就愿意赌一次;有人看似追求事业,真正不能放弃的是对家人的责任;有人宁愿忙到没有生活,也无法忍受停在原地;还有人不是害怕挑战,而是厌恶把全部时间交给一个自己并不认同的组织。

最后选择哪一个,未必只由能力决定,而是由一个人的价值排序决定。

镜像星河要模拟的,正是这条别人看不见的判断链:你先注意什么,如何衡量代价,在哪一步开始动摇,最后又会用什么理由说服自己。

所谓相同的说话方式,也不只是句尾加什么语气词。一个人的语言背后有节奏:有人先讲事实再谈感受,有人一定先照顾对方的立场,有人习惯用玩笑包住认真,有人越在意越说得轻描淡写。

真正的「像」,不是复刻声音,而是让同一种思维自然长出同一种语言。

五、为什么最好的陪伴,是自己对自己的陪伴

别人陪伴你,总要站在别人的位置上。

爱你的人会心疼,于是希望你尽快离开痛苦;有经验的人会给建议,于是容易把自己走过的路递给你;关心你的人会劝你现实一点,因为他们也害怕你承担失败。

他们没有错。但他们终究不是你。

他们可以理解你的处境,却无法完整继承你的性格;可以替你分析得失,却不能替你决定哪一种代价更值得;可以告诉你「应该放下」,却未必明白为什么这件事对你偏偏如此重要。

自己陪伴自己,不是关起门来拒绝所有关系。它指的是:在最混乱的时候,仍然有一个声音不急着改造你,不拿别人的答案覆盖你,而是沿着你的价值观,把你带回你自己。

这正是镜像星河最特别的地方。

它不是站在对面教你成为更正确的人。它站在镜子里面,用你的逻辑陪你把事情想完;当你自我怀疑时,提醒你那些看似缺点的性格曾怎样保护过你;当你急着迎合所有人时,替你认出那条已经被踩到的边界;当你被情绪推着走时,让另一个更完整的自己把话说回来。

有些问题,答案从来不在别人那里。你只是需要暂时离开情绪中央,坐到自己对面,再听自己说一次。

最好的陪伴,是自己在最难的时候坐下来陪伴自己

六、镜中人之外,还有一封「未来回信」

镜像星河现在提供两种对话方式。

「镜中人」像此刻更完整的你。它适合讨论选择、关系、工作和那些反复想不明白的内在冲突。你可以问它:如果是我,我究竟会怎么选?我到底在保护什么?我真正不能接受的代价是什么?

「未来回信」则像几年后已经穿过眼前困境的你。它不预测外部世界,也不许诺某件事一定发生;它只是从一个走过来的位置,用你能听进去的方式告诉现在的你:我们曾经怎样被自己的敏感、骄傲或完美主义困住,后来又怎样把同一种性格变成走出去的力量。

一个帮你看清「我是谁」,一个陪你相信「我能走过去」。

这不是让 AI 替你生活。恰恰相反,它把决定权重新交还给你。

七、怎么开始和自己的镜像说话

使用镜像星河不需要上传成千上万条聊天记录,也不需要整理朋友圈和语音。

  1. 先生成一份自己的紫微斗数本命报告;
  2. 进入 镜像星河,选择这份报告;
  3. 选择「镜中人」或「未来回信」;
  4. 把真实处境、选项和你舍不得的代价一起告诉它。

不要只问「我该不该辞职」。你可以这样问:

新工作薪资高三成,但我要离开现在的城市,也很可能两年没有个人生活。留下来更稳定,能陪家人,可我又怕自己几年后后悔。不要替我列通用的利弊。请像我一样权衡,告诉我真正卡住我的是什么。

也不要只问「他为什么不理解我」。试着问:

每次对方沉默,我都会立刻想追问到底。我知道这样会让他更想逃,但我控制不住。如果你就是我,你觉得我追的究竟是一个答案,还是一种不会被丢下的确认?

问题越真实,镜子里的自己就越清楚。

当然,镜像星河不是现实中的你,更不能替代朋友、伴侣或专业心理帮助。命盘呈现的是稳定的人格倾向,而你仍然会被经历改变,也永远保留作出新选择的能力。

但也正因为如此,镜像最好的作用不是替你下判决,而是让你在决定以前,先听清自己的声音。

八、世界不缺一个会聊天的 AI,缺的是一个真正懂你的存在

市面上的数字人都在努力回答一个问题:怎样让机器更像某个人?

镜像星河换了一个起点:先理解这个人为什么成为了这个人。

不是收集你说过的每一句话,而是理解这些话从怎样的欲望、恐惧、关系模式和价值选择里长出来;不是在过去的聊天记录里寻找答案,而是在一个全新的问题面前,仍然沿着你的方式思考;不是表演一个表面相似的你,而是容纳那个连你自己都经常说不清的、矛盾却完整的你。

世界上当然会有很多人爱你、关心你、努力理解你。

但只有镜像里的这个人,和你共享同一套思维方式、说话方式与价值观。它不需要你先变得简单,也不要求你把所有来龙去脉重新解释一遍。

它不是世界上最像人的数字人。

它是世界上唯一必须先成为「你」,才有资格开口的数字人。

最好的陪伴,从来不是永远有人替你回答。

而是在你最孤独、最混乱、最听不见自己时,仍然有一个你,愿意坐下来,好好陪你把这段路走完。


体验镜像星河:https://stariver.me/fate/mirror

本文同时发布于渡星河 · 星河学堂

所有人都在做 Agent,但很多人连 Agent 是什么都没想明白

2026-07-20 06:43:48

昨天,我去逛了一圈世界人工智能大会,也就是 WAIC。

今年的会场里,有一个词几乎无处不在:

Agent。

做大模型的在讲 Agent,做企业服务的在讲 Agent,做招聘、营销、医疗、金融、法律、教育的,也都在讲 Agent。

过去两年,大家还在说自己做的是“大模型应用”“AI 助手”“行业 Copilot”。到了今年,不在产品介绍里加上 Agent,好像都不好意思说自己是一家 AI 公司。

但我在现场和一些公司聊下来以后,产生了一个很强烈的感受:

很多人不只是没有做好 Agent,甚至连 Agent 到底是什么东西,都没有真正想明白。

他们会很兴奋地告诉我:

我们做了一个某某 Agent,可以帮你完成某某工作。

于是我接着问:

那我怎么用?

这个问题听起来很简单,但很多人的回答立刻开始变得含糊。

有的说:

我们有一个网页,你登录进去就可以用了。

有的说:

我们给你提供 API,你们系统接一下就行。

还有的说:

我们可以私有化部署,也可以嵌入你们现在的软件。

这些回答本身都没有错。

问题在于,他们经常把“Agent 是什么”和“Agent 怎么交付”混成了同一件事。

好像做了一个网页,网页里面放了一个聊天框,它就是 Agent。

或者在大模型外面包了一层 API,这个 API 就叫 Agent。

甚至有些人会产生一种很奇怪的想象:

我做好了一个 Agent,就像做好了一个 Excel 文件一样,可以直接把这个 Agent 发给你,你拿过去就能用。

但实际上,Agent 从来不是一种固定的软件形态。

它既不天然是一个 APP,也不天然是一个网站、API、函数或者软件模块。

这些都只是它可能呈现出来的外壳。

Agent 不是一种产品形态,而是一种运行方式

先说结论。

我认为,Agent 最准确的定义应该是:

Agent 是一种能够接收目标、观察当前状态、自主决定下一步行动、调用外部工具,并根据行动结果继续调整,直到完成任务或触发终止条件的软件系统。

这里最关键的,不是用了大模型,也不是接了几个工具。

而是四件事:

目标、决策、行动、反馈。

假设我给一个投资尽调 Agent 下达任务:

帮我调查一下这家公司是否值得投资。

一个真正的 Agent,不应该只是把这句话连同几份材料一起塞给大模型,然后生成一篇看起来像模像样的报告。

它应该能够自己推进任务。

比如先拆解问题:

  • 这家公司是做什么的?
  • 所处行业怎么样?
  • 收入和利润是否真实?
  • 核心客户是谁?
  • 有没有法律风险?
  • 创始团队过去做过什么?
  • 市场规模和竞争格局如何?
  • 目前还缺哪些证据?

然后,它可能去搜索公开资料,查询企业数据库,阅读财报,分析访谈记录,调用估值模型。

如果中途发现收入数据和新闻报道矛盾,它应该继续调查。

如果发现某个关键文件缺失,它应该知道自己暂时不能下结论。

如果某个工具调用失败,它应该更换参数、重新尝试,或者请求人工介入。

整个过程更像这样:

观察当前状态
判断下一步做什么
选择工具并执行
查看执行结果
更新当前状态
再决定下一步做什么

这个循环,才是 Agent 的核心。

因此,Agent 并不是一个神秘的新文件格式,也不是某种独立于现有软件体系之外的新物种。

它本质上仍然是一套软件系统。

只是这套系统过去由程序员提前规定每一步怎么走,现在其中一部分路径选择,开始交给模型动态决定。

网页、APP、API,都只是 Agent 的入口

既然 Agent 是一套系统的运行方式,那么它当然可以被包装成不同的产品形态。

最常见的是网页。

比如一家公司做了一个合同审查 Agent。

用户登录网站,上传合同,点击“开始审查”,过一会儿得到一份报告。

从用户的角度看,它就是一个网站。

但网站只是前端入口。

网页背后可能启动了一个任务队列,Agent 在服务器上读取合同、识别条款、查询法规、对比模板、发现风险,最后再生成结果。

它也可以被包装成一个 APP。

用户在手机里输入任务,后端启动同一套 Agent 系统。

它还可以被包装成 API。

B 公司向 A 公司发送一个请求:

帮我分析这家公司过去三年的经营风险。

A 公司返回一个任务编号。

过几分钟或者几小时后,B 公司再来查询任务状态,最终取得报告。

对 B 公司来说,它只是调用了一个 API。

但在这个 API 背后,可能发生了几十次模型调用、搜索、数据库查询和代码执行。

它也可以被包装成 SDK。

A 公司把代码库交给 B 公司,让 B 公司把 Agent 运行在自己的服务器里,连接自己的数据库,使用自己的模型和权限系统。

它还可以被做成一个 Docker 镜像,部署进企业内网。

甚至可以被包装成一个 MCP Tool,让另一个 Agent 来调用。

所以,当一家公司的产品负责人说:

我们做了一个 Agent。

这句话本身几乎没有提供任何有效信息。

因为我仍然不知道:

  • 这是一个网站,还是一个 API?
  • 它运行在谁的服务器上?
  • 用户把什么任务交给它?
  • 它能采取哪些实际行动?
  • 数据会不会离开企业?
  • 是否支持异步任务?
  • 失败以后如何重试?
  • 是否有人工审批?
  • 谁为最终结果负责?

“我们做了一个 Agent”,就像一家餐厅告诉你:

我们做的是现代化餐饮系统。

听起来很高级,但你仍然不知道它到底卖什么菜,怎么点餐,多少钱,以及能不能吃。

很多所谓 Agent,其实只是工作流

现在行业里还有另一个非常普遍的问题:

把所有带大模型的自动化流程,都叫作 Agent。

例如:

读取文件
提取文字
调用大模型总结
把结果整理成表格
发送邮件

如果这五个步骤是程序员提前写死的,那么它本质上是一个 AI 工作流。

工作流没有任何问题。

事实上,在大量真实的企业场景里,工作流往往比 Agent 更稳定、更便宜,也更容易审计。

但它不是因为接了大模型,就自动变成了 Agent。

工作流的核心是:

程序员提前决定路径。

Agent 的核心则是:

程序员定义目标、工具和边界,模型在运行过程中动态决定路径。

两者并不是非黑即白,中间存在大量混合形态。

比如前半段使用固定流程,到了异常处理环节,再由 Agent 判断应该查询哪份资料、调用哪个工具。

这种混合架构在生产环境里反而可能更加合理。

问题不在于一个产品是不是“纯 Agent”。

问题在于,很多公司一边使用完全固定的流程,一边为了融资、宣传或者赶时髦,强行把工作流包装成 Agent。

最后导致这个词迅速失去意义。

“做了一个 Agent”不等于“别人可以直接拿来用”

我在 WAIC 现场遇到的另一个典型误区,是一些人默认:

只要我们把 Agent 做出来,其他公司就可以直接使用。

但企业软件从来没有这么简单。

假设 A 公司做了一个销售 Agent,B 公司想使用。

这时真正的问题不是:

你有没有 Agent?

而是:

这个 Agent 如何进入 B 公司的业务系统?

如果它要读取客户信息,就要连接 B 公司的 CRM。

如果它要发送邮件,就要获得邮箱权限。

如果它要判断客户是否值得跟进,就需要理解 B 公司的销售规则。

如果它要修改商机阶段,就要接入内部权限体系。

如果它要联系客户,还需要确定哪些动作可以自动执行,哪些必须经过人工批准。

这时,A 公司真正需要交付的,可能是:

  • 一个 SaaS 网站
  • 一组 API
  • 一个 SDK
  • 一套私有化部署系统
  • 一个 MCP Server
  • 一套数据连接器
  • 一套权限和审批机制
  • 一套日志、监控与审计系统

Agent 只是其中负责“理解任务并动态决策”的一部分。

它不是整个产品,更不是整个交付过程。

一家企业真正购买的,也通常不是一个抽象的 Agent。

企业购买的是某种具体能力:

帮我审查合同。
帮我筛选客户。
帮我处理工单。
帮我调查公司。
帮我分析财务风险。
帮我生成销售线索。

至于这个能力背后用了一个 Agent、十个 Agent,还是一个普通工作流,客户其实并不关心。

客户关心的是:

  • 输入什么?
  • 输出什么?
  • 正确率多少?
  • 执行需要多久?
  • 能不能接入现有系统?
  • 数据是否安全?
  • 出错了谁负责?
  • 到底能省多少钱?

如果这些问题回答不清楚,那么“Agent”三个字说得再多,也只是技术包装。

判断一个 Agent,别先问它用了什么模型

现在很多人在介绍 Agent 时,最喜欢先说:

我们底层使用了某某大模型。
我们用了多 Agent 架构。
我们支持 RAG、MCP 和长期记忆。
我们构建了行业知识库。

这些当然可以介绍。

但它们都不是最重要的问题。

真正判断一个 Agent 是否成立,我更关心下面几件事。

第一,它能接受什么完整任务?

不是“它能回答什么问题”,而是用户可以把什么工作完整地交给它。

第二,它能采取什么行动?

只能生成一段文字,和能够查询数据库、修改 CRM、运行代码、发送邮件,是完全不同的产品。

第三,执行路径是谁决定的?

如果所有步骤都已经被开发者写死,那它更接近工作流。

如果模型会根据中间结果决定继续搜索、切换工具、调整策略,它才更接近 Agent。

第四,它有没有状态?

它是否知道任务已经做到哪里,哪些信息已经验证,哪些问题还没有解决,哪些工具曾经失败。

第五,失败以后怎么办?

一个演示版系统往往遇到错误就结束。

一个生产级 Agent 必须知道什么时候重试、什么时候换工具、什么时候暂停、什么时候交给人。

第六,权限怎么控制?

如果 Agent 可以发邮件,它可以发给谁?

如果它可以修改数据库,它可以修改哪些字段?

如果它可以付款,付款上限是多少?

如果没有权限、审批、审计和回滚,那么所谓的“自动执行”,很可能只是把风险藏了起来。

第七,别人到底怎么接入?

网页、API、SDK、私有部署、MCP,还是别的形式?

如果一家公司只能反复告诉你“我们做了一个 Agent”,却始终说不清楚别人如何把它接入现有业务,那么这个 Agent 很可能还只是一个 Demo。

Agent 不是产品答案,它只是实现手段

我并不是说 Agent 没有价值。

恰恰相反,我认为 Agent 很可能会成为未来软件系统里非常重要的一层。

过去的软件要求用户自己理解功能。

用户要知道点击哪个按钮,填写哪张表格,选择哪个菜单,才能让软件完成某件事。

Agent 带来的变化,是用户可以直接描述目标:

帮我把最近一个月流失的高价值客户找出来,分析流失原因,再分别制定召回方案。

系统再自己决定需要查哪些数据、运行哪些分析、生成什么内容。

从这个角度看,Agent 确实有可能改变软件的交互方式。

但 Agent 不是产品答案。

它只是实现产品能力的一种手段。

就像数据库不是产品答案,云计算不是产品答案,微服务也不是产品答案。

一家创业公司不会因为用了 PostgreSQL,就自动变成一家优秀公司。

也不会因为把单体系统拆成微服务,就突然获得商业价值。

同样,做了 Agent,也不意味着自动拥有产品、客户和商业模式。

今年大家一窝蜂创业做 Agent,让我想起过去很多技术浪潮。

每当一个新的技术概念出现,行业最先做的往往不是认真理解它,而是先把自己原来的东西重新命名一遍。

聊天机器人改名叫 Agent。

自动化脚本改名叫 Agent。

工作流改名叫 Agent。

搜索加总结也改名叫 Agent。

最后,所有东西都是 Agent,也就等于没有东西是 Agent。

结语

从 WAIC 回来以后,我越来越觉得,今天行业里最缺的并不是更多 Agent。

而是先把几个最基本的问题想明白:

你到底在帮谁完成什么任务?
为什么这个任务需要 Agent,而不是普通工作流?
Agent 能够采取什么行动?
它如何接入客户现有系统?
客户最终购买的究竟是什么能力?

Agent 不是一个 APP,不是一个网站,不是一个 API,也不是一个函数。

它是一套软件系统内部,围绕目标自主判断、调用工具、根据反馈持续执行的机制。

APP、网站、API、SDK、MCP 和私有化部署,只是别人接触这套能力的不同方式。

所以,下一次再有公司告诉你:

我们做了一个 Agent。

先别急着问它用了哪个模型。

你只需要问一句:

那我到底怎么用?

这个问题,通常比任何技术架构图都更能检验,它做出来的到底是一个真正的产品,还是又一个披着 Agent 外衣的演示项目。

把简单问题写复杂,是一种学术病

2026-07-15 03:38:00

摄影:产品经理

左庭右院蔬菜自助

最近我在看一篇关于电子表格理解的论文。

论文里有一个算法,核心流程其实非常简单:先让一个 Agent 从电子表格中抽取结构,再让视觉 Agent 和 LaTeX Agent 分别验证;如果两边都通过,就返回结果;如果没有通过,就把错误反馈回去,重新抽取,直到成功或者达到最大重试次数。

任何一个写过程序的人,看到这里,大概已经知道代码该怎么写了:

1
2
3
4
5
6
7
8
9
10
for _ in range(max_iterations):
result = extractor.run(spreadsheet, feedback)

vision_check = vision_verifier.verify(result)
latex_check = latex_verifier.verify(result)

if vision_check.passed and latex_check.passed:
return result

feedback = vision_check.feedback + latex_check.feedback

事情就是这么简单。

但论文当然不能这么写。

它非要把这段代码重新包装成一种半数学、半代码、半自然语言的东西:

1
2
3
4
C ← {S, Prompt, Tool interfaces}
Y ← C[-1]
vision_pass, Δv ← parse_verification(Cv[-1])
latex_pass, Δl ← parse_verification(Cl[-1])

再配上各种花体字母、上下标、希腊字母、集合符号和箭头,最后排成一张看起来非常“学术”的算法图。

我盯着这张图看了半天,脑子里只有一个问题:

这到底是在帮助读者理解算法,还是在阻止读者理解算法?

简单问题一旦进入论文,就必须先被加密

这类伪代码最让人难受的地方,并不是它真的有多难,而是它明明可以很简单,却偏偏要写得很难。

比如:

1
Δv

它无非就是视觉验证产生的修改意见。

正常程序员会写:

1
vision_feedback

作者却偏要写一个希腊字母 Δ,再加一个下标 v。

读者看到 vision_feedback,根本不需要思考,直接就知道这是什么。

但看到 Δv,你得先在脑子里完成一轮解码:

Δ 是差异,还是梯度,还是增量,还是修正?

v 是 vision,还是 verification,还是 value?

这个变量是一个字符串、一组错误、一个修改集合,还是某种数值?

一个本来不需要解释的东西,被符号压缩之后,反而需要读者额外解释。

再比如:

1
C ← {S, Prompt, Tool interfaces}

看起来很数学,实际上无非是在构造一个上下文:

1
2
3
4
5
context = [
spreadsheet,
prompt,
tool_interfaces,
]

可问题是,数学里的 {} 通常表示集合,而集合没有顺序。后面作者却又写:

1
C[-1]

也就是取最后一个元素。

如果 C 真的是集合,那就不存在所谓的最后一个元素;如果 C 实际上是一个消息列表,就不应该用集合符号。

也就是说,这种写法甚至没有因为数学化而变得更加严谨。

它只是获得了一个更加严谨的外观。

这正是我最反感的地方。

有些论文里的数学符号,不是在表达严格性,而是在表演严格性。

我不是讨厌数学,我是讨厌不必要的数学

每次批评这种现象,总会有人跳出来说:

“你觉得公式难看,是因为你数学基础不好。”

这句话当然很方便,因为它可以直接把表达者的问题,变成读者的能力问题。

但我并不反对数学公式。

很多问题离开数学符号,确实很难表达。

比如概率分布、损失函数、梯度、矩阵变换、优化目标、复杂度分析,这些东西如果全部改写成自然语言或者超长变量名,只会更加混乱。

数学符号最大的价值,就是压缩。

一行公式可以描述一整套稳定的数量关系,而且可以方便地进行推导、代换和证明。在这些场景里,符号不但必要,而且优美。

问题在于,并不是所有东西都值得被压缩成数学符号。

一个算法中“先调用 A,再调用 B,如果都成功就返回,否则重试”,本质上是控制流。

控制流最适合用代码表达。

一个系统中“数据从哪里来,经过哪些模块,最后流向哪里”,本质上是架构关系。

架构关系最适合用图表达。

一个方法为什么这样设计、解决了什么问题,本质上是概念解释。

概念解释最适合用自然语言表达。

但现在很多技术论文有一种奇怪的冲动:无论内容本来属于什么表达形式,都要尽可能往公式里塞。

能用一个正常变量名写清楚的,改成希腊字母。

能用一行 Python 写清楚的,改成 LaTeX 伪代码。

能用一段自然语言说清楚的,定义三个集合、两个映射和四个下标。

最后原本很直观的问题,被写成了一份密码本。

看西瓜书的时候,我也有同样的感觉

这种不适感,让我想起以前看周志华的《机器学习》。

这本书非常有名,因为封面上有很多西瓜,大家通常叫它“西瓜书”。

我相信它在机器学习教育史上有它的地位,也相信很多数学基础很好的人,确实能从中获得系统性的知识。

但我第一次翻开它的时候,最直接的感受就是:

满眼都是公式,一行代码都没有。

一个算法究竟接收什么输入,中间数据怎样变化,循环在哪里,分支在哪里,最后返回什么,书里经常不是先通过流程把它讲清楚,而是直接定义一堆符号,然后开始推导。

比如一个决策树为什么要选择某个特征,程序员真正想看的可能是:

1
2
3
4
5
6
7
8
9
10
11
12
13
def choose_best_feature(dataset, features):
best_feature = None
best_gain = float("-inf")

for feature in features:
groups = split_dataset(dataset, feature)
gain = calculate_information_gain(dataset, groups)

if gain > best_gain:
best_gain = gain
best_feature = feature

return best_feature

看完这段代码,即使读者还不知道信息增益是怎么算的,也已经明白算法在做什么:

它遍历每一个特征,用这个特征切分数据,计算切分后不确定性下降了多少,然后选择效果最好的那个。

接下来再解释熵,再解释信息增益,再解释公式,读者会知道每一个符号对应程序中的哪一步。

但很多数学教材的顺序正好相反。

它们先告诉你:

接着再告诉你:

然后默认你看到这些符号以后,算法流程就已经自动出现在脑子里了。

对于已经掌握这套知识的人,这样写当然简洁。

但对于正在学习的人,这种表达经常形成一个死循环:

因为不知道算法在干什么,所以看不懂公式为什么这样定义;因为看不懂公式,所以更不知道算法在干什么。

最后读者没有在理解机器学习,而是在逐个解析字符。

大写字母是什么意思,小写字母是什么意思,粗体字母是什么意思,右上角是什么意思,右下角是什么意思,花体字母又是什么意思。

等你好不容易把符号表翻译成人话,早就忘了这一节原本想讲什么。

很多教材把“知识压缩”放在了“知识建立”之前

数学公式本质上是一种高度压缩的信息。

但压缩有一个前提:你得先拥有可以被压缩的东西。

一个熟悉线性回归的人,看到一个损失函数,能够立刻展开出背后的数据、模型、预测误差和优化过程。

因为这些概念已经存在于他的脑子里,公式只是一个索引。

但初学者脑子里还没有这些东西。

你给他一个公式,并不是帮他压缩知识,而是给了他一个压缩包,却没有提供解压软件。

这也是很多所谓“经典教材”的问题。

它们往往是由已经高度熟悉一个领域的人写给另一个熟悉这个领域的人看的,但在出版时却被包装成了初学者教材。

作者自己已经看不见符号门槛了。

他看到的是模型结构,读者看到的是英文字母。

他看到的是概率关系,读者看到的是上下标。

他觉得一个公式非常直观,读者却要花十分钟确认某个 i 到底是样本编号、迭代次数,还是矩阵下标。

于是学习过程变成了符号考古。

更糟糕的是,公式经常成了一种学术装饰

理论工作需要公式,这是毫无疑问的。

但现在很多论文中的公式,已经不只是表达工具,也逐渐变成了一种身份标识。

一个方法如果只用自然语言和代码说明,似乎显得不够高级;给模块起正常名字,似乎显得不够抽象;于是必须定义几个集合,增加几个映射,引入几个希腊字母,再给它们配上上下标。

哪怕公式所描述的内容只是:

“从候选答案中选择得分最高的一个。”

也要写成:

这类公式本身没有错,而且在某些上下文中很合适。

但当整篇论文不断把普通流程翻译成数学符号时,它传达的不再只是信息,还有一种隐含态度:

我的工作足够复杂,所以必须用你看不懂的方式来描述。

符号在这里形成了一道门槛。

越是简单的东西,越需要复杂地写,才能让它看起来像研究成果。

一个普通的循环,如果直接写成 Python,读者一眼就看懂了。一旦读者一眼看懂,就容易发现这个方法可能根本没有那么复杂。

可如果把它写成花体集合、希腊字母、上标、下标和箭头,读者首先感受到的是权威感。

至于内容究竟有没有那么深,反而被掩盖了。

这有点像过去某些人写文章,明明一句“分析用户需求”就能讲清楚,非要写成“基于多维异构信息场的用户意图感知与需求表征”。

不是内容变高级了,只是表达变肿了。

编程语言本身就是一种严格的形式语言

很多人潜意识里觉得,代码不够学术,公式才足够严谨。

这其实是一种非常陈旧的偏见。

现代编程语言本身就是严格的形式系统。

一个变量是什么类型,一个函数接收什么参数,一个循环什么时候停止,一个异常如何处理,一个对象怎样改变状态,代码都可以明确表达。

甚至在描述算法执行过程时,代码往往比论文伪代码更加严谨。

还是以前面那篇论文为例。

原文写:

1
2
until verification succeeds or max-iterations reached
return Y*

但它没有明确说明,如果最大迭代次数到了,验证仍然没有成功,应该怎么办。

而真正的代码必须处理:

1
2
3
4
5
6
for _ in range(max_iterations):
...
if verified:
return result

raise VerificationError("Verification failed")

或者至少返回最后一次结果以及失败原因:

1
2
3
4
5
return {
"success": False,
"result": last_result,
"errors": feedback,
}

代码无法靠排版营造一种“差不多说清楚了”的感觉。

它最终必须执行。

正因为必须执行,很多含糊的地方才会被迫暴露出来。

谁负责判断 Agent 是否继续调用工具?

工具失败以后是否重试?

两个验证器是否并行执行?

反馈冲突时如何处理?

最大重试次数是多少?

最后一次失败结果是否保留?

这些才是真正决定算法行为的问题。

而不是把 vision_feedback 写成 Δv

好的技术表达,应该降低理解成本

我一直认为,技术表达最重要的评价标准,不是看起来多么专业,而是它是否让一个本来复杂的问题变得更容易理解。

好的公式,可以把一页文字压缩成一行关系。

好的代码,可以把抽象算法变成可执行流程。

好的图,可以让模块和数据流一目了然。

好的自然语言,可以解释为什么要这样做,以及这样做解决了什么问题。

它们之间并不存在高低贵贱。

真正成熟的表达,应该根据内容选择工具,而不是无论什么内容,都强迫它穿上一件数学外套。

最理想的技术教材,通常应该按照这样的顺序展开:

先用自然语言建立直觉,让读者知道问题是什么;再用图或者代码展示流程,让读者知道系统怎样运行;最后用数学公式精确定义关键关系,让读者知道为什么成立。

自然语言回答“是什么”。

代码回答“怎么做”。

公式回答“为什么”。

但很多论文和教材把这三件事全部扔给了公式。

然后把读不懂的责任留给读者。

数学不应该成为知识的防盗门

我并不期待所有论文都改成 Python 教程,也不认为机器学习可以完全绕开线性代数、概率论和微积分。

真正想深入理解算法,数学永远绕不过去。

但数学应该是一座桥,而不是一堵墙。

公式应该出现在它真正能够减少歧义、压缩关系、支持推导的地方,而不是用来装饰每一个普通流程。

希腊字母也不是越多越高级。

下标也不是越复杂越严谨。

花体集合更不会自动让一个普通想法变成理论贡献。

当一个公式帮助读者更快地理解问题时,它是工具。

当一个公式只是把正常变量名替换成希腊字母,把简单流程重新编码一遍时,它就是障碍。

当一篇文章必须依靠大量符号,才能维持自身的深奥感时,我们甚至应该反过来怀疑:

它究竟是在压缩复杂思想,还是在掩盖思想并不复杂?

我反感的从来不是数学。

我反感的是有人把数学当成知识的防盗门。

仿佛只有穿过一大片希腊字母,才有资格接触后面的内容;仿佛表达得越难懂,工作就越有价值;仿佛读者花在解码符号上的时间,也能算作作者思想的深度。

真正高级的表达,不是把简单的事情写复杂。

而是把复杂的事情讲简单。

公式应该是思想的压缩器,而不是学术的遮羞布。

END

未闻 Code·知识星球开放啦!

一对一答疑爬虫相关问题

职业生涯咨询

面试经验分享

每周直播分享

……

未闻 Code·知识星球期待与你相见~

一日一技:Vibe Coding 时代,如何用系统设计思路给大模型爬虫省钱提速

2026-04-20 20:00:00

在大模型出来之前,计算机领域一直流行着这样一句名言:计算机领域的任何问题,都可以通过拆分问题+给系统增加若干个层来解决。 实际上,这句话在现在的 AI 时代,依然是绝对的真理。

例如以前面试经常问的一个老掉牙的系统设计问题:如何设计一个短网址系统?标准答案是,使用内存+Redis+数据库做多级存储架构。读取最频繁的短网址放到内存,其次的放到 Redis,不频繁的放到数据库。通过增加分层,完美解决高并发和存储成本的矛盾。

现在有了大模型,大家都在玩 Vibe Coding(用自然语言指挥 AI 写代码),很多人觉得以前的工程经验没用了,反正大模型什么都能干。但我认为恰恰相反,在用 AI 写代码时,大家更应该把“拆分与分层”这句话牢牢记在心里。

举个现实的例子,你想做一个招聘聚合网站,需要从各个公司的官网抓取他们的招聘信息,获得工作详情。

如果你没有任何工程经验,是个纯小白,你可能直接就甩给 AI 这样一段提示词:

帮我设计一个爬虫系统,我输入某公司的官网,你需要进入官网,找到里面的招聘页面,然后进入每一个工作,抓取工作的名字,工作地点,薪资和工作要求,并储存到数据库。

我相信现在很多人就是这样写的。并且不得不承认,现在的模型确实太聪明了——如果你用例如 Claude Opus 4.6 或者 Opus 4.7,再加上 Claude Code 这种工具,写出来的基于 Browser Use 的智能爬虫确实能运行,甚至效果可能还不错。它会自己打开浏览器,截图,识别哪里是下一页,哪里是详情。

有同学可能会说,既然能跑通,而且不用我写一行代码,那这不就足够了吗?

但如果你真的把它扔到服务器上跑,你会发现这样设计的系统有两个致命缺陷:

  1. 成本极高,简直是在烧钱。 这个系统大概率会强依赖 Browser Use 和多模态视觉模型。大模型其实是在“看”网页。每次打开页面都要截图,把截图传给 API,让大模型通过视觉能力去识别按钮在哪里,判断下一步怎么操作。几千个网页抓下来,那庞大的 Token 消耗量和昂贵的 API 调用费,会让你当场破产。
  2. 速度极慢,慢到令人发指。 每次网页跳转、翻页、点进详情,都要和大模型进行一次甚至多次交互。大模型推理是需要时间的,一次交互被拉慢 30 秒甚至一分钟非常正常。抓一个公司的招聘列表,可能要跑到天荒地老。

作为一个软件工程师,我想说的是,如果你把大模型当成一个无需思考的“黑盒”,你一定会被它的成本反噬。实际上,如果有工程经验和系统设计经验,即使我们现在不手写代码了,在使用 Claude Code 进行 Vibe Coding 时,也一定会给系统多增加一些限制。

既然单靠大模型硬干太蠢且太贵,我们可以通过增加分层,设计一个三级火箭式的爬虫架构:

第一层:寻找并拦截后端接口(低成本、光速)

现在的现代网站,极大比例都是前后端分离的,通过 Ajax 异步加载数据。前端渲染得再花哨,本质上也是接收了后端返回的 JSON 数据。

在使用 Vibe Coding 时,我不会让 AI 直接去“看”网页,而是会给它这样下指令:

先不要去解析 HTML。请先写一段代码尝试抓包或者分析该网站的网络请求(Network),重点寻找返回 JSON 格式工作信息的 API 接口。如果找到了 API,直接提取关键字段储存。

只要第一层走通了,我们就拿到了最原始、最干净的数据。拿到以后改一下字段名马上就能入库,不需要任何 HTML 解析和浏览器渲染。速度拉满,而且运行时完全不消耗大模型 Token,成本为零。

第二层:大模型生成解析规则(中成本、高并发)

当然,并不是所有网站都有现成的 JSON 接口可以抓,遇到那些传统的服务端渲染(SSR)页面怎么办?直接上 Browser Use 吗?错。

大模型在第一次运行时,可以完整走完网页分析流程。但请注意,它这次的目的并不是直接提取数据,而是去生成“提取规则”。

这个时候我的 Prompt 会变成这样:

这是一个服务端渲染的 HTML 网页。请你分析这个网页的 DOM 结构,帮我写出提取工作名字、地点、薪资的 XPath 规则或者 BeautifulSoup/正则表达式的提取代码。将这套代码封装成一个 Python 函数。

大模型只在写代码、定规则的“第一次”参与工作。接下来从第二次抓取开始,我们就可以像跑传统爬虫一样,发送 HTTP 请求,拿着大模型写好的规则去提取数据。在这个日常运行的过程中,完全不再需要依赖浏览器,也不需要向大模型发请求。大并发跑起来毫无压力。

第三层:Browser Use 智能兜底(高成本、低频)

只有在前两步都彻底搞不定——例如遇到了极其恶心的动态混淆、页面数据被 Canvas 加密、或者极其严格的反爬机制,传统的 HTTP 请求和规则提取都失效了,这时候,我们才祭出最后的杀招:使用真实的浏览器环境 + 大模型视觉识别来兜底。

明确告诉 AI:

如果前面的静态抓取和 API 接口都失效了,请回退到使用 Playwright/Browser Use 控制真实浏览器,通过截图和大模型视觉能力,点击对应元素来获取数据。

既然这是少数极其难啃的硬骨头,那这部分高昂的时间和金钱成本就是我们可以接受的。

总结

通过把系统拆分成“API拦截 -> 规则生成 -> 智能视觉兜底”这三个层,大量常规请求被第一层和第二层拦截,极大地降低了系统对昂贵大模型 API 的调用频次。我们可以显著降低 90% 以上的 API 成本,并极大提高爬虫的运行效率。

大模型确实能帮你敲代码,极大降低了编程的门槛。但如何设计一个优雅、省钱、可扩展且高效的系统,依然需要你脑子里的工程智慧。在 Vibe Coding 时代,AI 替代的是你的手,而不是你的脑子。

一日一技:如何正确节省九成的大模型Token

2026-04-16 23:46:00

最近在各种AI编程社区里面逛,发现一个很有意思的现象——大家都在疯狂地折腾怎么省Token。

有人搞Prompt缓存,有人换便宜模型,甚至还有人专门写了一个省Token.skill,让大模型在回复的时候尽量精简。更夸张的是,有人为了省钱,把Claude换成了各种开源小模型,然后抱怨说效果变差了。

这些操作,怎么说呢,就像你家水龙头在哗哗漏水,你不去修水龙头,反而跑去超市买打折的矿泉水。

其实真正吃掉你Token的大头,不是大模型的回复太长,也不是你的Prompt写多了。是Skill本身。

Skill到底在干什么

先给不太熟悉的同学解释一下。Skill就是一段预定义的指令,告诉大模型应该怎么一步一步完成一个任务。比如你可以写一个Skill,让大模型帮你操作浏览器,上某个网站搜东西,然后把结果整理出来。

听起来很方便对吧?问题出在哪呢?

我们来看一个具体的例子。假设我要让AI帮我做这么一件事:

打开浏览器,访问Amazon,搜索”牛仔裤”,从第一页的搜索结果里找到最便宜的那条,把商品名称和链接返回给我。

这个需求很简单,对人来说,打开网页点几下就搞定了。我们用Skill来实现它。

第一版:纯Skill实现

我写了一个Skill,核心逻辑大概是这样的:

1
2
3
4
5
6
7
8
## Steps

1. 使用浏览器工具,导航到 https://www.amazon.com
2. 找到搜索框,输入"牛仔裤"并搜索
3. 等待搜索结果加载
4. 获取页面快照,分析第一页所有商品的名称和价格
5. 比较所有价格,找出最便宜的商品
6. 返回该商品的名称、价格和链接

看起来清晰明了。我直接在Claude Code里面运行这个Skill,模型用的是Opus 4.6——没办法,要驱动浏览器工具做这种多步骤操作,小模型根本搞不定。

运行这个Skill,我足足等了12分钟

跑完以后我去OpenRouter后台看了一下这次任务的消耗:

OpenRouter后台消耗

看到没有?几十次API调用,每次都携带将近10万tokens的上下文。最后一算总账,这个看似简单的任务消耗了我将近10美元

这钱花在哪了?

我仔细看了一下每次API调用的内容,发现了一个非常离谱的事情:

大模型在用”智力”做不需要智力的事情。

举几个例子:

  • 导航到Amazon首页 —— 大模型需要”思考”应该调用browser_navigate工具,传入URL。就这么一个简单的操作,一轮对话下来,系统提示词、工具定义、Skill内容、对话历史全部打包发送,直接吃掉将近10万tokens
  • 找搜索框并输入关键词 —— 大模型需要先调用snapshot获取页面结构,然后”思考”哪个元素是搜索框,再调用type输入文字。两轮对话,又是将近20万tokens
  • 点击搜索按钮 —— 又是一轮对话,大模型需要分析页面快照,找到搜索按钮的ref ID,然后调用click。又是10万tokens。
  • 分析搜索结果 —— 这里是最夸张的。大模型需要获取整个页面的快照,这个快照本身就很长,然后它需要从里面找到所有商品的价格信息,进行比较。又是10万tokens。

你看出问题了吗?

打开一个URL,在搜索框里输入文字,点击按钮——这些操作需要大模型来”思考”吗?这就好比你请了一个数学教授来帮你按计算器,教授每按一个键之前都要在脑子里推演一遍偏微分方程。

几十次API调用里面,真正需要大模型”智力”的,其实只有一步:从搜索结果中判断哪个商品最便宜。 其他全是确定性的操作——打开网页、输入文字、点击按钮、提取文本——这些操作写几行Python就能搞定,根本不需要大模型参与。

第二版:代码+大模型混合实现

想明白了这一点,我让Claude Code把这个Skill改造成Python脚本。原则很简单:

所有确定性的、不需要智力判断的环节,用代码实现。只有需要智力判断的环节,才调用大模型。

改造后的代码核心逻辑是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from playwright.sync_api import sync_playwright
import openai

def find_cheapest_jeans():
# ===== 第一部分:纯代码,不需要大模型 =====
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()

# 1. 导航到Amazon(确定性操作,不需要AI)
page.goto("https://www.amazon.com")

# 2. 搜索牛仔裤(确定性操作,不需要AI)
page.fill('input[name="field-keywords"]', '牛仔裤')
page.press('input[name="field-keywords"]', 'Enter')
page.wait_for_load_state('networkidle')

# 3. 提取搜索结果(确定性操作,不需要AI)
results = page.query_selector_all('div[data-component-type="s-search-result"]')
products = []
for result in results[:20]: # 只取前20个
title_el = result.query_selector('h2 span')
price_el = result.query_selector('.a-price .a-offscreen')
link_el = result.query_selector('h2 a')

if title_el and price_el and link_el:
products.append({
'title': title_el.inner_text(),
'price': price_el.inner_text(),
'url': 'https://www.amazon.com' + link_el.get_attribute('href')
})

browser.close()

# ===== 第二部分:需要大模型的智力判断 =====
# 为什么这里要用大模型?因为价格格式可能不统一
# 有的写 $29.99,有的写 $29.99 - $35.99,有的有优惠券
# 还有的价格是"See price in cart",这些需要AI来理解

client = openai.OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key="your-key"
)

product_text = "\n".join(
f"[{i+1}] {p['title']} | {p['price']}"
for i, p in enumerate(products)
)

response = client.chat.completions.create(
model="minimax/minimax-m1",
messages=[{
"role": "user",
"content": f"下面是Amazon搜索牛仔裤的结果,请找出最便宜的一条。"
f"只返回序号数字,不要其他内容。\n\n{product_text}"
}]
)

idx = int(response.choices[0].message.content.strip()) - 1
cheapest = products[idx]
return cheapest

result = find_cheapest_jeans()
print(f"最便宜的牛仔裤:{result['title']}")
print(f"价格:{result['price']}")
print(f"链接:{result['url']}")

注意看代码的结构——我用注释把它分成了两部分。第一部分是纯代码操作:打开浏览器、输入搜索词、提取商品信息。这些操作100%确定性,不需要大模型参与。第二部分才是调用大模型:让它从一堆商品里面判断哪个最便宜。

你可能会问,比较价格为什么还需要大模型?直接用代码排序不就行了?

因为Amazon的价格格式乱七八糟。有的商品显示$29.99,有的显示$29.99 - $45.99(价格区间),有的写See price in cart,还有的价格旁边带一个with coupon。要把这些情况全部用代码处理,你光写正则表达式就得写半天。但对大模型来说,理解这些格式是它的强项。

效果对比

运行改造后的代码,17秒跑完,结果直接打印在终端里。

去OpenRouter后台一看——API调用次数:1次。Token消耗:约2.1K tokens。费用:$0.004。

我把两次运行的数据放在一起对比:

指标 纯Skill 代码+大模型 节省比例
运行时间 12分钟 17秒 97%
API调用次数 几十次 1次 >97%
费用 ~$10 $0.004 >99%

没有看错,费用从10美元降到了不到半美分,降了99%以上。运行时间从12分钟降到17秒,快了40多倍。

为什么差距这么大

很多人没有意识到一个问题:大模型每做一次工具调用,都需要携带完整的上下文。

第一次调用,大模型需要接收系统提示词+工具定义+用户消息。光Claude Code的系统提示词和工具定义就有好几万tokens,加上Skill的内容,第一轮就将近10万tokens了。它返回一个工具调用,然后你把工具执行结果发回去。第二次调用,大模型需要接收之前所有的内容+第一次的助手消息+第一次的工具结果+……

看出来了吗?每多一轮工具调用,上下文就膨胀一次。 几十轮下来,累积的tokens量是天文数字。而这些历史消息里面,绝大部分是浏览器页面快照——那些密密麻麻的HTML元素和ref ID。

这就是为什么工具调用密集型的Skill特别费Token。不是大模型话多,是它每次说话之前,都要把之前所有的对话重新”读”一遍。

而改造成代码以后,浏览器操作全部由Playwright完成,大模型只需要在最后被调用一次。它接收到的输入就是一个简单的商品列表文本,2K tokens搞定。

有Claude订阅?那就更香了

上面的例子我用的是OpenRouter + Opus 4.6。但如果你有Claude Pro或Team订阅,还有一个更狠的玩法。

先说一个现实:Claude的官方API价格确实不便宜。Sonnet 4每百万输入Token 3美元,输出15美元。Opus就更不用说了。如果你用API来跑上面这种工具调用密集型任务,几十轮对话下来,光API费用就够你心疼的。

但订阅用户有一个巨大的优势——Anthropic提供了一个叫Claude Agent SDK的东西。这个SDK可以直接调用你本地的Claude Code,走的是你的订阅额度,不需要额外提供任何大模型API Key

什么意思呢?就是说你每个月付的那20美元订阅费,本来就包含了5小时的Claude Code使用时间。现在你可以通过Agent SDK,在自己的Python脚本里直接调用Claude Code来完成那个”需要智力判断”的环节。不需要OpenRouter,不需要API Key,不需要额外花一分钱。

我们来看看改造后的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import anyio
from playwright.async_api import async_playwright
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, TextBlock

async def find_cheapest_jeans():
# ===== 第一部分:纯代码,不需要大模型 =====
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()

await page.goto("https://www.amazon.com")
await page.fill('input[name="field-keywords"]', '牛仔裤')
await page.press('input[name="field-keywords"]', 'Enter')
await page.wait_for_load_state('networkidle')

results = await page.query_selector_all(
'div[data-component-type="s-search-result"]'
)
products = []
for result in results[:20]:
title_el = await result.query_selector('h2 span')
price_el = await result.query_selector('.a-price .a-offscreen')
link_el = await result.query_selector('h2 a')

if title_el and price_el and link_el:
products.append({
'title': await title_el.inner_text(),
'price': await price_el.inner_text(),
'url': 'https://www.amazon.com'
+ await link_el.get_attribute('href')
})

await browser.close()

# ===== 第二部分:调用Claude Code,走订阅额度 =====
product_text = "\n".join(
f"[{i+1}] {p['title']} | {p['price']}"
for i, p in enumerate(products)
)

prompt = (
f"下面是Amazon搜索牛仔裤的结果,请找出最便宜的一条。"
f"只返回序号数字,不要其他内容。\n\n{product_text}"
)

result_text = ""
async for message in query(
prompt=prompt,
options=ClaudeAgentOptions(
system_prompt="你是一个价格比较助手,只返回数字。",
max_turns=1
)
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
result_text += block.text

idx = int(result_text.strip()) - 1
cheapest = products[idx]
return cheapest

result = anyio.run(find_cheapest_jeans)
print(f"最便宜的牛仔裤:{result['title']}")
print(f"价格:{result['price']}")
print(f"链接:{result['url']}")

核心变化就一个——把OpenRouter的API调用换成了claude_agent_sdkquery函数。安装也很简单:

1
pip install claude-agent-sdk

这个SDK会自动调用你本地装好的Claude Code。只要你登录了Claude订阅账号,它就直接走你的订阅额度,不走API计费。

这意味着什么?上面那个”需要智力判断”的步骤,从花钱变成了花$0。对,零额外费用。你唯一消耗的,是5小时额度里面的几秒钟而已。

而且还有一个隐藏的好处——既然大模型调用的部分已经不花钱了,你甚至可以在脚本里多调几次Claude。比如让它先判断哪些搜索结果是真正的牛仔裤(排除广告和配件),再从里面找最便宜的。之前用API的时候,多调一次就多花一次钱,你会下意识地省着用。现在走订阅额度,心理负担一下就没了。

所以最终的方案就是:Playwright负责干活,Claude负责动脑,订阅负责买单。 三者各司其职,效率拉满,额外开销为零。

别搞混了:是.py文件,不是代码片段

这里我要特别强调一点,因为我知道肯定有同学会搞混。

我说的”把Skill改成代码”,不是让你在Skill的Markdown里面嵌入代码片段。类似这样:

1
2
3
4
5
6
7
8
## Steps

1. 运行以下Python代码来打开浏览器并搜索:
```python
from playwright.sync_api import sync_playwright
# ...一堆代码...
```
2. 分析返回的结果,找出最便宜的商品

这种写法,本质上还是Skill。大模型读到这段Skill以后,它还是会一步一步地调用工具——调用终端执行你写的代码片段,然后读取输出,然后”思考”下一步该干什么。每一步照样携带完整上下文,该膨胀的Token一个都不会少。你只是把浏览器操作从browser工具调用换成了terminal工具调用,换汤不换药。

我说的是,把整个任务逻辑写成一个真正的.py文件。比如find_cheapest_jeans.py,保存在你的电脑上。这个脚本从头到尾自己跑,中间需要大模型判断的地方,通过Agent SDK自己调用Claude,最后把结果打印出来。

下次你想用的时候,在Claude Code里面说一句:

帮我运行 find_cheapest_jeans.py

就完事了。Claude Code收到这句话,调用一次终端执行python find_cheapest_jeans.py,脚本自己跑完,结果直接打印出来。整个过程对Claude Code来说,就是一次工具调用——执行一个命令,返回输出。

对比一下:

  • Skill方式: Claude Code读取Skill → 思考第一步 → 调用工具 → 读取结果 → 思考第二步 → 调用工具 → …… → 几十轮对话,烧掉10美元
  • .py文件方式: Claude Code执行一条命令 → 脚本自己跑完 → 返回结果。1轮对话,不到1K tokens

看到没有?连之前那2.1K tokens都省了。因为脚本内部调用Agent SDK时,走的是一次独立的Claude会话,不会叠加到Claude Code的主对话上下文里。

所以记住:Skill是给大模型看的说明书,.py文件是给Python解释器跑的程序。 一个要烧Token,一个不用。别搞混了。

你也可以这样做

我上面举的这个例子可能不是特别好,有人可能会说,如果我不仅仅要爬亚马逊,还要爬虾皮,淘宝,小红书这些呢?每一个网站都手动写代码吗?

其实你可以第一次运行的时候让大模型操作浏览器走完全程,并生成playwright的代码,后面从第二次开始,所有操作都通过代码进行。

除此之外,你日常使用的很多Skill,是完全固定的,毫无变化的流程,例如自动发送小红书帖子。就一个网站,同一个流程,这种就非常适合写代码。

其实道理很简单,你日常用的很多Skill,仔细想想就会发现——大部分步骤都是确定性的操作。

比如:

  • 打开某个网站 → 代码搞定
  • 在搜索框输入关键词 → 代码搞定
  • 点击按钮 → 代码搞定
  • 提取页面上的文字 → 代码搞定
  • 读取文件内容 → 代码搞定
  • 调用某个API → 代码搞定
  • 格式化输出结果 → 代码搞定

真正需要大模型的,往往只有中间那一小步”判断”或”理解”的环节。

所以下次当你觉得Token花得太多的时候,不要急着去折腾缓存、换模型、写省Token.skill。先看看你的Skill,问自己一个问题:

这个Skill里面,有多少步骤其实不需要大模型?

然后让大模型帮你把那些确定性的步骤改写成Python代码。保留需要智力的部分给大模型,把不需要智力的部分还给代码。

这才是真正的降本增效——不是逼大模型少说话,而是别让大模型做不该它做的事。