国产大模型长程开发能力亟待突破的瓶颈的系列笔记(连载)
国产大模型长程开发能力亟待突破的瓶颈的系列笔记seak
引子篇
今年非常令人欣喜的是,国产主流模型编程能力已经有了空前进步。Kimi K3、GLM‑5.2 这一级模型,在部分代码、终端操作和长程任务基准上已经进入国际第一梯队。例如,Kimi K3 官方公布的 Terminal-Bench 2.1 为 88.3、FrontierSWE 为 81.2;GLM‑5.2 官方公布的 Terminal-Bench 2.1 为 81.0。
参考资料:
(https://huggingface.co/moonshotai/Kimi-K3)
(https://huggingface.co/zai-org/GLM-5.2)
评测是一个很好的参考风向标,提供了国产模型走入全球用户视野的一个重要路径。同时,长程任务评测,也并非是“裸模型智商”的单一结果,而是是“模型+Agent 挽具+上下文管理+算力预算”的组合,例如Kimi K3 的评测说明明确显示:不同模型使用了 Kimi Code、Claude Code、Codex 等不同脚手架,Kimi K3 采用最大推理强度,部分结果是特定环境、内部基准或多次运行结果。一方面,要看到大模型能力的体系复杂,另一方面,也需要看测试中的表现,并不能代替最终的大量应用的检验。无论是从WEB入手,还是结合Code工具,国产模型在WEB前端开发的表现也都非常丝滑,在做类似数据处理分析小工具、前端演示方面,都能相对很快达成目标。这也是因此在类似Aipy的适配度测评,此类不追求长程任务评价中,可以有大量国产模型上榜,包括甚至把GPT甩在后面。
但我想指出的时,这些不能直接等价为:
1、可以有效完成其自身规划的一个大型软件。
2、可以稳定接管一个完成了 60% 的 大型项目。
3、可以完成对原有CC或者Codex的相对复杂的项目的平移。
基于今年以来的使用、测试和开发工作,我对国产头部模型到目前状态的评价是:
代码智商已经很高,但工程人格、项目记忆和验收纪律依然不稳定。
工程人格、项目记忆、验收纪律,这些是正国产头部模型必须突破的。我想基于案例->总结的方式,写一组系列笔记,讲讲感受、经验和总结。
同事提醒说,谈国产大模型,如果是谈问题要先“叠甲”,表明一下立场。我觉得大可不必,因为立场是通过斗争考验,通过历史来检验的。更何况:
第一,我们自己就是国产模型的开发者,批评国产模型也是自我批判、推动提升的过程。
第二,我们也是挽具的开发者,挽具的部分价值是能局部对冲模型能力的不足。
第三,我们也是部分国产模型的用户和部分模型的安全生态合作者,用户本来就有批评厂商的权力,生态伙伴间的批评本来就是为了共同进步。
同时,我也无意和头部模型的专家们比拼大模型的理解,如果这样做就太班门弄斧了。我是以开发者的用户体感来写这组笔记的,我的分析“入口点”来自于自身作为一个“三线”开发者的感受。作为网安企业负责人,白天自然要见甲方爸爸、跑相关部门、见投资人、讨论研发项目进展、组织响应重大事件、写各种文档等。因此做一点点技术开发工作,也多数要到晚上十二点后进行。所以本文的案例,并不是对国产大模型实现的机理分析,而是基于个人使用国产大模型完成开发任务,包括和国际当前领先模型的一些对比。
与此此同时,我对互联网开发的新的技术栈是不熟悉的,记得2010年,同事在给我的《数据救赎时》写按语的时候,就写道“Seak作为一个DOS时代的底层研究者,在安天成立伊始已经转身为技术管理者角色,其并不熟悉最新系统和NTFS分区结构。”。我的AI开发也是对流行技术栈的学习过程。
笔记案例会来自几类:
一,垂直响应平台中我负责的工具ASearch搜索等,智甲EDR中我负责的配套工具,所以这些都是最大不过几千行到几万行级别代码的小型独立任务。
二,挽具AVL Code的开发测试,我们必然要在同样的任务和文档条件下,进行用同一个挽具使用不同模型的输出对比,或者同一个模型,不同挽具的对比。
三,客户在部署使用AVL Code中遇到的一些问题,经我们分析属于模型问题的。(获得了客户分享的同意)
四,作为大学兼职教师,给所担任课程做的课件,中遇到的问题。
每套模型+挽具都有其频繁出错的低级梗,在选取的案例也把握原则的原则是:案例都取自导致“翻车级”结果的情况,而不是类似在交互或者迭代中出的一些低级错误。
我们不会在所有案例中提及具体模型的名字,这些案例都今年以来遇到的出现的,也并不尽然一定是模型的问题,同样有可能是挽具的问题。
包括有些可能对应的模型已经有了调整,我们的重点不在于具体的问题,而在于通过案例引出若干共性问题。
如果,未来几天后半夜的时间,有保证,我拟用每天一篇笔记的节奏,大概用十天左右的时间完成这次盖楼。 能“从零开发”,却不会“接盘维护”
——国产大模型开发能力亟待突破的十二个瓶颈之一
从零开发和接盘维护,是两种完全不同的体验。
如果你要看模型是否有精致妆容,就给它一个空目录;如果你想考验模型是否有深厚的内力,就给它一个历史项目。
在从零开发上,国产模型已经可以做得相当不错。做一个 React 或 Vue 页面,写一个 Python 小工具,实现一组常规后端接口,很多时候不仅速度很快,视觉和功能效果也会让人眼前一亮。
Kimi K3 刚发布的那几天,我曾经用 AVL Code 配合 Kimi K3,生成了一个老式计算机操作演示站 `cs.avlcode.cn`。整个过程的 API 计费消耗约为 200 元人民币,最后呈现出来的效果总体令人满意。这就是老张在blog中,说我向他“致敬”的页面,其实这个页面不是给老张的,真正“献给老张”的页面遇到了一个值得总结的坑,我会在另一偏瓶颈点讲。
。Moonshot 对 Kimi K3 的官方定位也已经明确包括长程编码、大型仓库导航和终端工具编排,说明国产头部模型的目标早已不再局限于代码补全。
从实际应用看,前端页面、脚本工具和相对标准的业务接口,已经足以覆盖相当一部分机构的日常数字化需求。即便进入 C++、Rust 等技术栈,只要需求边界清晰,把国产模型作为 IDE 的增强器,用来补齐代码、解释接口、查找调用关系和生成局部实现,也有很大价值。问题在于,未来衡量编程模型和 Agent 挽具的,不是传统软件工程的场景。真正的软件工程变化,是编程正在从少数人的专业技能,逐渐变成一种按需生产能力。越来越多非专业开发者会从零起手,通过自然语言生成软件,再根据反馈持续迭代。传统意义上的“程序员”和“用户”之间,正在出现一个人数更大、边界更模糊的新群体。
这个新群体与国产模型结合中,共同面对一个大坑和一座大山。
一、需要填的大坑:历史项目不是一张白纸
所谓大坑,就是历史项目的接盘。国产模型现在通常已经能够读懂相当复杂的代码。把一个仓库交给它,让它解释模块关系、梳理调用链、说明某个函数在做什么,结果未必比国际主流模型差很多。但“看懂”和“动手”之间,隔着一道很深的沟。我曾经把一款历史跨平台工具的代码和文档,分别交给国产模型和国际主流模型做理解与迁移测试。单看代码解释,两者差距并不明显。可当第一个实际任务变成“恢复技术栈和编译环境,并成功完成构建”时,差别立刻出现了。国际模型很快沿着原有技术栈完成了编译。国产模型则判断这个项目技术栈复杂、陈旧、维护价值不高,建议直接换一套新技术栈重构。这类建议从文字上看甚至很有道理。老技术栈难维护,文档残缺,构建工具过时,代码风格混乱,重构似乎比修修补补更“先进”。但接下来真正让模型执行长程重构时,它又往往驾驭不了这个过程:旧系统没有完全理解,新系统没有真正建立,接口兼容和异常路径被逐渐遗漏,最后留下一个既不能替代旧版本、也无法独立交付的新工程。
这不是个别项目的偶然。国内软件工程的发展极不均衡。一些大厂和大型企业积累了成熟的工程体系,但作坊式开发也长期大量存在。很多历史项目文档不全,代码与文档不一致,构建环境依赖某一台旧电脑,关键逻辑只存在于原作者的记忆里。还有一些代码,经过十几年人员更替和需求叠加,早已形成了只有“考古”才能解释的结构。
这些项目本身就是一个巨大的历史遗留层。
模型进入这类仓库后,很容易出现几种典型行为:
[*]不理解某段“看起来很丑”的代码为什么不能动;
[*] 不知道现有抽象背后承担着哪些历史兼容责任;
[*] 放着已有工具类不用,重新实现一套;
[*] 绕过原有错误处理、日志、配置和生命周期框架;
[*]为完成一个局部任务,破坏公共接口或模块边界。
其中最危险的,不是模型写不出代码,而是它能够写出一段**局部合理、全局错误,而且可以顺利通过编译的代码**。
案例:一个小任务,怎样变成六个死循环
这是我们协助客户进行AVL Code+某国产模型移植的一个典型案例,项目前期约 60% 的代码由 Opus 协助完成,随后转交给 某国产模型继续开发。事故涉及的文件是一个约 1600行的 `Manifest.cpp`,接盘的首个任务看起来极小:为十个 `List*` 查询函数补上 `sqlite3_reset`。
模型的理解是:这就是一个十行修改。找到十个位置,各插入一行 `sqlite3_reset`,编译,测试,结束。
但这项任务真正的形状并不是“十行插入”,而是“确认十个调用点是否符合语句缓存的所有权契约”。
这个契约其实并不隐蔽,就写在文件最前面的 120 行里:
- 缓存命中时,`StmtCache::Get` 会统一执行 `sqlite3_reset` 和 `sqlite3_clear_bindings`;
- 缓存析构时,会统一 `finalize` 所有语句;
- 数据库关闭前,`Manifest::Close` 会先释放语句缓存,再关闭数据库连接。
也就是说,调用方原则上不拥有这些 SQLite 语句的最终释放权;下一次复用时,缓存层本身也已经负责 reset。那十个调用点并不存在必须补 reset 的正确性缺口。所谓“十个函数缺少 reset”,本身就是建立在错误诊断上的一张假工单。
模型没有读这段契约。它拿到交接摘要后,直接把一个所有权问题降维成了行号编辑问题。最终十个预定落点中,只有两个位置正确;六个 reset 被插进了查询循环体;另外两个甚至落进了任务清单之外的相邻函数。只要数据库中存在一行查询结果,循环体内的 `sqlite3_reset` 就会让下一次 `sqlite3_step` 从头重新执行查询,再次返回第一行,最终形成死循环,并让结果容器持续增长。
结果是:
> 十处修改,二处正确,六处埋下死循环,两处改错函数。
更危险的是,这份代码编译通过了。
模型还运行了一个样例测试。恰好,这个测试只经过十个函数中位置正确的那个函数,没有触及六个已经受损的查询路径。于是测试转绿,模型宣布“核心功能修复完成”。
这次事故最值得注意的地方,不是模型不知道 `sqlite3_reset` 怎么用。
恰恰相反,它知道这个 API,也知道如何插入代码,能够处理编译错误,甚至能够根据链接错误临时补写一个缺失函数。
它真正没有理解的是:
> reset 的责任究竟属于调用方,还是属于语句缓存?
这才是整个任务的逻辑关窍。
如果模型先读懂了缓存所有权契约,就会发现十处修改一处都不应该做。真正需要完成的任务,只有补上另一个链接所需的缺失函数,并为它增加行为测试。
它把不需要做的十件事做了一遍,还做错了其中八件。
事故中还有一个很有象征意味的细节。
模型接盘时,工作区里残留着上一轮修改失败形成的畸形代码:重复的 `return true`、多余的右花括号,以及位置错误的 reset。模型认为这些是垃圾,直接执行 `git checkout` 将文件恢复,而且没有先 stash。
事后复核才发现,那些代码虽然编译不过,但其中保留了前任正确的修改意图——reset 原本准备放在查询循环闭合之后,只是在复制代码时把 return 和右花括号一并带了进去。
换句话说:
> 前任留下的是“语法错误但意图基本正确”的代码;接盘模型把它清掉之后,写出了“语法正确但语义危险”的代码。
前一种错误会被编译器拦住,后一种错误却可能进入版本。
这就是接盘维护最典型的风险:模型把代码库看成了一块等待自己重新书写的画布,而不是一个已经运行多年、充满历史约束和所有权关系的系统。
二、需要越过的大山:如何让更多中国使用者摆脱国外模型与工具的依赖
如果说历史代码是大坑,那么更大的那座山,是当前国内产业领域中,不得不最终摆脱的国外模型与工具供应依赖。
问题并不只是把 API 地址从一家换成另一家。
编程智能体已经深度介入:
[*]项目理解;
[*] 架构设计;
[*] 代码生成;
[*] 调试;
[*] 测试;
[*] 文档;
[*] 发布;
[*] 版本交接;
[*] 团队知识沉淀。
当一个项目长期使用 Claude Code 和 Opus 开发后,模型的行为方式实际上已经进入了项目的生产过程。切换到国产模型,不只是“换一个更便宜的推理接口”,而是在更换一名熟悉项目历史、工具习惯和工作节奏的虚拟工程师。
支撑这个迁移过程比当年的 WPS 对决 Office 更困难,更低的价格、做好百分之二十的常见功能,这些打法有用,但效用不是太灵,办公软件迁移的主要问题是文件格式、功能习惯和生态兼容;编程模型迁移还多了一层:**新模型必须理解并延续旧模型参与塑造的软件系统。**
案例:模型如何以编译环境为最后的借口
我们指导客户进行工程迁移时,一家 AVL Code 客户此前也是基于 Claude Code 和 Opus开发,完成了一个万行级的客户端工具。后来,希望把后续开发迁移到某国产模型 API。
客户配置AVL Code 完成对接后,首先要求模型根据工程代码和文档检查编译环境。模型判断环境已经完备,同时发现了主机路径差异,也指出原编译脚本中的路径不一致,并成功编译出了第一个版本。
到这里,一切很顺利。但在实施一个很小的功能改进时,模型开始长时间陷入各种错误。几小时后,它给出的结论竟然是:
> “终于定位到问题,编译环境并不完整。”
但这个过程中,它莫名其妙地修改了部分头文件。
客户指出,同一个项目此前也曾在 Codex 和 Claude Code 之间迁移,主机技术栈环境同样存在差异,却没有发生这种反复推翻结论、又把环境问题转化成源码修改的问题。在之前的移植过程中,并不需要单独让Claude Code去理解环境差异,其会自然的重构编译脚本。
淡然这里是一个个案,并不是说 Claude Code 或 Codex 不会犯错,Codex的“我删”模式已经是多人都需要过的严重事故。
但我们需要看到的是而是它们在接管既有项目时,通常更能把以下几件事区分开:
[*]环境问题;
[*]构建脚本问题;
[*]代码问题;
[*]本次修改引入的问题;
[*]仓库原有问题。
而能力不足或工程纪律较弱的模型,容易在这些问题之间来回漂移。一开始说环境完整,后来又说环境缺失;一开始说路径有误,后来直接修改头文件;编译失败时不断缝补,最终已经说不清自己是在修功能,还是在重造构建环境。
从 AVL Code 开发者的角度,我们当然要不断通过技术栈标准化、环境指纹、编译探针、Plugin、Skill、任务状态机和验证门禁来改善这些问题。但对于已经重度依赖 Claude Code、Opus、Codex 和 GPT 系列模型的用户来说,他们不会用“某个国产模型已经比过去进步很多”作为评价标准。
他们真正比较的是: 能否给与一套国产模型+挽具同样的心智信任。这就形成了一个双重痛苦期。一方面,国产模型需要接续此前由国际模型生成和维护的版本;另一方面,已经习惯了 Codex 与 Claude Code“双枪并用”的开发者,也必须重新调整自己的能力预期、任务拆分方式和使用习惯。
它不仅要接代码,还要接前任模型的设计决策、临时方案、命名习惯、测试空白,甚至接前任留下的错误。
当交接文档与代码不一致时,模型必须知道应该相信谁;当旧代码很丑时,必须先判断这是技术债、兼容层,还是不能动的业务规则;当构建失败时,必须区分环境异常和代码回归;当局部测试通过时,还必须知道验证面是否覆盖了修改面。
这些能力,远远超过“根据需求生成代码”。
三、 “尊重代码”不是态度,而是一套方法
回到这个系列第一篇想讨论的瓶颈,我的核心感受是:
> 国产主流模型已经越来越能看懂“代码做了什么”,但不一定能推断出“为什么当初必须这么做”。
而在历史项目中,后者往往比前者更重要。
所以,从体验上说,我很想给当前的国产编程大模型——特别是我们自己的模型——一个不太客气的评价:
会写代码,不会尊重代码。
这里的“尊重”不是拟人化的道德要求,也不是要求模型迷信旧代码,我始终反对对大模型人格化想象————这是一种人的“认知幻觉”。
尊重代码,是模型+挽具的工程方法,我们总结本文中的案例,可以看到:
1. 契约先于工单。 涉及缓存、句柄、连接、线程和对象生命周期时,先找到所有权中枢,再修改调用点。
2. 代码先于交接叙事。 上一轮说“已经完成”,不等于仓库里真的存在;接盘第一步应当是逐项对账。
3. 疤痕先于清理。畸形工作区不一定只是垃圾,也可能保存着前任尚未表达完整的修改意图;回滚前必须保全。
4. 模式验证先于编译通过。 批量修改十个位置,就要逐点检查十个位置;编译器只能证明语法成立,不能证明语义正确。
5. 验证面不能小于改动面。 修改十个函数,只运行一条恰好不触及错误路径的测试,那个绿色没有多少意义。
6. 完成声明必须建立在证据上。 编译命令、退出码、测试覆盖范围和未验证项,应当比模型的总结更可信。
这次事故复盘给出的五步防线——读契约、做疤痕考古、复核工单、验证批量落点、让测试覆盖全部改动面——其中任何一步,都足以独立终止事故链。
因此,我非常反对把国产模型仍然存在的不足简单归结为“国产模型参数不够大”。模型当然需要继续提高软件演化、因果调试和长程工程能力;但编程智能体和 Agent 挽具同样必须承担责任。模型容易忘记的约束,就不应该只写在提示词里;模型容易夸大的完成状态,就应该由证据系统裁决;模型容易随意扩大的修改范围,就应该被 Diff 预算和接口锁限制。我们不能指望靠一句“请充分理解项目后再修改”解决工程纪律问题。
四、土壤不够肥沃,但空间足够宽广
写到这里,我要再次明确这个系列不是一份国产模型的败绩清单。
中国的软件开发者从宽口径计算约千万,即使对照美国BLS的全职程序员标准统计,也可能有400万之多,已经式美国的两倍。中国拥有毋庸置疑的巨大的软件需求、开发者生态和数字化市场。过去几十年,这片土地上产生了大量优秀的软件,也留下了数量更多、质量参差不齐的历史项目。它们可能没有完整文档,没有稳定测试,没有统一架构,甚至连编译环境都无法轻易恢复。这些田地谈不上肥沃,更谈不上精耕细作。但它足够广阔。
对于国产编程大模型来说,有价值的下一步,不是再生成一个更漂亮的 Todo List,不是在空目录里更快地搭出一个网页,甚至不是去刷新一些旧的和新的榜单记录,而是走进这些真实、混乱、带着历史伤痕的项目里,把它们接住。先理解它为什么会变成今天这样,再决定什么应该保留,什么可以修改,什么必须重构。
一个模型只有在动手之前开始追问:
> 这段代码为什么还存在?
> 谁在依赖它?
> 它背后有什么没有写出来的契约?
> 我真的有必要动它吗?
它才算真正从“会写代码”,走向了“会做软件工程”。
而当我们的国产模型开始学会“尊重代码”,它就将接住中国软件产业真正庞大、真正复杂,也真正有价值的历史,也能更好、更完全的承载住它的使命。 上下文窗口很长,项目记忆仍然很短
——国产大模型开发能力亟待突破的十二个瓶颈之二
(排版风格可能有点妖,是用AVL Code转成的Discuz!的排版语法,委屈同志们凑合看一下)
如果说上一篇讨论的是模型不太会尊重一个项目的历史,那么这一篇要讨论的是:它能装下百万Token,却有可能记不住刚刚发生的事情。用一个人格化的说法——它有时不够尊重自己刚刚创造的历史。
一个模型可以在同一轮任务中读完几十万行代码,却在几分钟后重新犯下刚刚修过的错误;可以把设计文档、项目代码、编译日志和子Agent报告全部装进上下文,却记不住十秒钟前已经搜索过同一个关键词。
这可能是当前国产编程大模型最容易被“百万上下文”这个已经很漂亮的数字指标掩盖的问题:
上下文窗口已经很长,项目记忆仍然很短。
这里首先要说,GLM-5.2 和 Kimi K3 支持 1M 上下文,无疑是令人鼓舞的进展。
[*]GLM-5.2 官方将“稳定的 1M Token 上下文”列为核心能力;
[*]Kimi K3 同样提供 1M Token 上下文,并将大规模仓库导航和长程工程任务作为重点方向。
从我们的实际测试看,1M 上下文带来的最典型能力突变,并不是“代码突然写得好五倍”,而是规模化工程盘点能力明显提高了。
我们以一套历史上被废弃的产品代码,分别交给:
[*]1M 上下文的国产模型;
[*]1M 上下文的 Opus;
[*]200K 上下文的 Opus;
[*]200K 上下文的 Sonnet。
让它们盘点整个仓库,识别模块边界、梳理依赖关系、还原产品结构,并结合历史文档和日志说明项目的演化过程。在全局理解任务中,1M 上下文的国产模型已经很接近 1M 上下文的 Opus,而超过了 200K 的 Opus。
以下几类工作,1M 上下文的国产模型表现很理想:
[*]阅读大几十万行工程代码;
[*]建立较完整的模块依赖图;
[*]同时分析大量历史日志和设计文档;
[*]对照多个版本的代码差异;
[*]生成多个工具或模块的迁移清单;
[*]在较长时间内避免过早进行上下文压缩。
这些能力对于历史项目盘点、技术尽调、代码审计和迁移准备都很有价值。
但必须看清楚:这些任务的主要产出,仍然是基于代码和文档理解的分析结果。类似一个阅读理解接近满分的学生,但还没有训练成为写作文的高手,但从“读完整个项目”到“持续正确地修改这个项目”,中间还隔着一层关键能力:
项目记忆。
一、百万上下文带来的,首先是仓库容量
如果基于手感的比较,我个人的主观判断是:
Opus 4.8@200K > Sonnet 5@200K ≈ 满血国产模型@1M。
这里说的不是基于一批算法题,也不是一次代码补全,而是基于多轮、长程、跨文件的软件工程作为测试任务。
截至 2026 年 8 月 13 日,DeepSWE v1.1 在同一套 mini-swe-agent 脚手架下给出的部分结果如下:
模型成功率平均输出 TokenAgent 步骤
Claude Opus 4.8 Max59%±2%135K120
Claude Sonnet 5 Max54%±4%214K268
GLM-5.2 Max44%±2%78K129
DeepSWE 使用 113 个原创长程软件工程任务,覆盖 91 个仓库和 5 种语言,并统一运行在 mini-swe-agent 上,因此它至少减少了不同 Agent 外壳造成的一部分干扰。
这组数据当然不能代表所有真实项目,也不能简单推导出某个模型在任何情况下都比另一个模型强。但它和我们的实际感受大致同向:
满血 GLM-5.2 的 1M 上下文,在全仓库扫描、超长任务不压缩、大量重复迁移、吞吐量和成本方面有明显优势;在私有化部署上,更有国际闭源模型无法替代的战略价值。
但在以下问题上,它和 Opus 4.8 仍有明显差距:
[*]长时间严格遵循既有架构;
[*]在大量信息中持续抓住少数关键约束;
[*]发现旧结论已经失效;
[*]把一次错误转化为后续任务的通用约束;
[*]在几十轮工具调用后仍然保持原始目标不漂移。
也就是说,1M 上下文真正解决的是:
东西能不能放进去。
它还没有充分解决:
放进去以后,能不能一直找得到、用得对,并且知道哪些东西已经过期。
上下文像一个仓储的总体容量。1M 上下文相当于把单间小仓储柜换成了一间大仓库。但如果仓库里没有货架、标签、编号、出入库记录和失效清单,那么东西越多,查找反而越困难。
所以,1M 上下文与 200K 上下文的关系,并不是:
1M 模型能力 = 5 × 200K 模型能力
编程 Agent 也不会在每一轮都把整个仓库原封不动地塞进提示词。它实际的工作过程通常是:
检索目录
→ 查找符号
→ 阅读相关文件
→ 修改有限模块
→ 运行编译和测试
→ 根据结果继续加载代码
如果任务拆分和检索做得合理,200K 上下文通常已经足以容纳:
[*]系统提示和工具说明;
[*]AGENTS.md;
[*]当前任务相关代码;
[*]必要的架构文档;
[*]若干轮工具结果;
[*]编译错误和测试日志;
[*]当前补丁;
[*]一份结构化任务状态。
真正决定长程任务质量的,并不是窗口里最多能塞多少 Token,而是:
模型和挽具能不能让重要信息始终处于正确的位置。
二、案例一:一场足球引发的数百次重复搜索
上一篇里我埋了一个伏笔,回应老张那篇“娃娃抓起,肌肉记忆”的 Blog。
cs.avlcode.cn 那个老式计算机操作页面,其实并不是真正“献给老张”的页面。真正向老张致敬的,是另一组叫《逃学的日子》的页面:gt.avlcode.cn。
当然它的主要作用,是怀念我们异地同时游戏的那段经历,也是我在给母校开设暑期课程留的同学们一个特殊彩蛋:学生在一个“智能体赛博之门”的实践中,如果双路六关都没有解出密码,都选择直接查看答案,就会点亮一个名为“叹息之地”的页面。
其中一个页面在开发过程中,也留下了一个很值得总结的“叹息”。
我最初在 GLM 的 API 中预存 200 元。第一批额度消耗完时,网站的整体框架和大部分主要功能已经基本完成,可以说是令人满意的。后续为了修补细节,我又存了 200 元,但第二批 Token 中相当大的一部分,并没有用于实现新功能,而是消耗在了数百次无意义的重复动作上。
问题出现在我对复刻 PS1 足球扑点游戏的复现的一个反馈,包括:
[*]切换全屏后画面变黑;
[*]点球阶段看不到足球。
当时的上下文已经包含:
[*]8 份设计文档;
[*]6 个页面的完整代码;
[*]多个页面的修复记录;
[*]5 个子 Agent 的验收报告;
[*]多轮编译和调试结果。
也就是说,从“容量”上看,模型几乎拥有了整个项目。它随后完整读取了 1211 行页面代码,并搜索到了 .penalty-ball 的 CSS 定义。
从这里开始,模型锚定在一个局部结论上:
CSS 已经定义,因此问题应该还在这个关键词附近。
然后,它开始反复执行同一条搜索:
fs.grep penalty-ball
同一个工具,同一个参数,同一个返回结果——数百次。直到 API 触发熔断(实际上是余额为零了),我的问题仍然没有得到回答。
真正的两个问题,其实只需要几次有方向的阅读就能发现:
[*]renderPenalty() 生成的 HTML 模板里根本没有插入 .penalty-ball 元素,所以足球从未被渲染;
[*]applyDisplayMode() 在切换屏幕时把父容器一起隐藏,屏幕自然只剩下一片黑色。
正确诊断大约只需要 4 次工具调用;实际执行却用了数百次。
这个案例最有意思的地方,不是模型没读代码。它读了。甚至读得太多了。它读完了 1211 行,其中真正与问题相关的只有三个很小的区域;剩余的记忆卡、CD 播放器、演出逻辑和其他游戏代码,都变成了背景噪声。模型虽然已经看到真正的错误,却没有把它识别为答案。
更关键的是,这个环境并不是没有外部记忆工具。当时有 TodoWrite 可以保存当前问题、假设和下一步动作。但它最后一次更新,还停留在“全站验收检查完成”。进入足球修复和 PS1 诊断后,任务状态就再也没有维护。
外部状态机停摆后,模型只能依赖上下文中的自然语言历史导航。而在很长的上下文里,最容易被复制的往往不是最初的全局目标,而是最近一次局部动作:
上一轮是 grep
→ 下一轮还是 grep
→ 再下一轮继续 grep
任务目标从“找出为什么看不到足球”,逐渐坍缩成了“继续执行最近一次搜索”。
所以,这个案例最后可以被压缩成一句比较尴尬的原因:
上下文装下了 6 个页面的全部代码,却装不下“我十秒钟前已经搜过同一个词”。
这并非容量不足,而是导航失灵。
但特别说明,这个案例不是对 GLM 的吐槽。这个案例我的概括就是:如果说这是一个“200 元”的 Token 代价,设计开发者(我)、GLM5.2 模型和 AVL Code 挽具,大概各有 1/3 的责任,而且就是这个案例直接触发了我们在 AVL Code 对重复的干预机制。
三、案例二:同一个坑,在同一轮对话里踩三次
第二个案例来自我打底的一款网管工具的开发,这次的上下文同样很完整:
[*]设计文档已经加载;
[*]AGENTS.md 已经加载;
[*]生成的代码全部在当前会话中;
[*]多次编译输出也完整保留。
但在同一轮对话中,几种已经出现并被修复过的错误,又反复出现:
[*]NetAdminConsole.App 与 System.Windows.Application 发生命名空间冲突;
[*]测试文件再次缺少 using Xunit;
[*]ToolCategoryGroup 的命名空间第一次猜错,第二次仍然猜错;
[*]重写 HotKeyService 时,再次遗漏原有兼容接口;
[*]对第三方库 API 继续凭记忆猜测,生成不存在或版本不兼容的方法。
其中最典型的是 Application.Current。模型第一次遇到冲突后,已经知道这个项目自己的 .App 命名空间会遮蔽 BCL 中的 Application。但这个经验只被用于修复当前文件,没有被抽象成一条项目约束:
本项目处于 .App 命名空间下的文件,不能直接使用未限定的 Application。
于是,进入后续的 HotKeyService.cs 和 MainWindowViewModel.cs 后,相同错误再次发生。
问题不是那条错误信息从上下文中消失了。它仍然在那里。真正的问题是:
模型修复了一个错误,却没有学到一条规则。
同样的问题也出现在第三方 API 上。第一次发现 CommunityToolkit.Mvvm 8.2.2 的 WeakReferenceMessenger 需要 token 参数后,模型没有建立当前项目的可信 API 清单;之后又凭模糊记忆生成无 token 版本。它还猜测 Window.GetHandle() 应该存在,因为“这种扩展方法按常识应该有”,直到编译器再次证明它不存在。
人类工程师在第二次遇到同一类错误时,通常会开始做一些结构化动作:
[*]写一条 Lint 规则;
[*]在 Code Review 清单里增加一项;
[*]在团队 Wiki 中记录命名空间禁忌;
[*]建立当前版本的 API 用法示例;
[*]全仓库搜索是否还存在同类问题。
而模型在这次任务中采取的是:
出现一处
→ 修一处
→ 离开当前文件
→ 在下一个文件里重新犯一次
所以,这个案例的本质也不是简单的“记性差”,而是:
经验没有被抽象为约束,错误没有被转化为知识。
完整的项目历史、设计文档和实时编译反馈都在上下文里,但没有形成:
错误模式
→ 项目规则
→ 全局检查
→ 后续预防
最终结果就是同一个坑反复踩,每一次都像第一次见到。
四、上下文不是记忆,历史也不等于经验
这两个案例表现不同。足球页面是不断重复同一个动作;网管工具是不断重复同一种错误。但它们有同一个根因:
上下文中的信息,没有被组织成可以持续支配后续行动的工程状态。
长上下文最容易给人一种错觉:只要历史都还在,模型就应该记得。但对编程 Agent 来说,“历史仍在窗口里”和“模型拥有项目记忆”,是完全不同的两件事。上下文只是材料。
项目记忆至少还需要以下能力:
写入
更新
抽象
分类
回读
冲突处理
失效
优先级排序
行动约束
例如:“Application.Current 曾经报过错”,只是一段历史。而下面这条才是项目记忆:
constraint:
id: namespace-application-conflict
scope: NetAdminConsole.App.*
rule: 禁止直接使用未限定的 Application
replacement: System.Windows.Application
evidence: CS0234 / Converters.cs
status: active
“刚才搜索过 penalty-ball”,只是一段工具记录。而下面这条才是任务状态:
current_goal: 找出点球无球和全屏黑屏的原因
known_facts:
- penalty-ball CSS 已定义
- 尚未确认 HTML 是否生成该元素
next_action:
- 检查 renderPenalty 的模板输出
forbidden_action:
- 不得重复执行相同 grep
一旦这些信息只是自然语言历史的一部分,模型就必须在几十万 Token 中重新把它找出来。找不出来,就会遗忘。找到了但没有正确使用,也等于遗忘。
更麻烦的是,长上下文不仅会保存正确结论,也会保存错误结论。一个错误判断如果没有被显式标记为“已证伪”,就可能长期留在上下文里,继续成为后续推理的锚点。所以,有时候上下文越长,错误并不是越容易被纠正,而是可能存活得越久。
五、模型的长程能力,还取决于挽具怎么保存历史
Kimi K3 的官方用法提供了一个很有代表性的信号。Kimi K3 采用 preserved thinking history 模式。官方明确要求,在多轮会话和工具调用中,必须把 API 返回的完整 Assistant 消息原样传回,包括:
[*]reasoning_content;
[*]tool_calls;
[*]content。
不能只把最终回答重新塞回上下文。这至少说明了一件事:
所谓模型的长程能力,并不只属于模型本身,也属于上下文协议和 Agent 挽具。
如果中转站、API 适配层或者编程智能体:
[*]丢弃了 reasoning_content;
[*]改写了工具调用历史;
[*]截断了关键错误输出;
[*]只保存最终自然语言总结;
[*]在 Compact 时丢失了例外条件;
[*]把临时猜测压缩成确定事实。
那么用户拿到的,就不是模型卡上那个“满血 1M 模型”的真实能力。这也是为什么:
满血模型的长程训练能力,不等于经过截断、摘要和字段转换后的实际使用能力。
同样的模型,在不同挽具中,可能表现得像两个完全不同的工程师。
但即使协议完整,也不能把全部责任继续推回模型。在足球案例中,不是没有 Todo 工具,而是模型在长程执行中忘记了继续维护 Todo。这说明仅仅“给模型一个记忆工具”还不够。如果记忆的写入、回读和更新仍然依赖模型自觉,那么任务越长,它越有可能忘记自己应该使用记忆。
因此,很多项目状态不能只是一个可选工具,而必须成为挽具的强制流程。因为项目记忆,不能只靠模型自己记。
六、真正缺少的,不是上下文,而是知识管理能力
从模型侧看,国产模型需要继续提高:
[*]长上下文中的注意力分配;
[*]关键约束识别;
[*]错误结论撤销;
[*]跨轮目标保持;
[*]经验抽象;
[*]长程计划执行。
但从编程智能体和 Agent 挽具侧看,我们同样不能把所有问题归结为模型“不够聪明”。
模型可以忘,系统不能跟着忘。
模型会偏航,任务状态机就必须把它拉回来。模型可能把猜测当作事实,记忆层就必须区分“假设”和“证据”。模型可能重复同一条命令,工具层就必须提供调用编号、增量信息和熔断机制。模型容易在第二个文件中重犯第一个文件的错误,挽具就应该把一次错误升级成项目规则。
所以,真正的项目记忆,不是保存更多聊天记录。它是把项目中的事实、约束、决策、错误和经验,持续转化为一种可以支配后续行动的结构化状态。
这也是“长上下文”和“长记忆”之间最关键的区别:
长上下文保存发生过什么。
项目记忆决定以后不能再发生什么。
七、仓库足够大了,导航不能再靠运气
1M 上下文是国产模型极其重要的、值得骄傲的能力,毕竟是在远低于对手的算力条件下取得的。特别是在私有化部署、大型历史代码盘点、企业文档分析、安全审计和多模块迁移方面,它不是一个为了跑榜单而增加的装饰性参数,而是真正具有产业价值的路径优势。
但我们不能把一个大仓库误认为一套完善的知识系统。一个真正具有项目记忆的编程模型,至少应该做到:
[*]在第八十轮仍然记得第一轮“不许修改公共接口”;
[*]第二次遇到同类错误时,不再把它当成新错误;
[*]工具返回相同结果时,知道自己正在原地踏步;
[*]新证据推翻旧结论后,停止继续引用旧结论;
[*]上下文压缩之后,关键例外条件仍然存在;
[*]下一次进入项目时,不必重新发明上一轮已经确认的架构。
我们在足球页面案例中看到的是:
装下了整个站点,却丢失了当前任务。
我们在网管工具案例中看到的是:
保留了全部错误日志,却没有形成一条项目规则。
这正是国产模型下一步需要突破的地方。有价值的 1M 上下文,不是让模型可以一次读进更多代码,也不是让上下文压缩发生得更晚。而是让模型在漫长的软件工程过程中,持续知道:
我现在要解决什么?
我已经确认了什么?
哪些结论已经失效?
哪种错误不能再犯?
下一步为什么应该这样做?
当国产模型不仅能把一个大型项目装进上下文,还能把每一次成功和失败沉淀为持续有效的项目知识,它才真正拥有了长程工程能力。
上下文的仓库,国产模型已经建得足够大。接下来需要补上的,是货架、目录、账本、路标,以及一套不会让模型在仓库里迷路的导航系统。
参考资料与案例依据
[*]GLM-5.2 官方模型资料:https://huggingface.co/zai-org/GLM-5.2
[*]Kimi K3 官方模型资料:https://huggingface.co/moonshotai/Kimi-K3
[*]Kimi K3 多轮历史与工具调用说明:https://huggingface.co/moonshotai/Kimi-K3/blob/main/README.md
[*]DeepSWE v1.1 独立评测:https://deepswe.datacurve.ai/
[*]内部案例复盘:《逃学的日子》全站开发会话——PS1 点球 Bug 诊断阶段发生数百次相同 grep,直至熔断。
[*]内部案例复盘:《项目记忆负面案例 2》——同一轮对话中重复出现命名空间冲突、缺少 using Xunit、API 版本猜测和状态漂移。
脚注:
案例复盘记录显示,模型在完整读取 1211 行页面代码后,数百次重复执行相同的 fs.grep penalty-ball;正确诊断只需要检查 renderPenalty() 和 applyDisplayMode() 等少量相关区域。
案例复盘记录显示,Application.Current 命名空间冲突、缺少 using Xunit、ToolCategoryGroup 命名空间猜错和 HotKeyService API 不兼容等问题均在同一轮对话中重复出现,其根因不是上下文缺失,而是经验没有沉淀为项目约束。
页:
[1]