1. 从"按字卖钱"到"按事收钱":计费逻辑为什么必须换轨
过去两年,只要聊到大模型商业化,绕不开的一个词就是 Token。几乎所有主流平台都按输入输出 Token 数量计价,这套逻辑简单、透明、容易核算,也确实撑起了第一波 API 生意的账本。但我在实际接触一批做 Agent 产品的团队之后,越来越强烈地感觉到:Token 计费这套尺子,量不准智能体时代的价值。
原因不复杂。Token 计费衡量的是"模型吐了多少字",而用户真正关心的是"我的事办成了没有"。一个智能体帮用户订好一张机票,可能只输出几十个 Token 的确认信息,但背后调用了搜索、比价、下单、支付四五个工具,跑了十几轮推理。反过来,一个啰嗦的智能体洋洋洒洒写了两千字,事情一件没办成,按 Token 算它反而"更值钱"。这种错位,就是奥锐方邵剑秋提出"从 Token 计费到 Task 计费"的现实背景。
Task 计费,说白了就是按"完成的任务"收费。你让智能体做一件事,它做成了,收一次费;没做成,不该按它烧了多少 Token 来收。这个转变听起来只是换个计价单位,实际上它把整个系统的重心从"模型输出"挪到了"任务编排"上。因为只有当你能够清晰地定义任务、拆解任务、追踪任务状态、判定任务成败,你才有资格按 Task 收钱。而这一整套能力,行业里有个统一的叫法——编排(Orchestration)。
我见过不少团队,模型选得很激进,Prompt 调得很精细,但一问到"你这个任务怎么算完成、失败怎么重试、多步之间状态怎么传递",就答不上来。这类产品按 Token 卖还能糊弄,一旦要按 Task 卖,立刻露馅。所以这篇文章我想把这件事掰开讲:Task 计费到底改变了什么,编排为什么是那个绕不过去的坎,以及一个能扛住 Task 计费的智能体系统,在工程上到底该怎么搭。
提示:本文讨论的"计费"是产品商业模式的抽象,不涉及任何具体支付通道或合规细节,重点始终放在编排这一技术核心上。
2. Task 计费真正考核的是"任务闭环能力"
2.1 一个任务从哪开始、到哪算结束
要按 Task 收钱,第一件必须想清楚的事是:什么算一个 Task?这个问题看着像产品问题,其实是彻头彻尾的工程问题。用户说"帮我安排下周去上海的出差",这是一个 Task 吗?还是说它应该被拆成"查航班""订酒店""排日程"三个 Task?拆法不同,计费口径完全不同,背后的编排结构也完全不同。
我的经验是,Task 的边界应该由"可独立判定成败的最小业务单元"来定义。也就是说,这个单元做完之后,系统能明确回答"成了还是没成"。查航班这个动作,成了就是拿到候选列表,没成就是没拿到,边界清晰。而"安排出差"这种复合目标,它本身不是一个可判定单元,而是一个任务容器,里面装着若干子任务。按 Task 计费时,通常按可判定单元来计,容器层只做聚合展示。
这里有个容易被忽略的细节:任务的"开始"和"结束"必须有明确的事件锚点。开始锚点通常是用户意图被结构化解析的那一刻,结束锚点则是任务状态机进入终态(成功、失败、取消、超时)的那一刻。很多团队的系统里,任务状态是散的,散落在各个工具调用的返回值里,没有一个统一的状态机来收口。这种系统按 Token 卖没问题,按 Task 卖就会天天和用户扯皮——用户说没办成,你说办了,谁也说服不了谁。
2.2 成败判定为什么比想象中难
判定一个任务成功,听起来就是"看结果对不对",实操里坑非常多。我举几个真实场景。第一个是"部分成功":用户要订三张票,系统订到了两张,第三张没票了。这算成功还是失败?如果按 Task 计费,你必须提前定义好这种情形的计费规则,而规则能不能落地,取决于编排层有没有把"三张票"建模成三个子任务还是一个整体任务。
第二个是"结果正确但过程异常"。智能体通过一条意料之外的路径完成了任务,比如本该走 A 接口,结果 A 挂了它绕道 B 接口办成了。从用户视角这是成功,但从系统视角这是一次降级执行,可能需要在计费上做区分。第三个是"延迟成功",任务提交后过了很久才异步完成,这时候用户可能已经离开了会话,任务状态怎么回传、怎么确认,又是一套编排机制。
这些情形逼着你在编排层做一件事:把任务的生命周期显式建模出来。我通常建议用一张任务表来承载,字段至少包括任务 ID、父任务 ID、任务类型、当前状态、重试次数、创建时间、终态时间、结果摘要、失败原因码。有了这张表,成败判定就从"猜"变成了"查"。这也是 Task 计费能成立的技术底座——没有可查询的任务状态,就没有可信的计费依据。
2.3 计费口径倒逼出的三个硬指标
一旦决定按 Task 计费,有三个指标会立刻变成团队的生命线。第一个是任务成功率,它直接决定收入,因为失败的任务大概率收不到钱。第二个是平均任务成本,注意这里说的成本仍然包含 Token 消耗和工具调用开销,Task 计费只是改变了收费方式,没有让成本消失,所以你必须知道每个 Task 背后烧了多少资源,否则定价就是拍脑袋。第三个是任务时长分布,尤其是长尾部分,因为超时任务既占资源又难收费。
这三个指标合起来,其实就是在要求你把"任务"当成一等公民来运营。我见过做得比较成熟的团队,他们的看板上第一屏不是 Token 消耗曲线,而是任务成功率、P95 任务时长、单任务平均成本这三条线。这个视角的切换,本身就是从 Token 思维转向 Task 思维的标志。编排系统要做的,就是让这三条线可观测、可归因、可优化。
3. 编排层到底在编排什么:拆开看四个核心动作
3.1 意图解析:把一句话变成可执行的任务图
编排的第一步,是把用户那句自然语言变成结构化的任务描述。这一步很多人以为交给大模型就行了,实际上模型只完成了一半工作。模型擅长的是理解意图、抽取槽位,比如从"帮我订明天下午去北京的高铁"里抽出时间、目的地、交通方式。但模型不擅长的是决定"这个任务要不要拆、拆成几步、每步依赖谁"。
我的做法是让模型输出一个中间结构,通常是一段结构化的任务描述(JSON 居多),然后由编排引擎把它编译成任务图。任务图里的节点是原子动作,边是依赖关系。比如"订高铁"可以编译成"查询车次 → 筛选 → 占座 → 支付"四个节点,其中筛选依赖查询结果,占座依赖筛选结果。这个编译过程是确定性的代码逻辑,不交给模型自由发挥,因为计费要求可复现、可审计。
这里有个实操心得:意图解析的输出一定要带"置信度"和"缺失槽位"两个字段。置信度低或者槽位缺失时,编排引擎应该走澄清分支,而不是硬着头皮往下跑。硬跑的结果往往是任务失败,而失败任务在 Task 计费下是纯亏损。宁可多问用户一句,也不要让一个注定失败的任务跑完全程。
3.2 任务拆解:粒度决定成败与成本
任务拆解的粒度,是编排里最考验经验的地方。拆得太粗,一个节点里塞了太多动作,失败了不知道哪一步出的问题,重试也只能整段重来,成本高。拆得太细,节点数量爆炸,编排开销和状态管理复杂度直线上升,而且细粒度节点之间的上下文传递容易丢信息。
我一般的判断标准是:一个节点应该对应"一次可独立重试的外部交互"。调用一次搜索接口是一个节点,调用一次支付是一个节点,而"根据搜索结果做决策"这种纯推理动作,可以合并进相邻节点,不必单独成节点。这样拆出来的任务图,节点数量通常控制在 3 到 8 个之间,既能定位问题,又不至于太碎。
还有一个关键点是幂等性。按 Task 计费意味着失败要重试,而重试最怕的就是重复产生副作用。支付节点重试两次,用户被扣两次钱,这是灾难。所以每个有副作用的节点,都必须设计幂等键,通常是"任务 ID + 节点 ID"的组合。编排引擎在重试前先查这个键有没有执行过,执行过就直接复用结果。这个机制不做,Task 计费迟早出大事。
3.3 状态流转:任务状态机怎么设计才不乱
任务状态机是编排层的心脏。我见过太多系统把状态藏在各种地方——有的在数据库字段里,有的在缓存里,有的干脆靠模型上下文记忆。这种散装状态在单步任务里能凑合,一旦任务图有分支、有并行、有重试,立刻乱成一锅粥。
比较稳妥的做法是定义一个显式的状态枚举,至少包含:待执行、执行中、等待依赖、成功、失败、重试中、已取消、超时。每个节点和整个任务都有自己的状态,节点状态向上聚合出任务状态。聚合规则要写死,比如"任一必需节点失败且重试耗尽,则任务失败",不能靠模型临场判断。
状态流转的每一次变更,都应该落一条事件日志,记录变更时间、触发原因、操作者(是用户还是系统)。这份日志在 Task 计费场景下价值极高,因为它是处理计费争议的唯一凭据。用户说任务没完成,你调出日志一看,节点在几点几分成功、结果是什么,一目了然。没有这份日志,计费就是一笔糊涂账。
3.4 结果聚合:把碎片拼成用户能看懂的答复
任务图跑完之后,各个节点的结果是碎的,需要聚合成一段用户能看懂的答复。这一步看似只是文案工作,其实直接影响用户对"任务是否完成"的感知。同样一个成功任务,聚合得好,用户觉得办得漂亮;聚合得差,用户觉得你没办明白,进而质疑计费。
我的经验是,结果聚合要遵循"结论先行、证据在后"的原则。先给一句明确的结论,比如"已为您订好明天 14:30 的高铁,二等座 05 车 12A",然后再附上必要的细节和凭证。如果任务是部分成功,结论里必须明确说清楚哪部分成了、哪部分没成,以及没成的原因和后续建议。含糊其辞的聚合,是计费纠纷的最大来源。
4. 多智能体场景下,编排难度为什么指数级上升
4.1 单智能体编排与多智能体编排的分水岭
单智能体做编排,本质上是"一个大脑指挥一双手",任务图是线性的或者简单分支的,状态管理相对可控。但一旦进入多智能体场景,比如一个负责理解需求、一个负责查资料、一个负责执行操作、一个负责质检,编排就变成了"多个大脑如何协同"的问题,难度不是加一,是乘好几倍。
分水岭出现在三个地方。第一是通信,智能体之间怎么传消息、传什么格式、消息丢了怎么办。第二是共识,多个智能体对同一个任务状态的理解可能不一致,谁说了算。第三是冲突,两个智能体可能对同一资源发起操作,比如都想去改同一条数据,怎么避免打架。这三点在单智能体里根本不存在,在多智能体里却是天天要面对的。
我个人的判断是,多智能体不是越多越好。很多团队一上来就搞五六个角色,结果协调开销比干活还大。比较务实的做法是先从两三个角色起步,把通信和状态同步机制跑通,确认收益确实大于开销,再考虑扩展。编排框架的价值,恰恰在于把这些协同细节标准化,让团队不用每次从零造轮子。
4.2 角色分工与消息传递的常见坑
多智能体编排里,角色分工最容易踩的坑是"职责重叠"。两个智能体都能查资料,遇到查询任务时谁来干?如果没有明确的路由规则,就会出现要么都去干、要么都不干的尴尬。解决办法是在编排层定义清晰的能力注册表,每个智能体声明自己擅长什么,路由时按能力匹配,匹配到多个就按优先级或者负载来选。
消息传递的坑更多。最常见的是消息格式不统一,A 智能体发的是自然语言,B 智能体期待的是结构化数据,中间就得加转换层,转换层一多,信息损耗就大。我的建议是,智能体之间的内部通信尽量用结构化格式,把自然语言留给最终面向用户的输出。内部消息带上任务 ID、发送方、接收方、时间戳、消息类型,方便追踪。
还有一个隐蔽的坑是"消息风暴"。多个智能体互相触发,A 通知 B,B 又通知 A,形成循环。编排层必须设置消息跳数上限或者环路检测,超过阈值就中断并告警。这个机制不做,系统在压力下很容易自己把自己拖垮。
4.3 并发与资源争抢:编排层的调度职责
多智能体天然是并发的,多个任务同时跑,多个智能体同时抢资源。编排层在这里扮演的是调度器的角色。它要决定哪些任务可以并行、哪些必须串行、资源不够时谁先谁后。这个调度做得好不好,直接体现在任务成功率和平均时长上。
我见过一个典型的资源争抢场景:多个任务都要调用同一个有速率限制的外部接口。如果没有统一调度,每个智能体各自去调,很容易触发限流,导致一批任务集体失败。正确做法是在编排层做令牌桶或者队列,把对外部接口的调用统一收口,按配额分发。这样虽然单个任务可能稍微慢一点,但整体成功率会高很多。
并发控制还有一个维度是"任务优先级"。付费用户的任务、临近截止的任务,应该优先调度。这要求编排层支持优先级队列,并且在资源紧张时能做出取舍。这套机制在 Token 计费时代可有可无,在 Task 计费时代却是刚需,因为任务失败直接等于收入损失。
5. 从 Token 账本迁移到 Task 账本:数据模型怎么改
5.1 两套账本的本质差异
Token 账本记录的是"消耗",一行数据通常就是一次模型调用,字段是输入 Token 数、输出 Token 数、单价、金额。它天然是流水式的,来一条记一条,不需要关心这些调用之间有没有关系。Task 账本记录的是"交付",一行数据是一个任务,字段是任务 ID、任务类型、状态、开始结束时间、关联的 Token 消耗、关联的工具调用、最终金额。它天然是聚合式的,需要把散落的调用归拢到一个任务名下。
这个差异带来的第一个工程问题是"归因"。在 Token 账本里,每次调用自己就是一条记录,不需要归因。在 Task 账本里,你必须回答"这次模型调用属于哪个任务"。这就要求在调用发起时就把任务 ID 透传下去,一路带到日志和计费系统。很多老系统没有这个透传链路,迁移时就得补,补起来还挺费劲。
第二个问题是"跨任务复用"。有些调用是多个任务共享的,比如一次公共知识查询,被三个任务都用到了。这笔成本怎么摊?我的做法是按调用次数或者按任务权重分摊,规则提前定好,写进计费逻辑。不提前定,后面就是无休止的扯皮。
5.2 任务 ID 如何贯穿全链路
任务 ID 是 Task 账本的脊梁。它必须在任务创建时生成,然后贯穿意图解析、任务拆解、节点执行、工具调用、模型调用、结果聚合、计费结算每一个环节。任何一个环节丢了任务 ID,这个环节的成本就归不到账上,账本就不完整。
实操上,我建议把任务 ID 放进上下文对象里,所有下游调用都从这个上下文取,而不是靠参数一层层传。上下文对象在任务开始时初始化,在任务结束时销毁。这样即使调用链很深,任务 ID 也不会丢。同时,所有日志都要带上任务 ID,方便排查时按任务维度聚合。
还有一个细节是子任务 ID 的命名。如果任务有嵌套,子任务 ID 最好能体现层级关系,比如用"父 ID + 序号"的形式。这样在账本里既能按父任务汇总,也能下钻到子任务看细节。命名规则一旦定下来,就不要轻易改,因为历史数据都依赖它。
5.3 计费结算的时机与幂等
Task 计费什么时候结算?任务成功时结算是最自然的,但有些任务需要用户确认才算真正完成,比如下单后要用户点确认。这时候结算时机就有两种选择:任务执行成功时预扣,用户确认后正式结算;或者等用户确认后一次性结算。两种各有优劣,预扣能防止用户赖账,但用户体验差;后结算体验好,但有坏账风险。
不管选哪种,结算动作必须幂等。同一个任务被结算两次,是计费系统的大忌。实现幂等的常见做法是用任务 ID 作为唯一键,结算前先查这个任务有没有结算过,结算过就直接返回上次结果。这个检查要放在事务里,避免并发下重复结算。
结算还要考虑"退款"和"补偿"。任务失败了要不要退?部分成功怎么算?这些规则要在产品层面定清楚,然后在计费系统里实现。我见过一些团队规则定得含糊,结果客服天天处理计费投诉,工程团队天天改计费逻辑,两头受罪。规则清晰,代码才能清晰。
6. 编排框架选型:自研、开源还是平台
6.1 三类方案的适用边界
编排框架大致分三类:自研、开源框架、商业平台。自研的优点是贴合业务、可控性强,缺点是工作量大、容易重复造轮子。开源框架的优点是起步快、社区活跃,缺点是抽象层次未必匹配你的业务,深度定制时可能比自研还麻烦。商业平台的优点是开箱即用、运维省心,缺点是灵活性受限、长期成本可能不低。
我的判断标准是看团队规模和业务确定性。小团队、业务还在探索期,优先用开源或者平台,把精力放在业务验证上。团队有一定规模、业务模式已经跑通、编排是核心竞争力,那就值得自研,把关键能力握在自己手里。最怕的是业务没跑通就大投入自研,最后发现方向错了,沉没成本很高。
还有一点要提醒:选型时不要只看功能列表,要看"可观测性"和"可扩展性"。编排系统出问题时,能不能快速定位到是哪个节点、哪次调用、什么原因,这比多支持几种任务类型重要得多。可扩展性则决定了你未来加新工具、新智能体时,是改配置还是改代码。
6.2 自研编排引擎的最小可行架构
如果决定自研,我建议从一个最小可行架构起步,不要一上来就搞大而全。最小架构通常包含四个模块:任务定义模块(负责把意图编译成任务图)、调度模块(负责按依赖关系推进任务)、执行模块(负责调用工具和模型)、状态存储模块(负责持久化任务和节点状态)。
这四个模块之间通过明确接口通信,任务定义模块输出任务图,调度模块消费任务图并决定下一步执行哪个节点,执行模块执行节点并回写结果,状态存储模块提供读写。模块内部可以先做简单实现,比如调度先用单机内存队列,状态先用关系型数据库。等业务量上来了,再把调度换成分布式、状态换成更适合的存储。
这个架构的关键是"接口稳定、实现可换"。只要接口定得好,后面替换实现不会影响其他模块。我见过一些团队一开始就把调度和存储耦合在一起,后面想换存储发现牵一发动全身,只能推倒重来。
6.3 什么时候该引入工作流引擎
当任务图变得复杂——有大量并行分支、有循环、有复杂的补偿逻辑——纯手写的调度代码会越来越难维护。这时候可以考虑引入工作流引擎,把任务图用声明式的方式描述出来,由引擎负责调度和状态管理。工作流引擎的好处是把"怎么调度"和"调度什么"分开了,业务逻辑更清晰。
但引入工作流引擎也有代价,主要是学习成本和抽象泄漏。引擎有自己的一套概念和约束,团队要花时间理解;而且引擎的抽象未必能覆盖所有业务场景,遇到覆盖不到的地方,还是得绕过去写代码,反而更别扭。所以我的建议是,任务图简单时别急着上引擎,等复杂度真的成为痛点再引入,而且要选那种允许"逃生舱"的引擎,遇到特殊场景能插入自定义逻辑。
7. 实测中那些文档不会写的坑
7.1 任务超时与僵尸任务的清理
任务超时是编排里最容易被低估的问题。一个任务卡在某个节点上,既没成功也没失败,就那么挂着,占着资源,还影响成功率统计。这种"僵尸任务"在 Token 计费时代影响不大,因为没输出就没消耗;在 Task 计费时代却是实打实的损失,因为用户看到的是任务一直没完成。
我的做法是给每个节点和整个任务都设置超时时间,超时后由编排层主动把状态置为超时,并触发清理逻辑。清理包括释放占用的资源、回滚已产生的副作用、通知相关方。超时时间要根据任务类型分别设置,查询类任务可以短一些,涉及人工确认的任务要长一些。一刀切的超时时间,要么误杀正常任务,要么放过僵尸任务。
还有一个细节是"心跳"。长任务在执行过程中应该定期上报心跳,编排层根据心跳判断任务是否还活着。心跳停了超过阈值,就判定为僵尸,走清理流程。这个机制在分布式环境下尤其重要,因为节点可能因为各种原因失联。
7.2 重试策略:次数、间隔与退避
重试是编排的标配,但重试策略设计不好,反而会放大故障。最常见的错误是无脑重试,失败了立刻重试,重试次数还设得很多。结果下游服务本来就压力大,被重试流量一冲,彻底雪崩。正确做法是带退避的重试,每次重试间隔逐渐拉长,给下游喘息的机会。
重试次数也要克制。我的经验是,对于瞬时故障(网络抖动、临时限流),重试两三次足够;对于确定性故障(参数错误、权限不足),重试多少次都没用,应该直接失败并给出明确原因。区分这两类故障,需要在错误码层面做设计,让编排层能根据错误类型决定是否重试。
还有一个容易被忽略的点是"重试的副作用"。前面提过幂等,这里再强调一次:有副作用的节点重试前必须确认上次执行的结果。我见过一个案例,支付节点因为超时重试,结果用户被扣了两次款,最后只能人工退款。这种事故在 Task 计费下是双重损失,既赔了钱又坏了口碑。
7.3 上下文膨胀与截断的取舍
多步任务跑下来,上下文会越来越长,因为每一步的结果都要带进下一步。上下文太长有两个问题:一是模型调用成本上升,二是可能超出模型的上下文窗口。这时候就要做截断或者摘要。
截断的策略有几种:保留最近 N 轮、保留关键节点结果、对历史做摘要压缩。我的经验是,关键节点的结果(比如用户确认过的信息、最终的决策依据)必须保留,中间过程的细节可以压缩。摘要压缩可以交给模型做,但要小心模型摘要时丢信息,最好在摘要后做一次校验,确认关键字段还在。
上下文管理还有一个技巧是"分层"。把上下文分成系统层(角色设定、规则)、任务层(当前任务的目标和约束)、会话层(最近的交互)三层,每层有不同的保留策略。系统层基本不变,任务层随任务走,会话层滚动更新。这样管理起来清晰,也方便按层做截断。
7.4 可观测性:没有日志就没有计费公信力
最后说一个我认为最重要的坑:可观测性。Task 计费要让人信服,前提是每一次计费都能被解释。用户问"为什么收我这个钱",你得能拿出证据:任务是什么、跑了哪些步骤、每步结果如何、最终交付了什么。这些全靠日志和追踪。
我的建议是,从第一天就把追踪做起来。每个任务一个 trace,每个节点一个 span,span 里记录输入、输出、耗时、状态、错误。trace 和 span 的 ID 要能关联到任务 ID 和计费记录。这样排查问题时,从一笔计费记录能一路下钻到具体的调用细节。
日志的粒度也要注意。太粗,排查时信息不够;太细,存储成本高还影响性能。我的做法是,关键节点记详细日志,非关键节点记摘要日志,错误日志一律详细记。同时设置日志保留策略,热数据保留久一点,冷数据归档。这套东西前期投入不小,但它是 Task 计费能长期跑下去的地基,省不得。
8. 我踩过几次坑之后总结的几条经验
第一,Task 的边界一定要在动手写代码之前和产品、商务对齐。技术团队自己拍脑袋定的边界,往往和计费口径对不上,后面改起来伤筋动骨。我现在的习惯是,任何涉及计费的编排改动,先拉一个三方会议,把任务定义、成败判定、结算时机三件事说清楚,再开工。
第二,编排系统的复杂度要跟着业务走,不要提前优化。我早期犯过一个错,业务还没跑通就设计了一套支持任意嵌套、任意并行的任务模型,结果大部分能力根本用不上,反而增加了理解和维护成本。后来学乖了,先用最简单的线性模型跑通闭环,遇到真实需求再扩展。
第三,幂等和可观测性这两件事,越早做越省事。它们不像新功能那样有即时反馈,但一旦缺失,后面补的代价是当初做的好几倍。我现在带项目,这两项是硬性要求,不达标不让上线。
第四,多智能体不是银弹。我见过太多团队为了"看起来先进"而上多智能体,结果协调成本吃掉了全部收益。判断要不要上多智能体,我的标准很简单:单智能体能不能干?能,就别上。只有当任务确实需要不同专长、不同权限、不同上下文的角色协同时,多智能体才有意义。
第五,计费规则要留出调整空间。Task 计费是个新事物,定价和规则肯定要迭代。系统设计时要把计费逻辑做成可配置的,规则变了改配置而不是改代码。这样商务调整定价时,工程团队不用跟着加班。这一点在快速试错阶段尤其重要。