1.2 AI搜索系统的基本架构 本章系统介绍AI搜索系统的核心架构组件,从数据层到应用层的完整技术栈,帮助开发者构建高质量的搜索系统。 1.2.1 AI搜索系统的分层架构 系统架构概览 AI搜索系统采用分层架构设计,每一层都有明确的职责和技术特点: 各层技术细节 应用层 (Application Layer) 核心组件: 搜索前端界面:用户交互界面,支持多种输入方式 API服务接口:为其他应用提供搜索能力 分析后台:系统监控、性能分析、用户行为分析 业务层 (Business Layer) 核心组件: 查询分析器:分析用户查询意图,优化搜索策略 结果排序器:综合考虑多种因素对结果进行排序 用户画像:构建用户兴趣模型,提供个性化结果 服务层 (Service Layer) 核心组件:
本章系统介绍AI搜索系统的核心架构组件,从数据层到应用层的完整技术栈,帮助开发者构建高质量的搜索系统。
AI搜索系统采用分层架构设计,每一层都有明确的职责和技术特点:
┌─────────────────────────────────────────┐ │ 应用层 (Application Layer) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ │ │ │ 搜索前端界面 │ │ API服务接口 │ │ 分析后台 │ │ │ └─────────────┘ └─────────────┘ └─────────┘ │ ├─────────────────────────────────────────┤ │ 业务层 (Business Layer) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ │ │ │ 查询分析器 │ │ 结果排序器 │ │ 用户画像 │ │ │ └─────────────┘ └─────────────┘ └─────────┘ │ ├─────────────────────────────────────────┤ │ 服务层 (Service Layer) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ │ │ │ 语义理解服务 │ │ 向量检索服务 │ │ 排序服务 │ │ │ └─────────────┘ └─────────────┘ └─────────┘ │ ├─────────────────────────────────────────┤ │ 数据层 (Data Layer) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ │ │ │ 向量数据库 │ │ 元数据索引 │ │ 用户数据 │ │ │ └─────────────┘ └─────────────┘ └─────────┘ │ └─────────────────────────────────────────┘
核心组件:
核心组件:
核心组件:
核心组件:
| 特性 | FAISS | Milvus | Pinecone | Chroma | Weaviate |
|---|---|---|---|---|---|
| 开发者 | Zilliz | Pinecone | Chroma | Weaviate | |
| 开源状态 | ✅ 开源 | ✅ 开源 | ❌ 商业 | ✅ 开源 | ✅ 开源 |
| 性能 | 极高 | 极高 | 高 | 中等 | 高 |
| 易用性 | 中等 | 中等 | 极高 | 极高 | 高 |
| 多语言支持 | Python/C++ | Python/Go/Java | Python | Python | Python/GraphQL |
| 索引类型 | HNSW/IVF | HNSW/IVF/HNSW | HNSW | HNSW | HNSW |
技术特点:
import faiss import numpy as np # 创建FAISS索引 def create_faiss_index(dimension=768, index_type='HNSW'): """创建FAISS索引""" if index_type == 'HNSW': # HNSW索引 index = faiss.IndexHNSWFlat(dimension, 32) # M=32 index.hnsw.ef = 200 # ef搜索参数 elif index_type == 'IVF': # IVF索引 nlist = 100 # 聚类数量 quantizer = faiss.IndexFlatL2(dimension) index = faiss.IndexIVFFlat(quantizer, dimension, nlist) elif index_type == 'PQ': # PQ(Product Quantization)索引 nlist = 100 m = 8 # 子空间数量 quantizer = faiss.IndexFlatL2(dimension) index = faiss.IndexIVFPQ(quantizer, dimension, nlist, m, 8) else: raise ValueError(f"不支持的索引类型: {index_type}") return index # 使用FAISS进行搜索 def faiss_search_example(): """FAISS搜索示例""" dimension = 768 n_vectors = 10000 top_k = 10 # 创建模拟数据 vectors = np.random.random((n_vectors, dimension)).astype('float32') # 创建索引 index = create_faiss_index(dimension, 'HNSW') index.train(vectors) index.add(vectors) # 搜索查询向量 query_vector = np.random.random((1, dimension)).astype('float32') distances, indices = index.search(query_vector, top_k) print(f"搜索结果: {indices[0]}") print(f"距离: {distances[0]}")
| 模型 | 参数量 | 上下文长度 | 语言支持 | 主要特点 |
|---|---|---|---|---|
| BERT-base | 110M | 512 | 多语言 | 双向编码,通用性强 |
| BERT-large | 340M | 512 | 多语言 | 性能更强,计算成本高 |
| RoBERTa-base | 125M | 512 | 英文 | 优化的BERT,性能更好 |
| DistilBERT | 66M | 512 | 多语言 | 轻量级,速度快 |
| ALBERT-base | 12M | 512 | 多语言 | 参数共享,高效 |
技术特点:
from transformers import BertTokenizer, BertModel import torch import numpy as np # 加载BERT模型 def load_bert_model(model_name='bert-base-chinese'): """加载BERT模型""" tokenizer = BertTokenizer.from_pretrained(model_name) model = BertModel.from_pretrained(model_name) return tokenizer, model # 文本向量化 def text_to_vector(text, tokenizer, model): """将文本转换为向量""" # 分词 inputs = tokenizer(text, return_tensors='pt', truncation=True, max_length=512) # 获取BERT输出 with torch.no_grad(): outputs = model(**inputs) # 使用[CLS]标记的向量作为句子表示 sentence_vector = outputs.last_hidden_state[:, 0, :].squeeze() return sentence_vector.numpy() # 计算语义相似度 def semantic_similarity(text1, text2, tokenizer, model): """计算两个文本的语义相似度""" vector1 = text_to_vector(text1, tokenizer, model) vector2 = text_to_vector(text2, tokenizer, model) # 计算余弦相似度 cosine_sim = np.dot(vector1, vector2) / (np.linalg.norm(vector1) * np.linalg.norm(vector2)) return cosine_sim
预处理步骤:
import re import jieba class QueryPreprocessor: def __init__(self): self.stop_words = self.load_stop_words() self.synonym_dict = self.load_synonym_dict() def preprocess_query(self, query): """预处理查询""" # 1. 文本清洗 cleaned = self.clean_text(query) # 2. 分词 tokens = self.tokenize(cleaned) # 3. 去除停用词 filtered_tokens = self.remove_stop_words(tokens) # 4. 查询扩展 expanded_queries = self.expand_query(filtered_tokens) return { 'original': query, 'cleaned': cleaned, 'tokens': filtered_tokens, 'expanded': expanded_queries } def clean_text(self, text): """文本清洗""" # 去除HTML标签 text = re.sub(r'<[^>]+>', '', text) # 去除特殊字符,保留中文、英文、数字 text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\s]', '', text) # 去除多余空格 text = re.sub(r'\s+', ' ', text).strip() return text def tokenize(self, text): """分词""" # 中文分词 chinese_tokens = list(jieba.cut(text)) # 英文分词 english_tokens = re.findall(r'\b[a-zA-Z]+\b', text) return chinese_tokens + english_tokens def remove_stop_words(self, tokens): """去除停用词""" return [token for token in tokens if token not in self.stop_words]
基于查询场景的索引选择:
增量更新:
批量更新:
缓存层次:
import redis import pickle class MultiLevelCache: def __init__(self): # Redis缓存 self.redis_client = redis.Redis(host='localhost', port=6379, db=0) # 本地缓存 self.local_cache = {} # 缓存配置 self.cache_config = { 'query_result_ttl': 3600, # 1小时 'vector_cache_ttl': 1800, # 30分钟 'metadata_ttl': 7200 # 2小时 } def get(self, key, cache_level='redis'): """获取缓存""" if cache_level == 'local': return self.get_local_cache(key) elif cache_level == 'redis': return self.get_redis_cache(key) else: return self.get_multi_level_cache(key) def set(self, key, value, cache_level='redis', ttl=None): """设置缓存""" if cache_level == 'local': self.set_local_cache(key, value) elif cache_level == 'redis': self.set_redis_cache(key, value, ttl) else: self.set_multi_level_cache(key, value, ttl) def cache_query_result(self, query, result): """缓存查询结果""" key = f"query:{hash(query)}" self.set(key, result, 'redis', self.cache_config['query_result_ttl']) def get_cached_query_result(self, query): """获取缓存的查询结果""" key = f"query:{hash(query)}" return self.get(key, 'redis')
查询性能指标:
系统资源指标:
业务指标:
import time import threading import psutil from prometheus_client import Counter, Histogram, Gauge class SystemMonitor: def __init__(self): # Prometheus指标定义 self.request_counter = Counter('search_requests_total', 'Total search requests') self.response_time_histogram = Histogram('search_response_time_seconds', 'Search response time') self.error_counter = Counter('search_errors_total', 'Total search errors') self.cpu_usage = Gauge('system_cpu_usage_percent', 'CPU usage percentage') self.memory_usage = Gauge('system_memory_usage_percent', 'Memory usage percentage') # 内部计数器 self.stats = { 'total_requests': 0, 'successful_requests': 0, 'failed_requests': 0, 'total_response_time': 0, 'average_response_time': 0 } # 启动系统资源监控 self.start_resource_monitoring() def record_request(self, response_time, success=True): """记录请求统计""" self.request_counter.inc() self.response_time_histogram.observe(response_time) self.stats['total_requests'] += 1 self.stats['total_response_time'] += response_time self.stats['average_response_time'] = self.stats['total_response_time'] / self.stats['total_requests'] if success: self.stats['successful_requests'] += 1 else: self.error_counter.inc() self.stats['failed_requests'] += 1 def start_resource_monitoring(self): """启动系统资源监控""" def monitor_resources(): while True: try: # CPU使用率 cpu_percent = psutil.cpu_percent() self.cpu_usage.set(cpu_percent) # 内存使用率 memory = psutil.virtual_memory() self.memory_usage.set(memory.percent) time.sleep(60) # 每分钟监控一次 except Exception as e: print(f"资源监控错误: {e}") time.sleep(60) # 启动监控线程 monitor_thread = threading.Thread(target=monitor_resources, daemon=True) monitor_thread.start()
日志策略:
错误追踪:
import logging import json from datetime import datetime class SearchLogger: def __init__(self): self.logger = logging.getLogger('search_engine') self.logger.setLevel(logging.INFO) # 创建文件处理器 file_handler = logging.FileHandler('search.log') file_handler.setLevel(logging.INFO) # 创建控制台处理器 console_handler = logging.StreamHandler() console_handler.setLevel(logging.INFO) # 创建格式化器 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) # 添加处理器 self.logger.addHandler(file_handler) self.logger.addHandler(console_handler) def log_request(self, request_id, query, user_id=None): """记录请求日志""" log_data = { 'event': 'request', 'request_id': request_id, 'query': query, 'user_id': user_id, 'timestamp': datetime.now().isoformat() } self.logger.info(json.dumps(log_data)) def log_response(self, request_id, response_time, success=True, error=None): """记录响应日志""" log_data = { 'event': 'response', 'request_id': request_id, 'response_time': response_time, 'success': success, 'error': error, 'timestamp': datetime.now().isoformat() } if success: self.logger.info(json.dumps(log_data)) else: self.logger.error(json.dumps(log_data)) def log_error(self, request_id, error_type, error_message, stack_trace=None): """记录错误日志""" log_data = { 'event': 'error', 'request_id': request_id, 'error_type': error_type, 'error_message': error_message, 'stack_trace': stack_trace, 'timestamp': datetime.now().isoformat() } self.logger.error(json.dumps(log_data))
┌─────────────────────────────────────────┐ │ 用户层 (Client Layer) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ │ │ │ Web前端 │ │ 移动端APP │ │ 小程序 │ │ │ └─────────────┘ └─────────────┘ └─────────┘ │ ├─────────────────────────────────────────┤ │ 网关层 (Gateway Layer) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ │ │ │ API网关 │ │ 负载均衡 │ │ 限流 │ │ │ └─────────────┘ └─────────────┘ └─────────┘ │ ├─────────────────────────────────────────┤ │ 业务层 (Business Layer) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ │ │ │ 搜索服务 │ │ 排序服务 │ │ 推荐服务 │ │ │ └─────────────┘ └─────────────┘ └─────────┘ │ ├─────────────────────────────────────────┤ │ 数据层 (Data Layer) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ │ │ │ 商品向量库 │ │ 用户向量库 │ │ 热点缓存 │ │ │ └─────────────┘ └─────────────┘ └─────────┘ │ ├─────────────────────────────────────────┤ │ 存储层 (Storage Layer) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────┐ │ │ │ MySQL主库 │ │ Redis缓存 │ │ CDN │ │ │ └─────────────┘ └─────────────┘ └─────────┘ │ └─────────────────────────────────────────┘
通过本章的学习,我们全面了解了AI搜索系统的架构设计,包括分层架构、核心组件选型、性能优化策略和实际应用案例。下一章我们将深入探讨向量表示技术,这是AI搜索的技术核心。