This commit is contained in:
李鹏宇
2026-06-05 16:29:06 +08:00
parent 3c90fdf45d
commit 024bbde425
+16 -9
View File
@@ -598,28 +598,35 @@ class AiConversation(models.Model):
# 主入口
# ---------------------------------------------------------
def _check_hallucinated_url(self, content):
"""检测 LLM 响应中是否编造了报表链接。
"""检测并移除 LLM 响应中编造的报表链接。
真正的报表链接由 generate_report 工具返回,格式为
https://域名/yuthon/report/<12位hex>。
LLM 有时会跳过工具调用,直接在文本中编造一个链接,
典型模式:/ai/report/<uuid>、/report/<uuid> 等。
典型模式:/ai/report/<任意>、/report/<uuid> 等。
检测到后移除伪造链接并用提示文本替换,避免用户点击无效链接。
"""
if not content:
return
return content
import re
# 匹配 URL 中包含 /report/ 但不是 /yuthon/report/ 的模式
# 匹配伪造的报表链接模式
hallucinated = re.findall(
r'(https?://[^\s]*?/(?:ai[-_]?)?report/[^\s]+|'
r'(?<!/)yuthon/report/[a-f0-9]{13,}|'
r'(?<!/)yuthon/report/[a-f0-9]{1,11}(?:\s|$))',
r'https?://[^\s]*?/(?:ai[-_]?)?report/[^\s]+',
content, re.IGNORECASE
)
if hallucinated:
_logger.warning(
'LLM 可能编造了报表链接 (conversation=%s, uid=%s): %s',
'LLM 编造了报表链接并已拦截 (conversation=%s, uid=%s): %s',
self.id, self.env.uid, hallucinated
)
cleaned = content
for url in hallucinated:
cleaned = cleaned.replace(url, '')
# 清理可能残留的空行
cleaned = re.sub(r'\n{3,}', '\n\n', cleaned).strip()
cleaned += '\n\n(系统检测到上述回复中包含无效链接,已自动移除。如需要报表,请重新提问。)'
return cleaned
return content
def send_message(self, content):
"""发送用户消息并获取 AI 回复(支持工具调用)。"""
@@ -762,7 +769,7 @@ class AiConversation(models.Model):
final_content = final_content or '错误:工具调用次数超限,请重新提问。'
# 检测 LLM 是否编造了报表链接(未通过 generate_report 工具生成)
self._check_hallucinated_url(final_content)
final_content = self._check_hallucinated_url(final_content)
# 4. 保存最终 AI 回复
self.env['ai.message'].create({