Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: 希望能加一个让模型忘记之前的记忆的命令 #4

Open
yi03 opened this issue Dec 5, 2022 · 11 comments
Open

Feature: 希望能加一个让模型忘记之前的记忆的命令 #4

yi03 opened this issue Dec 5, 2022 · 11 comments
Assignees
Labels
enhancement New feature or request

Comments

@yi03
Copy link

yi03 commented Dec 5, 2022

有时候反复问AI类似的问题,AI就会陷入死胡同,然后反复复读类似的话。希望能加一个命令,发了之后就让它忘记之前的记忆。
https://beta.openai.com/docs/api-reference/completions/create#completions/create-stop
查了查API,不知道这个接口是不是干这个的。
谢谢!

@TomLBZ TomLBZ added the enhancement New feature or request label Dec 5, 2022
@TomLBZ TomLBZ self-assigned this Dec 5, 2022
@TomLBZ
Copy link
Owner

TomLBZ commented Dec 5, 2022

这个 Feature Request 戳到了一个大难题。

机器人的记忆的确是个难点,这是因为OpenAI的接口是无状态(Stateless)的,毕竟GPT系列模型都没有状态。因此,记忆部分是咱利用prompt engineering模拟出来的,原理是每次都利用不同状态的记忆生成额外的上下文,帮助无状态AI作出“好像有记忆一样”的回答。因此,如果记忆中相对高频率地出现某种类似的话(相对频率高于正常对话),AI就会“认为”自己“学到了规律/找到了捷径”,进而陷入死胡同。

这个问题我目前还没有很好的解决办法,需要一些时间思考研究。目前有4个感觉都不太好的基本思路,先扔在这里抛砖引玉一下:

  1. 在把语料加入记忆之前额外调用一次API判断其主题或关键词,并与已经存在的语料比较。生成上下文时每个主题出现频次固定为1。优点:可以很大程度上解决死胡同问题。缺点:需要花费更高的Token数量,并且记忆的体积会大大增加(字典体积提升常数倍),或者需要依赖额外的数据库。
  2. 取消“字面记忆”,直接将新的语料转换成总结或者关键词。每次只使用设置中的示例对话维持人设,而不刻意维持上下文。优点:可以完全解决死胡同问题。缺点:无法正确回答“刚才我们都说了什么话?”这类完全取决于上下文的问题。
  3. 增加一个指令,例如“/忘 xxxx”,来清除包含字符串“xxxx”的记忆。优点:实现起来简单。缺点:其实没有解决死胡同问题,只能每次机器人进入复读状态的时候都让用户再输一次这个指令,而且可能意外遗忘与字符串相关的其他记忆。
  4. 在每次生成的上下文后附加上示例对话,而生成总结时排除示例对话。优点:实现相对容易,部分程度上能解决复读。缺点:消耗的Token数量几乎翻倍,而且无法根绝死胡同问题。

如果你或者其他人还有其他更好的想法,欢迎在这里继续回复,谢谢!

@yi03
Copy link
Author

yi03 commented Dec 6, 2022

这个 Feature Request 戳到了一个大难题。

机器人的记忆的确是个难点,这是因为OpenAI的接口是无状态(Stateless)的,毕竟GPT系列模型都没有状态。因此,记忆部分是咱利用prompt engineering模拟出来的,原理是每次都利用不同状态的记忆生成额外的上下文,帮助无状态AI作出“好像有记忆一样”的回答。因此,如果记忆中相对高频率地出现某种类似的话(相对频率高于正常对话),AI就会“认为”自己“学到了规律/找到了捷径”,进而陷入死胡同。

这个问题我目前还没有很好的解决办法,需要一些时间思考研究。目前有4个感觉都不太好的基本思路,先扔在这里抛砖引玉一下:

  1. 在把语料加入记忆之前额外调用一次API判断其主题或关键词,并与已经存在的语料比较。生成上下文时每个主题出现频次固定为1。优点:可以很大程度上解决死胡同问题。缺点:需要花费更高的Token数量,并且记忆的体积会大大增加(字典体积提升常数倍),或者需要依赖额外的数据库。
  2. 取消“字面记忆”,直接将新的语料转换成总结或者关键词。每次只使用设置中的示例对话维持人设,而不刻意维持上下文。优点:可以完全解决死胡同问题。缺点:无法正确回答“刚才我们都说了什么话?”这类完全取决于上下文的问题。
  3. 增加一个指令,例如“/忘 xxxx”,来清除包含字符串“xxxx”的记忆。优点:实现起来简单。缺点:其实没有解决死胡同问题,只能每次机器人进入复读状态的时候都让用户再输一次这个指令,而且可能意外遗忘与字符串相关的其他记忆。
  4. 在每次生成的上下文后附加上示例对话,而生成总结时排除示例对话。优点:实现相对容易,部分程度上能解决复读。缺点:消耗的Token数量几乎翻倍,而且无法根绝死胡同问题。

如果你或者其他人还有其他更好的想法,欢迎在这里继续回复,谢谢!

提issue的时候没看您的代码,不好意思。今天看了一下您的代码,我的理解是texts过长了就总结成summaries,summaries过长了就总结成topics,每次回复都会附带上最近的texts, summaries和topics。
我之前一直以为是openai有记忆相关的接口,没想到是这么实现的,好机智。

其实我的需求是,有一个reset指令,输入之后就忘记和这个人说过的所有话,如果能选择是忘记texts、summaries、topics中的某几项记忆就更好了,比如发送指令删除texts和summaries中关于数学的记忆。和您的办法3比较像。
另外根据我的观察,复读似乎主要是因为最近的texts里有几乎完全一样、只有某些关键词不一样的话(有些群友就是爱这么问)。所以我把textMemoryLength改小似乎对复读现象有改善。
又想了一下,意识到summary的记忆一段时间内每次向openai提交的都一样,所以似乎summary的记忆更可能导致复读。
举个例子,比如我和bot聊了很多数学相关的话题,之后再问她其他领域的问题,她也老拐到数学上去,如果能选择删除texts和summaries中关于数学的记忆就好了,或者只保留一两条关于数学的记忆也可以。
我的想法是找一下新消息和最近几条文本的重复度,重复度就用最基础的找公共子串的算法来算,如果重复度过高就只记录新消息不同的关键词。

@TomLBZ
Copy link
Owner

TomLBZ commented Dec 6, 2022

其实我的需求是,有一个reset指令,输入之后就忘记和这个人说过的所有话,如果能选择是忘记texts、summaries、topics中的某几项就更好了。和您的办法3比较像。因为我的大多数群友和bot对话话题都挺跳跃,不太会期望bot记住太过久远的对话。 另外根据我的观察,复读似乎主要是因为最近的texts里有几乎完全一样、只有某些关键词不一样的话(有些群友就是爱这么问)。所以我把textMemoryLength改小似乎对复读现象有改善。 又仔细研究了研究,意识到summary的记忆一段时间内每次向openai提交的都一样,所以似乎summary的记忆更可能导致复读。 我的想法是找一下新消息和最近几条文本的重复度,重复度就用最基础的找公共子串的算法来算,如果重复度过高就只记录新消息不同的关键词。

多谢反馈,我明白你的需求了,下一个版本会加上一条重置记忆的指令,用户可以用这条指令选择性清除bot和自己的某一类记忆o( ̄▽ ̄)ブ

补充:
总结记忆之所以一段时间内(等于字面记忆的长度)向openai提交的完全一样,是为了节省Token。理论上更好的办法是每次有新消息都更新一个消息队列,然后用队列内的消息生成总结(正如现在对关键词做的一样)。但是因为总结远远比关键词长,而且消息更新的频率实际上非常高,所以这种做法会快速花掉过多的Token,因此没有选择那样实现。
之所以存储了逐字的记忆而不是只存储关键词,是因为对于无状态的OpenAI来说,逐字的记忆可以保留说话的语气、人设、情绪、措辞等信息,有助于AI维持自洽的对话。这也是为什么不论对话是什么内容,记忆永远是逐字优先。但归根结底Prompt的长度很有限,能操作的空间因此并不大,因此采用了一种折衷的办法——对于比较久远或者过于久远的消息,分别利用总结与关键词提高信息密度。在这里,总结与关键词负责告诉OpenAI内容上的信息,而字面记忆除了内容上,还负责着措辞与语气上的信息。

flag:
我争取在下下个版本找到一个更好的在记忆中解决复读的办法┏┛墓┗┓

@yi03
Copy link
Author

yi03 commented Dec 6, 2022

其实我的需求是,有一个reset指令,输入之后就忘记和这个人说过的所有话,如果能选择是忘记texts、summaries、topics中的某几项就更好了。和您的办法3比较像。因为我的大多数群友和bot对话话题都挺跳跃,不太会期望bot记住太过久远的对话。 另外根据我的观察,复读似乎主要是因为最近的texts里有几乎完全一样、只有某些关键词不一样的话(有些群友就是爱这么问)。所以我把textMemoryLength改小似乎对复读现象有改善。 又仔细研究了研究,意识到summary的记忆一段时间内每次向openai提交的都一样,所以似乎summary的记忆更可能导致复读。 我的想法是找一下新消息和最近几条文本的重复度,重复度就用最基础的找公共子串的算法来算,如果重复度过高就只记录新消息不同的关键词。

多谢反馈,我明白你的需求了,下一个版本会加上一条重置记忆的指令,用户可以用这条指令选择性清除bot和自己的某一类记忆o( ̄▽ ̄)ブ

补充: 总结记忆之所以一段时间内(等于字面记忆的长度)向openai提交的完全一样,是为了节省Token。理论上更好的办法是每次有新消息都更新一个消息队列,然后用队列内的消息生成总结(正如现在对关键词做的一样)。但是因为总结远远比关键词长,而且消息更新的频率实际上非常高,所以这种做法会快速花掉过多的Token,因此没有选择那样实现。 之所以存储了逐字的记忆而不是只存储关键词,是因为对于无状态的OpenAI来说,逐字的记忆可以保留说话的语气、人设、情绪、措辞等信息,有助于AI维持自洽的对话。这也是为什么不论对话是什么内容,记忆永远是逐字优先。但归根结底Prompt的长度很有限,能操作的空间因此并不大,因此采用了一种折衷的办法——对于比较久远或者过于久远的消息,分别利用总结与关键词提高信息密度。在这里,总结与关键词负责告诉OpenAI内容上的信息,而字面记忆除了内容上,还负责着措辞与语气上的信息。

flag: 我争取在_下下个版本_找到一个更好的在记忆中解决复读的办法┏┛墓┗┓

(在您回复我的上一条前我刚好在编辑,我在这里重说一遍我更新的话吧。)
举个例子,比如我和bot聊了很多数学相关的话题,之后再问她其他领域的问题,她也老拐到数学上去,如果能选择删除texts和summaries中关于数学的记忆就好了,或者只保留一两条关于数学的记忆也可以。

另外又有一个想法,就是发送list指令,能列出目前的所有记忆,然后手动选择删除某些记忆。
或者再进一步,可以移植记忆。比如直接发送消息指定texts, summaries和topics的内容。
虽然这么做就有点太像bot了,不过感觉可能还挺实用(

@TomLBZ
Copy link
Owner

TomLBZ commented Dec 6, 2022

举个例子,比如我和bot聊了很多数学相关的话题,之后再问她其他领域的问题,她也老拐到数学上去

多谢反馈!这个观察很有价值。我会想办法解决这个问题。雀食,哪怕以前聊过很多数学,新的话题也不能总是拐到数学上(好像现实中热爱数学的人似乎也会这样子拐话题呢(划掉

或者再进一步,可以移植记忆。比如直接发送消息指定texts, summaries和topics的内容。
虽然这么做就有点太像bot了,不过感觉可能还挺实用(

的确太像bot了……但是移植记忆似乎是有用的,比如迁移bot的时候,如果bot的部署人可以导出全部的记忆,ta就不会忘了自己,也不会忘了以前对话过的用户。这个倒是可以实现一下,但是优先级暂时比较靠后,可能要多等一等。

@yi03
Copy link
Author

yi03 commented Feb 12, 2023

这个 Feature Request 戳到了一个大难题。

机器人的记忆的确是个难点,这是因为OpenAI的接口是无状态(Stateless)的,毕竟GPT系列模型都没有状态。因此,记忆部分是咱利用prompt engineering模拟出来的,原理是每次都利用不同状态的记忆生成额外的上下文,帮助无状态AI作出“好像有记忆一样”的回答。因此,如果记忆中相对高频率地出现某种类似的话(相对频率高于正常对话),AI就会“认为”自己“学到了规律/找到了捷径”,进而陷入死胡同。

这个问题我目前还没有很好的解决办法,需要一些时间思考研究。目前有4个感觉都不太好的基本思路,先扔在这里抛砖引玉一下:

  1. 在把语料加入记忆之前额外调用一次API判断其主题或关键词,并与已经存在的语料比较。生成上下文时每个主题出现频次固定为1。优点:可以很大程度上解决死胡同问题。缺点:需要花费更高的Token数量,并且记忆的体积会大大增加(字典体积提升常数倍),或者需要依赖额外的数据库。
  2. 取消“字面记忆”,直接将新的语料转换成总结或者关键词。每次只使用设置中的示例对话维持人设,而不刻意维持上下文。优点:可以完全解决死胡同问题。缺点:无法正确回答“刚才我们都说了什么话?”这类完全取决于上下文的问题。
  3. 增加一个指令,例如“/忘 xxxx”,来清除包含字符串“xxxx”的记忆。优点:实现起来简单。缺点:其实没有解决死胡同问题,只能每次机器人进入复读状态的时候都让用户再输一次这个指令,而且可能意外遗忘与字符串相关的其他记忆。
  4. 在每次生成的上下文后附加上示例对话,而生成总结时排除示例对话。优点:实现相对容易,部分程度上能解决复读。缺点:消耗的Token数量几乎翻倍,而且无法根绝死胡同问题。

如果你或者其他人还有其他更好的想法,欢迎在这里继续回复,谢谢!

拍脑袋想到一个保持记忆的办法。
把所有历史对话都存起来,每个对话都提取关键词再embedding存起来,然后对话的时候把输入的对话也提取关键词embedding,然后搜索历史对话中词向量相似度最高的三条对话作为related memory。用related memory来代替现在summary memory,每次给openai发送text memory, related memory, topic memory。
提取关键词embedding这一步使用本地计算,不调用openai接口。
我对ai是外行,可能某些概念理解有误。

@TomLBZ
Copy link
Owner

TomLBZ commented Mar 6, 2023

拍脑袋想到一个保持记忆的办法。
把所有历史对话都存起来,每个对话都提取关键词再embedding存起来,然后对话的时候把输入的对话也提取关键词embedding,然后搜索历史对话中词向量相似度最高的三条对话作为related memory。用related memory来代替现在summary memory,每次给openai发送text memory, related memory, topic memory。
提取关键词embedding这一步使用本地计算,不调用openai接口。
我对ai是外行,可能某些概念理解有误。

目前的版本(v2.0.1)已经重构到用embedding保存记忆的模式,但是embeddings还是用的openai接口。等一波可以本地算embedding vector的库。至于忘记记忆相关的功能,我倒是已经设想好了实现思路,就是缺时间写代码。争取下周再发布一个更新

@yi03
Copy link
Author

yi03 commented Mar 7, 2023

https://v2ex.com/t/921750
看到和自己思路一模一样的实现,虽然也是很自然的思路了🤣

话说大佬有没有试过不提取关键词,整句话直接做embedding,我看那个链接里有人发的这个链接是这么做的:https://github.com/openai/openai-cookbook/blob/main/apps/web-crawl-q-and-a/web-qa.ipynb

反正本质就是一个本地的搜索引擎,办法应该挺多的(

@TomLBZ
Copy link
Owner

TomLBZ commented Mar 7, 2023

https://v2ex.com/t/921750 看到和自己思路一模一样的实现,虽然也是很自然的思路了🤣

话说大佬有没有试过不提取关键词,整句话直接做embedding,我看那个链接里有人发的这个链接是这么做的:https://github.com/openai/openai-cookbook/blob/main/apps/web-crawl-q-and-a/web-qa.ipynb

我这里embedding就是整句做的,也是整句存储的,但是之所以还要提取关键词,是为了对下一轮回复进行启发。我举个例子:
我说:唐僧和孙悟空都是西游记的人物。其中关键词有["唐僧","孙悟空","西游记","人物"]
根据向量余弦搜索,假设查询到了两个match["孙悟空保护唐僧西天取经","西游记是我国四大名著之一"],则这里多出了两个从未出现过的关键词["西天取经","四大名著"]。它没有在原句的关键词组中出现。
于是我们舍弃第一组match,进行第二次余弦搜索,假设有句话"齐天大圣在西天取经之前曾经大闹天宫",这句话的余弦距离与我的输入相差较大,不易被搜索到。而第二次搜索时使用关键词进行了预选,于是提高了搜索到的概率。
这个行为的目的是在数据量极大、余弦距离过于集中的时候引入发散性。如果太过发散,ChatGPT也会帮我们在最后合成的时候进行修正。

@yi03
Copy link
Author

yi03 commented Apr 28, 2023

https://arxiv.org/abs/2304.13343
看到个这个论文,和现在这个插件使用的思路很像,多加了一个 summary of memory 和 recency score。
也许可以抄一抄他的prompt,有空的话也可以试试他的 summary of memory 和 recency score。
(论文原作者的代码仓库刚才不知道为啥被删了,搜到了一个fork: https://github.com/toufunao/SCM4LLMs)

不过他这篇论文每个对话会请求 openai 三次,前两个请求是问是否使用 memory ,第三个请求是回复,会增大响应延迟。我想到的解决办法是 是否使用 memory 和 是否使用 summary of memory 这两个问题合并成一个问题问,还有就是 gpt-3.5-turbo 现在延迟比较高,也许这种简单的任务可以交给 claude 或者其他速度快的模型。

论文机翻:
使用自控记忆系统释放大规模语言模型的无限长度输入能力.pdf

@yi03
Copy link
Author

yi03 commented May 15, 2023

https://github.com/imartinez/privateGPT
另一个思路类似但不用联网的库。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants