Files
mai-bot/src/config/official_configs.py

2755 lines
74 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from typing import Literal, Optional
import re
from .config_base import ConfigBase, Field
RULE_TYPE_OPTION_DESCRIPTIONS = {
"group": "群聊聊天流item_id 填群号或群聊 ID",
"private": "私聊聊天流item_id 填用户 ID",
}
VISUAL_MODE_OPTION_DESCRIPTIONS = {
"auto": "根据模型信息自动选择文本或多模态模式",
"text": "纯文本模式,不向模型发送视觉输入",
"multimodal": "多模态模式,会向模型发送视觉输入",
}
"""
须知:
1. 本文件中记录了所有的配置项
2. 所有新增的class都需要继承自ConfigBase
3. 所有新增的class都应在official_configs.py中的Config类中添加字段
4. 对于新增的字段若为可选项则应在其后添加Field()并设置default_factory或default
5. 所有的配置项都应该按照如下方法添加字段说明:
class ExampleConfig(ConfigBase):
example_field: str
\"""This is an example field\"""
- 注释前面增加_warp_标记可以实现配置文件中注释在配置项前面单独一行显示
"""
class BotConfig(ConfigBase):
"""机器人配置类"""
__ui_label__ = "基础"
__ui_icon__ = "bot"
platform: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "wifi",
"x-layout": "inline-right",
"x-input-width": "12rem",
},
)
"""平台"""
qq_account: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "user",
"x-layout": "inline-right",
"x-input-width": "12rem",
},
)
"""QQ账号"""
platforms: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "layers",
},
)
"""其他平台"""
nickname: str = Field(
default="麦麦",
json_schema_extra={
"x-widget": "input",
"x-icon": "user-circle",
},
)
"""机器人昵称"""
alias_names: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "tags",
"advanced": True,
},
)
"""别名列表"""
class PersonalityConfig(ConfigBase):
"""人格配置类"""
__ui_parent__ = "bot"
__ui_label__ = "人格"
__ui_icon__ = "user-circle"
personality: str = Field(
default="你是一个大二女大学生,现在正在上网和群友聊天。",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "user-circle",
"x-textarea-min-height": 40,
"x-textarea-rows": 1,
},
)
"""人格建议200字以内描述人格特质和身份特征可以写完整设定。要求第二人称"""
reply_style: str = Field(
default="你的风格平淡简短。可以参考贴吧,知乎和微博的回复风格。不浮夸不长篇大论,不要过分修辞和复杂句。尽量回复的简短一些,平淡一些",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "message-square",
"x-textarea-min-height": 40,
"x-textarea-rows": 1,
},
)
"""默认表达风格描述麦麦说话的表达风格表达习惯如要修改可以酌情新增内容建议1-2行"""
multiple_reply_style: list[str] = Field(
default_factory=lambda: [
"你的风格平淡但不失讽刺,很简短,很白话。可以参考贴吧,微博的回复风格。",
"用1-2个字进行回复",
"用1-2个符号进行回复",
"言辭凝練古雅,穿插《論語》經句卻不晦澀,以文言短句為基,輔以淺白語意,持長者溫和風範,全用繁體字表達,具先秦儒者談吐韻致。",
"带点翻译腔,但不要太长",
],
json_schema_extra={
"advanced": True,
"x-widget": "custom",
"x-icon": "list",
},
)
"""可选的多种表达风格列表,当配置不为空时可按概率随机替换 reply_style"""
multiple_probability: float = Field(
default=0,
ge=0,
le=1,
json_schema_extra={
"advanced": True,
"x-widget": "slider",
"x-icon": "percent",
"step": 0.1,
},
)
"""每次构建回复时,从 multiple_reply_style 中随机替换 reply_style 的概率0.0-1.0"""
class VisualConfig(ConfigBase):
"""视觉配置类"""
__ui_label__ = "视觉"
__ui_icon__ = "image"
planner_mode: Literal["text", "multimodal", "auto"] = Field(
default="auto",
json_schema_extra={
"x-widget": "select",
"x-icon": "git-branch",
"x-option-descriptions": VISUAL_MODE_OPTION_DESCRIPTIONS,
"x-row": "visual-modes",
},
)
"""规划器模式auto根据模型信息自动选择text为纯文本模式multimodal为多模态模式"""
replyer_mode: Literal["text", "multimodal", "auto"] = Field(
default="auto",
json_schema_extra={
"x-widget": "select",
"x-icon": "git-branch",
"x-option-descriptions": VISUAL_MODE_OPTION_DESCRIPTIONS,
"x-row": "visual-modes",
},
)
"""回复器模式auto根据模型信息自动选择text为纯文本模式multimodal为多模态模式"""
class TalkRulesItem(ConfigBase):
platform: str = ""
"""平台与ID一起留空表示全局"""
item_id: str = ""
"""用户ID与平台一起留空表示全局"""
rule_type: Literal["group", "private"] = Field(
default="group",
json_schema_extra={
"x-widget": "select",
"x-option-descriptions": RULE_TYPE_OPTION_DESCRIPTIONS,
},
)
"""聊天流类型group群聊或private私聊"""
time: str = ""
"""时间段,格式为 "HH:MM-HH:MM",支持跨夜区间"""
value: float = 0.5
"""聊天频率值范围0-1"""
class ChatConfig(ConfigBase):
"""聊天配置类"""
__ui_label__ = "聊天"
__ui_icon__ = "message-square"
talk_value: float = Field(
default=1,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "message-circle",
"x-row": "talk-values",
"step": 0.1,
},
)
"""聊天频率越小越沉默范围0-1"""
private_talk_value: float = Field(
default=1,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "message-circle",
"x-row": "talk-values",
"step": 0.1,
},
)
"""私聊聊天频率越小越沉默范围0-1"""
mentioned_bot_reply: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "at-sign",
"x-row": "reply-switches",
},
)
"""是否启用提及必回复"""
inevitable_at_reply: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "at-sign",
"x-row": "reply-switches",
},
)
"""是否启用at必回复"""
enable_at: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "at-sign",
"advanced": True,
},
)
"""是否允许 replyer 使用 at[msg_id] 标记来发送真正的 at 消息"""
enable_reply_quote: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "quote",
"advanced": True,
},
)
"""是否启用回复时附带引用回复"""
max_context_size: int = Field(
default=40,
json_schema_extra={
"x-widget": "input",
"x-icon": "layers",
"x-layout": "inline-right",
"x-input-width": "12rem",
"x-row": "context-sizes",
},
)
"""上下文长度"""
max_private_context_size: int = Field(
default=40,
json_schema_extra={
"x-widget": "input",
"x-icon": "layers",
"x-layout": "inline-right",
"x-input-width": "12rem",
"x-row": "context-sizes",
},
)
"""私聊上下文长度"""
planner_interrupt_max_consecutive_count: int = Field(
default=0,
ge=0,
json_schema_extra={
"x-widget": "input",
"x-icon": "pause-circle",
"advanced": True,
},
)
"""Planner 连续被新消息打断的最大次数0 表示不启用打断"""
group_chat_prompt: str = Field(
default=(
"你正在qq群里聊天下面是群里正在聊的内容其中包含聊天记录和聊天中的图片和表情包。\n"
"回复尽量简短一些。最好一次对一个话题进行回复,但必须考虑不同群友发言之间的交互,免得啰嗦或者回复内容太乱。请注意把握聊天内容。\n"
"不要总是提及自己的身份背景,根据聊天内容自由发挥,但是要日常不浮夸,不要太关注具体的聊天内容,不要刻意找话题,。\n"
"不要回复的太频繁!不用刻意回复表情包,只要关注表情包表达的含义。控制回复的频率,不要每个人的消息都回复,只回复你感兴趣的或者主动提及你的。\n"
),
json_schema_extra={
"x-widget": "textarea",
"x-icon": "users",
},
)
"""_wrap_群聊通用注意事项"""
private_chat_prompts: str = Field(
default=(
"你正在聊天,下面是正在聊的内容,其中包含聊天记录和聊天中的图片。\n"
"回复尽量简短一些。请注意把握聊天内容。\n"
"请考虑对方的发言频率,想法,思考自己何时回复以及回复内容。\n"
),
json_schema_extra={
"x-widget": "textarea",
"x-icon": "user",
},
)
"""_wrap_私聊通用注意事项"""
chat_prompts: list["ExtraPromptItem"] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
enable_talk_value_rules: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "settings",
},
)
"""是否启用动态发言频率规则"""
talk_value_rules: list[TalkRulesItem] = Field(
default_factory=lambda: [
TalkRulesItem(platform="", item_id="", rule_type="group", time="00:00-08:59", value=0.8),
TalkRulesItem(platform="", item_id="", rule_type="group", time="09:00-18:59", value=1.0),
],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""
_wrap_思考频率规则列表支持按聊天流/按日内时段配置。
"""
class MessageReceiveConfig(ConfigBase):
"""消息接收配置类"""
__ui_label__ = "消息接收"
__ui_icon__ = "message-square-text"
image_parse_threshold: int = Field(
default=5,
json_schema_extra={
"x-widget": "input",
"x-icon": "image",
},
)
"""
当消息中图片数量不超过此阈值时,启用图片解析功能,将图片内容解析为文本后再进行处理。
当消息中图片数量超过此阈值时,为了避免过度解析导致的性能问题,将跳过图片解析,直接进行处理。
"""
ban_words: set[str] = Field(
default_factory=lambda: set(),
json_schema_extra={
"x-widget": "custom",
"x-icon": "ban",
},
)
"""过滤词列表"""
ban_msgs_regex: set[str] = Field(
default_factory=lambda: set(),
json_schema_extra={
"x-widget": "custom",
"x-icon": "regex",
},
)
"""过滤正则表达式列表"""
def model_post_init(self, context: Optional[dict] = None) -> None:
for pattern in self.ban_msgs_regex:
try:
re.compile(pattern)
except re.error as e:
raise ValueError(f"Invalid regex pattern in ban_msgs_regex: '{pattern}'") from e
return super().model_post_init(context)
class TargetItem(ConfigBase):
platform: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "wifi",
},
)
"""平台与ID一起留空表示全局"""
item_id: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""用户/群ID与平台一起留空表示全局"""
rule_type: Literal["group", "private"] = Field(
default="group",
json_schema_extra={
"x-widget": "select",
"x-icon": "users",
"x-option-descriptions": RULE_TYPE_OPTION_DESCRIPTIONS,
},
)
"""聊天流类型group群聊或private私聊"""
class MemoryConfig(ConfigBase):
"""记忆配置类"""
__ui_parent__ = "a_memorix"
global_memory: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "globe",
},
)
"""是否允许记忆检索在聊天记录中进行全局查询忽略当前chat_id仅对 search_chat_history 等工具生效)"""
global_memory_blacklist: list[TargetItem] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "shield-off",
},
)
"""_wrap_全局记忆黑名单当启用全局记忆时不将特定聊天流纳入检索"""
enable_memory_query_tool: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "database",
},
)
"""是否启用 Maisaka 内置长期记忆检索工具 query_memory"""
memory_query_default_limit: int = Field(
default=5,
ge=1,
le=20,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""Maisaka 内置长期记忆检索工具 query_memory 的默认返回条数"""
person_fact_writeback_enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "user-round-pen",
},
)
"""是否在发送回复后自动提取并写回人物事实到长期记忆"""
chat_summary_writeback_enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "scroll-text",
},
)
"""是否在 Maisaka 聊天过程中按消息窗口自动写回聊天摘要到长期记忆"""
chat_summary_writeback_message_threshold: int = Field(
default=12,
ge=1,
json_schema_extra={
"x-widget": "input",
"x-icon": "messages-square",
"advanced": True,
},
)
"""自动写回聊天摘要的消息窗口阈值"""
chat_summary_writeback_context_length: int = Field(
default=50,
ge=1,
le=500,
json_schema_extra={
"x-widget": "input",
"x-icon": "rows-3",
"advanced": True,
},
)
"""自动写回聊天摘要时,从聊天流中回看的消息条数"""
feedback_correction_enabled: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "message-circle-warning",
"advanced": True,
},
)
"""是否启用反馈驱动的延迟记忆纠错任务"""
feedback_correction_window_hours: float = Field(
default=12.0,
ge=0.1,
json_schema_extra={
"x-widget": "input",
"x-icon": "clock-4",
"advanced": True,
},
)
"""反馈窗口时长(小时),以 query_memory 执行时间为起点"""
feedback_correction_check_interval_minutes: int = Field(
default=30,
ge=1,
json_schema_extra={
"x-widget": "input",
"x-icon": "timer",
"advanced": True,
},
)
"""反馈纠错定时任务轮询间隔(分钟)"""
feedback_correction_batch_size: int = Field(
default=20,
ge=1,
le=200,
json_schema_extra={
"x-widget": "input",
"x-icon": "list-ordered",
"advanced": True,
},
)
"""反馈纠错每轮最大处理任务数"""
feedback_correction_auto_apply_threshold: float = Field(
default=0.85,
ge=0.0,
le=1.0,
json_schema_extra={
"x-widget": "slider",
"x-icon": "gauge",
"step": 0.01,
"advanced": True,
},
)
"""自动应用纠错动作的最低置信度阈值"""
feedback_correction_max_feedback_messages: int = Field(
default=30,
ge=1,
le=200,
json_schema_extra={
"x-widget": "input",
"x-icon": "messages-square",
"advanced": True,
},
)
"""每个纠错任务最多使用的窗口内用户反馈消息数"""
feedback_correction_prefilter_enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "filter",
"advanced": True,
},
)
"""是否启用纠错前置预筛(用于减少不必要的模型调用)"""
feedback_correction_paragraph_mark_enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "sticky-note",
"advanced": True,
},
)
"""是否为受影响 paragraph 写入已纠正旧事实标记"""
feedback_correction_paragraph_hard_filter_enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "eye-off",
"advanced": True,
},
)
"""是否在用户侧查询中硬过滤带有 stale 标记的 paragraph"""
feedback_correction_profile_refresh_enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "user-round-search",
"advanced": True,
},
)
"""是否在反馈纠错后将受影响人物画像加入刷新队列"""
feedback_correction_profile_force_refresh_on_read: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "refresh-ccw",
"advanced": True,
},
)
"""人物画像处于脏队列时,读取是否强制刷新而不直接复用旧快照"""
feedback_correction_episode_rebuild_enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "clapperboard",
"advanced": True,
},
)
"""是否在反馈纠错后将受影响 source 加入 episode 重建队列"""
feedback_correction_episode_query_block_enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "ban",
"advanced": True,
},
)
"""episode source 处于重建队列时,是否对用户侧查询做屏蔽"""
feedback_correction_reconcile_interval_minutes: int = Field(
default=5,
ge=1,
json_schema_extra={
"x-widget": "input",
"x-icon": "repeat",
"advanced": True,
},
)
"""反馈纠错二阶段一致性后台协调任务轮询间隔(分钟)"""
feedback_correction_reconcile_batch_size: int = Field(
default=20,
ge=1,
le=200,
json_schema_extra={
"x-widget": "input",
"x-icon": "list-restart",
"advanced": True,
},
)
"""反馈纠错二阶段一致性每轮处理 profile/episode 队列的批大小"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证配置值"""
if self.feedback_correction_window_hours <= 0:
raise ValueError(
f"feedback_correction_window_hours 必须大于0当前值: {self.feedback_correction_window_hours}"
)
if self.feedback_correction_check_interval_minutes < 1:
raise ValueError(
"feedback_correction_check_interval_minutes 必须至少为1"
f"当前值: {self.feedback_correction_check_interval_minutes}"
)
if self.feedback_correction_batch_size < 1:
raise ValueError(
f"feedback_correction_batch_size 必须至少为1当前值: {self.feedback_correction_batch_size}"
)
if not 0 <= self.feedback_correction_auto_apply_threshold <= 1:
raise ValueError(
"feedback_correction_auto_apply_threshold 必须在 [0, 1] 之间,"
f"当前值: {self.feedback_correction_auto_apply_threshold}"
)
if self.feedback_correction_max_feedback_messages < 1:
raise ValueError(
"feedback_correction_max_feedback_messages 必须至少为1"
f"当前值: {self.feedback_correction_max_feedback_messages}"
)
if self.feedback_correction_reconcile_interval_minutes < 1:
raise ValueError(
"feedback_correction_reconcile_interval_minutes 必须至少为1"
f"当前值: {self.feedback_correction_reconcile_interval_minutes}"
)
if self.feedback_correction_reconcile_batch_size < 1:
raise ValueError(
"feedback_correction_reconcile_batch_size 必须至少为1"
f"当前值: {self.feedback_correction_reconcile_batch_size}"
)
return super().model_post_init(context)
class AMemorixPluginConfig(ConfigBase):
"""A_Memorix 子系统状态"""
enabled: bool = Field(default=False)
"""是否启用 A_Memorix"""
class AMemorixStorageConfig(ConfigBase):
"""A_Memorix 存储位置"""
data_dir: str = Field(default="data/a-memorix")
"""数据目录"""
class AMemorixEmbeddingFallbackConfig(ConfigBase):
"""A_Memorix Embedding 回退"""
enabled: bool = Field(default=True)
"""是否启用回退机制"""
probe_interval_seconds: int = Field(default=180, ge=10)
"""探测间隔秒数"""
allow_metadata_only_write: bool = Field(default=True)
"""是否允许仅写入元数据"""
class AMemorixParagraphVectorBackfillConfig(ConfigBase):
"""A_Memorix 段落向量回填"""
enabled: bool = Field(default=True)
"""是否启用回填任务"""
interval_seconds: int = Field(default=60, ge=5)
"""回填轮询间隔"""
batch_size: int = Field(default=64, ge=1)
"""单批回填数量"""
max_retry: int = Field(default=5, ge=0)
"""最大重试次数"""
class AMemorixEmbeddingConfig(ConfigBase):
"""A_Memorix Embedding 配置"""
model_name: str = Field(default="auto")
"""Embedding 模型选择"""
dimension: int = Field(default=1024, ge=1)
"""向量维度"""
batch_size: int = Field(default=32, ge=1)
"""单批请求大小"""
max_concurrent: int = Field(default=5, ge=1)
"""最大并发数"""
enable_cache: bool = Field(default=False)
"""是否启用缓存"""
quantization_type: Literal["int8"] = Field(default="int8")
"""量化方式,当前 vNext 仅支持 int8(SQ8)"""
fallback: AMemorixEmbeddingFallbackConfig = Field(default_factory=AMemorixEmbeddingFallbackConfig)
"""Embedding 回退配置"""
paragraph_vector_backfill: AMemorixParagraphVectorBackfillConfig = Field(
default_factory=AMemorixParagraphVectorBackfillConfig
)
"""段落向量回填配置"""
class AMemorixSparseRetrievalConfig(ConfigBase):
"""A_Memorix 稀疏检索配置"""
enabled: bool = Field(default=True)
"""是否启用稀疏检索"""
backend: Literal["fts5"] = Field(default="fts5")
"""稀疏检索后端"""
mode: Literal["auto", "fallback_only", "hybrid"] = Field(default="auto")
"""稀疏检索模式"""
tokenizer_mode: Literal["jieba", "mixed", "char_2gram"] = Field(default="jieba")
"""分词模式"""
candidate_k: int = Field(default=80, ge=1)
"""段落候选数"""
relation_candidate_k: int = Field(default=60, ge=1)
"""关系候选数"""
class AMemorixRetrievalConfig(ConfigBase):
"""A_Memorix 检索配置"""
top_k_paragraphs: int = Field(default=20, ge=1)
"""段落候选数"""
top_k_relations: int = Field(default=10, ge=1)
"""关系候选数"""
top_k_final: int = Field(default=10, ge=1)
"""最终返回条数"""
alpha: float = Field(default=0.5, ge=0.0, le=1.0)
"""关系融合权重"""
enable_ppr: bool = Field(default=True)
"""是否启用 PPR"""
ppr_alpha: float = Field(default=0.85, ge=0.0, le=1.0)
"""PPR alpha"""
ppr_timeout_seconds: float = Field(default=1.5, ge=0.1)
"""PPR 超时秒数"""
ppr_concurrency_limit: int = Field(default=4, ge=1)
"""PPR 并发限制"""
enable_parallel: bool = Field(default=True)
"""是否启用并行检索"""
sparse: AMemorixSparseRetrievalConfig = Field(default_factory=AMemorixSparseRetrievalConfig)
"""稀疏检索配置"""
class AMemorixThresholdConfig(ConfigBase):
"""A_Memorix 阈值过滤配置"""
min_threshold: float = Field(default=0.3, ge=0.0, le=1.0)
"""最小阈值"""
max_threshold: float = Field(default=0.95, ge=0.0, le=1.0)
"""最大阈值"""
percentile: int = Field(default=75, ge=0, le=100)
"""动态阈值百分位"""
min_results: int = Field(default=3, ge=1)
"""最小保留条数"""
enable_auto_adjust: bool = Field(default=True)
"""是否启用自动阈值调整"""
class AMemorixFilterConfig(ConfigBase):
"""A_Memorix 聊天过滤配置"""
enabled: bool = Field(default=True)
"""是否启用聊天过滤"""
mode: Literal["blacklist", "whitelist"] = Field(default="blacklist")
"""过滤模式"""
chats: list[str] = Field(default_factory=lambda: [])
"""聊天流列表"""
class AMemorixEpisodeConfig(ConfigBase):
"""A_Memorix Episode 配置"""
enabled: bool = Field(default=True)
"""是否启用 Episode"""
generation_enabled: bool = Field(default=True)
"""是否启用自动生成"""
pending_batch_size: int = Field(default=20, ge=1)
"""待处理批大小"""
pending_max_retry: int = Field(default=3, ge=0)
"""待处理最大重试次数"""
max_paragraphs_per_call: int = Field(default=20, ge=1)
"""单次最大段落数"""
max_chars_per_call: int = Field(default=6000, ge=100)
"""单次最大字符数"""
source_time_window_hours: float = Field(default=24.0, ge=0.0)
"""时间窗口小时数"""
segmentation_model: str = Field(default="auto")
"""分段模型选择"""
class AMemorixPersonProfileConfig(ConfigBase):
"""A_Memorix 人物画像配置"""
enabled: bool = Field(default=True)
"""是否启用画像"""
refresh_interval_minutes: int = Field(default=30, ge=1)
"""刷新间隔分钟数"""
active_window_hours: float = Field(default=72.0, ge=1.0)
"""活跃窗口小时数"""
max_refresh_per_cycle: int = Field(default=50, ge=1)
"""单轮最大刷新数"""
top_k_evidence: int = Field(default=12, ge=1)
"""证据条数"""
class AMemorixMemoryEvolutionConfig(ConfigBase):
"""A_Memorix 记忆演化配置"""
enabled: bool = Field(default=True)
"""是否启用记忆演化"""
half_life_hours: float = Field(default=24.0, ge=0.1)
"""半衰期小时数"""
prune_threshold: float = Field(default=0.1, ge=0.0, le=1.0)
"""裁剪阈值"""
freeze_duration_hours: float = Field(default=24.0, ge=0.0)
"""冻结时长小时数"""
class AMemorixAdvancedConfig(ConfigBase):
"""A_Memorix 高级运行时配置"""
enable_auto_save: bool = Field(default=True)
"""是否启用自动保存"""
auto_save_interval_minutes: int = Field(default=5, ge=1)
"""自动保存间隔"""
debug: bool = Field(default=False)
"""是否启用调试"""
class AMemorixWebImportConfig(ConfigBase):
"""A_Memorix 导入中心配置"""
enabled: bool = Field(default=True)
"""是否启用导入中心"""
max_queue_size: int = Field(default=20, ge=1)
"""最大队列长度"""
max_files_per_task: int = Field(default=200, ge=1)
"""单任务最大文件数"""
max_file_size_mb: int = Field(default=20, ge=1)
"""单文件大小上限 MB"""
max_paste_chars: int = Field(default=200000, ge=100)
"""粘贴字符数上限"""
default_file_concurrency: int = Field(default=2, ge=1)
"""默认文件并发"""
default_chunk_concurrency: int = Field(default=4, ge=1)
"""默认分块并发"""
class AMemorixWebTuningConfig(ConfigBase):
"""A_Memorix 调优中心配置"""
enabled: bool = Field(default=True)
"""是否启用调优中心"""
max_queue_size: int = Field(default=8, ge=1)
"""最大队列长度"""
poll_interval_ms: int = Field(default=1200, ge=200)
"""轮询间隔毫秒数"""
default_intensity: Literal["quick", "standard", "deep"] = Field(default="standard")
"""默认调优强度"""
default_objective: Literal["precision_priority", "balanced", "recall_priority"] = Field(
default="precision_priority"
)
"""默认调优目标"""
default_top_k_eval: int = Field(default=20, ge=1)
"""默认评估 Top-K"""
default_sample_size: int = Field(default=24, ge=1)
"""默认样本数"""
class AMemorixWebConfig(ConfigBase):
"""A_Memorix Web 运维配置"""
import_config: AMemorixWebImportConfig = Field(default_factory=AMemorixWebImportConfig)
"""导入中心配置"""
tuning: AMemorixWebTuningConfig = Field(default_factory=AMemorixWebTuningConfig)
"""调优中心配置"""
class AMemorixConfig(ConfigBase):
"""A_Memorix 长期记忆子系统配置"""
__ui_label__ = "长期记忆"
__ui_icon__ = "brain"
plugin: AMemorixPluginConfig = Field(default_factory=AMemorixPluginConfig)
"""子系统状态"""
storage: AMemorixStorageConfig = Field(default_factory=AMemorixStorageConfig)
"""存储位置"""
embedding: AMemorixEmbeddingConfig = Field(default_factory=AMemorixEmbeddingConfig)
"""Embedding 配置"""
retrieval: AMemorixRetrievalConfig = Field(default_factory=AMemorixRetrievalConfig)
"""检索配置"""
threshold: AMemorixThresholdConfig = Field(default_factory=AMemorixThresholdConfig)
"""阈值过滤配置"""
filter: AMemorixFilterConfig = Field(default_factory=AMemorixFilterConfig)
"""聊天过滤配置"""
episode: AMemorixEpisodeConfig = Field(default_factory=AMemorixEpisodeConfig)
"""Episode 配置"""
person_profile: AMemorixPersonProfileConfig = Field(default_factory=AMemorixPersonProfileConfig)
"""人物画像配置"""
memory: AMemorixMemoryEvolutionConfig = Field(default_factory=AMemorixMemoryEvolutionConfig)
"""记忆演化配置"""
advanced: AMemorixAdvancedConfig = Field(default_factory=AMemorixAdvancedConfig)
"""高级运行时配置"""
web: AMemorixWebConfig = Field(default_factory=AMemorixWebConfig)
"""Web 运维配置"""
class LearningItem(ConfigBase):
platform: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "wifi",
},
)
"""平台与ID一起留空表示全局"""
item_id: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""用户ID与平台一起留空表示全局"""
rule_type: Literal["group", "private"] = Field(
default="group",
json_schema_extra={
"x-widget": "select",
"x-icon": "users",
"x-option-descriptions": RULE_TYPE_OPTION_DESCRIPTIONS,
},
)
"""聊天流类型group群聊或private私聊"""
use_expression: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "message-square",
},
)
"""是否使用表达"""
enable_learning: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "graduation-cap",
},
)
"""是否学习表达"""
enable_jargon_learning: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "book",
},
)
"""是否学习黑话"""
class ExpressionGroup(ConfigBase):
"""表达互通组配置类,若列表为空代表全局共享"""
expression_groups: list[TargetItem] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "users",
},
)
"""_wrap_表达学习互通组"""
class ExpressionConfig(ConfigBase):
"""表达配置类"""
__ui_label__ = "表达"
__ui_icon__ = "pen-tool"
learning_list: list[LearningItem] = Field(
default_factory=lambda: [
LearningItem(
platform="",
item_id="",
rule_type="group",
use_expression=True,
enable_learning=True,
enable_jargon_learning=True,
)
],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""_wrap_表达学习配置列表支持按聊天流配置"""
expression_groups: list[ExpressionGroup] = Field(
default_factory=list,
json_schema_extra={
"x-widget": "custom",
"x-icon": "users",
},
)
"""_wrap_表达学习互通组"""
expression_checked_only: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "check",
},
)
"""是否仅选择已检查且未拒绝的表达方式"""
expression_self_reflect: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "refresh-cw",
},
)
"""是否启用自动表达优化"""
expression_auto_check_interval: int = Field(
default=900,
json_schema_extra={
"x-widget": "input",
"x-icon": "clock",
"advanced": True,
},
)
"""表达方式自动检查的间隔时间(秒)"""
expression_auto_check_count: int = Field(
default=5,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
"advanced": True,
},
)
"""每次自动检查时随机选取的表达方式数量"""
expression_auto_check_custom_criteria: list[str] = Field(
default_factory=list,
json_schema_extra={
"x-widget": "custom",
"x-icon": "file-text",
"advanced": True,
},
)
"""表达方式自动检查的额外自定义评估标准"""
all_global_jargon: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "globe",
},
)
"""是否开启全局黑话模式,注意,此功能关闭后,已经记录的全局黑话不会改变,需要手动删除"""
class VoiceConfig(ConfigBase):
"""语音识别配置类"""
__ui_label__ = "语音"
__ui_icon__ = "mic"
enable_asr: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "mic",
},
)
"""是否启用语音识别,启用后麦麦可以识别语音消息"""
class EmojiConfig(ConfigBase):
"""表情包配置类"""
__ui_label__ = "表情包"
__ui_icon__ = "smile"
emoji_send_num: int = Field(
default=25,
ge=1,
le=64,
json_schema_extra={
"x-widget": "input",
"x-icon": "grid",
"advanced": True,
},
)
"""一次从多少个表情包中选择发送,最大为 64"""
max_reg_num: int = Field(
default=64,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""表情包最大注册数量"""
do_replace: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "refresh-cw",
"advanced": True,
},
)
"""达到最大注册数量时替换旧表情包,关闭则达到最大数量时不会继续收集表情包"""
check_interval: int = Field(
default=10,
json_schema_extra={
"x-widget": "input",
"x-icon": "clock",
},
)
"""表情包检查间隔(分钟)"""
steal_emoji: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "copy",
},
)
"""是否偷取表情包,让麦麦可以将一些表情包据为己有"""
content_filtration: bool = Field(
default=False,
json_schema_extra={
"advanced": True,
"x-widget": "switch",
"x-icon": "filter",
},
)
"""是否启用表情包过滤,只有符合该要求的表情包才会被保存"""
class KeywordRuleConfig(ConfigBase):
"""关键词规则配置类"""
keywords: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "tag",
},
)
"""关键词列表"""
regex: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "regex",
},
)
"""正则表达式列表"""
reaction: str = Field(
default="",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "message-circle",
},
)
"""关键词触发的反应"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证配置"""
if not self.keywords and not self.regex:
raise ValueError("关键词规则必须至少包含keywords或regex中的一个")
if not self.reaction:
raise ValueError("关键词规则必须包含reaction")
for pattern in self.regex:
try:
re.compile(pattern)
except re.error as e:
raise ValueError(f"无效的正则表达式 '{pattern}': {str(e)}") from e
return super().model_post_init(context)
class KeywordReactionConfig(ConfigBase):
"""关键词配置类"""
__ui_parent__ = "message_receive"
keyword_rules: list[KeywordRuleConfig] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""关键词规则列表"""
regex_rules: list[KeywordRuleConfig] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""正则表达式规则列表"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证配置"""
for rule in self.keyword_rules + self.regex_rules:
if not isinstance(rule, KeywordRuleConfig):
raise ValueError(f"规则必须是KeywordRuleConfig类型而不是{type(rule).__name__}")
return super().model_post_init(context)
class ResponsePostProcessConfig(ConfigBase):
"""回复后处理配置类"""
__ui_label__ = "后处理"
__ui_icon__ = "settings"
enable_response_post_process: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "settings",
},
)
"""是否启用回复后处理,包括错别字生成器,回复分割器"""
class ChineseTypoConfig(ConfigBase):
"""中文错别字配置类"""
__ui_parent__ = "response_post_process"
enable: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "type",
},
)
"""是否启用中文错别字生成器"""
error_rate: float = Field(
default=0.01,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.01,
"advanced": True,
},
)
"""单字替换概率"""
min_freq: int = Field(
default=9,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
"advanced": True,
},
)
"""最小字频阈值"""
tone_error_rate: float = Field(
default=0.1,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.1,
"advanced": True,
},
)
"""声调错误概率"""
word_replace_rate: float = Field(
default=0.006,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.001,
"advanced": True,
},
)
"""整词替换概率"""
class ResponseSplitterConfig(ConfigBase):
"""回复分割器配置类"""
__ui_parent__ = "response_post_process"
enable: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "scissors",
},
)
"""是否启用回复分割器"""
max_length: int = Field(
default=512,
json_schema_extra={
"x-widget": "input",
"x-icon": "ruler",
},
)
"""回复允许的最大长度"""
max_sentence_num: int = Field(
default=8,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""回复允许的最大句子数"""
enable_kaomoji_protection: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "smile",
"advanced": True,
},
)
"""是否启用颜文字保护"""
enable_overflow_return_all: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "maximize",
"advanced": True,
},
)
"""是否在句子数量超出回复允许的最大句子数时一次性返回全部内容"""
class LogConfig(ConfigBase):
"""日志配置类"""
__ui_label__ = "调试与日志"
__ui_icon__ = "file-text"
date_style: str = Field(
default="m-d H:i:s",
json_schema_extra={
"x-widget": "input",
"x-icon": "clock",
},
)
"""日期格式"""
log_level_style: Literal["lite", "compact", "full"] = Field(
default="lite",
json_schema_extra={
"x-widget": "select",
"x-icon": "list",
},
)
"""日志等级显示样式"""
color_text: Literal["none", "title", "full"] = Field(
default="full",
json_schema_extra={
"x-widget": "select",
"x-icon": "palette",
},
)
"""控制台日志颜色模式"""
log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = Field(
default="INFO",
json_schema_extra={
"x-widget": "select",
"x-icon": "list-filter",
},
)
"""全局日志级别"""
console_log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = Field(
default="INFO",
json_schema_extra={
"x-widget": "select",
"x-icon": "terminal",
},
)
"""控制台日志级别"""
file_log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = Field(
default="DEBUG",
json_schema_extra={
"x-widget": "select",
"x-icon": "file-json",
},
)
"""文件日志级别"""
log_file_max_bytes: int = Field(
default=5 * 1024 * 1024,
json_schema_extra={
"x-widget": "input",
"x-icon": "hard-drive",
},
)
"""单个日志文件最大字节数"""
max_log_files: int = Field(
default=30,
json_schema_extra={
"x-widget": "input",
"x-icon": "files",
},
)
"""最多保留的主日志文件数量"""
log_cleanup_days: int = Field(
default=30,
json_schema_extra={
"x-widget": "input",
"x-icon": "calendar-days",
},
)
"""主日志文件保留天数"""
llm_request_snapshot_limit: int = Field(
default=128,
json_schema_extra={
"x-widget": "input",
"x-icon": "archive",
},
)
"""失败请求快照最多保留数量"""
maisaka_prompt_preview_limit: int = Field(
default=256,
json_schema_extra={
"x-widget": "input",
"x-icon": "panel-top",
},
)
"""每个会话最多保留的 Maisaka Prompt 预览组数"""
maisaka_reply_effect_limit: int = Field(
default=256,
json_schema_extra={
"x-widget": "input",
"x-icon": "clipboard-check",
},
)
"""每个会话最多保留的 Maisaka 回复效果记录数"""
suppress_libraries: list[str] = Field(
default_factory=lambda: [
"faiss",
"httpx",
"urllib3",
"asyncio",
"websockets",
"httpcore",
"requests",
"sqlalchemy",
"openai",
"uvicorn",
"jieba",
],
json_schema_extra={
"x-widget": "custom",
"x-icon": "volume-x",
"advanced": True,
},
)
"""完全屏蔽日志的第三方库列表"""
library_log_levels: dict[str, str] = Field(
default_factory=lambda: {"aiohttp": "WARNING"},
json_schema_extra={
"x-widget": "custom",
"x-icon": "sliders-horizontal",
"advanced": True,
},
)
"""特定第三方库的日志级别"""
class TelemetryConfig(ConfigBase):
"""遥测配置类"""
__ui_parent__ = "debug"
enable: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "activity",
},
)
"""是否启用遥测"""
class DebugConfig(ConfigBase):
"""调试配置类"""
__ui_parent__ = "log"
__ui_label__ = "其他"
__ui_icon__ = "more-horizontal"
enable_maisaka_stage_board: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "layout-dashboard",
},
)
"""是否启用 Maisaka 阶段看板"""
show_maisaka_thinking: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "brain",
},
)
"""是否显示回复器推理"""
fold_maisaka_thinking: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "minimize-2",
},
)
"""是否折叠 Maisaka 的 prompt 展示入口"""
show_jargon_prompt: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "book",
},
)
"""是否显示jargon相关提示词"""
show_memory_prompt: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "database",
},
)
"""是否显示记忆检索相关prompt"""
enable_reply_effect_tracking: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "activity",
},
)
"""是否开启回复效果评分追踪,默认关闭,需要手动打开"""
record_reply_request: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "file-json",
},
)
"""是否记录 Replyer 请求体,默认关闭"""
enable_llm_cache_stats: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "chart-no-axes-column",
},
)
"""是否记录 LLM prompt cache 调试统计,默认关闭"""
class ExtraPromptItem(ConfigBase):
platform: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "wifi",
},
)
"""平台,留空无效"""
item_id: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""用户ID留空无效"""
rule_type: Literal["group", "private"] = Field(
default="group",
json_schema_extra={
"x-widget": "select",
"x-icon": "users",
"x-option-descriptions": RULE_TYPE_OPTION_DESCRIPTIONS,
},
)
"""聊天流类型group群聊或private私聊"""
prompt: str = Field(
default="",
json_schema_extra={
"x-widget": "textarea",
"x-icon": "file-text",
},
)
"""额外的prompt内容"""
def model_post_init(self, context: Optional[dict] = None) -> None:
if not self.platform and not self.item_id and not self.prompt:
return super().model_post_init(context)
if not self.platform or not self.item_id or not self.prompt:
raise ValueError("ExtraPromptItem 中 platform, id 和 prompt 不能为空")
return super().model_post_init(context)
class MaimMessageConfig(ConfigBase):
"""maim_message配置类"""
__ui_parent__ = "debug"
ws_server_host: str = Field(
default="127.0.0.1",
json_schema_extra={
"x-widget": "input",
"x-icon": "server",
},
)
"""旧版基于WS的服务器主机地址"""
ws_server_port: int = Field(
default=8000,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""旧版基于WS的服务器端口号"""
auth_token: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "key",
},
)
"""认证令牌用于旧版API验证为空则不启用验证"""
enable_api_server: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "server",
},
)
"""是否启用额外的新版API Server"""
api_server_host: str = Field(
default="0.0.0.0",
json_schema_extra={
"x-widget": "input",
"x-icon": "globe",
},
)
"""新版API Server主机地址"""
api_server_port: int = Field(
default=8090,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""新版API Server端口号"""
api_server_use_wss: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "lock",
},
)
"""新版API Server是否启用WSS"""
api_server_cert_file: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "file",
},
)
"""新版API Server SSL证书文件路径"""
api_server_key_file: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "key",
},
)
"""新版API Server SSL密钥文件路径"""
api_server_allowed_api_keys: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "shield",
},
)
"""新版API Server允许的API Key列表为空则允许所有连接"""
class LPMMKnowledgeConfig(ConfigBase):
"""LPMM知识库配置类"""
__ui_label__ = "知识库"
__ui_icon__ = "book-open"
enable: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "database",
},
)
"""是否启用LPMM知识库"""
lpmm_mode: Literal["classic", "agent"] = Field(
default="classic",
json_schema_extra={
"x-widget": "select",
"x-icon": "brain",
},
)
"""LPMM知识库模式可选classic经典模式agent 模式"""
rag_synonym_search_top_k: int = Field(
default=10,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""同义检索TopK"""
rag_synonym_threshold: float = Field(
default=0.8,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.1,
},
)
"""同义阈值,相似度高于该值的关系会被当作同义词"""
info_extraction_workers: int = Field(
default=3,
json_schema_extra={
"x-widget": "input",
"x-icon": "cpu",
},
)
"""实体抽取同时执行线程数非Pro模型不要设置超过5"""
qa_relation_search_top_k: int = Field(
default=10,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""关系检索TopK"""
qa_relation_threshold: float = Field(
default=0.75,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.05,
},
)
"""关系阈值,相似度高于该值的关系会被认为是相关关系"""
qa_paragraph_search_top_k: int = Field(
default=1000,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""段落检索TopK不能过小可能影响搜索结果"""
qa_paragraph_node_weight: float = Field(
default=0.05,
json_schema_extra={
"x-widget": "slider",
"x-icon": "weight",
"step": 0.01,
},
)
"""段落节点权重(在图搜索&PPR计算中的权重当搜索仅使用DPR时此参数不起作用"""
qa_ent_filter_top_k: int = Field(
default=10,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""实体过滤TopK"""
qa_ppr_damping: float = Field(
default=0.8,
ge=0,
le=1,
json_schema_extra={
"x-widget": "slider",
"x-icon": "percent",
"step": 0.1,
},
)
"""PPR阻尼系数"""
qa_res_top_k: int = Field(
default=10,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""最终提供段落TopK"""
embedding_dimension: int = Field(
default=1024,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""嵌入向量维度,输出维度"""
max_embedding_workers: int = Field(
default=3,
json_schema_extra={
"x-widget": "input",
"x-icon": "cpu",
},
)
"""嵌入/抽取并发线程数"""
embedding_chunk_size: int = Field(
default=4,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""每批嵌入的条数"""
max_synonym_entities: int = Field(
default=2000,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""同义边参与的实体数上限,超限则跳过"""
enable_ppr: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "zap",
},
)
"""是否启用PPR低配机器可关闭"""
class WebUIConfig(ConfigBase):
"""WebUI配置类"""
__ui_label__ = "WebUI"
__ui_icon__ = "layout"
enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "monitor",
},
)
"""是否启用WebUI"""
host: str = Field(
default="127.0.0.1",
json_schema_extra={
"x-widget": "input",
"x-icon": "globe",
},
)
"""WebUI 绑定主机地址"""
port: int = Field(
default=8001,
json_schema_extra={
"x-widget": "input",
"x-icon": "hash",
},
)
"""WebUI 绑定端口"""
mode: Literal["development", "production"] = Field(
default="production",
json_schema_extra={
"x-widget": "select",
"x-icon": "settings",
},
)
"""运行模式development(开发) 或 production(生产)"""
anti_crawler_mode: Literal["false", "strict", "loose", "basic"] = Field(
default="basic",
json_schema_extra={
"x-widget": "select",
"x-icon": "shield",
},
)
"""防爬虫模式false(禁用) / strict(严格) / loose(宽松) / basic(基础-只记录不阻止)"""
allowed_ips: str = Field(
default="127.0.0.1",
json_schema_extra={
"x-widget": "input",
"x-icon": "network",
},
)
"""IP白名单逗号分隔支持精确IP、CIDR格式和通配符"""
trusted_proxies: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "server",
},
)
"""信任的代理IP列表逗号分隔只有来自这些IP的X-Forwarded-For才被信任"""
trust_xff: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "shield-check",
},
)
"""是否启用X-Forwarded-For代理解析默认false"""
secure_cookie: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "cookie",
},
)
"""是否启用安全Cookie仅通过HTTPS传输默认false"""
enable_paragraph_content: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "file-text",
},
)
"""是否在知识图谱中加载段落完整内容需要加载embedding store会占用额外内存"""
class DatabaseConfig(ConfigBase):
"""数据库配置类"""
__ui_parent__ = "debug"
save_binary_data: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "save",
"advanced": True,
},
)
"""
是否将消息中的二进制数据保存为独立文件
若启用,消息中的语音等二进制数据将会保存为独立文件,并在消息中以特殊标记替代。启用会导致数据文件夹体积增大,但可以实现二次识别等功能。
若禁用,则消息中的二进制将会在识别后删除,并在消息中使用识别结果替代,无法二次识别
该配置项仅影响新存储的消息,已有消息不会受到影响
"""
class MCPAuthorizationConfig(ConfigBase):
"""MCP HTTP 认证配置。"""
mode: Literal["none", "bearer"] = Field(
default="none",
json_schema_extra={
"x-widget": "select",
"x-icon": "shield",
},
)
"""认证模式,当前支持无认证和静态 Bearer Token"""
bearer_token: str = Field(
default="",
json_schema_extra={
"x-widget": "password",
"x-icon": "key",
},
)
"""静态 Bearer Token仅在 `mode=\"bearer\"` 时使用"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证 MCP 认证配置。
Args:
context: Pydantic 传入的上下文对象。
Returns:
None
"""
if self.mode == "bearer" and not self.bearer_token.strip():
raise ValueError("MCP 使用 bearer 认证时必须填写 bearer_token")
return super().model_post_init(context)
class MCPRootItemConfig(ConfigBase):
"""单个 MCP Root 配置。"""
enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "power",
},
)
"""是否启用当前 Root"""
uri: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "folder",
},
)
"""Root URI通常为 `file://` 路径 URI"""
name: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "tag",
},
)
"""Root 的显示名称"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证单个 Root 配置。
Args:
context: Pydantic 传入的上下文对象。
Returns:
None
"""
if self.enabled and not self.uri.strip():
raise ValueError("启用的 MCP Root 必须填写 uri")
return super().model_post_init(context)
class MCPRootsConfig(ConfigBase):
"""MCP Roots 能力配置。"""
enable: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "folder-tree",
},
)
"""是否向 MCP 服务器暴露 Roots 能力"""
items: list[MCPRootItemConfig] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "folder",
},
)
"""Roots 列表"""
class MCPSamplingConfig(ConfigBase):
"""MCP Sampling 能力配置。"""
enable: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "brain",
},
)
"""是否启用 Sampling 能力声明"""
task_name: str = Field(
default="planner",
json_schema_extra={
"x-widget": "input",
"x-icon": "sparkles",
},
)
"""执行 Sampling 请求时使用的主程序模型任务名"""
include_context_support: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "layers",
},
)
"""是否声明支持 `includeContext` 非 `none` 语义"""
tool_support: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "wrench",
},
)
"""是否声明支持在 Sampling 中继续使用工具"""
class MCPElicitationConfig(ConfigBase):
"""MCP Elicitation 能力配置。"""
enable: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "message-circle-question",
},
)
"""是否启用 Elicitation 能力声明"""
allow_form: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "form-input",
},
)
"""是否允许表单模式 Elicitation"""
allow_url: bool = Field(
default=False,
json_schema_extra={
"x-widget": "switch",
"x-icon": "link",
},
)
"""是否允许 URL 模式 Elicitation"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证 Elicitation 配置。
Args:
context: Pydantic 传入的上下文对象。
Returns:
None
"""
if self.enable and not (self.allow_form or self.allow_url):
raise ValueError("启用 MCP Elicitation 时至少需要允许一种模式")
return super().model_post_init(context)
class MCPClientConfig(ConfigBase):
"""MCP 客户端宿主能力配置。"""
client_name: str = Field(
default="MaiBot",
json_schema_extra={
"x-widget": "input",
"x-icon": "bot",
},
)
"""MCP 客户端实现名称"""
client_version: str = Field(
default="1.0.0",
json_schema_extra={
"x-widget": "input",
"x-icon": "info",
},
)
"""MCP 客户端实现版本"""
roots: MCPRootsConfig = Field(default_factory=MCPRootsConfig)
"""Roots 能力配置"""
sampling: MCPSamplingConfig = Field(default_factory=MCPSamplingConfig)
"""Sampling 能力配置"""
elicitation: MCPElicitationConfig = Field(default_factory=MCPElicitationConfig)
"""Elicitation 能力配置"""
class MCPServerItemConfig(ConfigBase):
"""单个 MCP 服务器配置。"""
name: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "tag",
},
)
"""服务器名称,必须唯一"""
enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "power",
},
)
"""是否启用当前 MCP 服务器"""
transport: Literal["stdio", "streamable_http"] = Field(
default="stdio",
json_schema_extra={
"x-widget": "select",
"x-icon": "shuffle",
},
)
"""传输方式,可选 `stdio` 或 `streamable_http`"""
command: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "terminal",
},
)
"""stdio 模式下启动服务器的命令"""
args: list[str] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "list",
},
)
"""stdio 模式下的命令参数列表"""
env: dict[str, str] = Field(
default_factory=lambda: {},
json_schema_extra={
"x-widget": "custom",
"x-icon": "variable",
},
)
"""stdio 模式下附加的环境变量"""
url: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "link",
},
)
"""`streamable_http` 模式下的 MCP 端点地址"""
headers: dict[str, str] = Field(
default_factory=lambda: {},
json_schema_extra={
"x-widget": "custom",
"x-icon": "file-json",
},
)
"""HTTP 模式下附加的请求头"""
http_timeout_seconds: float = Field(
default=30.0,
gt=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "clock-3",
},
)
"""HTTP 请求超时时间,单位秒"""
read_timeout_seconds: float = Field(
default=300.0,
gt=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "timer",
},
)
"""会话读取超时时间,单位秒"""
authorization: MCPAuthorizationConfig = Field(default_factory=MCPAuthorizationConfig)
"""HTTP 认证配置"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证 MCP 服务器配置。
Args:
context: Pydantic 传入的上下文对象。
Returns:
None
"""
if not self.name.strip():
raise ValueError("MCPServerItemConfig.name 不能为空")
if self.transport == "stdio" and not self.command.strip():
raise ValueError(f"MCP 服务器 {self.name} 使用 stdio 时必须填写 command")
if self.transport == "streamable_http" and not self.url.strip():
raise ValueError(f"MCP 服务器 {self.name} 使用 streamable_http 时必须填写 url")
return super().model_post_init(context)
class MCPConfig(ConfigBase):
"""MCP 总配置。"""
__ui_parent__ = "maisaka"
enable: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "zap",
},
)
"""是否启用 MCPModel Context Protocol"""
client: MCPClientConfig = Field(default_factory=MCPClientConfig)
"""MCP 客户端宿主能力配置"""
servers: list[MCPServerItemConfig] = Field(
default_factory=lambda: [],
json_schema_extra={
"x-widget": "custom",
"x-icon": "server",
},
)
"""_wrap_MCP 服务器配置列表"""
def model_post_init(self, context: Optional[dict] = None) -> None:
"""验证 MCP 总配置。
Args:
context: Pydantic 传入的上下文对象。
Returns:
None
"""
server_names = [server.name.strip() for server in self.servers if server.name.strip()]
if len(server_names) != len(set(server_names)):
raise ValueError("MCP 配置中的服务器名称不能重复")
return super().model_post_init(context)
class PluginRuntimeRenderConfig(ConfigBase):
"""插件运行时浏览器渲染配置。"""
enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "image",
},
)
"""是否启用插件运行时浏览器渲染能力"""
browser_ws_endpoint: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "link",
},
)
"""优先复用的现有 Chromium CDP 地址,可填写 ws/http 端点"""
executable_path: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "folder",
},
)
"""浏览器可执行文件路径,留空时自动探测本机 Chrome/Chromium"""
browser_install_root: str = Field(
default="data/playwright-browsers",
json_schema_extra={
"x-widget": "input",
"x-icon": "hard-drive",
},
)
"""Playwright 托管浏览器目录,自动下载 Chromium 时会复用该目录"""
headless: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "monitor",
},
)
"""是否以无头模式启动浏览器"""
launch_args: list[str] = Field(
default_factory=lambda: [
"--disable-gpu",
"--disable-dev-shm-usage",
"--disable-setuid-sandbox",
"--no-sandbox",
"--no-zygote",
],
json_schema_extra={
"x-widget": "custom",
"x-icon": "terminal",
},
)
"""浏览器启动参数列表"""
concurrency_limit: int = Field(
default=2,
ge=1,
json_schema_extra={
"x-widget": "number",
"x-icon": "layers",
},
)
"""同时允许进行的最大渲染任务数"""
startup_timeout_sec: float = Field(
default=20.0,
gt=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "clock",
},
)
"""浏览器连接或启动超时时间(秒)"""
render_timeout_sec: float = Field(
default=15.0,
gt=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "timer",
},
)
"""单次渲染默认超时时间(秒)"""
auto_download_chromium: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "download",
},
)
"""未检测到可用浏览器时,是否自动下载 Playwright Chromium"""
download_connection_timeout_sec: float = Field(
default=120.0,
gt=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "cloud-lightning",
},
)
"""自动下载 Chromium 时的连接超时时间(秒)"""
restart_after_render_count: int = Field(
default=200,
ge=0,
json_schema_extra={
"x-widget": "number",
"x-icon": "refresh-cw",
},
)
"""累计渲染指定次数后自动重建本地浏览器0 表示关闭该策略"""
class PluginRuntimeConfig(ConfigBase):
"""插件运行时配置类"""
__ui_label__ = "插件运行时"
__ui_icon__ = "puzzle"
enabled: bool = Field(
default=True,
json_schema_extra={
"x-widget": "switch",
"x-icon": "power",
},
)
"""启用插件系统"""
health_check_interval_sec: float = Field(
default=30.0,
json_schema_extra={
"x-widget": "number",
"x-icon": "activity",
},
)
"""健康检查间隔(秒)"""
max_restart_attempts: int = Field(
default=3,
json_schema_extra={
"x-widget": "number",
"x-icon": "refresh-cw",
},
)
"""Runner 崩溃后最大自动重启次数"""
runner_spawn_timeout_sec: float = Field(
default=30.0,
json_schema_extra={
"x-widget": "number",
"x-icon": "clock",
},
)
"""等待 Runner 子进程启动并注册的超时时间(秒)"""
hook_blocking_timeout_sec: float = Field(
default=30,
json_schema_extra={
"x-widget": "number",
"x-icon": "timer",
},
)
"""Hook 阻塞步骤的全局超时上限(秒)"""
ipc_socket_path: str = Field(
default="",
json_schema_extra={
"x-widget": "input",
"x-icon": "link",
},
)
"""
自定义 IPC Socket 路径(仅 Linux/macOS 生效)
留空则自动生成临时路径
"""
render: PluginRuntimeRenderConfig = Field(default_factory=PluginRuntimeRenderConfig)
"""浏览器渲染能力配置"""