# Phase F.4:AI 集成 日期:2026-04-04 状态:待开始 依赖:F.3(待完成) 前置:services/forum_ai_service.py --- ## 1. 本阶段目的 为 Jarvis Forum 集成 AI 能力: - AI 自动回复 - 帖子摘要生成 - 智能分类打标 - Agent 自主发帖 --- ## 2. Forum AI Service ### 2.1 服务架构 ``` ┌─────────────────────────────────────────────────────────────┐ │ ForumAIService │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │ │ AutoReply │ │ Summary │ │ SmartTagging │ │ │ │ Service │ │ Service │ │ Service │ │ │ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │ │ │ │ │ │ │ └────────────────┼───────────────────┘ │ │ │ │ │ ┌───────────┴───────────┐ │ │ │ LLM Service │ │ │ │ (复用 Agent LLM) │ │ │ └───────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ### 2.2 核心服务 ```python class ForumAIService: """论坛 AI 服务""" def __init__( self, llm_service: LLMService, config: ForumAIConfig, ): self.llm = llm_service self.config = config # === 自动回复 === async def generate_auto_reply( self, post: ForumPost, replies: List[ForumReply], ) -> Optional[str]: """生成自动回复""" if not self.config.auto_reply_enabled: return None # 检查是否需要回复 if not self._should_auto_reply(post): return None # 构建上下文 context = self._build_reply_context(post, replies) # 生成回复 prompt = self._build_reply_prompt(context) response = await self.llm.agenerate(prompt) return response.content if response else None def _should_auto_reply(self, post: ForumPost) -> bool: """判断是否应该自动回复""" # 指令类帖子不自动回复 if post.category == "instruction": return False # 有 AI 回复的不重复回复 if any(r.is_ai_reply for r in post.replies): return False # 检查时间窗口 if post.last_reply_at: hours_since = (datetime.utcnow() - post.last_reply_at).total_seconds() / 3600 if hours_since < self.config.auto_reply_min_hours: return False return True def _build_reply_context( self, post: ForumPost, replies: List[ForumReply], ) -> str: """构建回复上下文""" context = f"""## 帖子信息 标题: {post.title} 内容: {post.content[:500]}... ## 回复列表 """ for reply in replies[-5:]: # 最近 5 条 context += f"- {reply.user_id}: {reply.content[:200]}...\n" return context def _build_reply_prompt(self, context: str) -> str: """构建回复提示词""" return f"""你是一个友好的社区助手。请根据以下帖子内容,生成一条有帮助的回复。 {context} 要求: 1. 回复要友好、专业、有帮助 2. 不要重复已有的观点 3. 如果是问题,尽量给出建设性的建议 4. 回复长度控制在 100-300 字 5. 不要使用 Markdown 格式,直接输出文本 回复:""" # === 摘要生成 === async def generate_summary( self, content: str, max_length: int = 200, ) -> str: """生成帖子摘要""" if len(content) <= max_length: return content prompt = f"""请为以下内容生成一个简洁的摘要,不超过 {max_length} 字。 内容: {content} 摘要:""" response = await self.llm.agenerate(prompt) return response.content if response else content[:max_length] # === 智能打标 === async def suggest_tags( self, title: str, content: str, existing_tags: List[str], ) -> List[str]: """智能推荐标签""" prompt = f"""请根据以下帖子内容,推荐 3-5 个最合适的标签。 标题: {title} 内容: {content[:1000]}... 已有标签: {', '.join(existing_tags) if existing_tags else '无'} 要求: 1. 标签要简洁,2-4 个字 2. 选择最相关的标签 3. 如果已有标签合适可以保留 4. 只输出标签,用逗号分隔,不要其他内容 标签:""" response = await self.llm.agenerate(prompt) if not response: return existing_tags # 解析标签 tags = [t.strip() for t in response.content.split(",")] return tags[:5] # 最多 5 个 # === 智能分类 === async def classify_category( self, title: str, content: str, ) -> str: """智能分类""" categories = ["instruction", "discussion", "question", "praise", "bug", "other"] prompt = f"""请为以下帖子选择一个最合适的分类。 标题: {title} 内容: {content[:500]}... 可选分类: - instruction: 指令/任务请求 - discussion: 讨论/分享 - question: 问题/求助 - praise: 表扬/感谢 - bug: Bug 反馈 - other: 其他 请直接输出分类名称,不要其他内容。 分类:""" response = await self.llm.agenerate(prompt) if not response: return "other" category = response.content.strip().lower() if category not in categories: return "other" return category ``` --- ## 3. Summary Service ### 3.1 服务实现 ```python class SummaryService: """帖子摘要服务""" def __init__(self, cache: ForumCache): self.cache = cache async def get_post_summary( self, post_id: str, post: ForumPost, ) -> str: """获取帖子摘要(带缓存)""" cache_key = f"summary:{post_id}" # 尝试从缓存获取 cached = await self.cache.get(cache_key) if cached: return cached # 生成摘要 summary = await self._generate_summary(post) # 存入缓存(1 小时) await self.cache.set(cache_key, summary, ttl=3600) return summary async def get_thread_summary( self, post: ForumPost, replies: List[ForumReply], ) -> str: """获取帖子串摘要(主帖+回复摘要)""" summaries = [await self.get_post_summary(post.id, post)] # 汇总回复要点 if len(replies) > 0: summary_prompt = f"""请总结以下回复的核心观点,用 50 字以内概括。 回复列表: {self._format_replies(replies[:10])} 总结:""" response = await self.llm.agenerate(summary_prompt) if response: summaries.append(f"回复要点: {response.content}") return "\n\n".join(summaries) async def invalidate_summary(self, post_id: str) -> None: """清除摘要缓存""" await self.cache.invalidate(f"summary:{post_id}") ``` --- ## 4. Agent 自主发帖 ### 4.1 Agent Forum 工具 ```python # agents/tools/forum_tools.py from typing import List, Optional class ForumTools: """Forum Agent 工具集""" def __init__(self, forum_service: ForumService, ai_service: ForumAIService): self.forum = forum_service self.ai = ai_service @tool async def create_forum_post( title: str, content: str, board_id: Optional[str] = None, category: Optional[str] = None, tags: Optional[List[str]] = None, ) -> dict: """创建论坛帖子 参数: - title: 帖子标题 - content: 帖子内容 - board_id: 板块 ID(可选) - category: 分类(可选) - tags: 标签列表(可选) """ data = ForumPostCreate( title=title, content=content, board_id=board_id, category=category, tags=tags or [], ) post = await self.forum.create_post(agent_id=AGENT_ID, data=data) return {"post_id": post.id, "title": post.title} @tool async def reply_to_post( post_id: str, content: str, ) -> dict: """回复帖子 参数: - post_id: 帖子 ID - content: 回复内容 """ data = ForumReplyCreate(content=content) reply = await self.forum.create_reply( post_id=post_id, agent_id=AGENT_ID, data=data, ) return {"reply_id": reply.id, "floor": reply.floor} @tool async def search_forum_posts( query: str, board_id: Optional[str] = None, category: Optional[str] = None, limit: int = 10, ) -> List[dict]: """搜索论坛帖子 参数: - query: 搜索关键词 - board_id: 限定板块(可选) - category: 限定分类(可选) - limit: 返回数量(默认 10) """ posts = await self.forum.search_posts( query=query, board_id=board_id, category=category, limit=limit, ) return [ {"id": p.id, "title": p.title, "summary": p.content[:100]} for p in posts ] @tool async def get_forum_trending( board_id: Optional[str] = None, limit: int = 5, ) -> List[dict]: """获取热门帖子 参数: - board_id: 板块 ID(可选) - limit: 返回数量(默认 5) """ posts = await self.forum.get_trending( board_id=board_id, limit=limit, ) return [ { "id": p.id, "title": p.title, "reply_count": p.reply_count, "view_count": p.view_count, } for p in posts ] ``` ### 4.2 Agent 配置 ```python # agents/prompts/forum_agent.py FORUM_AGENT_PROMPT = """你是一个活跃的社区成员,可以帮助用户解决问题和参与讨论。 ## 你的能力 1. 在论坛发帖分享信息或见解 2. 回复其他用户的帖子 3. 搜索论坛内容 4. 查看热门帖子 ## 行为规则 1. 只在有帮助时才发帖/回复,不要刷屏 2. 回复要专业、有建设性 3. 如果用户的问题已经解决,不要重复回答 4. 遇到 Bug 或问题可以主动发帖提醒 5. 定期查看论坛,如果有重要帖子可以参与讨论 ## 当前时间 {current_time} ## 用户信息 用户名: {username} 积分: {forum_score} """ # Agent 可用的 Forum 工具 FORUM_TOOLS = [ create_forum_post, reply_to_post, search_forum_posts, get_forum_trending, ] ``` --- ## 5. 定时任务 ### 5.1 自动回复任务 ```python # tasks/forum_auto_reply.py from apscheduler.schedulers.asyncio import AsyncIOScheduler async def auto_reply_task(): """自动回复任务""" # 获取需要回复的帖子 posts = await forum_service.get_pending_posts( min_age_hours=settings.auto_reply_min_hours, limit=10, ) for post in posts: replies = await forum_service.get_replies(post.id) # 生成回复 response = await ai_service.generate_auto_reply(post, replies) if response: # 发布回复 await forum_service.create_reply( post_id=post.id, agent_id=AGENT_ID, data=ForumReplyCreate(content=response), ) # 更新回复计数 await forum_service.increment_reply_count(post.id) def setup_forum_scheduler(scheduler: AsyncIOScheduler): """配置论坛定时任务""" # 每小时检查一次自动回复 scheduler.add_job( auto_reply_task, "interval", hours=1, id="forum_auto_reply", ) ``` --- ## 6. 配置项 ### 6.1 AI 配置 ```python class ForumAIConfig: """Forum AI 配置""" # 自动回复 auto_reply_enabled: bool = True auto_reply_min_hours: int = 24 # 帖子发布 N 小时后才自动回复 auto_reply_max_per_day: int = 10 # 每天最多自动回复 N 条 # 摘要生成 summary_enabled: bool = True summary_max_length: int = 200 summary_cache_ttl: int = 3600 # 缓存 1 小时 # 智能打标 smart_tagging_enabled: bool = True smart_tagging_max_tags: int = 5 # 智能分类 smart_classification_enabled: bool = True # settings.py class Settings(BaseSettings): # Forum AI forum_ai_auto_reply: bool = True forum_ai_summary: bool = True forum_ai_smart_tagging: bool = True ``` --- ## 7. API 端点 ### 7.1 AI 相关端点 ```python @router.post("/posts/{post_id}/generate-summary") async def generate_post_summary( post_id: str, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """生成帖子摘要""" result = await db.execute( select(ForumPost).where(ForumPost.id == post_id) ) post = result.scalar_one_or_none() if not post: raise HTTPException(status_code=404, detail="帖子不存在") ai_service = ForumAIService(llm_service, config) summary = await ai_service.generate_summary(post.content) return {"summary": summary} @router.post("/posts/suggest-tags") async def suggest_post_tags( title: str, content: str, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """推荐帖子标签""" ai_service = ForumAIService(llm_service, config) tags = await ai_service.suggest_tags(title, content, []) return {"tags": tags} @router.post("/posts/classify") async def classify_post( title: str, content: str, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """分类帖子""" ai_service = ForumAIService(llm_service, config) category = await ai_service.classify_category(title, content) return {"category": category} @router.get("/posts/{post_id}/ai-status") async def get_ai_status( post_id: str, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """获取帖子 AI 状态""" result = await db.execute( select(ForumPost).where(ForumPost.id == post_id) ) post = result.scalar_one_or_none() if not post: raise HTTPException(status_code=404, detail="帖子不存在") # 检查 AI 回复状态 has_ai_reply = any(r.is_ai_reply for r in post.replies) summary_cached = await cache.get(f"summary:{post_id}") return { "has_ai_reply": has_ai_reply, "summary_available": bool(summary_cached), } ``` --- ## 8. 实现步骤 | 步骤 | 任务 | 优先级 | |------|------|--------| | 1 | 创建 ForumAIService | 🟢 高 | | 2 | 实现自动回复 | 🟢 高 | | 3 | 实现摘要生成 | 🟡 中 | | 4 | 实现智能打标 | 🟡 中 | | 5 | 实现智能分类 | 🟡 中 | | 6 | 创建 ForumTools | 🟢 高 | | 7 | 配置定时任务 | 🟡 中 | | 8 | 扩展 API 端点 | 🟡 中 | | 9 | 单元测试 | 🟡 中 | --- ## 9. 核心文件变更 | 文件 | 变更 | |------|------| | `services/forum_ai_service.py` | 新增 | | `services/summary_service.py` | 新增 | | `agents/tools/forum_tools.py` | 新增 | | `agents/prompts/forum_agent.py` | 新增 | | `tasks/forum_auto_reply.py` | 新增 | | `routers/forum.py` | 扩展 AI 端点 | --- ## 10. 工作量估算 | 任务 | 工作量 | |------|--------| | ForumAIService | 1 天 | | 自动回复 | 1 天 | | 摘要/打标/分类 | 1 天 | | ForumTools | 1 天 | | 定时任务 | 0.5 天 | | API 端点 | 0.5 天 | | 单元测试 | 0.5 天 | | **总计** | **5.5 天** | --- ## 11. 验收标准 - [ ] ForumAIService 可正常调用 LLM - [ ] 自动回复功能正常工作 - [ ] 摘要生成功能正常 - [ ] 智能打标推荐准确 - [ ] 智能分类推荐准确 - [ ] ForumTools 可被 Agent 调用 - [ ] 定时任务正常执行 - [ ] API 端点正常工作 - [ ] 单元测试覆盖核心逻辑