Files
abot/plugins/ai_auto_response/config.toml
liuwei e7d68a89c2 下放 ai_auto_response 参与判断到 LLM
变更项:
1. 新增 decision 配置并重写 ResponsePlanner,将是否送模型的本地粗筛收缩为轻量入口判断,允许在主动参与开启时更多普通文本进入模型。
2. 将 cooldown 从模型前挡板后移到 LLM 判定 should_reply 之后,改为发送闸门,减少本地提前拦截。
3. 调整上下文与 prompt 控制信息,明确 reply_mode 只是本地 hint,并把 acceptance_state、solver 等信号直接下放给模型统一判断是否参与和如何回复。
2026-04-28 17:41:02 +08:00

309 lines
13 KiB
TOML
Raw Permalink 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.
enable = true
[persona]
active_persona = "xiaoniu"
name = "小牛"
persona_file = "persona/xiaoniu.txt"
style = "自然、口语化、像群友,技术宅气质明显,先回答问题,再决定是否延伸"
emoji_probability = 0.18
max_reply_sentences = 3
familiarity_hint = "有熟悉感,但不过度装熟"
[persona.presets.xiaoniu]
name = "小牛"
persona_file = "persona/xiaoniu.txt"
style = "自然、松弛、像潜水老群友,技术宅气质明显,先给判断,再决定是否延伸"
max_reply_sentences = 3
familiarity_hint = "有熟悉感,但不过度装熟"
aliases = ["小牛", "xiaoniu", "默认"]
[persona.presets.yuqian]
name = "于谦"
persona_file = "persona/yuqian_sharp.txt"
style = "北京式温和挤兑,先捧后翻,笑着损两句,但不把场子聊僵"
max_reply_sentences = 3
familiarity_hint = "熟人式损两句,但别真伤人"
aliases = ["于谦", "yuqian", "毒舌", "毒舌版"]
[persona.presets.lingzhiling]
name = "林志玲"
persona_file = "persona/lingzhiling_gentle.txt"
style = "成熟、温柔、优雅,像有分寸的大姐姐,安抚感强但不肉麻"
max_reply_sentences = 3
familiarity_hint = "有亲和力,但不越界装熟"
aliases = ["林志玲", "lingzhiling", "温柔", "温柔版"]
[api]
# 群聊自动回复统一走 auto_reply.group 场景,便于灰度切换不同供应商。
scene = "auto_reply.group"
[runtime]
llm_max_concurrency = 3
llm_call_timeout_sec = 20
message_expire_sec = 12
queue_worker_count = 2
queue_maxsize = 500
[mode]
group_default_mode = "social"
question_reply_timeout_sec = 12
followup_session_window_sec = 300
recent_context_size = 30
allow_proactive_reply = true
returning_member_days = 7
long_absent_member_days = 30
memory_lookback_days = 180
active_context_hours = 8
[decision]
# 决策层改成“LLM 优先裁决”:
# 1. 本地尽量只做硬过滤和极轻的入口判断;
# 2. 是否参与聊天、是否回复、最终 reply_mode 尽量交给模型自己输出 should_reply 来决定;
# 3. 这样会增加一定模型调用量,但能明显减少本地规则把语境复杂消息提前拦掉的问题。
model_decides_participation = true
# 当 allow_proactive_reply=true 时,这里允许普通群聊文本也送模型:
# 1. 本地不再要求必须先命中 question/topic/followup 等信号才进模型;
# 2. 最终由模型结合最近消息、群接受度、是否已有真人在答等信号统一判断 should_reply
# 3. 如果后续觉得成本又偏高,可以只把这个开关关掉,而不必回退整套旧规则。
allow_all_text_when_proactive = true
[reply]
# 回复长度改成“下限放开、上限约束”的思路:
# 1. 允许模型只回几个字,避免每句都被逼着凑满;
# 2. 统一把本地最终兜底上限放到 30 字,给一句完整观点留空间;
# 3. qa_with_context 仍保留 2 句能力,但总字数同样压住,不让它长成说明文。
social_short_char_limit = 30
social_short_total_limit = 30
qa_fast_char_limit = 30
qa_fast_total_limit = 30
qa_with_context_sentence_limit = 2
qa_with_context_chunk_limit = 2
qa_with_context_char_limit = 18
qa_with_context_total_limit = 30
default_char_limit = 30
default_total_limit = 30
[emoji_reply]
# 自动回复和表情库的衔接策略:
# 1. 模型仍然只输出自然文本,本地只在“极短情绪回复”场景里尝试换成表情;
# 2. 这样不用把 md5 暴露给模型,也更方便后续继续扩展同义词和人工校准;
# 3. 第一版只做保守替换,避免把正常答疑文本误发成表情。
enable = true
asset_scan_limit = 800
cache_ttl_sec = 300
max_reply_chars = 8
max_alias_chars = 16
min_match_score = 75
min_semantic_length = 1
require_single_chunk = true
[prompt_compact]
# 这里改成“常驻轻背景 + 相关增强”后,群长期摘要和成员轻画像都会稳定带给模型:
# 1. group_profile 放宽,让群长期摘要不会总被前面的模式/知识域说明挤掉;
# 2. member_profile_brief_* 新增为常驻轻画像额度,每次都给当前发言人一小段稳定画像;
# 3. 更重的成员记忆、群事实、向量记忆仍然保留独立额度,并继续走按需增强。
group_profile_max_chars = 420
group_profile_max_lines = 10
member_profile_brief_max_chars = 260
member_profile_brief_max_lines = 6
# 最近上下文现在要真实交给模型 30 条,因此这里同步放宽整体上下文裁剪阈值:
# 1. recent_message_max_lines 提到 30避免“窗口明明有 30提示词里只留下 4 条”;
# 2. context_max_lines/context_max_chars 一起抬高,避免最近消息刚拼进去又被整体截断;
# 3. recent_message_line_max_chars 稍微放宽,让模型能看到每条消息更多细节,但仍避免单条刷屏。
context_max_chars = 5600
context_max_lines = 40
recent_message_max_lines = 30
recent_message_line_max_chars = 100
at_member_profile_max_chars = 160
at_member_profile_max_lines = 5
member_memory_max_chars = 180
member_memory_max_lines = 6
memory_max_chars = 520
memory_max_lines = 14
strict_memory_relevance = true
[image]
recent_followup_window_minutes = 5
[priority]
at_bot = 1.0
explicit_question = 0.95
# 这里从“必须 @ 才答”放宽到“群问句可以有限参与”:
# 1. 非定向问句不再直接判死刑;
# 2. 但代码层仍会要求命中 topic、或当前心流升温、或群接受度较高时才放行
# 3. 这样可以把频率拉回正常区间,同时避免回到早期“见问就抢答”。
question_requires_at = false
# 这里允许“点 bot 名字”作为弱定向信号,但不会把普通群问句当成 bot 提问。
# 只有出现这些名字/别名时,问句或社交召唤才会更像在对 bot 说话。
bot_name_keywords = ["小牛", "xiaoniu", "于谦", "谦哥", "林志玲", "志玲"]
# 这些词本身太泛,必须和 bot 名字一起出现,才算社交召唤。
social_call_verb_patterns = ["在吗", "出来", "帮忙看", "看看", "说句话", "回一句", "救一下"]
followup = 0.90
social_call = 0.65
light_social = 0.45
casual_topic = 0.35
[flow]
enable_flow_state = true
# 这里把心流门槛从“偏保守”调回“中等保守”:
# 1. 降低衰减速度,避免群里稍微安静一会儿就立刻掉回 idle
# 2. 下调 warming / engaged 门槛,让 bot 更容易在连续讨论里接住后续话题;
# 3. 仍保留 over_reply 与 ignored_reply 惩罚,避免高频刷存在感。
flow_decay_per_minute = 10
idle_threshold = 24
warming_threshold = 42
engaged_threshold = 72
at_bot_boost = 40
question_boost = 30
followup_boost = 20
topic_boost = 10
returning_member_boost = 6
response_accepted_boost = 10
ignored_reply_penalty = 18
over_reply_penalty = 18
night_penalty = 30
max_bot_reply_streak = 2
[cooldown]
# 这里把冷却从“强压频”回调到“正常拟人”:
# 1. 群级冷却缩短,避免 bot 说完一句后整段讨论都接不上;
# 2. 同人追问冷却同步缩短,方便连续答疑;
# 3. 定向 burst 限流仍在,只是把阈值调回不那么容易误伤的区间。
group_reply_cooldown_sec = 60
same_user_followup_cooldown_sec = 12
at_mention_min_interval_sec = 5
at_mention_burst_window_sec = 90
at_mention_burst_limit = 5
at_mention_silent_sec = 180
directed_burst_window_sec = 240
directed_burst_limit = 5
directed_burst_silent_sec = 300
night_silent_hours = ["01:00-07:30"]
[memory]
enable_member_context = true
enable_vector_memory = true
enable_group_fact_snapshot = true
enable_social_snapshot = true
social_lookback_hours = 72
max_relation_items = 4
social_cache_ttl_seconds = 120
group_fact_window_size = 80
ranked_vector_items = 2
ranked_social_items = 2
ranked_group_fact_items = 3
ranked_member_focus_items = 4
memory_domain_weight = 2.5
memory_relation_weight = 2.0
memory_freshness_weight = 1.5
memory_trigger_weight = 1.2
vector_provider = "qdrant"
embedding_provider = "ollama"
qdrant_url = "http://192.168.2.240:6333"
qdrant_collection = "abot_xiaoniu_memory"
ollama_base_url = "http://192.168.2.50:11434"
embedding_model = "bge-m3"
vector_top_k = 5
max_context_memories = 2
vector_min_score = 0.65
vector_trigger_modes = ["returning_member", "long_absent_member", "qa_with_context", "reactivated_topic"]
[topics]
focus = [
"技术", "开发", "程序", "python", "微信机器人", "脚本", "报错", "部署",
"服务器", "docker", "数据库", "redis", "mysql", "qdrant", "ollama", "dify",
"ai", "大模型", "接口", "插件", "自动化", "dota", "dota2", "刀塔"
]
[filters]
ignore_prefixes = ["/", "#"]
ignore_exact = ["收到", "好的", "嗯", "哦", "6", "1", "", "?"]
min_text_length = 1
[spam_guard]
repeat_window_sec = 20
repeat_threshold = 3
repeat_min_length = 4
[logging]
debug = true
[group_profiles]
# 群长期记忆不再只读“最新一天那篇总结”:
# 1. 这里读取最近 5 份群摘要,再聚合成稳定主题/近期重点/未决问题;
# 2. 自动回复消费时优先走这些结构字段,减少 markdown 大段文本的理解损耗;
# 3. item_limit 控制每类字段带给模型的条数,避免群背景过重。
# 4. cache_ttl_sec 现在按“群画像日更”来理解:默认一天内直接复用,只在群总结更新或过了窗口后才重建。
summary_history_limit = 5
summary_item_limit = 4
cache_ttl_sec = 86400
[group_profiles.default]
mode = "social"
persona_id = "xiaoniu"
knowledge_domain = "general"
knowledge_focus = ["群当前话题", "日常闲聊", "通用技术常识"]
reply_style = "自然、克制、短句"
interaction_tone = "像常驻群友,先看场合再开口"
humor_style = "轻微,偶尔一丝冷幽默"
sharpness_style = "轻微嘴硬,不刻薄"
expressiveness_style = "克制偏松弛"
address_style = "低频称呼,默认直接接话,只有在明确对你说话时才偶尔带一下昵称"
persona_overlay = "小牛默认是技术宅,但在普通闲聊群不端着,不强行上技术。"
[[group_profiles.profiles]]
mode = "robotics"
persona_id = "xiaoniu"
group_name_keywords = ["机器人", "bot", "wechat", "微信机器人", "自动化"]
knowledge_domain = "robotics"
knowledge_focus = ["微信机器人", "插件机制", "消息路由", "自动化脚本", "部署与调试"]
reply_style = "优先给结论,再补一个最关键排查点"
interaction_tone = "技术宅同好群,偏认真,少耍嘴皮子"
humor_style = "很低,只能点到为止"
sharpness_style = "可轻微吐槽错误姿势,但以排障为主"
expressiveness_style = "短句,偏干货"
address_style = "很少称呼,技术答疑时直接说结论,除非需要确认对象才点一下名字"
persona_overlay = "这里是机器人相关群,小牛可以优先从机器人、插件、接口、部署角度理解问题,但只有当前消息真的相关时再往这边靠。"
[[group_profiles.profiles]]
mode = "openclaw"
persona_id = "xiaoniu"
group_name_keywords = ["openclaw","龙虾","🦞"]
knowledge_domain = "openclaw"
knowledge_focus = ["OpenClaw架构", "OpenClaw接入", "配置排查", "运行问题", "接口联调"]
reply_style = "专注OpenClaw相关技术不跑偏到无关方向"
interaction_tone = "项目协作群,专注问题本身"
humor_style = "极低,除非对方明显在开玩笑"
sharpness_style = "尽量收着,别把项目群聊成斗嘴"
expressiveness_style = "克制、直接"
address_style = "几乎不点名,项目群里优先就事论事,除非必须确认责任或上下文"
persona_overlay = "这里是 OpenClaw 群,小牛理解技术问题时可以把 OpenClaw 当作优先背景,但如果当前消息只是普通闲聊或泛话题,就按当前上下文自然回复,不要硬提 OpenClaw。"
[[group_profiles.profiles]]
mode = "social"
persona_id = "xiaoniu"
group_name_keywords = ["闲聊", "唠嗑", "水群","养生"]
knowledge_domain = "casual"
knowledge_focus = ["群当前话题", "轻松闲聊"]
reply_style = "更像群友,少一点技术说明"
interaction_tone = "熟人闲聊群,可以更松一点"
humor_style = "中等,可以带一点冷幽默"
sharpness_style = "允许轻微嘴欠,但别刺人"
expressiveness_style = "松弛一点,像随口接话"
address_style = "可以偶尔带昵称,像熟人群友顺手接一句,但别每次都叫人"
persona_overlay = "这里偏闲聊,小牛可以轻松一点,但仍然少说,不抢话,也别硬把技术群偏好带进来。"
[[group_profiles.profiles]]
mode = "dota"
persona_id = "xiaoniu"
group_name_keywords = ["dota", "dota2", "刀塔","强神"]
knowledge_domain = "dota"
knowledge_focus = ["Dota英雄", "对线理解", "出装节奏", "团战思路", "版本常识"]
reply_style = "像懂游戏的老群友,短句,不硬装解说"
interaction_tone = "老玩家聊天,允许一点损和调侃"
humor_style = "中等偏上,能接梗"
sharpness_style = "允许轻微毒舌,但别上头"
expressiveness_style = "松弛、像老群友拌嘴"
address_style = "可偶尔带外号或昵称,像老群友接茬,但频率别高,别像故意抖机灵"
persona_overlay = "这里如果聊到 Dota小牛可以自然带一点懂行感但别尬玩梗别写成长篇攻略。只有当前消息明显在聊 Dota 时才往这边靠;如果问题涉及最近战绩、实时战绩、最新对局数据,要委婉承认现在没法提取,不要编。"