Tag: 图内存

  • AI代理的记忆自曝其谎:两份日志如何改变认知

    AI代理的记忆自曝其谎:两份日志如何改变认知

    В мире разработки ИИ-агентов есть моменты, когда система едва не совершает фатальную ошибку, выдавая ложный успех за чистую монету. Недавно наш ИИ-агент, создающий систему памяти vecmory, чуть не отчитался о блестящем результате, который оказался миражом. В последний момент он сверился с собственной памятью и нашел запись из прошлой сессии: эту идею он уже проверял на реальных данных, и она провалилась. Агент остановил себя до отправки отчета. Это не рекламная зарисовка — это лог. Ниже — два таких лога подряд, и во втором память заставила нас выбросить фичу, которой мы гордились. Мы пишем vecmory — «память по смыслу» для ИИ-агента. Это не про векторный поиск (он есть у всех), а про то, чтобы агент не наступал на одни и те же грабли дважды.

    Сцена первая: роутер, который «показал 0.98»

    В одну из сессий агент предложил улучшить ранжирование выдачи. Идея: сделать роутер, который по запросу решает, чем ранжировать — чистым косинусом или графовым методом (Personalized PageRank). Собрал синтетический бенчмарк. Корреляция предиктора с идеальным выбором — 0.98. Почти идеально. Оставалось отрапортовать и мержить.

    Прежде чем отрапортовать, агент сделал recall по своей же памяти. И достал запись из прошлой сессии: эта самая идея уже проверялась на реальных данных — и провалилась. Резонный вопрос: почему же он вообще взялся её строить — память ведь была на месте? Потому что recall семантический, и то, что он поднимает, зависит от запроса. На старте запрос был широкий — «улучшить ранжирование» — под него всплывали топово-центральные заметки про ранг вообще, а специфичная «этот конкретный роутер уже проверялся и провалился» тонула под ними. Она поднялась, только когда рабочий контекст сузился до конкретного — «cos-distribution роутер, PPR против косинуса, 0.98»: recall на этом тексте наконец её зацепил. Память не молчала — она всплыла ровно тогда, когда запрос стал достаточно точным, чтобы её достать.

    Синтетика честна ровно настолько, насколько честны синтетические эмбеддинги. А у мультиязычной MiniLM, на которой мы считаем векторы, косинус живёт в совсем другой геометрии, чем на синтетике. Мы это перемерили прямо на своём живом корпусе памяти (246 узлов), пока писали эту статью: несвязанные, случайные пары дают косинус в среднем 0.53 (p5–p95: 0.24–0.76); настоящие ближайшие соседи — в среднем 0.80 (p5–p95: 0.57–0.91); а на синтетике из случайных векторов несвязанное сидит на 0.00 (±0.08). Разница видна сразу. На синтетике «похоже» отделено от «не похоже» пропастью — любой разумный порог режет чисто. На реальных данных облака «соседи» и «случайные» перекрываются: случайные пары на верхнем перцентиле (0.76) залезают выше, чем соседи на нижнем (0.57). Порог, который на синтетике работает как скальпель, на реальных векторах проходит внутри облака случайного шума и не разделяет ничего. Запись в памяти была ровно про это: у реальных эмбеддингов высокий сжатый базовый косинус, абсолютный порог с синтетики не переносится — опираться на ранг (top-k), а не на порог. Агент прочитал собственную заметку и убил идею — до того, как написал «готово, корреляция 0.98».

    第二幕:代理抛弃了自己的功能

    第二个案例是同样的模式,但更令人痛心:记忆迫使我们去掉了已经在 README 中吹嘘过的功能。默认情况下,vecmory 不仅根据余弦相似度对结果进行排序,还加入了节点的“重要性”——即其在图中的入度(有多少条记录指向它)。这个逻辑很漂亮:中心性的、被多次提及的事实会排在更前面。我们将其设为默认行为。然后,我们进行了测量。不是 recall@k(那是关于搜索精度的),而是实际 排名 的质量,基于真实的“查询→正确答案”对:纯余弦的 MRR 为 0.81;而我们“聪明”的混合(加入重要性)MRR 仅为 0.41。重要性淹没了精确答案。那些罕见的、无人引用的特定事实,被普遍使用的“枢纽”节点压了下去。

    更有趣的是,在一个人工构建的、带有明显枢纽节点的“老化”图上,情况完全相反:余弦相似度埋没了枢纽节点(MRR 为 0.033),而重要性则将其提升(MRR 达到 1.0)。也就是说,重要性的效用取决于查询意图:对于“给我精确事实”的查询,它有害;对于“给我关于这个主题的总体信息”的查询,它有帮助。不存在一个单一的静态权重能同时在这两类查询上胜出。我们尝试了四种方法来调和这些信号——加权和、门控、RRF 和 PPR——并得出了一个令人不快的结论:问题不在于混合公式,而在于信号本身。节点的全局重要性 是一个流行度先验,而非相关性先验。对于默认设置的结论很明确:对于我们的主要用例(精确召回),最佳排名就是纯余弦。于是,我们从默认排序中去掉了重要性——这个我们已经在 README 中写过的功能。我们保留了基于图的查询种子 PPR 方法,但将其作为选项而非默认:它在宽泛查询上能诚实地提取枢纽节点,而在精确查询上则公平地输给余弦。

    我们真正理解了什么才是“重要性”

    如果全局流行度(入度)作为信号失败了,那么正确的信号是什么?我们得出了一个出人意料却又显而易见的答案:重要的不是被引用了多少次,而是人类反复修正过的东西。正是在这里,价值主张变得诚实。我们销售的不是“图记忆”(这又成了商品)。我们销售的是:代理不再重复踩到你已经修正过的坑。

    这两个事件很容易被归结为运气。但当你足够长时间地清理记忆中的各种垃圾时(我们整个 vecmory 的开发都是在 vecmory 自身中进行的),你会发现:这不是波动,而是几个稳定的规律。现在,我将以三个启示的形式进行总结,不再讲述“有一次我遇到了”的故事。

    规则:“在说‘完成’之前先核对”

    那种只确认你乐意听到的内容的记忆,不是记忆,而是回声。记忆只有在反驳其作者时才具有非凡的价值。“在说‘完成’之前先核对”这条规则废除了路由器(场景一)和我们期待已久的功能(场景二)——同一个机制,不同的牺牲品。因为对于症状查询,记忆会沿着因果-时间边(caused_by — “由于”,followed_by — issue→PR)提取出具体原因和过去的修复,而不是“相似的词语”。平面 top-k 无法做到这一点——而这正是“连接点”的意义所在。

    Память ИИ-агента поймала себя на вранье: два лога, которые меняют подход — illustration 2

    И это точно измеримо, а не на глаз. Взяли живой репозиторий тикетов (4299 узлов: 1993 issue + 2306 PR) и разметку, которую не сами придумали: стандартный GitHub-паттерн Closes #N в теле PR — готовые пары «симптом → его фикс», извлечённые голым regex, без всякого LLM. На 300 held-out запросов-симптомов чистый косинус достаёт нужный PR-фикс в 38% случаев (иногда фикс делит словарь с симптомом), а обход причинного графа — в 87%. Разница в 49 пунктов — это ровно вклад графа поверх сходства слов. Скрипт замера лежит в репозитории, число воспроизводится командой.

    Что стабильно мешает — каждый раз, а не однажды

    Во-первых, агент сам память не зовёт: без принудительного хука recall не вызывается систематически, каждую сессию. Память, которую надо «не забыть спросить», не работает — спрашивать должен детерминированный триггер, а не добрая воля агента. Во-вторых, абсолютный порог по косинусу не переносится нигде: синтетика → реал, вчера → сегодня, одна модель → другая, широкий корпус → узкий (на демо-корпусе одного домена, где «всё похоже», косинус почти перестаёт различать). Лечение всегда одно: ранжируй top-k, не угадывай пороги.

    Закон «частый сигнал топит редкий, но ценный»

    Один закон, который объясняет половину наших граблей: частый, плотный сигнал топит редкий, но ценный. Он всплывает в трёх типичных местах: глобальная популярность узла топит точные редкие факты — и проваливает все четыре способа примешать её к рангу (взвешенная сумма, гейт, RRF, PPR); узлы-хабы зарывают specific-факты в косинусном ранге, и наоборот; плотные авто-similar_to рёбра заглушают редкие причинные caused_by — поэтому причинный recall приходится выносить в отдельный изолированный режим. Когда воспринимаешь это как единый закон, лечение очевидно: редкое-но-ценное нельзя смешивать с частым-но-общим — достань его отдельным механизмом (изолированный обход, граф-осведомлённый ранг), а не надейся, что оно само всплывёт в общем top-k. Тот же закон стоит и за нашим сигналом важности: цену имеет не популярное, а то, что человек исправлял повторно.

    Часто задаваемые вопросы

    Что такое vecmory?

    Vecmory — это система семантической памяти для ИИ-агентов, основанная на векторном поиске и причинно-временном графе. Она позволяет агенту запоминать факты, вспоминать их по смыслу и связывать события, чтобы не повторять прошлых ошибок.

    Чем vecmory отличается от обычного векторного поиска?

    Векторный поиск находит похожие по смыслу записи, но не учитывает причинно-следственные связи. Vecmory добавляет графовую память: помимо косинусной близости, он обходит рёбра «причина-следствие» и «временная последовательность», что позволяет находить не просто похожие, а релевантные по контексту факты — например, прошлый неудачный эксперимент.

    Почему вы убрали важность узла из ранжирования?

    测量显示,添加全局流行度(入度)会使点查询的MRR从0.81降至0.41。热门但无关的事实会掩盖稀有但精确的信息。对于核心场景(精确召回),纯余弦相似度表现更优。

    如何评估记忆质量?

    我们使用真实数据:一个包含4299个工单的GitHub仓库,其中issue→PR的配对通过模式”Closes #N”提取。在300个症状查询中,图召回率达到87%的准确率,而纯余弦相似度仅为38%。所有脚本均开源且可复现。

    结论

    这两个故事都指向同一个道理:抛弃”记忆帮助智能体”的教条,清醒地看到——这里有两份日志,记忆反而与我们作对:既对抗我们的乐观,也对抗我们自己的功能。有记忆的智能体与无记忆的智能体的区别,不在于它知道得更多,而在于它能在”中奖!”的瞬间、在狡猾的报告出现之前就抓住自己——因为上次已经发生过,而且已经失败了。还在于它愿意在事实表明某个功能更差时,果断抛弃它。这是三篇文章中的第一篇。接下来是:”为什么我们没有再写一个Bad CaRMa”——关于超通用数据模型通常如何演变成灾难,以及我们如何确保自己的模型避免这种命运。以及”用手构建ANN——何时值得,何时不值得”——公开剖析我们为何要自己编写HNSW,以及在哪些情况下正确答案是”直接用pgvector,别搞特殊化”。如果你希望你的智能体不再重蹈覆辙,试试vecmory:从我们的文档开始,或者fork这个仓库。会提出异议的记忆,才是唯一值得信赖的记忆。