Orquestación de agentes de LLM: guía paso a paso con LangChain y Granite

Autor

Vrunda Gadesha

AI Advocate | Technical Content Author

La orquestación de agentes LLM se refiere al proceso de gestión y coordinación de las interacciones entre un Modelo de lenguaje grande (LLM) y varias herramientas, API o procesos para realizar tareas complejas dentro de los sistemas de IA. Implica estructurar flujos de trabajo en los que un agente de IA, impulsado por inteligencia artificial, actúa como el motor de razonamiento central, orquestando sus acciones en función de las entradas, el contexto y los resultados de sistemas externos. Mediante una infraestructura de orquestación, los LLM pueden integrarse perfectamente con API, bases de datos y otras aplicaciones de IA, habilitando funcionalidades como chatbots y herramientas de automatización. Los marcos de infraestructura de código abierto mejoran aún más la adaptabilidad de estos sistemas, lo que hace que los LLM sean más efectivos en escenarios del mundo real.

Muchas personas malinterpretan la diferencia entre la orquestación LLM y la orquestación de agentes LLM. La siguiente ilustración destaca las diferencias clave:

En este tutorial, aprenderá a crear un agente autónomo impulsado por modelos de lenguaje de gran tamaño (LLM) mediante modelos de IBM Granite y LangChain. Exploraremos cómo los agentes aprovechan componentes clave como la memoria, la planificación y la acción para realizar tareas inteligentes. También implementará un sistema práctico que procesa el texto de un libro, responde a las consultas de forma dinámica y evalúa su rendimiento mediante el uso de métricas de precisión como BLEU, precisión, recuperación y puntuación F1.

Marco para agentes autónomos basados en LLM

El marco presentado en la figura 1 proporciona un diseño holístico para agentes autónomos basados en modelos de lenguaje extensos, enfatizando la interacción entre los componentes clave: perfil, memoria, planificación y acción. Cada componente representa una etapa crítica en la construcción de un agente autónomo capaz de razonar, tomar decisiones e interactuar con entornos dinámicos.1

1. Perfil: definición de la identidad del agente

El perfil le da al agente su identidad por medio de la incorporación de información como datos demográficos, rasgos de personalidad y contexto social. Este proceso garantiza que el agente pueda interactuar de manera personalizada. Los perfiles pueden elaborarse manualmente, generarse mediante modelos de IA generativa, como los modelos IBM Granite o GPT (transformador generativo preentrenado) de OpenAI, o alinearse con conjuntos de datos específicos para cumplir con los requisitos de las tareas. Aprovechando la ingeniería rápida, los perfiles se pueden refinar dinámicamente para optimizar las respuestas. Además, dentro de la orquestación multiagente, el perfil ayuda a definir roles y comportamientos, lo que garantiza una coordinación perfecta entre los algoritmos de IA y los sistemas de toma de decisiones.

2. Memoria: almacenar y usar el contexto

La memoria ayuda al agente a retener y recuperar interacciones pasadas, lo que permite respuestas contextuales. Puede ser unificado (todos los datos en un solo lugar) o híbrido (estructurado y no estructurado). Las operaciones que incluyen lectura, escritura y reflexión permiten al agente aprender de la experiencia y proporcionar resultados coherentes e informados. Una memoria bien estructurada mejora la orquestación multiagente al garantizar que diferentes agentes, incluidos los agentes especializados diseñados para una tarea específica, puedan compartir y recuperar datos relevantes de manera eficiente. En infraestructuras como AutoGen y Crew IA, la memoria desempeña un papel crucial en el mantenimiento de la continuidad dentro del ecosistema de agentes colaboradores, lo que garantiza una coordinación perfecta y una ejecución optimizada de las tareas.

3. Planificación: estrategias de acciones

El componente de planificación permite al agente diseñar estrategias para alcanzar los objetivos. Puede seguir pasos predefinidos o adaptarse dinámicamente en función del feedback del entorno, los humanos o el propio LLM. Al integrar algoritmos de IA y aprovechar una base de conocimientos, la planificación se puede optimizar para mejorar la eficiencia del razonamiento y la precisión en la resolución de problemas. En las aplicaciones LLM, la planificación desempeña un papel crucial para garantizar que la comprensión del lenguaje natural y los procesos de toma de decisiones se alineen con los objetivos del agente. Además, las técnicas de recuperación aumentada mejoran la capacidad del agente para acceder a la información relevante de forma dinámica, mejorando la precisión de la respuesta. Esta flexibilidad garantiza que el agente siga siendo eficaz en escenarios cambiantes, especialmente en la orquestación multiagente, en la que varios agentes coordinan sus planes para lograr objetivos complejos mientras mantienen la escalabilidad para manejar tareas grandes y diversas.

4. Acción: ejecutar decisiones

Las acciones son la forma en que el agente interactúa con el mundo, ya sea completando tareas, recopilando información o comunicándose. Utiliza la memoria y la planificación para guiar la ejecución, emplea herramientas cuando es necesario y adapta su estado interno en función de los resultados para la mejora continua. La optimización del algoritmo de ejecución de acciones garantiza la eficiencia, especialmente al integrar modelos de razonamiento impulsados por GPT y técnicas de IA generativa para la toma de decisiones en tiempo real.

Al combinar estos componentes, la infraestructura transforma los LLM en agentes adaptables capaces de razonar, aprender y realizar tareas de forma autónoma. Este diseño modular lo hace ideal para aplicaciones como atención al cliente, asistencia en investigación y resolución creativa de problemas.

Caso de uso: creación de un agente de conocimiento consultable

Este tutorial demuestra la creación de un agente de conocimiento consultable diseñado para procesar documentos de texto grandes (como libros) y responder a las consultas de los usuarios con precisión. Utilizando modelos de IBM Granite y LangChain, el agente se crea siguiendo los principios descritos en el marco para agentes autónomos basados en LLM. Los componentes de la infraestructura se alinean perfectamente con el flujo de trabajo del agente para garantizar la adaptabilidad y las respuestas inteligentes.

Comprendamos cómo se aplica el marco en nuestro caso de uso.

Perfil: el agente está diseñado con un perfil de "asistente de conocimientos", que se centra en tareas de resumen, respuesta a preguntas y razonamiento. Su contexto está personalizado para procesar un documento específico (por ejemplo, Las aventuras de Sherlock Holmes).

Memoria: el agente emplea memoria híbrida mediante la incorporación de fragmentos del libro en un almacén de vectores FAISS. Esta capacidad le permite recuperar el contexto relevante de forma dinámica durante las consultas. Las operaciones de memoria, como la lectura (recuperación) y la escritura (actualización de incorporaciones), garantizan que el agente pueda adaptarse a nuevas consultas con el tiempo.

Planificación: la resolución de consultas implica un razonamiento de ruta única. El agente recupera fragmentos de texto relevantes, genera respuestas utilizando Granite LLM de IBM y evalúa la precisión de la salida. La planificación sin retroalimentación garantiza la simplicidad, mientras que la modularidad del sistema permite incorporar bucles de retroalimentación en iteraciones futuras.

Acción: el agente ejecuta la resolución de consultas integrando la recuperación de memoria y el procesamiento LLM. Completa tareas como generar respuestas, calcular métricas de precisión (BLEU, precisión, recuperación y puntuación F1) y visualizar resultados para la interpretación del usuario. Estos resultados reflejan la capacidad del agente para actuar de manera inteligente en función del razonamiento y la planificación.

Requisitos previos

Necesita una cuenta de IBM Cloud para crear un proyecto en watsonx.ai .

Pasos

Paso 1. Configure su entorno

Si bien puede elegir entre varias herramientas, este tutorial lo guiará a través de cómo configurar una cuenta de IBM mediante un Jupyter Notebook.

  1. Inicie sesión en watsonx.ai con su cuenta de IBM Cloud.
  2. 2. Cree un proyecto de watsonx.ai. Puede obtener su ID de proyecto desde dentro de su proyecto. Haga clic en la pestaña Administrar. Luego, copie el ID del proyecto de la sección Detalles de la página General. Necesita este ID para este tutorial.
  3. 3. Cree un Jupyter Notebook.

Este paso abre un entorno de notebook donde puede copiar el código de este tutorial. También puede descargar este cuaderno en su sistema local y cargarlo en su proyecto watsonx.ai como activo. Para ver más tutoriales de Granite, consulte la comunidad de IBM Granite. Este tutorial también está disponible en GitHub.

Paso 2. Configure el servicio de tiempo de ejecución de watsonx.ai y la clave de API

  1. Cree una instancia de servicio watsonx.ai Runtime (elija el plan Lite, que es una instancia gratuita).
  2. Genere una clave (API) de interfaz de programación de aplicaciones.
  3. Asocie el servicio de watsonx.ai Runtime al proyecto que creó en watsonx.ai.

Paso 3. Instalación de los paquetes

Para trabajar con la infraestructura LangChain e integrar IBM WatsonxLLM, necesitamos instalar algunas bibliotecas esenciales. Comencemos por instalar los paquetes necesarios:

Nota: Si está utilizando una versión anterior de pip, puede usar el comando instalar-actualizarpip , puede usar el comandopip install --upgrade pip para actualizar e instalar fácilmente los paquetes más recientes, que pueden no ser compatibles con versiones anteriores. Pero si ya está utilizando la última versión o actualizó recientemente sus paquetes, puede omitir este comando.

!pip install --upgrade pip
!pip install langchain faiss-cpu pandas sentence-transformers
%pip install langchain
!pip install langchain-ibm

En la celda de código anterior,

  • langchain  es el marco central para crear aplicaciones con modelos de lenguaje.
  • faiss-cpu  es para una búsqueda de similitud eficiente, utilizada para crear y consultar índices vectoriales.
  • Pandas  es para la manipulación y el análisis de datos.
  • transformadores de frase  es para generar incorporaciones para la búsqueda semántica.
  • langchain-ibm  es integrar IBM WatsonxLLM (en este tutorial es granite-3-8b-instruct) con LangChain.

Este paso garantiza que su entorno esté listo para las tareas futuras.

Paso 4. Importe las bibliotecas necesarias

Ahora que instalamos las bibliotecas necesarias, importemos los módulos necesarios para este tutorial:

import os
from langchain_ibm import WatsonxLLM
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
import pandas as pd
import getpass

En la celda de código anterior,

  • os  proporciona una forma de interactuar con el sistema operativo (por ejemplo, accediendo a variables de entorno).
  • langchain_ibm.WatsonxLLM  nos permite utilizar IBM Watson Granite LLM perfectamente dentro del marco LangChain.
  • langchain.incorporaciones.HuggingFaceIncorporaciones  genera incorporaciones para texto mediante el uso de modelos HuggingFace, esenciales para la búsqueda semántica.
  • langchain.vectorstores.FAISS  es una biblioteca para el almacenamiento eficiente de vectores y la búsqueda de similitudes, lo que nos permite crear y consultar un índice vectorial.
  • RecursiveCharacterTextSplitter  ayuda a dividir grandes bloques de texto en fragmentos más pequeños, lo cual es crítico para procesar documentos de manera eficiente.
  • Pandas  es una potente biblioteca para el análisis y la manipulación de datos, que se utiliza aquí para manejar datos tabulares.
  • getpass  es una forma segura de capturar entradas confidenciales, como claves API, sin mostrarlas en la pantalla.

Este paso configura todas las herramientas y módulos que necesitamos para procesar texto, crear incorporaciones, almacenarlos en una base de datos vectorial e interactuar con watsonxLLM de IBM.

Paso 5. Configure las credenciales

Este código establece las credenciales para acceder a la API de IBM watson machine learning (WML) y garantiza que el ID del proyecto esté configurado correctamente.

  • Un diccionariocomprometidas se crea con elURL del servicio WML YClave API . La clave API se recopila de forma segura mediante `getpass.getpass` para evitar exponer información confidencial.
  • El código intenta obtener el PROJECT_ID  de variables de entorno mediante os.environ . Si el PROJECT_ID  no se encuentra, se le da una instrucción al usuario para que lo ingrese manualmente a través de la entrada.
# Set up credentials
credentials = {
      "url": "https://us-south.ml.cloud.ibm.com", # Replace with the correct region if needed
      "apikey": getpass.getpass("Please enter your WML API key (hit enter): ")
     }
# Set up project_id
try:
     project_id = os.environ["PROJECT_ID"]
except KeyError:
     project_id = input("Please enter your project_id (hit enter): ")

Paso 6. Inicialice el modelo de lenguaje grande

Este código inicializa watsonxLLM IBM para su uso en la aplicación:

  1. Este código crea una instancia de watsonxLLM utilizando el modeloibm/granite-3-8b-instruct diseñado para tareas de IA generativa basadas en instrucciones.
  2. Hayurl ,clave api  yproject_id Los valores de las credenciales configuradas previamente se pasan para autenticar y conectarse al servicio watsonxLLM de IBM.
  3. Configura el parámetromax_new_tokens para limitar el número de tokens generados por el modelo en cada respuesta (150 tokens en este caso).

Este paso prepara watsonxLLM para generar respuestas en el flujo de trabajo.

# Initialize the IBM Granite LLM
llm = WatsonxLLM(
      model_id="ibm/granite-3-8b-instruct",
      url=credentials["url"],
      apikey=credentials["apikey"],
      project_id=project_id,
      params={
           "max_new_tokens": 150
      }
)

Paso 7. Defina una función para extraer texto de un archivo

Para procesar el texto de un documento, necesitamos una función que pueda leer y extraer su contenido. La siguiente función está diseñada para manejar archivos de texto sin formato:

def extract_text_from_txt(file_path):
      """Extracts text from a plain text file."""
           with open(file_path, "r", encoding="utf-8") as file:
           text = file.read()
return text

Esta función,extract_text_from_txt , está diseñada para leer y extraer el contenido de un archivo de texto sin formato. Acepta la ruta del archivo como argumento y abre el archivo en modo de lectura concodificación UTF-8 , asegurándose de que los caracteres especiales se manejen correctamente.

Todo el contenido del archivo se lee en una variable llamadatexto , que luego se entrega de nuevo. Esta función desempeña un papel crucial en la preparación de la entrada al extraer texto sin procesar del documento, dejándolo listo para operaciones posteriores, como fragmentación, incorporación y consulta. Proporciona una forma sencilla y eficiente de procesar datos textuales de cualquier archivo de texto sin formato.

Esta función nos permite procesar el archivo de entrada (Las aventuras de Sherlock Holmes) y extraer su contenido para otras operaciones, como fragmentación de texto e incorporación. Garantiza que el texto sin procesar esté fácilmente disponible para su análisis.

Paso 8. Divida el texto en fragmentos

Para procesar e indexar de manera eficiente grandes bloques de texto, necesitamos dividir el texto en fragmentos más pequeños y manejables. La siguiente función maneja esta tarea:

def split_text_into_chunks(text, chunk_size=500, chunk_overlap=50):
           """Splits text into smaller chunks for indexing."""
           splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
return splitter.split_text(text)

Haysplit_text_into_chunks la función está diseñada para dividir grandes bloques de texto en fragmentos más pequeños y manejables para un procesamiento y una indexación eficientes. Toma el texto sin procesar como entrada, junto con dos parámetros opcionales:chunk_size , que define el tamaño máximo de cada fragmento (el valor predeterminado es 500 caracteres), ychunk_overlap , que especifica el número de caracteres superpuestos entre fragmentos consecutivos (el valor predeterminado es 50).

Esta función garantiza la continuidad contextual en todos los fragmentos. La función utiliza elRecursiveCharacterTextSplitter deLangChain , que divide de forma inteligente el texto conservando su contexto. Al entregar una lista de fragmentos de texto más pequeños, esta función prepara la entrada para otras operaciones, como la incorporación y la indexación.

Es esencial cuando se trabaja con documentos grandes, ya que los modelos de lenguaje a menudo tienen limitaciones de token y no pueden procesar texto extenso directamente.

Paso 9: Cree un índice vectorial

Para permitir una búsqueda semántica eficaz, necesitamos convertir fragmentos de texto en incorporaciones vectoriales y almacenarlos en un índice de búsqueda. Este paso utiliza las incorporaciones FAISS y HuggingFace para crear el índice vectorial, formando la base para recuperar información relevante basada en consultas.

def create_vector_index(chunks):
           """Creates a FAISS vector index from text chunks."""
               embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
               vector_store = FAISS.from_texts(chunks, embeddings)
return vector_store

Haycreate_vector_index función construye unVector FAISS índice a partir de los fragmentos de texto generados en el paso anterior. Esta función es crucial para permitir la búsqueda semántica al mapear cada fragmento en un espacio vectorial de alta dimensión mediante el uso de incorporaciones.

Primero inicializa un modelo HuggingFaceEmbeddings sentence-transformers/all-MiniLM-L6-v2 que genera incorporaciones vectoriales para los fragmentos de texto. Estas incorporaciones capturan el significado semántico de cada trozo.

A continuación, la función utilizaFAISS para crear un almacén de vectores indexando estas incorporaciones, lo que permite una búsqueda de similitud eficiente más adelante.

El almacén de vectores resultante se regresa y se utilizará para encontrar fragmentos relevantes basados en las consultas de los usuarios, formando la columna vertebral del proceso de búsqueda y recuperación del agente.

Paso 10. Consulte el índice vectorial con Granite

Este paso implica consultar el índice vectorial para recuperar información relevante y utilizar LLM de Granite de IBM para generar una respuesta refinada. Al integrar la búsqueda de similitud y razonamiento LLM, la función proporciona un proceso de resolución de consultas dinámico e inteligente.

def query_index_with_granite_dynamic(vector_store, query, llm):
         """Searches the vector index, uses Granite to refine the response, and returns all components."""
             # Perform similarity search
             print("\n> Entering new AgentExecutor chain...")
             thought = f"The query '{query}' requires context from the book to provide an accurate response."
             print(f" Thought: {thought}")
             action = "Search FAISS Vector Store"
             print(f" Action: {action}")
             action_input = query
             print(f" Action Input: \"{action_input}\"")
             # Retrieve context
             results = vector_store.similarity_search(query, k=3)
             observation = "\n".join([result.page_content for result in results])
             print(f" Observation:\n{observation}\n")
            # Generate response with Granite
            prompt = f"Context:\n{observation}\n\nQuestion: {query}\nAnswer:"
            print(f" Thought: Combining retrieved context with the query to generate a detailed answer.")
            final_answer = llm(prompt)
            print(f" Final Answer: {final_answer.strip()}")
            print("\n> Finished chain.")
            # Return all components as a dictionary
            return {
                    "Thought": thought,
                     "Action": action,
                     "Action Input": action_input,
                     "Observation": observation,
                     "Final Answer": final_answer.strip()
                     }

Hayquery_index_with_granite_dynamic toma tres entradas: primero, el almacén de vectores (tienda vectorial ), segundo, la consulta del usuario (Consulta ) y tercero, la instancia de LLM de Granite (LLM ).

Primero realiza una búsqueda de similitud en el índice vectorial para recuperar los fragmentos de texto más relevantes. Estos fragmentos, denominadosobservación , se combinan en un único bloque de contexto.

Luego, la función construye una instrucción combinando la consulta y el contexto recuperado. Esta instrucción se pasa alLLM de Granite , que genera una respuesta detallada y contextualmente precisa (final_answer ).

A lo largo del proceso, los pasos intermedios, como elpensamiento ,la acción  yla entrada dentro de la acción  se imprimen para mayor transparencia.

Finalmente, la función recupera un diccionario que contiene todos los componentes, incluido el proceso de pensamiento, la acción tomada, la observación recuperada y la respuesta final.

Este paso es crítico para transformar la recuperación de datos sin procesar en insights aplicables en la práctica y significativos por medio de las capacidades de razonamiento del LLM.

Paso 11. Genere un "DataFrame" para los resultados de la consulta

Este paso procesa dinámicamente múltiples consultas, recupera información relevante y guarda los resultados en un formato estructurado para su análisis. La función integra capacidades de consulta, estructuración de datos y exportación.

def dynamic_output_to_dataframe(vector_store, queries, llm, csv_filename="output.csv"):
           """Generates a DataFrame dynamically for multiple queries and saves it as a CSV file."""
           # List to store all query outputs
           output_data = []
           # Process each query
           for query in queries:
           # Capture the output dynamically
           output = query_index_with_granite_dynamic(vector_store, query, llm)
           output_data.append(output)
           # Convert the list of dictionaries into a DataFrame
           df = pd.DataFrame(output_data)
           # Display the DataFrame
           print("\nFinal DataFrame:")
           print(df)
           # Save the DataFrame as a CSV file
           df.to_csv(csv_filename, index=False)
           print(f"\nOutput saved to {csv_filename}")

Haydynamic_output_to_dataframe  función acepta cuatro entradas: el almacén de vectores (tienda vectorial ), una lista de consultas (Consultas ), la instancia de LLM de Granite (LLM ) y un nombre de archivo CSV opcional (csv_filename , el valor predeterminado esoutput.csv ).

Para cada consulta, utiliza elquery_index_with_granite_dynamic  para recuperar el contexto relevante y generar una respuesta mediante el uso del LLM. Los resultados, incluidos los componentes intermedios, comoPensamiento ,Observación  yRespuesta final  se almacenan en una lista.

Una vez procesadas todas las consultas, la lista de resultados se convierte en un DataFrame de Pandas. Este formato tabular permite un fácil análisis y visualización de los resultados de la consulta. El DataFrame se imprime para su revisión y se guarda como un archivo CSV para uso futuro.

Este paso es esencial para organizar el resultado en un formato fácil de usar, lo que permite realizar tareas posteriores, como la evaluación de la precisión y la visualización.

Paso 12: Ejecute el flujo de trabajo principal

Este paso combina todos los pasos anteriores en un único flujo de trabajo para procesar un archivo de texto, responder a las consultas de los usuarios y guardar los resultados en un formato estructurado. La funciónmain_workflow sirve como orquestador central del tutorial.

def main_workflow():
           # Replace with your text file
           file_path = "aosh.txt"
           # Extract text from the text file
           text = extract_text_from_txt(file_path)
           # Split the text into chunks
           chunks = split_text_into_chunks(text)
           # Create a vector index
           vector_store = create_vector_index(chunks)
           # Define queries
           queries = [
                     "What is the plot of 'A Scandal in Bohemia'?",
                     "Who is Dr. Watson, and what role does he play in the stories?",
                     "Describe the relationship between Sherlock Holmes and Irene Adler.",
                     "What methods does Sherlock Holmes use to solve cases?"
                     ]
           # Generate and save output dynamically
          dynamic_output_to_dataframe(vector_store, queries, llm)

Comprendamos cómo se ejecuta este flujo de trabajo:

Entrada de un archivo de texto: elfile_path especifica el archivo de texto que se va a procesar. En este tutorial, el archivo de entrada es"aosh.txt" , que contiene el texto de Las aventuras de Sherlock Holmes.

Extracción de texto:extract_text_from_txt se llama a la función para leer y extraer el contenido del archivo de texto de entrada.

Fragmentación de texto: el texto extraído se divide en fragmentos más pequeños mediante lasplit_text_into_chunks función para facilitar la incorporación y la indexación.

Crear un índice vectorial: Los fragmentos de texto se convierten en incorporaciones y se almacenan en unVector FAISS índice empleandocreate_vector_index de negocio.

Definir consultas: se proporciona una lista de consultas de muestra, cada una diseñada para recuperar información específica del texto. Estas consultas serán respondidas por el agente.

Consultas del proceso: Eldynamic_output_to_dataframe  procesa las consultas mediante el índice vectorial y LLM de Granite de IBM. Recupera el contexto relevante, genera respuestas y guarda los resultados como un archivo CSV para su posterior análisis.

Este paso integra todos los componentes del tutorial en un flujo de trabajo cohesivo. Automatiza el proceso desde la extracción de texto hasta la resolución de consultas, lo que le permite probar las capacidades del agente y examinar los resultados en un formato estructurado.

Para ejecutar el flujo de trabajo, simplemente llame almain_workflow()  y todo el pipeline se ejecutará perfectamente.

# Run the workflow
main_workflow()

Salida


 

> Entering new AgentExecutor chain...
 Thought: The query 'What is the plot of 'A Scandal in Bohemia'?' requires context from the book to provide an accurate response.
 Action: Search FAISS Vector Store
 Action Input: "What is the plot of 'A Scandal in Bohemia'?"
 Observation:
I. A SCANDAL IN BOHEMIA


I.
“I was aware of it,” said Holmes dryly.

“The circumstances are of great delicacy, and every precaution has to
be taken to quench what might grow to be an immense scandal and
seriously compromise one of the reigning families of Europe. To speak
plainly, the matter implicates the great House of Ormstein, hereditary
kings of Bohemia.”

“I was also aware of that,” murmured Holmes, settling himself down in
his armchair and closing his eyes.
Contents

   I.     A Scandal in Bohemia
   II.    The Red-Headed League
   III.   A Case of Identity
   IV.    The Boscombe Valley Mystery
   V.     The Five Orange Pips
   VI.    The Man with the Twisted Lip
   VII.   The Adventure of the Blue Carbuncle
   VIII.  The Adventure of the Speckled Band
   IX.    The Adventure of the Engineer’s Thumb
   X.     The Adventure of the Noble Bachelor
   XI.    The Adventure of the Beryl Coronet
   XII.   The Adventure of the Copper Beeches

 Thought: Combining retrieved context with the query to generate a detailed answer.
/var/folders/4w/smh16qdx6l98q0534hr9v52r0000gn/T/ipykernel_2648/234523588.py:23: LangChainDeprecationWarning: The method `BaseLLM.__call__` was deprecated in langchain-core 0.1.7 and will be removed in 1.0. Use :meth:`~invoke` instead.
  final_answer = llm(prompt)
 Final Answer: Step 1: Identify the main characters and their roles.
- Sherlock Holmes: The detective who is approached by a client with a delicate matter.
- An unnamed client: A representative of the great House of Ormstein, hereditary kings of Bohemia, who seeks Holmes' help to prevent a potential scandal.

Step 2: Understand the main issue or conflict.
- The main issue is a delicate matter that, if exposed, could lead to a massive scandal and compromise one of the reigning families of Europe, specifically the House of Ormstein.

Step 3: Ident

> Finished chain.

> Entering new AgentExecutor chain...
 Thought: The query 'Who is Dr. Watson, and what role does he play in the stories?' requires context from the book to provide an accurate response.
 Action: Search FAISS Vector Store
 Action Input: "Who is Dr. Watson, and what role does he play in the stories?"
 Observation:
“Sarasate plays at the St. James’s Hall this afternoon,” he remarked.
“What do you think, Watson? Could your patients spare you for a few
hours?”

“I have nothing to do to-day. My practice is never very absorbing.”
“Try the settee,” said Holmes, relapsing into his armchair and putting
his fingertips together, as was his custom when in judicial moods. “I
know, my dear Watson, that you share my love of all that is bizarre and
outside the conventions and humdrum routine of everyday life. You have
shown your relish for it by the enthusiasm which has prompted you to
chronicle, and, if you will excuse my saying so, somewhat to embellish
so many of my own little adventures.”
“My God! It’s Watson,” said he. He was in a pitiable state of reaction,
with every nerve in a twitter. “I say, Watson, what o’clock is it?”

“Nearly eleven.”

“Of what day?”

“Of Friday, June 19th.”

“Good heavens! I thought it was Wednesday. It is Wednesday. What d’you
want to frighten a chap for?” He sank his face onto his arms and began
to sob in a high treble key.

“I tell you that it is Friday, man. Your wife has been waiting this two
days for you. You should be ashamed of yourself!”

 Thought: Combining retrieved context with the query to generate a detailed answer.
 Final Answer: Dr. Watson is a character in the Sherlock Holmes stories, written by Sir Arthur Conan Doyle. He is a former military surgeon who becomes the narrator and chronicler of Holmes' adventures. Watson is a close friend and confidant of Holmes, often accompanying him on cases and providing a more human perspective to the stories. He is known for his enthusiasm for the bizarre and unconventional, as well as his skill in recording the details of their investigations. Watson's role is crucial in presenting the narrative and offering insights into Holmes' character and methods.

> Finished chain.


Final DataFrame:
                                             Thought  \
0  The query 'What is the plot of 'A Scandal in B...   
1  The query 'Who is Dr. Watson, and what role do...   
2  The query 'Describe the relationship between S...   
3  The query 'What methods does Sherlock Holmes u...   

                      Action  \
0  Search FAISS Vector Store   
1  Search FAISS Vector Store   
2  Search FAISS Vector Store   
3  Search FAISS Vector Store   

                                        Action Input  \
0        What is the plot of 'A Scandal in Bohemia'?   
1  Who is Dr. Watson, and what role does he play ...   
2  Describe the relationship between Sherlock Hol...   
3  What methods does Sherlock Holmes use to solve...   

                                         Observation  \
0  I. A SCANDAL IN BOHEMIA\n\n\nI.\n“I was aware ...   
1  “Sarasate plays at the St. James’s Hall this a...   
2  “You have really got it!” he cried, grasping S...   
3  to learn of the case was told me by Sherlock H...   

                                        Final Answer  
0  Step 1: Identify the main characters and their...  
1  Dr. Watson is a character in the Sherlock Holm...  
2  Sherlock Holmes and Irene Adler have a profess...  
3  Sherlock Holmes uses a variety of methods to s...  

Output saved to output.csv

 

Después de ejecutar lamain_workflow() función, procesamos un archivo de texto (aosh.txt) y ejecutamos cuatro consultas definidas por el usuario sobre Las aventuras de Sherlock Holmes. El resultado proporciona un desglose detallado de cómo se manejó cada consulta:

  • El pensamiento describe el razonamiento detrás de la consulta y el contexto que requiere para una respuesta precisa.
  • La acción indica el paso dado, que en este caso es realizar una búsqueda de similitud mediante el índice vectorial FAISS.
  • La entrada de acción es la consulta específica que se procesa en una iteración.
  • La observación son los fragmentos de texto recuperados del índice vectorial que son relevantes para la consulta.
  • La respuesta final es la respuesta detallada generada por el LLM de Granite de IBM mediante el contexto recuperado.

Además, los resultados de todas las consultas se han estructurado en un DataFrame y se han guardado comooutput.csv . Este archivo contiene todos los componentes anteriores para su posterior análisis o uso compartido.

En este proceso, combinamos la recuperación de texto con el razonamiento de LLM para responder preguntas complejas sobre el libro. El agente recuperó dinámicamente la información relevante, utilizó el contexto para generar respuestas precisas y organizó el resultado en un formato estructurado para facilitar el análisis.

Visualización de los resultados

Con el archivo output.csv creado, ahora procederemos a visualizar los resultados de la consulta y sus métricas de precisión asociadas, proporcionando insights más profundos sobre el rendimiento del agente.

En la siguiente celda de código, cargamos los resultados de la consulta guardada deloutput.csv archivo en un DataFrame de Pandas para preparar la visualización y el análisis. El DataFrame nos permite manipular y explorar los datos en un formato estructurado.

# Load the output.csv file into a DataFrame
df = pd.read_csv("output.csv")
print(df.head()) # Display the first few rows

RESULTADOS


Thought  \
0  The query 'What is the plot of 'A Scandal in B...   
1  The query 'Who is Dr. Watson, and what role do...   
2  The query 'Describe the relationship between S...   
3  The query 'What methods does Sherlock Holmes u...   

                      Action  \
0  Search FAISS Vector Store   
1  Search FAISS Vector Store   
2  Search FAISS Vector Store   
3  Search FAISS Vector Store   

                                        Action Input  \
0        What is the plot of 'A Scandal in Bohemia'?   
1  Who is Dr. Watson, and what role does he play ...   
2  Describe the relationship between Sherlock Hol...   
3  What methods does Sherlock Holmes use to solve...   

                                         Observation  \
0  I. A SCANDAL IN BOHEMIA\n\n\nI.\n“I was aware ...   
1  “Sarasate plays at the St. James’s Hall this a...   
2  “You have really got it!” he cried, grasping S...   
3  to learn of the case was told me by Sherlock H...   

                                        Final Answer  
0  Step 1: Identify the main characters and their...  
1  Dr. Watson is a character in the Sherlock Holm...  
2  Sherlock Holmes and Irene Adler have a profess...  
3  Sherlock Holmes uses a variety of methods to s...

En este código, el DataFrame incluye componentes clave comoPensamiento ,Acción ,Observación  yRespuesta final  para cada consulta. Al mostrar las primeras filas usandodf.head() , nos aseguramos de que los datos tengan el formato correcto y estén listos para la siguiente etapa: crear visualizaciones significativas.

Importe bibliotecas de visualización

Para crear visualizaciones de los resultados de la consulta, importamos las bibliotecas necesarias:

import matplotlib.pyplot as plt
from wordcloud import WordCloud

 

matplotlib.pyplot  es una biblioteca ampliamente utilizada para crear visualizaciones estáticas, interactivas y animadas en Python. Se utilizará para generar gráficos de barras, gráficos circulares y otras visualizaciones.

wordcloud  es una biblioteca para crear nubes de palabras, que resaltan visualmente las palabras más frecuentes en los datos. Este paso ayuda a resumir y explorar el contexto recuperado del texto.

Nota importante: si encuentra el error"No se encontró WordCloud" , puede resolverlo instalando la biblioteca con el comandopip install wordcloud .

Visualice la longitud de las observaciones y las respuestas

Este código crea un gráfico de barras horizontales para comparar la longitud de las observaciones (contexto recuperado) y las respuestas (respuestas generadas) para cada consulta. Esta visualización proporciona insight sobre cuánto contexto utiliza el agente en comparación con la longitud de las respuestas generadas.

def visualize_lengths_with_queries(df):
"""Visualizes the lengths of observations and answers with queries on the y-axis."""
df["Observation Length"] = df["Observation"].apply(len)
df["Answer Length"] = df["Final Answer"].apply(len)
# Extract relevant data
queries = df["Action Input"]
observation_lengths = df["Observation Length"]
answer_lengths = df["Answer Length"]
# Create a horizontal bar chart
plt.figure(figsize=(10, 6))
bar_width = 0.4
y_pos = range(len(queries))
plt.barh(y_pos, observation_lengths, bar_width, label="Observation Length", color="skyblue", edgecolor="black")
plt.barh([y + bar_width for y in y_pos], answer_lengths, bar_width, label="Answer Length", color="lightgreen", edgecolor="black")
plt.yticks([y + bar_width / 2 for y in y_pos], queries, fontsize=10)
plt.xlabel("Length (characters)", fontsize=14)
plt.ylabel("Queries", fontsize=14)
plt.title("Observation and Answer Lengths by Query", fontsize=16)
plt.legend(fontsize=12)
plt.tight_layout()
plt.show()
# Call the visualization function
visualize_lengths_with_queries(df)
 

Esta función,visualize_lengths_with_queries , crea un gráfico de barras horizontales para comparar la longitud de las observaciones (contexto recuperado) y las respuestas (respuestas generadas) para cada consulta.

Calcula la longitud de los caracteres tanto de las observaciones como de las respuestas, agregándolas como nuevas columnas (Longitud de la observación  yLongitud de la respuesta ) al DataFrame. Usandomatplotlib , luego traza estas longitudes para cada consulta, y las consultas se muestran en el eje y para una mejor legibilidad.

El gráfico de barras está codificado por colores para diferenciar entre la observación y la longitud de las respuestas, e incluye etiquetas, una leyenda y un título para mayor claridad.

Esta visualización ayuda a analizar el equilibrio entre el tamaño del contexto recuperado y el detalle de la respuesta generada, ofreciendo insights sobre cómo el agente procesa y responde a las consultas.

Visualice la proporción de texto utilizado en las observaciones

Este paso visualiza cuánto del texto total procesado por el agente se utiliza en observaciones (contexto recuperado) en comparación con el texto restante. Se crea un gráfico circular para proporcionar una representación intuitiva de la proporción.

def visualize_text_proportion(df):
     """Visualizes the proportion of text used in observations."""
     total_text_length = sum(df["Observation"].apply(len)) + sum(df["Final Answer"].apply(len))
     observation_text_length = sum(df["Observation"].apply(len))
     sizes = [observation_text_length, total_text_length - observation_text_length]
     labels = ["Observation Text", "Remaining Text"]
     colors = ["#66b3ff", "#99ff99"]
     plt.figure(figsize=(4, 4))
     plt.pie(sizes, labels=labels, colors=colors, autopct="%1.1f%%", startangle=140)
     plt.title("Proportion of Text Used in Observations", fontsize=16)
     plt.show()
# Call the visualization function
visualize_text_proportion(df)

Hayvisualize_text_proportion  crea un gráfico circular para ilustrar la proporción del texto total que se utiliza en las observaciones (contexto recuperado) en comparación con el texto restante. Calcula la longitud total del texto sumando la longitud de los caracteres de todas las observaciones y respuestas, y luego determina la parte aportada solo por las observaciones.

Estos datos se visualizan en un gráfico circular, con etiquetas claras para"Texto de observación" Y"Texto restante" y colores distintos para mejorar la legibilidad. El gráfico incluye valores porcentuales para que las proporciones sean fáciles de interpretar.

Esta visualización proporciona una visión general de alto nivel de la cantidad de texto que el agente utiliza como contexto durante el procesamiento de consultas, ofreciendo insights sobre la eficiencia y el enfoque del proceso de recuperación.

Genere nubes de palabras para observaciones y respuestas finales

Este código genera dos nubes de palabras para representar visualmente las palabras que aparecen con más frecuencia en los Observación Y Respuesta final textos.

def generate_wordclouds_side_by_side(df):
      """Generates and displays word clouds for Observations and Final Answers side by side."""
      # Combine text for Observations and Final Answers
      observation_text = " ".join(df["Observation"])
      final_answer_text = " ".join(df["Final Answer"])
      # Create word clouds
      observation_wordcloud = WordCloud(width=800, height=400, background_color="white").generate(observation_text)
      final_answer_wordcloud = WordCloud(width=800, height=400, background_color="white").generate(final_answer_text)
      # Create a side-by-side visualization
      plt.figure(figsize=(16, 8))
      # Plot the Observation word cloud
      plt.subplot(1, 2, 1)
      plt.imshow(observation_wordcloud, interpolation="bilinear")
      plt.axis("off")
      plt.title("Word Cloud of Observations", fontsize=16)
      # Plot the Final Answer word cloud
      plt.subplot(1, 2, 2)
      plt.imshow(final_answer_wordcloud, interpolation="bilinear")
      plt.axis("off")
      plt.title("Word Cloud of Final Answers", fontsize=16)
      plt.tight_layout()
      plt.show()
# Call the function to generate and display the word clouds
generate_wordclouds_side_by_side(df)
 

Este código genera dos nubes de palabras para representar visualmente las palabras que aparecen con más frecuencia en losObservación YRespuesta final , mostrándolos uno al lado del otro para facilitar la comparación. LosObservación  yRespuesta final  textos se concatenan primero en dos cadenas separadas mediante el uso de" ".join()  para combinar todas las filas de las columnas respectivas. La biblioteca deWordCloud luego se utiliza para generar nubes de palabras para cada texto con configuraciones específicas.

Para crear una visualización en paralelo, se utilizan subtramas: la primera subtrama muestra la nube de palabras paraObservación y la segundo muestra la deRespuesta final . Eltight_layout()  garantiza un espaciado ordenado entre los gráficos. Estas nubes de palabras nos permiten analizar intuitivamente el rendimiento del agente al resaltar los términos clave recuperados del contexto (Observación ) y los enfatizados en las respuestas (Respuesta final ).

Pruebe la precisión del agente

En esta sección, evaluamos el rendimiento del agente utilizando múltiples métricas de precisión:Concordancia de palabras clave ,Puntuaciones BLEU ,Precisión y coincidencia  yPuntuaciones F1 . Estas métricas proporcionan una visión completa de qué tan bien el agente genera respuestas precisas y relevantes basadas en las consultas de los usuarios.

Importe las bibliotecas necesarias

Antes de comenzar las pruebas, importamos las bibliotecas necesarias para la evaluación de la precisión.

from sklearn.feature_extraction.text import CountVectorizer
from nltk.translate.bleu_score import sentence_bleu
from sklearn.metrics import precision_score, recall_score

Estas bibliotecas incluyen herramientas para la coincidencia de palabras clave, el cálculo de la puntuación BLEU, la precisión y la evaluación de la recuperación. Asegúrese de haber instalado estas bibliotecas en su entorno para evitar errores de importación.

Precisión de la concordancia de palabras clave

Esta prueba evalúa qué tan bien las respuestas generadas incluyen las palabras clave de las consultas. UtilizaCountVectorizer para tokenizar y extraer palabras clave de las consultas y respuestas. La función calcula la proporción de palabras clave de consulta presentes en la respuesta generada, marcando la respuesta como precisa si esta proporción supera un umbral (0.5 de forma predeterminada). Los resultados se agregan al DataFrame bajo laPuntuación de concordancia de palabras clave YIs Accurate columns .

def keyword_matching_accuracy(df):
      """Checks if key phrases from the query are present in the final answer."""
      vectorizer = CountVectorizer(stop_words='english')
      def check_keywords(query, answer):
      query_keywords = set(vectorizer.build_tokenizer()(query.lower()))
      answer_keywords = set(vectorizer.build_tokenizer()(answer.lower()))
      common_keywords = query_keywords & answer_keywords
      return len(common_keywords) / len(query_keywords) # Proportion of matched keywords
      df["Keyword Match Score"] = df.apply(lambda row: check_keywords(row["Action Input"], row["Final Answer"]), axis=1)
      df["Is Accurate"] = df["Keyword Match Score"] >= 0.5 # Set a threshold for accuracy
      return df
# Apply keyword matching
df = keyword_matching_accuracy(df)
df.to_csv("output_with_accuracy.csv", index=False)
df

Cálculo del puntaje BLEU

Esta prueba mide en qué medida las respuestas generadas coinciden con las observaciones recuperadas.BLEU (suplente de evaluación bilingüe) es una métrica popular para evaluar la similitud del texto basada en superposicionesn-gram . La función calculaPuntuaciones BLEU  para cada par de consulta-respuesta y las agrega al DataFrame en la columna de puntuación BLEU.

def calculate_bleu_scores(df):
    """Calculates BLEU scores for answers against observations."""
    df["BLEU Score"] = df.apply(
       lambda row: sentence_bleu([row["Observation"].split()], row["Final Answer"].split()),
       axis=1
       )
    return df
# Apply BLEU score calculation
df = calculate_bleu_scores(df)
df.to_csv("output_with_bleu.csv", index=False)

Precisión y recuperación

La precisión y la recuperación se calculan para evaluar la relevancia y la integridad de las respuestas. La precisión mide la proporción de palabras recuperadas en la respuesta que son relevantes, mientras que la recuperación mide la proporción de palabras relevantes en la observación que aparecen en la respuesta.

Estas métricas se adjuntan al DataFrame bajo las columnas de precisión Y Recordar .

def calculate_precision_recall(df):
     """Calculates precision and recall for extractive answers."""
         def precision_recall(observation, answer):
                observation_set = set(observation.lower().split())
                answer_set = set(answer.lower().split())
                precision = len(observation_set & answer_set) / len(answer_set) if answer_set else 0
                recall = len(observation_set & answer_set) / len(observation_set) if observation_set else 0
         return precision, recall
        df[["Precision", "Recall"]] = df.apply(
        lambda row: pd.Series(precision_recall(row["Observation"], row["Final Answer"])),
        axis=1
        )
return df
# Apply precision/recall
df = calculate_precision_recall(df)
df.to_csv("output_with_precision_recall.csv", index=False)
df

Cálculo del puntaje F1

La puntuación F1 combina precisión y recuperación en una sola métrica, proporcionando una evaluación equilibrada de relevancia e integridad. La fórmula para la puntuación F1 es: F1 Score = 2 * (Precision * Recall) / (Precision + Recall)

Las puntuaciones deF1 calculadas se agregan al DataFrame en la columna de puntuación F1.

def calculate_f1(df):
      """Calculates F1 scores based on precision and recall."""
          df["F1 Score"] = 2 * (df["Precision"] * df["Recall"]) / (df["Precision"] + df["Recall"])
          df["F1 Score"].fillna(0, inplace=True) # Handle divide by zero
          return df
# Apply F1 calculation
df = calculate_f1(df)
df.to_csv("output_with_f1.csv", index=False)
df

Resumir métricas de precisión

Por último, una función de resumen consolida todas las métricas para proporcionar una visión general del rendimiento del agente. Calcula el número total de consultas, el recuento y el porcentaje de respuestas precisas y las puntuaciones medias de BLEU y F1.

def summarize_accuracy_metrics(df):
      """Summarizes overall accuracy metrics."""
          total_entries = len(df)
          accurate_entries = df["Is Accurate"].sum()
          average_bleu = df["BLEU Score"].mean()
          average_f1 = df["F1 Score"].mean()
          print(f"Total Entries: {total_entries}")
          print(f"Accurate Entries: {accurate_entries} ({accurate_entries / total_entries * 100:.2f}%)")
          print(f"Average BLEU Score: {average_bleu:.2f}")
          print(f"Average F1 Score: {average_f1:.2f}")
# Call summary function
summarize_accuracy_metrics(df)

RESULTADOS


 

Total Entries: 4
Accurate Entries: 4 (100.00%)
Average BLEU Score: 0.04
Average F1 Score: 0.24

Estas pruebas de precisión ofrecen una evaluación detallada de la capacidad del agente para generar respuestas relevantes y precisas. Cada prueba se centra en un aspecto específico, desde la inclusión de palabras clave hasta la similitud del texto y la integridad de la respuesta. El resumen consolida estas métricas para ofrecer una instantánea general del rendimiento.

Resumen

Este tutorial lo guio a través de la creación de un agente autónomo impulsado por Granite LLM y LangChain de IBM. Desde la extracción de texto hasta la vectorización y la resolución de consultas, cubrimos todo el proceso de diseño e implementación de un agente funcional basado en LLM. Los pasos clave incluyeron la gestión de la memoria con almacenes de vectores, el procesamiento de consultas y la generación de respuestas mediante Granite.

Evaluamos el rendimiento del agente mediante el uso de métricas de precisión, como coincidencia de palabras clave, puntajes BLEU, precisión, recuperación y puntajes F1. Las visualizaciones, como gráficos de barras, gráficos circulares y nubes de palabras, proporcionaron insights adicionales sobre el comportamiento y la eficacia del agente.

Al completar este tutorial, aprendió a diseñar, probar y visualizar el rendimiento de un agente de LLM. Esta base se puede ampliar para abordar conjuntos de datos más complejos, mejorar la precisión y explorar características avanzadas, como los sistemas multiagente.

Soluciones relacionadas
Agentes de IA para empresas

Cree, implemente y gestione poderosos asistentes y agentes de IA que automaticen flujos de trabajo y procesos con IA generativa.

    Explore watsonx Orchestrate
    Soluciones de agentes de IA de IBM

    Construya el futuro de su empresa con soluciones de IA en las que pueda confiar.

    Explorar las soluciones de agentes de IA
    Servicios de IA de IBM Consulting

    Los servicios de IA de IBM Consulting ayudan a reinventar la forma en que las empresas trabajan con IA para la transformación.

    Explorar los servicios de inteligencia artificial
    Dé el siguiente paso

    Ya sea que elija personalizar aplicaciones y habilidades predefinidas o crear y desplegar servicios agénticos personalizados utilizando un estudio de IA, la plataforma IBM watsonx responde a sus necesidades.

    Explore watsonx Orchestrate Explore watsonx.ai