GitHub 把 Agent CI 工作流的 Token 开销砍了 62%——三板斧拆解

2026-05-29 29 预计阅读时间:1 分钟
来源:infoq.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:11 分钟

Agent 工作流跑 CI,模型调用一多,Token 费用就悄悄失控。GitHub 工程团队最近公开了一组数据:通过修剪 MCP 工具、用 gh CLI 替代部分 MCP 调用、再加上每天自动跑"审计员"和"优化员"两个 Agent,他们把 agentic CI 流程的 Token 消耗压降了最多 62%。不是靠换便宜模型,而是靠让每次调用更"有效"。

下面拆解他们的做法,并给出可以直接拿来改造的脚本和配置。

第一斧:修剪 MCP 工具列表——少给就是省

MCP(Model Context Protocol)让 Agent 能调用外部工具,但问题在于:你往工具列表塞了 20 个能力,模型每次决策都要扫描一遍描述,哪怕最终只用了 2 个。这些"看了但没用"的 Token 就是纯浪费。

GitHub 的做法很直接——审计每个 MCP 工具的实际调用率,把长期零调用的直接删掉。这不是一次性动作,而是持续修剪:工具需求会随工作流演进变化,昨天有用的今天可能已经多余。

实际操作思路:

# mcp-config.json — 只保留工作流真正需要的工具
{
  "mcpServers": {
    "github": {
      "command": "mcp-server-github",
      "args": [],
      "tools": [
        # 精简到工作流实际使用的子集,而非全量暴露
        "search_repositories",
        "get_file_contents",
        "create_issue"
        # 删掉: list_all_repositories, get_user_profile, manage_labels ...
      ]
    }
  }
}

关键原则:工具描述本身也消耗 Token。一个 500 字的工具说明,如果模型 99% 的时候不会选它,那这 500 字就是每轮对话的白烧。修剪工具列表不是功能裁减,而是成本裁减。

第二斧:用 gh CLI 替代 MCP 调用——绕过协议开销

MCP 调用链路长:模型决策 → 协议协商 → 工具执行 → 结果回传。每一步都有 Token 开销,尤其是协议协商阶段的上下文注入。

GitHub 发现,很多操作用 gh CLI 一行命令就能搞定,根本不需要走 MCP。比如查 PR 状态、读文件内容、创建 Issue——这些 gh 本身就是为自动化设计的。

# 替代 MCP github.get_file_contents
gh api repos/{owner}/{repo}/contents/{path} --jq '.content' | base64 -d

# 替代 MCP github.list_pull_requests
gh pr list --repo {owner}/{repo} --state open --json number,title,author

# 替代 MCP github.create_issue
gh issue create --repo {owner}/{repo} \
  --title "Agent detected regression in token spend" \
  --body "See attached token-usage.jsonl for details."

在 Agent 工作流里,这类调用可以写成 shell 步骤直接嵌入 CI pipeline,模型只需要读命令输出,不需要先"理解工具描述→选择工具→构造调用参数"这条长路。Token 节省来自两处:省掉了工具选择的推理 Token,也省掉了协议层的上下文注入

当然,不是所有 MCP 调用都能替换。需要模型做复杂判断的场景(比如"这段代码变更是否引入了安全风险")仍然适合走 MCP,让模型拿到结构化上下文。但纯粹的 CRUD 式操作,CLI 更划算。

第三斧:每日审计 + 自动优化——用 Agent 管 Agent

最有趣的部分是 GitHub 用两个专用 Agent 来治理 Token 消耗:

  • Auditor Agent:每天扫描 Token 使用日志,标记异常飙升、无效调用、工具闲置。
  • Optimizer Agent:根据审计报告,自动建议(或执行)工具修剪、调用替换、参数精简。

这两个 Agent 本身也消耗 Token,但它们的目标是降低主工作流的长期成本——相当于花小钱省大钱。

核心数据载体是 token-usage.jsonl,每行记录一次模型调用的 Token 消耗明细:

{"timestamp":"2025-06-10T08:12:00Z","model":"gpt-4.1","prompt_tokens":3200,"completion_tokens":180,"tool_calls":["search_repositories"],"effective_tokens":2800,"workflow":"ci-review"}
{"timestamp":"2025-06-10T08:13:00Z","model":"gpt-4.1","prompt_tokens":5100,"completion_tokens":420,"tool_calls":["get_file_contents","list_all_repositories"],"effective_tokens":1200,"workflow":"ci-review"}

注意第二行的 effective_tokens 只有 1200——总消耗 5520 Token,但"有效"的只有 1200。差距来自哪里?list_all_repositories 被调用了但结果没被后续推理使用,加上它的工具描述被加载却未被选中。Effective Tokens = 模型输出中实际驱动了工作流下一步的 Token 数。这个指标比原始 Token 数更能反映真实效率。

下面是一个可以直接跑的分析脚本,帮你从 token-usage.jsonl 中算出效率比和问题点:

#!/usr/bin/env python3
"""token_auditor.py — 分析 token-usage.jsonl,输出效率报告"""

import json
import sys
from collections import defaultdict
from datetime import datetime

def analyze(path: str):
    records = []
    with open(path) as f:
        for line in f:
            line = line.strip()
            if line:
                records.append(json.loads(line))

    if not records:
        print("No records found.")
        return

    # 按工作流分组统计
    by_workflow = defaultdict(list)
    for r in records:
        by_workflow[r.get("workflow", "unknown")].append(r)

    print("=" * 60)
    print("TOKEN EFFICIENCY AUDIT REPORT")
    print(f"Generated: {datetime.now().isoformat()}")
    print("=" * 60)

    for wf, recs in by_workflow.items():
        total_prompt = sum(r["prompt_tokens"] for r in recs)
        total_completion = sum(r["completion_tokens"] for r in recs)
        total_effective = sum(r.get("effective_tokens", 0) for r in recs)
        total_raw = total_prompt + total_completion
        efficiency = total_effective / total_raw if total_raw else 0

        # 统计工具调用频次
        tool_counts = defaultdict(int)
        for r in recs:
            for t in r.get("tool_calls", []):
                tool_counts[t] += 1

        print(f"\n## Workflow: {wf}")
        print(f"   Calls:          {len(recs)}")
        print(f"   Raw tokens:     {total_raw}")
        print(f"   Effective:      {total_effective}")
        print(f"   Efficiency:     {efficiency:.1%}")
        print(f"   Waste:          {total_raw - total_effective} tokens")
        print(f"   Tool calls:")
        for tool, count in sorted(tool_counts.items(), key=lambda x: -x[1]):
            print(f"     - {tool}: {count}")

    # 全局低效调用标记
    print("\n## FLAGGED CALLS (efficiency < 20%)")
    for r in records:
        raw = r["prompt_tokens"] + r["completion_tokens"]
        eff = r.get("effective_tokens", 0)
        if raw and eff / raw < 0.2:
            print(f"   {r['timestamp']} | eff={eff}/{raw} ({eff/raw:.1%}) | tools={r.get('tool_calls', [])}")

if __name__ == "__main__":
    analyze(sys.argv[1] if len(sys.argv) > 1 else "token-usage.jsonl")

运行方式:

python3 token_auditor.py token-usage.jsonl

这个脚本会按工作流分组输出效率比,并标记效率低于 20% 的单次调用——这些就是你该优先修剪的目标。

把三板斧串成日常流程

GitHub 的做法不是一次性优化,而是日级别循环

  1. 主 Agent 工作流跑完,每次调用都往 token-usage.jsonl 写一行。
  2. Auditor Agent 每天定时跑 token_auditor.py(或其内部版本),生成报告。
  3. Optimizer Agent 读报告,决定:删哪个 MCP 工具、哪步该换 gh CLI、哪个工作流的 prompt 该精简。
  4. 变更落地后,第二天审计数据验证效果。

在 CI 里可以这样串起来:

# .github/workflows/agent-token-governance.yml
name: Agent Token Governance

on:
  schedule:
    - cron: '0 6 * * *'   # 每天 UTC 6:00 跑审计
  workflow_dispatch:        # 也支持手动触发

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Collect token-usage logs
        run: |
          # 从最近 24h 的 workflow runs 中聚合 token-usage.jsonl
          gh run list --repo ${{ github.repository }} \
            --created ">$(date -d '1 day ago' +%Y-%m-%d)" \
            --json databaseId --jq '.[].databaseId' | \
          while read id; do
            gh run download $id --repo ${{ github.repository }} \
              --name token-usage || true
          done
          cat token-usage*.jsonl > combined-usage.jsonl

      - name: Run token auditor
        run: python3 token_auditor.py combined-usage.jsonl > audit-report.md

      - name: Optimizer decides actions
        run: |
          # 这里可以接入 LLM 读取 audit-report.md 并输出优化建议
          # 简单版:自动标记效率 <30% 的 MCP 工具,生成修剪清单
          python3 optimizer_agent.py audit-report.md

      - name: Create optimization issue if needed
        run: |
          if [ -s optimization-actions.md ]; then
            gh issue create --repo ${{ github.repository }} \
              --title "Token optimization: $(date +%Y-%m-%d)" \
              --body-file optimization-actions.md
          fi

落地前想清楚几件事

  • 修剪 MCP 工具要留退路。今天没用的工具,下周新工作流可能需要。建议用"软删除"——配置里注释掉而非删掉,保留恢复路径。
  • gh CLI 替代有边界。需要模型做语义判断的操作(代码审查、风险评估)不适合硬编码成 shell 步骤,那些场景 MCP 的上下文注入反而更高效。
  • Effective Tokens 的定义要适配你的场景。GitHub 的定义是"驱动了工作流下一步的 Token",你需要根据自己的流程判定什么叫"有效"——是产生了文件变更?还是触发了后续步骤?定义不同,审计结论就不同。
  • 治理 Agent 本身也有成本。Auditor 和 Optimizer 每天跑,本身消耗 Token。如果主工作流规模很小(日均几十次调用),治理成本可能抵不掉节省。日调用量过百时,这套循环才明显划算。

GitHub 这组数据的核心启示:Agent 的 Token 成本不是只看模型单价,而是看每次调用的有效产出比。把"看了没用"的工具描述砍掉、把"绕了远路"的协议调用换成直连 CLI、再用 Agent 自动盯住效率指标——三步叠加,62% 的降幅不是魔法,是工程。


相关推荐