⚡ Creación de aplicaciones basadas en LLM en Ruby ⚡
Para una integración profunda de Rails, consulte: langchainrb_rails gem.
¡Disponible para contratos de consultoría pagados! Envíame un correo electrónico.
Instale la gema y agréguela al Gemfile de la aplicación ejecutando:
bundle add langchainrb
Si el paquete no se utiliza para administrar dependencias, instale la gema ejecutando:
gem install langchainrb
Es posible que se requieran gemas adicionales. No están incluidos de forma predeterminada, por lo que puedes incluir solo lo que necesitas.
require "langchain"
El módulo Langchain::LLM
proporciona una interfaz unificada para interactuar con varios proveedores de modelos de lenguaje grande (LLM). Esta abstracción le permite cambiar fácilmente entre diferentes backends de LLM sin cambiar el código de su aplicación.
Todas las clases LLM heredan de Langchain::LLM::Base
y proporcionan una interfaz consistente para operaciones comunes:
La mayoría de las clases de LLM se pueden inicializar con una clave API y opciones predeterminadas opcionales:
llm = Langchain :: LLM :: OpenAI . new (
api_key : ENV [ "OPENAI_API_KEY" ] ,
default_options : { temperature : 0.7 , chat_model : "gpt-4o" }
)
Utilice el método embed
para generar incrustaciones para un texto determinado:
response = llm . embed ( text : "Hello, world!" )
embedding = response . embedding
embed()
text
: (Obligatorio) El texto de entrada que se va a incrustar.model
: (Opcional) Se utilizará el nombre del modelo a usar o el modelo de incrustación predeterminado. Utilice el método complete
para generar terminaciones para un mensaje determinado:
response = llm . complete ( prompt : "Once upon a time" )
completion = response . completion
complete()
prompt
: (Obligatorio) El mensaje de entrada para completar.max_tokens
: (opcional) la cantidad máxima de tokens a generar.temperature
: (Opcional) Controla la aleatoriedad en la generación. Los valores más altos (por ejemplo, 0,8) hacen que la producción sea más aleatoria, mientras que los valores más bajos (por ejemplo, 0,2) la hacen más determinista.top_p
: (Opcional) Una alternativa a la temperatura, controla la diversidad de tokens generados.n
: (Opcional) Número de finalizaciones que se generarán para cada mensaje.stop
: (opcional) secuencias en las que la API dejará de generar más tokens.presence_penalty
: (Opcional) Penaliza nuevos tokens según su presencia en el texto hasta el momento.frequency_penalty
: (Opcional) Penaliza nuevos tokens según su frecuencia en el texto hasta el momento. Utilice el método chat
para generar finalizaciones de 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
: (obligatorio) una matriz de objetos de mensaje que representan el historial de conversaciones.model
: (Opcional) El modelo de chat específico que se utilizará.temperature
: (Opcional) Controla la aleatoriedad en la generación.top_p
: (Opcional) Una alternativa a la temperatura, controla la diversidad de tokens generados.n
: (Opcional) Número de opciones de finalización del chat para generar.max_tokens
: (Opcional) La cantidad máxima de tokens que se generarán al finalizar el chat.stop
: (Opcional) Secuencias en las que la API dejará de generar más tokens.presence_penalty
: (Opcional) Penaliza nuevos tokens según su presencia en el texto hasta el momento.frequency_penalty
: (Opcional) Penaliza nuevos tokens según su frecuencia en el texto hasta el momento.logit_bias
: (Opcional) Modifica la probabilidad de que aparezcan tokens específicos en la finalización.user
: (opcional) un identificador único que representa a su usuario final.tools
: (Opcional) Una lista de herramientas que el modelo puede llamar.tool_choice
: (Opcional) Controla cómo el modelo llama a las funciones. Gracias a la interfaz unificada, puede cambiar fácilmente entre diferentes proveedores de LLM cambiando la clase que crea una instancia:
# 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" ] )
Cada método LLM devuelve un objeto de respuesta que proporciona una interfaz coherente para acceder a los resultados:
embedding
: Devuelve el vector de incrustacióncompletion
: Devuelve la finalización del texto generado.chat_completion
: Devuelve la finalización del chat generado.tool_calls
: Devuelve llamadas a herramientas realizadas por el LLMprompt_tokens
: devuelve el número de tokens en el mensaje.completion_tokens
: Devuelve el número de tokens en la finalizacióntotal_tokens
: Devuelve el número total de tokens utilizados Nota
Si bien la interfaz principal es coherente entre los proveedores, algunos LLM pueden ofrecer funciones o parámetros adicionales. Consulte la documentación de cada clase de LLM para conocer las capacidades y opciones específicas del proveedor.
Cree un mensaje con variables de entrada:
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."
Crear un PromptTemplate usando solo un mensaje y sin variables de entrada:
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."
Guarde la plantilla de aviso en un archivo JSON:
prompt . save ( file_path : "spec/fixtures/prompt/prompt_template.json" )
Cargando una nueva plantilla de aviso usando un archivo JSON:
prompt = Langchain :: Prompt . load_from_path ( file_path : "spec/fixtures/prompt/prompt_template.json" )
prompt . input_variables # ["adjective", "content"]
Cree un mensaje con algunos ejemplos de tomas:
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:
Guarde la plantilla de aviso en un archivo JSON:
prompt . save ( file_path : "spec/fixtures/prompt/few_shot_prompt_template.json" )
Cargando una nueva plantilla de aviso usando un archivo 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."
Cargando una nueva plantilla de aviso usando un archivo YAML:
prompt = Langchain :: Prompt . load_from_path ( file_path : "spec/fixtures/prompt/prompt_template.yaml" )
prompt . input_variables #=> ["adjective", "content"]
Analice las respuestas de texto de LLM en resultados estructurados, como JSON.
Puede utilizar StructuredOutputParser
para generar un mensaje que indique al LLM que proporcione una respuesta JSON que se adhiera a un esquema JSON específico:
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.
# ...
Luego analice la respuesta de 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
# },
# ...
# ]
# }
Si el analizador no puede analizar la respuesta de LLM, puede utilizar OutputFixingParser
. Envía un mensaje de error, un resultado anterior y el texto del mensaje original al LLM, solicitando una respuesta "fija":
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
Alternativamente, si no necesita manejar OutputParserException
, puede simplificar el código:
# 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 )
Vea aquí un ejemplo concreto.
RAG es una metodología que ayuda a los LLM a generar información precisa y actualizada. Un flujo de trabajo típico de RAG sigue los 3 pasos siguientes:
Langchain.rb proporciona una cómoda interfaz unificada además de las bases de datos de búsqueda de vectores compatibles que facilitan la configuración de su índice, agregar datos, realizar consultas y recuperarlos.
Base de datos | Código abierto | Oferta en la nube |
---|---|---|
croma | ✅ | ✅ |
Epsilla | ✅ | ✅ |
Hnswlib | ✅ | |
milvus | ✅ | ✅ Nube Zilliz |
Piña | ✅ | |
Pgvector | ✅ | ✅ |
Qdrant | ✅ | ✅ |
Weaviate | ✅ | ✅ |
búsqueda elástica | ✅ | ✅ |
Elija la base de datos de búsqueda de vectores que utilizará, agregue la dependencia de la gema y cree una instancia del cliente:
gem "weaviate-ruby" , "~> 0.8.9"
Elija y cree una instancia del proveedor LLM que utilizará para generar incrustaciones
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
)
Puede crear una instancia de cualquier otra base de datos de búsqueda de vectores compatible:
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"`
Cree el esquema predeterminado:
client . create_default_schema
Agregue datos de texto sin formato a su base de datos de búsqueda de vectores:
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."
]
)
O utilice los analizadores de archivos para cargar, analizar e indexar datos en su base de datos:
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 ] )
Formatos de archivo admitidos: docx, html, pdf, texto, json, jsonl, csv, xlsx, eml, pptx.
Recupere documentos similares según la cadena de consulta pasada:
client . similarity_search (
query : ,
k : # number of results to be retrieved
)
Recupere documentos similares basados en la cadena de consulta pasada mediante la técnica HyDE:
client . similarity_search_with_hyde ( )
Recupere documentos similares según la incrustación pasada en:
client . similarity_search_by_vector (
embedding : ,
k : # number of results to be retrieved
)
Consulta basada en RAG
client . ask ( question : "..." )
Langchain::Assistant
es una clase potente y flexible que combina modelos de lenguajes grandes (LLM), herramientas y gestión de conversaciones para crear asistentes inteligentes e interactivos. Está diseñado para manejar conversaciones complejas, ejecutar herramientas y proporcionar respuestas coherentes basadas en el contexto de la interacción.
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 )
Tenga en cuenta que la transmisión por secuencias no es compatible actualmente con todos los LLM.
llm
: la instancia de LLM a utilizar (obligatorio)tools
: una variedad de instancias de herramientas (opcional)instructions
: Instrucciones del sistema para el asistente (opcional)tool_choice
: especifica cómo se deben seleccionar las herramientas. Valor predeterminado: "automático". Se puede pasar un nombre de función de herramienta específica. Esto obligará al Asistente a utilizar siempre esta función.parallel_tool_calls
: si se deben realizar múltiples llamadas a herramientas paralelas. Predeterminado: verdaderoadd_message_callback
: una función de devolución de llamada (proc, lambda) que se llama cuando se agrega cualquier mensaje a la conversación (opcional) assistant . add_message_callback = -> ( message ) { puts "New message: #{ message } " }
tool_execution_callback
: una función de devolución de llamada (proc, lambda) que se llama justo antes de ejecutar una herramienta (opcional) 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
: agrega un mensaje de usuario a la matriz de mensajesrun!
: Procesa la conversación y genera respuestas.add_message_and_run!
: Combina agregar un mensaje y ejecutar el asistentesubmit_tool_output
: envía manualmente la salida a una llamada de herramientamessages
: devuelve una lista de mensajes en cursoLangchain::Tool::Calculator
: Útil para evaluar expresiones matemáticas. Requiere gem "eqn"
.Langchain::Tool::Database
: Conecte su base de datos SQL. Requiere gem "sequel"
.Langchain::Tool::FileSystem
: Interactuar con el sistema de archivos (lectura y escritura).Langchain::Tool::RubyCodeInterpreter
: útil para evaluar el código Ruby generado. Requiere gem "safe_ruby"
(se necesita una solución mejor).Langchain::Tool::NewsRetriever
: un contenedor de NewsApi.org para buscar artículos de noticias.Langchain::Tool::Tavily
: un envoltorio de la IA de Tavily.Langchain::Tool::Weather
: llama a Open Weather API para recuperar el clima actual.Langchain::Tool::Wikipedia
: Llama a la API de Wikipedia. Langchain::Assistant se puede ampliar fácilmente con herramientas personalizadas creando clases que extend Langchain::ToolDefinition
e implementan los métodos necesarios.
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
El asistente incluye manejo de errores para entradas no válidas, tipos de LLM no admitidos y fallas en la ejecución de herramientas. Utiliza una máquina de estado para gestionar el flujo de la conversación y manejar diferentes escenarios con elegancia.
El módulo Evaluaciones es una colección de herramientas que se pueden utilizar para evaluar y rastrear el rendimiento de los productos de salida de LLM y sus procesos RAG (Generación Aumentada de Recuperación).
Ragas lo ayuda a evaluar sus tuberías de generación aumentada de recuperación (RAG). La implementación se basa en este documento y en el repositorio original de Python. Ragas rastrea las siguientes 3 métricas y asigna puntuaciones de 0,0 a 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
# }
Ejemplos adicionales disponibles: /ejemplos
Langchain.rb utiliza el mecanismo estándar Ruby Logger y por defecto tiene el mismo valor level
(actualmente Logger::DEBUG
).
Para mostrar todos los mensajes de registro:
Langchain . logger . level = Logger :: DEBUG
El registrador inicia sesión en STDOUT
de forma predeterminada. Para configurar el destino del registro (es decir, iniciar sesión en un archivo), haga lo siguiente:
Langchain . logger = Logger . new ( "path/to/file" , ** Langchain :: LOGGER_OPTIONS )
Si tiene problemas para instalar la gema unicode
requerida por pragmatic_segmenter
, intente ejecutar:
gem install unicode -- --with-cflags= " -Wno-incompatible-function-pointer-types "
git clone https://github.com/andreibondarev/langchainrb.git
cp .env.example .env
, luego complete las variables de entorno en .env
bundle exec rake
para garantizar que las pruebas pasen y ejecutar standardrbbin/console
para cargar la gema en una sesión REPL. Siéntase libre de agregar sus propias instancias de LLM, herramientas, agentes, etc. y experimentar con ellos.gem install lefthook && lefthook install -f
Únase a nosotros en el servidor Langchain.rb Discord.
Los informes de errores y las solicitudes de extracción son bienvenidos en GitHub en https://github.com/andreibondarev/langchainrb.
La gema está disponible como código abierto según los términos de la licencia MIT.