TT Lab
开始
学习 学习路径 课程

LLM 服务

做一个带限流与 token 记账的网关

在 TT Lab 中继续学习

目标

亲手构建 LLM 网关,实现按 token 而非按请求的限流与计量,并完成按租户的预算控制。

为什么重要

每分钟限制 60 个请求,在 LLM 前几乎没有意义。如果某个租户每次请求都输入 200,000 个 token,请求数仍在限制内,但成本和 GPU 占用可能是其他租户的数百倍,而且这些请求会独占 KV 缓存并挤占其他请求。因此,LLM 网关的首要设计原则是统计 token。本实验中最棘手的是第 4 步和第 8 步。输出 token 只有生成结束后才能确定;如果仅在完成后检查预算,并发进入的请求会同时判断自己仍在预算内,全部通过后一起超支。以 max_tokens 为上限预先预留,完成后按实际用量结算,可以解决这个问题。真实服务中的成本事故,往往就发生在这里。

步骤

  1. 在 127.0.0.1:8171 启动 /root/gw/gateway.py,把 POST /v1/generate 转发到 8170 后端。响应必须与后端一致。将租户 t1 的 API 密钥逐行保存到 /root/gw/key.txt,将 t2 的密钥逐行保存到 /root/gw/key2.txt——后续步骤的评分会使用这两个文件。
  2. 通过 X-API-Key 请求头识别租户。密钥到租户的映射位于 /opt/fixtures/llms/apikeys.json。缺少密钥或密钥未知时返回 401。
  3. 为每个租户应用每分钟 10 次请求的限制。第 11 次请求必须返回 429。在 /root/gw/rpm.txt 中写入 allowed=10 rejected=1。
  4. GET /v1/usage 返回 {"tenant":"...","prompt_tokens":<n>,"completion_tokens":<n>,"requests":<n>}。两个 token 值都必须大于 0。
  5. 使用 token bucket 实现每分钟 2000 个 token 的限制。超出限制的请求必须收到 429。在 /root/gw/tpm.txt 中写入 limit=2000 consumed=<n> rejected=<n>,且 rejected 必须至少为 1。
  6. 所有 429 响应都必须带有 Retry-After 请求头,其值为 1 到 60 之间的整数。在 /root/gw/retry.txt 中写入 retry_after=<정수>。
  7. 使用 /opt/fixtures/llms/pricing.json 中各模型的单价计算费用,在 /root/gw/cost.csv 中写入 tenant,model,prompt_tokens,completion_tokens,cost_usd 表头和至少 2 行数据。
  8. 将租户 t1 的每日预算设为 0.01 美元,超出时返回 402。预留时以 max_tokens 为基准提前占用额度,完成后按实际用量结算。在 /root/gw/budget.txt 中写入 budget_usd=0.01 spent_usd=<수> blocked=true。

参考

通过网关代理后端

在 127.0.0.1:8171 启动 /root/gw/gateway.py,把 POST /v1/generate 转发到 8170 后端。响应必须与后端一致。将租户 t1 的 API 密钥逐行保存到 /root/gw/key.txt,将 t2 的密钥逐行保存到 /root/gw/key2.txt——后续步骤的评分会使用这两个文件。

先创建原样透传的代理,再逐项添加功能。

使用 API 密钥识别租户

通过 X-API-Key 请求头识别租户。密钥到租户的映射位于 /opt/fixtures/llms/apikeys.json。缺少密钥或密钥未知时返回 401。

缺少密钥或密钥未知时返回 401。请保存密钥到租户的映射。

设置每分钟请求数限制

为每个租户应用每分钟 10 次请求的限制。第 11 次请求必须返回 429。在 /root/gw/rpm.txt 中写入 allowed=10 rejected=1。

固定窗口最简单。请思考超出限制时应返回哪个状态码。

分别计量输入与输出 token

GET /v1/usage 返回 {"tenant":"...","prompt_tokens":<n>,"completion_tokens":<n>,"requests":<n>}。两个 token 值都必须大于 0。

必须分别统计两者,因为单价不同。

设置每分钟 token 限制

使用 token bucket 实现每分钟 2000 个 token 的限制。超出限制的请求必须收到 429。在 /root/gw/tpm.txt 中写入 limit=2000 consumed=<n> rejected=<n>,且 rejected 必须至少为 1。

token bucket 很适合这种场景。它既允许平时安静的租户突发请求,又能保持长期平均速率。

在 429 中提供重试时间

所有 429 响应都必须带有 Retry-After 请求头,其值为 1 到 60 之间的整数。在 /root/gw/retry.txt 中写入 retry_after=<정수>。

计算剩余时间并以整数秒返回。缺少该值会导致客户端形成请求浪涌。

按模型单价计算费用

使用 /opt/fixtures/llms/pricing.json 中各模型的单价计算费用,在 /root/gw/cost.csv 中写入 tenant,model,prompt_tokens,completion_tokens,cost_usd 表头和至少 2 行数据。

通常输出比输入更昂贵。单价表位于 fixture 中。

阻止预算超支并报告用量

将租户 t1 的每日预算设为 0.01 美元,超出时返回 402。预留时以 max_tokens 为基准提前占用额度,完成后按实际用量结算。在 /root/gw/budget.txt 中写入 budget_usd=0.01 spent_usd=<수> blocked=true。

也可以不阻止,而是降级到更便宜的模型。本实验采用阻止方式。