AB
AiBoss
Tutorials

为托管大模型的 RAG 助手估算能耗与碳排放:分层拆解与实测方法

Tutorials

为托管大模型的 RAG 助手估算能耗与碳排放:分层拆解与实测方法

当模型跑在别人的机房里,能耗与碳排放并没有消失,只是转移到了你看不见的地方。这篇教程把一次 RAG 问答拆成可归属的几层,讲清哪些层由你用 CodeCarbon 自己测、哪些层由 EcoLogits 按调用估算、哪些层谁都算不到,并给出一个从零跑通的最小示例。

当模型跑在别人的机房里,能耗与碳排放并没有消失,只是转移到了你看不见的地方。这篇教程要教会你做成一件具体的事:把一个托管大模型的 RAG 助手拆成若干层,逐层判断哪些能耗由你自己测量、哪些由调用估算工具给出、哪些根本不在任何人的统计口径里,最后得到一个可以写进项目文档的能耗与碳排估算。适合已经用 API 搭过应用、想给项目补上环境维度核算的 AI/ML 工程师与数据科学从业者。全文只讨论使用阶段,也就是机器运行 AI 时消耗的电,以及由此产生的碳排放与用水,不涉及硬件制造与报废处理。

准备工作

先明确你要核算的边界

讨论 AI 的环境足迹时,人们通常只想到碳。实际上至少有五类影响值得分开看:

  • 能源:机器消耗的电,单位是瓦时(Wh)或千瓦时(kWh)。
  • 温室气体排放:以克或千克二氧化碳当量(CO2e)表示。同样一度电,来自煤电和来自核电、风电,排放差别很大。
  • 水:数据中心冷却(蒸发)用水,以及发电过程用水。
  • 材料:制造芯片、服务器、网络设备所开采的金属与矿物。
  • 电子废弃物:IT 硬件被替换之后的去向。

这些影响分布在机器生命周期的不同阶段:制造、使用、报废。把阶段和影响合起来做完整分析,叫生命周期评估(LCA)。本教程只覆盖使用阶段,原因有两个:制造与报废的评估非常复杂;而使用阶段恰好是工程师能施加影响的那一段。

判断你处在价值链的哪一环

核算难度取决于你离硬件有多远。可以按控制力从强到弱分成几类角色:

  1. 自己拥有全部机器,自己训练、自己部署——每一瓦都能追踪。
  2. 在云上租用实例自己跑训练或推理——机器不是你的,但实例类型、运行时长、区域由你决定。
  3. 调用托管模型的 API,自己只负责应用侧逻辑。
  4. 把提示词串起来、把智能体接到工具上,核心计算完全发生在模型提供方的服务器上。
  5. 直接打开别人做好的 AI 功能。

规律很直接:越少从零构建,越难测量自己行为的环境影响。在第 4 类位置,足迹并没有消失,只是转移到了你看不见的地方。本教程针对的正是第 3、4 类场景。

需要准备的东西

  • 一个可用的托管大模型 API 账号与密钥,用于跑通示例中的调用。
  • Python 环境,用于安装能耗测量库与估算库。
  • 一个向量库或至少一个能返回若干段文本的检索函数,示例里用最简实现代替。
  • 你所用云服务商的数据中心 PUE 数值,以及机器所在地区的电网碳强度。这两项如果拿不到,就使用工具内置的默认值,并在结论里注明这是估算。

需要提醒的是,下面出现的任何具体数值都只是参考量级,价格、配额、模型版本、区域可用性请以各服务商官网当前信息为准。

操作步骤

第一步:理解一个「每次调用」的数字是怎么算出来的

在动手之前,先搞清楚提供方公布的单个请求能耗包含哪些部分。以一次文本提示为例,一个常被引用的参考值是:中位数提示消耗约 0.24 Wh 电、排放约 0.03 g CO2e、用水约 0.26 mL。所谓中位数,意味着一半的提示低于这个值,一半高于这个值。

0.24 Wh 是什么概念?瓦时是功率 1 瓦的设备运行一小时消耗的能量,电费单上的单位是千瓦时,1 kWh = 1000 Wh。单次提示不到一次手机充电的 2%。但项目从来不是一次提示:一百万次提示按 0.24 Wh 计是 240 kWh。一个每天回答 3 万个问题的助手,大约一个月就会累积到一百万次。

这个数字由四部分相加得到,理解这四部分,才能理解你之后读到的任何「每次调用」数字里包含了什么、漏掉了什么:

  1. AI 芯片本身。提示被送到装有 AI 加速卡(TPU 或 GPU)的服务器,芯片读取提示、逐词生成回答,这部分功耗计入。
  2. 服务器其余部件与待机机器。每台服务器还有普通处理器和内存,负责接收请求、预处理数据、返回响应,它们也耗电。此外提供方会保留一部分空闲服务器应对流量高峰或故障,这些机器什么都不做但持续耗电,其能耗被摊到所有请求上。
  3. 数据中心建筑本身。制冷、变电、配电都要耗能,用 PUE(电能利用效率)量化:数据中心总能耗除以服务器能耗。PUE 为 1.09 意味着服务器每用 1 Wh,建筑还要多花 0.09 Wh。
  4. 从电到碳与水。前三步加总得到电量,再乘以当地电网的碳强度(每 kWh 排放多少克 CO2),得到碳排放;用水量用类似的「每 kWh 多少升」系数换算。这一步最能体现地区差异:同样的电量,以水电、核电、风电为主的地区排放远低于以煤电、气电为主的地区。

还要注意这个口径的边界:它通常不包含网络传输、用户设备、模型训练和数据存储;并且这类数字往往未经独立第三方核验。你在项目里引用时应当把这两点写清楚。

第二步:把提供方的数字翻译成你项目的数字

上面那个中位数描述的是发给通用聊天模型的一句短问题。你的模型、你的提示词、你的提供方机房都不一样,所以不能直接把这个数字搬过来。可以复用的是方法,而且不必手工算,有两个免费工具分别覆盖两侧:

  • EcoLogits:针对你调用的模型。它把上述步骤套用到提供方的服务器上,给出你所用模型每次调用的估算值。
  • CodeCarbon:针对你自己运行的机器。它把同样的步骤套用到你的服务器上,包括机器空转等待的时间。

这两个工具的配置项和输出里会反复出现三个词,先记住:

  • Idle(空转):机器开机但没有做有效工作的时间。
  • PUE:第三步里的建筑开销系数。向云服务商询问实际值,多数数据中心的 PUE 高于 1.09。在 CodeCarbon 里它是一个可设参数。
  • Carbon intensity(碳强度,也叫电网因子):机器所在地每消耗 1 kWh 电排放多少克 CO2e。不同国家之间可以相差数倍,两个工具都会替你查。

第三步:把一次调用拆成可归属的层

这是整篇教程的核心方法。以一次 RAG 问答为例,把能耗来源分成三层归属:

层包含什么谁来算
第 1 层你的 API 服务器、向量数据库、你计算的嵌入、重试、日志、评测任务你自己,用 CodeCarbon
第 2 至 5 层提供方机房里为你的请求发生的计算:AI 芯片、服务器其余部件、待机机器、建筑开销,以及换算出的碳与水提供方口径,或用 EcoLogits 按你的模型估算
第 6 至 8 层硬件制造、模型训练、网络传输没有任何按次口径统计,本教程不计入

第 1 层百分之百是你的责任,没有提供方会替你算。第 2 至 5 层不在你的公司里,你只通过 API 账单或订阅付费,但它们之所以存在,是因为你的应用发出了请求,所以它们属于你项目的足迹。第 6 至 8 层与大量其他用途共享,任何按次数字都不包含它们,记住它们存在即可。

第四步:安装并初始化两个测量工具

先安装依赖:

pip install codecarbon ecologits

CodeCarbon 的典型用法是三步:启动追踪器、运行你的计算、停止追踪器,然后拿到本次实验的 kWh 与 CO2e。初始化时把项目名、输出目录、所在地区、PUE 填进去:

from codecarbon import EmissionsTracker

tracker = EmissionsTracker(
    project_name="rag-assistant",
    output_dir="./emissions",
    country_iso_code="FRA",
    pue=1.2,
)
tracker.start()
# 这里放你要测量的应用侧逻辑
tracker.stop()

其中 country_iso_code 决定碳强度取值,pue 决定建筑开销系数,两者都直接影响最终结果,务必按实际情况填写,不要沿用示例值。

EcoLogits 的用法是在调用模型时套一层,让每次请求自动带上能耗估算:

from ecologits import EcoLogits
from openai import OpenAI

EcoLogits.init()
client = OpenAI()

response = client.chat.completions.create(
    model="your-model-name",
    messages=[{"role": "user", "content": "你好"}],
)
print(response.impacts)

返回的 impacts 对象里包含能耗、碳排放与用水相关的估算字段,具体字段名与单位以库的当前版本文档为准。

第五步:注意你的提示词不是「中位数提示」

这是最容易出错的地方。参考值描述的是短聊天问题,而你的 RAG 助手每次调用会把问题和若干段检索到的文本一起发出去,常常是几千字,模型在写出第一个字之前就要读完这些内容。读的文本越多,第一步里芯片的工作量越大,而且这个问题在每一次提问上都会重复。

推理模型和智能体把这一点推得更远:推理、智能体任务和视频生成,单次请求的能耗可以是简单文本回答的数百倍甚至数千倍。所以参考值只能当作量级锚点,不能当作你项目的系数。

一个完整示例

下面是一个从头到尾能跑通的最小例子:一个基于托管模型的内置文档问答助手。每个问题的处理流程是:服务器收到问题;把问题转成嵌入并在向量库里检索最相关的段落;把问题和这些段落通过 API 发给托管大模型;模型写出回答,服务器返回给用户。第 1、2、4 步发生在你控制的基础设施上,第 3 步发生在提供方一侧。

应用侧代码

import time
from codecarbon import EmissionsTracker
from ecologits import EcoLogits
from openai import OpenAI

EcoLogits.init()
client = OpenAI()

# 用最简实现代替真实向量库:返回若干段文档文本
def retrieve(question: str, k: int = 4) -> list[str]:
    docs = [
        "第一段公司文档内容……",
        "第二段公司文档内容……",
        "第三段公司文档内容……",
        "第四段公司文档内容……",
    ]
    return docs[:k]

def build_prompt(question: str, passages: list[str]) -> str:
    context = "\n\n".join(passages)
    return f"根据以下资料回答问题。\n\n资料:\n{context}\n\n问题:{question}"

def answer(question: str) -> str:
    passages = retrieve(question)
    prompt = build_prompt(question, passages)
    response = client.chat.completions.create(
        model="your-model-name",
        messages=[{"role": "user", "content": prompt}],
    )
    # 提供方一侧的估算,按次记录
    print("provider impacts:", response.impacts)
    return response.choices[0].message.content

if __name__ == "__main__":
    tracker = EmissionsTracker(
        project_name="rag-assistant",
        output_dir="./emissions",
        country_iso_code="FRA",
        pue=1.2,
    )
    tracker.start()
    try:
        for q in ["我们的报销流程是什么?", "年假如何申请?"]:
            print(answer(q))
            time.sleep(1)
    finally:
        emissions = tracker.stop()
        print("app-side kg CO2e:", emissions)

如何读这个示例的结果

运行结束后你会得到两组数字。第一组来自 tracker.stop(),覆盖第 1 层:你的服务器、检索、重试、日志这些应用侧动作消耗的电与排放。第二组来自每次调用打印的 response.impacts,覆盖第 2 至 5 层:提供方为这次请求发生的计算。把两组相加,才是这次问答在你项目口径下的总足迹。

把单次结果乘以业务量,就能得到有意义的规模感。例如每天 3 万次问答,一个月约一百万次调用;如果每次调用的提供方侧估算与参考值同量级,仅这一部分就是数百 kWh。这个换算不需要精确,它的作用是让你在评审会上能说出「我们的助手一年大概是什么量级」,而不是「不知道」。

把结果写进项目文档

建议在文档里固定记录四项内容,缺一项结论就不可复现:

  • 测量边界:只含使用阶段,不含硬件制造、模型训练、网络传输。
  • 关键参数:PUE 取值及来源、碳强度取值及地区、模型名称与版本。
  • 两组数字:应用侧实测值、提供方侧估算值,分开列,不要合并成一个数。
  • 已知偏差:提示词长度分布、是否使用推理模型或智能体、估算是否经第三方核验。

注意事项

  • 不要把参考值当成自己项目的系数。提供方公布的单次数字对应的是中位数短提示,而 RAG 每次调用要读入大量检索文本,实际能耗显著更高。
  • 推理模型与智能体会放大能耗。推理、智能体任务、视频生成的单次请求能耗可能是简单文本回答的数百到数千倍,做容量与足迹评估时必须单独考虑。
  • 碳强度随地区变化很大。同样的电量,在煤电为主的地区排放远高于水电、核电、风电为主的地区。跨区域部署的应用不能只算一个地区的数。
  • PUE 要问服务商。不同数据中心的 PUE 差异明显,用错系数会让建筑开销部分整体偏移。
  • 空转时间要计入。机器开机但没做有效工作的时间同样耗电,CodeCarbon 会把它算进去,这也是为什么追踪器要覆盖完整的运行区间而不是只包住一次函数调用。
  • 口径边界要如实说明。常见口径不含网络、用户设备、模型训练与数据存储,且数字往往未经独立第三方核验。引用时把这些限制写出来,比给出一个看似精确的数字更可信。
  • 制造与报废不在本教程范围内。这不是因为它们不重要,而是因为评估复杂,且使用阶段才是工程师能直接影响的部分。
  • 工具版本、模型名称、配额与计费方式会变化。安装命令、参数名、返回字段请以各库与服务商官网当前信息为准。