自建 Agent 用 create_tool_calling_agent,工具查库返回整张表 JSON 共 6 万字符,第二轮就报 context_length_exceeded,模型是 gpt-4o-mini 的 128k 窗口。
真正麻烦的地方在于,几个原因的现象几乎一样。工具返回值原样进消息历史,没有任何长度控制;多轮里每条历史都带着旧的大结果,累积远超单次;历史裁剪只按条数删,没按 token 删;工具本身没分页,一次查全表。
量工具返回的 token 规模
python -c "import tiktoken;e=tiktoken.get_encoding('cl100k_base');print(len(e.encode(open('tool_out.json',encoding='utf-8').read())))"
然后在工具里加 limit 和字段裁剪
python -c "print({'rows':[],'total':0,'truncated':True})"
给历史加 token 上限的裁剪
python -c "from langchain_core.messages import trim_messages;print(trim_messages([],max_tokens=6000,token_counter=lambda m:0,strategy='last'))"
复现一次完整调用看请求体大小
python -c "import json;print(len(json.dumps({'messages':[]})))"
改之前我把相关日志按时间截了一段存着,事后对时间线用得上。
中途换过一次思路,把范围缩到最小的那一层,反而快了。
恢复的判定其实很直接。第二轮请求的 prompt_tokens 稳定在 8000 以内,工具返回体带 truncated 标记,Agent 仍能给出结论而不是报超限。
提醒一点。裁剪历史时别把工具调用与结果拆开,成对删掉才不会被服务端判成格式错误。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
