补充 ai_auto_response 的完整模型决策日志
变更项: 1. 新增 LLM_RESULT 日志,记录模型输出的 should_reply、reply_mode、topic、reply 预览和原始响应预览。 2. 新增 BLOCKED_REPLY 日志,记录模型原本想回复但被 post_llm_cooldown、过期、覆盖或重复回复拦下的具体原因。 3. 保留原有 SKIP 与 SENT 日志,使模型判定、发送阻断和最终发出三段链路可以串起来排查。
This commit is contained in:
@@ -608,6 +608,21 @@ class AIAutoResponsePlugin(MessagePluginInterface):
|
|||||||
fallback_reply_mode=reply_mode,
|
fallback_reply_mode=reply_mode,
|
||||||
fallback_topic=trigger.topic or "",
|
fallback_topic=trigger.topic or "",
|
||||||
)
|
)
|
||||||
|
# 这里补一条完整的模型决策日志:
|
||||||
|
# 1. 无论模型最终决定回还是不回,都先把 should_reply / reply_mode / topic / reply 预览记下来;
|
||||||
|
# 2. 同时保留 sanitize 后的原始响应预览,方便排查“模型其实回了什么 JSON / 文本”;
|
||||||
|
# 3. 这样后面即使被 cooldown、过期、去重拦住,也能明确看到“模型本来想怎么做”。
|
||||||
|
self._log_event(
|
||||||
|
"llm_result",
|
||||||
|
room_id=room_id,
|
||||||
|
sender=sender,
|
||||||
|
trigger_type=trigger.trigger_type,
|
||||||
|
should_reply=bool(llm_result.get("should_reply", True)),
|
||||||
|
reply_mode=str(llm_result.get("reply_mode", reply_mode) or reply_mode),
|
||||||
|
topic=str(llm_result.get("topic_summary", "") or llm_result.get("topic_id", "") or trigger.topic or ""),
|
||||||
|
response_preview=preview_text(str(llm_result.get("reply", "") or ""), 120),
|
||||||
|
raw_response_preview=preview_text(response, 160),
|
||||||
|
)
|
||||||
if not llm_result.get("should_reply", True):
|
if not llm_result.get("should_reply", True):
|
||||||
self._log_event(
|
self._log_event(
|
||||||
"skip",
|
"skip",
|
||||||
@@ -639,6 +654,16 @@ class AIAutoResponsePlugin(MessagePluginInterface):
|
|||||||
# 2. 模型先统一判断 should_reply,只有当它明确想回时,才进入频率控制;
|
# 2. 模型先统一判断 should_reply,只有当它明确想回时,才进入频率控制;
|
||||||
# 3. 仍然保留冷却,是为了守住群内刷屏风险,但职责已经变成“限制发送”,不是“替模型做语义裁决”。
|
# 3. 仍然保留冷却,是为了守住群内刷屏风险,但职责已经变成“限制发送”,不是“替模型做语义裁决”。
|
||||||
if not self.cooldown.pass_cooldown(room_id, sender, trigger.__dict__):
|
if not self.cooldown.pass_cooldown(room_id, sender, trigger.__dict__):
|
||||||
|
self._log_event(
|
||||||
|
"blocked_reply",
|
||||||
|
room_id=room_id,
|
||||||
|
sender=sender,
|
||||||
|
reason=f"post_llm_{trigger.__dict__.get('_cooldown_reason', 'cooldown')}",
|
||||||
|
trigger_type=trigger.trigger_type,
|
||||||
|
reply_mode=reply_mode,
|
||||||
|
topic=selected_topic,
|
||||||
|
response_preview=preview_text(reply_text, 120),
|
||||||
|
)
|
||||||
self._log_event(
|
self._log_event(
|
||||||
"skip",
|
"skip",
|
||||||
room_id=room_id,
|
room_id=room_id,
|
||||||
@@ -657,6 +682,17 @@ class AIAutoResponsePlugin(MessagePluginInterface):
|
|||||||
# 2. 即使消息进模型时还新鲜,等模型回完也可能已经跟不上群聊了;
|
# 2. 即使消息进模型时还新鲜,等模型回完也可能已经跟不上群聊了;
|
||||||
# 3. 这种情况下直接放弃发送,比突然补回旧话更自然。
|
# 3. 这种情况下直接放弃发送,比突然补回旧话更自然。
|
||||||
if self._is_message_stale(message):
|
if self._is_message_stale(message):
|
||||||
|
self._log_event(
|
||||||
|
"blocked_reply",
|
||||||
|
room_id=room_id,
|
||||||
|
sender=sender,
|
||||||
|
reason="stale_before_send",
|
||||||
|
trigger_type=trigger.trigger_type,
|
||||||
|
reply_mode=reply_mode,
|
||||||
|
topic=selected_topic,
|
||||||
|
response_preview=preview_text(final_response_text, 120),
|
||||||
|
age_sec=round(self._get_message_queue_age_sec(message), 2),
|
||||||
|
)
|
||||||
self._log_event(
|
self._log_event(
|
||||||
"skip",
|
"skip",
|
||||||
room_id=room_id,
|
room_id=room_id,
|
||||||
@@ -673,6 +709,16 @@ class AIAutoResponsePlugin(MessagePluginInterface):
|
|||||||
# 2. 这时即使模型产出了结果,也不应该再把旧回复补发出去;
|
# 2. 这时即使模型产出了结果,也不应该再把旧回复补发出去;
|
||||||
# 3. 直接丢弃旧结果,让群里只看到贴着最新现场的回复。
|
# 3. 直接丢弃旧结果,让群里只看到贴着最新现场的回复。
|
||||||
if self._is_message_superseded(message):
|
if self._is_message_superseded(message):
|
||||||
|
self._log_event(
|
||||||
|
"blocked_reply",
|
||||||
|
room_id=room_id,
|
||||||
|
sender=sender,
|
||||||
|
reason="superseded_before_send",
|
||||||
|
trigger_type=trigger.trigger_type,
|
||||||
|
reply_mode=reply_mode,
|
||||||
|
topic=selected_topic,
|
||||||
|
response_preview=preview_text(final_response_text, 120),
|
||||||
|
)
|
||||||
self._log_event(
|
self._log_event(
|
||||||
"skip",
|
"skip",
|
||||||
room_id=room_id,
|
room_id=room_id,
|
||||||
@@ -690,6 +736,16 @@ class AIAutoResponsePlugin(MessagePluginInterface):
|
|||||||
reply_text=final_response_text,
|
reply_text=final_response_text,
|
||||||
expiry_sec=reply_dedup_expiry,
|
expiry_sec=reply_dedup_expiry,
|
||||||
):
|
):
|
||||||
|
self._log_event(
|
||||||
|
"blocked_reply",
|
||||||
|
room_id=room_id,
|
||||||
|
sender=sender,
|
||||||
|
reason="duplicate_reply",
|
||||||
|
trigger_type=trigger.trigger_type,
|
||||||
|
reply_mode=reply_mode,
|
||||||
|
topic=selected_topic,
|
||||||
|
response_preview=preview_text(final_response_text, 120),
|
||||||
|
)
|
||||||
self._log_event(
|
self._log_event(
|
||||||
"skip",
|
"skip",
|
||||||
room_id=room_id,
|
room_id=room_id,
|
||||||
|
|||||||
@@ -76,6 +76,31 @@ def build_log_summary(event: str, data: Dict[str, Any]) -> str:
|
|||||||
f"err={data.get('last_error', '')}"
|
f"err={data.get('last_error', '')}"
|
||||||
).strip()
|
).strip()
|
||||||
|
|
||||||
|
if event == "llm_result":
|
||||||
|
return (
|
||||||
|
f"[XIAONIU] LLM_RESULT room={room} user={sender} "
|
||||||
|
f"trigger={data.get('trigger_type', 'none')} "
|
||||||
|
f"want={yn(data.get('should_reply'))} "
|
||||||
|
f"mode={data.get('reply_mode', '')} "
|
||||||
|
f"topic={data.get('topic', '-') or '-'} "
|
||||||
|
f"reply={data.get('response_preview', '')} "
|
||||||
|
f"raw={data.get('raw_response_preview', '')}"
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
if event == "blocked_reply":
|
||||||
|
age_text = ""
|
||||||
|
if data.get("age_sec") not in (None, ""):
|
||||||
|
age_text = f" age={data.get('age_sec')}"
|
||||||
|
return (
|
||||||
|
f"[XIAONIU] BLOCKED_REPLY room={room} user={sender} "
|
||||||
|
f"reason={data.get('reason', '')} "
|
||||||
|
f"trigger={data.get('trigger_type', 'none')} "
|
||||||
|
f"mode={data.get('reply_mode', '')} "
|
||||||
|
f"topic={data.get('topic', '-') or '-'} "
|
||||||
|
f"reply={data.get('response_preview', '')}"
|
||||||
|
f"{age_text}"
|
||||||
|
).strip()
|
||||||
|
|
||||||
if event == "sent":
|
if event == "sent":
|
||||||
return (
|
return (
|
||||||
f"[XIAONIU] SENT room={room} user={sender_name}/{sender} "
|
f"[XIAONIU] SENT room={room} user={sender_name}/{sender} "
|
||||||
|
|||||||
Reference in New Issue
Block a user