feat: 优化 FAQ 处理和系统稳定性

- 添加本地 FAQ 库快速路径(问候语等社交响应)
- 修复 Chatwoot 重启循环问题(PID 文件清理)
- 添加 LLM 响应缓存(Redis 缓存,提升性能)
- 添加智能推理模式(根据查询复杂度自动启用)
- 添加订单卡片消息功能(Chatwoot 富媒体)
- 增加 LLM 超时时间至 60 秒

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
wangliang
2026-01-20 14:51:30 +08:00
parent c4e97cf312
commit 6b6172d8f0
8 changed files with 684 additions and 18 deletions

121
agent/utils/faq_library.py Normal file
View File

@@ -0,0 +1,121 @@
"""
Local FAQ Library for instant responses
Common questions can be answered immediately without API calls
"""
import re
from typing import Optional, Dict
from .logger import get_logger
logger = get_logger(__name__)
class FAQLibrary:
"""Local FAQ library for instant common question responses"""
def __init__(self):
"""Initialize FAQ library with ONLY common greetings and social responses
Note: Business-related FAQs (register, order, payment, shipment, return, etc.)
should be handled by Strapi MCP to ensure accuracy and consistency.
This library only contains instant social responses for better UX.
"""
self.faqs = {
# ========== 问候类 Greetings ==========
"你好": "你好我是您的B2B客户服务助手很高兴为您服务。我可以帮您处理订单查询、产品咨询、售后问题等。请问有什么可以帮到您的吗",
"您好": "您好我是您的B2B客户服务助手很高兴为您服务。我可以帮您处理订单查询、产品咨询、售后问题等。请问有什么可以帮到您的吗",
"hi": "Hello! I'm your B2B customer service assistant. How can I help you today?",
"hello": "Hello! I'm here to assist you. How can I help you today?",
"hey": "Hey there! How can I help you today?",
# ========== 感谢类 Gratitude ==========
"谢谢": "不客气!如果还有其他问题,随时可以问我。祝您购物愉快!",
"感谢": "感谢您的支持!如有任何问题,随时联系我们。",
"thank you": "You're welcome! If you have any other questions, feel free to ask. Have a great day!",
"thanks": "You're welcome! Let me know if you need anything else.",
# ========== 再见类 Farewell ==========
"再见": "再见!如有需要,随时联系。祝您生活愉快!",
"bye": "Goodbye! Feel free to reach out anytime. Have a great day!",
"goodbye": "Goodbye! Have a wonderful day!",
# ========== 社交礼貌类 Social Politeness ==========
"早上好": "早上好!很高兴为您服务。请问有什么可以帮到您的吗?",
"下午好": "下午好!很高兴为您服务。请问有什么可以帮到您的吗?",
"晚上好": "晚上好!很高兴为您服务。请问有什么可以帮到您的吗?",
"good morning": "Good morning! How can I assist you today?",
"good afternoon": "Good afternoon! How can I assist you today?",
"good evening": "Good evening! How can I assist you today?",
}
# Compile regex patterns for fuzzy matching
self._compile_patterns()
def _compile_patterns(self):
"""Compile regex patterns for fuzzy FAQ matching"""
self.patterns = []
for keyword, response in self.faqs.items():
# Case-insensitive pattern with word boundaries
pattern = re.compile(re.escape(keyword), re.IGNORECASE)
self.patterns.append((pattern, response))
def find_match(self, query: str) -> Optional[str]:
"""Find matching FAQ response
Args:
query: User query text
Returns:
Matching FAQ response or None if no match found
"""
# Remove HTML tags and extra whitespace
clean_query = re.sub(r'<[^>]+>', '', query)
clean_query = ' '.join(clean_query.split())
# Try exact match first
if clean_query.lower() in (k.lower() for k in self.faqs.keys()):
for key, response in self.faqs.items():
if key.lower() == clean_query.lower():
logger.info("FAQ exact match", key=key, query=clean_query[:50])
return response
# Try fuzzy match (contains keyword)
for pattern, response in self.patterns:
if pattern.search(clean_query):
logger.info("FAQ fuzzy match", pattern=pattern.pattern, query=clean_query[:50])
return response
# No match found
logger.debug("No FAQ match found", query=clean_query[:50])
return None
def add_faq(self, keyword: str, response: str) -> None:
"""Add or update FAQ entry
Args:
keyword: Question keyword
response: Answer text
"""
self.faqs[keyword] = response
pattern = re.compile(re.escape(keyword), re.IGNORECASE)
self.patterns.append((pattern, response))
logger.info("FAQ added", keyword=keyword)
def get_all_keywords(self) -> list[str]:
"""Get all FAQ keywords
Returns:
List of FAQ keywords
"""
return list(self.faqs.keys())
# Global FAQ library instance
faq_library: Optional[FAQLibrary] = None
def get_faq_library() -> FAQLibrary:
"""Get or create global FAQ library instance"""
global faq_library
if faq_library is None:
faq_library = FAQLibrary()
return faq_library