Practica3 / rag_engine.py
Calvoloncio's picture
Upload 4 files
e581cb0 verified
import json
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
from sentence_transformers import SentenceTransformer, util
# --- 1. CARGA DE MODELOS ---
# Usamos un modelo para buscar informacion en los documentos
print("Cargando el modelo de busqueda...")
embed_model = SentenceTransformer("MongoDB/mdbr-leaf-ir")
# Usamos un modelo para que nos ayude a redactar la respuesta
print("Cargando el modelo de lenguaje...")
model_id = "microsoft/Phi-2"
tokenizer = AutoTokenizer.from_pretrained(model_id)
llm_model = AutoModelForCausalLM.from_pretrained(model_id)
# --- 2. BASE DE CONOCIMIENTO ---
# Leemos los documentos que tenemos guardados en el archivo JSON
with open("documents.json", "r", encoding="utf-8") as f:
docs_dict = json.load(f)
documents = list(docs_dict.values())
# Preparamos los datos para que el ordenador pueda buscar en ellos rapidamente
print("Preparando los documentos para la busqueda...")
docs_embeddings = embed_model.encode(documents, convert_to_tensor=True)
# --- 3. FUNCIONES DEL SISTEMA ---
def recuperar_documentos(consulta, top_k=2, umbral=0.4):
""" Busca en nuestra base de datos los textos que mas se parecen a la pregunta """
# Pasamos la pregunta a un formato que el modelo entienda
query_embedding = embed_model.encode(consulta, convert_to_tensor=True)
# Comparamos la pregunta con todos los documentos para ver cuales coinciden mejor
cos_scores = util.cos_sim(query_embedding, docs_embeddings)[0]
# Nos quedamos con los mejores resultados segun lo que hayamos configurado
top_results = torch.topk(cos_scores, k=min(top_k, len(documents)))
final_docs = []
for score, idx in zip(top_results[0], top_results[1]):
# Solo guardamos el documento si se parece lo suficiente a la pregunta
if score >= umbral:
final_docs.append(documents[idx])
return final_docs
def generar_respuesta(consulta, documentos_recuperados):
""" Redacta una respuesta usando la pregunta y la informacion encontrada """
# Si no hemos encontrado nada, usamos un texto por defecto
contexto = " ".join(documentos_recuperados) if documentos_recuperados else "No se ha encontrado informacion relevante."
# Preparamos las instrucciones para el modelo
prompt = f"Context: {contexto}\nQuestion: {consulta}\nAnswer:"
# Convertimos el texto a un formato que el modelo pueda procesar
inputs = tokenizer(prompt, return_tensors="pt")
# El modelo genera el texto de la respuesta
with torch.no_grad():
outputs = llm_model.generate(**inputs, max_new_tokens=100)
# Limpiamos el texto generado para quedarnos solo con lo importante
resultado_total = tokenizer.decode(outputs[0], skip_special_tokens=True)
respuesta_limpia = resultado_total.split("Answer:")[-1].strip()
return respuesta_limpia
def preguntar(consulta, top_k=2, umbral=0.4):
""" Funcion principal que busca la informacion y redacta la respuesta """
docs = recuperar_documentos(consulta, top_k, umbral)
respuesta = generar_respuesta(consulta, docs)
return respuesta, docs