# AI聊天功能技术实现计划 ## 1. 项目概述 基于现有徵象防伪验证系统,扩展AI客服聊天功能,继承Kimi K2大模型能力,为每个品牌租户提供个性化的AI客服服务。 ## 2. 需求分析 ### 2.1 核心功能需求 - 接入Kimi K2或其他AI大模型API - 品牌专属AI客服,独立回答本品牌产品相关问题 - 多模态回答:文字、图片、视频链接、微信小程序码等 - 联网搜索,以品牌官方信息为主 - 支持客户上传额外内容供AI学习 - 验证失败时提供对话式结果展示 - 支持品牌色调定制 ### 2.2 技术约束 - 保留原有传统查询页面 - 通过序列码批次管理选择使用页面类型 - 与现有防伪验证流程集成 ## 3. 系统架构设计 ### 3.1 整体架构 ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 小程序前端 │ │ Web管理端 │ │ AI服务层 │ │ (AI聊天界面) │◄──►│ (内容管理) │◄──►│ (Kimi K2 API) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 验证服务 │ │ 内容存储 │ │ 知识库管理 │ │ (二维码识别) │ │ (OSS/数据库) │ │ (品牌知识) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ### 3.2 数据流设计 1. 用户扫描二维码 → 验证服务 2. 验证结果 → AI聊天界面 3. 用户提问 → AI服务层处理 4. AI回答 → 返回多模态内容 5. 用户反馈 → 知识库更新 ## 4. 技术实现方案 ### 4.1 AI模型集成 #### 4.1.1 模型选择 - **主要模型**: Kimi K2 API ✅ **已实现** - **备选模型**: 智谱AI (ChatGLM)、百度文心一言 - **理由**: Kimi K2在中文理解、多模态处理和联网搜索方面表现优秀,API稳定可靠,特别适合品牌客服场景 #### 4.1.2 API集成架构 ✅ **已实现** ```python # api/products/aichat.py class AIChatService: def __init__(self, api_key: str = None, base_url: str = None): self.api_key = api_key or getattr(settings, 'KIMI_API_KEY', None) self.base_url = base_url or getattr(settings, 'KIMI_API_URL', None) self.client = OpenAI(api_key=self.api_key, base_url=self.base_url) def chat(self, user_message: str) -> str: # 调用Moonshot API,支持工具调用 response = self.client.chat.completions.create( model=self.model, messages=self.conversation_history, tools=self.tools, tool_choice="auto" ) return self._process_response(response) ``` #### 4.1.3 工具调用系统 ✅ **已实现** - **工具定义**: `start_qr_scan` 二维码扫描工具 - **工具执行**: 模拟5秒扫描过程,返回验证结果 - **工具集成**: 完整的工具调用流程,支持多轮对话 #### 4.1.4 智能能力调度系统 - **架构选择**: 直接以Tool形式接入Kimi K2,无需复杂路由 - **能力分类**: 知识库检索工具、二维码扫描工具、一般问答 - **调度策略**: 依赖Kimi K2的智能判断,自动选择合适的工具 - **优势**: 实现简单、维护成本低、Kimi K2原生支持 - **扩展性**: 后续可轻松添加更多工具,无需修改路由逻辑 #### 4.1.5 本地知识库系统 - **存储方案**: 向量数据库 + 文件存储 - **内容类型**: 文字、图片、视频、文档 - **检索策略**: 语义搜索 + 关键词匹配 - **更新机制**: 支持实时更新和版本控制 - **成本优化**: 本地处理,减少API调用 #### 4.1.6 RAG架构设计 ```python class AIChatService: def __init__(self): self.client = OpenAI(api_key=KIMI_API_KEY, base_url=KIMI_API_URL) self.knowledge_base = LocalKnowledgeBase() # 本地知识库 self.tools = self._define_tools() def chat(self, message: str) -> str: # 步骤1:从本地知识库检索相关信息 relevant_docs = self.knowledge_base.search(message, k=3) # 步骤2:构建增强的上下文 enhanced_context = self._build_enhanced_context(message, relevant_docs) # 步骤3:使用Kimi K2生成回答(基于检索到的信息) response = self.client.chat.completions.create( model=self.model, messages=[ {"role": "system", "content": self.system_prompt + enhanced_context}, {"role": "user", "content": message} ], tools=self.tools, tool_choice="auto" ) # 步骤4:处理工具调用(如果需要) if response.choices[0].message.tool_calls: # 执行工具调用逻辑... pass # 步骤5:将问答对保存到知识库(可选) self.knowledge_base.add_qa_pair(message, response.choices[0].message.content) return response.choices[0].message.content def _build_enhanced_context(self, query: str, docs: List[Document]) -> str: """构建增强的上下文信息""" if not docs: return "" context = "\n\n相关参考信息:\n" for i, doc in enumerate(docs, 1): context += f"{i}. {doc.page_content}\n" context += f"\n请基于以上信息回答用户问题:{query}" return context ``` **RAG流程**: - **检索(Retrieval)**:从本地知识库找到相关信息 - **增强(Augmentation)**:将检索到的信息作为上下文 - **生成(Generation)**:Kimi K2基于增强的上下文生成回答 #### 4.1.7 本地知识库实现 ```python class LocalKnowledgeBase: def __init__(self): # 使用轻量级向量数据库 self.vector_store = Chroma( embedding_function=OpenAIEmbeddings(api_key=KIMI_API_KEY), persist_directory="./knowledge_base" ) self.file_storage = FileStorage() # 文件存储 def search(self, query: str, k: int = 3, threshold: float = 0.5) -> List[Document]: """搜索本地知识库,返回相关文档列表""" # 语义搜索 results = self.vector_store.similarity_search_with_score(query, k=k) # 过滤低置信度结果,但保留更多候选 filtered_results = [r for r in results if r[1] > threshold] # 转换为Document对象列表 documents = [] for doc, score in filtered_results: documents.append(Document( page_content=doc.page_content, metadata={ **doc.metadata, 'similarity_score': score } )) return documents def add_content(self, content: str, content_type: str, metadata: dict): """添加内容到知识库""" # 文本内容直接向量化 if content_type == 'text': self.vector_store.add_texts([content], [metadata]) # 图片内容使用OCR提取文本 elif content_type == 'image': text = self._extract_text_from_image(content) self.vector_store.add_texts([text], [metadata]) # 视频内容提取关键帧和音频 elif content_type == 'video': frames = self._extract_key_frames(content) audio_text = self._extract_audio_text(content) self.vector_store.add_texts([audio_text], [metadata]) def add_qa_pair(self, question: str, answer: str): """添加问答对到知识库""" qa_text = f"问题:{question}\n答案:{answer}" metadata = { 'type': 'qa_pair', 'question': question, 'answer': answer, 'created_at': datetime.now().isoformat() } self.vector_store.add_texts([qa_text], [metadata]) ``` **技术特点**: - **轻量级**:使用Chroma向量数据库,无需复杂部署 - **多模态**:支持文字、图片、视频内容 - **实时更新**:支持动态添加和更新内容 - **成本优化**:本地处理,减少API调用 #### 4.1.8 完整RAG实现示例 ```python from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import Chroma from langchain.document_loaders import TextLoader, ImageLoader, VideoLoader class RAGService: def __init__(self): self.embeddings = OpenAIEmbeddings(api_key=KIMI_API_KEY) self.text_splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200 ) self.vector_store = Chroma( embedding_function=self.embeddings, persist_directory="./knowledge_base" ) def add_document(self, file_path: str, content_type: str): """添加文档到知识库""" if content_type == 'text': loader = TextLoader(file_path) elif content_type == 'image': loader = ImageLoader(file_path) elif content_type == 'video': loader = VideoLoader(file_path) else: raise ValueError(f"不支持的内容类型: {content_type}") documents = loader.load() # 分块处理 chunks = self.text_splitter.split_documents(documents) # 添加到向量数据库 self.vector_store.add_documents(chunks) def retrieve_context(self, query: str, k: int = 3) -> str: """检索相关上下文""" docs = self.vector_store.similarity_search(query, k=k) context = "\n\n".join([doc.page_content for doc in docs]) return context def generate_answer(self, query: str, context: str) -> str: """使用Kimi K2生成回答""" enhanced_prompt = f""" 基于以下参考信息回答用户问题: 参考信息: {context} 用户问题:{query} 请基于参考信息提供准确、详细的回答。如果参考信息不足以回答问题,请明确说明。 """ response = self.client.chat.completions.create( model="kimi-k2-0711-preview", messages=[ {"role": "system", "content": "你是徵象防伪验证平台的AI助手,请基于提供的参考信息回答问题。"}, {"role": "user", "content": enhanced_prompt} ], temperature=0.7, max_tokens=2000 ) return response.choices[0].message.content # 使用示例 rag_service = RAGService() # 添加文档 rag_service.add_document("产品说明.txt", "text") rag_service.add_document("防伪标识.jpg", "image") rag_service.add_document("操作演示.mp4", "video") # 问答流程 query = "如何验证产品真伪?" context = rag_service.retrieve_context(query) answer = rag_service.generate_answer(query, context) ``` **RAG优势**: - **信息可控**:检索到的信息来自平台知识库 - **回答质量**:Kimi K2基于准确信息生成高质量回答 - **成本优化**:避免重复的API调用,知识库一次构建多次使用 - **专业性强**:平台专业知识 + AI生成能力 #### 4.1.9 架构选择说明 **为什么选择直接以Tool形式接入Kimi K2?** 1. **符合Kimi K2设计理念** - Kimi K2本身就是为工具调用设计的 - 原生支持Function Calling,无需额外路由层 - AI能根据上下文智能选择合适的工具 2. **实现简单,维护成本低** - 代码逻辑清晰,易于理解和维护 - 避免复杂的if-else路由规则 - 减少系统复杂度,降低出错概率 3. **足够灵活,扩展性好** - 可以轻松添加新的工具 - 工具优先级通过描述和系统提示词控制 - 支持复杂的工具组合调用 4. **性能优势** - 减少额外的路由判断逻辑 - 直接利用Kimi K2的智能判断能力 - 避免不必要的中间层处理 **具体实现方式**: ```python def _define_tools(self): return [ { "type": "function", "function": { "name": "search_knowledge_base", "description": "搜索徵象平台知识库,获取产品信息、防伪验证方法、技术文档等相关内容。当用户询问平台相关问题时,优先使用此工具。", "parameters": { "type": "object", "properties": { "query": { "type": "string", "description": "搜索查询,支持中文关键词" }, "content_type": { "type": "string", "enum": ["all", "text", "image", "video"], "description": "内容类型过滤" } }, "required": ["query"] } } }, { "type": "function", "function": { "name": "start_qr_scan", "description": "启动二维码扫描功能,用于产品防伪验证。当用户需要验证产品真伪时使用。", "parameters": { "type": "object", "properties": {}, "required": [] } } } ] ``` **系统提示词优化**: ```python system_prompt = """你是一个专业的徵象防伪验证平台AI客服助手。 使用策略: 1. 当用户询问平台相关问题时,优先使用search_knowledge_base工具搜索知识库 2. 当用户需要验证产品真伪时,使用start_qr_scan工具启动扫描 3. 基于检索到的信息,结合你的知识,提供准确、详细的回答 4. 如果知识库信息不足,可以结合你的通用知识回答,但要明确说明信息来源 工具优先级:知识库搜索 > 二维码扫描 > 一般问答 """ ``` ### 4.2 数据模型扩展 #### 4.2.1 新增数据表 ```python # api/products/models.py class AIConfig(models.Model): """AI配置表""" tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE) model_provider = models.CharField(max_length=50, default='kimi') api_key = models.CharField(max_length=255) model_name = models.CharField(max_length=100, default='kimi-k2') class BrandKnowledge(models.Model): """品牌知识库""" tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE) title = models.CharField(max_length=200) content = models.TextField() content_type = models.CharField(max_length=20) # text, image, video, link file_url = models.URLField(null=True, blank=True) priority = models.IntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) class PlatformKnowledge(models.Model): """平台知识库""" title = models.CharField(max_length=200) content = models.TextField() content_type = models.CharField(max_length=20, choices=[ ('platform_intro', '平台介绍'), ('service_guide', '服务指南'), ('faq', '常见问题') ]) ai_summary = models.TextField(null=True, blank=True, verbose_name="AI摘要版本") ai_segments = models.JSONField(default=dict, verbose_name="AI分段内容") ai_keywords = models.JSONField(default=list, verbose_name="AI关键词") is_platform_content = models.BooleanField(default=True) ai_priority = models.IntegerField(default=0) created_at = models.DateTimeField(auto_now_add=True) class ChatSession(models.Model): """聊天会话""" session_id = models.CharField(max_length=100, unique=True) tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE) user_openid = models.CharField(max_length=100, null=True) created_at = models.DateTimeField(auto_now_add=True) last_active = models.DateTimeField(auto_now=True) class ChatMessage(models.Model): """聊天消息""" session = models.ForeignKey(ChatSession, on_delete=models.CASCADE) role = models.CharField(max_length=20) # user, assistant, system content = models.TextField() content_type = models.CharField(max_length=20, default='text') metadata = models.JSONField(default=dict) created_at = models.DateTimeField(auto_now_add=True) ``` #### 4.2.2 现有模型扩展 ```python # 扩展CodeBatch模型 class CodeBatch(models.Model): # ... 现有字段 ... enable_ai_chat = models.BooleanField(default=False, verbose_name="启用AI聊天") ai_chat_config = models.JSONField(null=True, blank=True, verbose_name="AI聊天配置") # 扩展Tenant模型 class Tenant(models.Model): # ... 现有字段 ... ai_brand_name = models.CharField(max_length=100, null=True, blank=True, verbose_name="AI品牌名称") ai_welcome_message = models.TextField(null=True, blank=True, verbose_name="AI欢迎语") ai_theme_colors = models.JSONField(null=True, blank=True, verbose_name="AI主题色彩") # TODO: 在MiniProgramContent模型中添加enable_ai_chat字段 # class MiniProgramContent(models.Model): # # ... 现有字段 ... # enable_ai_chat = models.BooleanField(default=False, verbose_name="启用AI客服") ``` ### 4.3 后端API设计 #### 4.3.1 AI聊天API ```python # api/products/views.py class AIChatView(BaseView): name = 'ai-chat' auth_check = 'tenant' def post(self, request): """发送消息给AI""" session_id = request.data.get('session_id') message = request.data.get('message') context = request.data.get('context', {}) # 获取或创建会话 session = self._get_or_create_session(session_id, request.tenant) # 调用AI服务 ai_service = AIService(request.tenant.id) response = ai_service.chat(message, context, self._get_tenant_context(request.tenant)) # 保存消息记录 self._save_message(session, 'user', message) self._save_message(session, 'assistant', response) return JsonResponse({ 'session_id': session.session_id, 'response': response }) def get(self, request): """获取聊天历史""" session_id = request.GET.get('session_id') if not session_id: return http400("session_id required") session = ChatSession.objects.filter( session_id=session_id, tenant=request.tenant ).first() if not session: return http404("Session not found") messages = ChatMessage.objects.filter(session=session).order_by('created_at') return JsonResponse({ 'messages': [self._serialize_message(m) for m in messages] }) class BrandKnowledgeView(BaseView): name = 'brand-knowledge' auth_check = 'tenant' def post(self, request): """上传品牌知识""" title = request.data.get('title') content = request.data.get('content') content_type = request.data.get('content_type', 'text') file_url = request.data.get('file_url') knowledge = BrandKnowledge.objects.create( tenant=request.tenant, title=title, content=content, content_type=content_type, file_url=file_url ) return JsonResponse({'id': knowledge.id}) ``` #### 4.3.2 配置管理API ```python class AIConfigView(BaseView): name = 'ai-config' auth_check = 'tenant' def get(self, request): """获取AI配置""" config = AIConfig.objects.filter(tenant=request.tenant).first() if not config: config = AIConfig.objects.create(tenant=request.tenant) return JsonResponse({ 'model_provider': config.model_provider, 'model_name': config.model_name, 'temperature': config.temperature, 'max_tokens': config.max_tokens, 'is_active': config.is_active }) def patch(self, request): """更新AI配置""" config = AIConfig.objects.filter(tenant=request.tenant).first() if not config: config = AIConfig.objects.create(tenant=request.tenant) for field in ['model_provider', 'model_name', 'temperature', 'max_tokens', 'is_active']: if field in request.data: setattr(config, field, request.data[field]) config.save() return JsonResponse({'status': 'success'}) ``` ### 4.4 前端界面设计 #### 4.4.1 小程序AI聊天界面 ```javascript // scanner/pages/chat/chat.js Page({ data: { messages: [], inputValue: '', sessionId: null, tenant: null, loading: false }, onLoad(options) { this.initChat(options); }, async initChat(options) { // 获取租户信息 const tenant = await this.getTenantInfo(options.tenant); this.setData({ tenant }); // 创建或获取会话 const sessionId = await this.createChatSession(tenant.id); this.setData({ sessionId }); // 显示欢迎消息 this.showWelcomeMessage(tenant); // 如果有验证结果,显示相关产品信息 if (options.serial_code) { await this.showProductInfo(options.serial_code); } }, async sendMessage() { if (!this.data.inputValue.trim()) return; const message = this.data.inputValue; this.addMessage('user', message); this.setData({ inputValue: '', loading: true }); try { const response = await this.callAIChat(message); this.addMessage('assistant', response); } catch (error) { this.addMessage('system', '抱歉,AI服务暂时不可用,请稍后再试。'); } finally { this.setData({ loading: false }); } }, async callAIChat(message) { const response = await wx.request({ url: `${this.data.tenant.server_url}/api/v1/ai-chat/`, method: 'POST', data: { session_id: this.data.sessionId, message: message, context: this.getContext() }, header: { 'Authorization': `token ${this.data.tenant.token}` } }); return response.data.response; } }); ``` #### 4.4.2 Web管理端界面 ```vue ``` ### 4.5 内容管理系统 #### 4.5.1 知识库管理 - 支持文本、图片、视频、链接等多种内容类型 - 内容优先级设置 - 内容分类标签 - 版本控制 #### 4.5.2 品牌定制 - 品牌色调配置 - 欢迎语定制 - 头像和图标上传 - 回答风格调整 #### 4.5.3 首页AI客服开关 - TODO: 在MiniProgramContent中添加enable_ai_chat字段 - 后台管理:简单的on/off开关 - 小程序端:判断bool值,如果为true则跳转到chat页面 - 实现方式:几行代码即可完成 #### 4.5.3 平台知识库管理(简化版) - 平台介绍内容(4000字)的基础分块 - 分层内容策略:摘要、完整两个层次 - 基于关键词的简单内容选择 - 基础内容压缩,避免信息过载 #### 4.5.4 智能内容处理(简化版) - 基于LangChain的文档基础预处理 - 简单分块策略:按段落和句子分割 - 基础内容压缩:摘要和完整内容 - 固定上下文长度,简化Token管理 ## 5. 技术实现细节 #### 5.1.3 智能能力路由(简化版) ```python def route_capability(self, query, context): # 基于规则的快速路由 capability = self._rule_based_routing(query) # 根据能力类型构建相应的Prompt if capability == "rag_knowledge": return self._build_rag_prompt(query, context) elif capability == "platform_service": return self._build_platform_prompt(query, context) else: return self._build_general_prompt(query, context) ``` ### 5.2 多模态内容处理 #### 5.2.1 内容类型支持 - **文本**: 直接返回 - **图片**: 上传到OSS,返回URL - **视频**: 支持微信视频号链接 - **链接**: 小程序码、商城链接等 - **富文本**: Markdown格式支持 #### 5.2.2 内容渲染 ```javascript // 内容渲染组件 function renderContent(content, type) { switch (type) { case 'text': return {content}; case 'image': return ; case 'video': return