多加两种语言,为何推理负载超出预估
作者为自托管模型驱动的资讯应用新增德语和葡萄牙语后,发现推理负载远超原先估算,任务开始积压。原估算依赖一次调用生成全部语言,但四语合并输出此前已出现质量问题,使该成本假设不再成立。
AI 深度解读
给自托管的语言模型多加两种输出语言,成本会增加多少?RealFeedApp 的作者按新增文本量算过账,认为服务器还有余量。上线当天,模型却几乎一直忙碌,实际负载达到预估的数倍,等待摘要的新闻开始超时。
问题出在估算依据:原先一次请求完成的任务,已经变成了两次完整请求。这次复盘值得程序员读的地方,是它把容量估算、优先级队列和产品需求验证串到了一起:省成本之前,先确认自己究竟在测什么。
新增两种语言,为什么多了一整轮成本
RealFeedApp 会为收录的科技新闻生成短摘要和通俗解释,模型部署在自己的服务器上。此前支持两种语言,作者在周一加入了 German 和 Portuguese。
最初的估算很直观:同一次调用多写两种语言,答案长一些,成本应该按输出量增长。
但这个前提在实现时已经变了。他们之前测试过一次生成四种语言,结果是回答变长,语言之间还会相互混杂。为了保证质量,原来的两种语言保留在一次请求里,新增两种语言放到另一次请求,并把已经生成的 English 标题作为参考传进去。通俗解释也采用同样的拆分方式。
于是,每篇新闻都多了一次完整的摘要调用,需要重新读取全文、指令,再生成答案。生成解释时,也会额外调用一次。
调用结构变了,成本模型就必须跟着变。
作者没有说拆分请求是错误决策。质量测试支持这种拆分,错的是继续用「多输出几行文本」给它定价。对自托管服务来说,这笔成本直接表现为模型占用时间,以及其他任务还能分到多少处理能力。
为什么调用次数和队列长度都可能误导你
作者起初按任务类型统计调用次数。解释类调用翻倍,摘要调用也增加了;解释又是系统里最长的文本,看上去最适合先砍掉新增语言。
但输出长,不代表累计消耗最多。
worker 会在每个步骤开始前写日志,每次模型调用也会记录耗时。作者把两者关联起来,统计各步骤实际占用了多少模型时间:
journalctl -u my-worker --since '-6h' -o cat | awk '
/worker: enriching/ {t="enrich"}
/worker: explaining/ {t="explain"}
match($0, /model .*: [0-9]+ s/) {
split(substr($0, RSTART, RLENGTH), a, " "); s[t] += a[3]; n[t]++
}
END { for (k in s) printf "%s: %d calls, %.0f s\n", k, n[k], s[k] }'
关键是 s[t] += a[3]:它按步骤累加耗时,而 n[t]++ 才是累计调用次数。--since '-6h' 将统计范围限定在最近六小时。
结果与直觉相反:解释只占模型时间的一小部分,绝大多数时间花在摘要步骤。解释虽然长,却生成得少;摘要需要覆盖每一篇新闻,累计下来才是大头。砍解释几乎省不下多少资源,还会损失产品体验。
队列监控也有类似陷阱。当时只有少数新闻排队,但最老的一条大约从发布时就开始等待。
原因是 worker 总先处理排名最高的新闻。有空余容量时,这能让重要内容尽快上线;容量耗尽后,新来的高排名新闻不断插队,低排名新闻就一直轮不到。
优先级队列可以一直很短,同时让某些任务一直等下去。
因此,报警盯的是最老待处理任务的等待时间。只看队列长度,那天晚上监控可能始终显示正常。
留一种语言能省多少,为什么必须实测
作者面临三个选择:撤掉新增语言、增加硬件,或者保留一部分功能。
他们选择测试只保留 German。但 German 和 Portuguese 原本共用一次调用,删掉其中一种只会缩短输出,读取文章和指令的成本仍然存在,不能直接按成本减半计算。
质量也需要重新验证。此前单语言生成曾偏向指令使用的语言,不过那次指令是 Russian,这次新增请求使用 English,旧结论不能直接照搬。
作者用同一组文章、同样的提示词和采样设置,对比双语言生成与仅生成 German。结果是,单语言调用便宜了约三分之一,没有发现文字系统错误、漂移到 English 或内容截断。
这里还有一个具体细节:German 和 English 使用相同字母表,检查字符所属文字系统无法识别语言漂移。作者另外统计常见功能词来辅助判断。最终,Portuguese 被移出生成流程,German 保留。
接下来还有一个诱人的方案:German 也暂停预生成,等用户在菜单中选择时再翻译,有需求后恢复。
作者没有这么做。这个新闻站的新语言需求主要来自搜索,而搜索流量依赖对应语言的页面已经存在。站点只有完成翻译,才会构建对应语言的日期页和文章页。停掉生成,页面随之消失,搜索用户无法进入,最后再用「没人访问」证明没有需求,实验就失去了意义。
菜单因此只展示实际生成的语言,出现的选项必须完整可用。
我的判断
我认同这次复盘的诊断顺序:先确认调用结构,再按稀缺资源计量,最后测试可以削减的变体。它尤其适合固定硬件容量下的模型服务,也适合由 Node worker 调度的内容生成流水线。
但约三分之一的节省只能视为作者这组实验的结果。原文没有给出模型名称、硬件配置、文章样本量、具体耗时,也没有完整说明质量评估方法。「没有发现质量下降」有参考价值,还不足以证明换一批内容仍然成立。
监控也需要保留多个视角。最老任务年龄能揭示优先级饥饿,但队列长度仍能帮助判断积压规模。原文定位了问题,没有继续讨论等待时间加权、配额或先进先出等调度方案。
至于预生成和按需翻译的取舍,关键前提是搜索获客。对这个站点,缺页面会直接破坏需求验证;对主要靠已登录用户使用的内部工具,按需生成仍可能合适。原文没有两种方案的对照数据,不宜据此判断谁普遍更省。
能拿来做什么
- 给 AI 编程或内容生成流程增加步骤前,先列出变更前后的调用次数,以及每次重复传入的上下文。拆成独立请求的审查、解释或多语言任务,都要重新估算完整调用成本。
- 在 Node worker 中记录任务类型、调用耗时和入队时间,同时观察各步骤累计耗时与最老任务年龄。使用优先级调度时,尤其要检查低优先级任务是否长期得不到处理。
- 缩减语言或输出内容时,用同一批输入、同样的提示词和采样设置做对比,同时检查耗时、语言漂移与截断,别把输出减少一半直接当成成本减少一半。
- 前端语言菜单只展示能够完整交付的语言。若用搜索流量验证新语言需求,先确认成本优化是否会让对应页面停止生成,进而破坏验证条件。