# 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/ai_service.py class AIService: def __init__(self, tenant_id, model_config): self.tenant_id = tenant_id self.model_config = model_config self.client = self._init_client() def chat(self, message, context, tenant_context): # 构建prompt prompt = self._build_prompt(message, context, tenant_context) # 调用Kimi K2 API response = self._call_kimi_api(prompt) # 后处理 return self._post_process(response) def _call_kimi_api(self, prompt): # 调用Kimi K2 API,支持联网搜索和多模态处理 pass def _build_prompt(self, message, context, tenant_context): # 包含品牌信息、产品知识、用户上下文 pass ``` #### 4.1.3 智能能力调度系统(简化版) - **能力分类**: RAG知识检索、平台服务、一般问答 - **优先级策略**: 平台服务 > RAG知识 > 一般问答 - **智能路由**: 基于规则的快速路由策略 - **降级机制**: 简单的能力降级和回退 - **后续扩展**: 工具执行、网络搜索等高级功能 #### 4.1.4 RAG框架集成(简化版) - **框架选择**: LangChain基础功能 - **文档处理**: 基础分块、简单向量化、相似度检索 - **上下文优化**: 基础分层策略(摘要、完整) - **检索策略**: 向量相似度检索,关键词匹配作为备选 ### 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主题色彩") ``` ### 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 平台知识库管理(简化版) - 平台介绍内容(4000字)的基础分块 - 分层内容策略:摘要、完整两个层次 - 基于关键词的简单内容选择 - 基础内容压缩,避免信息过载 #### 4.5.4 智能内容处理(简化版) - 基于LangChain的文档基础预处理 - 简单分块策略:按段落和句子分割 - 基础内容压缩:摘要和完整内容 - 固定上下文长度,简化Token管理 ## 5. 技术实现细节 ### 5.1 AI Prompt工程 #### 5.1.1 系统Prompt模板 ``` 你是一个专业的品牌客服助手,专门为{品牌名称}提供产品咨询和服务。 品牌信息: {品牌背景介绍} 产品知识: {产品相关信息} 服务原则: 1. 只回答与{品牌名称}相关的问题 2. 不评价竞品,不与竞品对比 3. 优先使用官方信息回答 4. 对于不确定的信息,明确告知用户 5. 保持专业、友好的服务态度 用户上下文: {用户验证的产品信息、历史对话等} 请根据以上信息,为用户提供准确、有用的回答。 ``` #### 5.1.2 平台客服Prompt模板 ``` 你是一个专业的徵象防伪验证平台客服助手。 平台介绍: 徵象是由广州市诚投科技有限公司开发的AI驱动的智能防伪平台,通过多模态特征识别构建新一代防伪验证体系,实现从物理防伪到数字认证的全链路保护。系统采用ISO 12931国际防伪标准,已获取国家发明专利(证书编号:CN 115222000 B)。 服务范围: 1. 商品防伪验证 2. 证件安全验证 3. 工业品防伪 4. 品牌数字化服务 服务原则: 1. 专业、友好、准确回答用户问题 2. 优先使用官方信息回答 3. 对于不确定的信息,明确告知用户 4. 引导用户使用相关功能和服务 请根据用户问题提供准确、有用的回答。 ``` #### 5.1.2 动态Prompt构建 ```python def build_dynamic_prompt(self, message, context, tenant_context): # 获取品牌知识 knowledge = self._get_relevant_knowledge(message, tenant_context) # 获取产品信息 product_info = self._get_product_info(context.get('serial_code')) # 构建完整prompt prompt = self._get_system_prompt(tenant_context) prompt += f"\n\n相关产品信息:{product_info}" prompt += f"\n\n品牌知识:{knowledge}" prompt += f"\n\n用户问题:{message}" return prompt ``` #### 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