把 Backstage 变成 AI 编码代理的上下文入口:减少 90% Token 消耗的工程思路

2026-09-04 24 预计阅读时间: 1 分钟
来源: engineering.atspotify.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

AI 编码代理消耗的 Token,并不全花在推理上。它经常需要反复扫描仓库、搜索服务名称、读取配置、定位负责人,再从大量输出里拼出真正有用的上下文。来源案例指出,将 Spotify Backstage Portal 作为统一入口后,Claude Code 的 Token 用量减少了 90%。这个数字来自特定环境,未必能直接复现,但背后的优化方向很明确:减少无边界 I/O,让代理通过结构化查询获取小而准确的上下文。

Token 往往消耗在“找资料”上

面对“修改支付服务的重试策略”这样的任务,代理可能先执行一串探索命令:

find . -type f | head -n 200
rg -n "payment|retry|timeout" .
rg -n "owner|oncall|runbook" .

这些命令本身并不错误,问题在于返回结果会进入上下文窗口。单体仓库、多语言项目或生成文件较多时,一次宽泛搜索就可能产生数千行输出。随后代理还要读取多个配置文件,判断哪个目录属于目标服务。

Backstage Portal 的价值在于把这些关系预先整理为软件目录:服务名称、代码仓库、负责人、系统归属、文档和运行手册可以围绕同一个实体组织起来。代理不再从文件系统猜测组织结构,而是先查询目录,再读取少数相关文件。

这里真正节省的不是一次回答的字数,而是整个任务中的探索轮次:

  • 减少递归扫描仓库产生的无关输出。
  • 避免重复读取已经存在于服务目录中的元数据。
  • 先确定服务边界,再执行精确的代码搜索。
  • 让负责人、文档和依赖关系以结构化字段返回。

把 Portal 当成机器可查询的上下文层

仅仅让开发者能在浏览器里打开 Backstage 还不够。编码代理需要一个稳定、权限受控并且输出紧凑的查询接口。可以把交互拆成三步:

  1. 根据组件名查询目录实体。
  2. 从返回结果提取仓库、负责人、系统和文档位置。
  3. 只在目标仓库或目录中继续搜索代码。

关键原则是“默认少返回”。不要把完整实体、全部注解和整份文档直接塞给模型。更合适的响应可能只有:

{
  "name": "payments-api",
  "owner": "group:payments",
  "system": "checkout",
  "repository": "ssh://git.example.com/checkout/payments-api.git",
  "docs": "/docs/default/component/payments-api"
}

这也要求团队治理目录质量。过期的负责人、失效的仓库地址或含义不一致的标签,会让代理更快地得到错误答案。Portal 能降低检索成本,但不能自动修复元数据质量。

可以这样实践:给 Claude Code 一个窄查询脚本

下面示例假设 Backstage 部署暴露了 Catalog API,并接受 Bearer Token。不同版本、插件和认证代理的路径可能不同,运行前需要修改 BACKSTAGE_URLBACKSTAGE_TOKEN,必要时调整 API 路径。

创建 scripts/service-context.sh

#!/usr/bin/env bash
set -euo pipefail

if [[ $# -ne 1 ]]; then
  echo "usage: $0 <component-name>" >&2
  exit 2
fi

: "${BACKSTAGE_URL:?set BACKSTAGE_URL, for example https://backstage.example.com}"
: "${BACKSTAGE_TOKEN:?set BACKSTAGE_TOKEN}"

component="$1"
encoded_name="$(jq -rn --arg value "$component" '$value|@uri')"

curl --fail --silent --show-error \
  -H "Authorization: Bearer ${BACKSTAGE_TOKEN}" \
  "${BACKSTAGE_URL%/}/api/catalog/entities/by-name/component/default/${encoded_name}" |
  jq '{
    name: .metadata.name,
    description: .metadata.description,
    owner: .spec.owner,
    system: .spec.system,
    lifecycle: .spec.lifecycle,
    repository: .metadata.annotations["backstage.io/source-location"],
    docs: .metadata.annotations["backstage.io/techdocs-ref"]
  }'

运行方式:

chmod +x scripts/service-context.sh
export BACKSTAGE_URL="https://backstage.example.com"
export BACKSTAGE_TOKEN="replace-with-a-read-only-token"
./scripts/service-context.sh payments-api

然后在项目的 CLAUDE.md 中约束代理的探索顺序:

## Service discovery

Before searching the whole repository for service ownership or documentation:

1. Run `scripts/service-context.sh <component-name>`.
2. Use the returned repository and system fields to limit code searches.
3. Request full documentation only when the summary is insufficient.
4. Never print or persist `BACKSTAGE_TOKEN`.

如果不希望代理直接接触 Backstage Token,可以在内部网关或 MCP 工具后面封装同样的查询,并只开放只读、字段白名单化的方法,例如 get_service_context(name)。这通常比把通用 HTTP 凭据交给代理更容易审计。

衡量效果不能只看总 Token

“减少 90%”是醒目的结果,但落地时应建立自己的基线。至少记录以下指标:

  • 每类任务的输入 Token、中间工具输出和总调用次数。
  • 从收到任务到首次修改正确文件的时间。
  • 全仓库搜索、目录遍历和重复文件读取的次数。
  • 因目录元数据错误导致的返工率。
  • Portal 查询延迟、失败率和权限拒绝率。

选取一批可重复任务,例如定位负责人、修改服务配置、查找运行手册和分析依赖关系,分别在接入前后执行。除了平均值,也要观察高分位数;真正拖慢代理的通常是少数上下文极其混乱的任务。

接入时的边界与检查清单

优先从高频、低风险的只读查询开始,不要一开始就允许代理修改 Catalog 实体或触发运维操作。推荐的上线顺序是:

  • 为服务名称、负责人、仓库和文档字段定义统一规范。
  • 提供只读身份,并采用最小权限和短期凭据。
  • 对返回字段做白名单过滤,避免泄露内部注解和敏感配置。
  • 设置超时、缓存与降级策略,Portal 不可用时允许代理回退到本地搜索。
  • 在提示词或项目说明中明确“先查目录,再查代码”的顺序。
  • 用真实任务做 A/B 对比,而不是只统计一次演示的 Token。

Backstage 在这里不是替代代码搜索,而是帮助代理决定去哪里搜索。只要目录数据可信、接口足够窄、权限设计合理,就能把大量试探性 I/O 变成一次结构化查询,让 Token 更多地用于理解和修改代码。


相关推荐