标签归档:AI

历史总是在重演,AI 时代的我们应该做些什么

很多公司以为自己接入了几个大模型,采购了一批智能体工具,员工就获得了某种近乎无限的生产力。

换个角度看:每个人突然多出了一百万名能力不稳定、缺乏上下文、不会主动澄清目标、偶尔虚构进度、还能高速消耗预算的下属。

这些下属不需要工位,也不会请假。它们一天可以提交上千次结果,看起来永远在工作。管理者很容易被这种吞吐量迷惑,误把生成速度当成有效产出,误把调用次数当成自动化程度,误把一段流畅的回答当成任务已经完成。

AI 把执行成本压得很低,同时把管理问题放大了。

今天的智能体系统可以被看成一种新型组织。模型是员工,token 是人力预算,上下文是岗前培训,工具权限是组织授权,工作流是汇报关系,评估体系是绩效制度,人工验收则对应管理责任。

按照这个视角观察,很多 AI 项目的失败也是情里之中。它们把模型能力当成唯一变量,却没有建立与之配套的管理系统。结果类似一家突然扩张到百万人的公司:招聘极快,职责模糊,没有培训,没有绩效标准,管理者还希望它自行涌现出秩序。

历史上,这类问题出现过。

铁路旧事

十九世纪三十年代的铁路热潮带来了前所未有的运输能力。铁路解决了距离和速度问题,也制造了规模、调度、协作和安全问题。

单条铁路容易运营。线路变长、车次增加、岗位分化以后,系统复杂度迅速上升。信息必须跨地区传递,车辆必须统一调度,责任必须分层,事故必须被记录和复盘。原有的管理方式无法支撑新基础设施的吞吐量,事故随之发生。

铁路公司最终补上的,是现代管理体系。

技术增加了系统能力,管理制度把能力组织成可持续的产出。铁路后来成为第一个十亿美元产业,支撑它的并非轨道和机车本身,还包括围绕大规模协作建立的组织结构。

AI 正在重演类似的路径。

过去的软件系统严格服从预定义逻辑。输入符合条件,程序进入对应分支。工程团队可以通过代码结构、类型系统、测试和运行指标逐层收紧系统行为。

智能体的行为边界宽得多。它可以搜索、分析、生成、调用工具、保存记忆、继续拆解任务。它也可能误解任务、忽略约束、重复调用、把猜测写成事实,在结果看似完整时掩盖中间步骤的错误。

当模型调用规模扩大,问题便从「它会不会回答」变成「我们怎样管理一支由概率模型构成的劳动力」。

许多企业仍在用采购软件的思路处理这件事:买更强的模型,开放更多上下文,增加 token 预算,再连接更多工具。

这很容易走向失控。

人海复现

遇到复杂任务就增加 token,和过去遇到项目延期就增加人手,逻辑高度相似。

管理者看到结果不好,第一反应往往是扩大上下文窗口,让智能体多思考几轮,再增加几个子智能体并行搜索。系统图越来越复杂,调用链越来越长,账单同步上涨。

问题可能出在任务定义上。

一个智能体收到「分析这家公司是否值得投资」,它需要自行猜测分析期限、风险偏好、数据范围、估值框架和输出用途。另一个智能体收到「优化系统性能」,它也要猜瓶颈位于吞吐量、尾延迟、内存占用、启动时间还是硬件成本。

人类员工面对这种指令,会追问。智能体更可能直接开始工作。它会用流畅语言填补任务中的空白,把未经确认的假设埋入推理过程,最终交付一份结构完整、目标偏离的结果。

给它更多 token,只会让偏离过程更长。

这和组织扩张中的人海战术没有本质差异。需求尚未稳定时增加开发人员,沟通路径随人数增长,信息损耗也随之增长。新增人员首先要理解问题,再理解已有方案,然后处理方案之间的冲突。最后,大量时间花在协调新增人力本身。

多智能体系统也会出现同样的问题。

一个规划智能体拆任务,多个执行智能体并行处理,汇总智能体负责合并,审查智能体再做验证。架构图确实很漂亮。但实际运行时,规划阶段的歧义被复制到所有分支,各个执行智能体基于不同假设工作,汇总阶段只能用更多 token 消解冲突。

最终系统花费大量计算资源,证明自己已经花费了大量计算资源。

智能体反复自我调用的循环尤其典型。表面上看,它在持续反思和改进;深入观察调用轨迹,常常会发现它没有获得新的外部信息,也没有引入新的判定标准,只是在几个近似答案之间改写措辞。

这种循环不会自然收敛。缺少验收条件时,「继续思考」没有终点。

工程上必须为循环设置退出规则:哪些指标达到后停止,连续多少轮没有新增信息后停止,成本超过多少后转人工,发生哪些工具错误后禁止重试。退出规则缺失,智能体就会把预算消耗当成工作进展。

上下文债务

几乎没人会给 AI 恰当的语境。

这句话听起来像提示词问题,实际涉及企业知识怎样存在、怎样更新、怎样被验证。

当一个人在公司里工作几年,会形成大量隐性知识。他知道某个字段名与实际含义不同,知道某项流程在文档里有三步、落地时有七步,知道某个客户的特殊约定,知道哪些数据能够使用,哪些结论虽然算得出来却不能直接发布。

这些知识分散在人的记忆、聊天记录、会议结论、历史工单和代码注释中。公司过去可以容忍这种状态,因为熟练员工承担了知识路由器的角色。谁遇到问题,找对人问一句即可。

AI 无法稳定获取这种语境。

把所有资料塞进上下文也解决不了。上下文越长,噪声越多;资料之间可能相互冲突;旧制度和新制度可能同时出现;局部例外可能被模型理解成通用规则。检索系统可以减少输入量,却无法自动判断哪份知识具备权威性。

上下文工程因此要处理四类问题。

第一类是范围。智能体完成当前任务究竟需要哪些信息,哪些材料只会分散注意力。范围太窄会漏掉约束,范围太宽会增加延迟和成本,也会提高错误引用的概率。

第二类是时效。文档必须带有版本、适用日期和失效条件。缺少这些元数据,模型很难区分现行规则与历史记录。

第三类是权威级别。制度文件、团队约定、个人经验和历史案例不能拥有相同权重。检索结果需要体现来源优先级,冲突时还要触发澄清或人工审批。

第四类是任务绑定。知识必须与执行步骤建立关系。把二十份文档交给智能体,让它自行判断何时使用,等于把一摞制度放到新员工桌上,然后要求他当天独立处理高风险业务。

上下文管理本身就是管理工作。它对应人类组织中的培训、制度建设和岗位说明。

企业在这里还会遇到政治阻力。

熟练员工掌握的独门知识,往往构成他在组织中的议价能力。让他把这些知识结构化地交给 AI,等于要求他亲手降低自身稀缺性。员工可能口头支持,实际只提交表层流程;关键判断仍保留在脑中,文档写得正确却无法操作。

靠宣传无法解决这种冲突。

知识沉淀必须进入正式职责,并与岗位价值重新绑定。贡献高质量规则、案例和评估集的人,需要获得与业务产出相当的认可。否则,组织一边要求员工共享知识,一边继续按照「不可替代程度」奖励个人,制度会驱动所有人保留信息。

AI 转型推进到深处,技术阻力通常会下降,组织阻力会持续上升。

冗员变形

传统组织里的冗员不一定完全不工作。他可能参加会议、整理材料、同步状态、反复确认,把时间消耗在缺少业务增量的活动上。

智能体也能制造同类繁忙。

大量 token 用于复述任务、生成计划、解释已经执行的步骤、重写已有答案。输出篇幅持续增长,新增信息却接近于零。调用记录看起来很丰富,真正影响最终决策的内容只占很小一部分。

「八成 token 什么都没做」虽然带有夸张色彩,却很接近许多智能体工作流的结构性问题。

衡量 token 效率不能只看输入输出数量。更合适的单位是有效决策增量:一次调用是否增加了新证据,是否排除了一个错误方向,是否完成了可验证的执行动作,是否降低了后续人工判断成本。

如果一轮调用没有完成以上任何一项,它大概率属于计算冗员。

企业很容易用平均调用成本掩盖这个问题。单次模型调用足够便宜时,团队会觉得多跑几轮无所谓。规模扩大后,浪费会在三个方向累积:直接推理成本、任务延迟,以及人工审查负担。

第三项经常被忽略。

智能体每多生成一份结果,人就多承担一份潜在验收工作。机器吞吐量可以在短时间扩大几十倍,人的审查能力没有同步扩张。最终形成新的队列:模型输出堆积,员工随机抽查,错误在未被发现的情况下进入下游。

这时再增加智能体,只会继续扩大待验收库存。

需要被放大的,是能够显著改变结果的「100 倍 token」。某次调用拿到了决定性证据,识别了关键矛盾,修正了任务边界,或者发现了会导致整条工作流失败的风险。这类调用数量很少,贡献却远高于普通生成。

寻找它们依赖调用追踪和结果归因。

每个工作流至少要记录:调用目的、输入来源、使用工具、产生的新信息、对最终结果的影响、失败类型以及人工修改位置。没有这套记录,团队只能看到账单和最终文本,无法分辨哪些调用有效,哪些调用只是增加长度。

这类似分析一个大型团队。只看员工人数和工作时长,无法判断组织效率。必须知道关键决策在哪里发生,哪些岗位形成瓶颈,哪些汇报关系制造重复劳动。

评估先行

管理智能体最有效的抓手是评估标准,也就是 evals。

编程成为 AI 当前最成功的应用场景,与代码天然具备可评估性有很大关系。程序可以编译或运行,测试可以通过或失败,性能可以测量,回归可以复现。模型生成的内容即使风格不同,也能被放入相对稳定的验证框架。

大量业务任务没有这种便利。

「研究一家企业」怎样算完成?

「生成高质量销售线索」中的高质量由谁定义?

「完成合同审查」需要发现哪些类型的风险?

「总结客户需求」允许遗漏哪些内容,又绝不能遗漏哪些内容?

企业如果不能回答这些问题,智能体也无法稳定交付。

很多团队先建设工作流,最后才补评估。他们把模型、检索、工具调用和记忆系统连接起来,跑出一批结果,然后组织专家凭感觉打分。几个版本之后,专家标准发生变化,历史结果无法比较,模型优化也失去方向。

评估应该早于大规模自动化。

任务进入智能体系统之前,先定义成功条件、失败类型和风险边界。评估集需要覆盖常规案例、边界案例、冲突信息、缺失信息以及必须拒绝处理的情况。只有理想样本的评估集,会把系统训练成演示环境里的优秀员工。

一个可用的评估体系至少分成四层。

第一层检查任务完成度。要求提取的字段是否齐全,要求执行的动作是否发生,输出格式是否符合下游接口。

第二层检查事实和证据。结论能否追溯到输入材料,引用是否支持对应判断,模型有没有用常识填补数据缺口。

第三层检查业务质量。结果是否符合领域规则,是否覆盖关键风险,是否达到能够进入下一流程的标准。

第四层检查运行效率。完成任务使用了多少 token、多少工具调用、多少时间,发生了多少次重试,人工修改比例是多少。

只评结果质量,系统可能通过十倍成本换取一点点效果提升。只评成本,系统又会通过减少分析步骤制造隐蔽错误。质量、成本和风险必须放在同一套评估里。

评估标准也不能永久固定。业务规则会变化,模型行为会变化,工具返回的数据结构也会变化。每次线上事故都应转化成新的评估案例。没有进入评估集的事故,后续很可能以相似形式再次出现。

这与人类团队的管理方式一致。OKR、质量标准、事故复盘和晋升要求,共同塑造员工行为。只给方向、不定义验收,最后只能依赖主管逐项盯人。

智能体同样需要制度化约束。

思想主权

AI 编程带来的另一个变化,是程序员的工作重心开始从逐行控制代码迁移到控制软件背后的想法。

模型一天能够生成数千行代码。开发者逐行审查全部输出,时间上已经不可行。即使坚持审完,也容易陷入局部细节:命名是否顺眼,函数是否拆得足够小,某段逻辑是否符合个人风格。

这些问题仍有价值,只是优先级下降了。

大模型擅长局部实现。给出清晰边界后,它可以完成函数、接口和测试,也能按照反馈快速调整。它对整体设计的把握更不稳定,尤其容易在多个局部合理选择之间拼出一个整体失衡的系统。

程序员必须控制设计意图。

数据结构为什么这样选择,状态由谁拥有,哪些不变量必须维持,失败后怎样恢复,性能目标是什么,哪些路径允许降级,哪些行为属于系统禁区。这些内容如果只存在于开发者脑中,AI 会用自己的概率偏好填补空白。

结果可能能运行,也可能通过局部测试,却难以演进。

控制思想要求开发者拥有足够深的系统理解。他需要判断某种设计会怎样影响内存布局、并发行为、故障边界和长期维护成本。只会写提示词无法完成这项工作。

vibe coding 最大的问题不在生成速度,而在责任链断裂。使用者描述一个模糊目标,模型生成实现,程序恰好能够运行,于是产物被视为完成。系统内部怎样工作、错误会在哪里积累、性能上限由什么决定,没有人掌控。

这种开发方式可以用于低风险原型。进入长期维护或高性能系统后,代价会快速暴露。需求变化一次,开发者无法判断应该修改哪一层;性能下降时,也不知道问题来自算法、数据结构还是调用关系。每次修改只能继续依赖模型猜测,系统逐步变成无人理解的代码堆积。

antirez 在开发本地 LLM 推理软件 DwarfStar 时,面对的是大量细微且会累积的错误。这类项目不能只看单个函数是否合理。一个局部误差、一处内存选择、一个数据结构上的偏差,都可能沿执行路径放大。

AI 在严谨设计和测试中可以提供很大帮助。前提是人掌握系统意图,知道该要求 AI 验证什么,也知道哪些结果不能接受。

代码审查也需要重新分配精力。

对于 Redis 这类大量用户会直接阅读和修改源码的项目,保持代码质量是对用户的尊重。审查仍然有意义。但如果开发者把全部时间用在检查每一行 AI 输出,QA、性能分析和下一步设计就会被挤压。

有限的人力应该优先投入故障模式、系统不变量、边界条件、性能退化和可维护性。代码风格可以交给自动化工具,重复性实现可以交给模型,局部错误可以由测试覆盖。设计责任无法外包。

设计文档

DESIGN.md 在 AI 编程环境中的地位会持续上升。

过去很多设计文档写于项目启动阶段,代码落地后很快过期。开发者最终以代码为准,文档只保留历史价值。AI 参与开发后,设计文档需要变成持续维护的系统接口。

它应该描述每个数据结构承担什么职责,关键实现技巧服务于什么目标,模块之间怎样协作,哪些不变量不能破坏,以及修改某部分时需要同步检查哪些路径。

模型阅读这样的文档,才能在修改代码前获取设计约束。当我们接手项目时,也可以先理解系统思想,再进入具体实现。

这并不意味着文档越长越好。把代码换成自然语言复述,价值很低。有效文档集中解释代码无法自行表达的内容:为什么选择这个方案,放弃了哪些方案,哪些行为依赖隐含前提,哪些性能特征必须保持。

文档还要进入变更流程。

如果代码改动影响数据结构、状态模型或失败处理,设计文档必须同步更新。评审时需要检查实现与文档是否一致。否则,AI 会依据旧设计修改新代码,错误会披着「遵循项目规范」的外衣进入系统。

设计文档可以视为给未来开发者和未来智能体准备的上下文。它承担组织记忆,减少关键思想只存在于少数人脑中的风险。

企业业务流程也需要同类文档。

流程说明不能停留在步骤列表。它要写清每一步的目标、输入、输出、判断依据、异常路径、升级条件和验收标准。只有这样,智能体才有可能承担稳定执行。

很多所谓 AI 落地难题,本质上暴露了企业从未把业务讲清楚。过去依赖熟练员工临场判断,这些模糊地带被人的经验掩盖。模型进入流程后,所有未定义部分同时暴露出来。

AI 没有制造这些混乱。它提高了混乱被复制的速度。

人的边界

AI 可以承担高吞吐的搜索、执行、分析和记忆管理。

搜索适合机器,因为它能在大量材料中并行查找候选信息;执行适合机器,因为重复流程可以被稳定调用;分析可以由机器生成多个假设和比较维度;记忆管理则可以通过检索、归档和关联降低人脑负担。

人需要保留四项责任:问题定义、歧义处理、风险判断和最终验收。

问题定义决定系统优化什么。目标写错,后续所有高效执行都会扩大偏差。

歧义处理决定何时允许模型自行推断,何时必须暂停并提问。完全禁止推断会让工作流频繁中断,完全开放推断又会把隐含假设带入结果。工程上应根据风险分级:低风险、可逆操作可以允许模型补全;高风险、不可逆操作必须要求显式确认。

风险判断需要结合业务后果。模型可以列出风险,却无法替组织承担责任。同样的错误,在内部草稿里可能只需重新生成,在合同、资金、生产系统和对外承诺中,影响完全不同。

最终验收意味着人要对结果负责。验收不能退化成快速扫一眼。模型输出量超过人的审查能力时,系统应限制吞吐量、增加自动评估或降低自动化范围。堆积大量无人验收的输出,没有形成生产力,只是形成了信息库存。

人机分工也不应按照「模型能做什么」设计。这个问题会随着模型升级不断变化。更稳定的划分方式是看责任和可验证性。

可验证、可回滚、低风险的任务,可以给智能体更大自治权。

结果可验证但动作难以回滚时,应增加审批点。

结果难以完整验证、错误影响又高的任务,AI 更适合作为分析和建议工具。

这套边界需要写进系统权限。只靠提示词要求模型谨慎,约束强度远远不够。工具层要限制可调用范围,工作流层要设置审批,运行层要保留审计记录,评估层要持续检查越权行为。

提示词属于沟通机制。权限系统才承担治理责任。

年轻工程师

我对年轻程序员是有些担心的,并非担心他们使用 AI,而是他们在建立心智模型之前就把实现过程全部交给 AI。

一个人没有亲手实现过解释器、数据库或哈希表,很难判断模型生成的实现在哪些地方存在结构性问题。他可能读得懂语法,也能运行测试,但无法推演数据怎样流动、状态怎样变化、性能为什么退化。

核对 AI 输出不能替代基础训练。

逐行检查一段自己并不理解的代码,只会制造虚假的参与感。更有效的训练方式是亲手实现规模受控的系统,遇到内存、并发、解析、索引和错误恢复问题,再用 AI 帮助验证思路、补充测试、寻找遗漏。

基础能力的价值还会上升。

代码生成越来越便宜以后,企业不会继续为普通代码行支付高溢价。能够定义系统、识别风险、设计评估、分析性能和承担技术决策的人,会掌握更大的杠杆。

年轻工程师如果只学习怎样让模型快速产出,能力会紧贴当前工具。模型更新一次,原有技巧可能迅速贬值。数据结构、操作系统、网络、数据库和编程语言建立的心智模型变化慢得多,它们决定一个人能否判断 AI 给出的方案。

高级工程师也不能因此停留在旧习惯里。

坚持所有代码都必须人工逐行编写,会把大量时间消耗在机器已经可以低成本完成的工作上。经验应该投入架构、约束、验证和复杂问题拆解。继续用代码行数证明专业性,和管理者用团队人数证明影响力没有太大差别。

管理重构

企业引入 AI 时,组织结构也要调整。

过去,一个经理管理十几个人已经接近沟通上限。未来,每个员工都可能拥有大量智能体。管理对象数量突然扩张,个人需要具备过去只有管理者才需要的能力:拆解任务、定义结果、提供上下文、设置检查点和处理异常。

工程师会越来越像技术经理。经理则需要理解评估、权限、成本和模型行为,单靠资源协调很难管理智能体劳动力。

团队流程也会变化。

需求评审需要增加可评估性检查。一个需求如果无法写出验收条件,进入智能体工作流后只会制造更多不确定输出。

架构评审需要关注智能体权限、上下文来源和失败路径。模型调用成功不等于业务任务成功,工具返回正常也不等于动作合理。

上线评审需要检查成本上限和停止条件。任何允许递归、自我调用或动态扩展任务的系统,都必须有预算约束。

事故复盘需要分析模型为什么做出对应行为,输入中缺少了什么,评估为什么没有拦截,以及权限设计是否允许错误继续扩大。把问题归结为「模型偶尔会犯错」,相当于铁路事故后只说机车存在风险。

采购更强的模型可能提升基线能力,却不会补齐管理缺口。模型越强,执行范围越大,错误的影响半径也越大。

AI 项目的成熟度最终会体现在几个问题上:

  1. 团队能否精确描述智能体负责的任务?
  2. 能否量化什么叫完成?
  3. 能否追溯结论来自哪些输入?
  4. 能否限制循环、重试和预算?
  5. 能否知道哪些 token 改变了结果?
  6. 能否在高风险动作前强制人工介入?
  7. 能否把线上失败转化成评估案例?
  8. 能否让设计思想脱离个人记忆,进入可维护的组织资产?

这些问题回答不出来,再复杂的智能体架构也只是一次昂贵的演示。

铁路时代的企业最终学会了管理速度、规模和复杂性。AI 时代需要处理的是概率行为、无限执行能力和有限人类判断之间的冲突。

我们已经拥有了数量近乎无限的数字员工。它们勤奋、便宜、速度极快,也缺少组织记忆、责任意识和稳定判断。

接下来的工作落在人身上:把问题讲清楚,把标准写出来,把权限收紧,把思想保存下来,对最后的结果签字。

这些都是基于当前模型能力和个人认知所作出的判断,随着时间的推移,也可能会涌现其它我当前所认知不到的,那又将是另一个世界。

以上。

SaaS 已死?AI 当立?

在 AI 编程逛飙的年份,到当前的阶段,能感觉到速度在加快,形式也在不断的迭代,写代码这个事情也变得门槛很低。

X 上有人在讲「AI 让软件开发成本接近零,所以 SaaS 价值也接近零」

美股前段时间也因此大跌了一波,但当前这个价值为零的逻辑还是不成立的。

这里有一个概念混淆:构建软件的成本 vs 拥有软件的成本。AI 主要压低前者,后者还在,甚至在很多公司里变得更贵。

在各种自媒体、AI 编程培训或者博眼球的报道中,「一个下午做出 Linear 替代」「一个周末写完 Stripe 替代」这种话,我不觉得完全是吹牛。用 Claude Code 这类工具,把界面、CRUD、简单流程、甚至一些边角的自动化都拼出来,确实快。

但在做出来的那一刻,资产没增加多少,负债突然多了。尤其是碰钱、碰身份、碰合规、碰客户数据的时候。

以做了一个 Stripe 为例,我把 Vibe Coding 一个周末后,「现在拥有了什么」用更工程的语言翻译一下:

  • 拥有了 规则持续变化 的税务与开票适配:欧盟 VAT、各国电子发票、免税/退税、税率变更、发票作废红冲。
  • 拥有了 审计与认证的对话成本:PCI DSS、SOC 2、ISO 27001、渗透测试报告、供应商安全评估问卷。企业客户要的往往不是「你写得对不对」,是「谁在对这件事负责」。
  • 拥有了 支付与账务的边界条件:拒付、部分退款、重复扣款、汇率、四舍五入、账期、对账差异、资金在途、延迟入账。
  • 拥有了 全球化的坑:货币重估、货币小数位变化、地区性监管、某个国家突然要求强制 3DS、某个渠道突然不支持某种卡组织。
  • 拥有了 数据与权限的事故半径:某个字段脱敏没做好、某个导出接口忘了做权限校验、某个后台操作没有审计日志。
  • 拥有了 7×24 的值班现实:系统降级策略、容量、限流、重试风暴、第三方故障兜底、SLA 与赔付条款。

这些事大概率不是「可能发生」。按行业经验只是早晚问题。自从拥有系统开始,就等于自己签了那张无限期维护合同。

回想一个问题,SaaS 是什么?软件即服务,核心是服务,根本就没有提代码。

很多团队在内部系统上很执着,原因很直接:控制感强、改需求快、看起来省钱。上线半年以后,气氛通常变得不太好:需求排队、线上出过几次事故、业务抱怨响应慢、研发觉得自己在打杂。

这时候再看 SaaS,价值就很清晰了:SaaS 的核心商品是「运营表面积」的转移

代码只是其中一层,除了代码还有:

  • 基础设施与部署:多区域、容灾、备份恢复演练、变更管理。
  • 安全:漏洞扫描、依赖升级、密钥轮换、权限最小化、WAF、DDoS。
  • 合规:隐私条款、数据驻留、审计证据、流程制度落地。
  • 可靠性:监控告警、事故复盘、容量规划、灰度发布、回滚策略。
  • 支持与客户成功:工单、排障、培训、文档、FAQ、升级沟通。

当我们把软件「买回来」自己跑,这些都要自己补齐。很多公司低估的就是这一块。这也是为什么很多公司在 AI 赋能后,「运营表面积」的转移速度要慢于「代码」的转移速度。除非这些对公司不重要,如果这些都不重要, 这个系统可能也不重要了。

从 SaaS 的生命周期来看,AI 提升的是「0 到 1」,然而从成本的角度看,最贵的是「1 到 ∞」

这件事可以拆成两条曲线:

  • vibe coded 工具:初期成本很低,后期成本增长很快。越多人用、越多数据、越多流程依赖,它的「改动风险」和「维护面」指数上升。
  • 成熟 SaaS:初期采购成本看着不低,后期增长更接近线性。因为供应商把大量共性维护摊薄到所有客户身上。

AI 把 0→1 压得更便宜,直觉上会让人误判「买 SaaS 更不划算」。实际情况常常相反:AI 让 1→∞ 更贵了,因为我们会更频繁地改、更大胆地接更多业务进来,系统的负债增长速度被我们自己加速了。

这个成本不仅仅是 SaaS 软件的。

AI 让一个工程师单位时间产出更高,但单位工程小时的机会成本同步上升

至少当前的认知是这样的,可能到终极形态,完成不用人介入的时候,这个机会成本也会消失掉。

那是另一个话题了。

所以我对「AI 让 SaaS 价值归零」的判断是反的:AI 越强,成熟 SaaS 越值钱,前提是它真的把服务做扎实,真的帮我们把运营表面积吃掉。

SaaS 本质上还是一种服务。

如果 SaaS 只是「界面更好看的 CRUD」,那这样的 SaaS 确实会死掉一批。

这些 SaaS 太薄了。

在 AI 时代要想活得更好,SaaS 通常需要如下的一些特征:

  • 规则密度高,正确性要求高
  • 合规与安全负担重
  • 生态变化快,需要持续跟进
  • 故障代价高,客户不想背锅
  • 接口与集成复杂,长期维护吃人

Stripe、WorkOS、Cloudflare 这类产品的共同点很明显:它们难点不在「写出来」,难点在「长期把它跑对」。正确性要靠无数细碎决策堆出来,运营水位要常年拉满。

AI 始终会改写 SaaS,整体逻辑会有一些变化。这里的 AI 改写过程,肯定不是「加一个聊天框」「做一个总结」「做一个生成报表」。

我觉得至少有三个点在当前阶段能快速跟进:

  1. 意图驱动,SaaS 的用户最终都是想通过 SaaS 完成工作,以前靠 UI 引导的,现在可以让用户意图表达,然后把意图落为可审计的操作序列,不管是用 MCP,还是 SKILLS;
  2. 更关注结果,传统 SaaS 交付的是工具,客户负责把工具嵌进流程。AI 让厂商有机会把流程吃进去,直接交付结果,比如「自动完成对账」「自动完成入职」「自动完成工单分流」。关键点在「责任」
  3. 定制方式的迭代,企业客户永远会提定制。以前定制意味着项目制和人力黑洞;AI 让「生成」变得便宜,但不要把生成等同于可维护,可以允许客户用自然语言提出规则,系统把规则编译成可测试、可审计的约束,每次变更都能跑回归校验,出问题能定位到规则版本与变更人。

我们常听到对于自研和购买 SaaS 的一个判断逻辑是:「核心业务自研,非核心买 SaaS」。

这句话太粗,没有啥指导意义。

如下一个判断清单,可以做为决策的一些依据:

适合买 SaaS 的场景

  • 领域合规重:支付、税务、身份、隐私、审计
  • 失败代价高:一出错就上新闻、上法务、上客户群
  • 生态变化快:标准常变、监管常变、攻击手法常变
  • 需要对外背书:企业客户会问「谁负责」「有没有认证」「有没有 SLA」

这种场景自研的隐性成本巨大。AI 再强,也只是让我们更快地把「维护合同」签在自己身上。

适合自研的场景

  • 强差异化:流程就是你的竞争力,外部产品很难贴合
  • 业务规则变化快,且只对内部负责:错了能快速纠正,不会引发合规事故
  • 生命周期短:一个季度就会重构或下线的东西
  • 数据高度敏感,且已经有成熟的数据治理与安全团队

这里自研的价值很实在:迭代速度、贴合度、数据控制。

AI 时代的「自研陷阱」会更隐蔽

以前自研失败,多数死在「做不出来」。现在会死在「做出来以后一路堆债」。

AI 会在早期持续正反馈:

  • 功能做得快
  • Demo 好看
  • 业务觉得爽
  • 老板觉得省钱

债务也在同期累积:

  • 没有威胁建模
  • 没有权限与审计体系
  • 没有数据分级与脱敏
  • 没有灾备演练
  • 没有 SLA 与值班机制
  • 没有供应链安全策略(依赖库、镜像、密钥)

等到系统进入关键路径,会发现自己已经没有退路。再想补课,代价是「停业务」或者「带病重构」。

这也是我反复强调「拥有软件是负债」的原因。负债不会因为 AI 变聪明就消失,它只会增长得更快。

AI 把「做一个能用的软件」变成了常态,把「把软件长期跑对」推成了门槛。薄 SaaS 会被挤压,真正提供服务、背负责任、把运营表面积吃掉的 SaaS,会更值钱。

以上。

AI Agent 核心策略:如何判断 Agent 应该停止

简单来讲,AI Agent 实现的的大逻辑就是一个大的循环 + 获取上下文 + 不停的 LLM 调用 + 工具的调用。

那么一个关键问题就出现了:这个循环什么时候应该停止?如果处理不当,Agent 可能会陷入无限循环,浪费计算资源,或者过早停止而无法完成任务。本文将深入探讨 AI Agent 停止策略的核心设计思路。

常用停止策略

AI Agent 停止策略无外乎以下几种情况:

1. 硬性限制

最简单粗暴的方法:

  • 最大步数限制(比如最多循环 30 次)
  • 执行时间限制(比如最多跑 5 分钟)
  • API 调用次数限制(比如最多调 100 次)
  • API 调用 Token 数限制

这种方法简单有效,但用户体验很差。经常出现任务做到一半被强制停止的情况。

2. 任务完成检测

让 LLM 判断任务是否完成:

# 每次循环后问 LLM
response = llm.ask("任务是否已经完成?")
if response == "是":
    stop()

3. 显式停止信号

给 Agent 一个专门的”停止”工具:

tools = [
    "search",
    "calculate", 
    "terminate"  # 专门用来停止
]

当 Agent 调用 terminate 工具时就停止。这个方法不错,但需要在 prompt 里教会 Agent 什么时候该调用它。

4. 循环检测

检测 Agent 是否在做重复的事:

  • 连续多次调用同一个工具
  • 动作序列出现循环模式(A→B→A→B…)
  • 输出内容高度相似

5. 错误累积

连续失败多次就放弃:

if consecutive_errors > 3:
    stop("连续失败太多次")

6. 用户中断

让用户能随时喊停。

下面我们以 OpenManus 和 Gemini CLI 的源码来看一下他们是怎么做的。

OpenManus 的停止逻辑

OpenManus 的停止机制设计得比较完整,它用了一个多层防护的思路。

核心:terminate 工具

OpenManus 给每个 Agent 都配了一个 terminate 工具:

class Terminate(BaseTool):
    name: str = "terminate"
    description = """当请求已满足或无法继续时终止交互。
    完成所有任务后,调用此工具结束工作。"""
    
    async def execute(self, status: str) -> str:
        return f"交互已完成,状态:{status}"
        
以上为示例,原始代码:
from app.tool.base import BaseTool


_TERMINATE_DESCRIPTION = """Terminate the interaction when the request is met OR if the assistant cannot proceed further with the task.
When you have finished all the tasks, call this tool to end the work."""


class Terminate(BaseTool):
    name: str = "terminate"
    description: str = _TERMINATE_DESCRIPTION
    parameters: dict = {
        "type""object",
        "properties": {
            "status": {
                "type""string",
                "description""The finish status of the interaction.",
                "enum": ["success""failure"],
            }
        },
        "required": ["status"],
    }

    async def execute(self, status: str) -> str:
        """Finish the current execution"""
        return f"The interaction has been completed with status: {status}"

OpenManus 使用的是方案 3,把「何时停止」的决策权交给了 LLM。prompt 里会明确告诉 Agent:任务完成了就调用 terminate。

状态机管理

OpenManus 用状态机来管理 Agent 的生命周期:

class AgentState(Enum):
    IDLE = "idle"
    RUNNING = "running"  
    FINISHED = "finished"
    ERROR = "error"

当检测到特殊工具(如 terminate)被调用时,会触发状态转换:

async def _handle_special_tool(self, name: str, result: Any):
    if name.lower() == "terminate":
        self.state = AgentState.FINISHED
        logger.info(" 任务完成!")

步数限制

不同类型的 Agent 有不同的步数上限:

# ToolCallAgent: 30 步
# SWEAgent: 20 步
# PlanningFlow: 可配置

while self.current_step < self.max_steps and self.state != AgentState.FINISHED:
    self.current_step += 1
    await self.step()

if self.current_step >= self.max_steps:
    results.append(f"达到最大步数限制 ({self.max_steps})")

这是一个保底机制,防止 Agent 无限运行。

卡死检测

OpenManus 还会检测 Agent 是否卡住了:

def is_stuck(self) -> bool:
    # 检查是否有重复的 assistant 消息
    # 如果最近的回复都一样,说明卡住了
    recent_messages = self.get_recent_assistant_messages()
    if len(set(recent_messages)) == 1:
        return True
    return False

Planning Agent 的结束逻辑

1. 计划完成的判断机制

PlanningFlow 的结束判断并不是简单检查所有步骤是否完成:

# 在主执行循环中
while True:
    # 获取当前需要执行的步骤
    self.current_step_index, step_info = await self._get_current_step_info()
    
    # 如果没有更多活跃步骤,则结束计划
    if self.current_step_index is None:
        result += await self._finalize_plan()
        break

2. 步骤状态检查逻辑

_get_current_step_info() 方法负责判断是否还有未完成的步骤:

# 查找第一个非完成状态的步骤
for i, step in enumerate(steps):
    if i >= len(step_statuses):
        status = PlanStepStatus.NOT_STARTED.value
    else:
        status = step_statuses[i]
    
    # 如果步骤状态为活跃状态(未开始或进行中),返回该步骤
    if status in PlanStepStatus.get_active_statuses():
        return i, step_info

# 如果没找到活跃步骤,返回 None
return None, None

其中 get_active_statuses() 返回 ["not_started", "in_progress"],意味着只有当所有步骤都是 "completed""blocked" 状态时,计划才会结束。

3. 计划结束处理

当没有更多活跃步骤时,会调用 _finalize_plan() 方法:

async def _finalize_plan(self) -> str:
    """使用 LLM 生成计划完成总结"""
    plan_text = await self._get_plan_text()
    
    # 使用 LLM 生成总结
    system_message = Message.system_message(
        "You are a planning assistant. Your task is to summarize the completed plan."
    )
    
    user_message = Message.user_message(
        f"The plan has been completed. Here is the final plan status:\n\n{plan_text}\n\nPlease provide a summary of what was accomplished and any final thoughts."
    )
    
    response = await self.llm.ask(messages=[user_message], system_msgs=[system_message])
    return f"Plan completed:\n\n{response}"

Gemini CLI 的停止逻辑

Gemini CLI 的设计思路完全不同,它用了一个更优雅但也更复杂的方案。

subagent 的停止逻辑

1. 达到最大轮次(MAX_TURNS)

if (this.runConfig.max_turns && turnCounter >= this.runConfig.max_turns) {
    this.output.terminate_reason = SubagentTerminateMode.MAX_TURNS;
    break;
}

这是最简单的保护机制,防止无限循环。

2. 执行超时(TIMEOUT)

let durationMin = (Date.now() - startTime) / (1000 * 60);
if (durationMin >= this.runConfig.max_time_minutes) {
    this.output.terminate_reason = SubagentTerminateMode.TIMEOUT;
    break;
}

注意这里检查了两次超时:

  • 在调用 LLM 之前检查一次
  • 在调用 LLM 之后又检查一次

这是因为 LLM 调用可能很耗时,要确保不会超时太多。

3. 用户中断(通过 AbortSignal)

if (abortController.signal.aborted) return;

这个检查出现在 stream 处理循环里,确保能及时响应用户的取消操作。

4. 错误异常(ERROR)

catch (error) {
    console.error('Error during subagent execution:', error);
    this.output.terminate_reason = SubagentTerminateMode.ERROR;
    throw error;
}

任何未捕获的异常都会导致停止。

5. 目标完成(GOAL)

目标完成的判断分两种情况:

情况A:没有预定输出要求

if (!this.outputConfig || Object.keys(this.outputConfig.outputs).length === 0) {
    // 没有要求特定输出,LLM 不调用工具就认为完成了
    if (functionCalls.length === 0) {
        this.output.terminate_reason = SubagentTerminateMode.GOAL;
        break;
    }
}

情况B:有预定输出要求

// 检查是否所有要求的变量都已输出
const remainingVars = Object.keys(this.outputConfig.outputs).filter(
    (key) => !(key in this.output.emitted_vars)
);

if (remainingVars.length === 0) {
    this.output.terminate_reason = SubagentTerminateMode.GOAL;
    break;
}

声明式输出系统的实现

声明式输出系统的核心是 outputConfig

// 预先声明需要什么输出
this.outputConfig = {
    outputs: {
        "summary""string",
        "recommendations""array", 
        "risk_score""number"
    }
};

// Agent 通过 self.emitvalue 工具来产生输出
// 每次调用会把值存到 this.output.emitted_vars 里
this.output.emitted_vars = {
    "summary""这是总结...",
    "recommendations": ["建议1""建议2"]
    // risk_score 还没输出
};

系统会不断检查 emitted_vars 是否包含了所有 outputs 中声明的变量。只有全部输出了才认为目标完成。

Nudge 机制

Nudge(轻推)机制代码:

if (functionCalls.length === 0) {  // LLM 停止调用工具了
    // 检查是否还有变量没输出
    const remainingVars = Object.keys(this.outputConfig.outputs).filter(
        (key) => !(key in this.output.emitted_vars)
    );
    
    if (remainingVars.length > 0) {
        // 还有变量没输出,"推"它一下
        const nudgeMessage = `You have stopped calling tools but have not emitted 
        the following required variables: ${remainingVars.join(', ')}. 
        Please use the 'self.emitvalue' tool to emit them now, 
        or continue working if necessary.`;
        
        // 把提醒作为新的用户消息发给 LLM
        currentMessages = [{
            role: 'user',
            parts: [{ text: nudgeMessage }]
        }];
        
        // 继续循环,不退出
    }
}

完整的 subagent 执行流程

开始
  ↓
while (true) {
  检查是否超时/超轮次 → 是 → 退出
    ↓ 否
  调用 LLM
    ↓
  LLM 返回工具调用?
    ├─ 是 → 执行工具 → 检查目标是否完成
    │         ├─ 是 → 退出
    │         └─ 否 → 继续循环
    │
    └─ 否(LLM 停止调用工具)
         ↓
       有预定输出要求吗?
         ├─ 没有 → 退出(认为完成)
         └─ 有 → 检查是否都输出了
                   ├─ 是 → 退出
                   └─ 否 → Nudge 提醒 → 继续循环
}

三层循环检测机制

第一层:工具调用重复检测

这是最简单直接的检测,针对 Agent 反复调用相同工具的情况。

private checkToolCallLoop(toolCall: { name: string; args: object }): boolean {
    // 把工具名和参数一起哈希,生成唯一标识
    const key = this.getToolCallKey(toolCall);
    
    if (this.lastToolCallKey === key) {
        // 和上次调用完全一样,计数+1
        this.toolCallRepetitionCount++;
    } else {
        // 不一样,重置计数
        this.lastToolCallKey = key;
        this.toolCallRepetitionCount = 1;
    }
    
    // 连续5次调用相同工具+相同参数 = 循环
    if (this.toolCallRepetitionCount >= TOOL_CALL_LOOP_THRESHOLD) {
        return true;
    }
}

触发条件:连续 5 次调用完全相同的工具(包括参数)。

这种检测很严格——必须是连续的、完全相同的调用。如果中间插入了其他工具调用,计数就会重置。

第二层:内容重复检测(”咒语”检测)

这是最复杂的部分,用来检测 LLM 输出重复内容的情况,就像在念咒语一样。

private checkContentLoop(content: string): boolean {
    // 1. 先检查是否在特殊内容块中(代码块、表格、列表等)
    const numFences = (content.match(/```/g) ?? []).length;
    const hasTable = /(^|\n)\s*(\|.*\||[|+-]{3,})/.test(content);
    // ... 检查各种格式
    
    // 在代码块中不检测循环(代码本来就可能有重复)
    if (this.inCodeBlock) {
        return false;
    }
    
    // 2. 把新内容加入历史
    this.streamContentHistory += content;
    
    // 3. 保持历史在 1000 字符以内
    this.truncateAndUpdate();
    
    // 4. 分析内容块是否重复
    return this.analyzeContentChunksForLoop();
}

核心算法是滑动窗口 + 哈希检测

private analyzeContentChunksForLoop(): boolean {
    while (this.hasMoreChunksToProcess()) {
        // 提取 50 字符的块
        const currentChunk = this.streamContentHistory.substring(
            this.lastContentIndex,
            this.lastContentIndex + CONTENT_CHUNK_SIZE  // 50
        );
        
        // 计算哈希
        const chunkHash = createHash('sha256').update(currentChunk).digest('hex');
        
        // 检查这个块是否重复出现
        if (this.isLoopDetectedForChunk(currentChunk, chunkHash)) {
            return true;
        }
        
        // 滑动窗口向前移动 1 个字符
        this.lastContentIndex++;
    }
}

判断循环的条件:

private isLoopDetectedForChunk(chunk: string, hash: string): boolean {
    const existingIndices = this.contentStats.get(hash);
    
    if (!existingIndices) {
        // 第一次见到这个块,记录位置
        this.contentStats.set(hash, [this.lastContentIndex]);
        return false;
    }
    
    // 验证内容确实相同(防止哈希碰撞)
    if (!this.isActualContentMatch(chunk, existingIndices[0])) {
        return false;
    }
    
    existingIndices.push(this.lastContentIndex);
    
    // 需要出现至少 10 次
    if (existingIndices.length < CONTENT_LOOP_THRESHOLD) {  // 10
        return false;
    }
    
    // 关键:这 10 次必须距离很近(平均距离 ≤ 75 字符)
    const recentIndices = existingIndices.slice(-CONTENT_LOOP_THRESHOLD);
    const totalDistance = recentIndices[recentIndices.length - 1] - recentIndices[0];
    const averageDistance = totalDistance / (CONTENT_LOOP_THRESHOLD - 1);
    const maxAllowedDistance = CONTENT_CHUNK_SIZE * 1.5;  // 75
    
    return averageDistance <= maxAllowedDistance;
}

触发条件:同一个 50 字符的内容块,在很短的距离内重复出现 10 次

第三层:LLM 智能检测

这是最高级的检测,用 AI 来判断 AI 是否陷入循环。

private async checkForLoopWithLLM(signal: AbortSignal) {
    // 取最近 20 轮对话
    const recentHistory = this.config
        .getGeminiClient()
        .getHistory()
        .slice(-LLM_LOOP_CHECK_HISTORY_COUNT);  // 20
    
    // 清理历史(去掉悬空的函数调用等)
    const trimmedHistory = this.trimRecentHistory(recentHistory);
    
    // 让 Gemini Flash 模型分析
    const result = await this.config.getBaseLlmClient().generateJson({
        contents: [...trimmedHistory, { role: 'user', parts: [{ text: taskPrompt }] }],
        schema: {
            type'object',
            properties: {
                reasoning: { type'string' },
                confidence: { type'number' }  // 0-1 之间
            }
        },
        model: DEFAULT_GEMINI_FLASH_MODEL,
        systemInstruction: LOOP_DETECTION_SYSTEM_PROMPT
    });
    
    if (result['confidence'] > 0.9) {
        // 高置信度认为是循环
        console.warn(result['reasoning']);
        return true;
    }
}

触发时机:

async turnStarted(signal: AbortSignal) {
    this.turnsInCurrentPrompt++;
    
    if (
        this.turnsInCurrentPrompt >= LLM_CHECK_AFTER_TURNS &&  // 至少 30 轮
        this.turnsInCurrentPrompt - this.lastCheckTurn >= this.llmCheckInterval
    ) {
        this.lastCheckTurn = this.turnsInCurrentPrompt;
        return await this.checkForLoopWithLLM(signal);
    }
}
  • 必须执行超过 30 轮才开始检查(避免误判)
  • 不是每轮都检查,有间隔(默认 3 轮)
  • 间隔会根据置信度动态调整(5-15 轮)
// 动态调整检查频率
this.llmCheckInterval = Math.round(
    MIN_LLM_CHECK_INTERVAL +  // 5
    (MAX_LLM_CHECK_INTERVAL - MIN_LLM_CHECK_INTERVAL) * (1 - result['confidence'])
    // 置信度越高,检查越频繁
);

三种循环类型

系统定义了三种循环类型:

enum LoopType {
    CONSECUTIVE_IDENTICAL_TOOL_CALLS,  // 连续相同工具调用
    CHANTING_IDENTICAL_SENTENCES,      // 重复输出相同内容
    LLM_DETECTED_LOOP                  // LLM 检测到的逻辑循环
}

每种都有不同的检测方法和触发条件。

这比较适合处理长对话场景,既能有效检测循环,又不会因为过于敏感而误判正常的迭代操作。

小结

AI Agent 的停止策略是一个容易被忽视但极其重要的技术问题。从原理上看,Agent 就是一个大循环,不断调用 LLM 和工具来完成任务,但如果没有合理的停止机制,就会出现无限循环浪费资源,或者过早停止无法完成任务的问题。常见的停止方案包括硬性限制(步数、时间、API调用次数)、任务完成检测、显式停止信号、循环检测、错误累积和用户中断等,实际应用中需要组合使用多种策略。

OpenManus 采用了相对简单直接的设计:给每个 Agent 配备 terminate 工具,让 LLM 自己决定何时停止,同时用状态机管理生命周期,配合步数限制作为保底,并确保无论如何停止都会正确清理资源。

而 Gemini CLI 的设计更加精巧,核心是声明式输出系统——预先定义需要什么输出,只有全部输出才算完成,如果 Agent 停止调用工具但还有变量未输出,系统会通过 Nudge 机制温和提醒;在循环检测上,Gemini 实现了三层防护:工具调用重复检测(连续5次相同调用)、内容重复检测(滑动窗口+哈希算法检测”咒语”现象)、以及用 LLM 分析对话历史判断是否陷入逻辑循环。

实践中的关键是不要依赖单一停止机制,要组合使用多种策略形成多层防护,给 LLM 明确的停止指引,为不同类型的停止原因提供清晰的用户反馈,并确保资源能够可靠清理。停止策略的本质是在”让 Agent 完成任务”和”防止失控”之间找到平衡点。

以上。