Spotify Portal 如何把 Claude Code 的 Token 消耗降低 90%:别让上下文浪费在 I/O 上

2026-09-04 39 预计阅读时间: 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 Portal 将 Claude Code 的 Token 使用量降低了 90%;其关键观察是:代理的大部分工作不是推理,而是 I/O。

这个数字是作者在特定环境中的结果,不能直接视为所有项目的通用基准。不过,它指出了一个很实用的优化方向:与其只调整模型和提示词,不如先缩短代理获取有效信息的路径。

Token 为什么会被 I/O 吃掉

在一次常见的排障任务中,编码代理可能依次执行这些操作:

  • 列出整个仓库的文件。
  • 搜索某个类名或错误消息。
  • 打开多个可能相关的文件。
  • 读取大段构建日志和测试输出。
  • 因为上下文被压缩或遗忘,再次读取相同内容。

这些操作在本地终端里成本很低,但进入模型上下文后,每一行都可能转化为输入 Token。尤其是 node_modules、生成文件、锁文件、压缩后的前端资源和冗长日志,通常信息密度很低。

真正需要模型推理的内容往往只是:服务归谁维护、入口在哪里、最近改了什么、哪个测试失败,以及相关模块之间有什么依赖。Portal 这类开发者门户的价值,可以理解为把分散的工程事实整理成更小、更明确的查询结果,让代理少“翻仓库”,多处理已经筛选过的信息。

优化重点不是少调用,而是提高每次读取的密度

单纯限制工具调用次数可能适得其反。代理拿不到足够信息时,会猜测实现细节,或者用更昂贵的方式反复确认。更稳妥的做法是给它窄而准确的工具接口:

  • 用符号或关键词搜索代替递归读取目录。
  • 默认返回摘要,需要时再展开全文。
  • 先提供服务目录、所有者和依赖关系,再读取源码。
  • 测试命令只返回失败项及其附近输出。
  • 对相同查询做缓存,并标明数据是否过期。
  • 把权限过滤放在数据访问层,而不是只写进提示词。

这里的核心指标不只是总 Token 数,还包括“找到第一个有效线索用了多少 Token”和“解决一个任务需要重复读取多少次”。如果 Token 降低了,但错误率、等待时间或人工返工增加,优化就没有真正成立。

可以这样实践:给代理一个受控的上下文入口

下面不是来源文章中 Portal 接口的复刻,而是一个可以直接改造的最小实践。它把常见仓库查询收敛到一个脚本里,默认排除高噪声目录并限制输出规模。

在 Git 仓库根目录运行以下命令:

mkdir -p tools
cat > tools/agent-context.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

command_name="${1:-help}"
argument="${2:-}"

case "$command_name" in
  status)
    git status --short
    printf '\nRecent commits:\n'
    git log -5 --oneline
    ;;
  search)
    if [[ -z "$argument" ]]; then
      echo "Usage: $0 search <pattern>" >&2
      exit 2
    fi
    rg --line-number --hidden \
      --glob '!node_modules/**' \
      --glob '!dist/**' \
      --glob '!build/**' \
      --glob '!coverage/**' \
      --glob '!*.lock' \
      -- "$argument" . | head -n 120 || true
    ;;
  changed)
    git diff --stat
    printf '\nChanged file names:\n'
    git diff --name-only | head -n 100
    ;;
  failures)
    if [[ -z "$argument" || ! -f "$argument" ]]; then
      echo "Usage: $0 failures <test-log-file>" >&2
      exit 2
    fi
    rg --line-number --context 3 \
      'FAIL|FAILED|ERROR|Error:|AssertionError|panic:' \
      "$argument" | head -n 160 || true
    ;;
  *)
    echo "Commands: status, search <pattern>, changed, failures <log>"
    ;;
esac
EOF
chmod +x tools/agent-context.sh

随后可以让代理优先运行这些窄查询:

./tools/agent-context.sh status
./tools/agent-context.sh search 'PaymentService'
./tools/agent-context.sh changed
./tools/agent-context.sh failures test-output.log

还可以在项目的代理说明文件中加入一条明确规则。例如 Claude Code 项目可采用类似约束:

## Context retrieval policy

- Start with `./tools/agent-context.sh status`.
- Use `search <pattern>` before opening files.
- Do not scan generated directories, dependencies, coverage output, or lock files.
- Read only the relevant line range unless the whole file is required.
- Run focused tests first; expand to the full suite only after the focused test passes.
- Summarize findings before requesting more repository context.

脚本里的行数上限需要按项目调整。限制过低会隐藏关键错误,限制过高则失去压缩上下文的意义。对于大型组织,更适合把脚本升级为结构化服务,返回 JSON 格式的服务元数据、代码位置、负责人、运行手册和依赖关系。

落地时要守住的边界

采用这类方案前,可以先记录一周基线:每个任务的输入 Token、工具调用次数、完成时间、重试次数和最终成功率。然后选择重复性高的任务,例如定位构建失败或查找服务负责人,逐步接入经过筛选的上下文工具。

还要检查三个风险:缓存信息是否过期,摘要是否遗漏关键细节,以及门户是否扩大了代理的数据访问权限。开发者门户能减少无效 I/O,但它不应该成为未经审计的“万能读权限”。

更合理的目标不是机械追求 90%,而是让代理先获得高密度的工程事实,再按需读取原始代码。Token 节省只是结果;更快定位问题、更少重复扫描和更可控的数据边界,才是这套方法长期有效的原因。


相关推荐