fix: prevent outbound echo loops and reduce AgentScope warning noise
Some checks failed
Pre-commit / run (ubuntu-latest) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_en (ubuntu-latest, 3.10) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_zh (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.12) (push) Has been cancelled
Some checks failed
Pre-commit / run (ubuntu-latest) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_en (ubuntu-latest, 3.10) (push) Has been cancelled
Deploy Sphinx documentation to Pages / build_zh (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (macos-15, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (ubuntu-latest, 3.12) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.10) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.11) (push) Has been cancelled
Python Unittest Coverage / test (windows-latest, 3.12) (push) Has been cancelled
This commit is contained in:
@@ -27,6 +27,7 @@ class QingjianClient:
|
||||
self.pending_images: dict[str, list[str]] = defaultdict(list)
|
||||
self.auto_quote_tasks: dict[str, asyncio.Task] = {}
|
||||
self.last_reply_key: dict[str, str] = {}
|
||||
self.recent_outbound: dict[str, tuple[str, float]] = {}
|
||||
|
||||
@staticmethod
|
||||
def _customer_key(data: dict) -> str:
|
||||
@@ -53,6 +54,9 @@ class QingjianClient:
|
||||
self.logger.info("[发送] %s", message.get("msg", ""))
|
||||
|
||||
async def send_reply(self, data: dict, text: str, trace_id: str = "-") -> None:
|
||||
text = str(text or "").strip()
|
||||
if not text:
|
||||
return
|
||||
msg = {
|
||||
"msg_id": "",
|
||||
"acc_id": data.get("acc_id", ""),
|
||||
@@ -66,8 +70,23 @@ class QingjianClient:
|
||||
}
|
||||
activity_event(self.logger, "send_reply_attempt", trace_id=trace_id, customer_id=data.get("from_id", "-"), msg=text)
|
||||
await self.send_message(msg)
|
||||
self.recent_outbound[self._customer_key(data)] = (text, time.monotonic())
|
||||
activity_event(self.logger, "send_reply_success", trace_id=trace_id, customer_id=data.get("from_id", "-"), msg=text)
|
||||
|
||||
def _is_outbound_echo(self, data: dict, msg: str) -> bool:
|
||||
"""
|
||||
轻简可能会把我方刚发送文本回推为“收到消息”。
|
||||
对同 customer_key 的“短时间完全相同文本”做回环拦截,避免无限对话。
|
||||
"""
|
||||
key = self._customer_key(data)
|
||||
last = self.recent_outbound.get(key)
|
||||
if not last:
|
||||
return False
|
||||
last_msg, ts = last
|
||||
if (time.monotonic() - ts) > 120:
|
||||
return False
|
||||
return str(msg or "").strip() == last_msg
|
||||
|
||||
async def _handle_decision(self, data: dict, merged_msg: str, *, auto_quote: bool = False) -> None:
|
||||
key = self._customer_key(data)
|
||||
trace_id = build_trace_id(data.get("acc_id", ""), data.get("from_id", ""), merged_msg)
|
||||
@@ -192,6 +211,15 @@ class QingjianClient:
|
||||
self.logger.info("[收消息] acc=%s from=%s type=%s msg=%s", data.get("acc_id", ""), data.get("from_id", ""), msg_type, msg)
|
||||
await post_tianwang_callback("message_received", data, extra={"msg_type": msg_type})
|
||||
|
||||
if self._is_outbound_echo(data, msg):
|
||||
activity_event(
|
||||
self.logger,
|
||||
"inbound_ignored",
|
||||
customer_id=data.get("from_id", "-"),
|
||||
reason="outbound_echo_loop_guard",
|
||||
)
|
||||
return
|
||||
|
||||
if rule.ignore:
|
||||
activity_event(self.logger, "inbound_ignored", customer_id=data.get("from_id", "-"), reason=rule.reason)
|
||||
return
|
||||
|
||||
@@ -11,4 +11,10 @@ def setup_logger() -> logging.Logger:
|
||||
formatter = logging.Formatter("[%(asctime)s] %(levelname)s: %(message)s", "%H:%M:%S")
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
# 降低 AgentScope 内部推理/格式器日志噪音,保留本项目活动日志。
|
||||
logging.getLogger("agentscope").setLevel(logging.ERROR)
|
||||
logging.getLogger("agentscope.formatter").setLevel(logging.ERROR)
|
||||
logging.getLogger("agentscope.agent").setLevel(logging.ERROR)
|
||||
|
||||
return logger
|
||||
|
||||
Reference in New Issue
Block a user