Agent 越用越贵?四招把 Token 账单砍下来

本周技术圈热议关键词:AI Agent 从「能跑」走向「看得见、管得住、花得起」。
模型单价在降,可很多人的月账单却在涨——今天用四个可落地的小技巧,帮你把 Agent 成本压住。


写在前面

最近刷 CSDN、技术公众号,你会发现一个有意思的现象:

  • 一边是 开源大模型、Agent 工具链 更新飞快;
  • 另一边是企业开始认真谈 预算告警、组织级限额、按团队控成本

行业正在从「先跑通 Demo」切到「上线后能不能花得起」。

很多团队踩过同一个坑:

Token 单价降了 10 倍,Agent 总账单却涨了 5 倍。

原因通常不是模型「变贵了」,而是 Agent 会多轮调用、反复读上下文、子任务并行跑——用量暴增把单价红利吃光了

下面四招,都是工程侧立刻能改的,不依赖某家特定模型。


第一招:别让「长上下文」成为默认税

Agent 最常见的浪费,是把整份文档、整段对话历史,每次都原样塞进 Prompt。

反例:每次全量塞历史

# ❌ 每次请求都把完整历史塞进去
def build_prompt(history: list[str], question: str) -> str:
    return "\n".join(history) + f"\n用户问题:{question}"

对话一长,输入 Token 就会线性膨胀。

正例:滑动窗口 + 摘要

from typing import List

def summarize_old_turns(turns: List[str]) -> str:
    """把较早轮次压成摘要(可用小模型或规则摘要)"""
    joined = " | ".join(turns)
    # 生产环境可换成小模型摘要接口
    return f"[历史摘要] {joined[:200]}..."

def build_prompt_with_window(
    history: List[str],
    question: str,
    keep_recent: int = 6,
) -> str:
    if len(history) <= keep_recent:
        context = "\n".join(history)
    else:
        old = history[:-keep_recent]
        recent = history[-keep_recent:]
        context = summarize_old_turns(old) + "\n" + "\n".join(recent)

    return f"{context}\n\n用户问题:{question}"

原则:最近几轮保留原文,更早内容压缩成摘要。多数业务对话质量几乎不受影响,输入成本却能明显下降。


第二招:能缓存就缓存(尤其是系统提示和知识块)

很多厂商已经支持 Prompt Caching / 上下文缓存:不变的系统提示、工具说明、知识库片段,命中缓存后输入价往往大幅降低。

示例:把「稳定前缀」和「变化后缀」拆开

SYSTEM_PROMPT = """
你是公司内部的工单助手。
规则:
1. 只基于给定知识回答
2. 不确定时明确说不知道
3. 输出简洁中文
""".strip()

TOOLS_SPEC = """
可用工具:
- search_kb(query): 检索知识库
- create_ticket(title, body): 创建工单
""".strip()

def make_messages(user_question: str, kb_chunk: str) -> list[dict]:
    # 稳定前缀放前面,便于缓存命中
    stable_prefix = f"{SYSTEM_PROMPT}\n\n{TOOLS_SPEC}\n\n知识片段:\n{kb_chunk}"
    return [
        {"role": "system", "content": stable_prefix},
        {"role": "user", "content": user_question},
    ]

落地建议:

  1. 系统提示、工具定义、固定知识 尽量保持字节级稳定;
  2. 把每次变化的用户问题放在后面;
  3. 监控缓存命中率——命中率上不去,优先检查「前缀是否被频繁改动」。

提示:不同平台的缓存字段名、TTL、计费规则不同,接入前请以官方文档为准。


第三招:简单题别开「满血推理」

本周不少文章都在谈「思考力度可调」:简单路由用轻量模式,复杂任务再拉满。

即使你用的平台没有显式「思考档位」,也可以自己做 模型路由

示例:按任务难度分流

import re

LIGHT_MODEL = "small-fast-model"   # 便宜、够用
HEAVY_MODEL = "large-reason-model" # 贵、更强

HARD_PATTERNS = [
    r"重构",
    r"架构",
    r"根因分析",
    r"对比.*方案",
    r"写.*设计文档",
]

def pick_model(user_input: str) -> str:
    text = user_input.strip()
    if len(text) < 20 and not any(re.search(p, text) for p in HARD_PATTERNS):
        return LIGHT_MODEL
    if any(re.search(p, text) for p in HARD_PATTERNS):
        return HEAVY_MODEL
    # 默认走轻量,必要时再升级
    return LIGHT_MODEL


def run_agent(user_input: str) -> dict:
    model = pick_model(user_input)
    # call_llm 换成你的实际调用封装
    answer = call_llm(model=model, prompt=user_input)
    return {"model": model, "answer": answer}

经验法则:

  • FAQ、格式转换、摘要 → 小模型;
  • 多步推理、跨文件改代码、复杂排障 → 大模型;
  • 先便宜后升级:小模型不确定时,再 escalate 到大模型。

这样通常比「全程旗舰模型」更省,且体感不一定更差。


第四招:给 Agent 装「预算熔断器」

企业侧本周讨论很热:支出阈值预警、按组织/用户设上限、程序化切断。

个人项目或小团队同样适用——别等月底账单出来才后悔。

示例:请求前估算 + 超预算熔断

from dataclasses import dataclass

@dataclass
class BudgetGuard:
    daily_limit_cny: float
    spent_cny: float = 0.0

    # 粗略单价:按你实际账单校准
    input_price_per_1k: float = 0.002
    output_price_per_1k: float = 0.01

    def estimate_cost(self, input_tokens: int, output_tokens: int) -> float:
        return (
            input_tokens / 1000 * self.input_price_per_1k
            + output_tokens / 1000 * self.output_price_per_1k
        )

    def allow(self, input_tokens: int, expected_output_tokens: int = 800) -> bool:
        estimate = self.estimate_cost(input_tokens, expected_output_tokens)
        return self.spent_cny + estimate <= self.daily_limit_cny

    def commit(self, input_tokens: int, output_tokens: int) -> None:
        self.spent_cny += self.estimate_cost(input_tokens, output_tokens)


guard = BudgetGuard(daily_limit_cny=30.0)

def safe_call(prompt: str) -> str:
    input_tokens = max(1, len(prompt) // 2)  # 粗估,生产请用官方 tokenizer
    if not guard.allow(input_tokens):
        return "今日预算已用尽,请明天再试或提高限额。"

    result = call_llm(prompt=prompt)  # 返回文本
    output_tokens = max(1, len(result) // 2)
    guard.commit(input_tokens, output_tokens)
    return result

再补两条运维习惯:

  1. 按任务类型记账:检索、写作、改代码分开看,哪类最烧钱一目了然;
  2. 限制最大步数:Agent 循环设 max_steps,防止工具调用空转烧 Token。
MAX_STEPS = 8

def agent_loop(goal: str) -> str:
    state = {"goal": goal, "scratch": []}
    for step in range(MAX_STEPS):
        action = plan_next_action(state)
        if action["type"] == "finish":
            return action["result"]
        state["scratch"].append(execute(action))
    return "已达最大步数,请缩小任务范围后重试。"

一张表记住四招

招数 解决什么浪费 立刻可做的动作
上下文窗口化 历史越聊越贵 最近 N 轮原文 + 旧内容摘要
Prompt 缓存 重复系统提示被反复计费 稳定前缀前置,监控命中率
模型路由 简单题用旗舰模型 难易分流,先小后大
预算熔断 月末账单失控 日限额 + max_steps + 分任务记账

写给团队的落地清单(今晚就能开)

  1. 给 Agent 加上 max_steps 和每日预算;
  2. 把系统提示、工具定义固定下来,打开缓存;
  3. 统计一周内「各模型调用占比」和「平均每任务 Token」;
  4. 先把 FAQ / 摘要类流量切到小模型,观察质量是否可接受;
  5. 周会只看三个数:成功率、单次成本、缓存命中率

当你能稳定回答「这个 Agent 每次对话大概花多少钱」时,才算真正进入可运营阶段。


结语

2026 年下半年,Agent 竞争不再只比谁更会聊,而是比谁更能在可控成本下稳定交付。

单价会继续波动,但工程方法是可复用的:

少传、能缓存、会分流、敢熔断。

如果你正在把内部助手、客服 Bot、研发 Agent 往生产推,不妨先从「成本可观测」做起——比再换一个更贵的模型,往往更划算。


声明:文中价格、缓存策略、模型能力会随厂商更新变化,示例代码仅供学习与改造参考,请以各平台最新官方文档为准。欢迎在评论区交流你的控本实践。


(完)

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐