
2. 模型读取系统提示词、历史消息以及当前输入。
3. 模型判断是否需要调用工具。4. 工具返回结果,结果被追加到上下文中。
5. 模型基于新增结果继续规划下一步。6. 多轮执行,直到生成最终答案。
如果第 4 步返回的是完整日志、数据库查询结果,或者网页正文全文,那么下一轮请求往往会再次把这些内容发送给模型。即使每一轮新增内容看起来不多,累计后的上下文长度也会迅速膨胀。
可以用一个简单的近似公式描述输入 Token 的来源:
```text
输入 Token = 系统提示词 历史消息 工具结果 当前问题```
在多轮智能体任务中,历史消息与工具结果通常才是主要增长项。与此同时,总成本和响应延迟还会受到输出 Token、重试次数、并发量以及不同模型计费单价的影响。缺少调用级别的可观测记录时,团队通常很难准确判断到底是哪个环节造成了消耗失控。
二、先建立预算,而不是先做压缩
每次模型调用之前,都应该先设定明确的预算边界。预算至少应覆盖四个维度:上下文最大长度、单轮输出上限、单任务最大调用次数,以及单任务费用上限。
下面是一个与模型供应商无关的配置示例:
```yaml
agent:max_context_tokens: 12000
max_output_tokens: 1200max_tool_calls: 8
max_retries: 2max_cost_cents: 30
timeout_seconds: 40```
这些数值仅作为示例,不能直接视为任何模型的通用限制。实际配置需要结合模型上下文窗口、业务回答长度、工具返回规模以及价格表进行校准和测试。
程序应该在调用模型之前完成预算计算,而不是等到请求失败后再被动处理。对于无法精确统计 Token 的场景,可以优先使用目标模型对应的 Tokenizer;如果 SDK 没有提供,也至少要基于字符数或字节数设定保守阈值,避免上下文无限增长,影响大模型调用成本与响应性能。
三、用分层策略处理历史消息
历史消息管理不应该只有“全部保留”或“全部删除”两种极端策略。更适合生产环境的做法,是对上下文进行分层处理:
- 系统规则始终保留。
- 最近几轮用户问题和模型回答优先保留。- 已完成的工具调用只保留结论、时间和关键标识。
- 重复的工具结果只保留一次。- 更早的对话压缩成结构化摘要。
- 无法证明仍有价值的内容直接丢弃。摘要同样应该采用结构化形式,避免只是把一大段原始长文本替换成另一段同样冗长的自然语言。例如:```json{
"goal": "检查订单 20260807001 的支付状态","facts": [
"订单已创建","支付平台返回待确认"
],"constraints": [
"不能修改订单状态","需要用户确认后才能重试支付"
],"open_questions": [
"是否继续查询支付平台"]
}```
摘要必须清晰区分事实、约束条件与待确认事项。否则模型很容易把推测误当成事实,或者在后续执行步骤中忘记权限边界与业务限制。
四、工具结果要做裁剪和分页
工具返回的数据在进入模型上下文之前,应该先经过 Agent 适配层处理。不要把数据库全量记录、完整 HTTP 响应或调试日志原样交给模型,否则很容易造成 Token 激增。
例如,查询订单列表时,可以只返回必要字段,并限制结果数量:
```python
from typing import Anydef normalize_orders(rows: list[dict[str, Any]], limit: int = 20) -> dict[str, Any]:
items = []for row in rows[:limit]:
items.append({"id": row.get("id"),
"status": row.get("status"),"amount": row.get("amount"),
"created_at": row.get("created_at"),})
return {
"items": items,"returned": len(items),
"truncated": len(rows) > limit,}
````truncated` 这类字段非常重要。它可以明确告诉模型当前结果并不完整,模型就能进一步判断是否需要分页查询,而不是错误地以为列表只有这些记录。对于网页、日志、知识库文档这类工具结果,可以采用三步处理策略:先过滤明显无关的信息,再按字符数或 Token 数进行截断,最后保留来源标识和截断状态。截断最好发生在可信的业务边界内,例如按日志事件、自然段或记录切分,而不是简单地截断到任意字符位置。## 五、模型分层与失败降级并不是每一个步骤都需要同等能力、同等价格的大模型。更合理的方案,是把任务拆分为不同类型,再匹配不同模型:- 路由、分类、字段提取:优先使用成本更低、响应更快的模型。
- 多步规划、复杂归纳:使用能力更强的模型。
- 最终答案润色:根据业务要求选择普通模型,或直接使用模板输出。模型分层必须基于离线评估结果来决定,而不能只看价格。至少要持续记录这些关键指标:准确率、工具选择正确率、平均输入 Token、平均输出 Token、重试率,以及任务完成率。当模型调用失败时,降级策略同样要提前定义。常见顺序可以包括:缩短上下文、减少工具结果、切换备用模型、返回可解释的部分结果。每一步都要记录原因,避免系统表面上恢复了服务,实际上却悄悄降低了回答质量。在接入兼容常见聊天接口的模型服务时,建议将服务地址、模型名称和密钥全部做成配置项。HaerAPI 可作为需要评估的模型 API 接入选项之一,但具体接口格式、可用模型、限流规则以及数据处理方式,仍应以其当前官方文档为准。## 六、实现一个最小的预算守门器下面的代码展示了调用前检查和结果截断的基本结构。示例通过环境变量读取配置,不包含任何真实密钥:```pythonimport os
from dataclasses import dataclass@dataclass
class Budget:max_context_chars: int = 36000
max_output_tokens: int = 1200max_tool_calls: int = 8
def estimate_chars(messages: list[dict[str, str]]) -> int:return sum(len(message.get("content", "")) for message in messages)
def build_request(messages: list[dict[str, str]], budget: Budget) -> dict:size = estimate_chars(messages)
if size > budget.max_context_chars:raise ValueError(f"context budget exceeded: {size}")
return {
"model": os.environ["LLM_MODEL"],"messages": messages,
"max_tokens": budget.max_output_tokens,"temperature": 0.1,
}```
字符数并不是精确的 Token 数,尤其在中英文混合、代码片段和 JSON 数据场景下,误差可能会比较明显。因此在生产环境中,应替换为与实际模型对应的 Token 计算方法,并预留足够的安全余量。
调用日志建议至少包含以下字段:
```json
{"request_id": "内部生成的请求标识",
"task_id": "业务任务标识","model": "实际使用的模型名",
"input_tokens": 0,"output_tokens": 0,
"tool_calls": 0,"retry_count": 0,
"latency_ms": 0,"finish_reason": "stop"
}```
其中各项数值应由真实响应结果或本地计量结果填充,不能使用估算值冒充供应商账单数据。与此同时,密钥、完整用户文本以及敏感工具返回内容,也不应直接写入日志。
七、常见问题
### 1. 压缩历史后,Agent 变得不准确怎么办?
先检查摘要中是否保留了业务约束、权限范围、时间范围以及待确认事项。不要只按长度去压缩上下文;可以针对高风险字段建立结构化摘要,并在回归测试中比较压缩前后的任务完成率与准确率。
### 2. 是否应该把所有工具结果都缓存?
不能一概而论。静态文档和短期内不会变化的配置适合缓存;但订单状态、库存信息、权限数据等可能变化很快,缓存必须带有明确的过期策略或版本标识。缓存命中率也应纳入可观测指标体系。
### 3. 失败后重试会不会进一步增加成本?
会。重试之前应先区分超时、限流、参数错误和业务拒绝等不同类型。只有可恢复错误才适合重试,并应配合指数退避与最大次数限制。对于参数错误,重复发送相同请求通常没有实际意义,只会增加大模型费用。
### 4. 只降低 Token 就能解决费用问题吗?
不能。费用还会受到模型单价、并发规模、重试次数和任务总量等因素影响。一个上下文更短但反复失败的 Agent,可能比上下文略长但一次完成任务的 Agent 更昂贵。最终必须同时观察成本、延迟与质量,才能做出正确优化判断。
总结
Agent 的 Token 治理,本质上是一项运行时层面的系统工程,而不是简单修改几句提示词就能完成的表面优化。真正能够落地的做法,通常需要把以下几件事一起做好:先为上下文和任务设定清晰的预算边界;再按层级保留历史信息;对工具返回结果进行裁剪、分页和状态标记;根据任务复杂度设计模型分层;同时为失败场景预先准备可解释的降级路径;最后,还要通过调用级指标验证这些优化是否真的有效。
当这些机制被纳入统一的调用层后,Agent 成本控制问题才会从“感觉越来越贵”,变成一个可以定位、可以比较、也可以回归验证的工程化问题。
","createTime":1786084263,"ext":{"closeTextLink":0,"comment_ban":0,"description":"","focusRead":0},"fa vNum":0,"html":"","isOriginal":0,"likeNum":0,