# AI集成模块学习 - server/ai/ai_manager.py
## 📋 模块概述
`server/ai/ai_manager.py` 实现了Chat-Room项目的AI智能助手功能,集成了智谱AI GLM-4-Flash模型,提供智能对话、上下文管理、自动回复等功能。这是现代聊天应用的重要特性。
## 🎯 AI集成架构设计
### 系统组件架构
```mermaid
graph TD
A[AIManager
AI管理器] --> B[ZhipuClient
智谱客户端]
A --> C[ContextManager
上下文管理器]
A --> D[MessageProcessor
消息处理器]
B --> B1[API调用]
B --> B2[连接管理]
B --> B3[错误处理]
B --> B4[模型配置]
C --> C1[对话上下文]
C --> C2[上下文清理]
C --> C3[上下文限制]
C --> C4[分组管理]
D --> D1[触发检测]
D --> D2[消息清理]
D --> D3[回复生成]
D --> D4[内容过滤]
subgraph "外部服务"
E[智谱AI API
GLM-4-Flash]
end
B --> E
```
### 核心类设计
```python
class AIManager:
"""AI管理器 - 统一的AI服务入口"""
def __init__(self, api_key: str = None):
"""
初始化AI管理器
Args:
api_key: 智谱AI API密钥
"""
self.zhipu_client = None
self.context_manager = ContextManager()
self.enabled = False
self.logger = get_logger("server.ai.ai_manager")
# 尝试初始化智谱客户端
try:
self.zhipu_client = ZhipuClient(api_key)
if self.zhipu_client.test_connection():
self.enabled = True
self.logger.info("✅ AI功能已启用")
else:
self.logger.warning("❌ AI连接测试失败,AI功能已禁用")
except Exception as e:
self.logger.error(f"❌ AI初始化失败: {e}")
self.logger.info("💡 请设置正确的API密钥启用AI功能")
# 启动定期清理任务
if self.enabled:
self._start_cleanup_task()
```
**设计特点**:
- **容错设计**:AI服务不可用时不影响其他功能
- **自动检测**:启动时自动测试API连接
- **资源管理**:自动清理过期的上下文数据
- **日志完善**:详细的状态和错误日志
## 🤖 智谱AI客户端
### API客户端设计
```python
class ZhipuClient:
"""智谱AI客户端"""
def __init__(self, api_key: str):
"""
初始化智谱客户端
Args:
api_key: API密钥
"""
self.api_key = api_key
self.base_url = "https://open.bigmodel.cn/api/paas/v4/"
self.model = "glm-4-flash"
self.max_tokens = 1024
self.temperature = 0.7
self.top_p = 0.9
# 初始化HTTP客户端
self.client = ZhipuAI(api_key=api_key)
self.logger = get_logger("server.ai.zhipu_client")
def test_connection(self) -> bool:
"""测试API连接"""
try:
# 发送简单的测试请求
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": "Hello"}],
max_tokens=10
)
if response and response.choices:
self.logger.info("API连接测试成功")
return True
else:
self.logger.warning("API连接测试失败:无响应")
return False
except Exception as e:
self.logger.error(f"API连接测试失败: {e}")
return False
```
### 聊天完成API调用
```python
def chat_completion(self, messages: List[Dict], system_prompt: str = None) -> str:
"""
调用聊天完成API
Args:
messages: 对话消息列表
system_prompt: 系统提示词
Returns:
AI回复内容
"""
try:
# 构建请求消息
request_messages = []
# 添加系统提示词
if system_prompt:
request_messages.append({
"role": "system",
"content": system_prompt
})
# 添加对话消息
request_messages.extend(messages)
# 记录请求开始时间
start_time = time.time()
# 调用API
response = self.client.chat.completions.create(
model=self.model,
messages=request_messages,
max_tokens=self.max_tokens,
temperature=self.temperature,
top_p=self.top_p,
stream=False # 不使用流式响应
)
# 计算响应时间
response_time = time.time() - start_time
# 提取回复内容
if response and response.choices and len(response.choices) > 0:
reply_content = response.choices[0].message.content
# 记录成功日志
self.logger.info(f"AI回复生成成功,耗时: {response_time:.2f}s")
# 记录token使用情况
if hasattr(response, 'usage'):
usage = response.usage
self.logger.debug(f"Token使用: 输入={usage.prompt_tokens}, "
f"输出={usage.completion_tokens}, "
f"总计={usage.total_tokens}")
return reply_content.strip()
else:
self.logger.warning("API返回空响应")
return None
except Exception as e:
self.logger.error(f"AI API调用失败: {e}")
return None
def get_model_info(self) -> Dict:
"""获取模型信息"""
return {
"model": self.model,
"max_tokens": self.max_tokens,
"temperature": self.temperature,
"top_p": self.top_p,
"api_key_status": "已配置" if self.api_key else "未配置"
}
```
## 🧠 上下文管理系统
### 上下文管理器设计
```python
class ContextManager:
"""AI对话上下文管理器"""
def __init__(self):
"""初始化上下文管理器"""
# 上下文存储 {context_id: [messages]}
self.contexts: Dict[str, List[Dict]] = {}
# 上下文元数据 {context_id: metadata}
self.context_metadata: Dict[str, Dict] = {}
# 配置参数
self.max_context_length = 10 # 最大上下文长度
self.context_timeout = 3600 # 上下文超时时间(秒)
# 线程锁
self._lock = threading.RLock()
# 系统提示词
self.system_prompts = {
"group": """你是Chat-Room聊天室的AI助手。你的任务是:
1. 友好、有帮助地回答用户问题
2. 保持对话自然流畅
3. 在群聊中,注意上下文中的多个用户
4. 回复要简洁明了,避免过长的回答
5. 如果不确定答案,诚实地说不知道""",
"private": """你是Chat-Room聊天室的AI助手。在私聊中:
1. 提供更详细和个性化的回答
2. 可以进行深入的对话
3. 记住用户的偏好和之前的对话内容
4. 保持友好和专业的态度
5. 主动提供有用的建议和信息"""
}
```
### 上下文操作方法
```python
def add_message(self, context_id: str, role: str, content: str,
is_group_chat: bool = True):
"""
添加消息到上下文
Args:
context_id: 上下文ID(群聊用group_id,私聊用user_id)
role: 消息角色(user/assistant)
content: 消息内容
is_group_chat: 是否为群聊
"""
with self._lock:
# 初始化上下文
if context_id not in self.contexts:
self.contexts[context_id] = []
self.context_metadata[context_id] = {
"created_at": time.time(),
"last_updated": time.time(),
"is_group_chat": is_group_chat,
"message_count": 0
}
# 添加消息
message = {
"role": role,
"content": content,
"timestamp": time.time()
}
self.contexts[context_id].append(message)
# 更新元数据
metadata = self.context_metadata[context_id]
metadata["last_updated"] = time.time()
metadata["message_count"] += 1
# 限制上下文长度
if len(self.contexts[context_id]) > self.max_context_length:
# 保留最新的消息,但保留第一条系统消息(如果有)
messages = self.contexts[context_id]
if messages[0].get("role") == "system":
self.contexts[context_id] = [messages[0]] + messages[-(self.max_context_length-1):]
else:
self.contexts[context_id] = messages[-self.max_context_length:]
def get_context(self, context_id: str, is_group_chat: bool = True) -> List[Dict]:
"""
获取对话上下文
Args:
context_id: 上下文ID
is_group_chat: 是否为群聊
Returns:
上下文消息列表
"""
with self._lock:
if context_id not in self.contexts:
return []
# 检查上下文是否过期
metadata = self.context_metadata[context_id]
if time.time() - metadata["last_updated"] > self.context_timeout:
self.clear_context(context_id)
return []
# 返回上下文消息(不包含时间戳)
messages = []
for msg in self.contexts[context_id]:
messages.append({
"role": msg["role"],
"content": msg["content"]
})
return messages
def clear_context(self, context_id: str):
"""清除指定的上下文"""
with self._lock:
self.contexts.pop(context_id, None)
self.context_metadata.pop(context_id, None)
def get_system_prompt(self, context_type: str) -> str:
"""获取系统提示词"""
return self.system_prompts.get(context_type, self.system_prompts["group"])
```
### 上下文清理机制
```python
def cleanup_expired_contexts(self):
"""清理过期的上下文"""
current_time = time.time()
expired_contexts = []
with self._lock:
for context_id, metadata in self.context_metadata.items():
if current_time - metadata["last_updated"] > self.context_timeout:
expired_contexts.append(context_id)
# 清理过期上下文
for context_id in expired_contexts:
self.clear_context(context_id)
if expired_contexts:
logger.info(f"清理了 {len(expired_contexts)} 个过期的AI上下文")
def get_context_summary(self) -> Dict:
"""获取上下文统计摘要"""
with self._lock:
total_contexts = len(self.contexts)
group_contexts = sum(1 for meta in self.context_metadata.values()
if meta.get("is_group_chat", True))
private_contexts = total_contexts - group_contexts
total_messages = sum(meta.get("message_count", 0)
for meta in self.context_metadata.values())
return {
"total_contexts": total_contexts,
"group_contexts": group_contexts,
"private_contexts": private_contexts,
"total_messages": total_messages,
"max_context_length": self.max_context_length,
"context_timeout": self.context_timeout
}
```
## 🎯 消息处理和触发机制
### 消息触发检测
```python
def should_respond_to_message(self, message_content: str,
is_group_chat: bool = True) -> bool:
"""
判断是否应该回复消息
Args:
message_content: 消息内容
is_group_chat: 是否为群聊
Returns:
是否应该回复
"""
if not self.is_enabled():
return False
# 私聊中总是回复
if not is_group_chat:
return True
# 群聊中的触发条件
message_lower = message_content.lower()
# 1. 检查@AI标记
if f"@{AI_USERNAME.lower()}" in message_lower or "@ai" in message_lower:
return True
# 2. 检查AI相关关键词
ai_keywords = ["ai", "人工智能", "助手", "机器人", "智能", "问答"]
for keyword in ai_keywords:
if keyword in message_lower:
return True
# 3. 检查问号结尾的问题
if message_content.strip().endswith(("?", "?")):
return True
# 4. 检查特定的求助词汇
help_keywords = ["帮助", "help", "怎么", "如何", "为什么", "什么是"]
for keyword in help_keywords:
if keyword in message_lower:
return True
return False
def _clean_message(self, message_content: str) -> str:
"""
清理消息内容,移除@AI标记等
Args:
message_content: 原始消息内容
Returns:
清理后的消息内容
"""
import re
# 移除@AI标记
cleaned = re.sub(r'@ai\b|@AI\b|@智能助手\b', '', message_content, flags=re.IGNORECASE)
# 移除多余的空格
cleaned = re.sub(r'\s+', ' ', cleaned).strip()
return cleaned
```
### 主要消息处理方法
```python
def process_message(self, user_id: int, username: str, message_content: str,
chat_group_id: int = None) -> Optional[str]:
"""
处理用户消息并生成AI回复
Args:
user_id: 用户ID
username: 用户名
message_content: 消息内容
chat_group_id: 聊天组ID,None表示私聊
Returns:
AI回复内容,None表示不回复
"""
if not self.is_enabled():
return None
is_group_chat = chat_group_id is not None
# 判断是否应该回复
if not self.should_respond_to_message(message_content, is_group_chat):
return None
try:
# 清理消息内容
cleaned_message = self._clean_message(message_content)
# 获取上下文ID
context_id = str(chat_group_id) if is_group_chat else str(user_id)
# 添加用户消息到上下文
self.context_manager.add_message(
context_id, "user", f"{username}: {cleaned_message}", is_group_chat
)
# 获取对话上下文
context_messages = self.context_manager.get_context(context_id, is_group_chat)
# 获取系统提示词
context_type = "group" if is_group_chat else "private"
system_prompt = self.context_manager.get_system_prompt(context_type)
# 调用AI生成回复
ai_reply = self.zhipu_client.chat_completion(context_messages, system_prompt)
if ai_reply:
# 添加AI回复到上下文
self.context_manager.add_message(
context_id, "assistant", ai_reply, is_group_chat
)
return ai_reply
else:
return "抱歉,我现在无法回复您的消息。"
except Exception as e:
self.logger.error(f"处理AI消息时发生错误: {e}")
return "抱歉,处理您的消息时出现了问题。"
```
## 🛠️ AI命令处理
### AI专用命令
```python
def handle_ai_command(self, command: str, user_id: int,
chat_group_id: int = None) -> str:
"""
处理AI相关命令
Args:
command: 命令内容
user_id: 用户ID
chat_group_id: 聊天组ID
Returns:
命令执行结果
"""
try:
command_parts = command.strip().split()
if not command_parts:
return "请提供有效的AI命令"
cmd = command_parts[0].lower()
if cmd == "status":
return self._handle_status_command()
elif cmd == "clear":
return self._handle_clear_command(user_id, chat_group_id)
elif cmd == "help":
return self._handle_help_command()
elif cmd == "stats":
return self._handle_stats_command()
else:
return f"未知的AI命令: {cmd}。输入 'ai help' 查看可用命令。"
except Exception as e:
self.logger.error(f"处理AI命令时发生错误: {e}")
return "命令执行失败"
def _handle_status_command(self) -> str:
"""处理状态查询命令"""
if not self.enabled:
return "❌ AI功能未启用"
status_info = self.get_ai_status()
status_text = "🤖 AI助手状态:\n"
status_text += f"• 服务状态: {'✅ 正常' if status_info['enabled'] else '❌ 异常'}\n"
status_text += f"• API连接: {'✅ 正常' if status_info['api_connected'] else '❌ 异常'}\n"
status_text += f"• 模型: {status_info['model_info'].get('model', 'Unknown')}\n"
context_summary = status_info.get('context_summary', {})
status_text += f"• 活跃对话: {context_summary.get('total_contexts', 0)}\n"
return status_text
def _handle_clear_command(self, user_id: int, chat_group_id: int = None) -> str:
"""处理清除上下文命令"""
context_id = str(chat_group_id) if chat_group_id else str(user_id)
self.context_manager.clear_context(context_id)
return "✅ AI对话上下文已清除"
def _handle_help_command(self) -> str:
"""处理帮助命令"""
help_text = """🤖 AI助手帮助:
可用命令:
• ai status - 查看AI服务状态
• ai clear - 清除当前对话上下文
• ai help - 显示此帮助信息
• ai stats - 查看AI使用统计
触发方式:
• @AI 或 @ai - 在群聊中@AI
• 包含AI相关关键词
• 以问号结尾的问题
• 私聊中直接对话"""
return help_text
```
## 📊 监控和统计
### AI状态监控
```python
def get_ai_status(self) -> Dict[str, Any]:
"""
获取AI状态信息
Returns:
AI状态字典
"""
status = {
"enabled": self.enabled,
"api_connected": False,
"model_info": {},
"context_summary": {}
}
if self.zhipu_client:
status["api_connected"] = self.zhipu_client.test_connection()
status["model_info"] = self.zhipu_client.get_model_info()
if self.context_manager:
status["context_summary"] = self.context_manager.get_context_summary()
return status
def _start_cleanup_task(self):
"""启动定期清理任务"""
def cleanup_worker():
while self.enabled:
try:
time.sleep(3600) # 每小时清理一次
self.context_manager.cleanup_expired_contexts()
except Exception as e:
self.logger.error(f"AI上下文清理错误: {e}")
cleanup_thread = threading.Thread(target=cleanup_worker, daemon=True)
cleanup_thread.start()
self.logger.info("AI上下文清理任务已启动")
```
## 💡 学习要点
### AI集成设计
1. **容错机制**:AI服务不可用时不影响其他功能
2. **上下文管理**:维护对话连贯性
3. **触发机制**:智能判断何时回复
4. **性能优化**:合理控制API调用频率
### API集成最佳实践
1. **错误处理**:完善的API错误处理
2. **超时控制**:避免长时间等待
3. **重试机制**:网络异常时的重试策略
4. **监控日志**:详细的API调用日志
### 上下文管理策略
1. **内存控制**:限制上下文长度和数量
2. **过期清理**:定期清理过期上下文
3. **分组管理**:群聊和私聊分别管理
4. **持久化**:重要上下文的持久化存储
## 🤔 思考题
1. **如何优化AI响应速度?**
- 异步处理
- 响应缓存
- 模型优化
2. **如何控制AI使用成本?**
- 请求频率限制
- 上下文长度控制
- 智能触发机制
3. **如何提高AI回复质量?**
- 优化提示词
- 上下文丰富化
- 用户反馈机制
---
**下一步**:学习客户端核心模块 → [../04-client-modules/](../04-client-modules/)