任务:查找新模型整合没有回答的原因
可能存在问题:
(1)搜索返回格式错误
(2)相似度阈值太高 (MIN_SIMILARITY = 0.75)---->应该不可能,因为输入一样的句子,没有结果,仅点击标签,也没有结果
(3)数据库为空(没有问答对)-------->应该也没有问题
(4)模型向量生成问题
排除后:
问题1:返回格式错误(最可能)
前端需要 original_question,但我们的返回可能是 question。
问题2:标签筛选逻辑问题
纯标签搜索时,相似度计算可能为0,达不到阈值。
问题3:搜索方法逻辑错误
需要逐行检查代码逻辑。
(1)先修改一下large和rerank的路径,修改为绝对路径+修改返回格式(好像之前已经修改过了)
# 路径
MODEL_NAME = "D:\\下载\\戴雄斌_中华心法问答系统源代码\\bge-large-zh-v1.5"
RERANKER_NAME = "D:\\下载\\戴雄斌_中华心法问答系统源代码\\bge-reranker-large"
# 放回格式
return [{
**self.qa_pairs[res["index"]], # 关键修改:包含所有字段,包括 original_question
"similarity": round(float(res['similarity']), 4)
} for res in final_results]
等待测试结果---------->不行
(2)移除重排序,修改阈值为0,放回改为10
# TOP_K = 1000
TOP_K = 10
RERANK_TOP_K = 15
FINAL_TOP_K = 5
# MIN_SIMILARITY = 0.75
MIN_SIMILARITY = 0.0
# DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
DEVICE = "cpu" # 强制使用CPU
def search(self, query: str, selected_tags: Dict = None) -> List[Dict]:
if not self.qa_pairs:
return []
cleaned_query = clean_text(query)
# 如果没有搜索词,也没有选择任何标签,则直接返回空列表
if not cleaned_query and not (selected_tags and any(selected_tags.values())):
return []
if cleaned_query:
query_emb = self._get_embedding(cleaned_query)
similarities = np.dot(self.question_vectors, query_emb)
else:
# 如果没有搜索词(纯标签搜索),则所有问题的基础相似度视为0
similarities = np.zeros(len(self.qa_pairs))
expert_scores = db.session.query(SimilarityScore.question_id, func.avg(SimilarityScore.score)).filter(SimilarityScore.query_text == query).group_by(SimilarityScore.question_id).all()
expert_scores_map = dict(expert_scores)
results_with_sim = []
for i, qa_pair in enumerate(self.qa_pairs):
final_score = (similarities[i] + expert_scores_map.get(qa_pair['db_id'], similarities[i])) / 2
# --- 标签筛选逻辑(与BERT版本一致)---
passes_filter = True
if selected_tags:
# 筛选一级标签
if selected_tags.get('level1') and qa_pair['tags']['level1'] not in selected_tags['level1']:
passes_filter = False
# 筛选二级标签 (只要有一个匹配即可)
if passes_filter and selected_tags.get('level2') and not any(t in qa_pair['tags']['level2'] for t in selected_tags['level2']):
passes_filter = False
# 筛选三级标签/关键词 (只要有一个匹配即可)
if passes_filter and selected_tags.get('keywords') and not any(t in qa_pair['tags']['keywords'] for t in selected_tags['keywords']):
passes_filter = False
if passes_filter:
results_with_sim.append({"similarity": final_score, "index": i})
# 如果有搜索词,按相似度排序;如果只按标签搜,则按默认顺序
if cleaned_query:
sorted_results = sorted(results_with_sim, key=lambda x: x['similarity'], reverse=True)
else:
sorted_results = results_with_sim
# 移除阈值筛选和重排序逻辑,先保证能返回结果
final_results = sorted_results[:self.config.TOP_K]
# 关键:返回格式与BERT版本完全一致
return [{
**self.qa_pairs[res["index"]],
"similarity": round(float(res['similarity']), 4)
} for res in final_results]

可以!!!
------>不是返回格式的问题
有可能是阈值,有可能是重排序太复杂了。
(3)再次测试
- 可以去除关键词权重。
2.阈值先还是0,
3.需要重排序,
- 返回格式保持正确的格式,
5.用bert的索引返回
6.top_k=1000
def search(self, query: str, selected_tags: Dict = None) -> List[Dict]:
if not self.qa_pairs:
return []
cleaned_query = clean_text(query)
# 如果没有搜索词,也没有选择任何标签,则直接返回空列表
if not cleaned_query and not (selected_tags and any(selected_tags.values())):
return []
if cleaned_query:
query_emb = self._get_embedding(cleaned_query)
similarities = np.dot(self.question_vectors, query_emb)
# 可选:关键词权重增强(暂时注释掉)
# query_keywords = set(jieba.lcut(cleaned_query))
# keyword_weights = np.array([
# len(set(jieba.lcut(q["cleaned_question"])) & query_keywords)
# / max(len(query_keywords), 1)
# for q in self.qa_pairs
# ])
# final_similarities = 0.95 * similarities + 0.05 * keyword_weights
final_similarities = similarities # 暂时只用向量相似度
else:
# 如果没有搜索词(纯标签搜索),给基础相似度
final_similarities = np.ones(len(self.qa_pairs)) * 0.5
# 专家评分
expert_scores = db.session.query(SimilarityScore.question_id, func.avg(SimilarityScore.score))\
.filter(SimilarityScore.query_text == query)\
.group_by(SimilarityScore.question_id).all()
expert_scores_map = dict(expert_scores)
results_with_sim = []
for i, qa_pair in enumerate(self.qa_pairs):
base_score = final_similarities[i]
expert_score = expert_scores_map.get(qa_pair['db_id'], base_score)
final_score = (base_score + expert_score) / 2
# 标签筛选逻辑
passes_filter = True
if selected_tags:
# 一级标签筛选
if selected_tags.get('level1'):
if not isinstance(selected_tags['level1'], list):
selected_tags['level1'] = [selected_tags['level1']]
if qa_pair['tags']['level1'] not in selected_tags['level1']:
passes_filter = False
# 二级标签筛选
if passes_filter and selected_tags.get('level2'):
if not isinstance(selected_tags['level2'], list):
selected_tags['level2'] = [selected_tags['level2']]
if not any(t in qa_pair['tags']['level2'] for t in selected_tags['level2']):
passes_filter = False
# 关键词筛选
if passes_filter and selected_tags.get('keywords'):
if not isinstance(selected_tags['keywords'], list):
selected_tags['keywords'] = [selected_tags['keywords']]
if not any(t in qa_pair['tags']['keywords'] for t in selected_tags['keywords']):
passes_filter = False
# 阈值设为0,先保证所有结果都能返回
if passes_filter: # 移除阈值检查:and final_score >= self.config.MIN_SIMILARITY
results_with_sim.append({
"similarity": final_score,
"index": i
})
# 排序
if cleaned_query:
sorted_results = sorted(results_with_sim, key=lambda x: x['similarity'], reverse=True)
else:
sorted_results = results_with_sim
# 应用重排序(如果有查询词)
if len(sorted_results) > 0 and cleaned_query:
# 准备重排序的候选结果
candidates = []
for res in sorted_results[:self.config.RERANK_TOP_K]:
qa_data = self.qa_pairs[res["index"]]
candidates.append({
"similarity": res["similarity"],
"index": res["index"],
"original_question": qa_data["original_question"],
"answer": qa_data["answer"],
"tags": qa_data["tags"],
"db_id": qa_data["db_id"]
})
# 执行重排序
reranked_results = self._rerank(query, candidates)
# 转换回索引格式
final_indices = []
for reranked in reranked_results[:self.config.FINAL_TOP_K]:
# 找到对应的原始索引
for res in sorted_results:
if res["index"] == reranked.get("index"):
final_indices.append(res)
break
final_results = final_indices
else:
final_results = sorted_results[:self.config.FINAL_TOP_K]
# 索引返回模式(与BERT版本一致)
return [{
**self.qa_pairs[res["index"]], # 关键:使用索引获取完整数据
"similarity": round(float(res['similarity']), 4)
} for res in final_results]
------>一开始可以搜出结果,但是立马又没有结果了。
接着搜索,会显示没有结果,后台也卡住了,会一条一条慢慢蹦出来,然后又有结果了。
然后后台开始报错:
127.0.0.1 - - [01/Dec/2025 22:05:12] "POST /search HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 22:05:13] "POST /search HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 22:06:38] "POST /search HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 22:06:41] "POST /search HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 22:06:56] "POST /search HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 22:06:57] "POST /search HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 22:06:59] "POST /search HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 22:07:04] "POST /search HTTP/1.1" 200 -
127.0.0.1 - - [01/Dec/2025 22:07:08] "POST /search HTTP/1.1" 500 -
Traceback (most recent call last):
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\flask\app.py", line 1536, in __call__
return self.wsgi_app(environ, start_response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\flask\app.py", line 1514, in wsgi_app
response = self.handle_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\flask\app.py", line 1511, in wsgi_app
response = self.full_dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\flask\app.py", line 919, in full_dispatch_request
rv = self.handle_user_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\flask\app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\flask\app.py", line 902, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\Mind-Dharma Q&A System\xinfa_QA.py", line 715, in search
results = system.search(data.get('question', ''), data.get('tags', {}))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\Mind-Dharma Q&A System\xinfa_QA.py", line 507, in search
reranked_results = self._rerank(query, candidates)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\Mind-Dharma Q&A System\xinfa_QA.py", line 194, in _rerank
raw_scores = self.reranker.compute_score(pairs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\FlagEmbedding\abc\inference\AbsReranker.py", line 218, in compute_score
return self.compute_score_single_gpu(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\torch\utils\_contextlib.py", line 116, in decorate_context
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\FlagEmbedding\inference\reranker\encoder_only\base.py", line 138, in compute_score_single_gpu
passages_inputs_batch = self.tokenizer(
^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\transformers\tokenization_utils_base.py", line 2855, in __call__
encodings = self._call_one(text=text, text_pair=text_pair, **all_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\transformers\tokenization_utils_base.py", line 2943, in _call_one
return self.batch_encode_plus(
^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\transformers\tokenization_utils_base.py", line 3144, in batch_encode_plus
return self._batch_encode_plus(
^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\transformers\tokenization_utils_fast.py", line 541, in _batch_encode_plus
self.set_truncation_and_padding(
File "D:\下载\戴雄斌_中华心法问答系统源代码\venv\Lib\site-packages\transformers\tokenization_utils_fast.py", line 494, in set_truncation_and_padding
self._tokenizer.enable_truncation(**target)
RuntimeError: Already borrowed
reranker模型内部错误 :RuntimeError: Already borrowed。
这是多线程/多请求并发问题:reranker tokenizer在同一时间被多个请求调用,导致冲突。
问题分析:
前端快速连续搜索 → 多个请求同时到达
reranker tokenizer不是线程安全的 → Already borrowed错误
导致500内部服务器错误

过一会没输入了又可以运行了。
解决方案:
(1)先禁用rerank
(2)给rerank上锁(线程安全)
(3)在前端JavaScript中,添加防抖(debounce),避免快速连续搜索。
因为可以运行,所以暂且不修改。
(1)这一版本直接去掉了关键词(没什么用,最开始测试的时候就发现了,但是为了保持原来的逻辑,所以加上了),现在可以直接去掉。
(2)阈值修改为0!尽管修改为0,但是下面例子还是只有5条输出。(包括之前在匹配的时候,有相似度阈值检查,现在直接去掉了。)------>但是好像是rerank控制的就返回5条?------->没错!rerank控制返回5条!那为什么要设置阈值呢?因为没有到5条的时候,可以不返回5条吗?但是感觉有点没必要。因为一共就返回5条,感觉再减少一点没啥必要。----->所以先设置阈值=0。而且设置阈值之后,感觉仅进行标签搜索时,答案会被过滤掉。
(3)还有一个就是返回结果的格式和返回形式。保持与之前bert一样。(返回格式。输入数据的准备方式是和bert一样的索引)
(4)纯标签搜索时,给0.5分。原本是0分。----->这个可以考虑改回去。

测试上面这个例子,从输入到稳定输出结果,至少5分钟。
模型启动,至少30分钟。
存在速度很慢问题!
记得删掉之前添加的测试路由!