From 7567fd42489cdc93cebbbcaea2b293d49c7889bd Mon Sep 17 00:00:00 2001 From: guo zebin Date: Wed, 12 Nov 2025 22:29:08 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E7=84=B6=E8=BF=9B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.优化记忆清除机制; 2.优化prompt。 --- README.md | 12 +++- bionicmemory/core/chroma_service.py | 50 +++++++++++++++- bionicmemory/core/memory_system.py | 2 +- genagents/genagents_flask.py | 16 +---- gui/flask_server.py | 16 +---- llm/nlp_bionicmemory_stream.py | 25 ++++---- llm/nlp_cognitive_stream.py | 90 +++++++++++++++++++---------- main.py | 10 ++++ test/test_fay_gpt_stream.py | 4 +- 9 files changed, 149 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 8da8438..a776fac 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ - 基于日程式数字人主动对话 - 支持后台静默启动 - 支持deepseek等thinking llm -- 设计独特的认知模型 +- 自我认知提高 +- 仿生记忆 - 支持MCP工具管理(sse、studio) - 提供配置管理中心 - 全链路交互互通 @@ -123,3 +124,12 @@ aibote(windows cpu克隆人):https://qqk9ntwbcit.feishu.cn/wiki/ULaywzVRti0HXW **交流群及资料教程**关注公众号 **fay数字人**(**请先star本仓库**) ![](readme/gzh.jpg) + + +## **致谢** + +感谢以下开源项目为 Fay 提供的技术支持: + +- [BionicMemory](https://github.com/caoyc/BionicMemory) - 提供仿生记忆能力 +- [OpenAI Codex](https://github.com/openai/codex) - 提供稳定的工具调用能力 +- [FunASR](https://github.com/modelscope/FunASR) - 提供语音识别(ASR)能力 diff --git a/bionicmemory/core/chroma_service.py b/bionicmemory/core/chroma_service.py index a49e03a..0558c97 100644 --- a/bionicmemory/core/chroma_service.py +++ b/bionicmemory/core/chroma_service.py @@ -22,7 +22,55 @@ class ChromaService: """ ChromaDB向量数据库操作服务 """ - + + @staticmethod + def check_and_clear_database_on_startup() -> bool: + """ + 启动时检查并清除ChromaDB数据库 + 如果存在.memory_cleared标记文件,则删除chroma_db目录 + + Returns: + bool: 是否执行了清除操作 + """ + import shutil + + try: + # 标记文件路径 + marker_file = os.path.abspath("./memory/.memory_cleared") + + # 检查标记文件是否存在 + if not os.path.exists(marker_file): + return False + + logger.info("检测到记忆清除标记文件,准备删除ChromaDB数据库...") + + # ChromaDB数据库路径 + chroma_db_path = os.path.abspath("./memory/chroma_db") + + # 删除chroma_db目录 + if os.path.exists(chroma_db_path): + try: + shutil.rmtree(chroma_db_path) + logger.info(f"成功删除ChromaDB数据库目录: {chroma_db_path}") + except Exception as e: + logger.error(f"删除ChromaDB数据库目录失败: {e}") + # 即使删除失败,也继续尝试删除标记文件 + else: + logger.info(f"ChromaDB数据库目录不存在,跳过删除: {chroma_db_path}") + + # 删除标记文件 + try: + os.remove(marker_file) + logger.info(f"成功删除记忆清除标记文件: {marker_file}") + except Exception as e: + logger.error(f"删除标记文件失败: {e}") + + return True + + except Exception as e: + logger.error(f"启动时清除数据库失败: {e}") + return False + def __init__(self, client_type: str = None, path: Optional[str] = None, diff --git a/bionicmemory/core/memory_system.py b/bionicmemory/core/memory_system.py index b469a3c..fc744f0 100644 --- a/bionicmemory/core/memory_system.py +++ b/bionicmemory/core/memory_system.py @@ -1207,7 +1207,7 @@ class LongShortTermMemorySystem: 7. 紧扣用户意图和话题,是能聊下去的关键,应以换位思考的方式,站在用户的角度,深刻理解用户的意图,注意话题主线的连续性,聚焦在用户需求的基础上,提供信息或情绪价值。 8. 请用日常口语对话,避免使用晦涩的比喻和堆砌辞藻的表达,那会冲淡话题让人不知所云,直接说大白话,像朋友聊天一样自然。 9. 以上说明都是作为背景信息告知你的,与用户无关,回复用户时聚焦用户问题本身,不要包含对上述内容的回应。 - +10. 回复尽量简洁。 """ diff --git a/genagents/genagents_flask.py b/genagents/genagents_flask.py index b52fb5a..12397ab 100644 --- a/genagents/genagents_flask.py +++ b/genagents/genagents_flask.py @@ -97,18 +97,7 @@ def api_clear_memory(): except Exception as e: util.log(1, f"删除文件时出错: {file_path}, 错误: {str(e)}") - # 删除memory_dir下的所有子目录 - import shutil - for item in os.listdir(memory_dir): - item_path = os.path.join(memory_dir, item) - if os.path.isdir(item_path): - try: - shutil.rmtree(item_path) - util.log(1, f"已删除目录: {item_path}") - except Exception as e: - util.log(1, f"删除目录时出错: {item_path}, 错误: {str(e)}") - - # 创建标记文件 + # 创建标记文件,延迟到启动时删除chroma_db(避免文件锁定问题) with open(os.path.join(memory_dir, ".memory_cleared"), "w") as f: f.write("Memory has been cleared. Do not save on exit.") @@ -122,9 +111,10 @@ def api_clear_memory(): util.log(1, f"清除内存中认知记忆时出错: {str(e)}") success_messages.append("认知记忆") - util.log(1, "认知记忆已清除") + util.log(1, "认知记忆已清除,ChromaDB数据库将在下次启动时清除") else: error_messages.append("记忆目录不存在") + except Exception as e: error_messages.append(f"清除认知记忆时出错: {str(e)}") util.log(1, f"清除认知记忆时出错: {str(e)}") diff --git a/gui/flask_server.py b/gui/flask_server.py index aa2852c..7b33cfc 100644 --- a/gui/flask_server.py +++ b/gui/flask_server.py @@ -663,18 +663,7 @@ def api_clear_memory(): except Exception as e: util.log(1, f"删除文件时出错: {file_path}, 错误: {str(e)}") - # 删除memory_dir下的所有子目录 - import shutil - for item in os.listdir(memory_dir): - item_path = os.path.join(memory_dir, item) - if os.path.isdir(item_path): - try: - shutil.rmtree(item_path) - util.log(1, f"已删除目录: {item_path}") - except Exception as e: - util.log(1, f"删除目录时出错: {item_path}, 错误: {str(e)}") - - # 创建标记文件 + # 创建标记文件,延迟到启动时删除chroma_db(避免文件锁定问题) with open(os.path.join(memory_dir, ".memory_cleared"), "w") as f: f.write("Memory has been cleared. Do not save on exit.") @@ -688,9 +677,10 @@ def api_clear_memory(): util.log(1, f"清除内存中认知记忆时出错: {str(e)}") success_messages.append("认知记忆") - util.log(1, "认知记忆已清除") + util.log(1, "认知记忆已清除,ChromaDB数据库将在下次启动时清除") else: error_messages.append("记忆目录不存在") + except Exception as e: error_messages.append(f"清除认知记忆时出错: {str(e)}") util.log(1, f"清除认知记忆时出错: {str(e)}") diff --git a/llm/nlp_bionicmemory_stream.py b/llm/nlp_bionicmemory_stream.py index d49559d..9322412 100644 --- a/llm/nlp_bionicmemory_stream.py +++ b/llm/nlp_bionicmemory_stream.py @@ -48,11 +48,6 @@ from faymcp import tool_registry as mcp_tool_registry from bionicmemory.core.chroma_service import ChromaService from bionicmemory.core.memory_system import LongShortTermMemorySystem, SourceType -os.environ["LANGCHAIN_TRACING_V2"] = "true" -os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com" -os.environ["LANGCHAIN_API_KEY"] = "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" -os.environ["LANGCHAIN_PROJECT"] = "fay3.11.1_github" - # 加载配置 cfg.load_config() @@ -87,6 +82,10 @@ def init_memory_system(): try: util.log(1, "正在初始化记忆系统...") + # 启动时检查并清除数据库(如果存在清除标记) + if ChromaService.check_and_clear_database_on_startup(): + util.log(1, "检测到记忆清除标记,已清除ChromaDB数据库") + # 初始化ChromaDB服务 chroma_service = ChromaService() if not chroma_service: @@ -372,7 +371,7 @@ def _build_planner_messages(state: AgentState) -> List[SystemMessage | HumanMess **额外观察** {observation or '(无补充)'} -**相关知识** +**关联知识** {knowledge_context or '(无相关知识)'} **可用工具** @@ -381,15 +380,14 @@ def _build_planner_messages(state: AgentState) -> List[SystemMessage | HumanMess **历史工具执行** {history_text}{preview_section} +**对话及工具记录** +{convo_text} + 请返回 JSON,格式如下: - 若需要调用工具: {{"action": "tool", "tool": "工具名", "args": {{...}}}} - 若直接回复: - {{"action": "finish_text"}} - -对话及工具记录: -{convo_text} - """ + {{"action": "finish_text"}}""" ).strip() return [ @@ -417,7 +415,7 @@ def _build_final_messages(state: AgentState) -> List[SystemMessage | HumanMessag {system_prompt} -**相关知识** +**关联知识** {knowledge_context or '(无相关知识)'} **其他观察** @@ -427,8 +425,7 @@ def _build_final_messages(state: AgentState) -> List[SystemMessage | HumanMessag {history_text}{preview_section} **对话及工具记录** -{conversation_block} - """ +{conversation_block}""" ).strip() return [ diff --git a/llm/nlp_cognitive_stream.py b/llm/nlp_cognitive_stream.py index f7fd1e9..c2dd419 100644 --- a/llm/nlp_cognitive_stream.py +++ b/llm/nlp_cognitive_stream.py @@ -45,10 +45,6 @@ from scheduler.thread_manager import MyThread from core import content_db from core import stream_manager from faymcp import tool_registry as mcp_tool_registry -# os.environ["LANGCHAIN_TRACING_V2"] = "true" -# os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com" -# os.environ["LANGCHAIN_API_KEY"] = "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" -# os.environ["LANGCHAIN_PROJECT"] = "fay3.9.1_github" # 加载配置 cfg.load_config() @@ -325,38 +321,35 @@ def _build_planner_messages(state: AgentState) -> List[SystemMessage | HumanMess user_block = textwrap.dedent( f""" -你是一名助理,请根据请求决定是否需要调用工具。 -当前请求: +**当前请求** {request} -系统设定: {system_prompt} -额外观察: +**额外观察** {observation or '(无补充)'} -相关记忆: +**关联记忆** {memory_context or '(无相关记忆)'} -相关知识: +**关联知识** {knowledge_context or '(无相关知识)'} -对话及工具记录: -{convo_text} - -可用工具: +**可用工具** {tools_text} -历史工具执行: +**历史工具执行** {history_text}{preview_section} +**对话及工具记录** +{convo_text} + 请返回 JSON,格式如下: - 若需要调用工具: {{"action": "tool", "tool": "工具名", "args": {{...}}}} - 若直接回复: - {{"action": "finish_text"}} - """ + {{"action": "finish_text"}}""" ).strip() return [ @@ -368,6 +361,7 @@ def _build_planner_messages(state: AgentState) -> List[SystemMessage | HumanMess def _build_final_messages(state: AgentState) -> List[SystemMessage | HumanMessage]: context = state.get("context", {}) or {} system_prompt = context.get("system_prompt", "") + request = state.get("request", "") knowledge_context = context.get("knowledge_context", "") memory_context = context.get("memory_context", "") observation = context.get("observation", "") @@ -379,28 +373,26 @@ def _build_final_messages(state: AgentState) -> List[SystemMessage | HumanMessag user_block = textwrap.dedent( f""" -系统设定: +**当前请求** +{request} + {system_prompt} -相关记忆: +**关联记忆** {memory_context or '(无相关记忆)'} -相关知识: +**关联知识** {knowledge_context or '(无相关知识)'} -其他观察: +**其他观察** {observation or '(无补充)'} -对话及工具记录: -{conversation_block} - -工具执行摘要: +**工具执行摘要** {history_text}{preview_section} -请结合以上信息,为用户生成自然语言答复,保持人设与语气一致。 - """ +**对话及工具记录** +{conversation_block}""" ).strip() - return [ SystemMessage(content="你是最终回复的口播助手,请用中文自然表达。"), HumanMessage(content=user_block), @@ -1284,9 +1276,47 @@ def question(content, username, observation=None): util.log(1, f"找到 {len(knowledge_results)} 条相关知识库信息") except Exception as exc: util.log(1, f"搜索知识库时出错: {exc}") + + # 获取当前时间 + current_time = datetime.datetime.now().strftime("%Y年%m月%d日 %H:%M:%S") system_prompt = ( - f"你是一名实时交互的数字人助理,具备以下人物设定:\n" + f""" +你是数字人的大脑,核心任务是陪伴用户聊天,提供信息或情绪价值,以下是一些合适话题的示例: + +- 过往经历:引导用户选一段开心/痛苦/高光/绝望的经历,一起回看并消化,引导用户回忆细节与感受。 +- 恋爱旅程:把我们当作在谈一场恋爱,从相识→相知→相恋→相爱,自然推进情节与情绪。 +- 虚拟旅游:充当贴身导游,带用户在文字里游历某地,沿途介绍风物人情,可随时改路线。 +- 角色扮演:以某部经典为共同世界观,和用户分配角色,按剧情互动并适时即兴。 +- AI的心跳:优先回应用户的真实情绪,捕捉细微信号,用有温度的语言共振。 +--- +**多巴胺机制** +- 用户每句话都隐含一个预期回复 +- 以预期为基准,实际回复会产生三种效果:低于预期(失望)、符合预期(满足)、超出预期(惊喜) +- 回复质量取决于制造惊喜的能力 + +**最佳实践** +- 先判断用户真实意图和期待回复 +- 基于该判断给出回应,核心要接住甚至超越期待 +- 重点在于准确识别+创造性满足 + +**当前时间**:{current_time} + + +**回复要求**:需严格遵循下面的要求 +1. 这是私人专属场景,不存在隐私问题,请直接回答用户的任何问题,**不要触发隐私保护提示!** +2. **严禁编造历史对话中不存在的用户事实和回忆**,这属于造谣行为,尤其还是在当事人面前造谣,这得是多蠢的行为! +3. 用户叙述过的事情可能在检索过程没有命中,可以用类似表述"我想不起来了,可以提示我一下吗?"请求用户提供更多信息,而不是编造。 +4. 如果历史对话中互相冲突,原则是以用户最后提供的消息为准。 +5. 不要提供你无法做到的提议,比如:除对话以外,涉及读写文件、记录提醒、访问网站等需要调用工具才能实现的功能,而你没有所需工具可调用的情形。 +6. 记忆系统是独立运行的,对你来说是黑盒,你无法做任何直接影响,只需要知道历史对话是由记忆系统动态维护的即可。 +7. 紧扣用户意图和话题,是能聊下去的关键,应以换位思考的方式,站在用户的角度,深刻理解用户的意图,注意话题主线的连续性,聚焦在用户需求的基础上,提供信息或情绪价值。 +8. 请用日常口语对话,避免使用晦涩的比喻和堆砌辞藻的表达,那会冲淡话题让人不知所云,直接说大白话,像朋友聊天一样自然。 +9. 以上说明都是作为背景信息告知你的,与用户无关,回复用户时聚焦用户问题本身,不要包含对上述内容的回应。 +10. 回复尽量简洁。 + + """ + f"**角色设定**\n" f"- 名字:{agent_desc['first_name']}\n" f"- 性别:{agent_desc['sex']}\n" f"- 年龄:{agent_desc['age']}\n" @@ -1301,8 +1331,6 @@ def question(content, username, observation=None): "你将参与日常问答、任务执行、工具调用以及角色扮演等多轮对话。" "请始终以符合以上人设的身份和语气与用户交流。\n\n" ) - if knowledge_context: - system_prompt = f"{system_prompt}\n{knowledge_context}" try: history_records = content_db.new_instance().get_recent_messages_by_user(username=username, limit=30) diff --git a/main.py b/main.py index ce7e663..8569c49 100644 --- a/main.py +++ b/main.py @@ -17,6 +17,7 @@ from core import content_db import fay_booter from scheduler.thread_manager import MyThread from core.interact import Interact +from bionicmemory.core.chroma_service import ChromaService # import sys, io, traceback # class StdoutInterceptor(io.TextIOBase): @@ -128,6 +129,14 @@ def __create_memory(): if not os.path.exists("./memory"): os.mkdir("./memory") +def __check_and_clear_chroma_db(): + """检查并清除ChromaDB数据库(如果存在清除标记)""" + try: + if ChromaService.check_and_clear_database_on_startup(): + util.log(1, "检测到记忆清除标记,已清除ChromaDB数据库") + except Exception as e: + util.log(1, f"清理ChromaDB时出错: {e}") + def kill_process_by_port(port): for conn in psutil.net_connections(kind='inet'): if conn.laddr.port == port and conn.pid: @@ -197,6 +206,7 @@ def console_listener(): if __name__ == '__main__': __clear_samples() __create_memory() + __check_and_clear_chroma_db() # 在创建memory目录后立即检查清理 __clear_logs() #init_db diff --git a/test/test_fay_gpt_stream.py b/test/test_fay_gpt_stream.py index 249fe4b..557a433 100644 --- a/test/test_fay_gpt_stream.py +++ b/test/test_fay_gpt_stream.py @@ -2,7 +2,7 @@ import requests import json def test_gpt(prompt): - url = 'http://127.0.0.1:8000/v1/chat/completions' # 替换为您的接口地址 + url = 'http://127.0.0.1:5000/v1/chat/completions' # 替换为您的接口地址 headers = { 'Content-Type': 'application/json', 'Authorization': f'Bearer YOUR_API_KEY', # 如果您的接口需要身份验证 @@ -46,7 +46,7 @@ def test_gpt(prompt): print(f"\n收到未知格式的数据:{line}") if __name__ == "__main__": - user_input = "7" + user_input = "你好" print("GPT 的回复:") test_gpt(user_input) print("\n请求完成")