Spaces:
Sleeping
Sleeping
File size: 5,067 Bytes
600d58a 23c53c9 57a0f1d 5048890 600d58a ba52088 600d58a 83f207f ba52088 23c53c9 a2280fa 23c53c9 ba52088 83f207f a2280fa 23c53c9 a2280fa 23c53c9 ba52088 83f207f 5048890 ba52088 a2280fa 7b3fe08 ba52088 83f207f ba52088 23c53c9 7b3fe08 ba52088 83f207f 23c53c9 ba52088 83f207f ba52088 5dded11 a2280fa 84b8028 a2280fa 84b8028 ba52088 a2280fa ba52088 a2280fa 631984e 84b8028 631984e 84b8028 a2280fa 84b8028 a2280fa 84b8028 a2280fa 84b8028 a2280fa 84b8028 a2280fa 84b8028 ba52088 499b5c3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | from llama_index.core import VectorStoreIndex, Settings
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core.response_synthesizers import get_response_synthesizer, ResponseMode
from llama_index.core.prompts import PromptTemplate
from llama_index.retrievers.bm25 import BM25Retriever
from llama_index.core.retrievers import QueryFusionRetriever
from my_logging import log_message
from config import CUSTOM_PROMPT, PROMPT_SIMPLE_POISK
def create_vector_index(documents):
log_message("Строю векторный индекс")
return VectorStoreIndex.from_documents(documents)
def create_query_engine(vector_index):
try:
bm25_retriever = BM25Retriever.from_defaults(
docstore=vector_index.docstore,
similarity_top_k=20 # Increased for more candidates
)
vector_retriever = VectorIndexRetriever(
index=vector_index,
similarity_top_k=25, # Increased
similarity_cutoff=0.65 # Slightly lower for recall
)
hybrid_retriever = QueryFusionRetriever(
[vector_retriever, bm25_retriever],
similarity_top_k=40, # More candidates for reranking
num_queries=1
)
custom_prompt_template = PromptTemplate(PROMPT_SIMPLE_POISK)
response_synthesizer = get_response_synthesizer(
response_mode=ResponseMode.TREE_SUMMARIZE,
text_qa_template=custom_prompt_template
)
query_engine = RetrieverQueryEngine(
retriever=hybrid_retriever,
response_synthesizer=response_synthesizer
)
log_message("Query engine успешно создан")
return query_engine
except Exception as e:
log_message(f"Ошибка создания query engine: {str(e)}")
raise
def rerank_nodes(query, nodes, reranker, top_k=20, min_score_threshold=0.5, diversity_penalty=0.3):
"""
Rerank nodes with diversity and adaptive scoring
"""
if not nodes or not reranker:
return nodes[:top_k]
try:
log_message(f"Переранжирую {len(nodes)} узлов")
pairs = [[query, node.text] for node in nodes]
scores = reranker.predict(pairs)
scored_nodes = list(zip(nodes, scores))
# Sort by score descending
scored_nodes.sort(key=lambda x: x[1], reverse=True)
# Filter by minimum threshold (more strict)
if min_score_threshold is not None:
scored_nodes = [(node, score) for node, score in scored_nodes
if score >= min_score_threshold]
log_message(f"После фильтрации по порогу {min_score_threshold}: {len(scored_nodes)} узлов")
if not scored_nodes:
log_message("Нет узлов после фильтрации, снижаю порог")
scored_nodes = list(zip(nodes, scores))
scored_nodes.sort(key=lambda x: x[1], reverse=True)
min_score_threshold = scored_nodes[0][1] * 0.5 # 50% of top score
scored_nodes = [(node, score) for node, score in scored_nodes
if score >= min_score_threshold]
# MMR-like diversity selection
selected_nodes = []
selected_docs = set()
selected_sections = set()
for node, score in scored_nodes:
if len(selected_nodes) >= top_k:
break
metadata = node.metadata if hasattr(node, 'metadata') else {}
doc_id = metadata.get('document_id', 'unknown')
section_key = f"{doc_id}_{metadata.get('section_path', metadata.get('section_id', ''))}"
# Apply diversity penalty
penalty = 0
if doc_id in selected_docs:
penalty += diversity_penalty * 0.5
if section_key in selected_sections:
penalty += diversity_penalty
adjusted_score = score * (1 - penalty)
# Add if still competitive
if not selected_nodes or adjusted_score >= selected_nodes[0][1] * 0.6:
selected_nodes.append((node, score))
selected_docs.add(doc_id)
selected_sections.add(section_key)
log_message(f"Выбрано {len(selected_nodes)} узлов с разнообразием")
log_message(f"Уникальных документов: {len(selected_docs)}, секций: {len(selected_sections)}")
if selected_nodes:
log_message(f"Score range: {selected_nodes[0][1]:.3f} to {selected_nodes[-1][1]:.3f}")
return [node for node, score in selected_nodes]
except Exception as e:
log_message(f"Ошибка переранжировки: {str(e)}")
return nodes[:top_k] |