夜雨聆风学习资料网

ARTICLE · 1283388

从零打造AI助手:后台任务为什么不听我的

从零打造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,让它按需读主题。但这样每张图可能要多请求一次模型,而分类用不上主题里的背景信息,所以没这么做。

六、最后改了什么

一共三处改动:

改动
具体做了什么
后台图片分类带上记忆
分类请求多一条 system 消息,放记忆内容
长期指令写进核心记忆
改记忆提取的提示词和 write_core 工具描述
只带核心记忆
把 memory.snapshot 换成 memory.core

另外手动清理了本地记忆:删掉主题里那行写歪的规则,在 CORE.md 里补一条“代码截图归档到「代码笔记」分类;其他图片按内容自动判断分类”。

还有几件事按“先能用,遇到再补”的原则没做:

  • 规则改了会新旧并存。
     核心记忆现在只能追加,哪天我改主意了,两条会同时存在。
  • 刚说完规则就发图,可能赶不上。
     记忆提取是在对话结束后才在后台进行的。
  • 已经归错的图挪不了。
     还没有改分类的工具。
  • 模型乱承诺。
     那句“我可以挪过去”还没有处理。

七、开发时冒出的疑问

1. 核心记忆和主题,到底有什么区别?

打个比方:核心记忆是贴在显示器上的便利贴,每次干活都看得到;主题是抽屉里的文件夹,桌上只放一张目录,要用时再拉开抽屉。便利贴贵在随时可见,但贴多了会挡屏幕,所以只放每次都用得上的东西:称呼、长期指令。职业背景、项目决定这类信息放进抽屉。

2. 主对话不是知道这条规则吗?为什么不让它来分类?

分类放在后台,是为了不耽误聊天:发图后马上提问,回答不用等几秒的分类。这是上一篇做的决定。代价是分类成了另一次独立的模型请求,主对话知道的东西,它默认都不知道。这次的修复,就是把该知道的那部分交给它。

3. 为什么传 memory.core 而不是 memory.core()?

带括号是马上读一次,得到当时的一段文字,之后记忆再怎么变,分类线程拿着的都是旧的。不带括号是把“读记忆”这个动作交过去,分类线程每处理一张图就读一次,永远是最新的。

4. 改完以后,我说完规则立刻发图,能生效吗?

不一定。顺序是:我说完话,主对话回答,然后记忆提取才在后台开始整理,要再请求一次模型。如果图片在这之前就开始分类,看到的还是旧记忆。这个先不处理,真遇到了再补。

八、写在最后

这次修的是一个很小的 bug,最后的代码改动也只有几行。值得记下来的是那两次纠正:

  • 遇到具体问题,先问它是不是一类问题。
     “代码截图归错”看起来是图片的问题,其实是“后台任务看不到记忆”。按具体问题修,每来一个需求就要定制一次;按一类问题修,以后的后台任务不用改。
  • 给模型的每样东西,都要问它用不用得上。
     索引是现成的,顺手就带上了,但没有读记忆的工具,它就只是噪音。

现在的 Kairos,后台任务也能听到我说过的话了。

一句“以后都这样”,不用再为它单独写代码。

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料