Tutoriales

Ajuste LLM local con trapos usando ollama y langchain

Los modelos de idiomas grandes (LLM) son poderosos, pero tienen una limitación importante: dependen únicamente del conocimiento que han recibido.

Esto significa que carecen de actualizaciones en tiempo real específicas de dominio, que es un proceso costoso y poco práctico a menos que se vuelva a entrenar. Esto es Búsqueda de la generación autorizada (trapo) Adelante.

RAG permite a LLM recuperar el conocimiento externo relevante antes de generar una respuesta, accediendo así a la información fresca, contexto y específica.

Imagine tener un asistente de IA que no solo recuerda los hechos generales, sino que también hace referencia a su PDF, notas o datos privados para una respuesta más precisa.

Este artículo tiene una comprensión más profunda de cómo funcionan los trapos, cómo se entrenan LLM y cómo los usamos Horama y Langchain Implemente un sistema de RAG local que ajuste la respuesta de LLM integrando dinámicamente y recuperando el conocimiento externo.

Al final de este tutorial, construiremos un proyecto RAG basado en PDF que permita a los usuarios cargar documentos y hacer preguntas y responder según los datos almacenados.

No soy un experto en IA. Este artículo es un estudio práctico de la generación de energía mejorada por la búsqueda (RAG) por Ollama y Langchain para el aprendizaje y los experimentos. Puede haber errores y no dude en compartir si encuentra algo o tiene mejores ideas. Cómo las empresas manejan los trapos a escala en todas partes, usan grandes conjuntos de datos, bases de datos profesionales y GPU de alto rendimiento.

¿Cuál es la generación de efectos de recuperación (trapo)?

trapo Es uno Marco de IA Mejore la respuesta de LLM integrando la recuperación de información en tiempo real.

Las búsquedas de LLM confían más en sus datos de capacitación solo Documentos relacionados Antes de generar la respuesta, comience desde una fuente externa (como una base de datos vectorial).

Cómo funciona el trapo

  1. Entrada de consulta – El usuario envía preguntas.
  2. Recuperación de archivos – Algoritmo de búsqueda para obtener bloques de texto relevantes de las tiendas Vector.
  3. Generación de respuesta al contexto – El texto recuperado se alimenta al LLM, lo que lo lleva a producir respuestas más precisas y relevantes.
  4. Salida final – La respuesta basada en el conocimiento buscado ahora se devolverá al usuario.

¿Por qué usar un trapo en lugar de un ajuste fino?

  • No hay necesidad de más capacitación – El ajuste fino tradicional requiere una gran cantidad de potencia de GPU y conjuntos de datos etiquetados. RAG elimina esta necesidad recuperando dinámicamente datos.
  • Último conocimiento – Este modelo puede referirse a documentos recién cargados en lugar de depender de datos de capacitación obsoletos.
  • Respuestas más precisas y específicas del dominio – Ideal para tareas legales, médicas o relacionadas con la investigación que son críticas.

Cómo se entrena LLM (y por qué el trapo los mejora)

Antes de sumergirnos en el trapo, comprendamos cómo está entrenado LLM:

  1. Pre-entrenamiento – Este modelo aprende patrones de lenguaje, hechos y razonamiento de una gran cantidad de textos (por ejemplo, libros, Wikipedia).
  2. Ajuste fino – Entrenamiento adicional de casos de uso específicos en conjuntos de datos especializados (por ejemplo, investigación médica, asistencia de codificación).
  3. razonamiento – Los modelos capacitados se implementan para responder consultas de los usuarios.

Si bien el ajuste es útil, tiene limitaciones:

  • Esto es El cálculo es costoso.
  • Eso es cierto No se permiten actualizaciones dinámicas Conocimiento.
  • él Posible introducción de sesgo Si se capacita en un conjunto de datos limitado.

Usando RAG, hacemos que los LLM sean más adaptables al permitir la recuperación en tiempo real de fuentes externas.

Construya una aplicación de trapo local con Ollama y Langchain

En este tutorial, utilizaremos Langchain para crear una aplicación de búsqueda de documentos de RAG simple, Cromadby Ollama.

La aplicación permite a los usuarios cargar PDFS, incrustarlos en bases de datos vectoriales y consultarlos para obtener información relevante.

Instalar dependencias

Para evitar meterse con nuestros paquetes de sistema, primero creamos un entorno virtual de Python. Esto mantiene nuestras dependencias a los huérfanos y evita conflictos con los paquetes de Python de todo el sistema.

Navegue a su directorio de proyecto y cree un entorno virtual:

cd ~/RAG-Tutorial
python3 -m venv venv

Ahora, active el entorno virtual:

source venv/bin/activate

Una vez activado, su mensaje terminal debe cambiar para indicar que ahora está en el entorno virtual.

Al activar el entorno virtual, use requirements.txt:

pip install -r requirements.txt
Instalar dependencias

Esto instalará todas las dependencias requeridas para nuestras tuberías de trapo, incluidos frascos, lamban, orama y pai Atlantic.

Después de la instalación, ¡establecerá todo el siguiente paso!

Estructura de proyectos

Nuestra estructura del proyecto es la siguiente:

RAG-Tutorial/
│── app.py              # Main Flask server
│── embed.py            # Handles document embedding
│── query.py            # Handles querying the vector database
│── get_vector_db.py    # Manages ChromaDB instance
│── .env                # Stores environment variables
│── requirements.txt    # List of dependencies
└── _temp/              # Temporary storage for uploaded files

Paso 1: Crear App.py (servidor API de Flask)

Este script establece un servidor frasco con dos puntos finales:

  • /embed – Sube PDF e incrusta en ChromadB.
  • /query – Acepte consultas de usuario y recupere bloques de texto relevantes de ChromAdB.
  • route_embed(): Guarde el archivo cargado e incruste su contenido en ChromAdB.
  • route_query(): Acepte la consulta y recupere los bloques de documentos relevantes.
import os
from dotenv import load_dotenv
from flask import Flask, request, jsonify
from embed import embed
from query import query
from get_vector_db import get_vector_db

load_dotenv()
TEMP_FOLDER = os.getenv('TEMP_FOLDER', './_temp')
os.makedirs(TEMP_FOLDER, exist_ok=True)

app = Flask(__name__)

@app.route('/embed', methods=['POST'])
def route_embed():
    if 'file' not in request.files:
        return jsonify({"error": "No file part"}), 400
    file = request.files['file']
    if file.filename == '':
        return jsonify({"error": "No selected file"}), 400
    embedded = embed(file)
    return jsonify({"message": "File embedded successfully"}) if embedded else jsonify({"error": "Embedding failed"}), 400

@app.route('/query', methods=['POST'])
def route_query():
    data = request.get_json()
    response = query(data.get('query'))
    return jsonify({"message": response}) if response else jsonify({"error": "Query failed"}), 400

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8080, debug=True)

Paso 2: Crear incrust.py (documento de incrustación)

Este archivo procesa el procesamiento de documentos, extrae texto e incorpora vectores en ChromadB.

  • allowed_file(): Asegúrese de procesar solo PDF.
  • save_file(): Guarde temporalmente el archivo cargado.
  • load_and_split_data():uso UnstructuredPDFLoader y RecursiveCharacterTextSplitter Extraiga texto y divídalo en bloques manejables.
  • embed(): Convierta los bloques de texto a las incrustaciones de vectores y guárdelos en ChromAdB.
import os
from datetime import datetime
from werkzeug.utils import secure_filename
from langchain_community.document_loaders import UnstructuredPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from get_vector_db import get_vector_db

TEMP_FOLDER = os.getenv('TEMP_FOLDER', './_temp')

def allowed_file(filename):
    return filename.lower().endswith('.pdf')

def save_file(file):
    filename = f"{datetime.now().timestamp()}_{secure_filename(file.filename)}"
    file_path = os.path.join(TEMP_FOLDER, filename)
    file.save(file_path)
    return file_path

def load_and_split_data(file_path):
    loader = UnstructuredPDFLoader(file_path=file_path)
    data = loader.load()
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=7500, chunk_overlap=100)
    return text_splitter.split_documents(data)

def embed(file):
    if file and allowed_file(file.filename):
        file_path = save_file(file)
        chunks = load_and_split_data(file_path)
        db = get_vector_db()
        db.add_documents(chunks)
        db.persist()
        os.remove(file_path)
        return True
    return False

Paso 3: Cree Query.py (procesamiento de consultas)

Recupera información relevante de ChromAdB y genera una respuesta utilizando LLM.

  • get_prompt(): Crear indicaciones estructuradas para búsquedas multiformitivas.
  • query(): Use la LLM de Ollama para volver a establecer consultas de usuarios, recuperar bloques de documentos relevantes y generar respuestas.
import os
from langchain_community.chat_models import ChatOllama
from langchain.prompts import ChatPromptTemplate, PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain.retrievers.multi_query import MultiQueryRetriever
from get_vector_db import get_vector_db

LLM_MODEL = os.getenv('LLM_MODEL')
OLLAMA_HOST = os.getenv('OLLAMA_HOST', '

def get_prompt():
    QUERY_PROMPT = PromptTemplate(
        input_variables=["question"],
        template="""You are an AI assistant. Generate five reworded versions of the user question
        to improve document retrieval. Original question: {question}""",
    )
    template = "Answer the question based ONLY on this context:\n{context}\nQuestion: {question}"
    prompt = ChatPromptTemplate.from_template(template)
    return QUERY_PROMPT, prompt

def query(input):
    if input:
        llm = ChatOllama(model=LLM_MODEL)
        db = get_vector_db()
        QUERY_PROMPT, prompt = get_prompt()
        retriever = MultiQueryRetriever.from_llm(db.as_retriever(), llm, prompt=QUERY_PROMPT)
        chain = ({"context": retriever, "question": RunnablePassthrough()} | prompt | llm | StrOutputParser())
        return chain.invoke(input)
    return None

Paso 4: Crear get_vector_db.py (Vector Database Management)

Inicializa y administra ChromAdB, que almacena integración de texto para una recuperación rápida.

  • get_vector_db():usar Modelo de incrustación general Y cargue el vector de documento almacenado.
import os
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores.chroma import Chroma

CHROMA_PATH = os.getenv('CHROMA_PATH', 'chroma')
COLLECTION_NAME = os.getenv('COLLECTION_NAME')
TEXT_EMBEDDING_MODEL = os.getenv('TEXT_EMBEDDING_MODEL')
OLLAMA_HOST = os.getenv('OLLAMA_HOST', '

def get_vector_db():
    embedding = OllamaEmbeddings(model=TEXT_EMBEDDING_MODEL, show_progress=True)
    return Chroma(collection_name=COLLECTION_NAME, persist_directory=CHROMA_PATH, embedding_function=embedding)

Paso 5: Variables de entorno

crear .envVariables de entorno de almacenamiento:

TEMP_FOLDER = './_temp'
CHROMA_PATH = 'chroma'
COLLECTION_NAME = 'rag-tutorial'
LLM_MODEL = 'smollm:360m'
TEXT_EMBEDDING_MODEL = 'nomic-embed-text'
  • TEMP_FOLDER: Cargar temporalmente PDF.
  • CHROMA_PATH: Defina la ubicación de almacenamiento de ChromAdB.
  • COLLECTION_NAME: Establezca el nombre de la colección ChromAdB.
  • LLM_MODEL: Especifica el modelo LLM utilizado para la consulta.
  • TEXT_EMBEDDING_MODEL: Define el modelo integrado utilizado para el almacenamiento vectorial.
Lista de modelos Ollama instalados
Usé estos LLM livianos en este tutorial porque no tengo una GPU dedicada para razonar sobre modelos grandes. | Puede editar LLM en el archivo .env

Prueba de tubería de trapo temporal + LLM

Ahora que nuestra aplicación RAG se ha construido, necesitamos verificar su efectividad. El objetivo es garantizar que el sistema sea correcto:

  1. Incrustar archivos – Convierta el texto para insertar vector y guárdelo en ChromadB.
  2. Bloques relacionados con la búsqueda – Obtenga el fragmento de texto más relevante de ChromadB de acuerdo con la consulta.
  3. Producir respuestas significativas – Use Ollama para desarrollar respuestas inteligentes basadas en datos recuperados.

Esta fase de prueba asegura que nuestras tuberías de RAG temporales funcionen como se esperaba y ajustan cuando es necesario.

Ejecute el servidor Flask

Primero debemos asegurarnos de que nuestra aplicación Flask se esté ejecutando. Abra el terminal, navegue a su directorio de proyecto y active su entorno virtual:

cd ~/RAG-Tutorial
source venv/bin/activate  # On Linux/macOS
# or
venv\Scripts\activate  # On Windows (if using venv)

Ahora, ejecute la aplicación Flask:

python3 app.py

Si todo está configurado correctamente, el servidor debe iniciar y escuchar http://localhost:8080. Debería ver la siguiente salida:

Ejecute el servidor Flask

Después de que el servidor se esté ejecutando, usaremos curl Los comandos interactúan con nuestra tubería y analizan las respuestas para confirmar que todo funciona como se esperaba.

1. Incorporar documentos de prueba

El primer paso es cargar el documento y asegurarse de que su contenido esté incrustado con éxito en ChromAdB.

curl --request POST \
  --url  \
  --header 'Content-Type: multipart/form-data' \
  --form file=@/path/to/file.pdf

descomponer:

  • curl --request POST → Enviar POST Solicite nuestra API.
  • --url → Apuntar a nosotros embed El punto final se ejecuta en el puerto 8080.
  • --header 'Content-Type: multipart/form-data' → Especifique que estamos cargando el archivo.
  • --form file=@/path/to/file.pdf → Adjunte el archivo a procesar (en este caso PDF).

Respuesta esperada:

Incrustar documentos PDF

¿Qué está pasando adentro?

  1. El servidor lee el archivo PDF cargado.
  2. Extraiga el texto, divídalo en trozos y conviértalo en una incrustación vectorial.
  3. Estas embedidas se almacenan en ChromAdB para una recuperación futura.

Si hay un problema:

preguntaRazones posiblesArreglarse
"status": "error"Archivo no se encuentra o no se puede leerVerifique las rutas y permisos de los archivos
collection.count() == 0Falla de almacenamiento de ChromadBReiniciar chromadb y verificar registros

2. Documentos de consulta

Ahora que nuestro documento está integrado, podemos probar si recuperamos información relevante cuando hacemos una pregunta.

curl --request POST \
  --url  \
  --header 'Content-Type: application/json' \
  --data '{ "query": "Question about the PDF?" }'

descomponer:

  • curl --request POST → Enviar POST Requerir.
  • --url → Apuntar a nosotros query Punto final.
  • --header 'Content-Type: application/json' → Especifique que estamos enviando datos JSON.
  • --data '{ "query": "Question about the PDF?" }' → Envíe nuestra consulta de búsqueda para recuperar información relevante.

Respuesta esperada:

Consulta documentos PDF usando ollama

¿Qué está pasando adentro?

  1. Consulta "Whats in this file?" Pasó a ChromadB para recuperar los bloques más relevantes.
  2. El bloque recuperado se pasa a Orama como el fondo para generar la respuesta.
  3. Ollama hizo respuestas significativas basadas en la información recuperada.

Si la respuesta no es lo suficientemente buena:

preguntaRazones posiblesArreglarse
Recuperar bloques es irrelevanteEstrategia de fragmentación pobreCambiar el tamaño del bloque e intente incrustar nuevamente
"llm_response": "I don't know"El contexto no se pasa correctamenteCompruebe si ChromAdB está devolviendo resultados
Respuesta Falta de detalles de documentaciónLLM necesita una mejor explicaciónModificar las indicaciones del sistema

3. Ajunte al LLM para una mejor respuesta

Si la respuesta de Ollama no es lo suficientemente detallada, necesitamos mejorar cómo proporcionar los antecedentes.

Ajustar la estrategia:

  1. Mejore los bloques: asegúrese de que el bloque de texto sea lo suficientemente grande como para retener el significado pero lo suficientemente pequeño como para recuperar de manera eficiente.
  2. Búsqueda mejorada – Agregar n_results Obtenga bloques de documentos más relevantes.
  3. Modificar consejos de LLM: agregue directivas estructuradas para una mejor respuesta.

El sistema de muestra solicita a Ollama:

prompt = f"""
You are an AI assistant helping users retrieve information from documents.
Use the following document snippets to provide a helpful answer.
If the answer isn't in the retrieved text, say 'I don't know.'

Retrieved context:
{retrieved_chunks}

User's question:
{query_text}
"""

Esto asegura que Ollama:

    • Use el texto que se recupere correctamente.
    • Evite las alucinaciones apegándose a los contextos disponibles.
    • Proporcionar respuestas estructuradas significativas.

El pensamiento final

Construir esta tubería de ajuste temporal de Rag LLM es una experiencia perspicaz, pero creo que está claro que no soy un experto en IA. Todo aquí es algo que todavía estoy aprendiendo.

Definitivamente habrá errores, ineficiencia y cosas que se pueden mejorar. Si usted es una persona que sabe mejor, o si perdí algún punto clave, no dude en compartir sus ideas.

Dicho esto, este proyecto me dio una pequeña comprensión de cómo funcionan los trapos. Esencialmente, Rag se trata de obtener el contexto correcto antes de pedirle al LLM que genere una respuesta.

Esto es lo que permite a los chatbots de IA recuperar información de una amplia gama de conjuntos de datos, no solo responder según sus datos de capacitación.

Las grandes empresas usan esta tecnología a gran escala, procesan grandes cantidades de datos, ajustan sus modelos y optimizan sus mecanismos de búsqueda para construir asistentes de IA intuitivos y conocedores.

El nivel que construimos aquí es mucho menor que ese nivel, pero aún es fascinante cómo guiar la respuesta de la LLM controlando la información que recupera.

Incluso con esta configuración básica, vemos que el impacto de la calidad de la recuperación, las estrategias de construcción y el diseño oportuno tienen cierta comprensión de la respuesta final.

Esto me hace preguntarme, ¿alguna vez has considerado entrenar a tu propio LLM? ¿Estaría interesado en algo como esto, pero se dirige específicamente a los tutoriales de Linux?

Imagine un LLM personalizado que puede responder a sus preguntas de Linux con respuestas precisas de RAG, ¿lo usaría? ¡Háganos saber en los comentarios!

Publicaciones relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba