仓库:MuZiCul/GPT(原创)· 语言:Python (Flask) · 定位:基于 SentenceTransformer 嵌入向量的语义问答
基于 Flask 的智能问答系统:用预训练语言模型把问题映射成嵌入向量,在 SQLite 知识库中检索最相似的问答对,返回答案。系统包含数据库管理、NLP 处理、Web 接口三大模块。
GPT/
├── qa_system/
│ ├── app.py # Flask 入口 + 日志配置
│ ├── database.py # 数据库连接与问答对 CRUD
│ ├── nlp_processor.py # 嵌入向量 + 相似度检索
│ ├── init_data.py # 初始化数据
│ └── templates/
├── models/ # 模型缓存目录
├── logs/ # 日志
├── knowledge.db # SQLite 知识库
└── README.md
nlp_processor.py)模型:paraphrase-multilingual-MiniLM-L12-v2(支持多语言的 SentenceTransformer)
def __init__(self, model_name='paraphrase-multilingual-MiniLM-L12-v2'):
cache_dir = Path('models')
cache_dir.mkdir(exist_ok=True)
os.environ['TRANSFORMERS_CACHE'] = str(cache_dir)
os.environ['HF_HOME'] = str(cache_dir)
self.model = SentenceTransformer(model_name, cache_folder=str(cache_dir))
降级方案(很有工程价值)——模型加载失败时自动退回简单词袋向量:
def _get_simple_embedding(self, text: str) -> np.ndarray:
"""简单的文本向量化方法(100维哈希词袋)"""
words = text.lower().split()
vector = np.zeros(100)
for i, word in enumerate(words):
vector[hash(word) % 100] += 1 # 哈希到 100 维桶
norm = np.linalg.norm(vector)
if norm > 0:
vector = vector / norm # L2 归一化
return vector
相似度计算:标准余弦相似度,异常时返回 0.0
def calculate_similarity(self, embedding1, embedding2) -> float:
return np.dot(embedding1, embedding2) / (np.linalg.norm(embedding1) * np.linalg.norm(embedding2))
检索逻辑:遍历候选问答对 → 计算相似度 → 取最大且超过阈值(默认 0.5)的结果
def find_most_similar(self, query, candidates, threshold=0.5):
query_embedding = self.get_embedding(query)
max_similarity = 0
best_answer = None
for row in candidates:
id_, question, answer, embedding_str, created_at = row
embedding = np.array([float(x) for x in embedding_str.strip('[]').split(',')])
similarity = self.calculate_similarity(query_embedding, embedding)
if similarity > max_similarity:
max_similarity = similarity
best_answer = answer
if max_similarity < threshold:
return None, 0 # 低于阈值判定为"无答案"
return best_answer, max_similarity
单条异常
continue跳过,不会中断整体检索——健壮性考虑周到。
database.py)check_same_thread=False 支持多线程_instance + _lock)保证并发安全qa_pairs(id, question, answer, embedding, created_at)app.py)RotatingFileHandler(单文件 1MB,保留 10 个备份),写入 logs/qa_system.log/ 渲染首页,/api/ask(POST)接收问题返回答案用户输入 → AJAX POST /api/ask → 数据库取全部问答对
→ 问题转嵌入向量 → 逐一算余弦相似度
→ 取最高分且 > 0.5 → 返回答案(否则返回"无匹配")
这是一个传统的语义检索式问答实现,思路也算现代 RAG 的早期形态。几点说明:
理解这套"嵌入 → 检索 → 阈值"的骨架,再看现代 RAG(向量库 + LLM)会好懂一些。