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 还不够。编码代理需要一个稳定、权限受控并且输出紧凑的查询接口。可以把交互拆成三步:
- 根据组件名查询目录实体。
- 从返回结果提取仓库、负责人、系统和文档位置。
- 只在目标仓库或目录中继续搜索代码。
关键原则是“默认少返回”。不要把完整实体、全部注解和整份文档直接塞给模型。更合适的响应可能只有:
{
"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_URL、BACKSTAGE_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 更多地用于理解和修改代码。