site logo

Marico's space

Token 预算下的分诊 Agent:免费层工具调用统计案例研究

编程技术 2026-08-25 17:35:48 9

上个月参与维护的一个开源项目,一周之内涌进来 40 个 issue。手工分类花了四个小时:读内容、打标签、定优先级、回复。动念头想上个 Agent 帮我做第一轮筛选。问题是:项目没钱买云资源,没 GPU,也没有任何 AI 预算。

零预算不是口号,是硬约束。

背景

这个仓库收到的 issue 包括 bug 报告、功能需求、环境配置问题各种混在一起。大部分 issue 篇幅不长,但有些会带上一堆堆堆栈日志。工作量波动很大:有时候好几天没动静,有时候一觉醒来堆了 10 个。

常规思路是上托管式 Agent 平台。常规思路也是要花钱的。我给自己定了个不同的约束:MonkeyCode 的免费模型访问加上免费服务器。提前说明:这篇东西是 MonkeyCode 产品推广的一部分。MonkeyCode 是个开源项目,写稿时宣传的是一千万 Token 免费额度加免费服务器。具体限制会变,用之前去项目文档里核实一下。

仓库细节只是具体案例。可复用的是那套 harness 和记账方法。

目标

动手写 Agent 代码之前,我先定了三条成功标准:

  1. 每周能在 Token 额度内处理 50 个 issue。
  2. 对 30 个已标注的 issue 集合,标注准确率至少 85%。
  3. 跑在免费服务器上无人值守,用定时任务每晚执行。

第四条隐含标准才是真正重要的:搞清楚每一个 Token 花哪儿去了。

实现

Agent 设计

这个 Agent 有三个工具加一道护栏:

  • list_issues — 拉取 open 状态的 issue,每次一页。
  • get_issue — 拉取单个 issue 的完整内容。
  • classify — 返回标签、置信度分数和草稿回复。
  • 护栏:每个 issue 最多 5 次工具调用,在循环里强制执行。

每次工具调用都在 Agent 继续之前记录日志。这个日志记录机制才是本文真正要说的东西。

预算账本

核心 harness 来了。每次工具调用记录一行 JSON(JSONL)格式的数据:

# tool_budget_ledger.py
import json
from dataclasses import dataclass, asdict @dataclass
class ToolCall: ts: float agent_step: int tool: str input_tokens: int output_tokens: int status: str # ok | error | skipped
 latency_ms: int def append_call(run_id: str, call: ToolCall) -> None: path = f"ledgers/{run_id}.jsonl" with open(path, "a", encoding="utf-8") as f: f.write(json.dumps(asdict(call)) + "\n")

统计器把账本转成按工具分项的成本表:

def summarize(run_id: str) -> dict: totals = {} with open(f"ledgers/{run_id}.jsonl", encoding="utf-8") as f: for line in f: c = json.loads(line) t = totals.setdefault( c["tool"], {"calls": 0, "input": 0, "output": 0, "errors": 0}, ) t["calls"] += 1 t["input"] += c["input_tokens"] t["output"] += c["output_tokens"] t["errors"] += int(c["status"] == "error") return totals

预算护栏放在循环里,不放在钱包里:

BUDGET = 10_000_000 # free-tier allowance, operator-reported; verify in docs
RESERVE = 0.8 # stop at 80% to leave headroom

def within_budget(spent: int) -> bool: return spent < BUDGET * RESERVE

故意设得保守一点。跑到 80% 就停虽然有点烦,但跑到 100% 半途停下导致 20 个 issue 没分类、还没额度补救,那才是真麻烦。

Token 到底花哪儿了

用合成数据跑了个 10 个 issue 的试点来验证 harness,数据准确之后才动真格额度。下面的数字是示意性的,记账逻辑跟 harness 记录任何 provider 的方式完全一致。

工具 调用次数 输入 Token 输出 Token 占比
list_issues 6 4,200 900 6%
get_issue 10 61,400 1,800 74%
classify 10 9,800 2,100 14%
post_comment 4 3,100 800 6%

结论非常明显。get_issue 吃掉了 74% 的预算,根本原因是工具调用 Agent 的一个天然特性:工具返回结果会在后续每一步重新发给模型。一个两千 Token 的 issue 主体,模型第一次看到花两千,第二次看到又花两千,第三次还是两千。

这张表催生了三个改进:

  1. 每个 issue 主体只拉取一次,缓存在运行上下文里。
  2. 分类时把主体截到前 800 字符,堆栈日志基本不影响标签结果。
  3. get_issueclassify 合并成一步,主体只发一次。

改完试点跑下来,每个 issue 的成本降了大概一半,估算的周消耗稳稳落在额度范围内。

决策表

这套路子不是万能的。下面是我用来判断免费层分诊 Agent 适不适用的表格:

工作负载 免费层适用性 原因
每周少于 200 个 issue,主体小于 1k Token 适用 额度够用,还有余量
夜间批量分诊 适用 定时任务友好,不介意延迟
长文档审核(50k Token 文件) 不适用 一个文件就能把额度吃掉大半
2 秒内实时响应 不适用 免费服务器冷启动跟 SLA 合不来
合规敏感数据 不适用 送出去之前先核实数据处理方式

经验总结

  1. 先测量再优化。 账本显示成本大户是工具结果重发,不是模型调用本身。不看这个按工具分项的表,我肯定会甩锅给模型然后换 provider,白折腾。
  2. 预算上限要放在循环里。 在额度的 80% 硬停,把潜在的账单惊吓变成可计划的透明事件。
  3. 免费层是设计约束,不是障碍。 一千万 Token 限制逼出了截断、缓存、单遍设计。Agent 变得更简单更便宜,测试也更容易。
  4. 日志要全量记录,试点阶段也一样。 合成数据跑一遍不花额度,却提前暴露了 74% 的问题,没让它碰到真额度。

谁不该用这个

对延迟有 SLA 要求、合规限制严格、或者文档量大的工作负载,不应该在免费服务器加 Token 额度上建生产系统。那种场景下 harness 还是有用的,但用途是作为测量工具,不是生产平台。先测量,再决定该为什么付钱。

自己跑一遍

harness 大概 120 行代码,一个文件搞定。想搞清楚自己的 Agent Token 到底花哪儿去了,先把账本搭起来,别急着换更大的模型。MonkeyCode 免费层是个跑这个实验的合理起点,项目文档里有最新的限制说明。跑试点、读表格,让数字说话。