Spotify工程团队通过Portal(内置提示词优化+上下文压缩层)将Claude Code单次任务Token消耗降低90%。
大多数情况下,AI 编程 agent 为我做的事情并不是在「思考」,而是在做 I/O。
读五个文件只是为了回答一个方法的问题。生成一个测试文件,其模式与旁边二十个测试文件完全一致。会后更新文档。成千上万的 token 消耗,几乎零推理。座位许可证并不是痛点,token 才是。而且你把这一切都喂给了一个 frontier model,它的能力远远超出任务所需。如果能把这些苦活脏活路由到更便宜的模型来处理,节省下昂贵的模型用于真正需要它的问题上呢?
这显然不是我一个人的问题。到 2028 年,AI 编程成本预计将超过普通开发者的薪资。四分之一的工程负责人已经在每个开发者身上燃烧 $200–$500/月的 token。有些已经超过 $2,000。工具本身是值得的,但前提是你得停止在不需要 frontier token 的工作上浪费它们。
事实证明,修复不需要平台团队或新订阅,只需要两种模式。
这正是 Portal by Spotify 中的 AiKA Modes 的用武之地。模式(mode)是一个声明式的 agent,运行在短暂的运行时上——可以理解为 AWS Lambda,不过是给 agent 用的。你定义指令,选择模型,设置 temperature 等参数,附加 MCP 工具。Portal 处理其余一切。无需管理 infra,无需 API key,无需长期运行的服务器。模式可以通过 Portal CLI 或 API 调用,可以是公开的(公司内共享)或私有的。
为了让这个路由工作,我创建了两个模式。下面的示例都使用 Gemini 2.5 Flash 作为 worker 模型,但 model 字段接受你在 Portal 实例中配置的任何模型。选择适合你的即可。
用于当 Claude 原本需要读取多个大文件只是为了回答一个问题时。
name: bulk-reader
description: Bulk file reader for code analysis - delegates I/O from Claude Code
instructions: You are a precise code analyst. Read the provided files and answer the question concisely. Output structured bullets only. No greetings, no prose, no preambles. Lead every bullet with the exact name, type, or line number. Use nested bullets for details. Skip anything the caller did not ask for.
visibility: public
model: gemini-2.5-flash
resourceLimits:
temperature: 0.2
tags:
- coding
- delegation
用于测试、配置脚手架、类型存根,或任何输出可以从现有模式预测的场景。
name: code-writer
description: Boilerplate code generator - delegates output-heavy work from Claude Code
instructions: You generate code files based on a spec and reference files. Match the existing patterns, conventions, naming, and style exactly. Output only the code — no explanations, no markdown fences unless asked. If the spec is ambiguous, make reasonable choices that match the reference code's patterns.
visibility: public
model: gemini-2.5-flash
resourceLimits:
temperature: 0.2
tags:
- coding
- delegation
「Output only the code」这条指令很重要。没有它,模型会把所有东西都用 markdown 围栏和解释性散文包裹起来,然后 Claude 必须费力解析这些内容。
最初版本是 CLAUDE.md 中的一组路由规则。它有一定效果:Claude 会读取指令并自我路由到 Portal。但它有问题。这些规则是建议性的,不是强制性的。Claude 可以忽略它们。而且每个项目都需要自己的一份指令副本。
当前版本是一个名为 shunt 的 Claude Code 插件。委托通过 Portal CLI 的 actions 注册表进行,因此该插件可以对接任何启用了 AiKA 插件的 Portal 实例。
Claude Code hooks 在每次工具调用前触发。Shunt 注册了两个 PreToolUse hooks:
check-file-size 对每个 Read 调用触发。如果文件超过可配置的行列阈值(默认:350),hook 会阻止读取,并告诉 Claude 改用 /bulk-reader skill。定向读取会直接通过——Claude 本身已经知道它需要哪部分内容。
check-bash-read 捕获 cat、head、tail、less 和 more 对大文件的操作。管道命令(如 cat file | grep)会直接通过,因为那些是定向读取。
阈值可以通过 SHUNT_MIN_LINES 环境变量配置。在 shell 配置文件或 .claude/settings.json 中设置:
{
"env": {
"SHUNT_MIN_LINES": "500"
}
}
我有两个 bash 脚本封装了 Portal CLI 调用。Claude 通过命名参数调用脚本。脚本在内部处理一切:构建请求、调用 actions、展开错误、并向 stderr 报告 token 使用情况。
模式通过名称寻址,由 Portal 解析:不区分大小写,优先使用你自己的模式,然后是团队的和公开的。把公开的 bulk-reader fork 成定制版本,你的版本自动获得优先权——无需任何配置。
bulk-read 将每个文件包裹在 XML 标签中以形成清晰边界,连同问题一起发送给 bulk-reader 模式。
bulk-read --question "What does this service do?" --paths src/Service.java src/Handler.java
# Follow-up: ask again with the same paths
bulk-read --question "Which methods call the database?" --paths src/Service.java src/Handler.java
每次委托都是一次性的。调用是短暂的(服务器端不存储任何内容),重新发送文件到后续问题时在关键处是免费的,因为语料库发送给 worker 模型,从不进入 Claude 的上下文。
code-write 将 spec 和参考文件发送到 code-writer 模式,从输出中剥离 markdown 围栏,可以直接写入磁盘。Claude 从不看到生成的代码。参考文件是必需的:没有文件来匹配模式,worker 会生成与项目中任何内容都不契合的上下文无关代码。
code-write --spec "Write tests for UserService" --reference tests/OrderTest.java --target tests/UserTest.java
# Output to stdout
code-write --spec "Generate a config stub" --reference config/existing.yaml
两个 skill 文件告诉 Claude 何时以及如何调用脚本。Skills 是包含描述和使用示例的 markdown 文件。当 hook 阻止读取时,阻止消息会指向 /bulk-reader skill,其中展示了精确的调用语法。
这种分层设计意味着系统可以优雅降级。即使 Claude 没有读取 skill 描述,hook 仍然会阻止昂贵的读取。skill 只是让重定向更顺畅。
在 Java monorepo 中针对四种场景进行了测试,测量 Claude 直接读取文件与通过 bulk-reader 摘要或通过 code-writer 写代码所消耗的 token。平均 bulk-read 节省约 90%。
code-write 场景的 token 测量更难,因为没有 shunt 时,Claude 既读取参考文件又生成输出作为昂贵的 output token。有了 shunt,代码直接写入磁盘,Claude 从不看到它。
你无法委托编辑。worker 模型的摘要不包含可靠的行号。如果 Claude 需要根据分析进行编辑,它仍然必须直接读取特定部分。hooks 正是出于这个原因允许定向读取(带 offset/limit),所以委托在理解阶段节省 token。
你无法委托推理。worker 模型在测试中发现了表面层面的模式,但漏掉了一个微妙的线程安全问题。Claude 一旦获得正确上下文,在几秒钟内就发现了它。路由明确排除了调试、架构决策和安全关键代码。
延迟会累积。每次委托都是一个网络往返:Claude Code → Portal 后端 → worker 模型 → 返回。响应通常需要 10–30 秒,Portal 单次调用上限为 30 秒,所以非常大的生成需要拆分成更小的调用。这对大文件读取是可以接受的,但对小文件来说适得其反。行阈值存在正是出于这个原因——低于阈值时,委托的开销超过节省。
Token 节省只是起点
这个插件是 Claude Code 的产物,但背后的理念是由 AiKA modes 驱动的模型路由。模式才是承重的那一层:
它们是可复用的。同一个 bulk-reader 和 code-writer 模式适用于每个项目和每个能执行 Portal CLI 的工具。
它们是可共享的。两个模式在 AiKA 中都是公开的。任何人都可以直接使用,无需自己创建。
它们是可组合的。你可以创建一个 doc-writer 模式来处理文档、reviewer 模式来生成代码审查摘要、translator 模式来做 i18n。每一个都只需几次点击即可实现。
它们将路由决策与 worker 解耦。插件决定何时委托。模式决定如何响应。切换 Gemini Flash 到更便宜的模型、修改 system prompt、添加 MCP 工具——插件本身无需改变。
这才是 AiKA Modes 的真正力量:它把模型路由从系统工程问题变成了配置问题。你不需要构建基础设施。你只需要描述你想要什么,然后给它起个名字。
从 spotify/portal-ai-plugins 市场安装两个插件:
claude plugin marketplace add spotify/portal-ai-plugins
claude plugin install portal@portal
claude plugin install shunt@portal
portal 插件提供了 shunt 所依赖的 Portal CLI。
在新的 Claude Code 会话中,运行 /portal:setup 来设置并验证 Portal CLI 对你的 Portal 实例的认证。
设置完成,你就可以提问跨越多个文件的问题了。
bulk-reader 和 code-writer 模式已经是公开的,所以无需创建。如果你想定制它们——使用不同的 worker 模型、不同的指令——在 Portal 中 fork 它们,你的版本会自动获得优先权。
这些模式可以在项目间复用,可以与团队共享。插件强制执行路由,所以你无需刻意去想它。了解更多关于 modes 的信息。