Capítulo 7: Memoria y Conversaciones de Varios Turnos
7.2 Gestión de hilos y ventanas de contexto
En conversaciones de múltiples turnos, especialmente aquellas que se extienden a lo largo de múltiples mensajes o sesiones, gestionar el contexto de manera efectiva es crucial para mantener un diálogo significativo. Esto se vuelve particularmente importante en aplicaciones de IA donde las conversaciones pueden volverse complejas y extensas. Los modelos de OpenAI operan dentro de una "ventana de contexto" fija—un número máximo de tokens que pueden considerar en una llamada (hasta 128K tokens para algunos modelos). Piensa en esta ventana como la memoria de trabajo del modelo, similar a cómo los humanos solo pueden mantener cierta cantidad de información en sus pensamientos inmediatos.
Cuando tu conversación se extiende más allá de este límite de ventana, los mensajes más antiguos pueden ser truncados o eliminados de la consideración, causando que el modelo pierda contexto importante. Esto puede llevar a varios problemas: el modelo podría olvidar partes anteriores de la conversación, repetir información o fallar en mantener la consistencia con hechos o preferencias previamente establecidos. Por ejemplo, si un usuario hace referencia a algo mencionado anteriormente en la conversación que fue truncado, el modelo no tendrá acceso a esa información para proporcionar una respuesta apropiada.
Por lo tanto, la gestión adecuada de hilos es esencial—asegura que tus aplicaciones permanezcan coherentes y enfocadas, incluso cuando las conversaciones crecen en longitud y complejidad. Esto implica implementar estrategias para preservar el contexto crucial mientras se gestiona eficientemente el límite de tokens, como resumir intercambios previos, mantener información relevante y decidir inteligentemente qué partes de la conversación mantener o eliminar. A través de una gestión efectiva de hilos, puedes crear conversaciones más naturales y conscientes del contexto que mantienen su coherencia y utilidad a lo largo de interacciones extendidas.
7.2.1 ¿Qué es una Ventana de Contexto?
Una ventana de contexto es un concepto fundamental en los modelos de lenguaje de IA que define la cantidad máxima de texto que el modelo puede procesar y comprender a la vez. Esta ventana actúa como la memoria de trabajo del modelo - similar a cómo los humanos solo pueden mantener cierta cantidad de información en sus pensamientos inmediatos. El tamaño de esta ventana se mide en tokens, que son los bloques fundamentales que el modelo utiliza para procesar el lenguaje.
Para entender mejor los tokens, piensa en ellos como las piezas del vocabulario del modelo. Mientras que los humanos naturalmente dividimos el lenguaje en palabras, los modelos de IA descomponen el texto de manera diferente. Una sola palabra puede convertirse en múltiples tokens - por ejemplo, "entendimiento" se convierte en "entend" + "imiento", mientras que palabras comunes como "el" o "y" suelen ser tokens individuales. Incluso los signos de puntuación y espacios cuentan como tokens. Esta tokenización ayuda al modelo a procesar el texto de manera más eficiente y comprender mejor los patrones del lenguaje.
Cuando mantienes una conversación con un modelo de IA, este maneja tu interacción de una manera fascinante. Cada parte de la conversación - ya sean las instrucciones iniciales (mensajes del sistema), tus preguntas (mensajes del usuario) o las respuestas de la IA (mensajes del asistente) - se entretejen en una secuencia continua. Este texto combinado luego pasa por el proceso de tokenización, donde se descompone en tokens y se analiza como una unidad completa.
Sin embargo, hay una limitación crucial a tener en cuenta: la ventana de contexto tiene un tamaño fijo. Cuando tu conversación crece demasiado y excede este límite de tokens, el modelo tiene que hacer espacio para nueva información. Lo hace eliminando mensajes antiguos desde el principio de la conversación, similar a cómo la aplicación de mensajería de tu teléfono podría mostrar solo los mensajes más recientes en una ventana de chat. Por esto es que a veces el modelo podría no recordar algo mencionado mucho antes en una conversación larga.
- GPT-3.5-turbo: ~16K tokens (aproximadamente equivalente a 12,000 palabras o 48 páginas de texto). Esta ventana de contexto sustancial permite conversaciones detalladas y tareas complejas, aunque puede necesitar gestión en interacciones más largas.
- GPT-4o y GPT-4o-mini: ~128K tokens (aproximadamente equivalente a 96,000 palabras o 384 páginas de texto, variando según tu plan de suscripción). Esta ventana de contexto significativamente más grande permite conversaciones mucho más largas y análisis más complejos, haciéndola adecuada para revisión extensa de documentación, creación de contenido de formato largo y tareas analíticas detalladas.
7.2.2 Estrategias de Gestión de Hilos
1. Segmentación en Hilos Lógicos
Al construir aplicaciones de IA que manejan conversaciones, es crucial implementar una segmentación adecuada de hilos. Esto significa organizar las conversaciones en matrices de mensajes separadas e independientes (hilos) basadas en diferentes usuarios, temas o contextos. Piensa en ello como tener diferentes salas de chat o canales de conversación - cada uno mantiene su propia historia y contexto sin interferir con los demás.
Por ejemplo, si tienes un bot de servicio al cliente ayudando a múltiples clientes simultáneamente, la conversación de cada cliente debe almacenarse en un hilo separado. Esto asegura que cuando el Cliente A pregunta sobre el estado de su pedido, el bot no hará referencia accidentalmente a los detalles de envío del Cliente B. De manera similar, si tu aplicación maneja diferentes temas (como consejos médicos vs soporte técnico), mantener hilos separados previene la confusión y mantiene la precisión contextual.
Este enfoque de segmentación ofrece varios beneficios:
- Límites claros de conversación
- Mejor gestión del contexto
- Mayor precisión en las respuestas
- Depuración y monitoreo más fácil
- Privacidad mejorada entre diferentes usuarios o temas
La clave es implementar un sistema robusto para crear, gestionar y almacenar estos hilos separados mientras se asegura que cada uno mantenga su propio historial completo de conversación.
# Example: Separate threads for different users.
threads = {
"user_1": [{"role": "system", "content": "You are a friendly assistant."}],
"user_2": [{"role": "system", "content": "You are an expert math tutor."}]
}
def append_message(user_id, role, content):
threads[user_id].append({"role": role, "content": content})
Este código demuestra una implementación básica de la gestión de hilos de conversación. Permíteme desglosarlo:
Estructura de Datos:
- El código utiliza un diccionario llamado 'threads' para almacenar hilos de conversación separados para diferentes usuarios
- Cada usuario (user_1, user_2) tiene su propio array de mensajes con un mensaje de sistema único que define el rol del asistente (asistente amigable vs tutor de matemáticas)
Funcionalidad:
- La función append_message() permite agregar nuevos mensajes al hilo de un usuario específico
- Toma tres parámetros: user_id (para identificar el hilo), role (quién está hablando), y content (el mensaje)
Esta implementación simple asegura que las conversaciones permanezcan separadas y contextualmente apropiadas para cada usuario, evitando la contaminación cruzada de conversaciones entre diferentes usuarios.
Aquí hay una implementación integral
# Example: Thread management with OpenAI API
import openai
from typing import Dict, List
import time
class ThreadManager:
def __init__(self, api_key: str):
self.threads: Dict[str, List[Dict]] = {}
openai.api_key = api_key
def create_thread(self, user_id: str, system_role: str) -> None:
"""Initialize a new thread for a user with system message."""
self.threads[user_id] = [
{"role": "system", "content": system_role}
]
def append_message(self, user_id: str, role: str, content: str) -> None:
"""Add a message to user's thread."""
if user_id not in self.threads:
self.create_thread(user_id, "You are a helpful assistant.")
self.threads[user_id].append({
"role": role,
"content": content,
"timestamp": time.time()
})
async def get_response(self, user_id: str, temperature: float = 0.7) -> str:
"""Get AI response using GPT-4o."""
try:
response = await openai.ChatCompletion.acreate(
model="gpt-4o",
messages=self.threads[user_id],
temperature=temperature,
max_tokens=1000
)
ai_response = response.choices[0].message.content
self.append_message(user_id, "assistant", ai_response)
return ai_response
except Exception as e:
return f"Error: {str(e)}"
# Usage example
async def main():
thread_mgr = ThreadManager("your-api-key-here")
# Create threads for different users
thread_mgr.create_thread("user_1", "You are a friendly assistant.")
thread_mgr.create_thread("user_2", "You are an expert math tutor.")
# Simulate conversation
thread_mgr.append_message("user_1", "user", "Hello! How are you?")
response = await thread_mgr.get_response("user_1")
print(f"Assistant: {response}")
Este ejemplo muestra una implementación de un sistema de gestión de hilos para manejar múltiples conversaciones con un asistente de IA. Aquí están los componentes principales:
Clase ThreadManager:
- Gestiona hilos de conversación separados para diferentes usuarios
- Almacena los hilos en un diccionario con IDs de usuario como claves
Funciones Principales:
- create_thread(): Configura nuevas conversaciones con un rol de sistema (por ejemplo, "asistente amigable" o "tutor de matemáticas")
- append_message(): Agrega nuevos mensajes al hilo de conversación de un usuario con marcas de tiempo
- get_response(): Realiza llamadas a la API de GPT-4o para obtener respuestas de la IA
Características Principales:
- Manejo de errores para llamadas a la API
- Soporte asíncrono para mejor rendimiento
- Creación automática de hilos si no existen
- Seguimiento de marcas de tiempo de mensajes
El código ayuda a prevenir la contaminación cruzada de conversaciones entre diferentes usuarios al mantener la conversación de cada usuario separada y contextualmente apropiada.
Desglose del Código:
Estructura de Clase
- La clase ThreadManager maneja todas las operaciones relacionadas con hilos
- Utiliza un diccionario para almacenar hilos con IDs de usuario como claves
- Se inicializa con la clave API de OpenAI
Métodos Principales
- create_thread(): Inicializa nuevos hilos de conversación
- append_message(): Agrega mensajes a hilos existentes
- get_response(): Maneja llamadas a la API de GPT-4o
Mejoras sobre la Versión Básica
- Manejo adecuado de errores
- Soporte asíncrono para mejor rendimiento
- Seguimiento de marcas de tiempo
- Control de temperatura para variación de respuestas
Características de Seguridad
- Creación automática de hilos si no existen
- Bloque try-except para llamadas a la API
- Indicaciones de tipo para mejor mantenibilidad del código
2. Conteo y Recorte de Tokens
Utiliza un tokenizador como tiktoken
para contar con precisión los tokens en tu historial de mensajes. Un tokenizador es esencial porque descompone el texto de la misma manera que lo hace el modelo de IA, asegurando conteos precisos de tokens. Cuando tu historial de conversación se acerca al límite de la ventana de contexto del modelo, necesitarás implementar una estrategia de recorte.
El enfoque más efectivo es eliminar los mensajes más antiguos en bloques completos (mensajes completos en lugar de parciales) para mantener la coherencia de la conversación. Esto preserva el flujo natural del diálogo mientras asegura que te mantengas dentro de los límites de tokens.
Por ejemplo, podrías eliminar primero el par más antiguo de mensajes usuario-asistente, manteniendo el mensaje del sistema y las interacciones más recientes intactas. Este enfoque es preferible a eliminar tokens individuales o mensajes parciales, lo que podría llevar a un contexto confuso o incompleto.
Ejemplo de código:
import tiktoken
from openai import OpenAI
client = OpenAI()
def count_tokens(messages, model="gpt-4o"):
"""Count tokens for a list of messages."""
try:
encoding = tiktoken.encoding_for_model(model)
except KeyError:
print(f"Warning: Model `{model}` not found. Using cl100k_base encoding.")
encoding = tiktoken.get_encoding("cl100k_base")
num_tokens = 0
for message in messages:
num_tokens += 4 # Format tax for each message
for key, value in message.items():
num_tokens += len(encoding.encode(value))
if key == "name": # Name tax
num_tokens += 1
num_tokens += 2 # Format tax for the entire message
return num_tokens
def trim_history(messages, max_tokens=10000, model="gpt-4o"):
"""Trim conversation history to fit within token limit."""
total_tokens = count_tokens(messages, model)
while total_tokens > max_tokens and len(messages) > 1:
# Calculate tokens of the message to be removed
tokens_to_remove = count_tokens([messages[1]], model) + 4 # +4 for format tax
if "name" in messages[1]:
tokens_to_remove += 1 # Name tax
messages.pop(1)
total_tokens -= tokens_to_remove
return messages
# Example usage:
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "The capital of France is Paris."},
{"role": "user", "name": "Alice", "content": "Tell me something else."},
{"role": "assistant", "content": "The Eiffel Tower is a famous landmark in Paris."},
]
token_count = count_tokens(messages)
print(f"Initial token count: {token_count}")
trimmed_messages = trim_history(messages, max_tokens=300)
trimmed_token_count = count_tokens(trimmed_messages)
print(f"Token count after trimming: {trimmed_token_count}")
print(f"Trimmed messages: {trimmed_messages}")
Desglose del Código:
- Importaciones y Configuración
- Importa tiktoken para el conteo de tokens
- Importa el cliente OpenAI para la interacción con la API
- Inicializa la instancia del cliente OpenAI
- Función count_tokens
Propósito: Cuenta con precisión los tokens en una lista de mensajes según las reglas de tokenización de OpenAI.
- Parámetros:
- messages: Lista de diccionarios de mensajes
- model: Nombre del modelo objetivo (predeterminado: "gpt-4o")
- Características Principales:
- Utiliza tokenizador específico del modelo cuando está disponible
- Recurre a la codificación cl100k_base si no se encuentra el modelo
- Considera el impuesto de formato de mensaje (+4 tokens por mensaje)
- Añade impuesto de nombre (+1 token) cuando está presente
- Incluye impuesto de formato para el mensaje completo (+2 tokens)
- Función trim_history
Propósito: Recorta el historial de conversación para ajustarse al límite de tokens mientras preserva el contexto reciente.
- Parámetros:
- messages: Lista de diccionarios de mensajes
- max_tokens: Tokens máximos permitidos (predeterminado: 10000)
- model: Nombre del modelo objetivo (predeterminado: "gpt-4o")
- Algoritmo:
- Cuenta el total de tokens en el historial actual
- Elimina los mensajes más antiguos (comenzando en el índice 1) hasta estar bajo el límite
- Conserva el mensaje del sistema (índice 0)
- Rastrea con precisión la reducción de tokens incluyendo impuestos de formato
- Implementación de Ejemplo
- Conversación de muestra:
- Mensaje del sistema definiendo el rol del asistente
- Dos mensajes de usuario (uno con nombre)
- Dos respuestas del asistente
- Demostración:
- Cuenta los tokens iniciales en la conversación
- Recorta el historial para ajustarse a 300 tokens
- Muestra el conteo de tokens antes y después del recorte
- Muestra la lista final de mensajes recortados
El ejemplo de uso muestra cómo aplicar estas funciones a un historial de conversación, contando los tokens iniciales y luego recortándolo para ajustarse a un límite de 300 tokens.
3. Resumen del Contexto Antiguo
Para conversaciones muy largas que abarcan muchos intercambios, implementar una estrategia de resumen se vuelve crucial para gestionar el contexto de manera efectiva mientras se mantiene dentro de los límites de tokens. Este enfoque implica condensar las partes anteriores de la conversación en un resumen conciso, que preserva la información esencial mientras utiliza significativamente menos tokens.
Puedes aprovechar las capacidades propias del modelo de IA llamándolo periódicamente para analizar el historial de conversación y generar un resumen significativo. Este resumen puede entonces reemplazar un bloque más grande de mensajes anteriores, manteniendo el contexto de la conversación mientras reduce drásticamente el uso de tokens.
El proceso de resumen es particularmente efectivo porque retiene los puntos clave de discusión y decisiones mientras elimina detalles redundantes o menos relevantes, asegurando que las respuestas futuras permanezcan contextualmente apropiadas sin requerir el historial completo de la conversación.
Ejemplo de código:
from openai import OpenAI
import tiktoken # Import tiktoken
def summarize_context(history, api_key, model="gpt-3.5-turbo", max_summary_tokens=80):
"""Summarizes a conversation history.
Args:
history: A list of message dictionaries.
api_key: Your OpenAI API key.
model: The OpenAI model to use for summarization.
max_summary_tokens: The maximum number of tokens for the summary.
Returns:
A list containing a single message with the summary, or the original
history if summarization fails.
"""
client = OpenAI(api_key=api_key)
encoding = tiktoken.encoding_for_model(model) # Added encoding
# Improved prompt with more specific instructions
prompt = [
{"role": "system", "content": "You are a helpful assistant that provides concise summaries of conversations."},
{"role": "user", "content": (
"Please provide a two-sentence summary of the following conversation, focusing on the key topics discussed and the main points:\n" +
"\n".join([f'{m["role"]}: {m["content"]}' for m in history])
)}
]
prompt_token_count = len(encoding.encode(prompt[1]["content"])) # Count tokens
if prompt_token_count > 4000: # Check if prompt is too long.
print("Warning: Prompt is longer than 4000 tokens. Consider Trimming History")
try:
response = client.chat.completions.create(
model=model,
messages=prompt,
max_tokens=max_summary_tokens,
temperature=0.2, # Lower temperature for more focused summaries
)
summary = response.choices[0].message.content
return [{"role": "system", "content": "Conversation summary: " + summary}]
except Exception as e:
print(f"Error during summarization: {str(e)}")
return history # Return original history if summarization fails
Este código implementa una función de resumen de conversaciones que ayuda a gestionar historiales de conversación extensos. Aquí está el desglose de sus componentes principales:
Descripción General de la Función:
La función summarize_context
toma un historial de conversación y lo convierte en un resumen conciso de dos oraciones. Los parámetros principales incluyen:
- history: Los mensajes de conversación a resumir
- api_key: Autenticación de la API de OpenAI
- model: El modelo de IA a utilizar (por defecto: GPT-3.5-turbo)
- max_summary_tokens: Longitud máxima del resumen
Características Principales:
- Utiliza tiktoken para un conteo preciso de tokens
- Implementa verificaciones de límite de tokens (advierte si supera los 4000 tokens)
- Utiliza una temperatura baja (0.2) para resúmenes más consistentes
- Recurre al historial original si falla el resumen
Proceso:
- Inicializa el cliente OpenAI y configura la codificación de tokens
- Crea un prompt con instrucciones específicas para el resumen
- Formatea el historial de conversación en un formato legible
- Realiza la llamada a la API para generar el resumen
- Devuelve el resumen como mensaje del sistema o el historial original si hay un error
Esta función es particularmente útil cuando los historiales de conversación se vuelven demasiado largos, ya que ayuda a mantener el contexto mientras reduce el uso de tokens. La versión resumida puede entonces anteponerse a los mensajes más recientes para mantener la continuidad de la conversación.
7.2.3 Integrando Todo
Ahora, exploremos cómo combinar perfectamente las técnicas de recorte y resumen que discutimos en un flujo de trabajo unificado y efectivo. Esta integración es crucial para mantener una gestión óptima de la conversación, ya que nos permite manejar tanto las restricciones inmediatas de tokens como la preservación del contexto a largo plazo en un proceso único y coordinado.
El siguiente ejemplo de código demuestra cómo estos componentes trabajan juntos para crear un sistema robusto de gestión de conversaciones que puede manejar desde el procesamiento básico de mensajes hasta el mantenimiento de contexto complejo.
from openai import OpenAI
from typing import List, Dict
import tiktoken
from datetime import datetime
class ConversationManager:
def __init__(self, api_key: str, model: str = "gpt-3.5-turbo"):
self.client = OpenAI(api_key=api_key)
self.model = model
self.threads: Dict[str, List[Dict]] = {}
self.encoding = tiktoken.encoding_for_model(model)
def append_message(self, user_id: str, role: str, content: str) -> None:
"""Add a new message to the user's conversation thread."""
if user_id not in self.threads:
self.threads[user_id] = [
{"role": "system", "content": "You are a helpful assistant."}
]
self.threads[user_id].append({"role": role, "content": content})
def count_tokens(self, messages: List[Dict]) -> int:
"""Count tokens in the message list."""
num_tokens = 0
for message in messages:
num_tokens += 4 # Message format tax
for key, value in message.items():
num_tokens += len(self.encoding.encode(str(value)))
if key == "name":
num_tokens += 1 # Name field tax
return num_tokens + 2 # Add final format tax
def summarize_context(self, history: List[Dict], max_summary_tokens: int = 300) -> List[Dict]:
"""Generate a summary of the conversation history."""
try:
prompt = [
{"role": "system", "content": "Summarize this conversation in two concise sentences:"},
{"role": "user", "content": "\n".join([f"{m['role']}: {m['content']}"
for m in history if m['role'] != "system"])}
]
response = self.client.chat.completions.create(
model=self.model,
messages=prompt,
max_tokens=max_summary_tokens,
temperature=0.3
)
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return [{
"role": "system",
"content": f"Summary as of {timestamp}: {response.choices[0].message.content}"
}]
except Exception as e:
print(f"Summarization failed: {str(e)}")
return history
def trim_history(self, messages: List[Dict], max_tokens: int) -> List[Dict]:
"""Trim conversation history to fit within token limit."""
while self.count_tokens(messages) > max_tokens and len(messages) > 1:
# Remove second message (preserve system message)
messages.pop(1)
return messages
def manage_context_thread(self, user_id: str, new_message: str,
max_tokens: int = 4000,
summary_threshold: int = 3000) -> List[Dict]:
"""Manage conversation context with token limits and summarization."""
# Add new message
self.append_message(user_id, "user", new_message)
history = self.threads[user_id]
current_tokens = self.count_tokens(history)
# Log for debugging
print(f"Current token count: {current_tokens}")
# If approaching token limit, summarize older context
if current_tokens > summary_threshold:
# Keep system message and last 3 message pairs (6 messages)
recent_messages = history[-6:] if len(history) > 6 else history
older_messages = history[1:-6] if len(history) > 6 else []
if older_messages:
summary = self.summarize_context(older_messages)
history = [history[0]] + summary + recent_messages
print("Context summarized")
# Ensure we're under max tokens
history = self.trim_history(history, max_tokens)
self.threads[user_id] = history
return history
# Example usage
if __name__ == "__main__":
manager = ConversationManager("your-api-key-here")
# Simulate a conversation
user_id = "user123"
messages = [
"Hello! How can you help me today?",
"I'd like to learn about machine learning.",
"Can you explain neural networks?",
"What's the difference between supervised and unsupervised learning?"
]
# Process messages
for msg in messages:
history = manager.manage_context_thread(user_id, msg)
print(f"\nMessage: {msg}")
print(f"Thread length: {len(history)}")
print(f"Token count: {manager.count_tokens(history)}")
Desglose del Código:
- Estructura de Clase
- La clase ConversationManager maneja todos los aspectos de la gestión de conversaciones
- Se inicializa con la clave API de OpenAI y la selección del modelo
- Mantiene hilos de conversación para múltiples usuarios
- Utiliza tiktoken para el conteo preciso de tokens
- Métodos Principales
- append_message()
- Agrega nuevos mensajes a los hilos de conversación específicos del usuario
- Inicializa nuevos hilos con un mensaje del sistema
- count_tokens()
- Cuenta tokens con precisión incluyendo impuestos de formato
- Considera la estructura del mensaje y campos de nombre
- Características Avanzadas
- summarize_context()
- Utiliza la API de OpenAI para generar resúmenes concisos
- Incluye marcas temporales para contexto
- Maneja errores de manera elegante
- trim_history()
- Elimina los mensajes más antiguos mientras preserva el mensaje del sistema
- Asegura que la conversación se mantenga dentro de los límites de tokens
- Lógica Principal de Gestión
- manage_context_thread()
- Implementa gestión de contexto en tres fases:
- Adición de nuevos mensajes
- Resumen del contexto anterior
- Control de límite de tokens
- Utiliza umbrales separados para resumen y tokens máximos
- Implementa gestión de contexto en tres fases:
- Ejemplo de Uso
- Demuestra implementación práctica con múltiples mensajes
- Incluye conteo de tokens y monitoreo de longitud de hilo
- Muestra cómo mantener el contexto de conversación a través de múltiples intercambios
Con este enfoque:
- Se agregan nuevos mensajes.
- Se verifica la longitud del historial.
- Si se supera el límite, se resume toda la conversación, se mantiene el resumen y los últimos mensajes.
- Se recorta cualquier exceso restante.
La gestión de hilos y ventanas de contexto es un aspecto fundamental para construir conversaciones escalables y coherentes de múltiples turnos en sistemas de IA. Aquí está por qué es importante y cómo funciona:
Primero, la segmentación de hilos por usuario asegura que cada conversación permanezca aislada y personal. Al mantener hilos de conversación separados para cada usuario, se previene la contaminación cruzada de contexto entre diferentes conversaciones, permitiendo respuestas más personalizadas y precisas.
Segundo, el conteo de tokens y recorte sirven como herramientas esenciales de mantenimiento. Al monitorear activamente el conteo de tokens de las conversaciones, puedes prevenir alcanzar los límites del contexto del modelo mientras preservas la información más relevante. Este proceso implica eliminar cuidadosamente mensajes antiguos mientras se mantiene el contexto crucial, similar a cómo las conversaciones humanas naturalmente se centran en información reciente y relevante.
Tercero, la sumarización del contexto actúa como una técnica de compresión de memoria. Cuando las conversaciones se alargan, resumir el contexto anterior permite mantener la narrativa esencial mientras se reduce el uso de tokens. Esto es similar a cómo los humanos mantienen la esencia de conversaciones anteriores sin recordar cada detalle.
La combinación de estas estrategias resulta en un asistente de IA que puede:
- Mantener un contexto consistente a través de múltiples turnos de conversación
- Escalar eficientemente sin degradar el rendimiento
- Proporcionar respuestas relevantes basadas tanto en contexto reciente como histórico
- Adaptarse a diferentes longitudes y complejidades de conversación
Estas capacidades aseguran que tu asistente de IA permanezca receptivo, informado y consciente del contexto durante diálogos extensos, creando una experiencia de conversación más natural y efectiva.
7.2 Gestión de hilos y ventanas de contexto
En conversaciones de múltiples turnos, especialmente aquellas que se extienden a lo largo de múltiples mensajes o sesiones, gestionar el contexto de manera efectiva es crucial para mantener un diálogo significativo. Esto se vuelve particularmente importante en aplicaciones de IA donde las conversaciones pueden volverse complejas y extensas. Los modelos de OpenAI operan dentro de una "ventana de contexto" fija—un número máximo de tokens que pueden considerar en una llamada (hasta 128K tokens para algunos modelos). Piensa en esta ventana como la memoria de trabajo del modelo, similar a cómo los humanos solo pueden mantener cierta cantidad de información en sus pensamientos inmediatos.
Cuando tu conversación se extiende más allá de este límite de ventana, los mensajes más antiguos pueden ser truncados o eliminados de la consideración, causando que el modelo pierda contexto importante. Esto puede llevar a varios problemas: el modelo podría olvidar partes anteriores de la conversación, repetir información o fallar en mantener la consistencia con hechos o preferencias previamente establecidos. Por ejemplo, si un usuario hace referencia a algo mencionado anteriormente en la conversación que fue truncado, el modelo no tendrá acceso a esa información para proporcionar una respuesta apropiada.
Por lo tanto, la gestión adecuada de hilos es esencial—asegura que tus aplicaciones permanezcan coherentes y enfocadas, incluso cuando las conversaciones crecen en longitud y complejidad. Esto implica implementar estrategias para preservar el contexto crucial mientras se gestiona eficientemente el límite de tokens, como resumir intercambios previos, mantener información relevante y decidir inteligentemente qué partes de la conversación mantener o eliminar. A través de una gestión efectiva de hilos, puedes crear conversaciones más naturales y conscientes del contexto que mantienen su coherencia y utilidad a lo largo de interacciones extendidas.
7.2.1 ¿Qué es una Ventana de Contexto?
Una ventana de contexto es un concepto fundamental en los modelos de lenguaje de IA que define la cantidad máxima de texto que el modelo puede procesar y comprender a la vez. Esta ventana actúa como la memoria de trabajo del modelo - similar a cómo los humanos solo pueden mantener cierta cantidad de información en sus pensamientos inmediatos. El tamaño de esta ventana se mide en tokens, que son los bloques fundamentales que el modelo utiliza para procesar el lenguaje.
Para entender mejor los tokens, piensa en ellos como las piezas del vocabulario del modelo. Mientras que los humanos naturalmente dividimos el lenguaje en palabras, los modelos de IA descomponen el texto de manera diferente. Una sola palabra puede convertirse en múltiples tokens - por ejemplo, "entendimiento" se convierte en "entend" + "imiento", mientras que palabras comunes como "el" o "y" suelen ser tokens individuales. Incluso los signos de puntuación y espacios cuentan como tokens. Esta tokenización ayuda al modelo a procesar el texto de manera más eficiente y comprender mejor los patrones del lenguaje.
Cuando mantienes una conversación con un modelo de IA, este maneja tu interacción de una manera fascinante. Cada parte de la conversación - ya sean las instrucciones iniciales (mensajes del sistema), tus preguntas (mensajes del usuario) o las respuestas de la IA (mensajes del asistente) - se entretejen en una secuencia continua. Este texto combinado luego pasa por el proceso de tokenización, donde se descompone en tokens y se analiza como una unidad completa.
Sin embargo, hay una limitación crucial a tener en cuenta: la ventana de contexto tiene un tamaño fijo. Cuando tu conversación crece demasiado y excede este límite de tokens, el modelo tiene que hacer espacio para nueva información. Lo hace eliminando mensajes antiguos desde el principio de la conversación, similar a cómo la aplicación de mensajería de tu teléfono podría mostrar solo los mensajes más recientes en una ventana de chat. Por esto es que a veces el modelo podría no recordar algo mencionado mucho antes en una conversación larga.
- GPT-3.5-turbo: ~16K tokens (aproximadamente equivalente a 12,000 palabras o 48 páginas de texto). Esta ventana de contexto sustancial permite conversaciones detalladas y tareas complejas, aunque puede necesitar gestión en interacciones más largas.
- GPT-4o y GPT-4o-mini: ~128K tokens (aproximadamente equivalente a 96,000 palabras o 384 páginas de texto, variando según tu plan de suscripción). Esta ventana de contexto significativamente más grande permite conversaciones mucho más largas y análisis más complejos, haciéndola adecuada para revisión extensa de documentación, creación de contenido de formato largo y tareas analíticas detalladas.
7.2.2 Estrategias de Gestión de Hilos
1. Segmentación en Hilos Lógicos
Al construir aplicaciones de IA que manejan conversaciones, es crucial implementar una segmentación adecuada de hilos. Esto significa organizar las conversaciones en matrices de mensajes separadas e independientes (hilos) basadas en diferentes usuarios, temas o contextos. Piensa en ello como tener diferentes salas de chat o canales de conversación - cada uno mantiene su propia historia y contexto sin interferir con los demás.
Por ejemplo, si tienes un bot de servicio al cliente ayudando a múltiples clientes simultáneamente, la conversación de cada cliente debe almacenarse en un hilo separado. Esto asegura que cuando el Cliente A pregunta sobre el estado de su pedido, el bot no hará referencia accidentalmente a los detalles de envío del Cliente B. De manera similar, si tu aplicación maneja diferentes temas (como consejos médicos vs soporte técnico), mantener hilos separados previene la confusión y mantiene la precisión contextual.
Este enfoque de segmentación ofrece varios beneficios:
- Límites claros de conversación
- Mejor gestión del contexto
- Mayor precisión en las respuestas
- Depuración y monitoreo más fácil
- Privacidad mejorada entre diferentes usuarios o temas
La clave es implementar un sistema robusto para crear, gestionar y almacenar estos hilos separados mientras se asegura que cada uno mantenga su propio historial completo de conversación.
# Example: Separate threads for different users.
threads = {
"user_1": [{"role": "system", "content": "You are a friendly assistant."}],
"user_2": [{"role": "system", "content": "You are an expert math tutor."}]
}
def append_message(user_id, role, content):
threads[user_id].append({"role": role, "content": content})
Este código demuestra una implementación básica de la gestión de hilos de conversación. Permíteme desglosarlo:
Estructura de Datos:
- El código utiliza un diccionario llamado 'threads' para almacenar hilos de conversación separados para diferentes usuarios
- Cada usuario (user_1, user_2) tiene su propio array de mensajes con un mensaje de sistema único que define el rol del asistente (asistente amigable vs tutor de matemáticas)
Funcionalidad:
- La función append_message() permite agregar nuevos mensajes al hilo de un usuario específico
- Toma tres parámetros: user_id (para identificar el hilo), role (quién está hablando), y content (el mensaje)
Esta implementación simple asegura que las conversaciones permanezcan separadas y contextualmente apropiadas para cada usuario, evitando la contaminación cruzada de conversaciones entre diferentes usuarios.
Aquí hay una implementación integral
# Example: Thread management with OpenAI API
import openai
from typing import Dict, List
import time
class ThreadManager:
def __init__(self, api_key: str):
self.threads: Dict[str, List[Dict]] = {}
openai.api_key = api_key
def create_thread(self, user_id: str, system_role: str) -> None:
"""Initialize a new thread for a user with system message."""
self.threads[user_id] = [
{"role": "system", "content": system_role}
]
def append_message(self, user_id: str, role: str, content: str) -> None:
"""Add a message to user's thread."""
if user_id not in self.threads:
self.create_thread(user_id, "You are a helpful assistant.")
self.threads[user_id].append({
"role": role,
"content": content,
"timestamp": time.time()
})
async def get_response(self, user_id: str, temperature: float = 0.7) -> str:
"""Get AI response using GPT-4o."""
try:
response = await openai.ChatCompletion.acreate(
model="gpt-4o",
messages=self.threads[user_id],
temperature=temperature,
max_tokens=1000
)
ai_response = response.choices[0].message.content
self.append_message(user_id, "assistant", ai_response)
return ai_response
except Exception as e:
return f"Error: {str(e)}"
# Usage example
async def main():
thread_mgr = ThreadManager("your-api-key-here")
# Create threads for different users
thread_mgr.create_thread("user_1", "You are a friendly assistant.")
thread_mgr.create_thread("user_2", "You are an expert math tutor.")
# Simulate conversation
thread_mgr.append_message("user_1", "user", "Hello! How are you?")
response = await thread_mgr.get_response("user_1")
print(f"Assistant: {response}")
Este ejemplo muestra una implementación de un sistema de gestión de hilos para manejar múltiples conversaciones con un asistente de IA. Aquí están los componentes principales:
Clase ThreadManager:
- Gestiona hilos de conversación separados para diferentes usuarios
- Almacena los hilos en un diccionario con IDs de usuario como claves
Funciones Principales:
- create_thread(): Configura nuevas conversaciones con un rol de sistema (por ejemplo, "asistente amigable" o "tutor de matemáticas")
- append_message(): Agrega nuevos mensajes al hilo de conversación de un usuario con marcas de tiempo
- get_response(): Realiza llamadas a la API de GPT-4o para obtener respuestas de la IA
Características Principales:
- Manejo de errores para llamadas a la API
- Soporte asíncrono para mejor rendimiento
- Creación automática de hilos si no existen
- Seguimiento de marcas de tiempo de mensajes
El código ayuda a prevenir la contaminación cruzada de conversaciones entre diferentes usuarios al mantener la conversación de cada usuario separada y contextualmente apropiada.
Desglose del Código:
Estructura de Clase
- La clase ThreadManager maneja todas las operaciones relacionadas con hilos
- Utiliza un diccionario para almacenar hilos con IDs de usuario como claves
- Se inicializa con la clave API de OpenAI
Métodos Principales
- create_thread(): Inicializa nuevos hilos de conversación
- append_message(): Agrega mensajes a hilos existentes
- get_response(): Maneja llamadas a la API de GPT-4o
Mejoras sobre la Versión Básica
- Manejo adecuado de errores
- Soporte asíncrono para mejor rendimiento
- Seguimiento de marcas de tiempo
- Control de temperatura para variación de respuestas
Características de Seguridad
- Creación automática de hilos si no existen
- Bloque try-except para llamadas a la API
- Indicaciones de tipo para mejor mantenibilidad del código
2. Conteo y Recorte de Tokens
Utiliza un tokenizador como tiktoken
para contar con precisión los tokens en tu historial de mensajes. Un tokenizador es esencial porque descompone el texto de la misma manera que lo hace el modelo de IA, asegurando conteos precisos de tokens. Cuando tu historial de conversación se acerca al límite de la ventana de contexto del modelo, necesitarás implementar una estrategia de recorte.
El enfoque más efectivo es eliminar los mensajes más antiguos en bloques completos (mensajes completos en lugar de parciales) para mantener la coherencia de la conversación. Esto preserva el flujo natural del diálogo mientras asegura que te mantengas dentro de los límites de tokens.
Por ejemplo, podrías eliminar primero el par más antiguo de mensajes usuario-asistente, manteniendo el mensaje del sistema y las interacciones más recientes intactas. Este enfoque es preferible a eliminar tokens individuales o mensajes parciales, lo que podría llevar a un contexto confuso o incompleto.
Ejemplo de código:
import tiktoken
from openai import OpenAI
client = OpenAI()
def count_tokens(messages, model="gpt-4o"):
"""Count tokens for a list of messages."""
try:
encoding = tiktoken.encoding_for_model(model)
except KeyError:
print(f"Warning: Model `{model}` not found. Using cl100k_base encoding.")
encoding = tiktoken.get_encoding("cl100k_base")
num_tokens = 0
for message in messages:
num_tokens += 4 # Format tax for each message
for key, value in message.items():
num_tokens += len(encoding.encode(value))
if key == "name": # Name tax
num_tokens += 1
num_tokens += 2 # Format tax for the entire message
return num_tokens
def trim_history(messages, max_tokens=10000, model="gpt-4o"):
"""Trim conversation history to fit within token limit."""
total_tokens = count_tokens(messages, model)
while total_tokens > max_tokens and len(messages) > 1:
# Calculate tokens of the message to be removed
tokens_to_remove = count_tokens([messages[1]], model) + 4 # +4 for format tax
if "name" in messages[1]:
tokens_to_remove += 1 # Name tax
messages.pop(1)
total_tokens -= tokens_to_remove
return messages
# Example usage:
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "The capital of France is Paris."},
{"role": "user", "name": "Alice", "content": "Tell me something else."},
{"role": "assistant", "content": "The Eiffel Tower is a famous landmark in Paris."},
]
token_count = count_tokens(messages)
print(f"Initial token count: {token_count}")
trimmed_messages = trim_history(messages, max_tokens=300)
trimmed_token_count = count_tokens(trimmed_messages)
print(f"Token count after trimming: {trimmed_token_count}")
print(f"Trimmed messages: {trimmed_messages}")
Desglose del Código:
- Importaciones y Configuración
- Importa tiktoken para el conteo de tokens
- Importa el cliente OpenAI para la interacción con la API
- Inicializa la instancia del cliente OpenAI
- Función count_tokens
Propósito: Cuenta con precisión los tokens en una lista de mensajes según las reglas de tokenización de OpenAI.
- Parámetros:
- messages: Lista de diccionarios de mensajes
- model: Nombre del modelo objetivo (predeterminado: "gpt-4o")
- Características Principales:
- Utiliza tokenizador específico del modelo cuando está disponible
- Recurre a la codificación cl100k_base si no se encuentra el modelo
- Considera el impuesto de formato de mensaje (+4 tokens por mensaje)
- Añade impuesto de nombre (+1 token) cuando está presente
- Incluye impuesto de formato para el mensaje completo (+2 tokens)
- Función trim_history
Propósito: Recorta el historial de conversación para ajustarse al límite de tokens mientras preserva el contexto reciente.
- Parámetros:
- messages: Lista de diccionarios de mensajes
- max_tokens: Tokens máximos permitidos (predeterminado: 10000)
- model: Nombre del modelo objetivo (predeterminado: "gpt-4o")
- Algoritmo:
- Cuenta el total de tokens en el historial actual
- Elimina los mensajes más antiguos (comenzando en el índice 1) hasta estar bajo el límite
- Conserva el mensaje del sistema (índice 0)
- Rastrea con precisión la reducción de tokens incluyendo impuestos de formato
- Implementación de Ejemplo
- Conversación de muestra:
- Mensaje del sistema definiendo el rol del asistente
- Dos mensajes de usuario (uno con nombre)
- Dos respuestas del asistente
- Demostración:
- Cuenta los tokens iniciales en la conversación
- Recorta el historial para ajustarse a 300 tokens
- Muestra el conteo de tokens antes y después del recorte
- Muestra la lista final de mensajes recortados
El ejemplo de uso muestra cómo aplicar estas funciones a un historial de conversación, contando los tokens iniciales y luego recortándolo para ajustarse a un límite de 300 tokens.
3. Resumen del Contexto Antiguo
Para conversaciones muy largas que abarcan muchos intercambios, implementar una estrategia de resumen se vuelve crucial para gestionar el contexto de manera efectiva mientras se mantiene dentro de los límites de tokens. Este enfoque implica condensar las partes anteriores de la conversación en un resumen conciso, que preserva la información esencial mientras utiliza significativamente menos tokens.
Puedes aprovechar las capacidades propias del modelo de IA llamándolo periódicamente para analizar el historial de conversación y generar un resumen significativo. Este resumen puede entonces reemplazar un bloque más grande de mensajes anteriores, manteniendo el contexto de la conversación mientras reduce drásticamente el uso de tokens.
El proceso de resumen es particularmente efectivo porque retiene los puntos clave de discusión y decisiones mientras elimina detalles redundantes o menos relevantes, asegurando que las respuestas futuras permanezcan contextualmente apropiadas sin requerir el historial completo de la conversación.
Ejemplo de código:
from openai import OpenAI
import tiktoken # Import tiktoken
def summarize_context(history, api_key, model="gpt-3.5-turbo", max_summary_tokens=80):
"""Summarizes a conversation history.
Args:
history: A list of message dictionaries.
api_key: Your OpenAI API key.
model: The OpenAI model to use for summarization.
max_summary_tokens: The maximum number of tokens for the summary.
Returns:
A list containing a single message with the summary, or the original
history if summarization fails.
"""
client = OpenAI(api_key=api_key)
encoding = tiktoken.encoding_for_model(model) # Added encoding
# Improved prompt with more specific instructions
prompt = [
{"role": "system", "content": "You are a helpful assistant that provides concise summaries of conversations."},
{"role": "user", "content": (
"Please provide a two-sentence summary of the following conversation, focusing on the key topics discussed and the main points:\n" +
"\n".join([f'{m["role"]}: {m["content"]}' for m in history])
)}
]
prompt_token_count = len(encoding.encode(prompt[1]["content"])) # Count tokens
if prompt_token_count > 4000: # Check if prompt is too long.
print("Warning: Prompt is longer than 4000 tokens. Consider Trimming History")
try:
response = client.chat.completions.create(
model=model,
messages=prompt,
max_tokens=max_summary_tokens,
temperature=0.2, # Lower temperature for more focused summaries
)
summary = response.choices[0].message.content
return [{"role": "system", "content": "Conversation summary: " + summary}]
except Exception as e:
print(f"Error during summarization: {str(e)}")
return history # Return original history if summarization fails
Este código implementa una función de resumen de conversaciones que ayuda a gestionar historiales de conversación extensos. Aquí está el desglose de sus componentes principales:
Descripción General de la Función:
La función summarize_context
toma un historial de conversación y lo convierte en un resumen conciso de dos oraciones. Los parámetros principales incluyen:
- history: Los mensajes de conversación a resumir
- api_key: Autenticación de la API de OpenAI
- model: El modelo de IA a utilizar (por defecto: GPT-3.5-turbo)
- max_summary_tokens: Longitud máxima del resumen
Características Principales:
- Utiliza tiktoken para un conteo preciso de tokens
- Implementa verificaciones de límite de tokens (advierte si supera los 4000 tokens)
- Utiliza una temperatura baja (0.2) para resúmenes más consistentes
- Recurre al historial original si falla el resumen
Proceso:
- Inicializa el cliente OpenAI y configura la codificación de tokens
- Crea un prompt con instrucciones específicas para el resumen
- Formatea el historial de conversación en un formato legible
- Realiza la llamada a la API para generar el resumen
- Devuelve el resumen como mensaje del sistema o el historial original si hay un error
Esta función es particularmente útil cuando los historiales de conversación se vuelven demasiado largos, ya que ayuda a mantener el contexto mientras reduce el uso de tokens. La versión resumida puede entonces anteponerse a los mensajes más recientes para mantener la continuidad de la conversación.
7.2.3 Integrando Todo
Ahora, exploremos cómo combinar perfectamente las técnicas de recorte y resumen que discutimos en un flujo de trabajo unificado y efectivo. Esta integración es crucial para mantener una gestión óptima de la conversación, ya que nos permite manejar tanto las restricciones inmediatas de tokens como la preservación del contexto a largo plazo en un proceso único y coordinado.
El siguiente ejemplo de código demuestra cómo estos componentes trabajan juntos para crear un sistema robusto de gestión de conversaciones que puede manejar desde el procesamiento básico de mensajes hasta el mantenimiento de contexto complejo.
from openai import OpenAI
from typing import List, Dict
import tiktoken
from datetime import datetime
class ConversationManager:
def __init__(self, api_key: str, model: str = "gpt-3.5-turbo"):
self.client = OpenAI(api_key=api_key)
self.model = model
self.threads: Dict[str, List[Dict]] = {}
self.encoding = tiktoken.encoding_for_model(model)
def append_message(self, user_id: str, role: str, content: str) -> None:
"""Add a new message to the user's conversation thread."""
if user_id not in self.threads:
self.threads[user_id] = [
{"role": "system", "content": "You are a helpful assistant."}
]
self.threads[user_id].append({"role": role, "content": content})
def count_tokens(self, messages: List[Dict]) -> int:
"""Count tokens in the message list."""
num_tokens = 0
for message in messages:
num_tokens += 4 # Message format tax
for key, value in message.items():
num_tokens += len(self.encoding.encode(str(value)))
if key == "name":
num_tokens += 1 # Name field tax
return num_tokens + 2 # Add final format tax
def summarize_context(self, history: List[Dict], max_summary_tokens: int = 300) -> List[Dict]:
"""Generate a summary of the conversation history."""
try:
prompt = [
{"role": "system", "content": "Summarize this conversation in two concise sentences:"},
{"role": "user", "content": "\n".join([f"{m['role']}: {m['content']}"
for m in history if m['role'] != "system"])}
]
response = self.client.chat.completions.create(
model=self.model,
messages=prompt,
max_tokens=max_summary_tokens,
temperature=0.3
)
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return [{
"role": "system",
"content": f"Summary as of {timestamp}: {response.choices[0].message.content}"
}]
except Exception as e:
print(f"Summarization failed: {str(e)}")
return history
def trim_history(self, messages: List[Dict], max_tokens: int) -> List[Dict]:
"""Trim conversation history to fit within token limit."""
while self.count_tokens(messages) > max_tokens and len(messages) > 1:
# Remove second message (preserve system message)
messages.pop(1)
return messages
def manage_context_thread(self, user_id: str, new_message: str,
max_tokens: int = 4000,
summary_threshold: int = 3000) -> List[Dict]:
"""Manage conversation context with token limits and summarization."""
# Add new message
self.append_message(user_id, "user", new_message)
history = self.threads[user_id]
current_tokens = self.count_tokens(history)
# Log for debugging
print(f"Current token count: {current_tokens}")
# If approaching token limit, summarize older context
if current_tokens > summary_threshold:
# Keep system message and last 3 message pairs (6 messages)
recent_messages = history[-6:] if len(history) > 6 else history
older_messages = history[1:-6] if len(history) > 6 else []
if older_messages:
summary = self.summarize_context(older_messages)
history = [history[0]] + summary + recent_messages
print("Context summarized")
# Ensure we're under max tokens
history = self.trim_history(history, max_tokens)
self.threads[user_id] = history
return history
# Example usage
if __name__ == "__main__":
manager = ConversationManager("your-api-key-here")
# Simulate a conversation
user_id = "user123"
messages = [
"Hello! How can you help me today?",
"I'd like to learn about machine learning.",
"Can you explain neural networks?",
"What's the difference between supervised and unsupervised learning?"
]
# Process messages
for msg in messages:
history = manager.manage_context_thread(user_id, msg)
print(f"\nMessage: {msg}")
print(f"Thread length: {len(history)}")
print(f"Token count: {manager.count_tokens(history)}")
Desglose del Código:
- Estructura de Clase
- La clase ConversationManager maneja todos los aspectos de la gestión de conversaciones
- Se inicializa con la clave API de OpenAI y la selección del modelo
- Mantiene hilos de conversación para múltiples usuarios
- Utiliza tiktoken para el conteo preciso de tokens
- Métodos Principales
- append_message()
- Agrega nuevos mensajes a los hilos de conversación específicos del usuario
- Inicializa nuevos hilos con un mensaje del sistema
- count_tokens()
- Cuenta tokens con precisión incluyendo impuestos de formato
- Considera la estructura del mensaje y campos de nombre
- Características Avanzadas
- summarize_context()
- Utiliza la API de OpenAI para generar resúmenes concisos
- Incluye marcas temporales para contexto
- Maneja errores de manera elegante
- trim_history()
- Elimina los mensajes más antiguos mientras preserva el mensaje del sistema
- Asegura que la conversación se mantenga dentro de los límites de tokens
- Lógica Principal de Gestión
- manage_context_thread()
- Implementa gestión de contexto en tres fases:
- Adición de nuevos mensajes
- Resumen del contexto anterior
- Control de límite de tokens
- Utiliza umbrales separados para resumen y tokens máximos
- Implementa gestión de contexto en tres fases:
- Ejemplo de Uso
- Demuestra implementación práctica con múltiples mensajes
- Incluye conteo de tokens y monitoreo de longitud de hilo
- Muestra cómo mantener el contexto de conversación a través de múltiples intercambios
Con este enfoque:
- Se agregan nuevos mensajes.
- Se verifica la longitud del historial.
- Si se supera el límite, se resume toda la conversación, se mantiene el resumen y los últimos mensajes.
- Se recorta cualquier exceso restante.
La gestión de hilos y ventanas de contexto es un aspecto fundamental para construir conversaciones escalables y coherentes de múltiples turnos en sistemas de IA. Aquí está por qué es importante y cómo funciona:
Primero, la segmentación de hilos por usuario asegura que cada conversación permanezca aislada y personal. Al mantener hilos de conversación separados para cada usuario, se previene la contaminación cruzada de contexto entre diferentes conversaciones, permitiendo respuestas más personalizadas y precisas.
Segundo, el conteo de tokens y recorte sirven como herramientas esenciales de mantenimiento. Al monitorear activamente el conteo de tokens de las conversaciones, puedes prevenir alcanzar los límites del contexto del modelo mientras preservas la información más relevante. Este proceso implica eliminar cuidadosamente mensajes antiguos mientras se mantiene el contexto crucial, similar a cómo las conversaciones humanas naturalmente se centran en información reciente y relevante.
Tercero, la sumarización del contexto actúa como una técnica de compresión de memoria. Cuando las conversaciones se alargan, resumir el contexto anterior permite mantener la narrativa esencial mientras se reduce el uso de tokens. Esto es similar a cómo los humanos mantienen la esencia de conversaciones anteriores sin recordar cada detalle.
La combinación de estas estrategias resulta en un asistente de IA que puede:
- Mantener un contexto consistente a través de múltiples turnos de conversación
- Escalar eficientemente sin degradar el rendimiento
- Proporcionar respuestas relevantes basadas tanto en contexto reciente como histórico
- Adaptarse a diferentes longitudes y complejidades de conversación
Estas capacidades aseguran que tu asistente de IA permanezca receptivo, informado y consciente del contexto durante diálogos extensos, creando una experiencia de conversación más natural y efectiva.
7.2 Gestión de hilos y ventanas de contexto
En conversaciones de múltiples turnos, especialmente aquellas que se extienden a lo largo de múltiples mensajes o sesiones, gestionar el contexto de manera efectiva es crucial para mantener un diálogo significativo. Esto se vuelve particularmente importante en aplicaciones de IA donde las conversaciones pueden volverse complejas y extensas. Los modelos de OpenAI operan dentro de una "ventana de contexto" fija—un número máximo de tokens que pueden considerar en una llamada (hasta 128K tokens para algunos modelos). Piensa en esta ventana como la memoria de trabajo del modelo, similar a cómo los humanos solo pueden mantener cierta cantidad de información en sus pensamientos inmediatos.
Cuando tu conversación se extiende más allá de este límite de ventana, los mensajes más antiguos pueden ser truncados o eliminados de la consideración, causando que el modelo pierda contexto importante. Esto puede llevar a varios problemas: el modelo podría olvidar partes anteriores de la conversación, repetir información o fallar en mantener la consistencia con hechos o preferencias previamente establecidos. Por ejemplo, si un usuario hace referencia a algo mencionado anteriormente en la conversación que fue truncado, el modelo no tendrá acceso a esa información para proporcionar una respuesta apropiada.
Por lo tanto, la gestión adecuada de hilos es esencial—asegura que tus aplicaciones permanezcan coherentes y enfocadas, incluso cuando las conversaciones crecen en longitud y complejidad. Esto implica implementar estrategias para preservar el contexto crucial mientras se gestiona eficientemente el límite de tokens, como resumir intercambios previos, mantener información relevante y decidir inteligentemente qué partes de la conversación mantener o eliminar. A través de una gestión efectiva de hilos, puedes crear conversaciones más naturales y conscientes del contexto que mantienen su coherencia y utilidad a lo largo de interacciones extendidas.
7.2.1 ¿Qué es una Ventana de Contexto?
Una ventana de contexto es un concepto fundamental en los modelos de lenguaje de IA que define la cantidad máxima de texto que el modelo puede procesar y comprender a la vez. Esta ventana actúa como la memoria de trabajo del modelo - similar a cómo los humanos solo pueden mantener cierta cantidad de información en sus pensamientos inmediatos. El tamaño de esta ventana se mide en tokens, que son los bloques fundamentales que el modelo utiliza para procesar el lenguaje.
Para entender mejor los tokens, piensa en ellos como las piezas del vocabulario del modelo. Mientras que los humanos naturalmente dividimos el lenguaje en palabras, los modelos de IA descomponen el texto de manera diferente. Una sola palabra puede convertirse en múltiples tokens - por ejemplo, "entendimiento" se convierte en "entend" + "imiento", mientras que palabras comunes como "el" o "y" suelen ser tokens individuales. Incluso los signos de puntuación y espacios cuentan como tokens. Esta tokenización ayuda al modelo a procesar el texto de manera más eficiente y comprender mejor los patrones del lenguaje.
Cuando mantienes una conversación con un modelo de IA, este maneja tu interacción de una manera fascinante. Cada parte de la conversación - ya sean las instrucciones iniciales (mensajes del sistema), tus preguntas (mensajes del usuario) o las respuestas de la IA (mensajes del asistente) - se entretejen en una secuencia continua. Este texto combinado luego pasa por el proceso de tokenización, donde se descompone en tokens y se analiza como una unidad completa.
Sin embargo, hay una limitación crucial a tener en cuenta: la ventana de contexto tiene un tamaño fijo. Cuando tu conversación crece demasiado y excede este límite de tokens, el modelo tiene que hacer espacio para nueva información. Lo hace eliminando mensajes antiguos desde el principio de la conversación, similar a cómo la aplicación de mensajería de tu teléfono podría mostrar solo los mensajes más recientes en una ventana de chat. Por esto es que a veces el modelo podría no recordar algo mencionado mucho antes en una conversación larga.
- GPT-3.5-turbo: ~16K tokens (aproximadamente equivalente a 12,000 palabras o 48 páginas de texto). Esta ventana de contexto sustancial permite conversaciones detalladas y tareas complejas, aunque puede necesitar gestión en interacciones más largas.
- GPT-4o y GPT-4o-mini: ~128K tokens (aproximadamente equivalente a 96,000 palabras o 384 páginas de texto, variando según tu plan de suscripción). Esta ventana de contexto significativamente más grande permite conversaciones mucho más largas y análisis más complejos, haciéndola adecuada para revisión extensa de documentación, creación de contenido de formato largo y tareas analíticas detalladas.
7.2.2 Estrategias de Gestión de Hilos
1. Segmentación en Hilos Lógicos
Al construir aplicaciones de IA que manejan conversaciones, es crucial implementar una segmentación adecuada de hilos. Esto significa organizar las conversaciones en matrices de mensajes separadas e independientes (hilos) basadas en diferentes usuarios, temas o contextos. Piensa en ello como tener diferentes salas de chat o canales de conversación - cada uno mantiene su propia historia y contexto sin interferir con los demás.
Por ejemplo, si tienes un bot de servicio al cliente ayudando a múltiples clientes simultáneamente, la conversación de cada cliente debe almacenarse en un hilo separado. Esto asegura que cuando el Cliente A pregunta sobre el estado de su pedido, el bot no hará referencia accidentalmente a los detalles de envío del Cliente B. De manera similar, si tu aplicación maneja diferentes temas (como consejos médicos vs soporte técnico), mantener hilos separados previene la confusión y mantiene la precisión contextual.
Este enfoque de segmentación ofrece varios beneficios:
- Límites claros de conversación
- Mejor gestión del contexto
- Mayor precisión en las respuestas
- Depuración y monitoreo más fácil
- Privacidad mejorada entre diferentes usuarios o temas
La clave es implementar un sistema robusto para crear, gestionar y almacenar estos hilos separados mientras se asegura que cada uno mantenga su propio historial completo de conversación.
# Example: Separate threads for different users.
threads = {
"user_1": [{"role": "system", "content": "You are a friendly assistant."}],
"user_2": [{"role": "system", "content": "You are an expert math tutor."}]
}
def append_message(user_id, role, content):
threads[user_id].append({"role": role, "content": content})
Este código demuestra una implementación básica de la gestión de hilos de conversación. Permíteme desglosarlo:
Estructura de Datos:
- El código utiliza un diccionario llamado 'threads' para almacenar hilos de conversación separados para diferentes usuarios
- Cada usuario (user_1, user_2) tiene su propio array de mensajes con un mensaje de sistema único que define el rol del asistente (asistente amigable vs tutor de matemáticas)
Funcionalidad:
- La función append_message() permite agregar nuevos mensajes al hilo de un usuario específico
- Toma tres parámetros: user_id (para identificar el hilo), role (quién está hablando), y content (el mensaje)
Esta implementación simple asegura que las conversaciones permanezcan separadas y contextualmente apropiadas para cada usuario, evitando la contaminación cruzada de conversaciones entre diferentes usuarios.
Aquí hay una implementación integral
# Example: Thread management with OpenAI API
import openai
from typing import Dict, List
import time
class ThreadManager:
def __init__(self, api_key: str):
self.threads: Dict[str, List[Dict]] = {}
openai.api_key = api_key
def create_thread(self, user_id: str, system_role: str) -> None:
"""Initialize a new thread for a user with system message."""
self.threads[user_id] = [
{"role": "system", "content": system_role}
]
def append_message(self, user_id: str, role: str, content: str) -> None:
"""Add a message to user's thread."""
if user_id not in self.threads:
self.create_thread(user_id, "You are a helpful assistant.")
self.threads[user_id].append({
"role": role,
"content": content,
"timestamp": time.time()
})
async def get_response(self, user_id: str, temperature: float = 0.7) -> str:
"""Get AI response using GPT-4o."""
try:
response = await openai.ChatCompletion.acreate(
model="gpt-4o",
messages=self.threads[user_id],
temperature=temperature,
max_tokens=1000
)
ai_response = response.choices[0].message.content
self.append_message(user_id, "assistant", ai_response)
return ai_response
except Exception as e:
return f"Error: {str(e)}"
# Usage example
async def main():
thread_mgr = ThreadManager("your-api-key-here")
# Create threads for different users
thread_mgr.create_thread("user_1", "You are a friendly assistant.")
thread_mgr.create_thread("user_2", "You are an expert math tutor.")
# Simulate conversation
thread_mgr.append_message("user_1", "user", "Hello! How are you?")
response = await thread_mgr.get_response("user_1")
print(f"Assistant: {response}")
Este ejemplo muestra una implementación de un sistema de gestión de hilos para manejar múltiples conversaciones con un asistente de IA. Aquí están los componentes principales:
Clase ThreadManager:
- Gestiona hilos de conversación separados para diferentes usuarios
- Almacena los hilos en un diccionario con IDs de usuario como claves
Funciones Principales:
- create_thread(): Configura nuevas conversaciones con un rol de sistema (por ejemplo, "asistente amigable" o "tutor de matemáticas")
- append_message(): Agrega nuevos mensajes al hilo de conversación de un usuario con marcas de tiempo
- get_response(): Realiza llamadas a la API de GPT-4o para obtener respuestas de la IA
Características Principales:
- Manejo de errores para llamadas a la API
- Soporte asíncrono para mejor rendimiento
- Creación automática de hilos si no existen
- Seguimiento de marcas de tiempo de mensajes
El código ayuda a prevenir la contaminación cruzada de conversaciones entre diferentes usuarios al mantener la conversación de cada usuario separada y contextualmente apropiada.
Desglose del Código:
Estructura de Clase
- La clase ThreadManager maneja todas las operaciones relacionadas con hilos
- Utiliza un diccionario para almacenar hilos con IDs de usuario como claves
- Se inicializa con la clave API de OpenAI
Métodos Principales
- create_thread(): Inicializa nuevos hilos de conversación
- append_message(): Agrega mensajes a hilos existentes
- get_response(): Maneja llamadas a la API de GPT-4o
Mejoras sobre la Versión Básica
- Manejo adecuado de errores
- Soporte asíncrono para mejor rendimiento
- Seguimiento de marcas de tiempo
- Control de temperatura para variación de respuestas
Características de Seguridad
- Creación automática de hilos si no existen
- Bloque try-except para llamadas a la API
- Indicaciones de tipo para mejor mantenibilidad del código
2. Conteo y Recorte de Tokens
Utiliza un tokenizador como tiktoken
para contar con precisión los tokens en tu historial de mensajes. Un tokenizador es esencial porque descompone el texto de la misma manera que lo hace el modelo de IA, asegurando conteos precisos de tokens. Cuando tu historial de conversación se acerca al límite de la ventana de contexto del modelo, necesitarás implementar una estrategia de recorte.
El enfoque más efectivo es eliminar los mensajes más antiguos en bloques completos (mensajes completos en lugar de parciales) para mantener la coherencia de la conversación. Esto preserva el flujo natural del diálogo mientras asegura que te mantengas dentro de los límites de tokens.
Por ejemplo, podrías eliminar primero el par más antiguo de mensajes usuario-asistente, manteniendo el mensaje del sistema y las interacciones más recientes intactas. Este enfoque es preferible a eliminar tokens individuales o mensajes parciales, lo que podría llevar a un contexto confuso o incompleto.
Ejemplo de código:
import tiktoken
from openai import OpenAI
client = OpenAI()
def count_tokens(messages, model="gpt-4o"):
"""Count tokens for a list of messages."""
try:
encoding = tiktoken.encoding_for_model(model)
except KeyError:
print(f"Warning: Model `{model}` not found. Using cl100k_base encoding.")
encoding = tiktoken.get_encoding("cl100k_base")
num_tokens = 0
for message in messages:
num_tokens += 4 # Format tax for each message
for key, value in message.items():
num_tokens += len(encoding.encode(value))
if key == "name": # Name tax
num_tokens += 1
num_tokens += 2 # Format tax for the entire message
return num_tokens
def trim_history(messages, max_tokens=10000, model="gpt-4o"):
"""Trim conversation history to fit within token limit."""
total_tokens = count_tokens(messages, model)
while total_tokens > max_tokens and len(messages) > 1:
# Calculate tokens of the message to be removed
tokens_to_remove = count_tokens([messages[1]], model) + 4 # +4 for format tax
if "name" in messages[1]:
tokens_to_remove += 1 # Name tax
messages.pop(1)
total_tokens -= tokens_to_remove
return messages
# Example usage:
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "The capital of France is Paris."},
{"role": "user", "name": "Alice", "content": "Tell me something else."},
{"role": "assistant", "content": "The Eiffel Tower is a famous landmark in Paris."},
]
token_count = count_tokens(messages)
print(f"Initial token count: {token_count}")
trimmed_messages = trim_history(messages, max_tokens=300)
trimmed_token_count = count_tokens(trimmed_messages)
print(f"Token count after trimming: {trimmed_token_count}")
print(f"Trimmed messages: {trimmed_messages}")
Desglose del Código:
- Importaciones y Configuración
- Importa tiktoken para el conteo de tokens
- Importa el cliente OpenAI para la interacción con la API
- Inicializa la instancia del cliente OpenAI
- Función count_tokens
Propósito: Cuenta con precisión los tokens en una lista de mensajes según las reglas de tokenización de OpenAI.
- Parámetros:
- messages: Lista de diccionarios de mensajes
- model: Nombre del modelo objetivo (predeterminado: "gpt-4o")
- Características Principales:
- Utiliza tokenizador específico del modelo cuando está disponible
- Recurre a la codificación cl100k_base si no se encuentra el modelo
- Considera el impuesto de formato de mensaje (+4 tokens por mensaje)
- Añade impuesto de nombre (+1 token) cuando está presente
- Incluye impuesto de formato para el mensaje completo (+2 tokens)
- Función trim_history
Propósito: Recorta el historial de conversación para ajustarse al límite de tokens mientras preserva el contexto reciente.
- Parámetros:
- messages: Lista de diccionarios de mensajes
- max_tokens: Tokens máximos permitidos (predeterminado: 10000)
- model: Nombre del modelo objetivo (predeterminado: "gpt-4o")
- Algoritmo:
- Cuenta el total de tokens en el historial actual
- Elimina los mensajes más antiguos (comenzando en el índice 1) hasta estar bajo el límite
- Conserva el mensaje del sistema (índice 0)
- Rastrea con precisión la reducción de tokens incluyendo impuestos de formato
- Implementación de Ejemplo
- Conversación de muestra:
- Mensaje del sistema definiendo el rol del asistente
- Dos mensajes de usuario (uno con nombre)
- Dos respuestas del asistente
- Demostración:
- Cuenta los tokens iniciales en la conversación
- Recorta el historial para ajustarse a 300 tokens
- Muestra el conteo de tokens antes y después del recorte
- Muestra la lista final de mensajes recortados
El ejemplo de uso muestra cómo aplicar estas funciones a un historial de conversación, contando los tokens iniciales y luego recortándolo para ajustarse a un límite de 300 tokens.
3. Resumen del Contexto Antiguo
Para conversaciones muy largas que abarcan muchos intercambios, implementar una estrategia de resumen se vuelve crucial para gestionar el contexto de manera efectiva mientras se mantiene dentro de los límites de tokens. Este enfoque implica condensar las partes anteriores de la conversación en un resumen conciso, que preserva la información esencial mientras utiliza significativamente menos tokens.
Puedes aprovechar las capacidades propias del modelo de IA llamándolo periódicamente para analizar el historial de conversación y generar un resumen significativo. Este resumen puede entonces reemplazar un bloque más grande de mensajes anteriores, manteniendo el contexto de la conversación mientras reduce drásticamente el uso de tokens.
El proceso de resumen es particularmente efectivo porque retiene los puntos clave de discusión y decisiones mientras elimina detalles redundantes o menos relevantes, asegurando que las respuestas futuras permanezcan contextualmente apropiadas sin requerir el historial completo de la conversación.
Ejemplo de código:
from openai import OpenAI
import tiktoken # Import tiktoken
def summarize_context(history, api_key, model="gpt-3.5-turbo", max_summary_tokens=80):
"""Summarizes a conversation history.
Args:
history: A list of message dictionaries.
api_key: Your OpenAI API key.
model: The OpenAI model to use for summarization.
max_summary_tokens: The maximum number of tokens for the summary.
Returns:
A list containing a single message with the summary, or the original
history if summarization fails.
"""
client = OpenAI(api_key=api_key)
encoding = tiktoken.encoding_for_model(model) # Added encoding
# Improved prompt with more specific instructions
prompt = [
{"role": "system", "content": "You are a helpful assistant that provides concise summaries of conversations."},
{"role": "user", "content": (
"Please provide a two-sentence summary of the following conversation, focusing on the key topics discussed and the main points:\n" +
"\n".join([f'{m["role"]}: {m["content"]}' for m in history])
)}
]
prompt_token_count = len(encoding.encode(prompt[1]["content"])) # Count tokens
if prompt_token_count > 4000: # Check if prompt is too long.
print("Warning: Prompt is longer than 4000 tokens. Consider Trimming History")
try:
response = client.chat.completions.create(
model=model,
messages=prompt,
max_tokens=max_summary_tokens,
temperature=0.2, # Lower temperature for more focused summaries
)
summary = response.choices[0].message.content
return [{"role": "system", "content": "Conversation summary: " + summary}]
except Exception as e:
print(f"Error during summarization: {str(e)}")
return history # Return original history if summarization fails
Este código implementa una función de resumen de conversaciones que ayuda a gestionar historiales de conversación extensos. Aquí está el desglose de sus componentes principales:
Descripción General de la Función:
La función summarize_context
toma un historial de conversación y lo convierte en un resumen conciso de dos oraciones. Los parámetros principales incluyen:
- history: Los mensajes de conversación a resumir
- api_key: Autenticación de la API de OpenAI
- model: El modelo de IA a utilizar (por defecto: GPT-3.5-turbo)
- max_summary_tokens: Longitud máxima del resumen
Características Principales:
- Utiliza tiktoken para un conteo preciso de tokens
- Implementa verificaciones de límite de tokens (advierte si supera los 4000 tokens)
- Utiliza una temperatura baja (0.2) para resúmenes más consistentes
- Recurre al historial original si falla el resumen
Proceso:
- Inicializa el cliente OpenAI y configura la codificación de tokens
- Crea un prompt con instrucciones específicas para el resumen
- Formatea el historial de conversación en un formato legible
- Realiza la llamada a la API para generar el resumen
- Devuelve el resumen como mensaje del sistema o el historial original si hay un error
Esta función es particularmente útil cuando los historiales de conversación se vuelven demasiado largos, ya que ayuda a mantener el contexto mientras reduce el uso de tokens. La versión resumida puede entonces anteponerse a los mensajes más recientes para mantener la continuidad de la conversación.
7.2.3 Integrando Todo
Ahora, exploremos cómo combinar perfectamente las técnicas de recorte y resumen que discutimos en un flujo de trabajo unificado y efectivo. Esta integración es crucial para mantener una gestión óptima de la conversación, ya que nos permite manejar tanto las restricciones inmediatas de tokens como la preservación del contexto a largo plazo en un proceso único y coordinado.
El siguiente ejemplo de código demuestra cómo estos componentes trabajan juntos para crear un sistema robusto de gestión de conversaciones que puede manejar desde el procesamiento básico de mensajes hasta el mantenimiento de contexto complejo.
from openai import OpenAI
from typing import List, Dict
import tiktoken
from datetime import datetime
class ConversationManager:
def __init__(self, api_key: str, model: str = "gpt-3.5-turbo"):
self.client = OpenAI(api_key=api_key)
self.model = model
self.threads: Dict[str, List[Dict]] = {}
self.encoding = tiktoken.encoding_for_model(model)
def append_message(self, user_id: str, role: str, content: str) -> None:
"""Add a new message to the user's conversation thread."""
if user_id not in self.threads:
self.threads[user_id] = [
{"role": "system", "content": "You are a helpful assistant."}
]
self.threads[user_id].append({"role": role, "content": content})
def count_tokens(self, messages: List[Dict]) -> int:
"""Count tokens in the message list."""
num_tokens = 0
for message in messages:
num_tokens += 4 # Message format tax
for key, value in message.items():
num_tokens += len(self.encoding.encode(str(value)))
if key == "name":
num_tokens += 1 # Name field tax
return num_tokens + 2 # Add final format tax
def summarize_context(self, history: List[Dict], max_summary_tokens: int = 300) -> List[Dict]:
"""Generate a summary of the conversation history."""
try:
prompt = [
{"role": "system", "content": "Summarize this conversation in two concise sentences:"},
{"role": "user", "content": "\n".join([f"{m['role']}: {m['content']}"
for m in history if m['role'] != "system"])}
]
response = self.client.chat.completions.create(
model=self.model,
messages=prompt,
max_tokens=max_summary_tokens,
temperature=0.3
)
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return [{
"role": "system",
"content": f"Summary as of {timestamp}: {response.choices[0].message.content}"
}]
except Exception as e:
print(f"Summarization failed: {str(e)}")
return history
def trim_history(self, messages: List[Dict], max_tokens: int) -> List[Dict]:
"""Trim conversation history to fit within token limit."""
while self.count_tokens(messages) > max_tokens and len(messages) > 1:
# Remove second message (preserve system message)
messages.pop(1)
return messages
def manage_context_thread(self, user_id: str, new_message: str,
max_tokens: int = 4000,
summary_threshold: int = 3000) -> List[Dict]:
"""Manage conversation context with token limits and summarization."""
# Add new message
self.append_message(user_id, "user", new_message)
history = self.threads[user_id]
current_tokens = self.count_tokens(history)
# Log for debugging
print(f"Current token count: {current_tokens}")
# If approaching token limit, summarize older context
if current_tokens > summary_threshold:
# Keep system message and last 3 message pairs (6 messages)
recent_messages = history[-6:] if len(history) > 6 else history
older_messages = history[1:-6] if len(history) > 6 else []
if older_messages:
summary = self.summarize_context(older_messages)
history = [history[0]] + summary + recent_messages
print("Context summarized")
# Ensure we're under max tokens
history = self.trim_history(history, max_tokens)
self.threads[user_id] = history
return history
# Example usage
if __name__ == "__main__":
manager = ConversationManager("your-api-key-here")
# Simulate a conversation
user_id = "user123"
messages = [
"Hello! How can you help me today?",
"I'd like to learn about machine learning.",
"Can you explain neural networks?",
"What's the difference between supervised and unsupervised learning?"
]
# Process messages
for msg in messages:
history = manager.manage_context_thread(user_id, msg)
print(f"\nMessage: {msg}")
print(f"Thread length: {len(history)}")
print(f"Token count: {manager.count_tokens(history)}")
Desglose del Código:
- Estructura de Clase
- La clase ConversationManager maneja todos los aspectos de la gestión de conversaciones
- Se inicializa con la clave API de OpenAI y la selección del modelo
- Mantiene hilos de conversación para múltiples usuarios
- Utiliza tiktoken para el conteo preciso de tokens
- Métodos Principales
- append_message()
- Agrega nuevos mensajes a los hilos de conversación específicos del usuario
- Inicializa nuevos hilos con un mensaje del sistema
- count_tokens()
- Cuenta tokens con precisión incluyendo impuestos de formato
- Considera la estructura del mensaje y campos de nombre
- Características Avanzadas
- summarize_context()
- Utiliza la API de OpenAI para generar resúmenes concisos
- Incluye marcas temporales para contexto
- Maneja errores de manera elegante
- trim_history()
- Elimina los mensajes más antiguos mientras preserva el mensaje del sistema
- Asegura que la conversación se mantenga dentro de los límites de tokens
- Lógica Principal de Gestión
- manage_context_thread()
- Implementa gestión de contexto en tres fases:
- Adición de nuevos mensajes
- Resumen del contexto anterior
- Control de límite de tokens
- Utiliza umbrales separados para resumen y tokens máximos
- Implementa gestión de contexto en tres fases:
- Ejemplo de Uso
- Demuestra implementación práctica con múltiples mensajes
- Incluye conteo de tokens y monitoreo de longitud de hilo
- Muestra cómo mantener el contexto de conversación a través de múltiples intercambios
Con este enfoque:
- Se agregan nuevos mensajes.
- Se verifica la longitud del historial.
- Si se supera el límite, se resume toda la conversación, se mantiene el resumen y los últimos mensajes.
- Se recorta cualquier exceso restante.
La gestión de hilos y ventanas de contexto es un aspecto fundamental para construir conversaciones escalables y coherentes de múltiples turnos en sistemas de IA. Aquí está por qué es importante y cómo funciona:
Primero, la segmentación de hilos por usuario asegura que cada conversación permanezca aislada y personal. Al mantener hilos de conversación separados para cada usuario, se previene la contaminación cruzada de contexto entre diferentes conversaciones, permitiendo respuestas más personalizadas y precisas.
Segundo, el conteo de tokens y recorte sirven como herramientas esenciales de mantenimiento. Al monitorear activamente el conteo de tokens de las conversaciones, puedes prevenir alcanzar los límites del contexto del modelo mientras preservas la información más relevante. Este proceso implica eliminar cuidadosamente mensajes antiguos mientras se mantiene el contexto crucial, similar a cómo las conversaciones humanas naturalmente se centran en información reciente y relevante.
Tercero, la sumarización del contexto actúa como una técnica de compresión de memoria. Cuando las conversaciones se alargan, resumir el contexto anterior permite mantener la narrativa esencial mientras se reduce el uso de tokens. Esto es similar a cómo los humanos mantienen la esencia de conversaciones anteriores sin recordar cada detalle.
La combinación de estas estrategias resulta en un asistente de IA que puede:
- Mantener un contexto consistente a través de múltiples turnos de conversación
- Escalar eficientemente sin degradar el rendimiento
- Proporcionar respuestas relevantes basadas tanto en contexto reciente como histórico
- Adaptarse a diferentes longitudes y complejidades de conversación
Estas capacidades aseguran que tu asistente de IA permanezca receptivo, informado y consciente del contexto durante diálogos extensos, creando una experiencia de conversación más natural y efectiva.
7.2 Gestión de hilos y ventanas de contexto
En conversaciones de múltiples turnos, especialmente aquellas que se extienden a lo largo de múltiples mensajes o sesiones, gestionar el contexto de manera efectiva es crucial para mantener un diálogo significativo. Esto se vuelve particularmente importante en aplicaciones de IA donde las conversaciones pueden volverse complejas y extensas. Los modelos de OpenAI operan dentro de una "ventana de contexto" fija—un número máximo de tokens que pueden considerar en una llamada (hasta 128K tokens para algunos modelos). Piensa en esta ventana como la memoria de trabajo del modelo, similar a cómo los humanos solo pueden mantener cierta cantidad de información en sus pensamientos inmediatos.
Cuando tu conversación se extiende más allá de este límite de ventana, los mensajes más antiguos pueden ser truncados o eliminados de la consideración, causando que el modelo pierda contexto importante. Esto puede llevar a varios problemas: el modelo podría olvidar partes anteriores de la conversación, repetir información o fallar en mantener la consistencia con hechos o preferencias previamente establecidos. Por ejemplo, si un usuario hace referencia a algo mencionado anteriormente en la conversación que fue truncado, el modelo no tendrá acceso a esa información para proporcionar una respuesta apropiada.
Por lo tanto, la gestión adecuada de hilos es esencial—asegura que tus aplicaciones permanezcan coherentes y enfocadas, incluso cuando las conversaciones crecen en longitud y complejidad. Esto implica implementar estrategias para preservar el contexto crucial mientras se gestiona eficientemente el límite de tokens, como resumir intercambios previos, mantener información relevante y decidir inteligentemente qué partes de la conversación mantener o eliminar. A través de una gestión efectiva de hilos, puedes crear conversaciones más naturales y conscientes del contexto que mantienen su coherencia y utilidad a lo largo de interacciones extendidas.
7.2.1 ¿Qué es una Ventana de Contexto?
Una ventana de contexto es un concepto fundamental en los modelos de lenguaje de IA que define la cantidad máxima de texto que el modelo puede procesar y comprender a la vez. Esta ventana actúa como la memoria de trabajo del modelo - similar a cómo los humanos solo pueden mantener cierta cantidad de información en sus pensamientos inmediatos. El tamaño de esta ventana se mide en tokens, que son los bloques fundamentales que el modelo utiliza para procesar el lenguaje.
Para entender mejor los tokens, piensa en ellos como las piezas del vocabulario del modelo. Mientras que los humanos naturalmente dividimos el lenguaje en palabras, los modelos de IA descomponen el texto de manera diferente. Una sola palabra puede convertirse en múltiples tokens - por ejemplo, "entendimiento" se convierte en "entend" + "imiento", mientras que palabras comunes como "el" o "y" suelen ser tokens individuales. Incluso los signos de puntuación y espacios cuentan como tokens. Esta tokenización ayuda al modelo a procesar el texto de manera más eficiente y comprender mejor los patrones del lenguaje.
Cuando mantienes una conversación con un modelo de IA, este maneja tu interacción de una manera fascinante. Cada parte de la conversación - ya sean las instrucciones iniciales (mensajes del sistema), tus preguntas (mensajes del usuario) o las respuestas de la IA (mensajes del asistente) - se entretejen en una secuencia continua. Este texto combinado luego pasa por el proceso de tokenización, donde se descompone en tokens y se analiza como una unidad completa.
Sin embargo, hay una limitación crucial a tener en cuenta: la ventana de contexto tiene un tamaño fijo. Cuando tu conversación crece demasiado y excede este límite de tokens, el modelo tiene que hacer espacio para nueva información. Lo hace eliminando mensajes antiguos desde el principio de la conversación, similar a cómo la aplicación de mensajería de tu teléfono podría mostrar solo los mensajes más recientes en una ventana de chat. Por esto es que a veces el modelo podría no recordar algo mencionado mucho antes en una conversación larga.
- GPT-3.5-turbo: ~16K tokens (aproximadamente equivalente a 12,000 palabras o 48 páginas de texto). Esta ventana de contexto sustancial permite conversaciones detalladas y tareas complejas, aunque puede necesitar gestión en interacciones más largas.
- GPT-4o y GPT-4o-mini: ~128K tokens (aproximadamente equivalente a 96,000 palabras o 384 páginas de texto, variando según tu plan de suscripción). Esta ventana de contexto significativamente más grande permite conversaciones mucho más largas y análisis más complejos, haciéndola adecuada para revisión extensa de documentación, creación de contenido de formato largo y tareas analíticas detalladas.
7.2.2 Estrategias de Gestión de Hilos
1. Segmentación en Hilos Lógicos
Al construir aplicaciones de IA que manejan conversaciones, es crucial implementar una segmentación adecuada de hilos. Esto significa organizar las conversaciones en matrices de mensajes separadas e independientes (hilos) basadas en diferentes usuarios, temas o contextos. Piensa en ello como tener diferentes salas de chat o canales de conversación - cada uno mantiene su propia historia y contexto sin interferir con los demás.
Por ejemplo, si tienes un bot de servicio al cliente ayudando a múltiples clientes simultáneamente, la conversación de cada cliente debe almacenarse en un hilo separado. Esto asegura que cuando el Cliente A pregunta sobre el estado de su pedido, el bot no hará referencia accidentalmente a los detalles de envío del Cliente B. De manera similar, si tu aplicación maneja diferentes temas (como consejos médicos vs soporte técnico), mantener hilos separados previene la confusión y mantiene la precisión contextual.
Este enfoque de segmentación ofrece varios beneficios:
- Límites claros de conversación
- Mejor gestión del contexto
- Mayor precisión en las respuestas
- Depuración y monitoreo más fácil
- Privacidad mejorada entre diferentes usuarios o temas
La clave es implementar un sistema robusto para crear, gestionar y almacenar estos hilos separados mientras se asegura que cada uno mantenga su propio historial completo de conversación.
# Example: Separate threads for different users.
threads = {
"user_1": [{"role": "system", "content": "You are a friendly assistant."}],
"user_2": [{"role": "system", "content": "You are an expert math tutor."}]
}
def append_message(user_id, role, content):
threads[user_id].append({"role": role, "content": content})
Este código demuestra una implementación básica de la gestión de hilos de conversación. Permíteme desglosarlo:
Estructura de Datos:
- El código utiliza un diccionario llamado 'threads' para almacenar hilos de conversación separados para diferentes usuarios
- Cada usuario (user_1, user_2) tiene su propio array de mensajes con un mensaje de sistema único que define el rol del asistente (asistente amigable vs tutor de matemáticas)
Funcionalidad:
- La función append_message() permite agregar nuevos mensajes al hilo de un usuario específico
- Toma tres parámetros: user_id (para identificar el hilo), role (quién está hablando), y content (el mensaje)
Esta implementación simple asegura que las conversaciones permanezcan separadas y contextualmente apropiadas para cada usuario, evitando la contaminación cruzada de conversaciones entre diferentes usuarios.
Aquí hay una implementación integral
# Example: Thread management with OpenAI API
import openai
from typing import Dict, List
import time
class ThreadManager:
def __init__(self, api_key: str):
self.threads: Dict[str, List[Dict]] = {}
openai.api_key = api_key
def create_thread(self, user_id: str, system_role: str) -> None:
"""Initialize a new thread for a user with system message."""
self.threads[user_id] = [
{"role": "system", "content": system_role}
]
def append_message(self, user_id: str, role: str, content: str) -> None:
"""Add a message to user's thread."""
if user_id not in self.threads:
self.create_thread(user_id, "You are a helpful assistant.")
self.threads[user_id].append({
"role": role,
"content": content,
"timestamp": time.time()
})
async def get_response(self, user_id: str, temperature: float = 0.7) -> str:
"""Get AI response using GPT-4o."""
try:
response = await openai.ChatCompletion.acreate(
model="gpt-4o",
messages=self.threads[user_id],
temperature=temperature,
max_tokens=1000
)
ai_response = response.choices[0].message.content
self.append_message(user_id, "assistant", ai_response)
return ai_response
except Exception as e:
return f"Error: {str(e)}"
# Usage example
async def main():
thread_mgr = ThreadManager("your-api-key-here")
# Create threads for different users
thread_mgr.create_thread("user_1", "You are a friendly assistant.")
thread_mgr.create_thread("user_2", "You are an expert math tutor.")
# Simulate conversation
thread_mgr.append_message("user_1", "user", "Hello! How are you?")
response = await thread_mgr.get_response("user_1")
print(f"Assistant: {response}")
Este ejemplo muestra una implementación de un sistema de gestión de hilos para manejar múltiples conversaciones con un asistente de IA. Aquí están los componentes principales:
Clase ThreadManager:
- Gestiona hilos de conversación separados para diferentes usuarios
- Almacena los hilos en un diccionario con IDs de usuario como claves
Funciones Principales:
- create_thread(): Configura nuevas conversaciones con un rol de sistema (por ejemplo, "asistente amigable" o "tutor de matemáticas")
- append_message(): Agrega nuevos mensajes al hilo de conversación de un usuario con marcas de tiempo
- get_response(): Realiza llamadas a la API de GPT-4o para obtener respuestas de la IA
Características Principales:
- Manejo de errores para llamadas a la API
- Soporte asíncrono para mejor rendimiento
- Creación automática de hilos si no existen
- Seguimiento de marcas de tiempo de mensajes
El código ayuda a prevenir la contaminación cruzada de conversaciones entre diferentes usuarios al mantener la conversación de cada usuario separada y contextualmente apropiada.
Desglose del Código:
Estructura de Clase
- La clase ThreadManager maneja todas las operaciones relacionadas con hilos
- Utiliza un diccionario para almacenar hilos con IDs de usuario como claves
- Se inicializa con la clave API de OpenAI
Métodos Principales
- create_thread(): Inicializa nuevos hilos de conversación
- append_message(): Agrega mensajes a hilos existentes
- get_response(): Maneja llamadas a la API de GPT-4o
Mejoras sobre la Versión Básica
- Manejo adecuado de errores
- Soporte asíncrono para mejor rendimiento
- Seguimiento de marcas de tiempo
- Control de temperatura para variación de respuestas
Características de Seguridad
- Creación automática de hilos si no existen
- Bloque try-except para llamadas a la API
- Indicaciones de tipo para mejor mantenibilidad del código
2. Conteo y Recorte de Tokens
Utiliza un tokenizador como tiktoken
para contar con precisión los tokens en tu historial de mensajes. Un tokenizador es esencial porque descompone el texto de la misma manera que lo hace el modelo de IA, asegurando conteos precisos de tokens. Cuando tu historial de conversación se acerca al límite de la ventana de contexto del modelo, necesitarás implementar una estrategia de recorte.
El enfoque más efectivo es eliminar los mensajes más antiguos en bloques completos (mensajes completos en lugar de parciales) para mantener la coherencia de la conversación. Esto preserva el flujo natural del diálogo mientras asegura que te mantengas dentro de los límites de tokens.
Por ejemplo, podrías eliminar primero el par más antiguo de mensajes usuario-asistente, manteniendo el mensaje del sistema y las interacciones más recientes intactas. Este enfoque es preferible a eliminar tokens individuales o mensajes parciales, lo que podría llevar a un contexto confuso o incompleto.
Ejemplo de código:
import tiktoken
from openai import OpenAI
client = OpenAI()
def count_tokens(messages, model="gpt-4o"):
"""Count tokens for a list of messages."""
try:
encoding = tiktoken.encoding_for_model(model)
except KeyError:
print(f"Warning: Model `{model}` not found. Using cl100k_base encoding.")
encoding = tiktoken.get_encoding("cl100k_base")
num_tokens = 0
for message in messages:
num_tokens += 4 # Format tax for each message
for key, value in message.items():
num_tokens += len(encoding.encode(value))
if key == "name": # Name tax
num_tokens += 1
num_tokens += 2 # Format tax for the entire message
return num_tokens
def trim_history(messages, max_tokens=10000, model="gpt-4o"):
"""Trim conversation history to fit within token limit."""
total_tokens = count_tokens(messages, model)
while total_tokens > max_tokens and len(messages) > 1:
# Calculate tokens of the message to be removed
tokens_to_remove = count_tokens([messages[1]], model) + 4 # +4 for format tax
if "name" in messages[1]:
tokens_to_remove += 1 # Name tax
messages.pop(1)
total_tokens -= tokens_to_remove
return messages
# Example usage:
messages = [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "The capital of France is Paris."},
{"role": "user", "name": "Alice", "content": "Tell me something else."},
{"role": "assistant", "content": "The Eiffel Tower is a famous landmark in Paris."},
]
token_count = count_tokens(messages)
print(f"Initial token count: {token_count}")
trimmed_messages = trim_history(messages, max_tokens=300)
trimmed_token_count = count_tokens(trimmed_messages)
print(f"Token count after trimming: {trimmed_token_count}")
print(f"Trimmed messages: {trimmed_messages}")
Desglose del Código:
- Importaciones y Configuración
- Importa tiktoken para el conteo de tokens
- Importa el cliente OpenAI para la interacción con la API
- Inicializa la instancia del cliente OpenAI
- Función count_tokens
Propósito: Cuenta con precisión los tokens en una lista de mensajes según las reglas de tokenización de OpenAI.
- Parámetros:
- messages: Lista de diccionarios de mensajes
- model: Nombre del modelo objetivo (predeterminado: "gpt-4o")
- Características Principales:
- Utiliza tokenizador específico del modelo cuando está disponible
- Recurre a la codificación cl100k_base si no se encuentra el modelo
- Considera el impuesto de formato de mensaje (+4 tokens por mensaje)
- Añade impuesto de nombre (+1 token) cuando está presente
- Incluye impuesto de formato para el mensaje completo (+2 tokens)
- Función trim_history
Propósito: Recorta el historial de conversación para ajustarse al límite de tokens mientras preserva el contexto reciente.
- Parámetros:
- messages: Lista de diccionarios de mensajes
- max_tokens: Tokens máximos permitidos (predeterminado: 10000)
- model: Nombre del modelo objetivo (predeterminado: "gpt-4o")
- Algoritmo:
- Cuenta el total de tokens en el historial actual
- Elimina los mensajes más antiguos (comenzando en el índice 1) hasta estar bajo el límite
- Conserva el mensaje del sistema (índice 0)
- Rastrea con precisión la reducción de tokens incluyendo impuestos de formato
- Implementación de Ejemplo
- Conversación de muestra:
- Mensaje del sistema definiendo el rol del asistente
- Dos mensajes de usuario (uno con nombre)
- Dos respuestas del asistente
- Demostración:
- Cuenta los tokens iniciales en la conversación
- Recorta el historial para ajustarse a 300 tokens
- Muestra el conteo de tokens antes y después del recorte
- Muestra la lista final de mensajes recortados
El ejemplo de uso muestra cómo aplicar estas funciones a un historial de conversación, contando los tokens iniciales y luego recortándolo para ajustarse a un límite de 300 tokens.
3. Resumen del Contexto Antiguo
Para conversaciones muy largas que abarcan muchos intercambios, implementar una estrategia de resumen se vuelve crucial para gestionar el contexto de manera efectiva mientras se mantiene dentro de los límites de tokens. Este enfoque implica condensar las partes anteriores de la conversación en un resumen conciso, que preserva la información esencial mientras utiliza significativamente menos tokens.
Puedes aprovechar las capacidades propias del modelo de IA llamándolo periódicamente para analizar el historial de conversación y generar un resumen significativo. Este resumen puede entonces reemplazar un bloque más grande de mensajes anteriores, manteniendo el contexto de la conversación mientras reduce drásticamente el uso de tokens.
El proceso de resumen es particularmente efectivo porque retiene los puntos clave de discusión y decisiones mientras elimina detalles redundantes o menos relevantes, asegurando que las respuestas futuras permanezcan contextualmente apropiadas sin requerir el historial completo de la conversación.
Ejemplo de código:
from openai import OpenAI
import tiktoken # Import tiktoken
def summarize_context(history, api_key, model="gpt-3.5-turbo", max_summary_tokens=80):
"""Summarizes a conversation history.
Args:
history: A list of message dictionaries.
api_key: Your OpenAI API key.
model: The OpenAI model to use for summarization.
max_summary_tokens: The maximum number of tokens for the summary.
Returns:
A list containing a single message with the summary, or the original
history if summarization fails.
"""
client = OpenAI(api_key=api_key)
encoding = tiktoken.encoding_for_model(model) # Added encoding
# Improved prompt with more specific instructions
prompt = [
{"role": "system", "content": "You are a helpful assistant that provides concise summaries of conversations."},
{"role": "user", "content": (
"Please provide a two-sentence summary of the following conversation, focusing on the key topics discussed and the main points:\n" +
"\n".join([f'{m["role"]}: {m["content"]}' for m in history])
)}
]
prompt_token_count = len(encoding.encode(prompt[1]["content"])) # Count tokens
if prompt_token_count > 4000: # Check if prompt is too long.
print("Warning: Prompt is longer than 4000 tokens. Consider Trimming History")
try:
response = client.chat.completions.create(
model=model,
messages=prompt,
max_tokens=max_summary_tokens,
temperature=0.2, # Lower temperature for more focused summaries
)
summary = response.choices[0].message.content
return [{"role": "system", "content": "Conversation summary: " + summary}]
except Exception as e:
print(f"Error during summarization: {str(e)}")
return history # Return original history if summarization fails
Este código implementa una función de resumen de conversaciones que ayuda a gestionar historiales de conversación extensos. Aquí está el desglose de sus componentes principales:
Descripción General de la Función:
La función summarize_context
toma un historial de conversación y lo convierte en un resumen conciso de dos oraciones. Los parámetros principales incluyen:
- history: Los mensajes de conversación a resumir
- api_key: Autenticación de la API de OpenAI
- model: El modelo de IA a utilizar (por defecto: GPT-3.5-turbo)
- max_summary_tokens: Longitud máxima del resumen
Características Principales:
- Utiliza tiktoken para un conteo preciso de tokens
- Implementa verificaciones de límite de tokens (advierte si supera los 4000 tokens)
- Utiliza una temperatura baja (0.2) para resúmenes más consistentes
- Recurre al historial original si falla el resumen
Proceso:
- Inicializa el cliente OpenAI y configura la codificación de tokens
- Crea un prompt con instrucciones específicas para el resumen
- Formatea el historial de conversación en un formato legible
- Realiza la llamada a la API para generar el resumen
- Devuelve el resumen como mensaje del sistema o el historial original si hay un error
Esta función es particularmente útil cuando los historiales de conversación se vuelven demasiado largos, ya que ayuda a mantener el contexto mientras reduce el uso de tokens. La versión resumida puede entonces anteponerse a los mensajes más recientes para mantener la continuidad de la conversación.
7.2.3 Integrando Todo
Ahora, exploremos cómo combinar perfectamente las técnicas de recorte y resumen que discutimos en un flujo de trabajo unificado y efectivo. Esta integración es crucial para mantener una gestión óptima de la conversación, ya que nos permite manejar tanto las restricciones inmediatas de tokens como la preservación del contexto a largo plazo en un proceso único y coordinado.
El siguiente ejemplo de código demuestra cómo estos componentes trabajan juntos para crear un sistema robusto de gestión de conversaciones que puede manejar desde el procesamiento básico de mensajes hasta el mantenimiento de contexto complejo.
from openai import OpenAI
from typing import List, Dict
import tiktoken
from datetime import datetime
class ConversationManager:
def __init__(self, api_key: str, model: str = "gpt-3.5-turbo"):
self.client = OpenAI(api_key=api_key)
self.model = model
self.threads: Dict[str, List[Dict]] = {}
self.encoding = tiktoken.encoding_for_model(model)
def append_message(self, user_id: str, role: str, content: str) -> None:
"""Add a new message to the user's conversation thread."""
if user_id not in self.threads:
self.threads[user_id] = [
{"role": "system", "content": "You are a helpful assistant."}
]
self.threads[user_id].append({"role": role, "content": content})
def count_tokens(self, messages: List[Dict]) -> int:
"""Count tokens in the message list."""
num_tokens = 0
for message in messages:
num_tokens += 4 # Message format tax
for key, value in message.items():
num_tokens += len(self.encoding.encode(str(value)))
if key == "name":
num_tokens += 1 # Name field tax
return num_tokens + 2 # Add final format tax
def summarize_context(self, history: List[Dict], max_summary_tokens: int = 300) -> List[Dict]:
"""Generate a summary of the conversation history."""
try:
prompt = [
{"role": "system", "content": "Summarize this conversation in two concise sentences:"},
{"role": "user", "content": "\n".join([f"{m['role']}: {m['content']}"
for m in history if m['role'] != "system"])}
]
response = self.client.chat.completions.create(
model=self.model,
messages=prompt,
max_tokens=max_summary_tokens,
temperature=0.3
)
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return [{
"role": "system",
"content": f"Summary as of {timestamp}: {response.choices[0].message.content}"
}]
except Exception as e:
print(f"Summarization failed: {str(e)}")
return history
def trim_history(self, messages: List[Dict], max_tokens: int) -> List[Dict]:
"""Trim conversation history to fit within token limit."""
while self.count_tokens(messages) > max_tokens and len(messages) > 1:
# Remove second message (preserve system message)
messages.pop(1)
return messages
def manage_context_thread(self, user_id: str, new_message: str,
max_tokens: int = 4000,
summary_threshold: int = 3000) -> List[Dict]:
"""Manage conversation context with token limits and summarization."""
# Add new message
self.append_message(user_id, "user", new_message)
history = self.threads[user_id]
current_tokens = self.count_tokens(history)
# Log for debugging
print(f"Current token count: {current_tokens}")
# If approaching token limit, summarize older context
if current_tokens > summary_threshold:
# Keep system message and last 3 message pairs (6 messages)
recent_messages = history[-6:] if len(history) > 6 else history
older_messages = history[1:-6] if len(history) > 6 else []
if older_messages:
summary = self.summarize_context(older_messages)
history = [history[0]] + summary + recent_messages
print("Context summarized")
# Ensure we're under max tokens
history = self.trim_history(history, max_tokens)
self.threads[user_id] = history
return history
# Example usage
if __name__ == "__main__":
manager = ConversationManager("your-api-key-here")
# Simulate a conversation
user_id = "user123"
messages = [
"Hello! How can you help me today?",
"I'd like to learn about machine learning.",
"Can you explain neural networks?",
"What's the difference between supervised and unsupervised learning?"
]
# Process messages
for msg in messages:
history = manager.manage_context_thread(user_id, msg)
print(f"\nMessage: {msg}")
print(f"Thread length: {len(history)}")
print(f"Token count: {manager.count_tokens(history)}")
Desglose del Código:
- Estructura de Clase
- La clase ConversationManager maneja todos los aspectos de la gestión de conversaciones
- Se inicializa con la clave API de OpenAI y la selección del modelo
- Mantiene hilos de conversación para múltiples usuarios
- Utiliza tiktoken para el conteo preciso de tokens
- Métodos Principales
- append_message()
- Agrega nuevos mensajes a los hilos de conversación específicos del usuario
- Inicializa nuevos hilos con un mensaje del sistema
- count_tokens()
- Cuenta tokens con precisión incluyendo impuestos de formato
- Considera la estructura del mensaje y campos de nombre
- Características Avanzadas
- summarize_context()
- Utiliza la API de OpenAI para generar resúmenes concisos
- Incluye marcas temporales para contexto
- Maneja errores de manera elegante
- trim_history()
- Elimina los mensajes más antiguos mientras preserva el mensaje del sistema
- Asegura que la conversación se mantenga dentro de los límites de tokens
- Lógica Principal de Gestión
- manage_context_thread()
- Implementa gestión de contexto en tres fases:
- Adición de nuevos mensajes
- Resumen del contexto anterior
- Control de límite de tokens
- Utiliza umbrales separados para resumen y tokens máximos
- Implementa gestión de contexto en tres fases:
- Ejemplo de Uso
- Demuestra implementación práctica con múltiples mensajes
- Incluye conteo de tokens y monitoreo de longitud de hilo
- Muestra cómo mantener el contexto de conversación a través de múltiples intercambios
Con este enfoque:
- Se agregan nuevos mensajes.
- Se verifica la longitud del historial.
- Si se supera el límite, se resume toda la conversación, se mantiene el resumen y los últimos mensajes.
- Se recorta cualquier exceso restante.
La gestión de hilos y ventanas de contexto es un aspecto fundamental para construir conversaciones escalables y coherentes de múltiples turnos en sistemas de IA. Aquí está por qué es importante y cómo funciona:
Primero, la segmentación de hilos por usuario asegura que cada conversación permanezca aislada y personal. Al mantener hilos de conversación separados para cada usuario, se previene la contaminación cruzada de contexto entre diferentes conversaciones, permitiendo respuestas más personalizadas y precisas.
Segundo, el conteo de tokens y recorte sirven como herramientas esenciales de mantenimiento. Al monitorear activamente el conteo de tokens de las conversaciones, puedes prevenir alcanzar los límites del contexto del modelo mientras preservas la información más relevante. Este proceso implica eliminar cuidadosamente mensajes antiguos mientras se mantiene el contexto crucial, similar a cómo las conversaciones humanas naturalmente se centran en información reciente y relevante.
Tercero, la sumarización del contexto actúa como una técnica de compresión de memoria. Cuando las conversaciones se alargan, resumir el contexto anterior permite mantener la narrativa esencial mientras se reduce el uso de tokens. Esto es similar a cómo los humanos mantienen la esencia de conversaciones anteriores sin recordar cada detalle.
La combinación de estas estrategias resulta en un asistente de IA que puede:
- Mantener un contexto consistente a través de múltiples turnos de conversación
- Escalar eficientemente sin degradar el rendimiento
- Proporcionar respuestas relevantes basadas tanto en contexto reciente como histórico
- Adaptarse a diferentes longitudes y complejidades de conversación
Estas capacidades aseguran que tu asistente de IA permanezca receptivo, informado y consciente del contexto durante diálogos extensos, creando una experiencia de conversación más natural y efectiva.