Merge branch 'MaiM-with-u:dev' into dev
This commit is contained in:
@@ -1,126 +1,75 @@
|
||||
# Changelog
|
||||
|
||||
## [0.8.0] - 2025-1-6
|
||||
重大升级!插件系统全面重构,表达方式系统大幅优化,focus大幅降低token花费和反应速度,加入了人物印象系统,麦麦可以记住群友的特点。支持更精细的分群聊天频率控制,normal模式可以使用planner和action
|
||||
## [0.8.0] - 2025-6-27
|
||||
|
||||
MaiBot 0.8.0 重磅升级!插件系统全面重构,支持更强大的扩展能力;表达方式系统大幅优化,支持智能学习和衰减机制;聊天频率控制更加精细,支持时段化管理;HFC系统性能大幅提升,处理器后置化减少消耗;关系系统升级支持即时构建和人物侧写;日志系统重构使用structlog;大量稳定性修复和性能优化。
|
||||
MaiBot 0.8.0 现已推出!
|
||||
|
||||
## 🚀 主要更新点
|
||||
### **主要升级点:**
|
||||
|
||||
1.插件系统正式加入,现已上线插件商店,同时支持normal和focus
|
||||
2.大幅降低了token消耗,更省钱
|
||||
3.加入人物印象系统,麦麦可以对群友有不同的印象
|
||||
4.可以精细化控制不同时段和不同群聊的发言频率
|
||||
|
||||
#### 其他升级
|
||||
|
||||
日志系统重构使用structlog
|
||||
大量稳定性修复和性能优化。
|
||||
MMC启动速度加快
|
||||
|
||||
### 🔌 插系统正式推出
|
||||
**全面重构的插件生态系统,支持强大 的扩展能力**
|
||||
|
||||
### 🔌 插件系统正式推出
|
||||
**全面重构的插件生态系统,支持强大的扩展能力**
|
||||
- **插件API重构**: 全面重构插件系统,统一加载机制,区分内部插件和外部插件
|
||||
- **插件仓库**:现可以分享和下载插件
|
||||
- **依赖管理**: 新增插件依赖管理系统,支持自动注册和依赖检查
|
||||
- **命令支持**: 插件现已支持命令(command)功能,提供更丰富的交互方式
|
||||
- **示例插件升级**: 更新禁言插件、豆包绘图插件、TTS插件等示例插件
|
||||
- **配置文件管理**: 插件支持自动生成和管理配置文件,支持版本自动更新
|
||||
- **文档完善**: 补全插件API文档,提供详细的开发指南
|
||||
- **Action选择优化**: 大大优化action的选择能力,提升动作执行的智能性
|
||||
|
||||
### ⚡ Focus模式大幅优化 - 降低Token消耗与提升速度
|
||||
**HFC系统性能革命性提升,大幅降低成本和提升响应速度**
|
||||
- **Planner架构更新**: 更新planner架构,大大加快速度和表现效果!
|
||||
- **处理器重构**:
|
||||
- 移除旧回复意愿控制系统
|
||||
- 精简处理器上下文,减少不必要的处理
|
||||
- 后置工具处理器,大大减少token消耗
|
||||
- 合并自我处理器和关系处理器,提高效率
|
||||
- 可关闭思考处理器(建议默认关闭)
|
||||
- **统计系统**: 提供focus统计功能,可查看详细的no_reply统计信息
|
||||
- **异步优化**: 将统计和person_info改为异步,提升整体性能
|
||||
|
||||
### 👥 人物印象系统
|
||||
**麦麦现在能认得群友,记住每个人的特点**
|
||||
- **人物侧写功能**: 加入了人物侧写!麦麦现在能认得群友,新增用户侧写功能,将印象拆分为多方面特点
|
||||
- **即时构建**: 重构关系构建逻辑,改为即时构建,提高实时性
|
||||
- **关系处理器**: 新增专门的关系处理器,支持更精准的关系管理
|
||||
- **熟悉度系统**: 添加熟悉度和关系值功能,提供更丰富的关系信息
|
||||
|
||||
### ⚡ Focus模式大幅优化 - 降低Token消耗与提升速度
|
||||
- **Planner架构更新**: 更新planner架构,大大加快速度和表现效果!
|
||||
- **处理器重构**:
|
||||
- 移除冗余处理器
|
||||
- 精简处理器上下文,减少不必要的处理
|
||||
- 后置工具处理器,大大减少token消耗
|
||||
- **统计系统**: 提供focus统计功能,可查看详细的no_reply统计信息
|
||||
|
||||
|
||||
### ⏰ 聊天频率精细控制
|
||||
**支持时段化的精细频率管理,让麦麦在合适的时间说合适的话**
|
||||
- **时段化控制**: 添加时段talk_frequency控制,支持不同时间段的精细频率管理
|
||||
- **时段化控制**: 添加时段talk_frequency控制,支持不同时间段不同群聊的精细频率管理
|
||||
- **严格频率控制**: 实现更加严格和可靠的频率控制机制
|
||||
- **Normal模式优化**: 大幅优化normal模式的频率控制逻辑,提升回复的智能性
|
||||
|
||||
### 🎭 表达方式系统大幅优化
|
||||
**智能学习群友聊天风格,让麦麦的表达更加多样化**
|
||||
- **智能学习机制**: 优化表达方式学习算法,支持衰减机制,太久没学的会被自动抛弃
|
||||
- **表达方式选择**: 新增表达方式选择处理器,大幅提升表达的多样性
|
||||
- **表达方式选择**: 新增表达方式选择器,让表达使用更合理
|
||||
- **跨群互通配置**: 表达方式现在可以选择在不同群互通或独立
|
||||
- **可视化工具**: 提供表达方式可视化脚本和检查脚本
|
||||
- **人格表达优化**: 修复人格表达生成太固定的问题,增加表达方式的多样性
|
||||
|
||||
### 💾 记忆系统改进
|
||||
**更快的记忆处理和更好的短期记忆管理**
|
||||
- **海马体优化**: 大大优化海马体同步速度,提升记忆处理效率
|
||||
- **记忆同步优化**: 优化记忆同步算法,修复记忆构建缺少chat_id的问题
|
||||
- **工作记忆升级**: 精简升级工作记忆模块,提供更好的短期记忆管理
|
||||
- **聊天记录构建**: 优化聊天记录构建方式,提升记忆提取效率
|
||||
|
||||
### 📊 日志系统重构
|
||||
**使用structlog提供更好的结构化日志**
|
||||
- **structlog替换**: 使用structlog替代loguru,提供更好的结构化日志
|
||||
- **日志查看器**: 新增更强大的日志查看器,支持更好的日志浏览
|
||||
- **日志查看器**: 新增日志查看脚本,支持更好的日志浏览
|
||||
- **可配置日志**: 提供可配置的日志级别和格式,支持不同环境的需求
|
||||
|
||||
## 🔧 优化修复点
|
||||
|
||||
### 🛠️ 开发体验提升
|
||||
- **API系统扩展**:
|
||||
- **Chat Stream API**: 提供获取Chat_stream的API接口
|
||||
- **统计API**: 支持统计数据输出API
|
||||
- **插件API扩展**: 新增多个插件相关的API接口
|
||||
- **API重构**: 重构插件API架构,提供更完善的接口体系
|
||||
- **Docker部署优化**:
|
||||
- **配置更新**: 更新docker-compose配置,优化端口映射和服务配置
|
||||
- **部署文档**: 优化Docker构建流程和部署文档
|
||||
|
||||
### 🐛 重要问题修复
|
||||
#### 稳定性修复
|
||||
- **模式切换**: 修复无法退出专注模式的问题,优化auto模式切换逻辑
|
||||
- **循环异常**: 修复循环异常思索问题,提高系统稳定性
|
||||
- **插件重载**: 解决插件重复加载问题,增加重复加载警告机制
|
||||
- **SQL问题**: 修复数据库相关的SQL问题和索引创建失败问题
|
||||
- **性能优化**: 修复日志占用和文件层级问题,解决too many open files问题
|
||||
|
||||
#### 功能修复
|
||||
- **display_name问题**: 修复base_command和base_action中未使用display_name的错误
|
||||
- **消息截断**: 修复被指令截断的消息无法保存到prompt的问题
|
||||
- **统计数据**: 修复统计相关的多个问题
|
||||
- **图片处理**: 优化图片展示形式,修复图片发送相关问题
|
||||
- **群名称**: 修复群名称导致log保存失败的问题
|
||||
- **Focus首条消息**: 修复focus吞掉首条消息的问题
|
||||
- **关键词功能**: 修复关键词功能,并且在focus中可用
|
||||
- **表情包Action**: 修复了表情包action相关问题
|
||||
- **Focus时间信息**: 修复focus没有时间信息的问题
|
||||
|
||||
### ⚙️ 配置与性能优化
|
||||
- **配置系统增强**:
|
||||
- **新配置项**: 添加大量新的配置项,支持更细粒度的控制
|
||||
- **版本管理**: 支持插件配置文件版本自动更新
|
||||
- **模板更新**: 更新bot_config_template.toml配置文件模板
|
||||
- **关闭选项**: 可关闭记忆和关系系统、消息后处理等功能
|
||||
- **性能优化**:
|
||||
- **Token优化**: 移除部分不必要的token限制,优化token消耗
|
||||
- **异步改进**: 人格表达和remote请求改为异步,不阻塞主线程
|
||||
- **内存优化**: 优化工作记忆处理器性能和内存使用
|
||||
- **Normal动作执行**: 为normal_chat加入动作执行能力
|
||||
|
||||
### 📚 文档与工具
|
||||
- **文档完善**:
|
||||
- **插件开发指南**: 提供详细的插件系统开发文档
|
||||
- **API文档**: 补全插件API文档和使用说明
|
||||
- **部署指南**: 优化部署相关文档的完整性
|
||||
- **辅助工具**:
|
||||
- **表达方式工具**: 提供表达方式检查脚本和可视化工具
|
||||
- **插件管理工具**: 新增插件和清单管理工具
|
||||
- **关系构建脚本**: 提供关系构建和回溯脚本
|
||||
|
||||
### 🎯 其他改进
|
||||
- **emoji系统**: 移除emoji默认发送模式,优化表情包审查功能
|
||||
- **控制台发送**: 添加不完善的控制台发送功能
|
||||
- **行为准则**: 添加贡献者契约行为准则
|
||||
- **代码质量**: 使用ruff进行代码格式化和质量检查
|
||||
- **图像清理**: 自动清理images文件夹,优化存储空间使用
|
||||
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@ logger = get_logger("expression_selector")
|
||||
|
||||
def init_prompt():
|
||||
expression_evaluation_prompt = """
|
||||
你的名字是{bot_name}
|
||||
|
||||
以下是正在进行的聊天内容:
|
||||
{chat_observe_info}
|
||||
|
||||
你的名字是{bot_name}{target_message}
|
||||
|
||||
以下是可选的表达情境:
|
||||
{all_situations}
|
||||
|
||||
@@ -28,6 +28,7 @@ def init_prompt():
|
||||
1. 聊天的情绪氛围(轻松、严肃、幽默等)
|
||||
2. 话题类型(日常、技术、游戏、情感等)
|
||||
3. 情境与当前语境的匹配度
|
||||
{target_message_extra_block}
|
||||
|
||||
请以JSON格式输出,只需要输出选中的情境编号:
|
||||
例如:
|
||||
@@ -156,7 +157,7 @@ class ExpressionSelector:
|
||||
new_count = min(current_count + increment, 5.0)
|
||||
expr_in_map["count"] = new_count
|
||||
expr_in_map["last_active_time"] = time.time()
|
||||
logger.info(
|
||||
logger.debug(
|
||||
f"表达方式激活: 原count={current_count:.3f}, 增量={increment}, 新count={new_count:.3f} in {file_path}"
|
||||
)
|
||||
|
||||
@@ -168,7 +169,7 @@ class ExpressionSelector:
|
||||
logger.error(f"批量更新表达方式count失败 for {file_path}: {e}")
|
||||
|
||||
async def select_suitable_expressions_llm(
|
||||
self, chat_id: str, chat_info: str, max_num: int = 10, min_num: int = 5
|
||||
self, chat_id: str, chat_info: str, max_num: int = 10, min_num: int = 5, target_message: str = None
|
||||
) -> List[Dict[str, str]]:
|
||||
"""使用LLM选择适合的表达方式"""
|
||||
|
||||
@@ -209,6 +210,13 @@ class ExpressionSelector:
|
||||
|
||||
all_situations_str = "\n".join(all_situations)
|
||||
|
||||
if target_message:
|
||||
target_message_str = f",现在你想要回复消息:{target_message}"
|
||||
target_message_extra_block = "4.考虑你要回复的目标消息"
|
||||
else:
|
||||
target_message_str = ""
|
||||
target_message_extra_block = ""
|
||||
|
||||
# 3. 构建prompt(只包含情境,不包含完整的表达方式)
|
||||
prompt = (await global_prompt_manager.get_prompt_async("expression_evaluation_prompt")).format(
|
||||
bot_name=global_config.bot.nickname,
|
||||
@@ -216,8 +224,12 @@ class ExpressionSelector:
|
||||
all_situations=all_situations_str,
|
||||
min_num=min_num,
|
||||
max_num=max_num,
|
||||
target_message=target_message_str,
|
||||
target_message_extra_block=target_message_extra_block,
|
||||
)
|
||||
|
||||
# print(prompt)
|
||||
|
||||
# 4. 调用LLM
|
||||
try:
|
||||
content, (_, _) = await self.llm_model.generate_response_async(prompt=prompt)
|
||||
|
||||
@@ -413,7 +413,6 @@ class HeartFChatting:
|
||||
"action_result": {
|
||||
"action_type": "error",
|
||||
"action_data": {},
|
||||
"reasoning": f"上下文处理失败: {e}",
|
||||
},
|
||||
"observed_messages": "",
|
||||
},
|
||||
@@ -650,143 +649,8 @@ class HeartFChatting:
|
||||
|
||||
return all_plan_info, processor_time_costs
|
||||
|
||||
async def _process_post_planning_processors(self, observations: List[Observation], action_data: dict) -> dict:
|
||||
"""
|
||||
处理后期处理器(规划后执行的处理器)
|
||||
包括:关系处理器、表达选择器、记忆激活器
|
||||
|
||||
参数:
|
||||
observations: 观察器列表
|
||||
action_data: 原始动作数据
|
||||
|
||||
返回:
|
||||
dict: 更新后的动作数据
|
||||
"""
|
||||
logger.info(f"{self.log_prefix} 开始执行后期处理器")
|
||||
|
||||
# 创建所有后期任务
|
||||
task_list = []
|
||||
task_to_name_map = {}
|
||||
|
||||
# 添加后期处理器任务
|
||||
for processor in self.post_planning_processors:
|
||||
processor_name = processor.__class__.__name__
|
||||
|
||||
async def run_processor_with_timeout(proc=processor):
|
||||
return await asyncio.wait_for(
|
||||
proc.process_info(observations=observations),
|
||||
timeout=global_config.focus_chat.processor_max_time,
|
||||
)
|
||||
|
||||
task = asyncio.create_task(run_processor_with_timeout())
|
||||
task_list.append(task)
|
||||
task_to_name_map[task] = ("processor", processor_name)
|
||||
logger.info(f"{self.log_prefix} 启动后期处理器任务: {processor_name}")
|
||||
|
||||
# 添加记忆激活器任务
|
||||
async def run_memory_with_timeout():
|
||||
return await asyncio.wait_for(
|
||||
self.memory_activator.activate_memory(observations),
|
||||
timeout=MEMORY_ACTIVATION_TIMEOUT,
|
||||
)
|
||||
|
||||
memory_task = asyncio.create_task(run_memory_with_timeout())
|
||||
task_list.append(memory_task)
|
||||
task_to_name_map[memory_task] = ("memory", "MemoryActivator")
|
||||
logger.info(f"{self.log_prefix} 启动记忆激活器任务")
|
||||
|
||||
# 如果没有任何后期任务,直接返回
|
||||
if not task_list:
|
||||
logger.info(f"{self.log_prefix} 没有启用的后期处理器或记忆激活器")
|
||||
return action_data
|
||||
|
||||
# 等待所有任务完成
|
||||
pending_tasks = set(task_list)
|
||||
all_post_plan_info = []
|
||||
running_memorys = []
|
||||
|
||||
while pending_tasks:
|
||||
done, pending_tasks = await asyncio.wait(pending_tasks, return_when=asyncio.FIRST_COMPLETED)
|
||||
|
||||
for task in done:
|
||||
task_type, task_name = task_to_name_map[task]
|
||||
|
||||
try:
|
||||
result = await task
|
||||
|
||||
if task_type == "processor":
|
||||
logger.info(f"{self.log_prefix} 后期处理器 {task_name} 已完成!")
|
||||
if result is not None:
|
||||
all_post_plan_info.extend(result)
|
||||
else:
|
||||
logger.warning(f"{self.log_prefix} 后期处理器 {task_name} 返回了 None")
|
||||
elif task_type == "memory":
|
||||
logger.info(f"{self.log_prefix} 记忆激活器已完成!")
|
||||
if result is not None:
|
||||
running_memorys = result
|
||||
else:
|
||||
logger.warning(f"{self.log_prefix} 记忆激活器返回了 None")
|
||||
running_memorys = []
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
if task_type == "processor":
|
||||
logger.warning(
|
||||
f"{self.log_prefix} 后期处理器 {task_name} 超时(>{global_config.focus_chat.processor_max_time}s),已跳过"
|
||||
)
|
||||
elif task_type == "memory":
|
||||
logger.warning(f"{self.log_prefix} 记忆激活器超时(>{MEMORY_ACTIVATION_TIMEOUT}s),已跳过")
|
||||
running_memorys = []
|
||||
except Exception as e:
|
||||
if task_type == "processor":
|
||||
logger.error(
|
||||
f"{self.log_prefix} 后期处理器 {task_name} 执行失败. 错误: {e}",
|
||||
exc_info=True,
|
||||
)
|
||||
elif task_type == "memory":
|
||||
logger.error(f"{self.log_prefix} 记忆激活器执行失败. 错误: {e}", exc_info=True)
|
||||
running_memorys = []
|
||||
|
||||
# 将后期处理器的结果整合到 action_data 中
|
||||
updated_action_data = action_data.copy()
|
||||
|
||||
relation_info = ""
|
||||
selected_expressions = []
|
||||
structured_info = ""
|
||||
|
||||
for info in all_post_plan_info:
|
||||
if isinstance(info, RelationInfo):
|
||||
relation_info = info.get_processed_info()
|
||||
elif isinstance(info, ExpressionSelectionInfo):
|
||||
selected_expressions = info.get_expressions_for_action_data()
|
||||
elif isinstance(info, StructuredInfo):
|
||||
structured_info = info.get_processed_info()
|
||||
|
||||
if relation_info:
|
||||
updated_action_data["relation_info_block"] = relation_info
|
||||
|
||||
if selected_expressions:
|
||||
updated_action_data["selected_expressions"] = selected_expressions
|
||||
|
||||
if structured_info:
|
||||
updated_action_data["structured_info"] = structured_info
|
||||
|
||||
# 特殊处理running_memorys
|
||||
if running_memorys:
|
||||
memory_str = "以下是当前在聊天中,你回忆起的记忆:\n"
|
||||
for running_memory in running_memorys:
|
||||
memory_str += f"{running_memory['content']}\n"
|
||||
updated_action_data["memory_block"] = memory_str
|
||||
logger.info(f"{self.log_prefix} 添加了 {len(running_memorys)} 个激活的记忆到action_data")
|
||||
|
||||
if all_post_plan_info or running_memorys:
|
||||
logger.info(
|
||||
f"{self.log_prefix} 后期处理完成,产生了 {len(all_post_plan_info)} 个信息项和 {len(running_memorys)} 个记忆"
|
||||
)
|
||||
|
||||
return updated_action_data
|
||||
|
||||
async def _process_post_planning_processors_with_timing(
|
||||
self, observations: List[Observation], action_data: dict
|
||||
self, observations: List[Observation], action_type: str, action_data: dict
|
||||
) -> tuple[dict, dict]:
|
||||
"""
|
||||
处理后期处理器(规划后执行的处理器)并收集详细时间统计
|
||||
@@ -794,6 +658,7 @@ class HeartFChatting:
|
||||
|
||||
参数:
|
||||
observations: 观察器列表
|
||||
action_type: 动作类型
|
||||
action_data: 原始动作数据
|
||||
|
||||
返回:
|
||||
@@ -815,7 +680,7 @@ class HeartFChatting:
|
||||
start_time = time.time()
|
||||
try:
|
||||
result = await asyncio.wait_for(
|
||||
proc.process_info(observations=observations),
|
||||
proc.process_info(observations=observations, action_type=action_type, action_data=action_data),
|
||||
timeout=global_config.focus_chat.processor_max_time,
|
||||
)
|
||||
end_time = time.time()
|
||||
@@ -1074,7 +939,7 @@ class HeartFChatting:
|
||||
# 记录详细的后处理器时间
|
||||
post_start_time = time.time()
|
||||
action_data, post_processor_time_costs = await self._process_post_planning_processors_with_timing(
|
||||
self.observations, action_data
|
||||
self.observations, action_type, action_data
|
||||
)
|
||||
post_end_time = time.time()
|
||||
logger.info(f"{self.log_prefix} 后期处理器总耗时: {post_end_time - post_start_time:.3f}秒")
|
||||
|
||||
@@ -181,9 +181,17 @@ class HeartFCMessageReceiver:
|
||||
mes_name = chat.group_info.group_name if chat.group_info else "私聊"
|
||||
# current_time = time.strftime("%H:%M:%S", time.localtime(message.message_info.time))
|
||||
current_talk_frequency = global_config.chat.get_current_talk_frequency(chat.stream_id)
|
||||
logger.info(
|
||||
f"[{mes_name}]{userinfo.user_nickname}:{message.processed_plain_text}[当前回复频率: {current_talk_frequency}]"
|
||||
)
|
||||
|
||||
# 如果消息中包含图片标识,则日志展示为图片
|
||||
import re
|
||||
|
||||
picid_match = re.search(r"\[picid:([^\]]+)\]", message.processed_plain_text)
|
||||
if picid_match:
|
||||
logger.info(f"[{mes_name}]{userinfo.user_nickname}: [图片] [当前回复频率: {current_talk_frequency}]")
|
||||
else:
|
||||
logger.info(
|
||||
f"[{mes_name}]{userinfo.user_nickname}:{message.processed_plain_text}[当前回复频率: {current_talk_frequency}]"
|
||||
)
|
||||
|
||||
# 8. 关系处理
|
||||
if global_config.relationship.enable_relationship:
|
||||
|
||||
@@ -27,7 +27,13 @@ class ExpressionSelectorProcessor(BaseProcessor):
|
||||
name = get_chat_manager().get_stream_name(self.subheartflow_id)
|
||||
self.log_prefix = f"[{name}] 表达选择器"
|
||||
|
||||
async def process_info(self, observations: List[Observation] = None, *infos) -> List[InfoBase]:
|
||||
async def process_info(
|
||||
self,
|
||||
observations: List[Observation] = None,
|
||||
action_type: str = None,
|
||||
action_data: dict = None,
|
||||
**kwargs,
|
||||
) -> List[InfoBase]:
|
||||
"""处理信息对象
|
||||
|
||||
Args:
|
||||
@@ -70,9 +76,14 @@ class ExpressionSelectorProcessor(BaseProcessor):
|
||||
return []
|
||||
|
||||
try:
|
||||
if action_type == "reply":
|
||||
target_message = action_data.get("reply_to", "")
|
||||
else:
|
||||
target_message = ""
|
||||
|
||||
# LLM模式:调用LLM选择5-10个,然后随机选5个
|
||||
selected_expressions = await expression_selector.select_suitable_expressions_llm(
|
||||
self.subheartflow_id, chat_info, max_num=12, min_num=2
|
||||
self.subheartflow_id, chat_info, max_num=12, min_num=2, target_message=target_message
|
||||
)
|
||||
cache_size = len(selected_expressions) if selected_expressions else 0
|
||||
mode_desc = f"LLM模式(已缓存{cache_size}个)"
|
||||
|
||||
@@ -13,7 +13,6 @@ from typing import List
|
||||
from typing import Dict
|
||||
from src.chat.focus_chat.info.info_base import InfoBase
|
||||
from src.chat.focus_chat.info.relation_info import RelationInfo
|
||||
from src.person_info.person_info import PersonInfoManager
|
||||
from json_repair import repair_json
|
||||
from src.person_info.person_info import get_person_info_manager
|
||||
import json
|
||||
@@ -26,7 +25,6 @@ from src.chat.utils.chat_message_builder import (
|
||||
)
|
||||
import os
|
||||
import pickle
|
||||
import random
|
||||
|
||||
|
||||
# 消息段清理配置
|
||||
@@ -37,139 +35,51 @@ SEGMENT_CLEANUP_CONFIG = {
|
||||
"cleanup_interval_hours": 1, # 清理间隔(小时)
|
||||
}
|
||||
|
||||
# 用于随机生成prompt示例的资源池
|
||||
USER_EXAMPLE_KEYS = ["用户A", "小明", "Alice", "陈皮", "老王", "Bob", "张三", "李四"]
|
||||
USER_EXAMPLE_VALUES = [
|
||||
"ta的昵称",
|
||||
"ta对你的态度",
|
||||
"你对ta的印象",
|
||||
"ta最近心情如何",
|
||||
"你们的关系",
|
||||
"ta的身份",
|
||||
"ta的兴趣爱好",
|
||||
"ta和你的共同点",
|
||||
"ta的习惯",
|
||||
"你们最近做的事",
|
||||
"你对ta的语气",
|
||||
"你们的互动方式",
|
||||
"给你的第一印象",
|
||||
"你们最近聊过什么",
|
||||
]
|
||||
BOT_EXAMPLE_VALUES = [
|
||||
"身份",
|
||||
"性格",
|
||||
"你的原则",
|
||||
"你的知识",
|
||||
"你的目标",
|
||||
"你的爱好",
|
||||
"你最近在做什么",
|
||||
"头像",
|
||||
"年龄",
|
||||
"性别",
|
||||
"职业",
|
||||
"兴趣爱好",
|
||||
"习惯",
|
||||
"目标",
|
||||
"原则",
|
||||
"知识",
|
||||
"爱好",
|
||||
]
|
||||
|
||||
|
||||
logger = get_logger("processor")
|
||||
|
||||
|
||||
def _generate_random_prompt_example() -> str:
|
||||
"""动态生成一个随机的、符合规则的JSON示例字符串"""
|
||||
|
||||
bot_nickname = global_config.bot.nickname
|
||||
bot_aliases = list(global_config.bot.alias_names)
|
||||
|
||||
# 确定示例数量
|
||||
num_user_examples = random.randint(1, 2)
|
||||
num_bot_examples = random.randint(1, 2)
|
||||
|
||||
example_dict = {}
|
||||
|
||||
# 1. 生成用户提取示例
|
||||
user_keys = random.sample(USER_EXAMPLE_KEYS, min(num_user_examples, len(USER_EXAMPLE_KEYS)))
|
||||
user_values = random.sample(USER_EXAMPLE_VALUES, min(num_user_examples, len(USER_EXAMPLE_VALUES)))
|
||||
for i in range(len(user_keys)):
|
||||
example_dict[user_keys[i]] = user_values[i]
|
||||
|
||||
# 2. 生成bot自身示例 (使用昵称和别名避免key重复)
|
||||
bot_name_pool = [bot_nickname] + bot_aliases
|
||||
random.shuffle(bot_name_pool)
|
||||
bot_values = random.sample(BOT_EXAMPLE_VALUES, min(num_bot_examples, len(BOT_EXAMPLE_VALUES)))
|
||||
|
||||
for i in range(min(num_bot_examples, len(bot_name_pool), len(bot_values))):
|
||||
example_dict[bot_name_pool[i]] = bot_values[i]
|
||||
|
||||
# 3. 添加固定示例
|
||||
example_dict["person_name"] = "其他信息"
|
||||
|
||||
# 随机化顺序并格式化为JSON字符串
|
||||
items = list(example_dict.items())
|
||||
random.shuffle(items)
|
||||
shuffled_dict = dict(items)
|
||||
|
||||
return json.dumps(shuffled_dict, ensure_ascii=False, indent=4)
|
||||
|
||||
|
||||
def init_prompt():
|
||||
relationship_prompt = """
|
||||
<聊天记录>
|
||||
{chat_observe_info}
|
||||
</聊天记录>
|
||||
|
||||
{info_cache_block}
|
||||
请不要重复调取相同的信息
|
||||
|
||||
{name_block}
|
||||
请你阅读聊天记录,查看是否需要调取某个人的信息,这个人可以是出现在聊天记录中的,也可以是记录中提到的人,也可以是你自己({bot_name})。
|
||||
你不同程度上认识群聊里的人,以及他们谈论到的人,你可以根据聊天记录,回忆起有关他们的信息,帮助你参与聊天
|
||||
1.你需要提供用户名和你想要提取的信息名称类型来进行调取
|
||||
2.请注意,提取的信息类型一定要和用户有关,不要提取无关的信息
|
||||
3.你也可以调取有关自己({bot_name})的信息
|
||||
4.如果当前聊天记录中没有需要查询的信息,或者现有信息已经足够回复,请返回{{"none": "不需要查询"}}
|
||||
现在,你想要回复{person_name}的消息,消息内容是:{target_message}。请根据聊天记录和你要回复的消息,从你对{person_name}的了解中提取有关的信息:
|
||||
1.你需要提供你想要提取的信息具体是哪方面的信息,例如:年龄,性别,对ta的印象,最近发生的事等等。
|
||||
2.请注意,请不要重复调取相同的信息,已经调取的信息如下:
|
||||
{info_cache_block}
|
||||
3.如果当前聊天记录中没有需要查询的信息,或者现有信息已经足够回复,请返回{{"none": "不需要查询"}}
|
||||
|
||||
请以json格式输出,例如:
|
||||
|
||||
{example_json}
|
||||
|
||||
如果不需要查询任何信息,请输出:
|
||||
{{"none": "不需要查询"}}
|
||||
|
||||
请严格按照json输出格式,不要输出多余内容,可以同时查询多个人的信息:
|
||||
{{
|
||||
"info_type": "信息类型",
|
||||
}}
|
||||
|
||||
请严格按照json输出格式,不要输出多余内容:
|
||||
"""
|
||||
Prompt(relationship_prompt, "relationship_prompt")
|
||||
|
||||
fetch_info_prompt = """
|
||||
|
||||
{name_block}
|
||||
以下是你在之前与{person_name}的交流中,产生的对{person_name}的了解,请你从中提取用户的有关"{info_type}"的信息,如果用户没有相关信息,请输出none:
|
||||
以下是你在之前与{person_name}的交流中,产生的对{person_name}的了解:
|
||||
{person_impression_block}
|
||||
{points_text_block}
|
||||
请严格按照以下json输出格式,不要输出多余内容:
|
||||
|
||||
请从中提取用户"{person_name}"的有关"{info_type}"信息
|
||||
请以json格式输出,例如:
|
||||
|
||||
{{
|
||||
{info_json_str}
|
||||
}}
|
||||
|
||||
请严格按照json输出格式,不要输出多余内容:
|
||||
"""
|
||||
Prompt(fetch_info_prompt, "fetch_person_info_prompt")
|
||||
|
||||
fetch_bot_info_prompt = """
|
||||
你是{nickname},你的昵称有{alias_names}。
|
||||
以下是你对自己的了解,请你从中提取和"{info_type}"有关的信息,如果无法提取,请输出none:
|
||||
{person_impression_block}
|
||||
{points_text_block}
|
||||
请严格按照以下json输出格式,不要输出多余内容:
|
||||
{{
|
||||
"{info_type}": "有关你自己的{info_type}的信息内容"
|
||||
}}
|
||||
"""
|
||||
Prompt(fetch_bot_info_prompt, "fetch_bot_info_prompt")
|
||||
|
||||
|
||||
class PersonImpressionpProcessor(BaseProcessor):
|
||||
log_prefix = "关系"
|
||||
@@ -293,7 +203,7 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
}
|
||||
segments.append(new_segment)
|
||||
|
||||
person_name = get_person_info_manager().get_value(person_id, "person_name") or person_id
|
||||
person_name = get_person_info_manager().get_value_sync(person_id, "person_name") or person_id
|
||||
logger.info(
|
||||
f"{self.log_prefix} 眼熟用户 {person_name} 在 {time.strftime('%H:%M:%S', time.localtime(potential_start_time))} - {time.strftime('%H:%M:%S', time.localtime(message_time))} 之间有 {new_segment['message_count']} 条消息"
|
||||
)
|
||||
@@ -341,7 +251,8 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
"message_count": self._count_messages_in_timerange(potential_start_time, message_time),
|
||||
}
|
||||
segments.append(new_segment)
|
||||
person_name = get_person_info_manager().get_value(person_id, "person_name") or person_id
|
||||
person_info_manager = get_person_info_manager()
|
||||
person_name = person_info_manager.get_value_sync(person_id, "person_name") or person_id
|
||||
logger.info(f"{self.log_prefix} 重新眼熟用户 {person_name} 创建新消息段(超过10条消息间隔): {new_segment}")
|
||||
|
||||
self._save_cache()
|
||||
@@ -515,16 +426,26 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
# 统筹各模块协作、对外提供服务接口
|
||||
# ================================
|
||||
|
||||
async def process_info(self, observations: List[Observation] = None, *infos) -> List[InfoBase]:
|
||||
async def process_info(
|
||||
self,
|
||||
observations: List[Observation] = None,
|
||||
action_type: str = None,
|
||||
action_data: dict = None,
|
||||
**kwargs,
|
||||
) -> List[InfoBase]:
|
||||
"""处理信息对象
|
||||
|
||||
Args:
|
||||
*infos: 可变数量的InfoBase类型的信息对象
|
||||
observations: 观察对象列表
|
||||
action_type: 动作类型
|
||||
action_data: 动作数据
|
||||
|
||||
Returns:
|
||||
List[InfoBase]: 处理后的结构化信息列表
|
||||
"""
|
||||
relation_info_str = await self.relation_identify(observations)
|
||||
await self.build_relation(observations)
|
||||
|
||||
relation_info_str = await self.relation_identify(observations, action_type, action_data)
|
||||
|
||||
if relation_info_str:
|
||||
relation_info = RelationInfo()
|
||||
@@ -535,28 +456,14 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
|
||||
return [relation_info]
|
||||
|
||||
async def relation_identify(
|
||||
self,
|
||||
observations: List[Observation] = None,
|
||||
):
|
||||
"""
|
||||
在回复前进行思考,生成内心想法并收集工具调用结果
|
||||
"""
|
||||
# 0. 执行定期清理
|
||||
async def build_relation(self, observations: List[Observation] = None):
|
||||
"""构建关系"""
|
||||
self._cleanup_old_segments()
|
||||
|
||||
# 1. 从观察信息中提取所需数据
|
||||
# 需要兼容私聊
|
||||
|
||||
chat_observe_info = ""
|
||||
current_time = time.time()
|
||||
|
||||
if observations:
|
||||
for observation in observations:
|
||||
if isinstance(observation, ChattingObservation):
|
||||
chat_observe_info = observation.get_observe_info()
|
||||
# latest_message_time = observation.last_observe_time
|
||||
# 从聊天观察中提取用户信息并更新消息段
|
||||
# 获取最新的非bot消息来更新消息段
|
||||
latest_messages = get_raw_msg_by_timestamp_with_chat(
|
||||
self.subheartflow_id,
|
||||
self.last_processed_message_time,
|
||||
@@ -610,6 +517,54 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
del self.person_engaged_cache[person_id]
|
||||
self._save_cache()
|
||||
|
||||
async def relation_identify(
|
||||
self,
|
||||
observations: List[Observation] = None,
|
||||
action_type: str = None,
|
||||
action_data: dict = None,
|
||||
):
|
||||
"""
|
||||
从人物获取信息
|
||||
"""
|
||||
|
||||
chat_observe_info = ""
|
||||
current_time = time.time()
|
||||
if observations:
|
||||
for observation in observations:
|
||||
if isinstance(observation, ChattingObservation):
|
||||
chat_observe_info = observation.get_observe_info()
|
||||
# latest_message_time = observation.last_observe_time
|
||||
# 从聊天观察中提取用户信息并更新消息段
|
||||
# 获取最新的非bot消息来更新消息段
|
||||
latest_messages = get_raw_msg_by_timestamp_with_chat(
|
||||
self.subheartflow_id,
|
||||
self.last_processed_message_time,
|
||||
current_time,
|
||||
limit=50, # 获取自上次处理后的消息
|
||||
)
|
||||
if latest_messages:
|
||||
# 处理所有新的非bot消息
|
||||
for latest_msg in latest_messages:
|
||||
user_id = latest_msg.get("user_id")
|
||||
platform = latest_msg.get("user_platform") or latest_msg.get("chat_info_platform")
|
||||
msg_time = latest_msg.get("time", 0)
|
||||
|
||||
if (
|
||||
user_id
|
||||
and platform
|
||||
and user_id != global_config.bot.qq_account
|
||||
and msg_time > self.last_processed_message_time
|
||||
):
|
||||
from src.person_info.person_info import PersonInfoManager
|
||||
|
||||
person_id = PersonInfoManager.get_person_id(platform, user_id)
|
||||
self._update_message_segments(person_id, msg_time)
|
||||
logger.debug(
|
||||
f"{self.log_prefix} 更新用户 {person_id} 的消息段,消息时间:{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(msg_time))}"
|
||||
)
|
||||
self.last_processed_message_time = max(self.last_processed_message_time, msg_time)
|
||||
break
|
||||
|
||||
for person_id in list(self.info_fetched_cache.keys()):
|
||||
for info_type in list(self.info_fetched_cache[person_id].keys()):
|
||||
self.info_fetched_cache[person_id][info_type]["ttl"] -= 1
|
||||
@@ -618,7 +573,33 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
if not self.info_fetched_cache[person_id]:
|
||||
del self.info_fetched_cache[person_id]
|
||||
|
||||
# 5. 为需要处理的人员准备LLM prompt
|
||||
if action_type != "reply":
|
||||
return None
|
||||
|
||||
target_message = action_data.get("reply_to", "")
|
||||
|
||||
if ":" in target_message:
|
||||
parts = target_message.split(":", 1)
|
||||
elif ":" in target_message:
|
||||
parts = target_message.split(":", 1)
|
||||
else:
|
||||
logger.warning(f"reply_to格式不正确: {target_message},跳过关系识别")
|
||||
return None
|
||||
|
||||
if len(parts) != 2:
|
||||
logger.warning(f"reply_to格式不正确: {target_message},跳过关系识别")
|
||||
return None
|
||||
|
||||
sender = parts[0].strip()
|
||||
text = parts[1].strip()
|
||||
|
||||
person_info_manager = get_person_info_manager()
|
||||
person_id = person_info_manager.get_person_id_by_person_name(sender)
|
||||
|
||||
if not person_id:
|
||||
logger.warning(f"未找到用户 {sender} 的ID,跳过关系识别")
|
||||
return None
|
||||
|
||||
nickname_str = ",".join(global_config.bot.alias_names)
|
||||
name_block = f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。"
|
||||
|
||||
@@ -638,19 +619,16 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
f"你已经调取了[{info_fetching['person_name']}]的[{info_fetching['info_type']}]信息\n"
|
||||
)
|
||||
|
||||
example_json = _generate_random_prompt_example()
|
||||
|
||||
prompt = (await global_prompt_manager.get_prompt_async("relationship_prompt")).format(
|
||||
name_block=name_block,
|
||||
bot_name=global_config.bot.nickname,
|
||||
time_now=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
|
||||
chat_observe_info=chat_observe_info,
|
||||
name_block=name_block,
|
||||
info_cache_block=info_cache_block,
|
||||
example_json=example_json,
|
||||
person_name=sender,
|
||||
target_message=text,
|
||||
)
|
||||
|
||||
try:
|
||||
logger.debug(f"{self.log_prefix} 人物信息prompt: \n{prompt}\n")
|
||||
logger.info(f"{self.log_prefix} 人物信息prompt: \n{prompt}\n")
|
||||
content, _ = await self.llm_model.generate_response_async(prompt=prompt)
|
||||
if content:
|
||||
# print(f"content: {content}")
|
||||
@@ -661,29 +639,12 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
logger.info(f"{self.log_prefix} LLM判断当前不需要查询任何信息:{content_json.get('none', '')}")
|
||||
# 跳过新的信息提取,但仍会处理已有缓存
|
||||
else:
|
||||
# 收集即时提取任务
|
||||
instant_tasks = []
|
||||
async_tasks = []
|
||||
|
||||
person_info_manager = get_person_info_manager()
|
||||
for person_name, info_type in content_json.items():
|
||||
is_bot = (
|
||||
person_name == global_config.bot.nickname or person_name in global_config.bot.alias_names
|
||||
)
|
||||
if is_bot:
|
||||
person_id = person_info_manager.get_person_id("system", "bot_id")
|
||||
logger.info(f"{self.log_prefix} 检测到对bot自身({person_name})的信息查询,使用特殊ID。")
|
||||
else:
|
||||
person_id = person_info_manager.get_person_id_by_person_name(person_name)
|
||||
|
||||
if not person_id:
|
||||
logger.warning(f"{self.log_prefix} 未找到用户 {person_name} 的ID,跳过调取信息。")
|
||||
continue
|
||||
|
||||
info_type = content_json.get("info_type")
|
||||
if info_type:
|
||||
self.info_fetching_cache.append(
|
||||
{
|
||||
"person_id": person_id,
|
||||
"person_name": person_name,
|
||||
"person_name": sender,
|
||||
"info_type": info_type,
|
||||
"start_time": time.time(),
|
||||
"forget": False,
|
||||
@@ -692,22 +653,12 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
if len(self.info_fetching_cache) > 20:
|
||||
self.info_fetching_cache.pop(0)
|
||||
|
||||
logger.info(f"{self.log_prefix} 调取用户 {person_name} 的 {info_type} 信息。")
|
||||
logger.info(f"{self.log_prefix} 调取用户 {sender} 的[{info_type}]信息。")
|
||||
|
||||
# 收集即时提取任务
|
||||
instant_tasks.append((person_id, info_type, time.time()))
|
||||
|
||||
# 执行即时提取任务
|
||||
if instant_tasks:
|
||||
await self._execute_instant_extraction_batch(instant_tasks)
|
||||
|
||||
# 启动异步任务(如果不是即时模式)
|
||||
if async_tasks:
|
||||
# 异步任务不需要等待完成
|
||||
pass
|
||||
|
||||
else:
|
||||
logger.warning(f"{self.log_prefix} LLM返回空结果,关系识别失败。")
|
||||
# 执行信息提取
|
||||
await self._fetch_single_info_instant(person_id, info_type, time.time())
|
||||
else:
|
||||
logger.warning(f"{self.log_prefix} LLM did not return a valid info_type. Response: {content}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 执行LLM请求或处理响应时出错: {e}")
|
||||
@@ -838,31 +789,6 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
# 负责实时分析对话需求、提取用户信息、管理信息缓存
|
||||
# ================================
|
||||
|
||||
async def _execute_instant_extraction_batch(self, instant_tasks: list):
|
||||
"""
|
||||
批量执行即时提取任务
|
||||
"""
|
||||
if not instant_tasks:
|
||||
return
|
||||
|
||||
logger.info(f"{self.log_prefix} [即时提取] 开始批量提取 {len(instant_tasks)} 个信息")
|
||||
|
||||
# 创建所有提取任务
|
||||
extraction_tasks = []
|
||||
for person_id, info_type, start_time in instant_tasks:
|
||||
# 检查缓存中是否已存在且未过期的信息
|
||||
if person_id in self.info_fetched_cache and info_type in self.info_fetched_cache[person_id]:
|
||||
logger.debug(f"{self.log_prefix} 用户 {person_id} 的 {info_type} 信息已存在且未过期,跳过调取。")
|
||||
continue
|
||||
|
||||
task = asyncio.create_task(self._fetch_single_info_instant(person_id, info_type, start_time))
|
||||
extraction_tasks.append(task)
|
||||
|
||||
# 并行执行所有提取任务并等待完成
|
||||
if extraction_tasks:
|
||||
await asyncio.gather(*extraction_tasks, return_exceptions=True)
|
||||
logger.info(f"{self.log_prefix} [即时提取] 批量提取完成")
|
||||
|
||||
async def _fetch_single_info_instant(self, person_id: str, info_type: str, start_time: float):
|
||||
"""
|
||||
使用小模型提取单个信息类型
|
||||
@@ -890,7 +816,7 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
|
||||
self.info_fetched_cache[person_id][info_type] = {
|
||||
"info": cached_info,
|
||||
"ttl": 4,
|
||||
"ttl": 2,
|
||||
"start_time": start_time,
|
||||
"person_name": person_name,
|
||||
"unknow": cached_info == "none",
|
||||
@@ -898,9 +824,6 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
logger.info(f"{self.log_prefix} 记得 {person_name} 的 {info_type}: {cached_info}")
|
||||
return
|
||||
|
||||
bot_person_id = PersonInfoManager.get_person_id("system", "bot_id")
|
||||
is_bot = person_id == bot_person_id
|
||||
|
||||
try:
|
||||
person_name = await person_info_manager.get_value(person_id, "person_name")
|
||||
person_impression = await person_info_manager.get_value(person_id, "impression")
|
||||
@@ -923,7 +846,7 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
self.info_fetched_cache[person_id] = {}
|
||||
self.info_fetched_cache[person_id][info_type] = {
|
||||
"info": "none",
|
||||
"ttl": 4,
|
||||
"ttl": 2,
|
||||
"start_time": start_time,
|
||||
"person_name": person_name,
|
||||
"unknow": True,
|
||||
@@ -932,27 +855,16 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
await self._save_info_to_cache(person_id, info_type, "none")
|
||||
return
|
||||
|
||||
if is_bot:
|
||||
prompt = (await global_prompt_manager.get_prompt_async("fetch_bot_info_prompt")).format(
|
||||
nickname=global_config.bot.nickname,
|
||||
alias_names=",".join(global_config.bot.alias_names),
|
||||
info_type=info_type,
|
||||
person_impression_block=person_impression_block,
|
||||
points_text_block=points_text_block,
|
||||
)
|
||||
else:
|
||||
nickname_str = ",".join(global_config.bot.alias_names)
|
||||
name_block = (
|
||||
f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。"
|
||||
)
|
||||
prompt = (await global_prompt_manager.get_prompt_async("fetch_person_info_prompt")).format(
|
||||
name_block=name_block,
|
||||
info_type=info_type,
|
||||
person_impression_block=person_impression_block,
|
||||
person_name=person_name,
|
||||
info_json_str=f'"{info_type}": "有关{info_type}的信息内容"',
|
||||
points_text_block=points_text_block,
|
||||
)
|
||||
nickname_str = ",".join(global_config.bot.alias_names)
|
||||
name_block = f"你的名字是{global_config.bot.nickname},你的昵称有{nickname_str},有人也会用这些昵称称呼你。"
|
||||
prompt = (await global_prompt_manager.get_prompt_async("fetch_person_info_prompt")).format(
|
||||
name_block=name_block,
|
||||
info_type=info_type,
|
||||
person_impression_block=person_impression_block,
|
||||
person_name=person_name,
|
||||
info_json_str=f'"{info_type}": "有关{info_type}的信息内容"',
|
||||
points_text_block=points_text_block,
|
||||
)
|
||||
except Exception:
|
||||
logger.error(traceback.format_exc())
|
||||
return
|
||||
@@ -972,7 +884,7 @@ class PersonImpressionpProcessor(BaseProcessor):
|
||||
self.info_fetched_cache[person_id] = {}
|
||||
self.info_fetched_cache[person_id][info_type] = {
|
||||
"info": "unknow" if is_unknown else info_content,
|
||||
"ttl": 8,
|
||||
"ttl": 3,
|
||||
"start_time": start_time,
|
||||
"person_name": person_name,
|
||||
"unknow": is_unknown,
|
||||
|
||||
@@ -8,7 +8,7 @@ from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
|
||||
from src.tools.tool_use import ToolUser
|
||||
from src.chat.utils.json_utils import process_llm_tool_calls
|
||||
from .base_processor import BaseProcessor
|
||||
from typing import List, Optional
|
||||
from typing import List
|
||||
from src.chat.heart_flow.observation.observation import Observation
|
||||
from src.chat.focus_chat.info.structured_info import StructuredInfo
|
||||
from src.chat.heart_flow.observation.structure_observation import StructureObservation
|
||||
@@ -47,13 +47,20 @@ class ToolProcessor(BaseProcessor):
|
||||
)
|
||||
self.structured_info = []
|
||||
|
||||
async def process_info(self, observations: Optional[List[Observation]] = None) -> List[StructuredInfo]:
|
||||
async def process_info(
|
||||
self,
|
||||
observations: List[Observation] = None,
|
||||
action_type: str = None,
|
||||
action_data: dict = None,
|
||||
**kwargs,
|
||||
) -> List[StructuredInfo]:
|
||||
"""处理信息对象
|
||||
|
||||
Args:
|
||||
observations: 可选的观察列表,包含ChattingObservation和StructureObservation类型
|
||||
running_memories: 可选的运行时记忆列表,包含字典类型的记忆信息
|
||||
*infos: 可变数量的InfoBase类型的信息对象
|
||||
action_type: 动作类型
|
||||
action_data: 动作数据
|
||||
**kwargs: 其他可选参数
|
||||
|
||||
Returns:
|
||||
list: 处理后的结构化信息列表
|
||||
@@ -85,7 +92,7 @@ class ToolProcessor(BaseProcessor):
|
||||
|
||||
return [structured_info]
|
||||
|
||||
async def execute_tools(self, observation: ChattingObservation):
|
||||
async def execute_tools(self, observation: ChattingObservation, action_type: str = None, action_data: dict = None):
|
||||
"""
|
||||
并行执行工具,返回结构化信息
|
||||
|
||||
@@ -95,6 +102,8 @@ class ToolProcessor(BaseProcessor):
|
||||
is_group_chat: 是否为群聊,默认为False
|
||||
return_details: 是否返回详细信息,默认为False
|
||||
cycle_info: 循环信息对象,可用于记录详细执行信息
|
||||
action_type: 动作类型
|
||||
action_data: 动作数据
|
||||
|
||||
返回:
|
||||
如果return_details为False:
|
||||
|
||||
@@ -470,7 +470,7 @@ class ActionModifier:
|
||||
response = response.strip().lower()
|
||||
|
||||
# print(base_prompt)
|
||||
print(f"LLM判定动作 {action_name}:响应='{response}'")
|
||||
# print(f"LLM判定动作 {action_name}:响应='{response}'")
|
||||
|
||||
should_activate = "是" in response or "yes" in response or "true" in response
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ class NormalChat:
|
||||
"message_count": self._count_messages_in_timerange(potential_start_time, message_time),
|
||||
}
|
||||
segments.append(new_segment)
|
||||
logger.info(
|
||||
logger.debug(
|
||||
f"[{self.stream_name}] 为用户 {person_id} 创建新消息段: 时间范围 {time.strftime('%H:%M:%S', time.localtime(potential_start_time))} - {time.strftime('%H:%M:%S', time.localtime(message_time))}, 消息数: {new_segment['message_count']}"
|
||||
)
|
||||
self._save_cache()
|
||||
@@ -230,7 +230,7 @@ class NormalChat:
|
||||
"message_count": self._count_messages_in_timerange(potential_start_time, message_time),
|
||||
}
|
||||
segments.append(new_segment)
|
||||
logger.info(f"[{self.stream_name}] 为用户 {person_id} 创建新消息段(超过10条消息间隔): {new_segment}")
|
||||
logger.debug(f"[{self.stream_name}] 为用户 {person_id} 创建新消息段(超过10条消息间隔): {new_segment}")
|
||||
|
||||
self._save_cache()
|
||||
|
||||
|
||||
@@ -53,7 +53,9 @@ async def generate_with_model(
|
||||
Tuple[bool, str, str, str]: (是否成功, 生成的内容, 推理过程, 模型名称)
|
||||
"""
|
||||
try:
|
||||
logger.info(f"[LLMAPI] 使用模型生成内容,提示词: {prompt[:200]}...")
|
||||
model_name = model_config.get("name")
|
||||
logger.info(f"[LLMAPI] 使用模型 {model_name} 生成内容")
|
||||
logger.debug(f"[LLMAPI] 完整提示词: {prompt}")
|
||||
|
||||
llm_request = LLMRequest(model=model_config, request_type=request_type, **kwargs)
|
||||
|
||||
|
||||
@@ -343,14 +343,15 @@ class NoReplyAction(BaseAction):
|
||||
|
||||
if success and response:
|
||||
response = response.strip()
|
||||
logger.info(f"{self.log_prefix} 模型({model_name})原始JSON响应: {response}")
|
||||
logger.debug(f"{self.log_prefix} 模型({model_name})原始JSON响应: {response}")
|
||||
|
||||
# 解析LLM的JSON响应,提取判断结果和理由
|
||||
judge_result, reason = self._parse_llm_judge_response(response)
|
||||
|
||||
logger.info(
|
||||
f"{self.log_prefix} JSON解析结果 - 判断: {judge_result}, 理由: {reason}"
|
||||
)
|
||||
if judge_result:
|
||||
logger.info(f"{self.log_prefix} 决定继续参与讨论,结束等待,原因: {reason}")
|
||||
else:
|
||||
logger.info(f"{self.log_prefix} 决定不参与讨论,继续等待,原因: {reason}")
|
||||
|
||||
# 将判断结果保存到历史中
|
||||
judge_history.append((current_time, judge_result, reason))
|
||||
|
||||
Reference in New Issue
Block a user