En este tutorial, nos centramos en cómo crear una herramienta CLI de respuesta a preguntas utilizando Dewy y LangChain.js. Dewy es una base de conocimientos de código abierto que ayuda a los desarrolladores a organizar y recuperar información de manera eficiente. LangChain.js es un marco que simplifica la integración de grandes modelos de lenguaje (LLM) en aplicaciones. Al combinar las capacidades de Dewy para gestionar el conocimiento con la integración LLM de LangChain.js, puede crear herramientas que respondan consultas complejas con información precisa y relevante. Esta guía lo guiará a través de la configuración de su entorno, la carga de documentos en Dewy y el uso de un LLM a través de LangChain.js para responder preguntas basadas en los datos almacenados. Está diseñado para ingenieros que buscan mejorar sus proyectos con funcionalidades avanzadas de respuesta a preguntas. ¿Por qué Dewy y LangChain.js? es una base de conocimientos de OSS diseñada para optimizar la forma en que los desarrolladores almacenan, organizan y recuperan información. Su flexibilidad y facilidad de uso lo convierten en una excelente opción para los desarrolladores que desean crear aplicaciones basadas en el conocimiento. Dewy , por otro lado, es un marco poderoso que permite a los desarrolladores integrar LLM en sus aplicaciones sin problemas. Al combinar la gestión del conocimiento estructurado de Dewy con las capacidades LLM de LangChain.js, los desarrolladores pueden crear sofisticados sistemas de respuesta a preguntas que pueden comprender y procesar consultas complejas, ofreciendo respuestas precisas y contextualmente relevantes. LangChain.js La meta Nuestro objetivo es crear un script CLI de respuesta a preguntas simple pero potente. Este script permitirá a los usuarios cargar documentos en la base de conocimientos de Dewy y luego utilizar un LLM, a través de LangChain.js, para responder preguntas basadas en la información almacenada en Dewy. Este tutorial lo guiará a través del proceso, desde la configuración de su entorno hasta la implementación del script CLI. Aprenderá cómo utilizar LangChain para crear una aplicación sencilla de respuesta a preguntas y cómo integrar Dewy como fuente de conocimiento, permitiendo que su aplicación responda preguntas basadas en documentos específicos que usted le proporcione. Requisitos previos Antes de sumergirse en el tutorial, asegúrese de tener cubiertos los siguientes requisitos previos: Conocimientos básicos de programación mecanografiada. Familiaridad con el desarrollo de herramientas CLI. Una copia de Dewy ejecutándose en su máquina local (consulte de Dewy si necesita ayuda aquí). las instrucciones de instalación Paso 1: configura tu proyecto El código final para este ejemplo está disponible si desea avanzar. en el repositorio de Dewy Primero, cree un directorio para el proyecto CLI de TypeScript y cámbielo al directorio mkdir dewy_qa cd dewy_qa Con el directorio configurado, puede instalar TypeScript e inicializar el proyecto: npm init -y npm i typescript --save-dev npx tsc --init Dependiendo de su entorno, es posible que deba realizar algunos cambios en su configuración de TypeScript. Asegúrese de que su se parezca a lo siguiente: tsconfig.json { "compilerOptions": { "target": "ES6", "module": "CommonJS", "moduleResolution": "node", "declaration": true, "outDir": "./dist", "esModuleInterop": true, "strict": true, } Ahora está listo para crear la aplicación CLI. Para evitar que el código se ensucie demasiado, organícelo en varios directorios, con el siguiente diseño dewy_qa/ ├── commands/ │ └── ... ├── utils/ │ └── ... ├── index.ts ├── package.json └── tsconfig.ts Cada comando se implementará en el directorio y el código compartido irá al directorio . El punto de entrada a la aplicación CLI es el archivo . commands utils index.ts Comience con una versión simple de "hola mundo" de ; comenzará a completarla en la siguiente sección index.ts #!/usr/bin/env ts-node-script console.log("hello world"); Para verificar que el entorno esté configurado correctamente, intente ejecutar el siguiente comando; debería ver "hola mundo" impreso en la consola: npx ts-node index.ts En lugar de escribir este comando muy largo cada vez, creemos una entrada en para el comando. Esto nos ayudará a recordar cómo invocar la CLI y facilitará la instalación como un comando: package.json { ... "bin": { "dewy_qa": "./index.ts" } ... } Ahora puede ejecutar su script con o el paquete y ejecutarlo simplemente como npm exec dewy_qa npm link dewy_qa Paso 2: implementar la carga de documentos Cargue documentos configurando el cliente Dewy. El primer paso es agregar algunas dependencias al proyecto. El primero es , la biblioteca cliente de Dewy. El segundo es , que nos ayudará a crear una aplicación CLI con análisis de argumentos, subcomandos y más. Finalmente, para que las indicaciones sean más coloridas. dewy-ts commander chalk npm install dewy-ts commander chalk A continuación, implemente la lógica del comando de carga. Hará esto en un archivo separado llamado . Este archivo implementa una función llamada , que espera una URL y algunas opciones adicionales; esto se conectará con la CLI en una sección posterior. commands/load.ts load Dewy hace que la carga de documentos sea súper simple: simplemente configure el cliente y llame a con la URL del archivo que desea cargar. Dewy se encarga de extraer el contenido del PDF, dividirlo en fragmentos del tamaño adecuado para enviarlos a un LLM e indexarlos para una búsqueda semántica. addDocument import { Dewy } from 'dewy-ts'; import { success, error } from '../utils/colors'; export async function load(url: string, options: { collection: string, dewy_endpoint: string }): Promise<void> { console.log(success(`Loading ${url} into collection: ${options.collection}`)); try { const dewy = new Dewy({ BASE: options.dewy_endpoint }) const result = await dewy.kb.addDocument({ collection: options.collection, url }); console.log(success(`File loaded successfully`)); console.log(JSON.stringify(result, null, 2)); } catch (err: any) { console.error(error(`Failed to load file: ${err.message}`)); } } Es posible que hayas notado que algunas funciones se importaron desde . Este archivo simplemente configura algunos asistentes para colorear la salida de la consola; colóquelo en para que pueda usarse en otros lugares: ../utils/colors utils import chalk from 'chalk'; export const success = (message: string) => chalk.green(message); export const info = (message: string) => chalk.blue(message); export const error = (message: string) => chalk.red(message); Paso 3: implementar la respuesta a preguntas Con la capacidad de cargar documentos en Dewy, es hora de integrar LangChain.js para utilizar LLM para responder preguntas. Este paso implica configurar LangChain.js para consultar la base de conocimientos de Dewy y procesar los resultados utilizando un LLM para generar respuestas. Para comenzar, instale algunos paquetes adicionales: y para usar la API de OpenAI como LLM: langchain openai npm install dewy-langchain langchain @langchain/openai openai Este comando es algo largo, por lo que repasaremos varias partes antes de combinarlas al final. Cree clientes para OpenAI y Dewy Lo primero que hay que configurar es Dewy (como antes) y un LLM. Una diferencia con respecto a antes es que se usa para construir un : este es un tipo especial usado por LangChain para recuperar información como parte de una cadena. Verás cómo se utiliza el retriever en tan sólo un minuto. dewy DewyRetriever const model = new ChatOpenAI({ openAIApiKey: options.openai_api_key, }); const dewy = new Dewy({ BASE: options.dewy_endpoint }) const retriever = new DewyRetriever({ dewy, collection }); Crear un mensaje LangChain Esta es una plantilla de cadena que indica al LLM cómo debe comportarse, con marcadores de posición para contexto adicional que se proporcionarán cuando se cree la "cadena". En este caso, el LLM debe responder la pregunta, pero únicamente utilizando la información que se le proporciona. Esto reduce la tendencia del modelo a "alucinar" o inventar una respuesta que sea plausible pero incorrecta. Los valores de y se proporcionan en el siguiente paso: context question const prompt = PromptTemplate.fromTemplate(`Answer the question based only on the following context: {context} Question: {question}`); Construye la cadena LangChain funciona construyendo "cadenas" de comportamiento que controlan cómo consultar el LLM y otras fuentes de datos. Este ejemplo utiliza , que proporciona una experiencia de programación más flexible que algunas de las interfaces originales de LangChain. LCEL Utilice para crear una cadena LCEL. Esta cadena describe cómo generar el y los valores : el contexto se genera utilizando el recuperador creado anteriormente y la pregunta se genera pasando por la entrada del paso. Los resultados que recupera Dewy se formatean como una cadena canalizándolos a la función . RunnableSequence context question formatDocumentsAsString Esta cadena hace lo siguiente: Recupera documentos utilizando , los asigna al y asigna el valor de entrada de la cadena a . DewyRetriever context question Da formato a la cadena de solicitud utilizando las variables y . context question Pasa el mensaje formateado al LLM para generar una respuesta. Formatea la respuesta del LLM como una cadena. const chain = RunnableSequence.from([ { context: retriever.pipe(formatDocumentsAsString), question: new RunnablePassthrough(), }, prompt, model, new StringOutputParser(), ]); Ejecutar la cadena Ahora que se ha construido la cadena, ejecútela y envíe los resultados a la consola. Como verá, es un argumento de entrada proporcionado por quien llama a la función. question La ejecución de la cadena usando le permite ver cada fragmento de respuesta tal como lo devuelve el LLM. El bucle del controlador de transmisión es algo feo, pero solo filtra los resultados de la transmisión apropiados y los escribe en (usando habría agregado nuevas líneas después de cada fragmento). chain.streamLog() STDOUT console.log const stream = await chain.streamLog(question); // Write chunks of the response to STDOUT as they're received console.log("Answer:"); for await (const chunk of stream) { if (chunk.ops?.length > 0 && chunk.ops[0].op === "add") { const addOp = chunk.ops[0]; if ( addOp.path.startsWith("/logs/ChatOpenAI") && typeof addOp.value === "string" && addOp.value.length ) { process.stdout.write(addOp.value); } } } Júntelo todo como un comando Ahora que ha visto todas las piezas, está listo para crear el comando . Esto debería ser similar al comando anterior, con algunas importaciones adicionales. query load import { StringOutputParser } from "@langchain/core/output_parsers"; import { PromptTemplate } from "@langchain/core/prompts"; import { formatDocumentsAsString } from "langchain/util/document"; import { RunnablePassthrough, RunnableSequence } from "@langchain/core/runnables"; import { ChatOpenAI } from "@langchain/openai"; import { Dewy } from 'dewy-ts'; import { DewyRetriever } from 'dewy-langchain'; import { success, error } from '../utils/colors'; export async function query(question: string, options: { collection: string, dewy_endpoint: string, openai_api_key: string }): Promise<void> { console.log(success(`Querying ${options.collection} collection for: "${question}"`)); try { const model = new ChatOpenAI({ openAIApiKey: options.openai_api_key, }); const dewy = new Dewy({ BASE: options.dewy_endpoint }) const retriever = new DewyRetriever({ dewy, collection: options.collection }); const prompt = PromptTemplate.fromTemplate(`Answer the question based only on the following context: {context} Question: {question}`); const chain = RunnableSequence.from([ { context: retriever.pipe(formatDocumentsAsString), question: new RunnablePassthrough(), }, prompt, model, new StringOutputParser(), ]); const stream = await chain.streamLog(question); // Write chunks of the response to STDOUT as they're received console.log("Answer:"); for await (const chunk of stream) { if (chunk.ops?.length > 0 && chunk.ops[0].op === "add") { const addOp = chunk.ops[0]; if ( addOp.path.startsWith("/logs/ChatOpenAI") && typeof addOp.value === "string" && addOp.value.length ) { process.stdout.write(addOp.value); } } } } catch (err: any) { console.error(error(`Failed to query: ${err.message}`)); } } Paso 4: construir la CLI Con Dewy y LangChain.js integrados, el siguiente paso es crear la interfaz CLI. Utilice una biblioteca como para crear una interfaz de línea de comandos fácil de usar que admita comandos para cargar documentos en Dewy y consultar la base de conocimientos utilizando LangChain.js. commander Primero, reescriba para crear los subcomandos y . El argumento determina en qué colección de Dewy se debe cargar el documento (Dewy le permite organizar documentos en diferentes colecciones, similar a las carpetas de archivos). El argumento le permite especificar cómo conectarse a Dewy; de forma predeterminada, se asume una instancia que se ejecuta localmente en el puerto . Finalmente, el argumento (que por defecto es una variable de entorno) configura la API de OpenAI: index.ts load query --collection --dewy-endpoint 8000 --openai_api_key #!/usr/bin/env ts-node-script import { Command } from 'commander'; import { load } from './commands/load'; import { query } from './commands/query'; const program = new Command(); program.name('dewy-qa').description('CLI tool for interacting with a knowledge base API').version('1.0.0'); const defaultOpenAIKey = process.env.OPENAI_API_KEY; program .command('load') .description("Load documents into Dewy from a URL") .option('--collection <collection>', 'Specify the collection name', 'main') .option('--dewy-endpoint <endpoint>', 'Specify the collection name', 'http://localhost:8000') .argument('<url>', 'URL to load into the knowledge base') .action(load); program .command('query') .description('Ask questions using an LLM and the loaded documents for answers') .option('--collection <collection>', 'Specify the collection name', 'main') .option('--dewy-endpoint <endpoint>', 'Specify the collection name', 'http://localhost:8000') .option('--openai-api-key <key>', 'Specify the collection name', defaultOpenAIKey) .argument('<question>', 'Question to ask the knowledge base') .action(query); program.parse(process.argv); Bien, ya está todo hecho. ¿No fue tan fácil? Puedes probarlo ejecutando el comando: dewy_qa load https://arxiv.org/pdf/2009.08553.pdf Deberías ver algo como Loading https://arxiv.org/pdf/2009.08553.pdf into collection: main File loaded successfully { "id": 18, "collection": "main", "extracted_text": null, "url": "https://arxiv.org/pdf/2009.08553.pdf", "ingest_state": "pending", "ingest_error": null } Extraer el contenido de un PDF grande puede llevar uno o dos minutos, por lo que a menudo verá cuando cargue un documento nuevo por primera vez. "ingest_state": "pending" A continuación, intente hacer algunas preguntas: dewy_qa query "tell me about RAG Deberías ver algo como Querying main collection for: "tell me about RAG" Answer: Based on the given context, RAG refers to the RAG proteins, which are involved in DNA binding and V(D)J recombination. The RAG1 and RAG2 proteins work together to bind specific DNA sequences known as RSS (recombination signal sequences) and facilitate the cutting and rearrangement of DNA segments during the process of V(D)J recombination... Conclusión Siguiendo esta guía, ha aprendido a crear una CLI que utiliza Dewy para gestionar el conocimiento y LangChain.js para procesar preguntas y generar respuestas. Esta herramienta demuestra la aplicación práctica de combinar una base de conocimientos estructurada con el poder analítico de los LLM, lo que permite a los desarrolladores crear aplicaciones más inteligentes y receptivas. Lecturas y recursos adicionales Repositorio Dewy GitHub: https://github.com/Dewy Repositorio del cliente Dewy TypeScript: https://github.com/DewyKB/dewy-ts Repositorio de integración de Dewy LangChain: https://github.com/DewyKB/dewy_langchainjs Documentación de LangChain.js: https://js.langchain.com Documentación de OpenAI: https://platform.opnai.com