¿Cómo se pueden guardar las entidades en un chatbot?
La interacción con los usuarios es crucial para ofrecer un servicio excepcional. Conocer detalles específicos sobre los clientes, como nombres, direcciones, números telefónicos y problemas particulares, ayuda a crear una experiencia de usuario personalizada. El uso de un sistema de memoria de entidades de conversación (Conversation Entity Memory) es clave para este propósito.
¿Qué es una memoria de entidad de conversación?
Las entidades son detalles específicos sobre una persona, como su nombre, teléfono o dirección. Con la ayuda de la inteligencia artificial, podemos extraer y organizar estas entidades eficientemente para mejorar el servicio al cliente. Este tipo de memoria permite almacenar y acceder a datos necesarios durante las interacciones del chatbot.
¿Cómo se configura un template de memoria de entidad?
Para configurar correctamente un template de Entity Memory Conversation, podemos importar elementos necesarios desde librerías especializadas como Conversation Prompt. Un buen punto de partida es analizar cómo luce el template predeterminado para entender mejor cómo ajustarlo a nuestras necesidades. Este proceso es invaluable cuando se quiere personalizar el prompt según casos de uso específicos.
¿Cómo se desarrolla un prompt personalizado?
A continuación, se detalla un ejemplo de cómo crear un prompt personalizado para un asistente de ventas de máquinas de micheladas:
Plantilla de Prompt: Utilizamos el objeto prompt template para establecer la estructura básica. La plantilla incluye variables importantes como entidades, historial de conversación y entradas (inputs).
Detalles Específicos: Se añaden instrucciones específicas, como preguntar si el cliente ha tratado de solucionar el problema. Se simula un tono de conversación local, como el estilo de Tepito, México, para dar personalidad.
Datos del Cliente: Se recopila información clave, como la fecha de compra, el número de garantía y el nombre de quien atendió originalmente al cliente.
# Creamos un template Tepitoprompt_tepito ={"entities":"Datos del cliente aquí...","history":"","input":""}
¿Cómo implementar la cadena de conversación?
Para llevar a cabo la funcionalidad del chatbot, se debe configurar una cadena de conversación:
Importación de librerías: Se comienza importando Conversation Chain de la librería adecuada.
Configuración del Modelo: Se utiliza un modelo de lenguaje como GPT-3.5 para el chat activo. Es importante seleccionar los modelos de lenguaje adecuados para diferentes tareas, como identificar entidades o interactuar con el usuario.
Memoria de Entidades: La memoria organiza los detalles capturados durante la conversación. Esto se facilita utilizando modelos como text DaVinci 003 que manejan el reconocimiento de entidades con precisión.
# Inicializar la cadena de conversaciónconversation_chain = ConversationChain( prompt=prompt_tepito, model_language=gpt35_model, entity_memory=text_davinci_model
)
¿Cómo se recopilan y reportan las entidades?
Para concluir la interacción, se puede generar un reporte detallado de las entidades recogidas durante el chat:
Uso de Pprint: Con la librería Pprint, se puede imprimir de forma ordenada un reporte JSON de las entidades recopiladas.
Revisión del Reporte: El reporte ofrece una visión consolidada de toda la información del cliente, útil para evaluaciones futuras y mejoras de servicio.
# Generar reporte de entidades con Pprintfrom pprint import pprint
entity_store = conversation_chain.memory.entity_store
pprint(entity_store)
La implementación de un sistema de memoria de entidades en un chatbot no solo mejora la calidad de atención al cliente sino que permite un nivel de personalización que genera valor a largo plazo. A medida que adquieras más experiencia, podrás ajustar los sistemas y modelos a las necesidades específicas de tu línea de negocio y sector.
Esta guía proporciona un caso de uso sobre “Entity Memory”, una estrategia de memorización basada en la extracción de entidades clave en una conversación.
.
🗂️ Background
Las “Entity Memory” son una estrategia de memoria que se centra en los hechos de entidades específicas en la conversación. Se extrae la información sobre entidades (utilizando un LLM) y construye su conocimiento sobre esa entidad a lo largo del tiempo (también utilizando un LLM).
.
Esta estrategia es particularmente útil para chatbots que necesitan extraer y entender información clave, como nombres de personas, identificadores de productos y otros detalles importantes.
.
Helper Links:
Entity Memory
.
🎯 Problem
Implementar un “Entity Memory” utilizando TypeScript para un Chat con IA, extrayendo campos de interés, como por ejemplo nombre y empresa en una conversación.
.
🚧 Solution
LangChain posee diferentes tipos de estrategias para la memorización de contextos. Así mismo, se poseen diferentes cadenas que, bajo su definición, nos proveen de interfaces a fines a la implementación.
.
LLMChain es una cadena que se enfoca en realizar consultas contra LLMs. Siendo la cadena más especializada en la obtención de información como recuperador.
Dependiendo del escenario, LangChain provee de plantillas que permiten inicializar los LLM bajo un contexto que se irá desarrollando durante el tiempo de servicio. Por ejemplo, la plantilla ENTITY_MEMORY_CONVERSATION_TEMPLATE, nos provee de un prompt para establecer el contexto en la resolución de tareas variadas, desde responder preguntas simples hasta proporcionar explicaciones detalladas y discusiones sobre una amplia gama de temas.
You are an assistant to a human, powered by a large language model trained by OpenAI.
You are designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, you are able to generate human-like text based on the input you receive, allowing you to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.
You are constantly learning and improving, and your capabilities are constantly evolving. You are able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. You have access to some personalized information provided by the human in the Context section below. Additionally, you are able to generate your own text based on the input you receive, allowing you to engage in discussions and provide explanations and descriptions on a wide range of topics.
Overall, you are a powerful tool that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether the human needs help with a specific question or just wants to have a conversation about a particular topic, you are here to assist.
Context:
{entities}
Current conversation:
{history}
Last line:
Human: {input}
You:
Para la memorización, LangChain provee la clase EntityMemory para gestionar la extracción de entidades y el resumen en la memoria en aplicaciones de chatbot.
El ajuste del atributo temperature en los modelos, establece la capacidad determinista del LLM. La recomendación para la EntityMemory es en 0 por la abstracción exacta entre cada interacción. Sin embargo, en la cadena, su LLM dependerá en la depuración a operar según su tipo (Funcional o Utility).
import{LLMChain}from'langchain/chains'import{OpenAI}from'langchain/llms/openai'import{EntityMemory,ENTITY_MEMORY_CONVERSATION_TEMPLATE,}from'langchain/memory'import{PromptTemplate}from'langchain/prompts'constAPI_TOKEN=// 👈 Enter the API Token from OpenAIconst prompt =newPromptTemplate({ inputVariables:ENTITY_MEMORY_CONVERSATION_TEMPLATE.inputVariables, template:ENTITY_MEMORY_CONVERSATION_TEMPLATE.template,})const memory =newEntityMemory({ llm:newOpenAI({ temperature:0, openAIApiKey:API_TOKEN,}),})const chain =newLLMChain({ llm:newOpenAI({ temperature:0.9, openAIApiKey:API_TOKEN,}), memory, prompt, verbose:true,})await chain.call({ input:"Hi! I'm Jim."})await chain.call({ input:'I work in sales. What about you?'})await chain.call({ input:'My office is the Utica branch of Dunder Mifflin. What about you?',})console.log(await memory.loadMemoryVariables({ input:'Who is Jim?'}))
{
history: "Human: Hi! I'm Jim.\nAI: Hi Jim! It's nice to meet you. How can I help you today?\nHuman: I work in sales. What about you?\nAI: I'm an assistant powered by a language model trained by OpenAI. I'm here to help you with any questions or tasks you may have related to the topics I'm familiar with. How can I assist you today?\nHuman: My office is the Utica branch of Dunder Mifflin. What about you?\nAI: I don't have an office, but I can help you with any questions or tasks related to the topics I'm familiar with. So, what can I do for you today?",
entities: {
Jim: "Jim is a human who works in sales and is based in the Utica branch of Dunder Mifflin.",
Utica: "Utica is the location of the Dunder Mifflin branch where Jim works.",
"Dunder Mifflin": "Dunder Mifflin is a company with a Utica branch."
}
}
¿Sería posible pasarle la transcripcion de una conversación entre dos personas para que generase las entidades?
asi es, sin embargo hay que ver el tamanio de la transcripción, dado que puede superar el max_token_len :thinking:
¡Gracias! Al final encontré esto:
OpenAI Whisper Speaker Diarization - Transcription with Speaker Names
En versiones de langchain >= 1.0, se puede replicar este comportamiento con los graph (workflow de nodos) de langgraph
1- Agregamos las importaciones necesarias
import uuid
from pydantic import BaseModel, Field
from typing import Optional
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage, RemoveMessage
from langgraph.graph import MessagesState, StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from langgraph.store.memory import InMemoryStore
from langgraph.store.base import BaseStore
from langchain_core.runnables import RunnableConfig
2- Definimos un schema de pydantic que representara un data-contract cuyos atributos son las entidades que queremos preservar del usuario.
# This entity schema for structured output allows LLM return data in a specific format.# Read docs: https://docs.langchain.com/oss/python/langchain/structured-outputclassExctractedUserEntities(BaseModel): direction: Optional[str]= Field(None, description="The customer's phyisical adress") phone_number: Optional[str]= Field(None, description="The customer's phone number") waranty: Optional[str]= Field(None, description="The machine's warranty number") sold_date: Optional[str]= Field(None, description="The date of purchase of machine by the customer") employee_name: Optional[str]= Field(None, description="The name of the employee who attend served them'")
3- Inicializar instancias de LLM y extraction LLM
# model for chatbot answers and questionsllm = ChatOpenAI( model="gpt-4o-mini", temperature=0.2, max_retries=3, max_tokens=1000)# model extractor will returns outputs formatted to match the given schema.# if `schema` is a pydantic class, then the model output will be a pydantic instance of that classextractor_llm = llm.with_structured_output(schema=ExctractedUserEntities)
4- Definimos una function-node la cual sera un paso en nuestro workflow para extraer entidades desde cada mensaje enviado por el usuario.
# extraction node finds entities in messages and saves to store.defextract_user_entities_node(state: MessagesState, config: RunnableConfig,*, store: BaseStore):""" This node will finds entities in messages
and saves to store.
Args:
state: state of the current conversation, contains 'messages' history.
config: Configuration of the conversation, contains conversation metadata.
store: where the entities will be stored in this conversation, langgraph looks for the store registered in it's workflow and passes directly.
""" user_id = config["configurable"].get("user_id","default_user")# Check if store existsif store isNone:raise ValueError("Store is not initialized.")# Analize only the last user message for new entities last_message = state["messages"][-1].content
# invoke the extrator_llm with the last human message extracted = extractor_llm.invoke(f"Extract information from this message {last_message}")# if found entities, then save on the store under entitiesif extracted: data ={k: v for k, v in extracted.model_dump().items()if v isnotNone}for key, value in data.items(): store.put(("entities", user_id), key, value)# returns empty dict because store updates are side-effectreturn{}
5- Definimos un function-node la cual sera otro paso en nuestro workflow para comunicarnos con el modelo en nuestro question/answering
defcall_model_node(state: MessagesState, config: RunnableConfig,*, store: BaseStore):""" This node will define the system prompt and
handle question/answering between user and LLM
Args:
state: state of the current conversation, contains 'messages' history.
config: Configuration of the conversation, contains conversation metadata.
store: where the entities will be stored in this conversation, langgraph looks for the store registered in it's workflow and passes directly.
""" user_id = config["configurable"].get("user_id","default_user")# Search and retrieve all entities for this user stored_items = store.search(("entities", user_id)) entities_str ="\n".join([f"- {item.key}: {item.value}"for item in stored_items])ifnot entities_str: entities_str ="There is not personalizated information yet." system_instruction =f"""
You are a sales assistant for a photography studio.
You are only designed to (1) try to resolve issues with downloading edited photos that are pending delivery to customers, and if the customer is unable to do so, (2) add the shots (photos) that the customer chose to the editors' task queue.
If the customer cannot find the photos on the download page, then ask if they want to send the shots back for editing, which will take one week. If the customer wants to send the shots back for editing, they must leave their cell phone number and address.
You also have access to personalized information provided by the human in the Context section below.
You are here to help, always with the spark and character of someone born in Medellin, Colombia.
It is essential that you ask for the date of their photo session, their invoice number, and who attended to them. Always ask if the customer's problem or question has been resolved.
Context:
{entities_str}"""# invoke the LLM with whole context with our system prompt with entities if found and the complete messages history messages =[system_instruction]+ state["messages"] response = llm.invoke(messages)return{"messages":[response]}
6- Creamos nuestro workflow the langgraph al cual enlazaremos con los nodos definidos arriba.
# Build and compile the graph# store to handle entities memoriesstore = InMemoryStore()# checkpointer to save each interaction between user and LLMcheckpointer = MemorySaver()# init the workflowworkflow = StateGraph(MessagesState)# Add our two defined nodes to the workflowworkflow.add_node("extract", extract_user_entities_node)workflow.add_node("assistant", call_model_node)# Define steps order of the workflow# init -> extract -> assistant -> endworkflow.add_edge(START,"extract")workflow.add_edge("extract","assistant")workflow.add_edge("assistant", END)# Compile with checkpointer for history and store for entitiesapp = workflow.compile(checkpointer=checkpointer, store=store)
7- Definimos la metadata necesaria para nuestra conversacion
# The user_id ensures the address/phone persists across different conversations config ={"configurable":{"thread_id":"x1s343","user_id":"user_001"}}
8- desde este punto podemos enviar mensajes a nuestro chatbot assistente, repetiremos el mismo codigo con diferentes mensajes para ir viendo las respuestas y asi reformular nuestro siguiente mensaje como mejor nos convenga
msg_1 = HumanMessage(content="Hi, My name is Evert Escalante, I would like support, I cant find my photos on your company url to download them")for chunk in app.stream({"messages":[msg_1]}, config, stream_mode="values"):if chunk["messages"]:print(f"Assistant: {chunk['messages'][-1].content}\n")
mensaje 2:
msg_2 = HumanMessage(content="it was on january 27th, invoice_number is 23332334 and Yurley Munioz attends me")for chunk in app.stream({"messages":[msg_2]}, config, stream_mode="values"):if chunk["messages"]:print(f"Assistant: {chunk['messages'][-1].content}\n")
Si quieren ver las entidades guardadas
all_entities = store.search(("entities","user_001"))for item in all_entities:# item.key is the entity name (e.g., 'direccion')# item.value is the stored valueprint(f"{item.key}: {item.value}")
Porque Los Ejemplos de Caso Uso son tan Informales en Este Curso ? Se vuelve fastidisoso tanto wokinsmo con el tiempo.
A mi me sale NotFoundError Traceback (most recent call last)
<ipython-input-16-750be73a0d15> in <cell line: 1>()
----> 1 conversation.predict(input="Que onda, mi máquina para hacer micheladas no está funcionando. Ando enojado.")
23 frames in _request(self, cast_to, options, remaining_retries, stream, stream_cls)
986
987 log.debug("Re-raising status error")
--> 988 raise self._make_status_error_from_response(err.response) from None
989
990 return self._process_response(
NotFoundError: Error code: 404 - {'error': {'message': 'The model text-davinci-003 has been deprecated, learn more here: ', 'type': 'invalid_request_error', 'param': None, 'code': 'model_not_found'}}...
alguien sabe como solucionar, lo reemplacé por gpt-4 pero sigue saliendo el mimsmo mensaje
Hola Lourdes, me parece que cambio un poco la documentacion, debes importar el modelo de chat de open ai:
from langchain_community.chat_models import ChatOpenAI