Comprensión del código en tu propio hardware

'Understanding code on your own hardware.'

Configuración de un LLM para hablar sobre tu código — con LangChain y hardware local

Prometo que tu código no saldrá de tu hardware local. Foto de Clément Hélardot en Unsplash

Entre las diversas tareas que los Modelos de Lenguaje de Gran Tamaño (LLM) pueden realizar hoy en día, el entendimiento de código puede ser de particular interés para ti, si trabajas con código fuente como desarrollador de software o científico de datos. ¿No sería genial tener un chatbot al que puedas hacerle preguntas sobre tu código? ¿Dónde se implementa el preprocesamiento de datos? ¿Ya existe una función para verificar la autenticación del usuario? ¿Cuál es la diferencia entre la función calculate_vector_dim y calculate_vector_dimension? En lugar de buscar el archivo correcto por ti mismo, simplemente pregúntale al bot y te dará una respuesta, junto con un enlace a los archivos que contienen los fragmentos de código relevantes. Ese mecanismo se llama búsqueda semántica y puedes imaginar lo útil que es.

En este tutorial, te mostraré cómo implementar un bot de LangChain que haga exactamente eso. Además, me centraré en el problema específico relacionado con la privacidad de datos de no entregar tu código a manos ajenas. El código que tú o tu empresa hayan producido es propiedad privada y puede contener información confidencial o conocimientos valiosos. Es posible que no desees o que las políticas de tu empresa no te permitan enviarlo a un LLM alojado por otra empresa, que puede estar ubicada en otro país. Por lo tanto, en este tutorial, te mostraré cómo configurar un bot de entendimiento de código que se ejecuta en tu hardware local, para que tu código nunca salga de tu infraestructura.

¡Comencemos! Primero, te daré una breve introducción al proceso general de búsqueda semántica antes de implementar un bot para el entendimiento de código.

Introducción a la búsqueda semántica

En la búsqueda semántica, todo se trata de encontrar los documentos relevantes. Foto de Markus Spiske en Unsplash

En primer lugar, permíteme explicarte brevemente la idea general de la búsqueda semántica. Este enfoque consta de dos pasos principales, que son la recuperación y la generación de respuestas por parte del LLM mismo. En el paso de recuperación, se seleccionan documentos que contienen información relevante y se alimentan al LLM para crear una respuesta en lenguaje natural. Por ejemplo, si haces una pregunta sobre una función llamada transform_vectors, la recuperación seleccionará aquellos archivos que son relevantes para responder esa pregunta. Eso puede incluir el archivo donde se implementa la función transform_vectors, pero también archivos que la utilizan o partes de la documentación que la mencionan. En el segundo paso, el contenido de esos archivos se entrega al LLM en un formato que puede verse algo así:

"""Responde la siguiente pregunta dada la información. <documento 1><documento 2>...<documento n>Pregunta: <pregunta del usuario>Respuesta:"""

El LLM crea una respuesta en lenguaje natural a la pregunta utilizando la información de los documentos que se le proporcionaron.

Esa es la idea principal de la búsqueda semántica. ¡Ahora comencemos a implementar! En primer lugar, tenemos que instalar los requisitos y leer nuestros datos.

Instalar requisitos

Antes de comenzar, asegúrate de tener configurado un entorno que ejecute Python e instala los siguientes paquetes:

pip install langchain==0.0.191pip install transformers

Leer los documentos

Ahora necesitamos leer los datos y convertirlos en un formato en el que LangChain pueda trabajar. Para esta demostración, descargaré el código de LangChain en sí, pero puedes usar tu propio código base, por supuesto:

import osfolder_name = "sample_code"os.system(f"git clone https://github.com/hwchase17/langchain {folder_name}")

Cargamos todos los archivos y los convertimos en un Documento cada uno, es decir, cada Documento contendrá exactamente un archivo del código base.

from langchain.docstore.document import Document
documents = []
for root, dirs, files in os.walk(folder_name):
    for file in files:
        try:
            with open(os.path.join(root, file), "r", encoding="utf-8") as o:
                code = o.readlines()
                d = Document(page_content="\n".join(code), metadata={"source": os.path.join(root, file)})
                documents.append(d)
        except UnicodeDecodeError:
            # algunos archivos no están codificados en utf-8; los ignoraremos por ahora
            pass

Recuperación

¿Cuál de estos es relevante para responder nuestra pregunta? Ese es el trabajo de la recuperación. Foto de Ed Robertson en Unsplash

Ahora que hemos creado nuestros Documentos, necesitamos indexarlos para que sean buscables. Indexar un Documento significa calcular un vector numérico que capture la información más relevante del Documento. A diferencia del propio texto, un vector de números se puede utilizar para realizar cálculos numéricos, lo que significa que podemos calcular fácilmente una similitud en él, que luego se utiliza para determinar qué Documentos son relevantes para responder una determinada pregunta.

En un nivel técnico, este índice que crearemos con la ayuda de un embedding y lo almacenaremos en un VectorStore. Hay VectorStores disponibles como servicio (por ejemplo, DeepLake), que vienen con algunas ventajas útiles, pero en nuestro escenario, no queremos dar el código fuera de nuestras manos, así que creamos un VectorStore localmente en nuestra máquina. La forma más sencilla de hacerlo es usando Chroma, que crea un VectorStore en memoria y nos permite persistirlo.

from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma
hfemb = HuggingFaceEmbeddings(model_name="krlvi/sentence-t5-base-nlpl-code-x-glue")
persist_directory = "db"
db = Chroma.from_documents(documents, hfemb, persist_directory=persist_directory)
db.persist()

Dentro de la función from_documents, se calculan los índices y se almacenan en la base de datos Chroma. La próxima vez, en lugar de llamar a la función from_documents nuevamente, podemos cargar la base de datos Chroma persistida en sí:

db = Chroma(persist_directory=persist_directory, embedding_function=hfemb)

Como viste anteriormente, como embedding utilicé krlvi/sentence-t5-base-nlpl-code-x-glue, que es un embedding que se entrenó en código de bibliotecas de GitHub de código abierto. Como puedes imaginar, es crucial que el embedding que utilicemos se haya entrenado en código (entre otros datos), para que pueda usar los datos que le proporcionamos. Es probable que un embedding que se haya entrenado solo en lenguaje natural funcione peor.

Ahora que tenemos nuestro VectorStore y nuestro embedding, podemos crear el recuperador directamente desde la base de datos Chroma:

retriever = db.as_retriever()

LLM

El LLM tiene que razonar sobre los documentos y encontrar una respuesta a la pregunta del usuario. Foto de Tingey Injury Law Firm en Unsplash

El último componente que necesitamos es un LLM. La solución más sencilla sería utilizar un LLM alojado, por ejemplo, utilizando la interfaz de OpenAI. Sin embargo, no queremos enviar nuestro código a un servicio alojado. En su lugar, ejecutaremos un LLM en nuestro propio hardware. Para hacerlo, utilizamos HuggingFacePipeline, que nos permite utilizar un modelo de HuggingFace en el framework de LangChain.

from langchain import HuggingFacePipeline
import transformers
model_id = "mosaicml/mpt-7b-instruct"
config = transformers.AutoConfig.from_pretrained(model_id,trust_remote_code=True)
tokenizer = transformers.AutoTokenizer.from_pretrained(model_id)
model = transformers.AutoModelForCausalLM.from_pretrained(model_id, config=config, trust_remote_code=True)
pipe = transformers.pipeline("text-generation", model=model, tokenizer=tokenizer, max_new_tokens=100)
llm = HuggingFacePipeline(pipeline=pipe)

Como puedes ver, utilicé el modelo mpt-7b de mosaico, que solo necesita ~16GB de memoria en una GPU. Creé un AutoModelForCausalLM, que se pasa a transformers.pipeline, que finalmente se transforma en un HuggingFacePipeline. El HuggingFacePipeline implementa la misma interfaz que los objetos típicos de LLM en LangChain. Es decir, puedes usarlo de la misma manera que usarías la interfaz de LLM de OpenAI, por ejemplo.

Si tienes varias GPU en tu máquina, debes especificar cuál usar. En este caso, quiero usar la GPU con índice 0:

config.init_device="cuda:0"model.to(device='cuda:0')pipe = transformers.pipeline("text-generation", model=model, tokenizer=tokenizer, max_new_tokens=100, device=0)

Algunos parámetros adicionales que he configurado arriba se pueden explicar de la siguiente manera:

  • trust_remote_code: Esto debe establecerse en true para permitir ejecutar un modelo proveniente de fuera de LangChain.
  • max_new_tokens: Esto define el número máximo de tokens que el modelo puede producir en su respuesta. Si este valor es demasiado bajo, la respuesta del modelo puede ser truncada antes de que pueda responder la pregunta por completo.

Conectar todo

Tenemos todos los componentes que necesitamos. Solo tenemos que conectarlos todos. Foto de John Barkiple en Unsplash

Ahora tenemos todos los componentes que necesitamos y podemos combinarlos en una ConversationalRetrievalChain.

from langchain.chains import ConversationalRetrievalChainqa_chain = ConversationalRetrievalChain.from_llm(llm=llm, retriever=retriever, return_source_documents=True)

Finalmente, podemos consultar la cadena para responder nuestras preguntas. El objeto de resultado incluirá una respuesta en lenguaje natural y una lista de source_documents que se consultaron para llegar a esa respuesta.

result = qa_chain({"question":"¿Cuál es el tipo de retorno de la función create_index en KNNRetriever?", "chat_history":[]})print(f"Respuesta: {result['answer']}")print(f"Fuentes: {[x.metadata['source'] for x in result['source_documents']]}")

Aquí está la respuesta:

Respuesta: El tipo de retorno de la función create_index en KNNRetriever es np.ndarray.Fuentes: ['sample_code/langchain/retrievers/knn.py', 'sample_code/langchain/vectorstores/elastic_vector_search.py', 'sample_code/langchain/vectorstores/elastic_vector_search.py', 'sample_code/langchain/vectorstores/opensearch_vector_search.py']

Resumen

¡Hemos terminado! Bueno, más o menos. Con el código anterior, ahora podemos hacer preguntas sobre el código fuente. Sin embargo, hay algunos pasos que quizás desees modificar según tus necesidades:

  • Usar tu propio código fuente como documentos en lugar del código de LangChain.
  • Probar un embedding diferente. Si el embedding no encaja, el recuperador no podrá encontrar los documentos correctos y, al final, las preguntas no podrán responderse con precisión.
  • Probar un modelo diferente. Hay modelos más grandes y más potentes disponibles, pero algunos pueden ser demasiado grandes para ejecutar en tu hardware. Debes encontrar el punto óptimo donde tengas un rendimiento decente pero aún puedas ejecutar el modelo de manera satisfactoria.
  • Probar diferentes formas de preprocesar los documentos para facilitar el paso de recuperación. Un ejemplo común sería dividirlos en fragmentos de igual longitud.

Estoy seguro de que hay mucho más que probar para obtener un mejor rendimiento. Solo experimenta y adapta el bot a tus necesidades.

Lectura adicional

Para obtener más ejemplos de comprensión de código con LangChain, echa un vistazo a su documentación aquí:

  • https://python.langchain.com/docs/use_cases/code/

En HuggingFace puedes encontrar modelos y embeddings que puedes usar fácilmente en LangChain:

  • https://huggingface.co/models

¿Te ha gustado este artículo? Sígueme para recibir notificaciones sobre mis futuras publicaciones.

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

Aumenta la productividad en Amazon SageMaker Studio Presentamos JupyterLab Spaces y herramientas de inteligencia artificial generativa

Amazon SageMaker Studio ofrece un conjunto amplio de entornos de desarrollo integrados completamente administrados (I...

Inteligencia Artificial

Ajustando la Tela de la IA Generativa FABRIC es un enfoque de IA que personaliza los modelos de difusión con retroalimentación iterativa

La inteligencia artificial generativa es un término con el que todos estamos familiarizados en la actualidad. Han ava...

Inteligencia Artificial

Los 5 mejores cursos de IA generativa para hacer en 2023

Introducción Es imperativo mantenerse actualizado sobre la información y habilidades más recientes relacionadas con l...

Aprendizaje Automático

Tienes que ajustar esas dimensiones DreamEditor es un modelo de IA que edita escenas en 3D utilizando indicaciones de texto.

El dominio de visión por computadora 3D se ha inundado de NeRF en los últimos años. Surgieron como una técnica innova...

Noticias de Inteligencia Artificial

Prohibido el ingreso a tiendas de comestibles mediante reconocimiento facial

El uso del reconocimiento facial por parte de empresas privadas en el Reino Unido está en aumento.