themblem/doc/ai-chat.md
2025-10-29 21:27:29 +00:00

970 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
<!-- web/src/views/ai-config.vue -->
<template>
<div class="ai-config">
<CCard>
<CCardHeader>
<h4>AI聊天配置</h4>
</CCardHeader>
<CCardBody>
<CForm>
<CFormGroup label="AI模型提供商">
<CSelect v-model="config.model_provider">
<option value="kimi">Kimi K2</option>
<option value="zhipu">智谱AI</option>
<option value="baidu">百度文心一言</option>
</CSelect>
</CFormGroup>
<CFormGroup label="API密钥">
<CInput v-model="config.api_key" type="password" />
</CFormGroup>
<CFormGroup label="模型名称">
<CInput v-model="config.model_name" />
</CFormGroup>
<CFormGroup label="温度">
<CInput v-model="config.temperature" type="number" step="0.1" min="0" max="2" />
</CFormGroup>
<CFormGroup label="最大Token数">
<CInput v-model="config.max_tokens" type="number" />
</CFormGroup>
<CButton color="primary" @click="saveConfig">保存配置</CButton>
</CForm>
</CCardBody>
</CCard>
<CCard class="mt-4">
<CCardHeader>
<h4>品牌知识库</h4>
<CButton color="success" @click="showAddKnowledge">添加知识</CButton>
</CCardHeader>
<CCardBody>
<CTable :items="knowledgeList" :fields="knowledgeFields">
<template #actions="{ item }">
<CButton color="danger" size="sm" @click="deleteKnowledge(item.id)">删除</CButton>
</template>
</CTable>
</CCardBody>
</CCard>
</div>
</template>
```
### 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 <Text>{content}</Text>;
case 'image':
return <Image src={content} mode="widthFix" />;
case 'video':
return <Video src={content} />;
case 'link':
return <Link href={content.url} text={content.text} />;
case 'rich_text':
return <RichText content={content} />;
default:
return <Text>{content}</Text>;
}
}
```
### 5.3 会话管理
#### 5.3.1 会话状态
- 会话创建和销毁
- 消息历史记录
- 上下文保持
- 会话超时处理
#### 5.3.2 用户身份识别
- 微信OpenID绑定
- 匿名会话支持
- 用户偏好记录
### 5.4 智能调度系统(简化版)
#### 5.4.1 能力处理器架构
- 基础能力处理器注册机制
- 简单的能力降级策略
- 固定路由规则
#### 5.4.2 调度策略
- 基于关键词的能力选择
- 基础异常处理和回退
- 简单性能监控
- 后续版本支持高级功能
### 5.5 上下文长度管理
#### 5.5.1 当前问题
- **无限累积**:对话历史无限制增长
- **Token超限**可能超出API的token限制
- **内存占用**:长时间对话占用大量内存
- **API失败**超长历史可能导致API调用失败
#### 5.5.2 优化策略
```python
class AIChatService:
def __init__(self, api_key: str = None, base_url: str = None):
# ... 现有代码 ...
self.max_history_length = 20 # 最大历史记录数
self.max_tokens_per_message = 1000 # 每条消息最大token数
def _truncate_history(self):
"""截断对话历史,保持上下文长度"""
if len(self.conversation_history) > self.max_history_length:
# 保留系统提示词和最近的对话
system_message = self.conversation_history[0] # 系统提示词
recent_messages = self.conversation_history[-self.max_history_length+1:]
self.conversation_history = [system_message] + recent_messages
def _estimate_tokens(self, text: str) -> int:
"""估算文本的token数量简化版"""
# 中文约1.5字符=1token英文约4字符=1token
chinese_chars = len([c for c in text if '\u4e00' <= c <= '\u9fff'])
english_chars = len(text) - chinese_chars
return int(chinese_chars / 1.5 + english_chars / 4)
def _smart_truncate(self):
"""智能截断基于token数量而非消息数量"""
total_tokens = sum(self._estimate_tokens(msg['content']) for msg in self.conversation_history)
max_total_tokens = 4000 # 预留1000token给AI回复
if total_tokens > max_total_tokens:
# 保留系统提示词和最近的对话直到token数合适
system_message = self.conversation_history[0]
truncated_history = [system_message]
for msg in reversed(self.conversation_history[1:]):
truncated_history.insert(1, msg)
current_tokens = sum(self._estimate_tokens(m['content']) for m in truncated_history)
if current_tokens > max_total_tokens:
truncated_history.pop(1) # 移除刚添加的消息
break
self.conversation_history = truncated_history
```
#### 5.5.3 分层历史策略
```python
def _build_context_aware_history(self, user_message: str) -> List[Dict]:
"""构建上下文感知的对话历史"""
# 策略1保留最近的N轮对话
recent_messages = self.conversation_history[-10:] # 最近10轮
# 策略2保留关键信息如工具调用结果
important_messages = [msg for msg in self.conversation_history
if msg.get('role') == 'tool' or '重要' in msg.get('content', '')]
# 策略3动态调整根据用户问题复杂度决定保留多少历史
if '刚才' in user_message or '之前' in user_message:
# 用户引用之前内容,保留更多历史
context_messages = self.conversation_history[-15:]
else:
# 新话题,保留较少历史
context_messages = self.conversation_history[-5:]
return [self.conversation_history[0]] + context_messages # 系统提示词 + 上下文
```
#### 5.5.4 错误处理和降级
```python
def chat(self, user_message: str) -> str:
try:
# 智能截断历史
self._smart_truncate()
# 调用API
response = self.client.chat.completions.create(
model=self.model,
messages=self.conversation_history,
tools=self.tools,
tool_choice="auto",
temperature=0.7,
max_tokens=2000
)
# ... 处理响应 ...
except Exception as e:
if "context_length_exceeded" in str(e) or "token_limit" in str(e):
# Token超限截断历史重试
self._truncate_history()
return self.chat(user_message) # 递归重试
else:
return f"AI服务调用失败: {str(e)}"
```
## 7. 安全考虑
### 7.1 数据安全
- API密钥加密存储
- 用户隐私保护
- 内容审核机制
- 访问权限控制
### 7.2 系统安全
- 请求频率限制
- 异常监控告警
## 9. 项目计划
### 9.1 开发阶段
1. **第一阶段 (1周)**: 核心架构和基础功能 ✅ **已完成**
- 数据模型扩展(最小化)
- Kimi K2 API基础集成 ✅
- 基础AI聊天功能 ✅
- 工具调用系统 ✅
- Django管理命令 ✅
2. **第二阶段 (1周)**: AI能力扩展
- 知识库检索工具集成
- 平台知识库(简化版)
- 工具调用优化和扩展
3. **第三阶段 (1周)**: 小程序集成和内容管理
- 小程序AI聊天界面核心功能
- 小程序与AI服务的集成
- 内容管理基础功能
4. **第四阶段 (1周)**: 集成测试和部署
- 功能测试和bug修复
- 性能优化
- 生产环境部署
### 9.2 里程碑
- Week 1: 完成核心架构和基础AI聊天功能 ✅ **已完成**
- Week 2: 完成知识库检索工具和RAG系统基础功能
- Week 3: 完成小程序AI聊天集成和内容管理
- Week 4: 完成测试、优化和上线
### 10.3 Backup
- 多AI服务商备选方案
### 11.2 开发周期
- **总周期**: 4周压缩版
- **核心功能**: AI聊天、RAG知识检索、工具调用、小程序集成、基础内容管理
- **技术栈**: Django + Kimi K2 + LangChain知识库管理+ 微信小程序 + 基础向量存储
- **开发策略**: MVP优先核心功能先行小程序集成优先后续迭代优化
### 11.3 架构设计总结
**核心架构选择直接以Tool形式接入Kimi K2**
1. **简化设计**:避免复杂的能力调度和路由逻辑
2. **原生支持**充分利用Kimi K2的Function Calling能力
3. **易于维护**:代码结构清晰,逻辑简单
4. **扩展性好**:后续可以轻松添加更多工具
**RAG实现方式**
- 知识库检索作为工具提供给Kimi K2
- AI根据用户问题自动选择是否使用知识库
- 基于检索结果生成高质量回答
- 无需手动路由完全依赖AI智能判断
**技术优势**
- 减少系统复杂度
- 降低维护成本
- 提高系统稳定性
- 保持架构简洁性