
前段时间我把 Pi Agent 正式接到日常编码流程里连着用了两周最大的感受是会话一旦越过某个长度它就开始肉眼可见地“变傻”。明明前面说过不要动某个接口到了第 40 轮它偏偏动了刚修完的 bug再问一次又给出了原来的错解。起初我以为是模型不行后来把会话历史导出来一段段看才发现问题出在我自己身上——我只知道一个劲地往同一个会话里追加任务却从来没有管理过这个会话的长度和结构。写这篇文章就是想从一个真实使用者的角度把你早晚也会遇到的“会话越长越难用”这件事讲透从原理到实操再到我踩过的坑一次说清。1. 会话为什么会越聊越长问题出在哪1.1 上下文窗口不是无限大的先说概念。Agent 收到你每一条新消息时不是孤立地处理这一句而是把过去所有的对话内容都重新“读”一遍再结合当前问题给出回答。这个“能重新读到的范围”就是上下文窗口单位是 token你可以把它理解成一张工作台。每次交办新任务你相当于把过去几个小时的全部聊天记录放在这张工作台上让它看着所有材料干活。工作台面积是固定的。不同工具的上下文窗口从几万 token 到上百万 token 不等听起来很大但编码类任务格外“吃”空间一段 50 行的代码可能就有 600 到 1000 个 token一个完整报错日志动辄几千 token一次 diff 改动又能吞掉一大块。我实测下来一个中等复杂的重构任务聊到 30 轮左右光历史记录就能把 128K 的窗口占掉七成。这时候如果再贴一段新代码进去最早的部分就会被系统强制“丢出”工作台或者干脆提示你超出上限。“越聊越长”本质上不是使用习惯问题而是物理上限问题。你不可能让模型记住无限长的历史就像你不能让一个同事同时记住三周前会议上说的每一句话。但很多人没有意识到当窗口快满的时候真正被扔掉的往往不是琐碎寒暄而是你最早就定好的约束条件——比如“不要改数据库结构”“接口路径保持原样”“密码不许出现明文”。这些恰恰是任务最初期说过的也是最容易被挤出窗口的。1.2 每多一轮成本都在涨长会话的代价不只是“变笨”还有实打实的资源开销。大模型按 token 计费每次请求都需要把当前窗口内的全部历史重新计算一遍而不是只算新增内容。这就导致一个反直觉的结论会话越长每问一句话的单价就越高。我举个例子。假设某次任务启动时初始上下文是 3000 token每轮对话平均新增 800 token。第 10 轮时一次请求的输入量大约是 3000 加 800 乘 10也就是 11000 token 左右到第 50 轮时单次输入已经涨到 43000 token。问题是 Agent 回答一个问题往往不止请求一次思考、调工具、生成回复都可能各算一次。算总账的话整体消耗会随轮数近似呈二次方上升而且响应延迟也跟着一起涨。有个很直观的现象可以检验这一点同一个问题在对话刚开头问一两秒就能看到回复开头聊到一小时后同样的响应可能要等上一阵子。这就是因为每次请求都要带着越来越庞大的历史“跑一遍”。很多朋友说 Agent 开销大其实一半的 token 钱都花在了反复搬运旧对话上而不是花在真正解决新问题上。所以学会给会话“减重”不只是为了让 Agent 更聪明更是为了别把钱和耐心一起烧掉。1.3 “越聊越笨”不是错觉是注意力被摊薄了模型处理长文本时注意力是有限的文本越长分布在每个 token 上的注意力就越稀薄。换句话说不是模型变笨了而是它的“注意力预算”被大量历史内容瓜分掉了早期关键指令自然就得不到足够的权重。这个现象我遇到过很多次。有一回我让 Pi Agent 修改一个登录模块明确要求“保持现有异常响应格式”。第 5 轮它还照着做到了第 30 轮再让它顺便补一个日志它竟然把整个响应结构都改了。我回翻记录发现后面十几轮里它已经因各种原因多次偏离原始要求而最早的那句约束早已被淹没在大量代码片段和报错信息里。长会话还会带来“上下文污染”。对话中的错误信息、试错过程、半成品代码都会以同样的权重留在历史里。模型分不清哪些是已经废弃的旧方案哪些是正在生效的新决定最后经常出现“从错误代码里学坏”的情况。你会发现它突然用了一个前面已经被你否掉的写法原因很简单那条被否定的历史也在上下文里而且权重未必比正确结论低。2. 会话管理的底层思路别把记忆全压在聊天记录里2.1 把结论沉淀到对话之外想明白问题根源之后我调整的第一个思路是会话只负责“过程”不负责“记忆”。真正重要的结论一定要在发生时就被写到对话之外的持久化载体里比如项目内的文档文件。我现在经常在任务快完成时直接对 Pi Agent 说一句“把这次确定的接口签名、命名约定、改动范围追加到 docs/decisions.md不要改动其他内容。”这句话的回报非常高。因为聊天记录随时可能被压缩、清理、截断但磁盘上的文件不会。下次无论开新会话、换工具还是隔天再干活只要这个文件还在核心约定就还在。在用 Pi Agent 管理会话时我会在项目根目录放两个文件AGENTS.md用来放给 Agent 看的项目级约束docs/current_state.md用来放当前任务的实时状态。前者是长期稳定的“操作手册”后者是每次任务都会重写的“临时档案”。这两个文件加起来不过几百行却比几万 token 的聊天历史可靠得多。2.2 三种“必拆”信号第二个思路是给会话设置“断点”。很多人觉得一个任务从开始到结束放在一个会话里是理所当然的但“一个任务”的边界往往比你想象的小得多。我总结了三种必须拆会话的信号。第一种单任务完成时。改完一个接口、写完一个模块、调通一个 bug这个瞬间就是天然的断点。哪怕你马上要开展下一个任务也别顺手往下聊。先收尾再重新开局。第二种文件范围切换时。比如刚刚一直在改前端组件现在要转而处理后端接口。这两种工作的上下文几乎没有重叠继续留在旧会话里只会让大量无关代码占据宝贵窗口。干脆新开会话轻装上阵。第三种当你发现自己开始重复解释同一件事时。比如第二次告诉它“表名是 user_account 不是 user”第三次强调“缓存键前缀是 app:user”。这说明当前会话已经信息过载旧内容正在干扰新指令。这时候不应该继续对话而应该立刻拆分。拆会话不是放弃进度而是把当前会话的“有效成果”提炼出来交给新会话继承。我通常会在新会话的第一条消息里写清楚“继续上一个会话已完成 A待办 B关键约定是 C。”这样新会话能快速进入状态又没有历史包袱。2.3 用文本文件做会话的“外交语言”聊到会话迁移我顺便说一个很多人在问的点各个 Agent 工具之间的会话怎么互导。比如有人问 OpenCode 的会话能不能导入 Codex。我的回答很简单与其等官方做格式转换不如把会话“降维”成最通用的文本格式。所有 Agent 工具都能读文本也都认 Markdown。所以我遇到跨工具迁移时不导原始聊天记录而是导一份“会话摘要”把旧会话导出成 Markdown然后清洗出目标、进展、约定、风险四个部分再把这份整理后的文本作为新会话的初始上下文。这样 OpenCode、Codex、Pi Agent 都能无缝识别根本不关心原始格式是什么。清洗的时候有个原则删掉过程只留决策。哪段代码是你探索时试错的、哪些讨论是最终没采用的这些都不值得带到新会话。真正要保留的只有四类信息——目标是什么、已完成到什么程度、有哪些明确约定、还剩哪些风险没解除。我用一个最简单的模板目标... 当前进度... 已完成... 待办... 约定与约束... 风险与待确认...这个模板后面还会反复提到。它是我的会话管理体系的“通用货币”。3. 实操从启动到断点的完整会话管理流程3.1 启动前把边界写进 prompt很多长会话失控根源在第一步就没控制好。不少人开新会话就是一句话“帮我改一下登录模块。”然后 Agent 就开始自由发挥问一句改一点改到哪算哪会话自然越拉越长。我现在会在启动前把边界写明白尤其是“范围”和“不做清单”。下面是我常用的启动模板字段不多但每个都关键目标把登录接口从 OAuth 1.0 迁移到 OAuth 2.0 范围只改 auth-service 模块不动数据库表结构和前端 输出代码改动 迁移说明 兼容性测试结果 约定接口路径不变错误码保持现有格式日志脱敏 不做不重构 Redis 缓存逻辑不调整 token 过期时间写“不做”这个字段尤其重要。模型天然倾向于多做、做全面如果不明确排除某些方向它会顺着自己的理解把任务越滚越大。我把“不做清单”理解为给 Agent 划了一条跑道不是让它只做这几件事而是让它在做这几件事时不会额外跑偏。每次任务范围清晰会话结束的时机也就清晰——范围做完这个会话就使命完成了。3.2 过程中三个存档点任务启动之后不要等到聊崩了才想起保存。我会在三个时间点强制设置存档点完成一个子任务时、上下文消耗肉眼可见超过一半时、以及中间要离开或中断超过半小时时。每个存档点的动作很机械把当前状态写进docs/current_state.md然后继续干活。这个文件的内容量不大五到十行就够关键是保持结构一致Agent 下次读到就知道发生了什么。我用的摘要格式如下## 当前任务 重构订单列表查询接口 ## 已完成 - 查询 SQL 重构完成去掉子查询 - 新增 create_time 索引执行了 EXPLAIN 验证 ## 待办 - controller 层参数校验待调整 - 需要补充分页边界测试 ## 约定 - 返回字段保持 snake_case - 分页参数统一用 page/page_size ## 风险 - 生产环境数据量 200 万索引上线需要低峰期执行这个文件的重点是“让一个完全没参与过当前会话的人或 Agent光看这份文件就能接手”。所以我写的时候会避免使用“这个”“那个”“上面说的”这类依赖上下文的口语全部改成明确的指代。完成一个子任务后顺手更新用时不超过两分钟但整个会话的可恢复性会大大提升。3.3 恢复与迁移断点续聊的正确姿势有了状态文件恢复会话就变得非常简单。新开会话后第一句话我会直接说继续处理订单列表查询接口重构任务。请先读取 docs/current_state.md确认当前进度然后告诉我你理解的下一步是什么。注意两个细节。第一不要试图把旧会话的聊天记录全部复制进新会话那样等于又把长会话问题搬了一次家。第二一定要让 Agent 先“复述”它从状态文件里读到的内容再开始动手。如果它复述的和实际情况有出入说明状态文件写得有歧义这时候修正文件比修正对话要高效得多。这个方法同样适用于工具迁移。把current_state.md内容贴进任何一款 Agent 工具它都能接着干。我甚至试过把状态文件发给没有上下文记忆的普通文本模型让它基于文件内容给我提代码 review 建议效果也说得过去。这就是“文本文件作为外交语言”的价值不绑定任何一家工具数据永远掌握在自己手里。顺带提一下守护进程与会话的关系。有些 Agent 工具支持以守护进程方式常驻运行让会话在后台保持存活随时可以追加指令。这个功能很方便但它也有隐患守护进程一旦重启常驻会话里的上下文就全没了。所以我在使用守护进程模式时反而更依赖状态文件。每次关键决策形成后我都会让 Agent 先把结论写进文件再继续下一步。守护进程只承担“执行器”的角色真正的“记忆体”是我自己的 Markdown 文件。4. 常见问题排查与独家经验4.1 上下文溢出报错怎么办聊到后面最常见的报错就是上下文超长大意是“请求超过模型最大上下文限制”。很多人的第一反应是继续发消息说“你简化一点”“只回复最后一段”但这只会让情况更糟——超限之后发多少条都可能被拒绝或截断。我的处理流程是先停止对话立刻把当前会话导出成 Markdown。别在满窗口状态下继续抢救先把“现场”固定下来。然后用一个新会话加载这份导出文件让它按前面说的摘要模板压缩出一份current_state.md。最后再开一个全新会话读状态文件继续干活。如果旧会话实在太长摘要也会很长可以分块处理把导出文件按时间切成三四段分别让新会话提取每段的决策和结论最后合并成一份精简状态。这个过程看着多花了十分钟实际上比反复硬聊省一小时。记住一句话上下文溢出的正确操作永远是“先保存再压缩换个会话再来”而不是“继续试试”。4.2 会话恢复后 Agent 反而“失忆”了有时候新会话开了状态文件也读了但 Agent 还是交接不清甚至说出“根据上下文我找不到你说的内容”。我遇到过很多次排查下来原因就两类一类是摘要文件里只有进度描述漏了“约定与约束”导致 Agent 只知道做了什么不知道为什么要这样做另一类是状态文件里全是模糊指代比如“按之前说好的方案进行”而“之前”这个信息在新会话里不存在。解决办法是引入“三要素复述法”。新会话启动后让 Agent 先做三件事复述当前目标复述最新状态复述下一步打算。这三条都对齐了再让它动手。只要其中任何一条和你的预期不一致就说明状态文件的表达有问题先修文件再继续。我后来检查状态文件时会特别留意有没有出现“此前”“如上”“刚刚”这类词一旦出现就说明写文件时还是带着旧会话的记忆这种内容一定会在迁移时变成失忆点。4.3 守护进程残留导致端口被占用在 Windows 上使用常驻类 Agent 工具时还有一类容易踩的坑就是进程没有完全退出、端口和会话资源被残留句柄占住。有一回我明明没有在跑任何调试任务系统却提示“此设备已为 Windows 内核调试程序预留以便在此启动会话持续期间使用代码 53”。我排查了一会儿才明白这是之前一个 Agent 守护进程异常退出后相关会话资源没有释放干净导致新的连接无法建立。处理方式很直接打开任务管理器找到残留的守护进程或相关进程强制结束然后重新启动。如果你的 Agent 工具支持命令行方式管理守护进程可以先用列表命令看看当前有哪些会话存活把不需要的明确停止。养成的习惯是每次结束一天工作前把常驻会话的状态文件更新一次然后主动关闭守护进程而不是让它一直挂在后台。这样做既避免资源残留也为第二天留了干净的起点。4.4 长会话管理速查表这里把我常遇到的问题和处理方式整理成一个表格方便直接对照。症状真正原因处理办法回复变慢延迟明显上下文过长每次请求携带大量历史压缩摘要换到新会话继续早期约定被违反关键指令被挤出上下文窗口把约定写入 AGENTS.md 或 current_state.md上下文超长报错窗口已满无法接收新内容立即导出会话新会话压缩生成状态文件恢复后 Agent 失忆状态文件缺少约定或存在模糊指代用三要素复述法验证修正文件成本飙升历史反复计费轮数过多及时拆分会话不用一个会话扛全程守护进程端口报错残留进程占用会话资源结束残留进程重启守护进程跨工具导入失败原始会话格式不兼容导出为 Markdown 摘要再作为新会话上下文这张表是我自己的排查顺序遇到问题先看表里有没有对应项有的话直接按方案处理通常几分钟就能恢复。没有的话再往深里查但大部分“会话越长越难用”的问题都能在这张表里找到答案。最后说一点个人感受。从我开始主动给会话设断点、坚持写状态文件之后Pi Agent 在我这里的可用性提升了一个台阶。最有价值的不是记住了哪条命令而是把“阶段性收尾”变成了肌肉记忆每次任务告一段落顺手花三十秒更新摘要把状态文件放好再结束会话。这三十秒换来的是后面每一轮对话都更快、更准也更便宜。如果你现在正被长会话折磨不妨就从下一次任务开始试试——先学会把会话聊短一点再把它聊好一点。