ARTICLE · 1283388
从零打造AI助手:后台任务为什么不听我的
我在微信里告诉 Kairos:“以后代码截图放到代码笔记。”它回答“好,记下了”,可下一张代码截图还是被归到了「开发备忘」。这篇记录我怎么找到原因,又怎么两次否定 AI 给的方案,最后只改了几行代码。
Kairos 是我的个人工作与生活助手,也是一个从零手写 agent 的学习项目。上一篇给它接上了微信图片:我发图过去,它会在后台自动分类归档,再回一行回执,比如“已存档 #9【开发备忘】《Python row 字典解包说明》”。
用了一天,就碰到了这个问题。
一、现象:嘴上记下了,手上没改
当时的对话是这样的:
1. 我先发了两张截图,一张 Token 用量统计页,一张讲 Python **row 字典解包,都被归到了「开发备忘」。
2. 我说:“如果我截的图是代码的话,给它放到代码笔记分类。”
3. Kairos 回答:“好,记下了:以后你发代码截图,我归到「代码笔记」。”
4. 我又发了一张代码截图,回执是:已存档 #9【开发备忘】。
它说记下了,下一张却没照做。我把截图丢给负责开发的 Claude Code,让它查原因。
二、原因:说“记下了”的和干活的,不是同一个模型
查下来,其实有三个问题叠在一起。

一句规则在 Kairos 里走过的路:分类线程完全看不到它
第一,后台分类根本看不到记忆。 和我聊天的是主对话模型,它每一轮都会带上我的记忆,所以知道我是谁、有什么偏好。但图片分类是后台线程单独发起的一次模型请求,提示词里只有两样东西:归档员的任务说明和已有分类列表。我说过什么,它一无所知。
第二,规则存错了地方,还写歪了。 Kairos 的记忆分两层:
- 核心记忆
:一个 CORE.md文件,每条一行,每次请求都完整带上。 - 主题
:一个主题一个文件,平时只给模型看标题和用途组成的“索引”,需要时用 read_memory工具去读正文。
对话结束后,后台的记忆提取把这条规则写进了“职业背景与兴趣方向”这个主题,原文是:
归档偏好:用户要求截图为代码时,归到「代码笔记」分类(归档在开发备忘下);其他截图按自动判断分类。
放在职业背景里本来就奇怪,括号里那句“归档在开发备忘下”还和规则本身矛盾。
第三,它答应了做不到的事。 回复里有一句“需要的话我可以把它们挪过去”,可图片相关的工具只有搜索和查看两个,都是只读的,根本挪不了。
三、第一版方案:专门给图片定制一套
Claude Code 给的第一版方案是这样的:
记忆里固定建一个主题叫“图片归档规则”,让记忆提取把图片分类的要求都写到这里。 分类时专门读这个主题,拼进提示词。 再加一个 move_image工具,用来改已经归错的图。
每一条都能解决问题,但我看完觉得不对:
我当时的原话
你这个做法相当于专门为 Kairos 定制了一套图片归档的流程和规范。但我想要的是通用的东西,自然而然用通用能力就能解决掉这个。那我总不能以后每遇到一个需求,就专门给他定制一个吧?
今天是图片分类,以后有了待办整理、定时提醒,难道每个后台任务都要再配一个专属主题、写一段专属读取代码?
四、换个角度:缺的不是“图片规则”,是记忆没接到后台
被我否定后,它换了个角度重新看这件事。图片分类只是一个例子,真正的缺口在架构上:
- 主对话
:每轮都带记忆。 - 后台任务
:只带自己的任务说明,看不到任何记忆。
所以,我在对话里交代的任何偏好,后台任务都听不见。这次是图片分类,以后加的每个后台任务都会犯同样的错。

专门定制 vs 用已有的记忆能力
通用的做法只有一条原则:凡是代表我做事的模型调用,都带上同一份记忆。 记忆本来就是现成的通用能力,只是之前只接到了主对话上。
具体是两处改动。
1. 后台分类带上记忆。 创建分类线程时多传一个函数,每张图分类前调用它取一次记忆:
# services.py:组装共享服务的地方classifier = ImageClassifier( db_path, data_dir / "files", lambda: build_model(settings), memory.core, # 传函数本身,不是调用结果:每张图分类前重新读一次)
传的是函数而不是字符串,是因为记忆会变。我刚说的规则,下一张图分类时就能读到。图片包也不需要知道记忆是怎么存的,它只收到一段文字。
2. 长期指令写进核心记忆。 主题文件只在模型主动读取时才会加载,这条规则落在主题里,后台任务永远看不到。所以记忆提取的提示词也要改宽:
- write_core:用户的姓名或称呼,以及所有长期指令。 长期指令是用户要求助手以后持续遵守的做法,按意思判断,不看措辞: “以后/每次/默认/凡是……”、“遇到 X 就 Y”、“X 都放到 Y”、“别再……”、“回复时要……”都算。 包括交流方式、格式、命名和分类规则、处理某类事情的固定做法、禁止事项。 写成一条脱离上下文也能照做的规则:说清在什么情况下做什么,不写“刚才那个”“这类”之类的指代。 只对这一次有效的要求不算。
“脱离上下文也能照做”这句是专门针对那个括号写的。提取模型照抄了对话里的上下文,才写出“归档在开发备忘下”这种自相矛盾的话。
这两处改动都和图片无关。以后加任何后台任务,接上核心记忆就行,不用再为每个需求单独设计。
五、第二次纠正:索引给了也没用
第一处改动最初传的不是 memory.core,而是 memory.snapshot,和主对话用的一样:核心记忆全文,加上主题索引。
我看代码时又发现一个问题:
我当时的原话
这个模型没有记忆读取的工具,却能拿到我记忆的索引。那有什么用呢?为什么要把这个索引传给它呢?
确实没用。索引只有配合 read_memory 才有意义:模型看到索引,知道有哪个主题,再去读正文。分类模型没有这个工具,索引对它只是白占 token。更糟的是,索引的标题里写着“需要时用 read_memory 按标题读取正文”,等于叫它去调一个它没有的工具。

给什么记忆,取决于它有没有读记忆的工具
于是改成只传 memory.core。由此得出一条接后台任务的原则:
核心记忆每次都带。长期指令都在这里。 主题索引只给有 read_memory的模型。
另一种做法是也给分类模型配上 read_memory,让它按需读主题。但这样每张图可能要多请求一次模型,而分类用不上主题里的背景信息,所以没这么做。
六、最后改了什么
一共三处改动:
write_core 工具描述 | |
memory.snapshot 换成 memory.core |
另外手动清理了本地记忆:删掉主题里那行写歪的规则,在 CORE.md 里补一条“代码截图归档到「代码笔记」分类;其他图片按内容自动判断分类”。
还有几件事按“先能用,遇到再补”的原则没做:
- 规则改了会新旧并存。
核心记忆现在只能追加,哪天我改主意了,两条会同时存在。 - 刚说完规则就发图,可能赶不上。
记忆提取是在对话结束后才在后台进行的。 - 已经归错的图挪不了。
还没有改分类的工具。 - 模型乱承诺。
那句“我可以挪过去”还没有处理。
七、开发时冒出的疑问
1. 核心记忆和主题,到底有什么区别?
打个比方:核心记忆是贴在显示器上的便利贴,每次干活都看得到;主题是抽屉里的文件夹,桌上只放一张目录,要用时再拉开抽屉。便利贴贵在随时可见,但贴多了会挡屏幕,所以只放每次都用得上的东西:称呼、长期指令。职业背景、项目决定这类信息放进抽屉。
2. 主对话不是知道这条规则吗?为什么不让它来分类?
分类放在后台,是为了不耽误聊天:发图后马上提问,回答不用等几秒的分类。这是上一篇做的决定。代价是分类成了另一次独立的模型请求,主对话知道的东西,它默认都不知道。这次的修复,就是把该知道的那部分交给它。
3. 为什么传 memory.core 而不是 memory.core()?
带括号是马上读一次,得到当时的一段文字,之后记忆再怎么变,分类线程拿着的都是旧的。不带括号是把“读记忆”这个动作交过去,分类线程每处理一张图就读一次,永远是最新的。
4. 改完以后,我说完规则立刻发图,能生效吗?
不一定。顺序是:我说完话,主对话回答,然后记忆提取才在后台开始整理,要再请求一次模型。如果图片在这之前就开始分类,看到的还是旧记忆。这个先不处理,真遇到了再补。
八、写在最后
这次修的是一个很小的 bug,最后的代码改动也只有几行。值得记下来的是那两次纠正:
- 遇到具体问题,先问它是不是一类问题。
“代码截图归错”看起来是图片的问题,其实是“后台任务看不到记忆”。按具体问题修,每来一个需求就要定制一次;按一类问题修,以后的后台任务不用改。 - 给模型的每样东西,都要问它用不用得上。
索引是现成的,顺手就带上了,但没有读记忆的工具,它就只是噪音。
现在的 Kairos,后台任务也能听到我说过的话了。
一句“以后都这样”,不用再为它单独写代码。















































































