В этом руководстве мы сосредоточимся на том, как создать инструмент CLI, отвечающий на вопросы, с использованием Dewy и LangChain.js. Dewy — это база знаний с открытым исходным кодом, которая помогает разработчикам эффективно организовывать и извлекать информацию. LangChain.js — это платформа, упрощающая интеграцию больших языковых моделей (LLM) в приложения. Объединив возможности Dewy по управлению знаниями с интеграцией LLM LangChain.js, вы можете создавать инструменты, которые отвечают на сложные запросы, предоставляя точную и актуальную информацию.
В этом руководстве вы узнаете, как настроить среду, загрузить документы в Dewy и использовать LLM через LangChain.js для ответа на вопросы на основе сохраненных данных. Он предназначен для инженеров, желающих улучшить свои проекты с помощью расширенных функций ответов на вопросы.
Dewy — это база знаний OSS, предназначенная для оптимизации способа хранения, организации и извлечения информации разработчиками. Гибкость и простота использования делают его отличным выбором для разработчиков, стремящихся создавать приложения, основанные на знаниях.
LangChain.js , с другой стороны, представляет собой мощную платформу, которая позволяет разработчикам легко интегрировать LLM в свои приложения. Объединив структурированное управление знаниями Dewy с возможностями LLM LangChain.js, разработчики могут создавать сложные системы ответов на вопросы, которые могут понимать и обрабатывать сложные запросы, предлагая точные и контекстуально соответствующие ответы.
Наша цель — создать простой, но мощный сценарий командной строки для ответов на вопросы. Этот скрипт позволит пользователям загружать документы в базу знаний Dewy, а затем использовать LLM через LangChain.js для ответа на вопросы на основе информации, хранящейся в Dewy. Это руководство проведет вас через весь процесс: от настройки среды до реализации сценария CLI.
Вы узнаете, как использовать LangChain для создания простого приложения, отвечающего на вопросы, и как интегрировать Dewy в качестве источника знаний, позволяя вашему приложению отвечать на вопросы на основе конкретных документов, которые вы ему предоставляете.
Прежде чем приступить к изучению руководства, убедитесь, что у вас выполнены следующие предварительные требования:
Окончательный код этого примера доступен в репозитории Dewy , если вы хотите пойти дальше.
Сначала создайте каталог для проекта TypeScript CLI и перейдите в каталог.
mkdir dewy_qa cd dewy_qa
После настройки каталога вы можете установить TypeScript и инициализировать проект:
npm init -y npm i typescript --save-dev npx tsc --init
В зависимости от вашей среды вам может потребоваться внести некоторые изменения в конфигурацию TypeScript. Убедитесь, что ваш tsconfig.json
выглядит примерно так:
{ "compilerOptions": { "target": "ES6", "module": "CommonJS", "moduleResolution": "node", "declaration": true, "outDir": "./dist", "esModuleInterop": true, "strict": true, }
Теперь вы готовы создать приложение CLI. Чтобы код не был слишком запутанным, разложите его по нескольким каталогам следующим образом:
dewy_qa/ ├── commands/ │ └── ... ├── utils/ │ └── ... ├── index.ts ├── package.json └── tsconfig.ts
Каждая команда будет реализована в каталоге commands
, а общий код — в каталоге utils
. Точкой входа в приложение CLI является файл index.ts
.
Начните с простой версии index.ts
«привет, мир» — вы начнете заполнять ее в следующем разделе.
#!/usr/bin/env ts-node-script console.log("hello world");
Чтобы убедиться, что среда настроена правильно, попробуйте выполнить следующую команду — вы должны увидеть «hello world», напечатанное в консоли:
npx ts-node index.ts
Вместо того, чтобы каждый раз вводить эту очень длинную команду, давайте создадим запись для этой команды в package.json
. Это поможет нам запомнить, как вызывать CLI, и облегчит установку с помощью команды:
{ ... "bin": { "dewy_qa": "./index.ts" } ... }
Теперь вы можете запустить свой скрипт с помощью npm exec dewy_qa
или npm link
пакет и запустить его как просто dewy_qa
Загрузите документы, настроив клиент Dewy. Первым шагом является добавление некоторых зависимостей в проект. Первая — dewy-ts
, клиентская библиотека для Dewy. Второй — commander
, который поможет нам создать приложение CLI с анализом аргументов, подкомандами и многим другим. Наконец, chalk
чтобы сделать подсказки более красочными.
npm install dewy-ts commander chalk
Затем реализуйте логику команды загрузки. Вы сделаете это в отдельном файле с именем commands/load.ts
. Этот файл реализует функцию с именем load
, которая ожидает URL-адрес и некоторые дополнительные параметры — это будет связано с CLI в следующем разделе.
Dewy делает загрузку документов очень простой — просто настройте клиент и вызовите addDocument
, указав URL-адрес файла, который вы хотите загрузить. Dewy берет на себя извлечение содержимого PDF-файла, разбивает его на фрагменты подходящего размера для отправки в LLM и индексирует их для семантического поиска.
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}`)); } }
Возможно, вы заметили, что некоторые функции были импортированы из ../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);
Благодаря возможности загружать документы в Dewy пришло время интегрировать LangChain.js, чтобы использовать LLM для ответов на вопросы. Этот шаг включает настройку LangChain.js для запроса базы знаний Dewy и обработки результатов с использованием LLM для генерации ответов.
Для начала установите несколько дополнительных пакетов — langchain
и openai
, чтобы использовать OpenAI API в качестве LLM:
npm install dewy-langchain langchain @langchain/openai openai
Эта команда довольно длинная, поэтому мы рассмотрим несколько ее частей, прежде чем объединить их в конце.
Первое, что нужно настроить, — это Dewy (как и раньше) и LLM. Единственное отличие от предыдущего заключается в том, что dewy
используется для создания DewyRetriever
: это специальный тип, используемый LangChain для получения информации как части цепочки. Всего за минуту вы увидите, как используется ретривер.
const model = new ChatOpenAI({ openAIApiKey: options.openai_api_key, }); const dewy = new Dewy({ BASE: options.dewy_endpoint }) const retriever = new DewyRetriever({ dewy, collection });
Это строковый шаблон, который указывает LLM, как ему следует себя вести, с заполнителями для дополнительного контекста, который будет предоставлен при создании «цепочки». В этом случае LLM поручается ответить на вопрос, но только используя предоставленную информацию. Это уменьшает склонность модели «галлюцинировать» или давать правдоподобный, но неправильный ответ. Значения context
и question
предоставляются на следующем шаге:
const prompt = PromptTemplate.fromTemplate(`Answer the question based only on the following context: {context} Question: {question}`);
LangChain работает путем создания «цепочек» поведения, которые контролируют, как запрашивать LLM и другие источники данных. В этом примере используется LCEL , который обеспечивает более гибкий интерфейс программирования, чем некоторые оригинальные интерфейсы LangChain.
Используйте RunnableSequence
для создания цепочки LCEL. Эта цепочка описывает, как генерировать значения context
и question
: контекст генерируется с использованием созданного ранее средства извлечения, а вопрос генерируется путем передачи входных данных шага. Результаты, которые получает Дьюи, форматируются как строка путем передачи их в функцию formatDocumentsAsString
.
Эта цепочка выполняет следующие действия:
DewyRetriever
, присваивает их context
и присваивает входное значение цепочки question
.context
и question
. const chain = RunnableSequence.from([ { context: retriever.pipe(formatDocumentsAsString), question: new RunnablePassthrough(), }, prompt, model, new StringOutputParser(), ]);
Теперь, когда цепочка построена, выполните ее и выведите результаты на консоль. Как вы увидите, question
— это входной аргумент, предоставляемый вызывающей функцией.
Выполнение цепочки с помощью chain.streamLog()
позволяет вам видеть каждый фрагмент ответа в том виде, в котором он возвращается из LLM. Цикл обработчика потока уродлив, но он просто фильтрует соответствующие результаты потока и записывает их в 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); } } }
Теперь, когда вы рассмотрели все части, вы готовы создать команду 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}`)); } }
После интеграции Dewy и LangChain.js следующим шагом будет создание интерфейса CLI. Используйте такую библиотеку, как commander
, чтобы создать удобный интерфейс командной строки, который поддерживает команды для загрузки документов в Dewy и запроса базы знаний с помощью LangChain.js.
Сначала перепишите index.ts
, чтобы создать подкоманды load
и query
. Аргумент --collection
определяет, в какую коллекцию Dewy следует загрузить документ (Dewy позволяет организовывать документы в разные коллекции, аналогично папкам с файлами). Аргумент --dewy-endpoint
позволяет указать способ подключения к Dewy — по умолчанию предполагается, что экземпляр работает локально на порту 8000
. Наконец, аргумент --openai_api_key
(по умолчанию это переменная среды) настраивает OpenAI API:
#!/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);
Хорошо, все готово, разве это не было легко? Вы можете попробовать это, выполнив команду:
dewy_qa load https://arxiv.org/pdf/2009.08553.pdf
Вы должны увидеть что-то вроде
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 }
Извлечение содержимого большого PDF-файла может занять минуту или две, поэтому при первой загрузке нового документа вы часто будете видеть "ingest_state": "pending"
.
Затем попробуйте задать несколько вопросов:
dewy_qa query "tell me about RAG
Вы должны увидеть что-то вроде
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...
Следуя этому руководству, вы узнали, как создать интерфейс командной строки, который использует Dewy для управления знаниями и LangChain.js для обработки вопросов и генерации ответов. Этот инструмент демонстрирует практическое применение сочетания структурированной базы знаний с аналитическими возможностями LLM, что позволяет разработчикам создавать более интеллектуальные и быстро реагирующие приложения.