⚡ Создание приложений на базе LLM на Ruby ⚡
Для глубокой интеграции с Rails см.: langchainrb_rails gem.
Возможна платная консультация! Напишите мне.
Установите драгоценный камень и добавьте его в Gemfile приложения, выполнив:
bundle add langchainrb
Если упаковщик не используется для управления зависимостями, установите драгоценный камень, выполнив:
gem install langchainrb
Могут потребоваться дополнительные драгоценные камни. Они не включены по умолчанию, поэтому вы можете включить только то, что вам нужно.
require "langchain"
Модуль Langchain::LLM
предоставляет унифицированный интерфейс для взаимодействия с различными поставщиками моделей большого языка (LLM). Эта абстракция позволяет вам легко переключаться между различными серверами LLM без изменения кода приложения.
Все классы LLM наследуют от Langchain::LLM::Base
и предоставляют согласованный интерфейс для общих операций:
Большинство классов LLM можно инициализировать с помощью ключа API и дополнительных параметров по умолчанию:
llm = Langchain :: LLM :: OpenAI . new (
api_key : ENV [ "OPENAI_API_KEY" ] ,
default_options : { temperature : 0.7 , chat_model : "gpt-4o" }
)
Используйте метод embed
для создания вложений для данного текста:
response = llm . embed ( text : "Hello, world!" )
embedding = response . embedding
embed()
text
: (Обязательно) Входной текст для встраивания.model
: (необязательно) будет использовано имя модели или модель внедрения по умолчанию. Используйте метод complete
для создания дополнений для данного приглашения:
response = llm . complete ( prompt : "Once upon a time" )
completion = response . completion
complete()
prompt
: (Обязательно) Подсказка для завершения ввода.max_tokens
: (Необязательно) Максимальное количество токенов для генерации.temperature
: (Необязательно) Управляет случайностью генерации. Более высокие значения (например, 0,8) делают вывод более случайным, а более низкие значения (например, 0,2) делают его более детерминированным.top_p
: (Необязательно) Альтернатива температуре, контролирует разнообразие генерируемых токенов.n
: (Необязательно) Количество завершений, создаваемых для каждого запроса.stop
: (Необязательно) Последовательности, при которых API прекращает генерировать дальнейшие токены.presence_penalty
: (Необязательно) Наказывает новые токены в зависимости от их присутствия в тексте на данный момент.frequency_penalty
: (Необязательно) Наказывает новые токены в зависимости от их частоты в тексте на данный момент. Используйте метод chat
для генерации завершений чата:
messages = [
{ role : "system" , content : "You are a helpful assistant." } ,
{ role : "user" , content : "What's the weather like today?" }
# Google Gemini and Google VertexAI expect messages in a different format:
# { role: "user", parts: [{ text: "why is the sky blue?" }]}
]
response = llm . chat ( messages : messages )
chat_completion = response . chat_completion
chat()
messages
: (Обязательно) Массив объектов сообщений, представляющих историю разговоров.model
: (Необязательно) Конкретная модель чата, которую нужно использовать.temperature
: (Необязательно) Управляет случайностью генерации.top_p
: (Необязательно) Альтернатива температуре, контролирует разнообразие генерируемых токенов.n
: (Необязательно) Количество вариантов завершения чата, которые нужно сгенерировать.max_tokens
: (Необязательно) Максимальное количество токенов, которые можно сгенерировать при завершении чата.stop
: (Необязательно) Последовательности, при которых API прекращает генерировать дальнейшие токены.presence_penalty
: (Необязательно) Наказывает новые токены в зависимости от их присутствия в тексте на данный момент.frequency_penalty
: (Необязательно) Наказывает новые токены в зависимости от их частоты в тексте на данный момент.logit_bias
: (Необязательно) Изменяет вероятность появления указанных токенов в завершении.user
: (Необязательно) Уникальный идентификатор, представляющий вашего конечного пользователя.tools
: (Необязательно) Список инструментов, которые может вызывать модель.tool_choice
: (Необязательно) Управляет тем, как модель вызывает функции. Благодаря унифицированному интерфейсу вы можете легко переключаться между разными поставщиками LLM, изменяя экземпляр класса:
# Using Anthropic
anthropic_llm = Langchain :: LLM :: Anthropic . new ( api_key : ENV [ "ANTHROPIC_API_KEY" ] )
# Using Google Gemini
gemini_llm = Langchain :: LLM :: GoogleGemini . new ( api_key : ENV [ "GOOGLE_GEMINI_API_KEY" ] )
# Using OpenAI
openai_llm = Langchain :: LLM :: OpenAI . new ( api_key : ENV [ "OPENAI_API_KEY" ] )
Каждый метод LLM возвращает объект ответа, который предоставляет согласованный интерфейс для доступа к результатам:
embedding
: Возвращает вектор внедрения.completion
: возвращает сгенерированное завершение текста.chat_completion
: Возвращает сгенерированное завершение чата.tool_calls
: Возвращает вызовы инструментов, сделанные LLM.prompt_tokens
: Возвращает количество токенов в приглашении.completion_tokens
: возвращает количество токенов в завершении.total_tokens
: возвращает общее количество использованных токенов. Примечание
Хотя основной интерфейс у всех поставщиков одинаков, некоторые LLM могут предлагать дополнительные функции или параметры. Ознакомьтесь с документацией для каждого класса LLM, чтобы узнать о возможностях и опциях конкретного поставщика.
Создайте приглашение с входными переменными:
prompt = Langchain :: Prompt :: PromptTemplate . new ( template : "Tell me a {adjective} joke about {content}." , input_variables : [ "adjective" , "content" ] )
prompt . format ( adjective : "funny" , content : "chickens" ) # "Tell me a funny joke about chickens."
Создание PromptTemplate с использованием только приглашения и без входных_переменных:
prompt = Langchain :: Prompt :: PromptTemplate . from_template ( "Tell me a funny joke about chickens." )
prompt . input_variables # []
prompt . format # "Tell me a funny joke about chickens."
Сохраните шаблон приглашения в файл JSON:
prompt . save ( file_path : "spec/fixtures/prompt/prompt_template.json" )
Загрузка нового шаблона приглашения с использованием файла JSON:
prompt = Langchain :: Prompt . load_from_path ( file_path : "spec/fixtures/prompt/prompt_template.json" )
prompt . input_variables # ["adjective", "content"]
Создайте подсказку с несколькими примерами снимков:
prompt = Langchain :: Prompt :: FewShotPromptTemplate . new (
prefix : "Write antonyms for the following words." ,
suffix : "Input: {adjective} n Output:" ,
example_prompt : Langchain :: Prompt :: PromptTemplate . new (
input_variables : [ "input" , "output" ] ,
template : "Input: {input} n Output: {output}"
) ,
examples : [
{ "input" : "happy" , "output" : "sad" } ,
{ "input" : "tall" , "output" : "short" }
] ,
input_variables : [ "adjective" ]
)
prompt . format ( adjective : "good" )
# Write antonyms for the following words.
#
# Input: happy
# Output: sad
#
# Input: tall
# Output: short
#
# Input: good
# Output:
Сохраните шаблон приглашения в файл JSON:
prompt . save ( file_path : "spec/fixtures/prompt/few_shot_prompt_template.json" )
Загрузка нового шаблона приглашения с использованием файла JSON:
prompt = Langchain :: Prompt . load_from_path ( file_path : "spec/fixtures/prompt/few_shot_prompt_template.json" )
prompt . prefix # "Write antonyms for the following words."
Загрузка нового шаблона приглашения с использованием файла YAML:
prompt = Langchain :: Prompt . load_from_path ( file_path : "spec/fixtures/prompt/prompt_template.yaml" )
prompt . input_variables #=> ["adjective", "content"]
Анализируйте текстовые ответы LLM в структурированный вывод, например JSON.
Вы можете использовать StructuredOutputParser
для создания запроса, который инструктирует LLM предоставить ответ JSON, соответствующий определенной схеме JSON:
json_schema = {
type : "object" ,
properties : {
name : {
type : "string" ,
description : "Persons name"
} ,
age : {
type : "number" ,
description : "Persons age"
} ,
interests : {
type : "array" ,
items : {
type : "object" ,
properties : {
interest : {
type : "string" ,
description : "A topic of interest"
} ,
levelOfInterest : {
type : "number" ,
description : "A value between 0 and 100 of how interested the person is in this interest"
}
} ,
required : [ "interest" , "levelOfInterest" ] ,
additionalProperties : false
} ,
minItems : 1 ,
maxItems : 3 ,
description : "A list of the person's interests"
}
} ,
required : [ "name" , "age" , "interests" ] ,
additionalProperties : false
}
parser = Langchain :: OutputParsers :: StructuredOutputParser . from_json_schema ( json_schema )
prompt = Langchain :: Prompt :: PromptTemplate . new ( template : "Generate details of a fictional character. n {format_instructions} n Character description: {description}" , input_variables : [ "description" , "format_instructions" ] )
prompt_text = prompt . format ( description : "Korean chemistry student" , format_instructions : parser . get_format_instructions )
# Generate details of a fictional character.
# You must format your output as a JSON value that adheres to a given "JSON Schema" instance.
# ...
Затем проанализируйте ответ llm:
llm = Langchain :: LLM :: OpenAI . new ( api_key : ENV [ "OPENAI_API_KEY" ] )
llm_response = llm . chat ( messages : [ { role : "user" , content : prompt_text } ] ) . completion
parser . parse ( llm_response )
# {
# "name" => "Kim Ji-hyun",
# "age" => 22,
# "interests" => [
# {
# "interest" => "Organic Chemistry",
# "levelOfInterest" => 85
# },
# ...
# ]
# }
Если анализатору не удается проанализировать ответ LLM, вы можете использовать OutputFixingParser
. Он отправляет сообщение об ошибке, предварительный вывод и исходный текст приглашения в LLM, запрашивая «фиксированный» ответ:
begin
parser . parse ( llm_response )
rescue Langchain :: OutputParsers :: OutputParserException => e
fix_parser = Langchain :: OutputParsers :: OutputFixingParser . from_llm (
llm : llm ,
parser : parser
)
fix_parser . parse ( llm_response )
end
Альтернативно, если вам не нужно обрабатывать OutputParserException
, вы можете упростить код:
# we already have the `OutputFixingParser`:
# parser = Langchain::OutputParsers::StructuredOutputParser.from_json_schema(json_schema)
fix_parser = Langchain :: OutputParsers :: OutputFixingParser . from_llm (
llm : llm ,
parser : parser
)
fix_parser . parse ( llm_response )
См. здесь конкретный пример
RAG — это методология, которая помогает LLM генерировать точную и актуальную информацию. Типичный рабочий процесс RAG состоит из трех следующих шагов:
Langchain.rb предоставляет удобный унифицированный интерфейс поверх поддерживаемых баз данных векторного поиска, который позволяет легко настраивать индекс, добавлять данные, выполнять запросы и извлекать из него данные.
База данных | с открытым исходным кодом | Облачное предложение |
---|---|---|
Цветность | ✅ | ✅ |
Эпсилла | ✅ | ✅ |
Hnswlib | ✅ | |
Милвус | ✅ | ✅ Облако Зиллиз |
Сосновая шишка | ✅ | |
Пгвектор | ✅ | ✅ |
Кдрант | ✅ | ✅ |
Плетение | ✅ | ✅ |
Эластичный поиск | ✅ | ✅ |
Выберите базу данных векторного поиска, которую вы будете использовать, добавьте зависимость драгоценного камня и создайте экземпляр клиента:
gem "weaviate-ruby" , "~> 0.8.9"
Выберите и создайте экземпляр поставщика LLM, который вы будете использовать для создания вложений.
llm = Langchain :: LLM :: OpenAI . new ( api_key : ENV [ "OPENAI_API_KEY" ] )
client = Langchain :: Vectorsearch :: Weaviate . new (
url : ENV [ "WEAVIATE_URL" ] ,
api_key : ENV [ "WEAVIATE_API_KEY" ] ,
index_name : "Documents" ,
llm : llm
)
Вы можете создать экземпляр любой другой поддерживаемой базы данных поиска векторов:
client = Langchain :: Vectorsearch :: Chroma . new ( ... ) # `gem "chroma-db", "~> 0.6.0"`
client = Langchain :: Vectorsearch :: Epsilla . new ( ... ) # `gem "epsilla-ruby", "~> 0.0.3"`
client = Langchain :: Vectorsearch :: Hnswlib . new ( ... ) # `gem "hnswlib", "~> 0.8.1"`
client = Langchain :: Vectorsearch :: Milvus . new ( ... ) # `gem "milvus", "~> 0.9.3"`
client = Langchain :: Vectorsearch :: Pinecone . new ( ... ) # `gem "pinecone", "~> 0.1.6"`
client = Langchain :: Vectorsearch :: Pgvector . new ( ... ) # `gem "pgvector", "~> 0.2"`
client = Langchain :: Vectorsearch :: Qdrant . new ( ... ) # `gem "qdrant-ruby", "~> 0.9.3"`
client = Langchain :: Vectorsearch :: Elasticsearch . new ( ... ) # `gem "elasticsearch", "~> 8.2.0"`
Создайте схему по умолчанию:
client . create_default_schema
Добавьте текстовые данные в вашу базу данных векторного поиска:
client . add_texts (
texts : [
"Begin by preheating your oven to 375°F (190°C). Prepare four boneless, skinless chicken breasts by cutting a pocket into the side of each breast, being careful not to cut all the way through. Season the chicken with salt and pepper to taste. In a large skillet, melt 2 tablespoons of unsalted butter over medium heat. Add 1 small diced onion and 2 minced garlic cloves, and cook until softened, about 3-4 minutes. Add 8 ounces of fresh spinach and cook until wilted, about 3 minutes. Remove the skillet from heat and let the mixture cool slightly." ,
"In a bowl, combine the spinach mixture with 4 ounces of softened cream cheese, 1/4 cup of grated Parmesan cheese, 1/4 cup of shredded mozzarella cheese, and 1/4 teaspoon of red pepper flakes. Mix until well combined. Stuff each chicken breast pocket with an equal amount of the spinach mixture. Seal the pocket with a toothpick if necessary. In the same skillet, heat 1 tablespoon of olive oil over medium-high heat. Add the stuffed chicken breasts and sear on each side for 3-4 minutes, or until golden brown."
]
)
Или используйте парсеры файлов для загрузки, анализа и индексации данных в вашу базу данных:
my_pdf = Langchain . root . join ( "path/to/my.pdf" )
my_text = Langchain . root . join ( "path/to/my.txt" )
my_docx = Langchain . root . join ( "path/to/my.docx" )
client . add_data ( paths : [ my_pdf , my_text , my_docx ] )
Поддерживаемые форматы файлов: docx, html, pdf, текст, json, jsonl, csv, xlsx, eml, pptx.
Получить похожие документы на основе переданной строки запроса:
client . similarity_search (
query : ,
k : # number of results to be retrieved
)
Получите похожие документы на основе строки запроса, переданной с помощью технологии HyDE:
client . similarity_search_with_hyde ( )
Получить аналогичные документы на основе встраивания, переданного в:
client . similarity_search_by_vector (
embedding : ,
k : # number of results to be retrieved
)
Запросы на основе RAG
client . ask ( question : "..." )
Langchain::Assistant
— это мощный и гибкий класс, который сочетает в себе модели большого языка (LLM), инструменты и управление диалогами для создания интеллектуальных интерактивных помощников. Он предназначен для обработки сложных диалогов, выполнения инструментов и предоставления последовательных ответов в зависимости от контекста взаимодействия.
llm = Langchain :: LLM :: OpenAI . new ( api_key : ENV [ "OPENAI_API_KEY" ] )
assistant = Langchain :: Assistant . new (
llm : llm ,
instructions : "You're a helpful AI assistant" ,
tools : [ Langchain :: Tool :: NewsRetriever . new ( api_key : ENV [ "NEWS_API_KEY" ] ) ]
)
# Add a user message and run the assistant
assistant . add_message_and_run! ( content : "What's the latest news about AI?" )
# Supply an image to the assistant
assistant . add_message_and_run! (
content : "Show me a picture of a cat" ,
image_url : "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
)
# Access the conversation thread
messages = assistant . messages
# Run the assistant with automatic tool execution
assistant . run ( auto_tool_execution : true )
# If you want to stream the response, you can add a response handler
assistant = Langchain :: Assistant . new (
llm : llm ,
instructions : "You're a helpful AI assistant" ,
tools : [ Langchain :: Tool :: NewsRetriever . new ( api_key : ENV [ "NEWS_API_KEY" ] ) ]
) do | response_chunk |
# ...handle the response stream
# print(response_chunk.inspect)
end
assistant . add_message ( content : "Hello" )
assistant . run ( auto_tool_execution : true )
Обратите внимание, что потоковая передача в настоящее время поддерживается не для всех LLM.
llm
: используемый экземпляр LLM (обязательно)tools
: массив экземпляров инструментов (необязательно).instructions
: Системные инструкции для помощника (опционально).tool_choice
: определяет, как следует выбирать инструменты. По умолчанию: «авто». Можно передать определенное имя функции инструмента. Это заставит Ассистента всегда использовать эту функцию.parallel_tool_calls
: следует ли выполнять несколько параллельных вызовов инструментов. По умолчанию: правдаadd_message_callback
: функция обратного вызова (proc, лямбда), которая вызывается, когда в разговор добавляется какое-либо сообщение (необязательно). assistant . add_message_callback = -> ( message ) { puts "New message: #{ message } " }
tool_execution_callback
: функция обратного вызова (proc, лямбда), которая вызывается непосредственно перед выполнением инструмента (необязательно). assistant . tool_execution_callback = -> ( tool_call_id , tool_name , method_name , tool_arguments ) { puts "Executing tool_call_id: #{ tool_call_id } , tool_name: #{ tool_name } , method_name: #{ method_name } , tool_arguments: #{ tool_arguments } " }
add_message
: добавляет сообщение пользователя в массив сообщений.run!
: Обрабатывает разговор и генерирует ответы.add_message_and_run!
: объединяет добавление сообщения и запуск помощника.submit_tool_output
: вручную отправить вывод на вызов инструмента.messages
: Возвращает список текущих сообщений.Langchain::Tool::Calculator
: полезен для вычисления математических выражений. Требуется gem "eqn"
.Langchain::Tool::Database
: подключите базу данных SQL. Требуется gem "sequel"
.Langchain::Tool::FileSystem
: Взаимодействие с файловой системой (чтение и запись).Langchain::Tool::RubyCodeInterpreter
: полезен для оценки сгенерированного кода Ruby. Требуется gem "safe_ruby"
(нужно лучшее решение).Langchain::Tool::NewsRetriever
: оболочка NewsApi.org для получения новостных статей.Langchain::Tool::Tavily
: оболочка вокруг Tavily AI.Langchain::Tool::Weather
: вызывает API открытой погоды для получения текущей погоды.Langchain::Tool::Wikipedia
: вызывает API Wikipedia. Langchain::Assistant можно легко расширить с помощью пользовательских инструментов, создав классы, которые extend Langchain::ToolDefinition
и реализуют необходимые методы.
class MovieInfoTool
extend Langchain :: ToolDefinition
define_function :search_movie , description : "MovieInfoTool: Search for a movie by title" do
property :query , type : "string" , description : "The movie title to search for" , required : true
end
define_function :get_movie_details , description : "MovieInfoTool: Get detailed information about a specific movie" do
property :movie_id , type : "integer" , description : "The TMDb ID of the movie" , required : true
end
def initialize ( api_key : )
@api_key = api_key
end
def search_movie ( query : )
...
end
def get_movie_details ( movie_id : )
...
end
end
movie_tool = MovieInfoTool . new ( api_key : "..." )
assistant = Langchain :: Assistant . new (
llm : llm ,
instructions : "You're a helpful AI assistant that can provide movie information" ,
tools : [ movie_tool ]
)
assistant . add_message_and_run ( content : "Can you tell me about the movie 'Inception'?" )
# Check the response in the last message in the conversation
assistant . messages . last
Помощник включает обработку ошибок недопустимых входных данных, неподдерживаемых типов LLM и сбоев выполнения инструмента. Он использует конечный автомат для управления потоком разговора и корректной обработки различных сценариев.
Модуль «Оценки» представляет собой набор инструментов, которые можно использовать для оценки и отслеживания производительности выходных продуктов с помощью LLM и ваших конвейеров RAG (Поиск дополненной генерации).
Ragas помогает вам оценить ваши конвейеры извлечения дополненной генерации (RAG). Реализация основана на этой статье и исходном репозитории Python. Рагас отслеживает следующие три показателя и присваивает баллы от 0,0 до 1,0:
# We recommend using Langchain::LLM::OpenAI as your llm for Ragas
ragas = Langchain :: Evals :: Ragas :: Main . new ( llm : llm )
# The answer that the LLM generated
# The question (or the original prompt) that was asked
# The context that was retrieved (usually from a vectorsearch database)
ragas . score ( answer : "" , question : "" , context : "" )
# =>
# {
# ragas_score: 0.6601257446503674,
# answer_relevance_score: 0.9573145866787608,
# context_relevance_score: 0.6666666666666666,
# faithfulness_score: 0.5
# }
Доступны дополнительные примеры: /examples
Langchain.rb использует стандартный механизм Ruby Logger и по умолчанию использует значение того же level
(в настоящее время Logger::DEBUG
).
Чтобы отобразить все сообщения журнала:
Langchain . logger . level = Logger :: DEBUG
По умолчанию регистратор регистрируется в STDOUT
. Чтобы настроить место назначения журнала (т. е. журнал в файл), выполните:
Langchain . logger = Logger . new ( "path/to/file" , ** Langchain :: LOGGER_OPTIONS )
Если у вас возникли проблемы с установкой драгоценного камня unicode
, необходимого для pragmatic_segmenter
, попробуйте запустить:
gem install unicode -- --with-cflags= " -Wno-incompatible-function-pointer-types "
git clone https://github.com/andreibondarev/langchainrb.git
cp .env.example .env
, затем заполните переменные среды в .env
bundle exec rake
чтобы убедиться, что тесты пройдены, и запустить стандартный rbbin/console
для загрузки драгоценного камня в сеансе REPL. Не стесняйтесь добавлять свои собственные экземпляры LLM, инструментов, агентов и т. д. и экспериментировать с ними.gem install lefthook && lefthook install -f
Присоединяйтесь к нам на сервере Discord Langchain.rb.
Отчеты об ошибках и запросы на включение приветствуются на GitHub по адресу https://github.com/andreibondarev/langchainrb.
Гем доступен с открытым исходным кодом в соответствии с условиями лицензии MIT.