From 67c24f84cd3ff7874c4e6ac706ce6a0aa280e868 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Wed, 31 Dec 2025 00:07:55 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E6=97=A5=E5=BF=97=E4=B8=8A?= =?UTF-8?q?=E7=BA=BF=E6=95=B0=E9=87=8F=E5=8F=AF=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/MaiBot_MCPBridgePlugin/plugin.py | 10 +++---- plugins/MaiBot_MCPBridgePlugin/tool_chain.py | 3 +-- scripts/analyze_evaluation_stats.py | 26 +++++++++---------- scripts/lpmm_manager.py | 2 +- src/bw_learner/jargon_miner.py | 8 +----- src/chat/knowledge/qa_manager.py | 3 +-- src/chat/logger/plan_reply_logger.py | 11 ++++++-- src/config/official_configs.py | 3 +++ src/dream/dream_generator.py | 1 - src/memory_system/chat_history_summarizer.py | 2 +- .../retrieval_tools/query_words.py | 1 - src/plugin_system/apis/message_api.py | 1 - src/webui/anti_crawler.py | 1 - src/webui/expression_routes.py | 2 +- template/bot_config_template.toml | 4 ++- 15 files changed, 38 insertions(+), 40 deletions(-) diff --git a/plugins/MaiBot_MCPBridgePlugin/plugin.py b/plugins/MaiBot_MCPBridgePlugin/plugin.py index 06055c6b..c202e852 100644 --- a/plugins/MaiBot_MCPBridgePlugin/plugin.py +++ b/plugins/MaiBot_MCPBridgePlugin/plugin.py @@ -113,8 +113,6 @@ from .core.claude_config import ( ) from .tool_chain import ( ToolChainDefinition, - ToolChainStep, - ChainExecutionResult, tool_chain_manager, ) @@ -1651,7 +1649,7 @@ class MCPStatusCommand(BaseCommand): tool_name = f"chain_{name}".replace("-", "_").replace(".", "_") if component_registry.get_component_info(tool_name, ComponentType.TOOL): registered += 1 - lines = [f"✅ 已重新加载工具链配置"] + lines = ["✅ 已重新加载工具链配置"] lines.append(f"📋 配置数: {len(chains)} 个") lines.append(f"🔧 已注册: {registered} 个(可被 LLM 调用)") if chains: @@ -1698,7 +1696,7 @@ class MCPStatusCommand(BaseCommand): output_preview += "..." lines.append(output_preview) else: - lines.append(f"❌ 工具链执行失败") + lines.append("❌ 工具链执行失败") lines.append(f"错误: {result.error}") if result.step_results: lines.append("") @@ -1777,9 +1775,9 @@ class MCPStatusCommand(BaseCommand): cb = info.get("circuit_breaker", {}) cb_state = cb.get("state", "closed") if cb_state == "open": - lines.append(f" ⚡ 断路器熔断中") + lines.append(" ⚡ 断路器熔断中") elif cb_state == "half_open": - lines.append(f" ⚡ 断路器试探中") + lines.append(" ⚡ 断路器试探中") if info["consecutive_failures"] > 0: lines.append(f" ⚠️ 连续失败 {info['consecutive_failures']} 次") diff --git a/plugins/MaiBot_MCPBridgePlugin/tool_chain.py b/plugins/MaiBot_MCPBridgePlugin/tool_chain.py index 2be515f1..96837b94 100644 --- a/plugins/MaiBot_MCPBridgePlugin/tool_chain.py +++ b/plugins/MaiBot_MCPBridgePlugin/tool_chain.py @@ -14,12 +14,11 @@ MCP Workflow 模块 v1.9.0 - 与 ReAct 软流程互补,用户可选择合适的执行方式 """ -import asyncio import json import re import time from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional, Tuple, Type +from typing import Any, Dict, List, Optional, Tuple try: from src.common.logger import get_logger diff --git a/scripts/analyze_evaluation_stats.py b/scripts/analyze_evaluation_stats.py index ff7d7b3b..9eec6243 100644 --- a/scripts/analyze_evaluation_stats.py +++ b/scripts/analyze_evaluation_stats.py @@ -11,7 +11,7 @@ import json import os import sys import glob -from collections import Counter, defaultdict +from collections import Counter from datetime import datetime from typing import Dict, List, Set, Tuple @@ -147,7 +147,7 @@ def print_file_stats(stats: Dict, index: int = None): if stats["last_updated"]: print(f"最后更新: {stats['last_updated']}") - print(f"\n【记录统计】") + print("\n【记录统计】") print(f" 文件中的 total_count: {stats['total_count']}") print(f" 实际记录数: {stats['actual_count']}") @@ -155,18 +155,18 @@ def print_file_stats(stats: Dict, index: int = None): diff = stats['total_count'] - stats['actual_count'] print(f" ⚠️ 数量不一致,差值: {diff:+d}") - print(f"\n【评估结果统计】") + print("\n【评估结果统计】") print(f" 通过 (suitable=True): {stats['suitable_count']} 条 ({stats['suitable_rate']:.2f}%)") print(f" 不通过 (suitable=False): {stats['unsuitable_count']} 条 ({100 - stats['suitable_rate']:.2f}%)") - print(f"\n【唯一性统计】") + print("\n【唯一性统计】") print(f" 唯一 (situation, style) 对: {stats['unique_pairs']} 条") if stats['actual_count'] > 0: duplicate_count = stats['actual_count'] - stats['unique_pairs'] duplicate_rate = (duplicate_count / stats['actual_count'] * 100) if stats['actual_count'] > 0 else 0 print(f" 重复记录: {duplicate_count} 条 ({duplicate_rate:.2f}%)") - print(f"\n【评估者统计】") + print("\n【评估者统计】") if stats['evaluators']: for evaluator, count in stats['evaluators'].most_common(): rate = (count / stats['actual_count'] * 100) if stats['actual_count'] > 0 else 0 @@ -174,7 +174,7 @@ def print_file_stats(stats: Dict, index: int = None): else: print(" 无评估者信息") - print(f"\n【时间统计】") + print("\n【时间统计】") if stats['date_range']: print(f" 最早评估时间: {stats['date_range']['start']}") print(f" 最晚评估时间: {stats['date_range']['end']}") @@ -182,7 +182,7 @@ def print_file_stats(stats: Dict, index: int = None): else: print(" 无时间信息") - print(f"\n【字段统计】") + print("\n【字段统计】") print(f" 包含 expression_id: {'是' if stats['has_expression_id'] else '否'}") print(f" 包含 reason: {'是' if stats['has_reason'] else '否'}") if stats['has_reason']: @@ -200,13 +200,13 @@ def print_summary(all_stats: List[Dict]): valid_files = [s for s in all_stats if not s.get("error")] error_files = [s for s in all_stats if s.get("error")] - print(f"\n【文件统计】") + print("\n【文件统计】") print(f" 总文件数: {total_files}") print(f" 成功解析: {len(valid_files)}") print(f" 解析失败: {len(error_files)}") if error_files: - print(f"\n 失败文件列表:") + print("\n 失败文件列表:") for stats in error_files: print(f" - {stats['file_name']}: {stats['error']}") @@ -232,7 +232,7 @@ def print_summary(all_stats: List[Dict]): except Exception: pass - print(f"\n【记录汇总】") + print("\n【记录汇总】") print(f" 总记录数: {total_records:,} 条") print(f" 通过: {total_suitable:,} 条 ({total_suitable / total_records * 100:.2f}%)" if total_records > 0 else " 通过: 0 条") print(f" 不通过: {total_unsuitable:,} 条 ({total_unsuitable / total_records * 100:.2f}%)" if total_records > 0 else " 不通过: 0 条") @@ -248,7 +248,7 @@ def print_summary(all_stats: List[Dict]): for stats in valid_files: all_evaluators.update(stats['evaluators']) - print(f"\n【评估者汇总】") + print("\n【评估者汇总】") if all_evaluators: for evaluator, count in all_evaluators.most_common(): rate = (count / total_records * 100) if total_records > 0 else 0 @@ -264,7 +264,7 @@ def print_summary(all_stats: List[Dict]): if all_dates: min_date = min(all_dates) max_date = max(all_dates) - print(f"\n【时间汇总】") + print("\n【时间汇总】") print(f" 最早评估时间: {min_date.isoformat()}") print(f" 最晚评估时间: {max_date.isoformat()}") print(f" 总时间跨度: {(max_date - min_date).days + 1} 天") @@ -272,7 +272,7 @@ def print_summary(all_stats: List[Dict]): # 文件大小汇总 total_size = sum(s['file_size'] for s in valid_files) avg_size = total_size / len(valid_files) if valid_files else 0 - print(f"\n【文件大小汇总】") + print("\n【文件大小汇总】") print(f" 总大小: {total_size:,} 字节 ({total_size / 1024 / 1024:.2f} MB)") print(f" 平均大小: {avg_size:,.0f} 字节 ({avg_size / 1024:.2f} KB)") diff --git a/scripts/lpmm_manager.py b/scripts/lpmm_manager.py index 9ca42254..60f32364 100644 --- a/scripts/lpmm_manager.py +++ b/scripts/lpmm_manager.py @@ -470,7 +470,7 @@ def _run_embedding_helper() -> None: test_path.rename(archive_path) except Exception as exc: # pragma: no cover - 防御性兜底 logger.error("归档 embedding_model_test.json 失败: %s", exc) - print(f"[ERROR] 归档 embedding_model_test.json 失败,请检查文件权限与路径。错误详情已写入日志。") + print("[ERROR] 归档 embedding_model_test.json 失败,请检查文件权限与路径。错误详情已写入日志。") return print( diff --git a/src/bw_learner/jargon_miner.py b/src/bw_learner/jargon_miner.py index 947d311e..4089f33d 100644 --- a/src/bw_learner/jargon_miner.py +++ b/src/bw_learner/jargon_miner.py @@ -2,7 +2,7 @@ import json import asyncio import random from collections import OrderedDict -from typing import List, Dict, Optional, Any, Callable +from typing import List, Dict, Optional, Callable from json_repair import repair_json from peewee import fn @@ -11,14 +11,8 @@ from src.common.database.database_model import Jargon from src.llm_models.utils_model import LLMRequest from src.config.config import model_config, global_config from src.chat.message_receive.chat_stream import get_chat_manager -from src.chat.utils.chat_message_builder import ( - build_readable_messages_with_id, -) from src.chat.utils.prompt_builder import Prompt, global_prompt_manager from src.bw_learner.learner_utils import ( - is_bot_message, - build_context_paragraph, - contains_bot_self_name, parse_chat_id_list, chat_id_list_contains, update_chat_id_list, diff --git a/src/chat/knowledge/qa_manager.py b/src/chat/knowledge/qa_manager.py index c3def2ed..8ba49bb8 100644 --- a/src/chat/knowledge/qa_manager.py +++ b/src/chat/knowledge/qa_manager.py @@ -7,9 +7,8 @@ from .kg_manager import KGManager # from .lpmmconfig import global_config from .utils.dyn_topk import dyn_select_top_k -from src.llm_models.utils_model import LLMRequest from src.chat.utils.utils import get_embedding -from src.config.config import global_config, model_config +from src.config.config import global_config MAX_KNOWLEDGE_LENGTH = 10000 # 最大知识长度 diff --git a/src/chat/logger/plan_reply_logger.py b/src/chat/logger/plan_reply_logger.py index d1f720dc..d81101f0 100644 --- a/src/chat/logger/plan_reply_logger.py +++ b/src/chat/logger/plan_reply_logger.py @@ -4,6 +4,8 @@ from pathlib import Path from typing import Any, Dict, List, Optional from uuid import uuid4 +from src.config.config import global_config + class PlanReplyLogger: """独立的Plan/Reply日志记录器,负责落盘和容量控制。""" @@ -11,9 +13,13 @@ class PlanReplyLogger: _BASE_DIR = Path("logs") _PLAN_DIR = _BASE_DIR / "plan" _REPLY_DIR = _BASE_DIR / "reply" - _MAX_PER_CHAT = 1000 _TRIM_COUNT = 100 + @classmethod + def _get_max_per_chat(cls) -> int: + """从配置中获取每个聊天流最大保存的日志数量""" + return getattr(global_config.chat, "plan_reply_log_max_per_chat", 1000) + @classmethod def log_plan( cls, @@ -85,7 +91,8 @@ class PlanReplyLogger: def _trim_overflow(cls, chat_dir: Path) -> None: """超过阈值时删除最老的若干文件,避免目录无限增长。""" files = sorted(chat_dir.glob("*.json"), key=lambda p: p.stat().st_mtime) - if len(files) <= cls._MAX_PER_CHAT: + max_per_chat = cls._get_max_per_chat() + if len(files) <= max_per_chat: return # 删除最老的 TRIM_COUNT 条 for old_file in files[: cls._TRIM_COUNT]: diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 791c0f3e..514d2639 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -122,6 +122,9 @@ class ChatConfig(ConfigBase): - dynamic: think_level由planner动态给出(根据planner返回的think_level决定) """ + plan_reply_log_max_per_chat: int = 1024 + """每个聊天流最大保存的Plan/Reply日志数量,超过此数量时会自动删除最老的日志""" + def _parse_stream_config_to_chat_id(self, stream_config_str: str) -> Optional[str]: """与 ChatStream.get_stream_id 一致地从 "platform:id:type" 生成 chat_id。""" try: diff --git a/src/dream/dream_generator.py b/src/dream/dream_generator.py index 3fe20f1c..dd830ed0 100644 --- a/src/dream/dream_generator.py +++ b/src/dream/dream_generator.py @@ -189,7 +189,6 @@ async def generate_dream_summary( summary_model = get_dream_summary_model() dream_content, (reasoning, model_name, _) = await summary_model.generate_response_async( dream_prompt, - max_tokens=512, temperature=0.8, ) diff --git a/src/memory_system/chat_history_summarizer.py b/src/memory_system/chat_history_summarizer.py index 330cc8bc..d290337f 100644 --- a/src/memory_system/chat_history_summarizer.py +++ b/src/memory_system/chat_history_summarizer.py @@ -15,7 +15,7 @@ from json_repair import repair_json from src.common.logger import get_logger from src.common.data_models.database_data_model import DatabaseMessages -from src.config.config import global_config, model_config +from src.config.config import model_config from src.llm_models.utils_model import LLMRequest from src.plugin_system.apis import message_api from src.chat.utils.chat_message_builder import build_readable_messages diff --git a/src/memory_system/retrieval_tools/query_words.py b/src/memory_system/retrieval_tools/query_words.py index 02b5eff3..2d7a0c60 100644 --- a/src/memory_system/retrieval_tools/query_words.py +++ b/src/memory_system/retrieval_tools/query_words.py @@ -3,7 +3,6 @@ 用于在记忆检索过程中主动查询未知词语或黑话的含义 """ -from typing import List, Optional from src.common.logger import get_logger from src.bw_learner.jargon_explainer import retrieve_concepts_with_jargon from .tool_registry import register_memory_retrieval_tool diff --git a/src/plugin_system/apis/message_api.py b/src/plugin_system/apis/message_api.py index 50a0497c..12578000 100644 --- a/src/plugin_system/apis/message_api.py +++ b/src/plugin_system/apis/message_api.py @@ -12,7 +12,6 @@ import time from typing import List, Dict, Any, Tuple, Optional from src.common.data_models.database_data_model import DatabaseMessages from src.common.database.database_model import Images -from src.config.config import global_config from src.chat.utils.utils import is_bot_self from src.chat.utils.chat_message_builder import ( get_raw_msg_by_timestamp, diff --git a/src/webui/anti_crawler.py b/src/webui/anti_crawler.py index 28d87170..b489179b 100644 --- a/src/webui/anti_crawler.py +++ b/src/webui/anti_crawler.py @@ -3,7 +3,6 @@ WebUI 防爬虫模块 提供爬虫检测和阻止功能,保护 WebUI 不被搜索引擎和恶意爬虫访问 """ -import os import time import ipaddress import re diff --git a/src/webui/expression_routes.py b/src/webui/expression_routes.py index f1befe2b..d3586947 100644 --- a/src/webui/expression_routes.py +++ b/src/webui/expression_routes.py @@ -1,7 +1,7 @@ """表达方式管理 API 路由""" from fastapi import APIRouter, HTTPException, Header, Query, Cookie -from pydantic import BaseModel, NonNegativeFloat +from pydantic import BaseModel from typing import Optional, List, Dict from src.common.logger import get_logger from src.common.database.database_model import Expression, ChatStreams diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index b01f032a..d84ae494 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "7.3.1" +version = "7.3.2" #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- # 如果你想要修改配置文件,请递增version的值 @@ -116,6 +116,8 @@ max_context_size = 30 # 上下文长度 planner_smooth = 3 # 规划器平滑,增大数值会减小planner负荷,略微降低反应速度,推荐1-5,0为关闭,必须大于等于0 think_mode = "dynamic" # 思考模式,可选:classic(默认浅度思考和回复)、deep(会进行比较长的,深度回复)、dynamic(动态选择两种模式) +plan_reply_log_max_per_chat = 1024 # 每个聊天保存最大的Plan/Reply日志数量,超过此数量时会自动删除最老的日志 + enable_talk_value_rules = true # 是否启用动态发言频率规则 # 动态发言频率规则:按时段/按chat_id调整 talk_value(优先匹配具体chat,再匹配全局)