From b1b08c181475d47994159424353c5ec047aa2eb4 Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Thu, 21 Aug 2025 12:32:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0=E4=BA=86=E6=9C=88?= =?UTF-8?q?=E5=BA=A6=E8=AE=A1=E5=88=92=20#=20=E6=88=91=E8=A6=81=E6=B7=B7?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/schedule_enhancement (1).md | 121 +++++++++++++++++++++++ src/common/database/monthly_plan_db.py | 68 +++++++++++++ src/common/database/sqlalchemy_models.py | 13 +++ src/common/logger.py | 2 + src/config/api_ada_configs.py | 1 + src/config/config.py | 4 +- src/config/official_configs.py | 9 ++ src/main.py | 8 ++ src/manager/schedule_manager.py | 55 ++++++++--- src/schedule/monthly_plan_manager.py | 106 ++++++++++++++++++++ src/schedule/plan_generator.py | 118 ++++++++++++++++++++++ template/bot_config_template.toml | 15 ++- template/model_config_template.toml | 7 +- 13 files changed, 512 insertions(+), 15 deletions(-) create mode 100644 docs/schedule_enhancement (1).md create mode 100644 src/common/database/monthly_plan_db.py create mode 100644 src/schedule/monthly_plan_manager.py create mode 100644 src/schedule/plan_generator.py diff --git a/docs/schedule_enhancement (1).md b/docs/schedule_enhancement (1).md new file mode 100644 index 000000000..aea1b8eb1 --- /dev/null +++ b/docs/schedule_enhancement (1).md @@ -0,0 +1,121 @@ +# “月层计划”系统架构设计文档 + +## 1. 系统概述与目标 + +本系统旨在为Bot引入一个动态的、由大型语言模型(LLM)驱动的“月层计划”机制。其核心目标是取代静态、预设的任务模板,转而利用LLM在程序启动时自动生成符合Bot人设的、具有时效性的月度计划。这些计划将被存储、管理,并在构建每日日程时被动态抽取和使用,从而极大地丰富日程内容的个性和多样性。 + +--- + +## 2. 核心设计原则 + +- **动态性与智能化:** 所有计划内容均由LLM实时生成,确保其独特性和创造性。 +- **人设一致性:** 计划的生成将严格围绕Bot的核心人设进行,强化角色形象。 +- **持久化与可管理:** 生成的计划将被存入专用数据库表,便于管理和追溯。 +- **消耗性与随机性:** 计划在使用后有一定几率被消耗(删除),模拟真实世界中计划的完成与迭代。 + +--- + +## 3. 系统核心流程规划 + +本系统包含两大核心流程:**启动时的计划生成流程**和**日程构建时的计划使用流程**。 + +### 3.1 流程一:启动时计划生成 + +此流程在每次程序启动时触发,负责填充当月的计划池。 + +```mermaid +graph TD + A[程序启动] --> B{检查当月计划池}; + B -- 计划数量低于阈值 --> C[构建LLM Prompt]; + C -- prompt包含Bot人设、月份等信息 --> D[调用LLM服务]; + D -- LLM返回多个计划文本 --> E[解析并格式化计划]; + E -- 逐条处理 --> F[存入`monthly_plans`数据库表]; + F --> G[完成启动任务]; + B -- 计划数量充足 --> G; +``` + +### 3.2 流程二:日程构建时计划使用 + +此流程在构建每日日程的提示词(Prompt)时触发。 + +```mermaid +graph TD + H[构建日程Prompt] --> I{查询数据库}; + I -- 读取当月未使用的计划 --> J[随机抽取N个计划]; + J --> K[将计划文本嵌入日程Prompt]; + K --> L{随机数判断}; + L -- 概率命中 --> M[将已抽取的计划标记为删除]; + M --> N[完成Prompt构建]; + L -- 概率未命中 --> N; +``` + +--- + +## 4. 数据库模型设计 + +为支撑本系统,需要新增一个数据库表。 + +**表名:** `monthly_plans` + +| 字段名 | 类型 | 描述 | +| :--- | :--- | :--- | +| `id` | Integer | 主键,自增。 | +| `plan_text` | Text | 由LLM生成的计划内容原文。 | +| `target_month` | String(7) | 计划所属的月份,格式为 "YYYY-MM"。 | +| `is_deleted` | Boolean | 软删除标记,默认为 `false`。 | +| `created_at` | DateTime | 记录创建时间。 | + +--- + +## 5. 详细模块规划 + +### 5.1 LLM Prompt生成模块 + +- **职责:** 构建高质量的Prompt以引导LLM生成符合要求的计划。 +- **输入:** Bot人设描述、当前月份、期望生成的计划数量。 +- **输出:** 一个结构化的Prompt字符串。 +- **Prompt示例:** + ``` + 你是一个[此处填入Bot人设描述,例如:活泼开朗、偶尔有些小迷糊的虚拟助手]。 + 请为即将到来的[YYYY年MM月]设计[N]个符合你身份的月度计划或目标。 + + 要求: + 1. 每个计划都是独立的、积极向上的。 + 2. 语言风格要自然、口语化,符合你的性格。 + 3. 每个计划用一句话或两句话简短描述。 + 4. 以JSON格式返回,格式为:{"plans": ["计划一", "计划二", ...]} + ``` + +### 5.2 数据库交互模块 + +- **职责:** 提供对 `monthly_plans` 表的增、删、改、查接口。 +- **规划函数列表:** + - `add_new_plans(plans: list[str], month: str)`: 批量添加新生成的计划。 + - `get_active_plans_for_month(month: str) -> list`: 获取指定月份所有未被删除的计划。 + - `soft_delete_plans(plan_ids: list[int])`: 将指定ID的计划标记为软删除。 + +### 5.3 配置项规划 + +需要在主配置文件 `config/bot_config.toml` 中添加以下配置项,以控制系统行为。 + +```toml +# ---------------------------------------------------------------- +# 月层计划系统设置 (Monthly Plan System Settings) +# ---------------------------------------------------------------- +[monthly_plan_system] + +# 是否启用本功能 +enable = true + +# 启动时,如果当月计划少于此数量,则触发LLM生成 +generation_threshold = 10 + +# 每次调用LLM期望生成的计划数量 +plans_per_generation = 5 + +# 计划被使用后,被删除的概率 (0.0 到 1.0) +deletion_probability_on_use = 0.5 +``` + +--- +**文档结束。** 本文档纯粹为架构规划,旨在提供清晰的设计思路和开发指引,不包含任何实现代码。 \ No newline at end of file diff --git a/src/common/database/monthly_plan_db.py b/src/common/database/monthly_plan_db.py new file mode 100644 index 000000000..2bff98b22 --- /dev/null +++ b/src/common/database/monthly_plan_db.py @@ -0,0 +1,68 @@ +# mmc/src/common/database/monthly_plan_db.py + +import datetime +from typing import List +from src.common.database.sqlalchemy_models import MonthlyPlan, get_db_session +from src.common.logger import get_logger + +logger = get_logger("monthly_plan_db") + +def add_new_plans(plans: List[str], month: str): + """ + 批量添加新生成的月度计划到数据库。 + + :param plans: 计划内容列表。 + :param month: 目标月份,格式为 "YYYY-MM"。 + """ + with get_db_session() as session: + try: + new_plan_objects = [ + MonthlyPlan(plan_text=plan, target_month=month) + for plan in plans + ] + session.add_all(new_plan_objects) + session.commit() + logger.info(f"成功向数据库添加了 {len(new_plan_objects)} 条 {month} 的月度计划。") + except Exception as e: + logger.error(f"添加月度计划时发生错误: {e}") + session.rollback() + raise + +def get_active_plans_for_month(month: str) -> List[MonthlyPlan]: + """ + 获取指定月份所有未被软删除的计划。 + + :param month: 目标月份,格式为 "YYYY-MM"。 + :return: MonthlyPlan 对象列表。 + """ + with get_db_session() as session: + try: + plans = session.query(MonthlyPlan).filter( + MonthlyPlan.target_month == month, + MonthlyPlan.is_deleted == False + ).all() + return plans + except Exception as e: + logger.error(f"查询 {month} 的有效月度计划时发生错误: {e}") + return [] + +def soft_delete_plans(plan_ids: List[int]): + """ + 将指定ID的计划标记为软删除。 + + :param plan_ids: 需要软删除的计划ID列表。 + """ + if not plan_ids: + return + + with get_db_session() as session: + try: + session.query(MonthlyPlan).filter( + MonthlyPlan.id.in_(plan_ids) + ).update({"is_deleted": True}, synchronize_session=False) + session.commit() + logger.info(f"成功软删除了 {len(plan_ids)} 条月度计划。") + except Exception as e: + logger.error(f"软删除月度计划时发生错误: {e}") + session.rollback() + raise \ No newline at end of file diff --git a/src/common/database/sqlalchemy_models.py b/src/common/database/sqlalchemy_models.py index 611486740..f75135410 100644 --- a/src/common/database/sqlalchemy_models.py +++ b/src/common/database/sqlalchemy_models.py @@ -509,6 +509,19 @@ class CacheEntries(Base): Index('idx_cache_entries_created_at', 'created_at'), ) +class MonthlyPlan(Base): + """月层计划模型""" + __tablename__ = 'monthly_plans' + + id = Column(Integer, primary_key=True, autoincrement=True) + plan_text = Column(Text, nullable=False) + target_month = Column(String(7), nullable=False, index=True) # "YYYY-MM" + is_deleted = Column(Boolean, nullable=False, default=False, index=True) + created_at = Column(DateTime, nullable=False, default=datetime.datetime.now) + + __table_args__ = ( + Index('idx_monthlyplan_target_month_is_deleted', 'target_month', 'is_deleted'), + ) # 数据库引擎和会话管理 _engine = None diff --git a/src/common/logger.py b/src/common/logger.py index e8b2d1236..61f300c22 100644 --- a/src/common/logger.py +++ b/src/common/logger.py @@ -434,6 +434,7 @@ MODULE_COLORS = { "dependency_manager": "\033[38;5;30m", # 深青色 "manifest_utils": "\033[38;5;39m", # 蓝色 "schedule_manager": "\033[38;5;27m", # 深蓝色 + "monthly_plan_manager": "\033[38;5;171m", # 聊天和多媒体扩展 "chat_voice": "\033[38;5;87m", # 浅青色 @@ -536,6 +537,7 @@ MODULE_ALIASES = { "dependency_manager": "依赖管理", "manifest_utils": "清单工具", "schedule_manager": "计划管理", + "monthly_plan_manager": "月度计划", # 聊天和多媒体扩展 "chat_voice": "语音处理", diff --git a/src/config/api_ada_configs.py b/src/config/api_ada_configs.py index c39c0ea13..5598095b0 100644 --- a/src/config/api_ada_configs.py +++ b/src/config/api_ada_configs.py @@ -114,6 +114,7 @@ class ModelTaskConfig(ValidatedConfigBase): lpmm_rdf_build: TaskConfig = Field(..., description="LPMM RDF构建模型配置") lpmm_qa: TaskConfig = Field(..., description="LPMM问答模型配置") schedule_generator: TaskConfig = Field(..., description="日程生成模型配置") + monthly_plan_generator: TaskConfig = Field(..., description="月层计划生成模型配置") emoji_vlm: TaskConfig = Field(..., description="表情包识别模型配置") anti_injection: TaskConfig = Field(..., description="反注入检测专用模型配置") diff --git a/src/config/config.py b/src/config/config.py index f3c5674ec..4dfe58a3e 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -43,7 +43,8 @@ from src.config.official_configs import ( WebSearchConfig, TavilyConfig, AntiPromptInjectionConfig, - PluginsConfig + PluginsConfig, + MonthlyPlanSystemConfig ) from .api_ada_configs import ( @@ -388,6 +389,7 @@ class Config(ValidatedConfigBase): web_search: WebSearchConfig = Field(default_factory=lambda: WebSearchConfig(), description="网络搜索配置") tavily: TavilyConfig = Field(default_factory=lambda: TavilyConfig(), description="Tavily配置") plugins: PluginsConfig = Field(default_factory=lambda: PluginsConfig(), description="插件配置") + monthly_plan_system: MonthlyPlanSystemConfig = Field(default_factory=lambda: MonthlyPlanSystemConfig(), description="月层计划系统配置") class APIAdapterConfig(ValidatedConfigBase): diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 9b31e6a57..e734bb08d 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -652,3 +652,12 @@ class PluginsConfig(ValidatedConfigBase): """插件配置""" centralized_config: bool = Field(default=True, description="是否启用插件配置集中化管理") + + +class MonthlyPlanSystemConfig(ValidatedConfigBase): + """月层计划系统配置类""" + + enable: bool = Field(default=True, description="是否启用本功能") + generation_threshold: int = Field(default=10, ge=0, description="启动时,如果当月计划少于此数量,则触发LLM生成") + plans_per_generation: int = Field(default=5, ge=1, description="每次调用LLM期望生成的计划数量") + deletion_probability_on_use: float = Field(default=0.5, ge=0.0, le=1.0, description="计划被使用后,被删除的概率") diff --git a/src/main.py b/src/main.py index da36c870f..4b242a02b 100644 --- a/src/main.py +++ b/src/main.py @@ -1,5 +1,6 @@ # 有一个人想混点提交() # 什么?混提交不带我一个喵~ +# 我要混提交 import asyncio import time import signal @@ -19,6 +20,7 @@ from src.common.server import get_global_server, Server from src.mood.mood_manager import mood_manager from rich.traceback import install from src.manager.schedule_manager import schedule_manager +from src.schedule.monthly_plan_manager import MonthlyPlanManager # from src.api.main import start_api_server # 导入新的插件管理器和热重载管理器 @@ -177,6 +179,12 @@ MaiMbot-Pro-Max(第三方改版) await self.individuality.initialize() # 初始化日程管理器 if global_config.schedule.enable: + logger.info("正在初始化月度计划...") + try: + await MonthlyPlanManager.initialize_monthly_plans() + logger.info("月度计划初始化完成") + except Exception as e: + logger.error(f"月度计划初始化失败: {e}") logger.info("日程表功能已启用,正在初始化管理器...") await schedule_manager.load_or_generate_today_schedule() await schedule_manager.start_daily_schedule_generation() diff --git a/src/manager/schedule_manager.py b/src/manager/schedule_manager.py index cd2cd9537..b6b6d390b 100644 --- a/src/manager/schedule_manager.py +++ b/src/manager/schedule_manager.py @@ -1,10 +1,12 @@ import json import asyncio +import random from datetime import datetime, time, timedelta from typing import Optional, List, Dict, Any from pydantic import BaseModel, ValidationError, validator from src.common.database.sqlalchemy_models import Schedule, get_db_session +from src.common.database.monthly_plan_db import get_active_plans_for_month, soft_delete_plans from src.config.config import global_config, model_config from src.llm_models.utils_model import LLMRequest from src.common.logger import get_logger @@ -168,9 +170,28 @@ class ScheduleManager: logger.error(f"加载或生成日程时出错: {e}") async def generate_and_save_schedule(self): - today_str = datetime.now().strftime("%Y-%m-%d") - weekday = datetime.now().strftime("%A") - + now = datetime.now() + today_str = now.strftime("%Y-%m-%d") + current_month_str = now.strftime("%Y-%m") + weekday = now.strftime("%A") + + # 获取月度计划作为额外参考 + monthly_plans_block = "" + used_plan_ids = [] + if global_config.monthly_plan_system and global_config.monthly_plan_system.enable: + active_plans = get_active_plans_for_month(current_month_str) + if active_plans: + # 随机抽取最多3个计划 + num_to_sample = min(len(active_plans), 3) + sampled_plans = random.sample(active_plans, num_to_sample) + used_plan_ids = [p.id for p in sampled_plans] # type: ignore + + plan_texts = "\n".join([f"- {p.plan_text}" for p in sampled_plans]) + monthly_plans_block = f""" +**我这个月的一些小目标/计划 (请在今天的日程中适当体现)**: +{plan_texts} +""" + guidelines = global_config.schedule.guidelines or DEFAULT_SCHEDULE_GUIDELINES personality = global_config.personality.personality_core personality_side = global_config.personality.personality_side @@ -180,10 +201,10 @@ class ScheduleManager: **关于我**: - **核心人设**: {personality} -- **具体习惯与兴趣**: +- **具体习惯与兴趣**: {personality_side} - -**我今天的规划原则**: +{monthly_plans_block} +**我今天的规划原则**: {guidelines} **重要要求**: @@ -219,15 +240,18 @@ class ScheduleManager: existing_schedule = session.query(Schedule).filter(Schedule.date == today_str).first() if existing_schedule: # 更新现有日程 - existing_schedule.schedule_data = json.dumps(schedule_data) - existing_schedule.updated_at = datetime.now() + session.query(Schedule).filter(Schedule.date == today_str).update({ + Schedule.schedule_data: json.dumps(schedule_data), + Schedule.updated_at: datetime.now() + }) else: # 创建新日程 - new_schedule = Schedule() - new_schedule.date = today_str - new_schedule.schedule_data = json.dumps(schedule_data) + new_schedule = Schedule( + date=today_str, + schedule_data=json.dumps(schedule_data) + ) session.add(new_schedule) - session.commit() + session.commit() # 美化输出 schedule_str = f"已成功生成并保存今天的日程 ({today_str}):\n" @@ -236,6 +260,13 @@ class ScheduleManager: logger.info(schedule_str) self.today_schedule = schedule_data + + # 成功生成日程后,根据概率软删除使用过的月度计划 + if used_plan_ids and global_config.monthly_plan_system: + if random.random() < global_config.monthly_plan_system.deletion_probability_on_use: + logger.info(f"根据概率,将使用过的月度计划 {used_plan_ids} 标记为已完成。") + soft_delete_plans(used_plan_ids) + return else: logger.warning(f"第 {attempt + 1} 次生成的日程验证失败,正在重试...") diff --git a/src/schedule/monthly_plan_manager.py b/src/schedule/monthly_plan_manager.py new file mode 100644 index 000000000..85ec08019 --- /dev/null +++ b/src/schedule/monthly_plan_manager.py @@ -0,0 +1,106 @@ +# mmc/src/schedule/monthly_plan_manager.py +# 我要混提交 +import datetime +from src.config.config import global_config +from src.common.database.monthly_plan_db import get_active_plans_for_month, add_new_plans +from src.schedule.plan_generator import PlanGenerator +from src.common.logger import get_logger + +logger = get_logger("monthly_plan_manager") + +class MonthlyPlanManager: + """ + 管理月度计划的生成和填充。 + """ + + @staticmethod + async def initialize_monthly_plans(): + """ + 程序启动时调用,检查并按需填充当月的计划池。 + """ + config = global_config.monthly_plan_system + if not config or not config.enable: + logger.info("月层计划系统未启用,跳过初始化。") + return + + now = datetime.datetime.now() + current_month_str = now.strftime("%Y-%m") + + try: + # 1. 检查当月已有计划数量 + existing_plans = get_active_plans_for_month(current_month_str) + plan_count = len(existing_plans) + + header = "📅 月度计划检查" + + # 2. 判断是否需要生成新计划 + if plan_count >= config.generation_threshold: + summary = f"计划数量充足 ({plan_count}/{config.generation_threshold}),无需生成。" + log_message = ( + f"\n┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n" + f"┃ {header}\n" + f"┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n" + f"┃ 月份: {current_month_str}\n" + f"┃ 状态: {summary}\n" + f"┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛" + ) + logger.info(log_message) + return + + # 3. 计算需要生成的计划数量并调用生成器 + needed_plans = config.generation_threshold - plan_count + summary = f"计划不足 ({plan_count}/{config.generation_threshold}),需要生成 {needed_plans} 条。" + generation_info = f"即将生成 {config.plans_per_generation} 条新计划..." + log_message = ( + f"\n┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n" + f"┃ {header}\n" + f"┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n" + f"┃ 月份: {current_month_str}\n" + f"┃ 状态: {summary}\n" + f"┃ 操作: {generation_info}\n" + f"┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛" + ) + logger.info(log_message) + + generator = PlanGenerator() + new_plans = await generator.generate_plans( + year=now.year, + month=now.month, + count=config.plans_per_generation # 每次生成固定数量以保证质量 + ) + + # 4. 将新计划存入数据库 + if new_plans: + add_new_plans(new_plans, current_month_str) + completion_header = "✅ 月度计划生成完毕" + completion_summary = f"成功添加 {len(new_plans)} 条新计划。" + + # 构建计划详情 + plan_details = "\n".join([f"┃ - {plan}" for plan in new_plans]) + + log_message = ( + f"\n┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n" + f"┃ {completion_header}\n" + f"┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n" + f"┃ 月份: {current_month_str}\n" + f"┃ 结果: {completion_summary}\n" + f"┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n" + f"{plan_details}\n" + f"┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛" + ) + logger.info(log_message) + else: + completion_header = "❌ 月度计划生成失败" + completion_summary = "未能生成任何新的月度计划。" + log_message = ( + f"\n┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n" + f"┃ {completion_header}\n" + f"┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫\n" + f"┃ 月份: {current_month_str}\n" + f"┃ 结果: {completion_summary}\n" + f"┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛" + ) + logger.warning(log_message) + + except Exception as e: + logger.error(f"初始化月度计划时发生严重错误: {e}", exc_info=True) \ No newline at end of file diff --git a/src/schedule/plan_generator.py b/src/schedule/plan_generator.py new file mode 100644 index 000000000..a85149a74 --- /dev/null +++ b/src/schedule/plan_generator.py @@ -0,0 +1,118 @@ +# mmc/src/schedule/plan_generator.py + +import json +import random +from typing import List +from src.config.config import global_config, model_config +from src.llm_models.model_client.base_client import client_registry +from src.llm_models.payload_content.message import Message, RoleType +from src.llm_models.payload_content.resp_format import RespFormat, RespFormatType +from src.common.logger import get_logger + +logger = get_logger("plan_generator") + +class PlanGenerator: + """ + 负责生成月度计划。 + """ + + def __init__(self): + self.bot_personality = self._get_bot_personality() + + def _get_bot_personality(self) -> str: + """ + 从全局配置中获取Bot的人设描述。 + """ + core = global_config.personality.personality_core or "" + side = global_config.personality.personality_side or "" + identity = global_config.personality.identity or "" + return f"核心人设: {core}\n侧面人设: {side}\n身份设定: {identity}" + + def _build_prompt(self, year: int, month: int, count: int) -> str: + """ + 构建用于生成月度计划的Prompt。 + """ + prompt_template = f""" + 你是一个富有想象力的助手,你的任务是为一位虚拟角色生成月度计划。 + + **角色设定:** + --- + {self.bot_personality} + --- + + 请为即将到来的 **{year}年{month}月** 设计 **{count}** 个符合该角色身份的、独立的、积极向上的月度计划或小目标。 + + **要求:** + 1. 每个计划都应简短、清晰,用一两句话描述。 + 2. 语言风格必须自然、口语化,严格符合角色的性格设定。 + 3. 计划内容要具有创造性,避免陈词滥调。 + 4. 请以严格的JSON格式返回,格式为:{{"plans": ["计划一", "计划二", ...]}} + 5. 除了JSON对象,不要包含任何额外的解释、注释或前后导语。 + """ + return prompt_template.strip() + + async def generate_plans(self, year: int, month: int, count: int) -> List[str]: + """ + 调用LLM生成指定月份的计划。 + + :param year: 年份 + :param month: 月份 + :param count: 需要生成的计划数量 + :return: 生成的计划文本列表 + """ + try: + # 1. 获取模型任务配置 + task_config = model_config.model_task_config.get_task("monthly_plan_generator") + + # 2. 随机选择一个模型 + model_name = random.choice(task_config.model_list) + model_info = model_config.get_model_info(model_name) + api_provider = model_config.get_provider(model_info.api_provider) + + # 3. 获取客户端实例 + llm_client = client_registry.get_client_class_instance(api_provider) + + # 4. 构建Prompt和消息体 + prompt = self._build_prompt(year, month, count) + message_list = [Message(role=RoleType.User, content=prompt)] + + logger.info(f"正在使用模型 '{model_name}' 为 {year}-{month} 生成 {count} 个月度计划...") + + # 5. 调用LLM + response = await llm_client.get_response( + model_info=model_info, + message_list=message_list, + temperature=task_config.temperature, + max_tokens=task_config.max_tokens, + response_format=RespFormat(format_type=RespFormatType.JSON_OBJ) # 请求JSON输出 + ) + + if not response or not response.content: + logger.error("LLM未能返回有效的计划内容。") + return [] + + # 6. 解析LLM返回的JSON + try: + # 移除可能的Markdown代码块标记 + clean_content = response.content.strip() + if clean_content.startswith("```json"): + clean_content = clean_content[7:] + if clean_content.endswith("```"): + clean_content = clean_content[:-3] + + data = json.loads(clean_content.strip()) + plans = data.get("plans", []) + + if isinstance(plans, list) and all(isinstance(p, str) for p in plans): + logger.info(f"成功生成并解析了 {len(plans)} 个月度计划。") + return plans + else: + logger.error(f"LLM返回的JSON格式不正确或'plans'键不是字符串列表: {response.content}") + return [] + except json.JSONDecodeError: + logger.error(f"无法解析LLM返回的JSON: {response.content}") + return [] + + except Exception as e: + logger.error(f"调用LLM生成月度计划时发生未知错误: {e}", exc_info=True) + return [] \ No newline at end of file diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index ae54897e1..8251761f9 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "6.3.10" +version = "6.3.11" #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- #如果你想要修改配置文件,请递增version的值 @@ -381,3 +381,16 @@ search_strategy = "single" # 搜索策略: "single"(使用第一个可用引擎) [plugins] # 插件配置 centralized_config = true # 是否启用插件配置集中化管理 + +# ---------------------------------------------------------------- +# 月层计划系统设置 (Monthly Plan System Settings) +# ---------------------------------------------------------------- +[monthly_plan_system] +# 是否启用本功能 +enable = true +# 启动时,如果当月计划少于此数量,则触发LLM生成 +generation_threshold = 30 +# 每次调用LLM期望生成的计划数量 +plans_per_generation = 5 +# 计划被使用后,被删除的概率 (0.0 到 1.0) +deletion_probability_on_use = 0.5 \ No newline at end of file diff --git a/template/model_config_template.toml b/template/model_config_template.toml index dcbefb2fb..4a47f41b9 100644 --- a/template/model_config_template.toml +++ b/template/model_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "1.2.6" +version = "1.2.7" # 配置文件版本号迭代规则同bot_config.toml @@ -193,6 +193,11 @@ model_list = ["moonshotai-Kimi-K2-Instruct"] # 使用快速的小模 temperature = 0.1 # 低温度确保检测结果稳定 max_tokens = 200 # 检测结果不需要太长的输出 +[model_task_config.monthly_plan_generator] # 月层计划生成模型 +model_list = ["deepseek-v3"] +temperature = 0.7 +max_tokens = 1000 + #嵌入模型 [model_task_config.embedding] model_list = ["bge-m3"]