Archived
fix: bge-m3 1024d向量维度 + save兼容list + search_by_vector + 修复_log.recall
This commit is contained in:
File diff suppressed because one or more lines are too long
+504
-498
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"model_name": "moka-ai/m3e-base", "doc_count": 498, "vector_dim": 768, "index_type": "FlatIP", "updated_at": "2026-05-26T16:15:26.247609"}
|
||||
{"model_name": "bge-m3", "doc_count": 504, "updated_at": "2026-05-27T02:32:31.802561"}
|
||||
+504
-35
File diff suppressed because one or more lines are too long
@@ -143,9 +143,14 @@ class SBertIndex:
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
json.dump(meta, f, ensure_ascii=False)
|
||||
|
||||
# 保存向量(NumPy 格式)
|
||||
# 保存向量(NumPy 格式或 Python list)
|
||||
if self.vectors:
|
||||
vectors_list = [v.tolist() for v in self.vectors]
|
||||
vectors_list = []
|
||||
for v in self.vectors:
|
||||
if hasattr(v, 'tolist'):
|
||||
vectors_list.append(v.tolist())
|
||||
else:
|
||||
vectors_list.append(list(v)) # 已经是 list
|
||||
with open(vectors_path, 'w', encoding='utf-8') as f:
|
||||
for v in vectors_list:
|
||||
f.write(json.dumps(v, ensure_ascii=False) + '\n')
|
||||
@@ -252,9 +257,64 @@ class SentenceTransformersRecall:
|
||||
self._needs_rebuild = False # 增量添加后索引已更新,不需要重建
|
||||
|
||||
def search(self, query: str, top_k: int = 10) -> list[tuple[str, float, dict]]:
|
||||
"""语义搜索"""
|
||||
"""语义搜索(文本查询,内部用 m3e-base 编码)"""
|
||||
return self.index.search(query, top_k)
|
||||
|
||||
def search_by_vector(self, query_vector: np.ndarray, top_k: int = 10) -> list[tuple[str, float, dict]]:
|
||||
"""向量搜索(使用预计算向量,避免重复编码)
|
||||
|
||||
query_vector: 预计算好的查询向量(1024d,来自 bge-m3)
|
||||
返回: [(doc_id, cosine_score, doc_dict)]
|
||||
"""
|
||||
import numpy as np
|
||||
if not self.index.vectors or not self.index.documents:
|
||||
return []
|
||||
|
||||
# 归一化查询向量(传入向量已是归一化bge-m3,这里确保格式正确)
|
||||
q = np.array(query_vector, dtype=np.float32)
|
||||
q = q / (np.linalg.norm(q) + 1e-8)
|
||||
|
||||
vectors_matrix = np.array(self.index.vectors) # (n, 1024)
|
||||
# cosine similarity = dot product(查询和向量都已归一化)
|
||||
scores = np.dot(vectors_matrix, q).astype(np.float64)
|
||||
|
||||
top_indices = np.argsort(scores)[::-1][:top_k]
|
||||
results = []
|
||||
for idx in top_indices:
|
||||
score = float(scores[idx])
|
||||
if score < 0.0: # 余弦相似度可为负,但归一化后范围 [0,1]
|
||||
score = max(0.0, score)
|
||||
results.append((
|
||||
self.index.documents[idx]['id'],
|
||||
score,
|
||||
self.index.documents[idx]
|
||||
))
|
||||
return results
|
||||
|
||||
def index_documents_with_vectors(self, docs: list[dict], vectors: list[np.ndarray]):
|
||||
"""全量重建索引(使用预计算向量,来自 bge-m3 1024d)
|
||||
|
||||
每次 commit 调用:从 JSONLShardStore 读取全部 docs,
|
||||
用 bge-m3 API 编码为 1024d 向量,传入此方法存储。
|
||||
"""
|
||||
self.index.documents = []
|
||||
self.index.vectors = []
|
||||
|
||||
for doc, vec in zip(docs, vectors):
|
||||
text = doc.get('content', '') + ' ' + ' '.join(str(f) for f in doc.get('facts', []))
|
||||
self.index.documents.append({
|
||||
'id': doc.get('id', ''),
|
||||
'text': text,
|
||||
'facts': doc.get('facts', []),
|
||||
'category': doc.get('category', 'unknown'),
|
||||
'timestamp': doc.get('timestamp', ''),
|
||||
})
|
||||
self.index.vectors.append(np.array(vec)) # 统一存为 numpy 数组
|
||||
|
||||
self.index.model_name = "bge-m3" # 存储的是 bge-m3 1024d 向量
|
||||
self.index.save()
|
||||
self._needs_rebuild = False
|
||||
|
||||
def _append_to_disk(self, docs: list[dict], vectors: list[np.ndarray]):
|
||||
"""增量持久化:追加文档和向量到磁盘(不覆盖现有数据)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user