事情本身不复杂,线索都在日志里。Agent 每轮把工具返回的完整 JSON 原样塞回消息列表,第三轮就报 context_length_exceeded,原文 maximum context length is 128000 tokens,单条工具结果接近 12KB。
第一反应是「JSON 带缩进和冗余字段,token 数被放大」,验证下来不成立。
原因不止一个,得分开看。工具结果全量回填,没有做字段裁剪。还有一种是每轮保留全部历史工具输出,重复计入。
不容易想到的是,失败重试时把上一次的完整结果又追加一遍。
量出每条工具结果的实际 token 数
python -c "import json,tiktoken;e=tiktoken.get_encoding('cl100k_base');print(len(e.encode(json.dumps(json.load(open('tool.json'))))))"
只保留模型需要的字段并去掉缩进
python slim_tool.py --src tool.json --keep id,status,items --compact
接着在消息列表里用摘要替换历史工具原文
python compact_history.py --session s123 --keep-last 2
给工具结果设长度上限,超限时截断并标注
python agent.py --max-tool-chars 2000 --trace
恢复的判定其实很直接。第三轮请求的输入 token 稳定在 2 万以内,模型仍能正确引用工具结果里的关键字段,不再出现上下文超限。
这里还有个坑。工具输出是上下文膨胀最快的来源,回填前先裁剪字段,历史轮次只留摘要,能省下大部分预算。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
