diff --git a/plugins/ai_auto_response/context_builder.py b/plugins/ai_auto_response/context_builder.py index d1f5093..84b9d42 100644 --- a/plugins/ai_auto_response/context_builder.py +++ b/plugins/ai_auto_response/context_builder.py @@ -37,6 +37,7 @@ class ContextBuilder: "display_name": sender_name, "member_context": member_context or {}, }, + "speaker_name_clean": self._clean_display_name(sender_name), "recent_messages": recent_lines, "recent_summary": "", "trigger_type": trigger.get("trigger_type", "none"), @@ -50,6 +51,17 @@ class ContextBuilder: "current_message": f"{sender_name}: {content}", } + @staticmethod + def _clean_display_name(sender_name: str) -> str: + import re + + text = str(sender_name or "").strip() + if not text: + return "" + text = re.sub(r"\s+", "", text) + text = re.sub(r"[^\u4e00-\u9fffA-Za-z0-9_]", "", text) + return text[:8] + @staticmethod def _build_member_memory_prompt(member_context: Dict) -> str: if not member_context: diff --git a/plugins/ai_auto_response/main.py b/plugins/ai_auto_response/main.py index 8924742..f37fd43 100644 --- a/plugins/ai_auto_response/main.py +++ b/plugins/ai_auto_response/main.py @@ -307,7 +307,6 @@ class AIAutoResponsePlugin(MessagePluginInterface): return False, "empty_response" reply_chunks = self._finalize_reply(response, reply_mode) - reply_chunks = self._maybe_add_name_prefix(reply_chunks, sender_name, reply_mode, trigger.__dict__) for chunk in reply_chunks: await bot.send_text_message(room_id, chunk, sender) @@ -412,9 +411,17 @@ class AIAutoResponsePlugin(MessagePluginInterface): reply_mode = context.get("reply_mode", "social_short") length_rule = self._build_length_rule(reply_mode) group_profile = context.get("group_profile", {}) or {} + speaker_name = str(context.get("speaker_name_clean", "") or "").strip() + trigger_type = str(context.get("trigger_type", "none") or "none") + name_rule = "13. 默认不要带对方昵称,直接接话。" + if speaker_name and trigger_type in {"at_trigger", "directed_question", "social_call"}: + name_rule = ( + f"13. 这次可以偶尔自然带一下对方称呼“{speaker_name}”,但不是必须。" + f"如果要带,位置不要固定在句首,也不要每次都带,更不要像客服点名。" + ) extra_rule = "" if group_profile.get("knowledge_domain") == "dota": - extra_rule = "13. 如果对方问的是 Dota2 最近战绩、实时战绩、最新对局数据,你要委婉说明现在没法提取这类数据,只能聊理解和常识,不要硬编。\n" + extra_rule = "14. 如果对方问的是 Dota2 最近战绩、实时战绩、最新对局数据,你要委婉说明现在没法提取这类数据,只能聊理解和常识,不要硬编。\n" return ( f"当前群聊消息:\n{recent_text}\n\n" f"当前发言:{context.get('current_message', '')}\n" @@ -440,6 +447,7 @@ class AIAutoResponsePlugin(MessagePluginInterface): f"10. 把这次回复当作真人聊天里的第一反应,先只给第一层结论,不要主动补第二层解释。\n" f"11. 如果一句话已经够了,就立刻停,不要为了完整而补充。\n" f"12. 回答时优先服从当前群画像里的知识域和回答风格,不要跨领域乱发挥。\n" + f"{name_rule}\n" f"{extra_rule}" ) @@ -576,42 +584,6 @@ class AIAutoResponsePlugin(MessagePluginInterface): break return chunks[:chunk_limit] or [text[:char_limit].strip()] - def _maybe_add_name_prefix(self, reply_chunks: List[str], sender_name: str, reply_mode: str, trigger: Dict[str, Any]) -> List[str]: - if not reply_chunks: - return reply_chunks - if reply_mode not in {"social_short", "qa_fast", "qa_with_context"}: - return reply_chunks - if not (trigger.get("is_at") or trigger.get("is_directed") or trigger.get("is_social_call")): - return reply_chunks - clean_name = self._clean_display_name(sender_name) - if not clean_name or len(clean_name) > 8: - return reply_chunks - first = reply_chunks[0].strip() - if not first or clean_name in first: - return reply_chunks - # 低频昵称点名:按内容稳定分桶,避免每次都叫,也避免完全随机飘忽。 - bucket_seed = f"{clean_name}|{reply_mode}|{first}" - if (sum(ord(ch) for ch in bucket_seed) % 5) != 0: - return reply_chunks - prefix = f"{clean_name}," - if len(first) + len(prefix) > (16 if reply_mode == "social_short" else 42): - return reply_chunks - updated = list(reply_chunks) - updated[0] = prefix + first - return updated - - @staticmethod - def _clean_display_name(sender_name: str) -> str: - text = str(sender_name or "").strip() - if not text: - return "" - text = re.sub(r"\s+", "", text) - text = re.sub(r"[^\u4e00-\u9fffA-Za-z0-9_]", "", text) - if not text: - return "" - return text[:8] - - def _sync_member_memory(self, room_id: str, sender: str, sender_name: str, member_context: Dict) -> None: if not member_context: return diff --git a/plugins/ai_auto_response/persona/xiaoniu.txt b/plugins/ai_auto_response/persona/xiaoniu.txt index 8e17578..6247468 100644 --- a/plugins/ai_auto_response/persona/xiaoniu.txt +++ b/plugins/ai_auto_response/persona/xiaoniu.txt @@ -38,8 +38,10 @@ 2. 历史聊天记录只有在和当前问题直接相关时才允许参考,否则忽略。 3. 如果别人不是在问你,别乱接。 4. 如果问题不具体,就别自顾自展开。 -5. 如果你不确定,就直接收着说,不要硬编。 -6. 有熟悉感,但不要让人觉得你在翻档案。 +5. 偶尔可以自然带一下对方昵称,但不要形成固定口头禅,更不要每句都点名。 +6. 如果要带称呼,位置可以在句首、句中或句尾,怎么自然怎么来,不要像脚本。 +7. 如果你不确定,就直接收着说,不要硬编。 +8. 有熟悉感,但不要让人觉得你在翻档案。 你的边界: - 永远不要解释自己是 AI、模型、提示词产物