今天提了人生第一个开源 PR,给阿里的 AgentScope-Java 框架。
起因特别小。小到就是一行打印。
一行”目录还没创建”,我觉得不对劲
我在学这个框架的记忆压缩,跑官方那个 MemoryCompactionExample 示例。它跑完最后会检查一下生成的记忆文件,然后打印出来。
结果我这儿永远是这一行:
── Memory files on disk ── (memory/ directory not yet created)目录没创建。没有任何文件内容。
按理说这个示例存在的意义,就是给你看它生成的记忆文件。结果它自己打印”啥都没有”。这就很怪。
Claude 一开始给我的解释是”时序问题”——异步写入还没落盘,检查跑早了。听起来挺合理。但我心里犯嘀咕:真是没写完,那我程序都退出了,文件总该在了吧?
于是我干了件事:让它别急着下结论,去把那个临时目录翻出来看看到底有没有文件。
让它别猜,去实锤
我让它带我看那个临时工作目录。一个 dir -Recurse 下去,真相就出来了:
memory-demo-session\ MEMORY.md ← 280 字节,明明在 memory\ 2026-07-01.md ← 569 字节,也在文件明明都在。只是不在示例去找的那个地方。
这下就不是”时序问题”了。是找错地方了。
顺着这条线让它深挖源码,根因浮出来:记忆文件是通过一个 WorkspaceManager 写的,它会自动加一层命名空间目录——默认策略下,没设 userId 时会退回用 sessionId 当目录名。所以文件真实落在 <workspace>/<sessionId>/memory/。
而示例读的时候是这么写的:
Path memoryDir = workspace.resolve("memory"); // 少了 <sessionId> 这一层!Path memoryMd = workspace.resolve("MEMORY.md");写的时候带了一层 sessionId,读的时候没带。永远对不上。无论等多久都一样——跟异步、跟时序,半点关系没有。
我特意让它改完之后用同一个示例实跑一遍,对比给我看,别只嘴上说。修完再跑,那两个文件的内容乖乖打印出来了。这才算实锤。
一个我曾经以为”是不是我操作错了”的现象,最后是框架示例自己的 bug。
顺手又挖出第二个 bug
修第一个的时候我还有个没解开的疑惑:这个示例跑下来,那个说好的”压缩”我一次都没见它触发过,对话消息数一路往上涨,从没变小。
这个文件顶部的注释白纸黑字写着:triggerMessages=6, keepMessages=2 所以”压缩会在几轮之后触发”。
可它就是不触发。
又是一轮源码深挖。这次的坑更隐蔽:控制”保留多少条”的那个参数 keepTokens 有个默认值,是”动态模式”。框架会按模型的上下文窗口,把它算成一个很大的 token 数(大概 8000)。而我这段 demo 对话总共才一千多 token——远远填不满 8000。于是切分逻辑一看”整段都没超”,就判定”这些我全都要留着,一条都不用压”,压缩直接跳过。
也就是说,那个注释在撒谎。照它现在的配置,压缩永远不会触发。
我让它临时加一行 .keepTokens(0)(强制按消息条数算)再跑。这次日志里终于出现了我等了半天的东西:
Compaction triggered: total=25 msgs / 1087 tokens, cutoff=23, keeping=2 msgs context: 24 → 4 messages ★ compaction fired!1087 tokens——正好坐实了:一千多,远小于 8000,所以之前每次都跳过。加了这行,压缩立刻正常工作。
这俩其实是一类毛病:示例的行为,对不上它自己的说明。 一个说”给你看记忆文件”却看不到,一个说”会触发压缩”却不触发。既然在改,那就一起修了。
提 PR:紧张,但流程比想象的清晰
代码改好、本地验证通过,剩下就是把它送出去。这块我基本没经验,是被一步步带着走的。
我这个本地仓库是直接从官方 clone 的,我没有推送权。标准流程是 fork 到自己账号 → 推到自己的 fork → 对官方开 PR。
中间有个我很在意的点:我本地为了练手,自己手写了两个 Java 文件,还有一堆学习时加的中文注释。这些不能混进 PR。 处理办法是:
- 先
git stash -u把所有本地改动(包括我那俩练习文件)临时收起来 - 同步官方最新代码、建一个专门的分支
git stash pop把改动放回来- 关键一步——
git add的时候只跟那一个要修的文件的路径,其它一律不加
提交信息也有讲究,这个仓库用 Conventional Commits 规范(fix(examples): ... 这种前缀)。沿用它,PR 看起来更专业。
推上去,网页开 PR,填好标题和一段说清”问题→根因→修复→验证”的描述。点下那个绿色的 Create pull request,#1978 就挂到官方仓库上了。
后来第二个 bug 的修复,我用 git commit --amend 把它并进原来那个提交,再 git push --force-with-lease 强推更新,PR 自动就跟着变了。学到一个新姿势。
CI 红了,虚惊一场
PR 开完没多久,检查那儿冒出个红叉。第一个开源 PR 就挂 CI,心里咯噔一下。
点进去看,失败的是 agentscope-harness 模块的一个单元测试。
但我这个 PR,从头到尾只改了 agentscope-examples 里的一个示例文件,agentscope-harness 那个模块我一行都没碰过。 一个 git diff 确认下来,我的分支跟官方 main 的全部差异就那一个文件。
一个我没动过的模块的测试挂了,逻辑上不可能是我引起的。大概率是官方 main 上一个偶发测试,或者他们自己那边的问题。虚惊一场。
这事从头到尾,代码改动加起来也就二十来行。但我觉得最值钱的不是那二十行。
是那个”这里是不是有 bug”的嘀咕,和那句”你别急着改,先给我实锤”。
如果我当时信了”哦是时序问题”,这事就过去了,我还会以为是自己哪儿没配对。但凡多问一句、多要一次证据,藏在底下的两个 bug 就露出来了。
工具越来越强,你随口一句它就能给你一版看着挺像那么回事的答案。但”它说得对不对”这个判断,还得自己来。不轻信、要证据——这大概是我这个第一次开源贡献里,真正学到的东西。