我们在Uber怎么管住AI编程开销:7倍用量,34%单均成本下降

2026年8月,Uber的AI编程工具周活涨了7倍,Agent请求涨了9.4倍,但总AI花费从4月开始稳定下来了。

这篇讲的是我们具体怎么做到的。核心不是压价,是把花在废话上的token省掉,同时保持输出质量不降。

我们说的“Software Factory”到底指什么

先讲清楚我们在做的这件事:把所有AI编程能力组织成四层,从最专用到最通用,越往上我们自己能控制的东西越多——模型选哪个、质量怎么卡、成本怎么管。

图像

Layer 1:专用Agent
代码审查、修CI失败、处理告警、修bug、维护任务。每个Agent只做一件事,benchmark最准,模型选最合适的那个。

Layer 2:通用Agent
比如Claude Code这类工具,工程师自己触发,干的事比较杂。

Layer 3:上下文检索
在代码库、数据表、日志、监控系统里找信息。我们现在有一个AI Context Graph,后面会细说。

Layer 4:基础模型API
最底层,直接调模型。

这四层的成本拆法是一样的,我们就靠这个拆法找到了优化方向。

一个公式说清楚钱花在哪了

我们把一次Agent会话的成本拆成六项:

图像

拆开看:

第一组:用量(我们不想压这俩)

  • 周活用户数 × 每人会话数

第二组:每次会话干了多少活(主要优化对象)

  • 每会话请求数 × 每请求token数

第三组:单价

  • 每token价格

如果只是用量涨了导致账单涨,那是正常的。真正要管的是:每个请求有没有塞了不该塞的东西,每次会话是不是绕了太多冤枉路。

怎么量:我们每周看的指标

下面这张表里是我们每周、每月追踪的全部指标,用来做短期排期和长期规划。

图像

表的核心逻辑就一句话:每个环节单独数清楚,才知道该动哪里。比如“每会话请求数”涨了,要去查是Agent自己多绕了几步,还是工具返回太慢导致重试。“每请求token数”涨了,可能是上下文里塞了太多工具schema。

我们具体动了什么

图像

整体思路是三层同时动:

  1. 选更便宜的模型跑合适的活(Price/token)
  2. 让每次请求少带点废话(Tokens/request)
  3. 让Agent少绕弯路(Requests/turn)

下面挨个讲。

一、选模型:不是最贵的就最好

模型定价是供应商定的,我们能做的是:对这个具体的活,挑性价比最高的模型来跑。什么叫性价比?三件事:完成任务的成本、输出质量、可靠性。

选模型走四步

每上一个托管Agent,都走同一套流程:

  • 用这个Agent的真实工作场景攒一套benchmark
  • 搭一个测试架子,能接任何模型(闭源开源都行),同一个接口
  • 挨个跑,看哪个在Pareto前沿上
  • 前沿每几周变一次,持续跟着换

uReview的例子

uReview是我们做AI代码审查的Agent。benchmark用的是真实PR,里面埋了已知bug,分easy/medium/hard三档。我们测precision、recall、F1,同时记每次review的成本、延迟、超时和乱报的情况。

图像

图上虚线是Pareto前沿。每个点是一种模型配置,往右下方向移动就是又便宜又好。换模型之后,F1提了,单次PR成本大幅下降。

除了uReview自己的benchmark,我们内部还搭了一个跨仓库的Uber SWE Benchmark,用几千个真实PR跑各种模型,覆盖多语言、多任务类型,用来给所有SDLC托管Agent做模型选型的参考依据。

默认模型怎么配

交互界面里,token单价是固定的,但我们可以控制哪些场景用什么模型。两个默认配置最管用:

一个是初始会话模型。用户进来说第一句话,用哪个模型接。

另一个是子Agent模型——这个影响最大,而且还在变大。因为模型能力上来了,越来越多场景适合用多Agent分工。主Agent负责拆任务和做判断,子Agent负责执行。子Agent干的活定义明确,输入输出清楚,不需要那么强的推理能力,所以默认用一个弱很多也便宜很多的模型。如果某个子任务确实需要强推理,人工可以单独覆写。

二、降token:每次请求少带点废话

每次模型调用都会把整段对话历史、项目上下文、工具返回结果全部重发一遍。每轮省一点,整场会话乘起来就很可观。

两个默认配置直接从源头卡

所有交互式工具用的同一个底层封装,统一管安装、配置、认证和成本可见性。下面两个默认值对降token效果最直接:

  • 自动压缩阈值设在400K token。就算模型支持1M上下文,我们也在400K就触发压缩。这个值是在模型性能和缓存命中率之间找的平衡点,实测下来全平台每次请求的输入token数确实降了。
  • 推理强度默认设Medium。输出token(包含内部推理token)在主模型上按输入token的若干倍计费,这个调整直接切在最贵的那一档。对一大类任务来说,Medium已经够用,性价比最好。

Prompt缓存怎么用才划算

每次请求都重发完整上下文,如果能把前面已经发过的内容缓存住,后面就只付0.1倍的输入token价格。但写缓存有成本:缓存5分钟的收1.25倍,缓存1小时的收2倍。选多长TTL(Time-to-Live)取决于两次请求之间间隔多久。

图像

工程师用交互工具的时候经常停下来想一会儿,或者切出去看别的再回来,间隔常常超过5分钟。所以我们把交互会话的缓存TTL从5分钟改成了1小时。改之前,只要间隔超过5分钟,之前的缓存就失效了,下次请求得重新付全价把上下文再写一遍。子Agent那边没这个问题,它们跑的都是短任务,连续执行,间隔短,所以保持5分钟TTL就够了。

MCP工具不进上下文,改成命令行调用

Uber内部所有MCP(Model Context Protocol)交互走一个统一网关。这个网关后面接了1000多个MCP服务器,包括内部系统和第三方SaaS。

标准MCP的问题在于:它把所有工具schema一次性塞进每个会话的上下文里。比如装了100多个工具,光初始prompt就多了5万-7万token的schema开销,而且每一轮都重发。

图像

我们做了两个补丁:

CLI工具解析:不让模型直接调MCP,而是让它执行一个shell命令。这个CLI在调用的时候才去网关那边解析和调用具体工具,所以MCP的schema完全不用进会话上下文。1000多个MCP工具全被投射成了CLI命令,模型用起来就像在终端敲命令一样。

工具搜索:当工具数量到了几千个的时候,全部塞进上下文已经不现实了。我们让模型自己去搜工具目录,需要什么就加载什么。这样既压住了上下文膨胀,搜工具的准确率也稳得住。

Code-Mode:把轮询踢出上下文

工具通过命令行调用的时候,模型可以一个脚本里批量执行多个动作。这对那种需要反复轮询的工具特别管用。

标准MCP工作流里,每个动作都要单独走一轮:模型发一个请求 → 等返回 → 上下文里加载响应 → 再处理。比如跑一条SQL查询,需要依次提交请求、轮询2-5次状态、拉结果。整个过程模型全程参与,每次轮询的响应都留在上下文中。

Code-Mode的做法是:把这些轮询逻辑写成一个Python脚本,在子进程里跑完,只有最终汇总结果回到模型上下文。

图像

我们用同一个会话跑5条同样的SQL查询做对比:

图像

即使返回结果集很小、远没到响应大小限制,Code-Mode也能把token用量压掉50%以上。省掉的不是大数据传输,而是schema初始化、多轮轮询、多余的分步推理这些开销。

批量场景效果更夸张:本来要N轮模型调用的事情,变成一个脚本跑完,省掉90%以上。我们现在给最常调用的MCP服务器预制了25个以上的Code-Mode技能,保证常用工作流默认走最省钱的路径。

SaaS MCP怎么处理

管第三方SaaS的MCP比管自己的难。供应商不知道你会怎么用,所以把整个产品能力全暴露出来。比如一个workspace套件自带49个工具,光schema就占~22K token;消息工具34个、项目管理46个。随便接两三个供应商,会话还没开始干活,上下文里塞的schema已经比你要改的代码还多了。

我们的做法是:把SaaS MCP也接到同一个MCP网关后面,同样走CLI方式让Agent调用。同时针对每个供应商的常用场景,在Code-Mode插件里预置专用技能。这样不管接了多少家SaaS,调用方式统一,效率也统一。

图像

三、降轮次:让Agent少走冤枉路

一个没有上下文的Agent犯错的方式是慢的,不是快的。它会拿着越来越长的上下文一遍遍去搜、去试、去等报错。给够信息,是省轮次最有效的办法。

AI Context Graph:把信息提前喂到位

Uber的代码库和数据生态规模很大:几亿行代码、几千张表。Agent大部分时间花在“找东西”上,不是“写东西”。

所以我们建了一个AI Context Graph:2400万个节点、8000万条边,覆盖86种节点类型和117种边类型,接了30多个内部系统的数据,包括服务信息、工程团队、事故日志、PR、架构文档、部署记录、数据集、历史表查询记录。任何Agent都可以用自然语言查这个图。

下面这个对比很直观,同一个模型、同一个prompt,一个有图一个没图:

图像

有图的Agent直接查了历史使用记录,发现某个表有超过50个分析师在用,38秒给出答案。

没图的Agent看不到那个表,花了20分钟翻服务代码、起了2个子Agent、撞了3个报错,最后说“查不了”。

38秒 vs 20分钟,这就是给够信息和让Agent自己摸索的差别。

两条辅助线:看得见才能管得住

上面说的都是技术层面的优化。但如果没有反馈回路,工程师不知道自己的会话花了多少钱、为什么花这么多,优化就无从谈起。

终端里的实时计价器

我们在所有交互工具的终端状态栏里放了一个实时计价器,显示当前会话花了多少钱,以及该用户所有会话的累计花费。

图像

分级提醒,不设硬上限

我们没有给工程师设死额度,而是做了一套渐进式提醒:

  • 状态栏实时显示当前会话成本
  • 所有交互工具共用一个额度池,不按单个工具分预算。托管Agent单独列池。
  • Slack通知:达到预期花费的50%/80%/100%时自动提醒
  • 额度升级需要经理审批,但审批通过后立即生效

会话分析面板

状态栏只能看到总额,看不到“钱到底花在哪了”。我们内置了一个成本分析技能,可以分析该用户所有会话的trace,覆盖本地和云沙箱、所有交互工具。

这个面板不报告汇总平均数,而是直接标出16种浪费模式,每一条都带着具体金额影响和改法。比如:

  • 模型选型不合理:简单多轮对话用了Opus,其实Sonnet就能搞定
  • 上下文膨胀:40KB的大返回结果一直留在上下文里,每轮重付
  • 缓存过期:会话中断太久,缓存已过期,下次请求全价重建
  • 初始化浪费:用户还没说话,系统指令和工具定义已经灌了10万token
图像

后续还要做的事

托管Agent扩量:每个新Agent上线的流程已经固化了——定结果指标、搭评估benchmark、找Pareto最优模型。按这个节奏把SDLC每个环节往上推。

动态模型路由:现在benchmark覆盖的编程语言、代码仓库、Agent类型还在扩展。路由准不准,全看评估覆盖得够不够,因为模型在不同任务上的表现差异很大。

Context Graph接入更多Agent:让更多Agent能直接查图,而不是自己慢慢摸索。

实时效率提醒:从现在的离线程式(跑完再分析)改成实时监控trace,直接在终端里给个性化建议。

技能自动迭代:正在做一个自动记录Agent执行过程中卡顿点、然后从trace里自动生成技能更新的流程。

操作清单

  • 检查你是否知道当前每个模型在你们具体任务上的实际性价比,不只是看跑分
  • 有没有把工具schema和系统指令从每次请求的上下文中移出去
  • 缓存TTL设多长,取决于你们用户两次请求之间的典型间隔,不是越长越好
  • 先把信息给够,再让Agent自己搜
  • 让每个会话的成本可见,工程师看到了自然会注意

常见问题

Q:靠换便宜模型能省下多少钱?
能省一些,但大头不在那儿。我们选模型的原则是“够用就好”,真正省掉的是那些不需要花、但一直在花的token。

Q:那省钱主要靠什么?
靠去掉工具schema的固定开销、把轮询踢出上下文、让Agent第一次就能拿到对的信息。这三样加起来,省掉的是模型调用次数和每次调用的token数,是乘法效应。

Q:Code-Mode是什么?所有人都能用吗?
Code-Mode就是把本来需要模型参与多轮轮询的操作,写成一个脚本在子进程里跑完,只把结果拿回来。目前我们用这个处理了25个以上最常用的内部MCP操作,用户直接调对应的技能就行,不需要自己写脚本。

Q:缓存TTL选5分钟还是1小时?
看你用户两次操作之间的典型间隔。如果经常停几分钟再回来,选1小时;如果是连续执行的自动化任务,5分钟就够。我们两种情况都在用,场景不同配置不同。

Q:Context Graph能搜到什么?
代码、服务、表、团队、事故记录、PR、设计文档、部署记录、历史查询记录,目前是这些。Agent用自然语言问就行。

Q:会话分析面板是强制开启的吗?
是内置的,不需要配置也不需要手动开启。执行成本分析技能就能看到所有会话的trace和浪费标记。

Q:这些优化手段开箱即用吗?
具体工具是我们自己搭的,但方法论可以照搬:拆解成本公式、每层单独度量、针对最大浪费点动手、让成本可见。不管代码库多大、用什么模型,这套逻辑通用。