尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

任务跑一半,API 突然报“对话超长“断流:我给 Agent 修的紧急逃生通道

任务跑一半,API 突然报“对话超长“断流:我给 Agent 修的紧急逃生通道 本文是我开源项目 codeAgent终端 AI 编程智能体的系列第 2 篇每天讲一个里面真实用到的技术点全部附源码。仓库https://github.com/Harvil1/codeAgent场景最猝不及防的一种死法长任务跑到第 30 轮一个大工具结果塞进来下一轮请求直接被 API 拒了Error: prompt_too_long / maximum context length exceeded …此时最不能做的就是把异常抛给用户——前面 30 轮的工作全卡在半空。我的做法是修一条紧急逃生通道识别它 → 立刻瘦身 → 马上重发任务自己缓过来。第一关四家服务商四种报错措辞DeepSeek 说prompt_too_longOpenAI 说maximum context length还有context_length、too long各种变体。如果识别口径不统一OpenAI 风格的错误会走普通失败重试——白烧一次熔断次数。所以我全项目只认一个判定函数源码在agent/context_compressor.py# PTL 错误识别的统一口径四家服务商措辞全认。此前三处各写各的# 子集摘要重试认 2 种、主循环认 3 种、丢条数计算认 4 种——OpenAI# 风格的 maximum context length ... 在摘要重试路径会被当普通失败# 白计一次熔断还降级规则总结。全项目判定一律走 is_prompt_too_long_error_PTL_MARKERS(prompt_too_long,context_length,too long,maximum context,)defis_prompt_too_long_error(err_str:str)-bool:判断一段错误文本是不是「输入超长」PTL。四家措辞口径统一。s(err_stror).lower()returnany(kwinsforkwin_PTL_MARKERS)教训藏在注释里错误分类这类知识必须收敛到一处三个地方各写一个子集版本迟早有人只改一处。第二关紧急压缩函数核心源码识别出来之后立刻瘦身重发。做法简单粗暴只留 system 一条边界占位 最近 5 条消息其余的靠落盘的 transcript 快照找回。源码在agent/context_pipeline.py# 紧急压缩的两道保险默认值config 可覆盖冷却窗口秒数 / 单会话次数上限REACTIVE_COOLDOWN_SECONDS60REACTIVE_MAX_PER_SESSION5defreactive_compact(messages:list,*,session_state:CompressionSessionState,keep_recent:int5,cooldown_seconds:floatREACTIVE_COOLDOWN_SECONDS,max_per_session:intREACTIVE_MAX_PER_SESSION,now_fntime.time,)-Tuple[list,bool]:紧急通道API 报「对话超长」prompt_too_long时立刻调用。 做法简单粗暴只留 system 一条说明占位 最后 keep_recent 条消息 其余全靠 transcript 文件找回。 **可多次触发**每次报错都可以再压但有两道保险 1. 冷却窗口距上次触发不足 cooldown_seconds 秒默认 60s→ 跳过 2. 单会话上限本场已触发 max_per_session 次默认 5→ 跳过 # 保护 1冷却窗口nownow_fn()elapsednow-session_state.reactive_last_atifsession_state.reactive_count0andelapsedcooldown_seconds:logger.info(reactive_compact 冷却中距上次 %ds %ds跳过,int(elapsed),int(cooldown_seconds),)returnmessages,False# 保护 2单会话上限ifsession_state.reactive_countmax_per_session:logger.warning(reactive_compact 达到单会话上限 %d 次跳过,session_state.reactive_count,)returnmessages,Falsesystem,conv_split_system(messages)keepconv[-keep_recent:]iflen(conv)keep_recentelseconv[:]placeholder{role:user,content:(# 边界前缀和大写统一恢复侧 _truncate_at_last_compact_boundary# 只认 [COMPACT_BOUNDARY] 开头reactive 的占位也得能被裁剪定位[COMPACT_BOUNDARY]\n[紧急上下文压缩API 返回 prompt_too_longf已只保留最近{len(keep)}条消息。如 .transcripts/ 下有快照latest.txt 指向最新一份可 read_file 分段找回无快照则被裁原文已不可恢复]),}new_conv[placeholder]keep new_conv_fix_tool_call_pairs(new_conv)new_messages_reassemble(system,new_conv)session_state.reactive_last_atnow session_state.reactive_count1returnnew_messages,True这 60 行里藏了四个细节1. 为什么允许触发 5 次而不是 1 次砍到只剩 5 条后下一轮又来一个巨型工具结果还会再超——所以留了多次触发的余地。但必须有冷却窗口60 秒 次数上限5 次两道闸否则会陷入压了又超、超了又压的死亡循环日志和账单一起爆炸。2. 占位消息以[COMPACT_BOUNDARY]开头。会话恢复时只认这个前缀来定位历史上次压到哪紧急压缩和常规压缩共用同一套边界标记——逃生通道也得上户口不然恢复逻辑找不到断点。3._fix_tool_call_pairs不能省。从中间砍消息很容易把模型要调工具和工具结果切成两半——孤儿 tool_call 会让下一次请求直接被 API 拒掉400。砍完必须对账补配。4. 被砍的内容给了一条活路。压缩前完整对话已落盘.transcripts/占位消息里明确告诉模型可以去读快照找回上下文。丢的是上下文窗口里的位置不是信息本身。小结三句话带走错误识别统一口径四家服务商措辞全收进一个函数全项目只认它紧急压缩 保 system 边界占位 最近 5 条立刻重发不断线两道保险冷却 60s / 上限 5 次防死亡循环砍完修 tool_call 配对下一篇讲它的上游四级上下文压缩怎么分层——目标是让任务压根走不到报超长这一步照样附源码。仓库在这注释全中文欢迎 Star ⭐https://github.com/Harvil1/codeAgent
返回列表