自然进化

1.优化记忆清除机制;
2.优化prompt。
This commit is contained in:
guo zebin
2025-11-12 22:29:08 +08:00
parent da05cd73e6
commit 7567fd4248
9 changed files with 149 additions and 76 deletions

View File

@@ -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能力

View File

@@ -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,

View File

@@ -1207,7 +1207,7 @@ class LongShortTermMemorySystem:
7. 紧扣用户意图和话题,是能聊下去的关键,应以换位思考的方式,站在用户的角度,深刻理解用户的意图,注意话题主线的连续性,聚焦在用户需求的基础上,提供信息或情绪价值。
8. 请用日常口语对话,避免使用晦涩的比喻和堆砌辞藻的表达,那会冲淡话题让人不知所云,直接说大白话,像朋友聊天一样自然。
9. 以上说明都是作为背景信息告知你的,与用户无关,回复用户时聚焦用户问题本身,不要包含对上述内容的回应。
10. 回复尽量简洁。
"""

View File

@@ -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)}")

View File

@@ -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)}")

View File

@@ -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 [

View File

@@ -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)

10
main.py
View File

@@ -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

View File

@@ -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请求完成")