Menu iconMenu icon
OpenAI API Biblia Volumen 1

Capítulo 7: Memoria y Conversaciones de Varios Turnos

7.4 Soluciones para los Límites de Contexto

Por muy potentes que sean los modelos de OpenAI como GPT-4o, aún operan dentro de una ventana de contexto—un límite estricto sobre cuántos tokens puede "recordar" el modelo en una sola interacción. Piensa en esta ventana de contexto como un búfer de conversación: es la cantidad máxima de diálogo de ida y vuelta que la IA puede considerar a la vez. Para GPT-4o, esto puede ser hasta 128K tokens, lo cual es masivo—pero no infinito. Para ponerlo en perspectiva, 128K tokens es aproximadamente equivalente a un libro de 100 páginas, permitiendo conversaciones extensas pero aún requiriendo una gestión cuidadosa.

Cuando tu aplicación alcanza ese límite, el modelo comienza a "olvidar" las partes anteriores de la conversación, de manera similar a cómo una persona podría olvidar el principio de una conversación muy larga. Este "olvido" ocurre automáticamente a menos que gestiones explícitamente el contexto mediante técnicas como resumen, recorte selectivo o soluciones ingeniosas.

El modelo siempre priorizará el contenido más reciente, eliminando los mensajes más antiguos desde el principio de la conversación cuando se agregan nuevos. Este comportamiento hace crucial implementar estrategias adecuadas de gestión de contexto. En esta sección, exploraremos soluciones efectivas que te ayudan a mantener interacciones largas y significativas fluyendo — incluso más allá del presupuesto de tokens del modelo. Estas estrategias aseguran que tu IA mantenga conversaciones coherentes y contextualmente conscientes mientras gestiona eficientemente sus limitaciones de memoria.

7.4.1 El Desafío de la Ventana de Contexto

Un token es el componente fundamental en cómo los modelos de lenguaje procesan y entienden texto. Piensa en los tokens como las piezas individuales de un rompecabezas que forman el texto completo. Estos tokens pueden variar significativamente en tamaño y complejidad:

  1. Caracteres Individuales: Los tokens más pequeños pueden ser solo un carácter, como:
    • Letras individuales ("a", "b", "c")
    • Signos de puntuación (".", ",", "!")
    • Caracteres especiales ("@", "#", "$")
  2. Fragmentos de Palabras: Muchos tokens son en realidad partes de palabras:
    • Prefijos comunes ("pre-", "des-", "re-")
    • Sufijos comunes ("-ando", "-ado", "-ción")
    • Raíces y bases que forman palabras más grandes
  3. Palabras Completas: Algunos tokens representan palabras enteras, particularmente:
    • Palabras comunes en español ("el", "y", "pero")
    • Sustantivos simples ("gato", "casa", "árbol")
    • Verbos básicos ("correr", "saltar", "dormir")

Por ejemplo:

  • "ChatGPT es asombroso." → aproximadamente 5 tokens, donde "Chat" y "GPT" a menudo se procesan como tokens separados, mientras que palabras comunes como "es" son típicamente tokens individuales. Este ejemplo muestra cómo incluso una oración simple puede desglosarse en múltiples tokens distintos.
  • "Érase una vez en un reino lejano..." → podría ser 10-12 tokens, ya que frases comunes como "érase una" a menudo se dividen en tokens individuales, y los signos de puntuación como "..." pueden contarse como tokens separados. Esto demuestra cómo las frases más largas se dividen en sus partes constituyentes.

Entender el conteo de tokens es absolutamente crucial para desarrolladores y usuarios porque impacta directamente en cómo los modelos de IA procesan y responden al texto. Tu conversación incluye varios componentes clave:

  • Prompts del sistema: Las instrucciones que definen cómo debe comportarse la IA
    Consultas del usuario: Las preguntas y entradas que proporcionas
    Respuestas del asistente: Las respuestas generadas por el modelo de IA

A medida que estos componentes se acumulan, el conteo de tokens de tu conversación crece rápidamente, como llenar un contenedor con agua. Cada nuevo mensaje, ya sea una pregunta, respuesta o instrucción, añade más tokens a este total.

Cuando tu conversación se acerca al límite de tokens del modelo, ocurre un proceso importante: el sistema comienza a eliminar mensajes antiguos automáticamente desde el principio de la conversación. Esto es similar a cómo un contenedor lleno podría desbordarse - el contenido más antiguo se desecha para hacer espacio para nueva información. Este proceso de truncamiento automático puede tener consecuencias significativas:

  1. Pérdida de Contexto: Los detalles importantes anteriores podrían olvidarse
  2. Respuestas Desconectadas: La IA podría no hacer referencia a información previa importante
  3. Confusión: Tanto el modelo como el usuario podrían perder el hilo de la conversación
  4. Continuidad Rota: El flujo natural del diálogo puede verse interrumpido

Esta limitación hace esencial gestionar el uso de tokens de tu conversación cuidadosa y estratégicamente para mantener interacciones coherentes y contextuales.

7.4.2 Estrategia 1: Resumir Diálogos Anteriores

Una de las soluciones más fiables es resumir los mensajes antiguos y mantener solo la información clave. Esta poderosa técnica implica analizar cuidadosamente los turnos previos de conversación y condensarlos en resúmenes concisos que capturan los puntos esenciales, decisiones y contexto. El proceso funciona identificando los elementos más importantes de cada segmento de conversación y creando una versión condensada que retiene la información crucial mientras elimina detalles redundantes o menos relevantes.

Por ejemplo, varios mensajes que discuten requisitos de proyecto podrían comprimirse en un único resumen que indique "El usuario necesita una herramienta de procesamiento de datos basada en Python con capacidad de exportación CSV". Esta compresión podría representar múltiples mensajes que incluían discusiones técnicas, solicitudes de funcionalidades y detalles de implementación, todo destilado en una única declaración clara y procesable.

Este enfoque preserva el contexto mientras reduce dramáticamente el uso de tokens, frecuentemente comprimiendo docenas de mensajes en un único resumen rico en información que mantiene la coherencia conversacional mientras libera valioso espacio en la ventana de contexto para nuevas interacciones. El proceso de resumen puede implementarse ya sea automáticamente usando herramientas impulsadas por IA o manualmente a través de una revisión humana cuidadosa. La clave es mantener el significado esencial y el contexto mientras se reduce significativamente el conteo de tokens, permitiendo conversaciones más largas y significativas sin alcanzar los límites de contexto. Esto es particularmente valioso en escenarios donde el contexto histórico es crucial, como discusiones técnicas complejas, gestión continua de proyectos o interacciones detalladas de soporte al cliente.

Ejemplo: Auto-Resumen con OpenAI

def summarize_messages(messages, max_summary_length=120, temperature=0.3):
    """
    Summarize a list of conversation messages using OpenAI's API.
    
    Args:
        messages (list): List of message dictionaries with 'role' and 'content' keys
        max_summary_length (int): Maximum tokens for the summary (default: 120)
        temperature (float): Creativity of the response (0.0-1.0, default: 0.3)
    
    Returns:
        dict: A system message containing the conversation summary
    """
    # Format messages into a readable string
    formatted_messages = []
    for msg in messages:
        # Skip system messages in the summary
        if msg["role"] == "system":
            continue
        # Format each message with role and content
        formatted_messages.append(f'{msg["role"].capitalize()}: {msg["content"]}')
    
    # Create the summarization prompt
    prompt = [
        {
            "role": "system",
            "content": """You summarize conversations clearly and concisely.
                         Focus on key points, decisions, and important context.
                         Use bullet points if multiple topics are discussed."""
        },
        {
            "role": "user",
            "content": "Please summarize the following dialogue:\n\n" + 
                      "\n".join(formatted_messages)
        }
    ]
    
    try:
        # Call OpenAI API for summarization
        response = openai.ChatCompletion.create(
            model="gpt-4o",
            messages=prompt,
            max_tokens=max_summary_length,
            temperature=temperature
        )
        
        summary = response["choices"][0]["message"]["content"]
        
        # Return formatted system message with summary
        return {
            "role": "system",
            "content": f"Summary of earlier conversation: {summary}"
        }
        
    except Exception as e:
        # Handle potential API errors
        print(f"Error during summarization: {str(e)}")
        return {
            "role": "system",
            "content": "Error: Could not generate conversation summary."
        }

Desglose del Código:

  • Definición de Función y Documentación
    • Agregada documentación completa explicando propósito y parámetros
    • Agregados parámetros configurables para longitud del resumen y temperatura
  • Formateo de Mensajes
    • Filtra los mensajes del sistema para centrarse en el diálogo usuario-asistente
    • Capitaliza los roles para mejor legibilidad
    • Crea una cadena de conversación limpia y formateada
  • Ingeniería de Prompts Mejorada
    • Instrucciones del sistema expandidas para mejores resúmenes
    • Sugiere formato de viñetas para discusiones de múltiples temas
  • Manejo de Errores
    • Agregado bloque try-except para manejar fallos de API elegantemente
    • Devuelve mensaje de error informativo si falla el resumen
  • Mejores Prácticas
    • Utiliza indicaciones de tipo y nombres de variables claros
    • Sigue las pautas de estilo PEP 8
    • Implementa estructura de código modular y mantenible

Puedes llamar a esto cada vez que tu conversación alcance cierta longitud (por ejemplo, 80% del límite de contexto), luego reemplazar los mensajes anteriores con este resumen antes de continuar.

7.4.3 Estrategia 2: Eliminar Mensajes Irrelevantes

En lugar de incluir todo el historial de conversación en cada interacción, es crucial ser selectivo sobre qué contexto mantener. Este enfoque estratégico ayuda a optimizar el uso de tokens y mantener el contexto relevante mientras se asegura que la IA pueda proporcionar respuestas significativas. Al seleccionar cuidadosamente qué información conservar, puedes mejorar significativamente la eficiencia de tus conversaciones mientras mantienes su calidad. Aquí hay un desglose detallado de lo que deberías priorizar mantener:

  • El prompt del sistema: Este contiene las instrucciones fundamentales y configuraciones de personalidad que guían el comportamiento de la IA. Sin él, la IA podría perder su rol o propósito previsto. El prompt del sistema típicamente incluye información crítica como:
    • Pautas de comportamiento y tono de voz
    • Capacidades o limitaciones específicas
    • Requisitos de conocimiento específico del dominio
  • Los últimos intercambios usuario-asistente: Las interacciones recientes suelen contener el contexto más relevante para la conversación actual. Usualmente, los últimos 3-5 intercambios son suficientes para mantener la coherencia. Esto es importante porque:
    • El contexto reciente es más relevante para las preguntas actuales
    • Mantiene el flujo natural de la conversación
    • Ayuda a prevenir repeticiones o contradicciones
  • Cualquier instrucción o hecho fundamental: Mantén cualquier información crítica que se estableció anteriormente en la conversación, como preferencias del usuario, requisitos específicos o contexto importante que influye en toda la interacción. Esto incluye:
    • Preferencias o restricciones especificadas por el usuario
    • Decisiones importantes o acuerdos alcanzados durante la conversación
    • Detalles técnicos clave o especificaciones que afectan toda la discusión

Fragmento de Código: Lógica de Recorte

def trim_messages(messages, max_messages=6, model="gpt-4"):
    """
    Trim conversation history while preserving system prompts and recent messages.
    
    Args:
        messages (list): List of message dictionaries with 'role' and 'content'
        max_messages (int): Maximum number of non-system messages to keep
        model (str): OpenAI model to use for potential follow-up
        
    Returns:
        list: Trimmed message history
    """
    try:
        # Separate system prompts and conversation
        system_prompt = [m for m in messages if m["role"] == "system"]
        conversation = [m for m in messages if m["role"] != "system"]
        
        # Calculate tokens (approximate)
        def estimate_tokens(text):
            return len(text.split()) * 1.3  # Rough estimate
            
        # Get recent messages while staying under limit
        trimmed_conversation = conversation[-max_messages:]
        
        # Add a system note about trimming if needed
        if len(conversation) > max_messages:
            system_prompt.append({
                "role": "system",
                "content": f"Note: {len(conversation) - max_messages} earlier messages were trimmed for context management."
            })
        
        # Combine and validate against OpenAI's limits
        final_messages = system_prompt + trimmed_conversation
        
        # Optional: Verify token count with OpenAI
        total_tokens = sum(estimate_tokens(m["content"]) for m in final_messages)
        if total_tokens > 8000:  # Conservative limit for GPT-4
            raise ValueError(f"Combined messages exceed token limit: {total_tokens}")
            
        return final_messages
        
    except Exception as e:
        print(f"Error trimming messages: {str(e)}")
        # Return last few messages as fallback
        return system_prompt + conversation[-3:]

# Example usage:
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello!"},
    {"role": "assistant", "content": "Hi there!"},
    # ... many messages later ...
]

trimmed = trim_messages(messages)

# Use with OpenAI API
response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=trimmed,
    temperature=0.7
)

Analicemos este código que gestiona el historial de conversación y los límites de tokens:

Propósito Principal de la Función:

La función trim_messages gestiona eficientemente el historial de conversación preservando los prompts del sistema mientras limita los mensajes regulares.

Componentes Clave:

  • Parámetros
    • messages: Lista de diccionarios de mensajes
    • max_messages: Máximo de mensajes no sistémicos a mantener (predeterminado 6)
    • model: Especifica el modelo de OpenAI
  • Separación de Mensajes
    • Separa los prompts del sistema de la conversación regular
    • Preserva todos los mensajes del sistema mientras recorta los mensajes regulares
  • Gestión de Tokens
    • Implementa una estimación simple de tokens (1.3 tokens por palabra)
    • Impone un límite de 8000 tokens para GPT-4
    • Genera un error si se excede el límite
  • Seguimiento del Historial
    • Mantiene un registro de los mensajes recortados
    • Añade una nota del sistema sobre cuántos mensajes fueron eliminados
    • Mantiene los mensajes más recientes dentro del límite especificado

Manejo de Errores:

Si ocurre un error, la función recurre a devolver los prompts del sistema más los últimos tres mensajes de la conversación.

Ejemplo de Uso:

El ejemplo muestra cómo usar esto con la API de OpenAI, manteniendo un historial de conversación limpio mientras se previene el desbordamiento de tokens.

Esta implementación asegura que la información más reciente y relevante permanezca en contexto mientras minimiza la sobrecarga de tokens.

7.4.4 Estrategia 3: Descarga a Memoria Externa (Recuperación Híbrida)

Si estás simulando memoria a largo plazo, puedes almacenar todas las interacciones externamente y recuperar solo las relevantes en tiempo de ejecución. Este poderoso enfoque utiliza una base de datos externa o sistema de almacenamiento para mantener un historial completo de todas las conversaciones, mensajes e información. En lugar de sobrecargar el contexto inmediato con datos excesivos, este método permite la recuperación inteligente y selectiva de información histórica cuando sea necesario. Por ejemplo, en un contexto de servicio al cliente, el sistema podría acceder instantáneamente a interacciones previas con el mismo cliente sobre problemas similares, proporcionando respuestas más personalizadas e informadas.

Usando embeddings, puedes transformar conversaciones en representaciones matemáticas que capturan su significado y contexto. Esta sofisticada técnica permite capacidades de búsqueda semántica que van mucho más allá de la simple coincidencia de palabras clave.

Aquí hay un desglose detallado de cómo funciona este sistema:

  • Cada mensaje se transforma en un vector de alta dimensionalidad usando modelos de embedding
    • Estos vectores capturan el significado semántico del texto convirtiendo palabras y frases en representaciones numéricas
    • Los conceptos similares terminan más cerca entre sí en el espacio vectorial, permitiendo un mapeo intuitivo de relaciones
    • El proceso de embedding considera el contexto, sinónimos y conceptos relacionados, no solo coincidencias exactas
  • Cuando llegan nuevas consultas, el sistema puede:
    • Convertir la nueva consulta en un vector usando el mismo modelo de embedding
    • Encontrar los vectores almacenados más similares usando algoritmos eficientes de búsqueda de similitud
    • Recuperar solo aquellas piezas relevantes de contexto, priorizando la información más semánticamente relacionada
    • Ajustar dinámicamente la cantidad de contexto basado en puntajes de relevancia

Este sofisticado enfoque permite una recuperación de contexto eficiente y relevante sin sobrepasar los límites de tokens. El sistema puede mantener una memoria virtualmente ilimitada mientras solo extrae la información más pertinente para cada interacción. Esto es particularmente valioso en aplicaciones que requieren contexto histórico profundo, como relaciones a largo plazo con clientes, plataformas educativas o sistemas complejos de gestión de proyectos.

Herramientas Esenciales para la Implementación:

  • openai.Embedding - La API de embedding de OpenAI que convierte texto en vectores numéricos, capturando significado semántico y relaciones entre diferentes piezas de texto. Esto es fundamental para crear representaciones vectoriales consultables de tu historial de conversación.
  • FAISS - La potente biblioteca de búsqueda de similitud de Facebook AI, optimizada para buscar rápidamente a través de millones de vectores de alta dimensionalidad. O Pinecone - Un servicio administrado de base de datos vectorial que maneja almacenamiento vectorial y búsqueda de similitud con escalado automático y actualizaciones en tiempo real.
  • Marcos de búsqueda vectorial:
    • chromadb - Una base de datos de embedding de código abierto que facilita el almacenamiento y consulta de tus embeddings vectoriales con metadatos adicionales
    • Weaviate - Un motor de búsqueda vectorial que combina almacenamiento vectorial con consultas basadas en GraphQL y capacidades de clasificación automática

Como discutimos en el Capítulo 6, sección 6.4 sobre RAG (Generación Aumentada por Recuperación), el principio clave sigue siendo sencillo: almacena más, inyecta menos. Esto significa mantener una base de conocimiento externa completa mientras se recupera selectivamente solo la información más relevante para cada interacción, en lugar de intentar meter todo en la ventana de contexto inmediata.

class ConversationManager:
    def __init__(self, openai_api_key):
        self.api_key = openai_api_key
        self.summary = ""
        self.messages = []
        self.summary_interval = 5  # Summarize every 5 messages
        self.message_count = 0
        
    def add_message(self, role, content):
        """Add a new message to the conversation."""
        self.messages.append({"role": role, "content": content})
        self.message_count += 1
        
        # Check if it's time to create a summary
        if self.message_count % self.summary_interval == 0:
            self.update_summary()
    
    def update_summary(self):
        """Create a summary of recent conversation."""
        try:
            # Create prompt for summarization
            summary_prompt = {
                "role": "system",
                "content": "Please create a brief summary of the following conversation. "
                          "Focus on key points and decisions made."
            }
            
            # Get last few messages to summarize
            recent_messages = self.messages[-self.summary_interval:]
            
            # Request summary from OpenAI
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    summary_prompt,
                    *recent_messages,
                    {"role": "user", "content": "Please summarize our discussion."}
                ],
                temperature=0.7
            )
            
            # Update the running summary
            new_summary = response.choices[0].message.content
            if self.summary:
                self.summary = f"{self.summary}\n\nUpdate: {new_summary}"
            else:
                self.summary = new_summary
                
            # Trim old messages but keep the summary
            self.messages = [
                {"role": "system", "content": f"Previous context: {self.summary}"},
                *recent_messages
            ]
            
        except Exception as e:
            print(f"Error updating summary: {str(e)}")
    
    def get_current_context(self):
        """Get current conversation context including summary."""
        if self.summary:
            return [
                {"role": "system", "content": f"Previous context: {self.summary}"},
                *self.messages
            ]
        return self.messages

# Example usage
conversation = ConversationManager("your-api-key")

# Add some messages
conversation.add_message("user", "Can you help me learn Python?")
conversation.add_message("assistant", "Of course! What specific topics interest you?")
conversation.add_message("user", "I'd like to learn about functions.")
conversation.add_message("assistant", "Let's start with the basics of functions...")
conversation.add_message("user", "Can you show me an example?")

Desglose del Código:

  • Estructura de la Clase
    • ConversationManager maneja todos los aspectos de la gestión y resumen de conversaciones
    • Mantiene tanto los mensajes actuales como el resumen continuo
    • Intervalo de resumen configurable (por defecto: cada 5 mensajes)
  • Componentes Principales
    • add_message(): Rastrea nuevos mensajes y activa actualizaciones de resumen
    • update_summary(): Crea resúmenes usando la API de OpenAI
    • get_current_context(): Combina el resumen con mensajes recientes
  • Gestión de Resúmenes
    • Se activa automáticamente después de un número específico de mensajes
    • Preserva el contexto combinando resúmenes antiguos con nueva información
    • Maneja errores con elegancia para prevenir pérdida de datos
  • Optimización de Memoria
    • Mantiene un resumen continuo de conversaciones anteriores
    • Conserva mensajes recientes para contexto inmediato
    • Gestiona eficientemente el uso de tokens mediante el resumen de contenido antiguo

Beneficios de esta Implementación:

  • Mantiene la coherencia de la conversación mientras gestiona la ventana de contexto
  • Maneja automáticamente la generación de resúmenes en intervalos regulares
  • Proporciona fácil acceso tanto al contexto actual como al resumen histórico
  • Escala bien para conversaciones de larga duración

7.4.5 Estrategia 4: Usar "Resúmenes Continuos" para Memoria Episódica

A medida que la sesión avanza, resume dinámicamente cada sección de la conversación y mantén un resumen evolutivo que se actualiza cada pocos turnos. Este poderoso enfoque funciona monitoreando y analizando continuamente la conversación en curso en segmentos discretos. El sistema identifica automáticamente las pausas naturales en la discusión, puntos clave de decisión y transiciones de temas, creando un documento vivo que refleja la evolución de la conversación.

Así es como funciona en la práctica:

  1. Cada pocos mensajes (típicamente 3-5 turnos), el sistema analiza la conversación reciente
  2. Extrae información esencial, decisiones y conclusiones
  3. Estas se condensan en un resumen conciso pero informativo
  4. El resumen se fusiona entonces con resúmenes previos, manteniendo el flujo cronológico

Por ejemplo, después de varios mensajes sobre funciones de Python, el resumen podría comenzar con "Se discutieron definiciones de funciones, parámetros y valores de retorno" mientras mantiene ejemplos específicos de código disponibles en el contexto a corto plazo. A medida que la conversación avanza hacia el manejo de errores, el resumen se expandiría para incluir "Se exploraron bloques try/except y sus ventajas sobre las declaraciones condicionales."

Puedes mantener esta "memoria episódica" junto con tu búfer a corto plazo, creando un sistema de memoria de dos niveles que refleja la cognición humana. El búfer a corto plazo contiene mensajes recientes con detalle completo, mientras que la memoria episódica mantiene versiones resumidas de conversaciones anteriores. Este enfoque de memoria dual sirve para múltiples propósitos:

  1. Mantiene la coherencia de la conversación conservando tanto el contexto reciente detallado como el contexto histórico más amplio
  2. Previene el desbordamiento de contexto condensando información antigua en resúmenes compactos
  3. Permite referencias rápidas a temas anteriores sin cargar el historial completo de conversación
  4. Crea un flujo natural de conversación permitiendo que la IA haga referencia tanto al contexto reciente como al histórico

Este sistema funciona de manera similar a la memoria humana, donde mantenemos recuerdos vívidos recientes mientras los recuerdos más antiguos se vuelven más condensados y resumidos con el tiempo. Este enfoque natural para la gestión de memoria ayuda a crear conversaciones más atractivas y contextualmente conscientes mientras gestiona eficientemente los recursos computacionales.

Ejemplo:

# Comprehensive conversation manager with OpenAI integration
import openai
from typing import List, Dict
import time

class ConversationManager:
    def __init__(self, api_key: str):
        self.api_key = api_key
        openai.api_key = api_key
        self.session_summary = ""
        self.messages: List[Dict[str, str]] = []
        self.last_summary_time = time.time()
        self.summary_interval = 300  # 5 minutes

    def add_message(self, role: str, content: str) -> None:
        """Add a new message and update summary if needed."""
        self.messages.append({"role": role, "content": content})
        
        # Check if it's time to update summary
        if time.time() - self.last_summary_time > self.summary_interval:
            self.update_summary()

    def update_summary(self) -> None:
        """Update conversation summary using OpenAI."""
        try:
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    {"role": "system", "content": "Create a brief summary of this conversation."},
                    *self.messages[-5:]  # Last 5 messages for context
                ],
                temperature=0.7,
                max_tokens=150
            )
            
            new_summary = response.choices[0].message.content
            self.session_summary = f"{self.session_summary}\n{new_summary}" if self.session_summary else new_summary
            self.last_summary_time = time.time()
            
        except Exception as e:
            print(f"Error updating summary: {str(e)}")

    def get_context(self) -> List[Dict[str, str]]:
        """Get current conversation context with summary."""
        return [
            {"role": "system", "content": f"Previous context: {self.session_summary}"},
            *self.messages[-5:]  # Keep last 5 messages
        ]

    async def get_response(self, user_message: str) -> str:
        """Get AI response using current context."""
        self.add_message("user", user_message)
        
        try:
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=self.get_context(),
                temperature=0.7,
                max_tokens=500
            )
            
            ai_response = response.choices[0].message.content
            self.add_message("assistant", ai_response)
            return ai_response
            
        except Exception as e:
            print(f"Error getting response: {str(e)}")
            return "I apologize, but I encountered an error processing your request."

# Example usage
api_key = "your-openai-api-key"
conversation = ConversationManager(api_key)

# Simulate a conversation
conversation.add_message("user", "I want to learn about Python error handling.")
conversation.add_message("assistant", "Let's start with try/except blocks.")
conversation.add_message("user", "What's the difference between try/except and if/else?")

# Get response with context
response = await conversation.get_response("Can you show me an example?")

Desglose del Código:

  • Componentes Principales:
    • La clase ConversationManager maneja todo el estado de la conversación y las interacciones con OpenAI
    • Generación automática de resúmenes cada 5 minutos
    • Mantiene tanto los mensajes recientes como el resumen histórico
    • Sugerencias de tipo y manejo de errores para mayor robustez
  • Métodos Principales:
    • add_message(): Rastrea el historial de conversaciones
    • update_summary(): Utiliza GPT-4 para crear resúmenes de conversaciones
    • get_context(): Combina el resumen con mensajes recientes
    • get_response(): Maneja la interacción con la API para las respuestas
  • Características:
    • Actualizaciones de resumen basadas en tiempo en lugar de cantidad de mensajes
    • Manejo adecuado de errores y registro
    • Gestión eficiente del contexto con ventana móvil
    • Soporte asíncrono para mejor rendimiento

Luego actualiza session_summary cada 5 turnos utilizando la estrategia de resumen anterior.

7.4.6 Estrategia 5: Prompts Modulares en Lugar de Hilos Largos

Para muchas aplicaciones, mantener un historial extenso de mensajes no siempre es necesario ni eficiente. De hecho, mantener historiales largos de conversación puede llevar a mayores costos de API, tiempos de respuesta más lentos y potencialmente resultados inconsistentes. En su lugar, un enfoque más eficiente es generar plantillas reutilizables con instrucciones completas incorporadas desde el principio. Esta estrategia reduce el uso de tokens y mejora la consistencia de las respuestas al cargar el contexto esencial por adelantado.

Las plantillas pueden incluir roles específicos, capacidades y restricciones que de otro modo necesitarían ser comunicados repetidamente. Estas plantillas actúan como base para el comportamiento y comprensión de la IA, eliminando la necesidad de transportar contexto a través de múltiples intercambios. Cuando están bien diseñadas, pueden proporcionar a la IA pautas claras sobre su rol, nivel de experiencia, estilo de comunicación y conocimiento específico del dominio.

Ejemplo: Construcción de un asistente experto en codificación de IA

# Template for an AI expert coding assistant
system_message = {
    "role": "system",
    "content": """You are a Python expert with the following capabilities:
    - Generate clean, efficient, and well-commented code
    - Provide detailed explanations of code functionality
    - Follow best practices and PEP 8 standards
    - Assume common data science libraries (pandas, numpy) are installed
    - Optimize code for readability and performance

    When responding:
    1. Always include docstrings and comments
    2. Explain complex logic
    3. Handle edge cases and errors
    4. Provide example usage where appropriate"""
}

# Example implementation using OpenAI API
import openai
from typing import Dict, Any

class PythonExpertAssistant:
    def __init__(self, api_key: str):
        """Initialize the Python expert assistant with API key."""
        self.api_key = api_key
        openai.api_key = api_key
        self.system_message = system_message

    async def get_code_solution(self, prompt: str) -> Dict[str, Any]:
        """
        Generate a code solution based on user prompt.
        
        Args:
            prompt (str): User's coding question or request
            
        Returns:
            Dict containing response and metadata
        """
        try:
            response = await openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    self.system_message,
                    {"role": "user", "content": prompt}
                ],
                temperature=0.7,
                max_tokens=1000,
                presence_penalty=0.6
            )
            
            return {
                "code": response.choices[0].message.content,
                "tokens_used": response.usage.total_tokens,
                "status": "success"
            }
            
        except Exception as e:
            return {
                "error": str(e),
                "status": "error"
            }

# Example usage
assistant = PythonExpertAssistant("your-api-key")
response = await assistant.get_code_solution(
    "Create a function to calculate Fibonacci sequence"
)

Desglose del Código:

  • Estructura del Mensaje del Sistema
    • Define el rol y las capacidades claramente
    • Establece expectativas para la calidad y el estilo del código
    • Establece un formato de respuesta consistente
  • Implementación de la Clase
    • Sugerencias de tipo para mejor mantenibilidad del código
    • Soporte asíncrono para mejor rendimiento
    • Manejo apropiado de errores y formato de respuesta
  • Integración de API
    • Temperatura configurable para la creatividad de las respuestas
    • Gestión de tokens
    • Penalización de presencia para fomentar respuestas diversas

Esto elimina la necesidad de transportar este contexto en cada mensaje.

7.4.7 Resumen: Consejos Prácticos

La ventana de contexto, en lugar de verse como una limitación, debe considerarse como una oportunidad creativa que nos impulsa a desarrollar soluciones más sofisticadas. Con decisiones arquitectónicas reflexivas, podemos crear sistemas que gestionen eficazmente conversaciones a largo plazo mientras permanecemos dentro de las restricciones de tokens. Así es como contribuye cada componente clave:

La Sumarización nos permite condensar historiales de conversación extensos en representaciones compactas y significativas. Esto preserva la información esencial mientras reduce significativamente el uso de tokens. Por ejemplo, una conversación de 1000 tokens podría destilarse en un resumen de 100 tokens capturando los puntos clave.

Los sistemas de Recuperación permiten un acceso inteligente a los datos históricos de conversación. Mediante el uso de incrustaciones vectoriales o búsqueda semántica, podemos extraer el contexto pasado relevante exactamente cuando se necesita, en lugar de transportar todo el historial de conversación. Esto crea un flujo más natural donde los temas anteriores pueden recordarse contextualmente.

Las estrategias de Recorte ayudan a mantener un rendimiento óptimo eliminando selectivamente las partes menos relevantes de la conversación mientras se mantiene el contexto crucial. Esto puede implicar eliminar mensajes más antiguos después de la sumarización o podar información redundante para permanecer dentro de los límites de tokens.

La inyección de memoria dinámica nos permite insertar estratégicamente contexto relevante cuando se necesita. Esto podría incluir preferencias del usuario, interacciones previas o conocimiento específico del dominio, haciendo las conversaciones más personalizadas y contextualmente conscientes sin repetición constante.

Cuando estas técnicas se combinan efectivamente, el resultado es un sistema de IA que puede mantener conversaciones extensas y naturales mientras gestiona eficientemente los recursos computacionales. Esto crea aplicaciones que se sienten notablemente humanas en su capacidad para mantener el contexto y hacer referencia a interacciones previas, incluso cuando las conversaciones se extienden por largos períodos o múltiples sesiones.

7.4 Soluciones para los Límites de Contexto

Por muy potentes que sean los modelos de OpenAI como GPT-4o, aún operan dentro de una ventana de contexto—un límite estricto sobre cuántos tokens puede "recordar" el modelo en una sola interacción. Piensa en esta ventana de contexto como un búfer de conversación: es la cantidad máxima de diálogo de ida y vuelta que la IA puede considerar a la vez. Para GPT-4o, esto puede ser hasta 128K tokens, lo cual es masivo—pero no infinito. Para ponerlo en perspectiva, 128K tokens es aproximadamente equivalente a un libro de 100 páginas, permitiendo conversaciones extensas pero aún requiriendo una gestión cuidadosa.

Cuando tu aplicación alcanza ese límite, el modelo comienza a "olvidar" las partes anteriores de la conversación, de manera similar a cómo una persona podría olvidar el principio de una conversación muy larga. Este "olvido" ocurre automáticamente a menos que gestiones explícitamente el contexto mediante técnicas como resumen, recorte selectivo o soluciones ingeniosas.

El modelo siempre priorizará el contenido más reciente, eliminando los mensajes más antiguos desde el principio de la conversación cuando se agregan nuevos. Este comportamiento hace crucial implementar estrategias adecuadas de gestión de contexto. En esta sección, exploraremos soluciones efectivas que te ayudan a mantener interacciones largas y significativas fluyendo — incluso más allá del presupuesto de tokens del modelo. Estas estrategias aseguran que tu IA mantenga conversaciones coherentes y contextualmente conscientes mientras gestiona eficientemente sus limitaciones de memoria.

7.4.1 El Desafío de la Ventana de Contexto

Un token es el componente fundamental en cómo los modelos de lenguaje procesan y entienden texto. Piensa en los tokens como las piezas individuales de un rompecabezas que forman el texto completo. Estos tokens pueden variar significativamente en tamaño y complejidad:

  1. Caracteres Individuales: Los tokens más pequeños pueden ser solo un carácter, como:
    • Letras individuales ("a", "b", "c")
    • Signos de puntuación (".", ",", "!")
    • Caracteres especiales ("@", "#", "$")
  2. Fragmentos de Palabras: Muchos tokens son en realidad partes de palabras:
    • Prefijos comunes ("pre-", "des-", "re-")
    • Sufijos comunes ("-ando", "-ado", "-ción")
    • Raíces y bases que forman palabras más grandes
  3. Palabras Completas: Algunos tokens representan palabras enteras, particularmente:
    • Palabras comunes en español ("el", "y", "pero")
    • Sustantivos simples ("gato", "casa", "árbol")
    • Verbos básicos ("correr", "saltar", "dormir")

Por ejemplo:

  • "ChatGPT es asombroso." → aproximadamente 5 tokens, donde "Chat" y "GPT" a menudo se procesan como tokens separados, mientras que palabras comunes como "es" son típicamente tokens individuales. Este ejemplo muestra cómo incluso una oración simple puede desglosarse en múltiples tokens distintos.
  • "Érase una vez en un reino lejano..." → podría ser 10-12 tokens, ya que frases comunes como "érase una" a menudo se dividen en tokens individuales, y los signos de puntuación como "..." pueden contarse como tokens separados. Esto demuestra cómo las frases más largas se dividen en sus partes constituyentes.

Entender el conteo de tokens es absolutamente crucial para desarrolladores y usuarios porque impacta directamente en cómo los modelos de IA procesan y responden al texto. Tu conversación incluye varios componentes clave:

  • Prompts del sistema: Las instrucciones que definen cómo debe comportarse la IA
    Consultas del usuario: Las preguntas y entradas que proporcionas
    Respuestas del asistente: Las respuestas generadas por el modelo de IA

A medida que estos componentes se acumulan, el conteo de tokens de tu conversación crece rápidamente, como llenar un contenedor con agua. Cada nuevo mensaje, ya sea una pregunta, respuesta o instrucción, añade más tokens a este total.

Cuando tu conversación se acerca al límite de tokens del modelo, ocurre un proceso importante: el sistema comienza a eliminar mensajes antiguos automáticamente desde el principio de la conversación. Esto es similar a cómo un contenedor lleno podría desbordarse - el contenido más antiguo se desecha para hacer espacio para nueva información. Este proceso de truncamiento automático puede tener consecuencias significativas:

  1. Pérdida de Contexto: Los detalles importantes anteriores podrían olvidarse
  2. Respuestas Desconectadas: La IA podría no hacer referencia a información previa importante
  3. Confusión: Tanto el modelo como el usuario podrían perder el hilo de la conversación
  4. Continuidad Rota: El flujo natural del diálogo puede verse interrumpido

Esta limitación hace esencial gestionar el uso de tokens de tu conversación cuidadosa y estratégicamente para mantener interacciones coherentes y contextuales.

7.4.2 Estrategia 1: Resumir Diálogos Anteriores

Una de las soluciones más fiables es resumir los mensajes antiguos y mantener solo la información clave. Esta poderosa técnica implica analizar cuidadosamente los turnos previos de conversación y condensarlos en resúmenes concisos que capturan los puntos esenciales, decisiones y contexto. El proceso funciona identificando los elementos más importantes de cada segmento de conversación y creando una versión condensada que retiene la información crucial mientras elimina detalles redundantes o menos relevantes.

Por ejemplo, varios mensajes que discuten requisitos de proyecto podrían comprimirse en un único resumen que indique "El usuario necesita una herramienta de procesamiento de datos basada en Python con capacidad de exportación CSV". Esta compresión podría representar múltiples mensajes que incluían discusiones técnicas, solicitudes de funcionalidades y detalles de implementación, todo destilado en una única declaración clara y procesable.

Este enfoque preserva el contexto mientras reduce dramáticamente el uso de tokens, frecuentemente comprimiendo docenas de mensajes en un único resumen rico en información que mantiene la coherencia conversacional mientras libera valioso espacio en la ventana de contexto para nuevas interacciones. El proceso de resumen puede implementarse ya sea automáticamente usando herramientas impulsadas por IA o manualmente a través de una revisión humana cuidadosa. La clave es mantener el significado esencial y el contexto mientras se reduce significativamente el conteo de tokens, permitiendo conversaciones más largas y significativas sin alcanzar los límites de contexto. Esto es particularmente valioso en escenarios donde el contexto histórico es crucial, como discusiones técnicas complejas, gestión continua de proyectos o interacciones detalladas de soporte al cliente.

Ejemplo: Auto-Resumen con OpenAI

def summarize_messages(messages, max_summary_length=120, temperature=0.3):
    """
    Summarize a list of conversation messages using OpenAI's API.
    
    Args:
        messages (list): List of message dictionaries with 'role' and 'content' keys
        max_summary_length (int): Maximum tokens for the summary (default: 120)
        temperature (float): Creativity of the response (0.0-1.0, default: 0.3)
    
    Returns:
        dict: A system message containing the conversation summary
    """
    # Format messages into a readable string
    formatted_messages = []
    for msg in messages:
        # Skip system messages in the summary
        if msg["role"] == "system":
            continue
        # Format each message with role and content
        formatted_messages.append(f'{msg["role"].capitalize()}: {msg["content"]}')
    
    # Create the summarization prompt
    prompt = [
        {
            "role": "system",
            "content": """You summarize conversations clearly and concisely.
                         Focus on key points, decisions, and important context.
                         Use bullet points if multiple topics are discussed."""
        },
        {
            "role": "user",
            "content": "Please summarize the following dialogue:\n\n" + 
                      "\n".join(formatted_messages)
        }
    ]
    
    try:
        # Call OpenAI API for summarization
        response = openai.ChatCompletion.create(
            model="gpt-4o",
            messages=prompt,
            max_tokens=max_summary_length,
            temperature=temperature
        )
        
        summary = response["choices"][0]["message"]["content"]
        
        # Return formatted system message with summary
        return {
            "role": "system",
            "content": f"Summary of earlier conversation: {summary}"
        }
        
    except Exception as e:
        # Handle potential API errors
        print(f"Error during summarization: {str(e)}")
        return {
            "role": "system",
            "content": "Error: Could not generate conversation summary."
        }

Desglose del Código:

  • Definición de Función y Documentación
    • Agregada documentación completa explicando propósito y parámetros
    • Agregados parámetros configurables para longitud del resumen y temperatura
  • Formateo de Mensajes
    • Filtra los mensajes del sistema para centrarse en el diálogo usuario-asistente
    • Capitaliza los roles para mejor legibilidad
    • Crea una cadena de conversación limpia y formateada
  • Ingeniería de Prompts Mejorada
    • Instrucciones del sistema expandidas para mejores resúmenes
    • Sugiere formato de viñetas para discusiones de múltiples temas
  • Manejo de Errores
    • Agregado bloque try-except para manejar fallos de API elegantemente
    • Devuelve mensaje de error informativo si falla el resumen
  • Mejores Prácticas
    • Utiliza indicaciones de tipo y nombres de variables claros
    • Sigue las pautas de estilo PEP 8
    • Implementa estructura de código modular y mantenible

Puedes llamar a esto cada vez que tu conversación alcance cierta longitud (por ejemplo, 80% del límite de contexto), luego reemplazar los mensajes anteriores con este resumen antes de continuar.

7.4.3 Estrategia 2: Eliminar Mensajes Irrelevantes

En lugar de incluir todo el historial de conversación en cada interacción, es crucial ser selectivo sobre qué contexto mantener. Este enfoque estratégico ayuda a optimizar el uso de tokens y mantener el contexto relevante mientras se asegura que la IA pueda proporcionar respuestas significativas. Al seleccionar cuidadosamente qué información conservar, puedes mejorar significativamente la eficiencia de tus conversaciones mientras mantienes su calidad. Aquí hay un desglose detallado de lo que deberías priorizar mantener:

  • El prompt del sistema: Este contiene las instrucciones fundamentales y configuraciones de personalidad que guían el comportamiento de la IA. Sin él, la IA podría perder su rol o propósito previsto. El prompt del sistema típicamente incluye información crítica como:
    • Pautas de comportamiento y tono de voz
    • Capacidades o limitaciones específicas
    • Requisitos de conocimiento específico del dominio
  • Los últimos intercambios usuario-asistente: Las interacciones recientes suelen contener el contexto más relevante para la conversación actual. Usualmente, los últimos 3-5 intercambios son suficientes para mantener la coherencia. Esto es importante porque:
    • El contexto reciente es más relevante para las preguntas actuales
    • Mantiene el flujo natural de la conversación
    • Ayuda a prevenir repeticiones o contradicciones
  • Cualquier instrucción o hecho fundamental: Mantén cualquier información crítica que se estableció anteriormente en la conversación, como preferencias del usuario, requisitos específicos o contexto importante que influye en toda la interacción. Esto incluye:
    • Preferencias o restricciones especificadas por el usuario
    • Decisiones importantes o acuerdos alcanzados durante la conversación
    • Detalles técnicos clave o especificaciones que afectan toda la discusión

Fragmento de Código: Lógica de Recorte

def trim_messages(messages, max_messages=6, model="gpt-4"):
    """
    Trim conversation history while preserving system prompts and recent messages.
    
    Args:
        messages (list): List of message dictionaries with 'role' and 'content'
        max_messages (int): Maximum number of non-system messages to keep
        model (str): OpenAI model to use for potential follow-up
        
    Returns:
        list: Trimmed message history
    """
    try:
        # Separate system prompts and conversation
        system_prompt = [m for m in messages if m["role"] == "system"]
        conversation = [m for m in messages if m["role"] != "system"]
        
        # Calculate tokens (approximate)
        def estimate_tokens(text):
            return len(text.split()) * 1.3  # Rough estimate
            
        # Get recent messages while staying under limit
        trimmed_conversation = conversation[-max_messages:]
        
        # Add a system note about trimming if needed
        if len(conversation) > max_messages:
            system_prompt.append({
                "role": "system",
                "content": f"Note: {len(conversation) - max_messages} earlier messages were trimmed for context management."
            })
        
        # Combine and validate against OpenAI's limits
        final_messages = system_prompt + trimmed_conversation
        
        # Optional: Verify token count with OpenAI
        total_tokens = sum(estimate_tokens(m["content"]) for m in final_messages)
        if total_tokens > 8000:  # Conservative limit for GPT-4
            raise ValueError(f"Combined messages exceed token limit: {total_tokens}")
            
        return final_messages
        
    except Exception as e:
        print(f"Error trimming messages: {str(e)}")
        # Return last few messages as fallback
        return system_prompt + conversation[-3:]

# Example usage:
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello!"},
    {"role": "assistant", "content": "Hi there!"},
    # ... many messages later ...
]

trimmed = trim_messages(messages)

# Use with OpenAI API
response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=trimmed,
    temperature=0.7
)

Analicemos este código que gestiona el historial de conversación y los límites de tokens:

Propósito Principal de la Función:

La función trim_messages gestiona eficientemente el historial de conversación preservando los prompts del sistema mientras limita los mensajes regulares.

Componentes Clave:

  • Parámetros
    • messages: Lista de diccionarios de mensajes
    • max_messages: Máximo de mensajes no sistémicos a mantener (predeterminado 6)
    • model: Especifica el modelo de OpenAI
  • Separación de Mensajes
    • Separa los prompts del sistema de la conversación regular
    • Preserva todos los mensajes del sistema mientras recorta los mensajes regulares
  • Gestión de Tokens
    • Implementa una estimación simple de tokens (1.3 tokens por palabra)
    • Impone un límite de 8000 tokens para GPT-4
    • Genera un error si se excede el límite
  • Seguimiento del Historial
    • Mantiene un registro de los mensajes recortados
    • Añade una nota del sistema sobre cuántos mensajes fueron eliminados
    • Mantiene los mensajes más recientes dentro del límite especificado

Manejo de Errores:

Si ocurre un error, la función recurre a devolver los prompts del sistema más los últimos tres mensajes de la conversación.

Ejemplo de Uso:

El ejemplo muestra cómo usar esto con la API de OpenAI, manteniendo un historial de conversación limpio mientras se previene el desbordamiento de tokens.

Esta implementación asegura que la información más reciente y relevante permanezca en contexto mientras minimiza la sobrecarga de tokens.

7.4.4 Estrategia 3: Descarga a Memoria Externa (Recuperación Híbrida)

Si estás simulando memoria a largo plazo, puedes almacenar todas las interacciones externamente y recuperar solo las relevantes en tiempo de ejecución. Este poderoso enfoque utiliza una base de datos externa o sistema de almacenamiento para mantener un historial completo de todas las conversaciones, mensajes e información. En lugar de sobrecargar el contexto inmediato con datos excesivos, este método permite la recuperación inteligente y selectiva de información histórica cuando sea necesario. Por ejemplo, en un contexto de servicio al cliente, el sistema podría acceder instantáneamente a interacciones previas con el mismo cliente sobre problemas similares, proporcionando respuestas más personalizadas e informadas.

Usando embeddings, puedes transformar conversaciones en representaciones matemáticas que capturan su significado y contexto. Esta sofisticada técnica permite capacidades de búsqueda semántica que van mucho más allá de la simple coincidencia de palabras clave.

Aquí hay un desglose detallado de cómo funciona este sistema:

  • Cada mensaje se transforma en un vector de alta dimensionalidad usando modelos de embedding
    • Estos vectores capturan el significado semántico del texto convirtiendo palabras y frases en representaciones numéricas
    • Los conceptos similares terminan más cerca entre sí en el espacio vectorial, permitiendo un mapeo intuitivo de relaciones
    • El proceso de embedding considera el contexto, sinónimos y conceptos relacionados, no solo coincidencias exactas
  • Cuando llegan nuevas consultas, el sistema puede:
    • Convertir la nueva consulta en un vector usando el mismo modelo de embedding
    • Encontrar los vectores almacenados más similares usando algoritmos eficientes de búsqueda de similitud
    • Recuperar solo aquellas piezas relevantes de contexto, priorizando la información más semánticamente relacionada
    • Ajustar dinámicamente la cantidad de contexto basado en puntajes de relevancia

Este sofisticado enfoque permite una recuperación de contexto eficiente y relevante sin sobrepasar los límites de tokens. El sistema puede mantener una memoria virtualmente ilimitada mientras solo extrae la información más pertinente para cada interacción. Esto es particularmente valioso en aplicaciones que requieren contexto histórico profundo, como relaciones a largo plazo con clientes, plataformas educativas o sistemas complejos de gestión de proyectos.

Herramientas Esenciales para la Implementación:

  • openai.Embedding - La API de embedding de OpenAI que convierte texto en vectores numéricos, capturando significado semántico y relaciones entre diferentes piezas de texto. Esto es fundamental para crear representaciones vectoriales consultables de tu historial de conversación.
  • FAISS - La potente biblioteca de búsqueda de similitud de Facebook AI, optimizada para buscar rápidamente a través de millones de vectores de alta dimensionalidad. O Pinecone - Un servicio administrado de base de datos vectorial que maneja almacenamiento vectorial y búsqueda de similitud con escalado automático y actualizaciones en tiempo real.
  • Marcos de búsqueda vectorial:
    • chromadb - Una base de datos de embedding de código abierto que facilita el almacenamiento y consulta de tus embeddings vectoriales con metadatos adicionales
    • Weaviate - Un motor de búsqueda vectorial que combina almacenamiento vectorial con consultas basadas en GraphQL y capacidades de clasificación automática

Como discutimos en el Capítulo 6, sección 6.4 sobre RAG (Generación Aumentada por Recuperación), el principio clave sigue siendo sencillo: almacena más, inyecta menos. Esto significa mantener una base de conocimiento externa completa mientras se recupera selectivamente solo la información más relevante para cada interacción, en lugar de intentar meter todo en la ventana de contexto inmediata.

class ConversationManager:
    def __init__(self, openai_api_key):
        self.api_key = openai_api_key
        self.summary = ""
        self.messages = []
        self.summary_interval = 5  # Summarize every 5 messages
        self.message_count = 0
        
    def add_message(self, role, content):
        """Add a new message to the conversation."""
        self.messages.append({"role": role, "content": content})
        self.message_count += 1
        
        # Check if it's time to create a summary
        if self.message_count % self.summary_interval == 0:
            self.update_summary()
    
    def update_summary(self):
        """Create a summary of recent conversation."""
        try:
            # Create prompt for summarization
            summary_prompt = {
                "role": "system",
                "content": "Please create a brief summary of the following conversation. "
                          "Focus on key points and decisions made."
            }
            
            # Get last few messages to summarize
            recent_messages = self.messages[-self.summary_interval:]
            
            # Request summary from OpenAI
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    summary_prompt,
                    *recent_messages,
                    {"role": "user", "content": "Please summarize our discussion."}
                ],
                temperature=0.7
            )
            
            # Update the running summary
            new_summary = response.choices[0].message.content
            if self.summary:
                self.summary = f"{self.summary}\n\nUpdate: {new_summary}"
            else:
                self.summary = new_summary
                
            # Trim old messages but keep the summary
            self.messages = [
                {"role": "system", "content": f"Previous context: {self.summary}"},
                *recent_messages
            ]
            
        except Exception as e:
            print(f"Error updating summary: {str(e)}")
    
    def get_current_context(self):
        """Get current conversation context including summary."""
        if self.summary:
            return [
                {"role": "system", "content": f"Previous context: {self.summary}"},
                *self.messages
            ]
        return self.messages

# Example usage
conversation = ConversationManager("your-api-key")

# Add some messages
conversation.add_message("user", "Can you help me learn Python?")
conversation.add_message("assistant", "Of course! What specific topics interest you?")
conversation.add_message("user", "I'd like to learn about functions.")
conversation.add_message("assistant", "Let's start with the basics of functions...")
conversation.add_message("user", "Can you show me an example?")

Desglose del Código:

  • Estructura de la Clase
    • ConversationManager maneja todos los aspectos de la gestión y resumen de conversaciones
    • Mantiene tanto los mensajes actuales como el resumen continuo
    • Intervalo de resumen configurable (por defecto: cada 5 mensajes)
  • Componentes Principales
    • add_message(): Rastrea nuevos mensajes y activa actualizaciones de resumen
    • update_summary(): Crea resúmenes usando la API de OpenAI
    • get_current_context(): Combina el resumen con mensajes recientes
  • Gestión de Resúmenes
    • Se activa automáticamente después de un número específico de mensajes
    • Preserva el contexto combinando resúmenes antiguos con nueva información
    • Maneja errores con elegancia para prevenir pérdida de datos
  • Optimización de Memoria
    • Mantiene un resumen continuo de conversaciones anteriores
    • Conserva mensajes recientes para contexto inmediato
    • Gestiona eficientemente el uso de tokens mediante el resumen de contenido antiguo

Beneficios de esta Implementación:

  • Mantiene la coherencia de la conversación mientras gestiona la ventana de contexto
  • Maneja automáticamente la generación de resúmenes en intervalos regulares
  • Proporciona fácil acceso tanto al contexto actual como al resumen histórico
  • Escala bien para conversaciones de larga duración

7.4.5 Estrategia 4: Usar "Resúmenes Continuos" para Memoria Episódica

A medida que la sesión avanza, resume dinámicamente cada sección de la conversación y mantén un resumen evolutivo que se actualiza cada pocos turnos. Este poderoso enfoque funciona monitoreando y analizando continuamente la conversación en curso en segmentos discretos. El sistema identifica automáticamente las pausas naturales en la discusión, puntos clave de decisión y transiciones de temas, creando un documento vivo que refleja la evolución de la conversación.

Así es como funciona en la práctica:

  1. Cada pocos mensajes (típicamente 3-5 turnos), el sistema analiza la conversación reciente
  2. Extrae información esencial, decisiones y conclusiones
  3. Estas se condensan en un resumen conciso pero informativo
  4. El resumen se fusiona entonces con resúmenes previos, manteniendo el flujo cronológico

Por ejemplo, después de varios mensajes sobre funciones de Python, el resumen podría comenzar con "Se discutieron definiciones de funciones, parámetros y valores de retorno" mientras mantiene ejemplos específicos de código disponibles en el contexto a corto plazo. A medida que la conversación avanza hacia el manejo de errores, el resumen se expandiría para incluir "Se exploraron bloques try/except y sus ventajas sobre las declaraciones condicionales."

Puedes mantener esta "memoria episódica" junto con tu búfer a corto plazo, creando un sistema de memoria de dos niveles que refleja la cognición humana. El búfer a corto plazo contiene mensajes recientes con detalle completo, mientras que la memoria episódica mantiene versiones resumidas de conversaciones anteriores. Este enfoque de memoria dual sirve para múltiples propósitos:

  1. Mantiene la coherencia de la conversación conservando tanto el contexto reciente detallado como el contexto histórico más amplio
  2. Previene el desbordamiento de contexto condensando información antigua en resúmenes compactos
  3. Permite referencias rápidas a temas anteriores sin cargar el historial completo de conversación
  4. Crea un flujo natural de conversación permitiendo que la IA haga referencia tanto al contexto reciente como al histórico

Este sistema funciona de manera similar a la memoria humana, donde mantenemos recuerdos vívidos recientes mientras los recuerdos más antiguos se vuelven más condensados y resumidos con el tiempo. Este enfoque natural para la gestión de memoria ayuda a crear conversaciones más atractivas y contextualmente conscientes mientras gestiona eficientemente los recursos computacionales.

Ejemplo:

# Comprehensive conversation manager with OpenAI integration
import openai
from typing import List, Dict
import time

class ConversationManager:
    def __init__(self, api_key: str):
        self.api_key = api_key
        openai.api_key = api_key
        self.session_summary = ""
        self.messages: List[Dict[str, str]] = []
        self.last_summary_time = time.time()
        self.summary_interval = 300  # 5 minutes

    def add_message(self, role: str, content: str) -> None:
        """Add a new message and update summary if needed."""
        self.messages.append({"role": role, "content": content})
        
        # Check if it's time to update summary
        if time.time() - self.last_summary_time > self.summary_interval:
            self.update_summary()

    def update_summary(self) -> None:
        """Update conversation summary using OpenAI."""
        try:
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    {"role": "system", "content": "Create a brief summary of this conversation."},
                    *self.messages[-5:]  # Last 5 messages for context
                ],
                temperature=0.7,
                max_tokens=150
            )
            
            new_summary = response.choices[0].message.content
            self.session_summary = f"{self.session_summary}\n{new_summary}" if self.session_summary else new_summary
            self.last_summary_time = time.time()
            
        except Exception as e:
            print(f"Error updating summary: {str(e)}")

    def get_context(self) -> List[Dict[str, str]]:
        """Get current conversation context with summary."""
        return [
            {"role": "system", "content": f"Previous context: {self.session_summary}"},
            *self.messages[-5:]  # Keep last 5 messages
        ]

    async def get_response(self, user_message: str) -> str:
        """Get AI response using current context."""
        self.add_message("user", user_message)
        
        try:
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=self.get_context(),
                temperature=0.7,
                max_tokens=500
            )
            
            ai_response = response.choices[0].message.content
            self.add_message("assistant", ai_response)
            return ai_response
            
        except Exception as e:
            print(f"Error getting response: {str(e)}")
            return "I apologize, but I encountered an error processing your request."

# Example usage
api_key = "your-openai-api-key"
conversation = ConversationManager(api_key)

# Simulate a conversation
conversation.add_message("user", "I want to learn about Python error handling.")
conversation.add_message("assistant", "Let's start with try/except blocks.")
conversation.add_message("user", "What's the difference between try/except and if/else?")

# Get response with context
response = await conversation.get_response("Can you show me an example?")

Desglose del Código:

  • Componentes Principales:
    • La clase ConversationManager maneja todo el estado de la conversación y las interacciones con OpenAI
    • Generación automática de resúmenes cada 5 minutos
    • Mantiene tanto los mensajes recientes como el resumen histórico
    • Sugerencias de tipo y manejo de errores para mayor robustez
  • Métodos Principales:
    • add_message(): Rastrea el historial de conversaciones
    • update_summary(): Utiliza GPT-4 para crear resúmenes de conversaciones
    • get_context(): Combina el resumen con mensajes recientes
    • get_response(): Maneja la interacción con la API para las respuestas
  • Características:
    • Actualizaciones de resumen basadas en tiempo en lugar de cantidad de mensajes
    • Manejo adecuado de errores y registro
    • Gestión eficiente del contexto con ventana móvil
    • Soporte asíncrono para mejor rendimiento

Luego actualiza session_summary cada 5 turnos utilizando la estrategia de resumen anterior.

7.4.6 Estrategia 5: Prompts Modulares en Lugar de Hilos Largos

Para muchas aplicaciones, mantener un historial extenso de mensajes no siempre es necesario ni eficiente. De hecho, mantener historiales largos de conversación puede llevar a mayores costos de API, tiempos de respuesta más lentos y potencialmente resultados inconsistentes. En su lugar, un enfoque más eficiente es generar plantillas reutilizables con instrucciones completas incorporadas desde el principio. Esta estrategia reduce el uso de tokens y mejora la consistencia de las respuestas al cargar el contexto esencial por adelantado.

Las plantillas pueden incluir roles específicos, capacidades y restricciones que de otro modo necesitarían ser comunicados repetidamente. Estas plantillas actúan como base para el comportamiento y comprensión de la IA, eliminando la necesidad de transportar contexto a través de múltiples intercambios. Cuando están bien diseñadas, pueden proporcionar a la IA pautas claras sobre su rol, nivel de experiencia, estilo de comunicación y conocimiento específico del dominio.

Ejemplo: Construcción de un asistente experto en codificación de IA

# Template for an AI expert coding assistant
system_message = {
    "role": "system",
    "content": """You are a Python expert with the following capabilities:
    - Generate clean, efficient, and well-commented code
    - Provide detailed explanations of code functionality
    - Follow best practices and PEP 8 standards
    - Assume common data science libraries (pandas, numpy) are installed
    - Optimize code for readability and performance

    When responding:
    1. Always include docstrings and comments
    2. Explain complex logic
    3. Handle edge cases and errors
    4. Provide example usage where appropriate"""
}

# Example implementation using OpenAI API
import openai
from typing import Dict, Any

class PythonExpertAssistant:
    def __init__(self, api_key: str):
        """Initialize the Python expert assistant with API key."""
        self.api_key = api_key
        openai.api_key = api_key
        self.system_message = system_message

    async def get_code_solution(self, prompt: str) -> Dict[str, Any]:
        """
        Generate a code solution based on user prompt.
        
        Args:
            prompt (str): User's coding question or request
            
        Returns:
            Dict containing response and metadata
        """
        try:
            response = await openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    self.system_message,
                    {"role": "user", "content": prompt}
                ],
                temperature=0.7,
                max_tokens=1000,
                presence_penalty=0.6
            )
            
            return {
                "code": response.choices[0].message.content,
                "tokens_used": response.usage.total_tokens,
                "status": "success"
            }
            
        except Exception as e:
            return {
                "error": str(e),
                "status": "error"
            }

# Example usage
assistant = PythonExpertAssistant("your-api-key")
response = await assistant.get_code_solution(
    "Create a function to calculate Fibonacci sequence"
)

Desglose del Código:

  • Estructura del Mensaje del Sistema
    • Define el rol y las capacidades claramente
    • Establece expectativas para la calidad y el estilo del código
    • Establece un formato de respuesta consistente
  • Implementación de la Clase
    • Sugerencias de tipo para mejor mantenibilidad del código
    • Soporte asíncrono para mejor rendimiento
    • Manejo apropiado de errores y formato de respuesta
  • Integración de API
    • Temperatura configurable para la creatividad de las respuestas
    • Gestión de tokens
    • Penalización de presencia para fomentar respuestas diversas

Esto elimina la necesidad de transportar este contexto en cada mensaje.

7.4.7 Resumen: Consejos Prácticos

La ventana de contexto, en lugar de verse como una limitación, debe considerarse como una oportunidad creativa que nos impulsa a desarrollar soluciones más sofisticadas. Con decisiones arquitectónicas reflexivas, podemos crear sistemas que gestionen eficazmente conversaciones a largo plazo mientras permanecemos dentro de las restricciones de tokens. Así es como contribuye cada componente clave:

La Sumarización nos permite condensar historiales de conversación extensos en representaciones compactas y significativas. Esto preserva la información esencial mientras reduce significativamente el uso de tokens. Por ejemplo, una conversación de 1000 tokens podría destilarse en un resumen de 100 tokens capturando los puntos clave.

Los sistemas de Recuperación permiten un acceso inteligente a los datos históricos de conversación. Mediante el uso de incrustaciones vectoriales o búsqueda semántica, podemos extraer el contexto pasado relevante exactamente cuando se necesita, en lugar de transportar todo el historial de conversación. Esto crea un flujo más natural donde los temas anteriores pueden recordarse contextualmente.

Las estrategias de Recorte ayudan a mantener un rendimiento óptimo eliminando selectivamente las partes menos relevantes de la conversación mientras se mantiene el contexto crucial. Esto puede implicar eliminar mensajes más antiguos después de la sumarización o podar información redundante para permanecer dentro de los límites de tokens.

La inyección de memoria dinámica nos permite insertar estratégicamente contexto relevante cuando se necesita. Esto podría incluir preferencias del usuario, interacciones previas o conocimiento específico del dominio, haciendo las conversaciones más personalizadas y contextualmente conscientes sin repetición constante.

Cuando estas técnicas se combinan efectivamente, el resultado es un sistema de IA que puede mantener conversaciones extensas y naturales mientras gestiona eficientemente los recursos computacionales. Esto crea aplicaciones que se sienten notablemente humanas en su capacidad para mantener el contexto y hacer referencia a interacciones previas, incluso cuando las conversaciones se extienden por largos períodos o múltiples sesiones.

7.4 Soluciones para los Límites de Contexto

Por muy potentes que sean los modelos de OpenAI como GPT-4o, aún operan dentro de una ventana de contexto—un límite estricto sobre cuántos tokens puede "recordar" el modelo en una sola interacción. Piensa en esta ventana de contexto como un búfer de conversación: es la cantidad máxima de diálogo de ida y vuelta que la IA puede considerar a la vez. Para GPT-4o, esto puede ser hasta 128K tokens, lo cual es masivo—pero no infinito. Para ponerlo en perspectiva, 128K tokens es aproximadamente equivalente a un libro de 100 páginas, permitiendo conversaciones extensas pero aún requiriendo una gestión cuidadosa.

Cuando tu aplicación alcanza ese límite, el modelo comienza a "olvidar" las partes anteriores de la conversación, de manera similar a cómo una persona podría olvidar el principio de una conversación muy larga. Este "olvido" ocurre automáticamente a menos que gestiones explícitamente el contexto mediante técnicas como resumen, recorte selectivo o soluciones ingeniosas.

El modelo siempre priorizará el contenido más reciente, eliminando los mensajes más antiguos desde el principio de la conversación cuando se agregan nuevos. Este comportamiento hace crucial implementar estrategias adecuadas de gestión de contexto. En esta sección, exploraremos soluciones efectivas que te ayudan a mantener interacciones largas y significativas fluyendo — incluso más allá del presupuesto de tokens del modelo. Estas estrategias aseguran que tu IA mantenga conversaciones coherentes y contextualmente conscientes mientras gestiona eficientemente sus limitaciones de memoria.

7.4.1 El Desafío de la Ventana de Contexto

Un token es el componente fundamental en cómo los modelos de lenguaje procesan y entienden texto. Piensa en los tokens como las piezas individuales de un rompecabezas que forman el texto completo. Estos tokens pueden variar significativamente en tamaño y complejidad:

  1. Caracteres Individuales: Los tokens más pequeños pueden ser solo un carácter, como:
    • Letras individuales ("a", "b", "c")
    • Signos de puntuación (".", ",", "!")
    • Caracteres especiales ("@", "#", "$")
  2. Fragmentos de Palabras: Muchos tokens son en realidad partes de palabras:
    • Prefijos comunes ("pre-", "des-", "re-")
    • Sufijos comunes ("-ando", "-ado", "-ción")
    • Raíces y bases que forman palabras más grandes
  3. Palabras Completas: Algunos tokens representan palabras enteras, particularmente:
    • Palabras comunes en español ("el", "y", "pero")
    • Sustantivos simples ("gato", "casa", "árbol")
    • Verbos básicos ("correr", "saltar", "dormir")

Por ejemplo:

  • "ChatGPT es asombroso." → aproximadamente 5 tokens, donde "Chat" y "GPT" a menudo se procesan como tokens separados, mientras que palabras comunes como "es" son típicamente tokens individuales. Este ejemplo muestra cómo incluso una oración simple puede desglosarse en múltiples tokens distintos.
  • "Érase una vez en un reino lejano..." → podría ser 10-12 tokens, ya que frases comunes como "érase una" a menudo se dividen en tokens individuales, y los signos de puntuación como "..." pueden contarse como tokens separados. Esto demuestra cómo las frases más largas se dividen en sus partes constituyentes.

Entender el conteo de tokens es absolutamente crucial para desarrolladores y usuarios porque impacta directamente en cómo los modelos de IA procesan y responden al texto. Tu conversación incluye varios componentes clave:

  • Prompts del sistema: Las instrucciones que definen cómo debe comportarse la IA
    Consultas del usuario: Las preguntas y entradas que proporcionas
    Respuestas del asistente: Las respuestas generadas por el modelo de IA

A medida que estos componentes se acumulan, el conteo de tokens de tu conversación crece rápidamente, como llenar un contenedor con agua. Cada nuevo mensaje, ya sea una pregunta, respuesta o instrucción, añade más tokens a este total.

Cuando tu conversación se acerca al límite de tokens del modelo, ocurre un proceso importante: el sistema comienza a eliminar mensajes antiguos automáticamente desde el principio de la conversación. Esto es similar a cómo un contenedor lleno podría desbordarse - el contenido más antiguo se desecha para hacer espacio para nueva información. Este proceso de truncamiento automático puede tener consecuencias significativas:

  1. Pérdida de Contexto: Los detalles importantes anteriores podrían olvidarse
  2. Respuestas Desconectadas: La IA podría no hacer referencia a información previa importante
  3. Confusión: Tanto el modelo como el usuario podrían perder el hilo de la conversación
  4. Continuidad Rota: El flujo natural del diálogo puede verse interrumpido

Esta limitación hace esencial gestionar el uso de tokens de tu conversación cuidadosa y estratégicamente para mantener interacciones coherentes y contextuales.

7.4.2 Estrategia 1: Resumir Diálogos Anteriores

Una de las soluciones más fiables es resumir los mensajes antiguos y mantener solo la información clave. Esta poderosa técnica implica analizar cuidadosamente los turnos previos de conversación y condensarlos en resúmenes concisos que capturan los puntos esenciales, decisiones y contexto. El proceso funciona identificando los elementos más importantes de cada segmento de conversación y creando una versión condensada que retiene la información crucial mientras elimina detalles redundantes o menos relevantes.

Por ejemplo, varios mensajes que discuten requisitos de proyecto podrían comprimirse en un único resumen que indique "El usuario necesita una herramienta de procesamiento de datos basada en Python con capacidad de exportación CSV". Esta compresión podría representar múltiples mensajes que incluían discusiones técnicas, solicitudes de funcionalidades y detalles de implementación, todo destilado en una única declaración clara y procesable.

Este enfoque preserva el contexto mientras reduce dramáticamente el uso de tokens, frecuentemente comprimiendo docenas de mensajes en un único resumen rico en información que mantiene la coherencia conversacional mientras libera valioso espacio en la ventana de contexto para nuevas interacciones. El proceso de resumen puede implementarse ya sea automáticamente usando herramientas impulsadas por IA o manualmente a través de una revisión humana cuidadosa. La clave es mantener el significado esencial y el contexto mientras se reduce significativamente el conteo de tokens, permitiendo conversaciones más largas y significativas sin alcanzar los límites de contexto. Esto es particularmente valioso en escenarios donde el contexto histórico es crucial, como discusiones técnicas complejas, gestión continua de proyectos o interacciones detalladas de soporte al cliente.

Ejemplo: Auto-Resumen con OpenAI

def summarize_messages(messages, max_summary_length=120, temperature=0.3):
    """
    Summarize a list of conversation messages using OpenAI's API.
    
    Args:
        messages (list): List of message dictionaries with 'role' and 'content' keys
        max_summary_length (int): Maximum tokens for the summary (default: 120)
        temperature (float): Creativity of the response (0.0-1.0, default: 0.3)
    
    Returns:
        dict: A system message containing the conversation summary
    """
    # Format messages into a readable string
    formatted_messages = []
    for msg in messages:
        # Skip system messages in the summary
        if msg["role"] == "system":
            continue
        # Format each message with role and content
        formatted_messages.append(f'{msg["role"].capitalize()}: {msg["content"]}')
    
    # Create the summarization prompt
    prompt = [
        {
            "role": "system",
            "content": """You summarize conversations clearly and concisely.
                         Focus on key points, decisions, and important context.
                         Use bullet points if multiple topics are discussed."""
        },
        {
            "role": "user",
            "content": "Please summarize the following dialogue:\n\n" + 
                      "\n".join(formatted_messages)
        }
    ]
    
    try:
        # Call OpenAI API for summarization
        response = openai.ChatCompletion.create(
            model="gpt-4o",
            messages=prompt,
            max_tokens=max_summary_length,
            temperature=temperature
        )
        
        summary = response["choices"][0]["message"]["content"]
        
        # Return formatted system message with summary
        return {
            "role": "system",
            "content": f"Summary of earlier conversation: {summary}"
        }
        
    except Exception as e:
        # Handle potential API errors
        print(f"Error during summarization: {str(e)}")
        return {
            "role": "system",
            "content": "Error: Could not generate conversation summary."
        }

Desglose del Código:

  • Definición de Función y Documentación
    • Agregada documentación completa explicando propósito y parámetros
    • Agregados parámetros configurables para longitud del resumen y temperatura
  • Formateo de Mensajes
    • Filtra los mensajes del sistema para centrarse en el diálogo usuario-asistente
    • Capitaliza los roles para mejor legibilidad
    • Crea una cadena de conversación limpia y formateada
  • Ingeniería de Prompts Mejorada
    • Instrucciones del sistema expandidas para mejores resúmenes
    • Sugiere formato de viñetas para discusiones de múltiples temas
  • Manejo de Errores
    • Agregado bloque try-except para manejar fallos de API elegantemente
    • Devuelve mensaje de error informativo si falla el resumen
  • Mejores Prácticas
    • Utiliza indicaciones de tipo y nombres de variables claros
    • Sigue las pautas de estilo PEP 8
    • Implementa estructura de código modular y mantenible

Puedes llamar a esto cada vez que tu conversación alcance cierta longitud (por ejemplo, 80% del límite de contexto), luego reemplazar los mensajes anteriores con este resumen antes de continuar.

7.4.3 Estrategia 2: Eliminar Mensajes Irrelevantes

En lugar de incluir todo el historial de conversación en cada interacción, es crucial ser selectivo sobre qué contexto mantener. Este enfoque estratégico ayuda a optimizar el uso de tokens y mantener el contexto relevante mientras se asegura que la IA pueda proporcionar respuestas significativas. Al seleccionar cuidadosamente qué información conservar, puedes mejorar significativamente la eficiencia de tus conversaciones mientras mantienes su calidad. Aquí hay un desglose detallado de lo que deberías priorizar mantener:

  • El prompt del sistema: Este contiene las instrucciones fundamentales y configuraciones de personalidad que guían el comportamiento de la IA. Sin él, la IA podría perder su rol o propósito previsto. El prompt del sistema típicamente incluye información crítica como:
    • Pautas de comportamiento y tono de voz
    • Capacidades o limitaciones específicas
    • Requisitos de conocimiento específico del dominio
  • Los últimos intercambios usuario-asistente: Las interacciones recientes suelen contener el contexto más relevante para la conversación actual. Usualmente, los últimos 3-5 intercambios son suficientes para mantener la coherencia. Esto es importante porque:
    • El contexto reciente es más relevante para las preguntas actuales
    • Mantiene el flujo natural de la conversación
    • Ayuda a prevenir repeticiones o contradicciones
  • Cualquier instrucción o hecho fundamental: Mantén cualquier información crítica que se estableció anteriormente en la conversación, como preferencias del usuario, requisitos específicos o contexto importante que influye en toda la interacción. Esto incluye:
    • Preferencias o restricciones especificadas por el usuario
    • Decisiones importantes o acuerdos alcanzados durante la conversación
    • Detalles técnicos clave o especificaciones que afectan toda la discusión

Fragmento de Código: Lógica de Recorte

def trim_messages(messages, max_messages=6, model="gpt-4"):
    """
    Trim conversation history while preserving system prompts and recent messages.
    
    Args:
        messages (list): List of message dictionaries with 'role' and 'content'
        max_messages (int): Maximum number of non-system messages to keep
        model (str): OpenAI model to use for potential follow-up
        
    Returns:
        list: Trimmed message history
    """
    try:
        # Separate system prompts and conversation
        system_prompt = [m for m in messages if m["role"] == "system"]
        conversation = [m for m in messages if m["role"] != "system"]
        
        # Calculate tokens (approximate)
        def estimate_tokens(text):
            return len(text.split()) * 1.3  # Rough estimate
            
        # Get recent messages while staying under limit
        trimmed_conversation = conversation[-max_messages:]
        
        # Add a system note about trimming if needed
        if len(conversation) > max_messages:
            system_prompt.append({
                "role": "system",
                "content": f"Note: {len(conversation) - max_messages} earlier messages were trimmed for context management."
            })
        
        # Combine and validate against OpenAI's limits
        final_messages = system_prompt + trimmed_conversation
        
        # Optional: Verify token count with OpenAI
        total_tokens = sum(estimate_tokens(m["content"]) for m in final_messages)
        if total_tokens > 8000:  # Conservative limit for GPT-4
            raise ValueError(f"Combined messages exceed token limit: {total_tokens}")
            
        return final_messages
        
    except Exception as e:
        print(f"Error trimming messages: {str(e)}")
        # Return last few messages as fallback
        return system_prompt + conversation[-3:]

# Example usage:
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello!"},
    {"role": "assistant", "content": "Hi there!"},
    # ... many messages later ...
]

trimmed = trim_messages(messages)

# Use with OpenAI API
response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=trimmed,
    temperature=0.7
)

Analicemos este código que gestiona el historial de conversación y los límites de tokens:

Propósito Principal de la Función:

La función trim_messages gestiona eficientemente el historial de conversación preservando los prompts del sistema mientras limita los mensajes regulares.

Componentes Clave:

  • Parámetros
    • messages: Lista de diccionarios de mensajes
    • max_messages: Máximo de mensajes no sistémicos a mantener (predeterminado 6)
    • model: Especifica el modelo de OpenAI
  • Separación de Mensajes
    • Separa los prompts del sistema de la conversación regular
    • Preserva todos los mensajes del sistema mientras recorta los mensajes regulares
  • Gestión de Tokens
    • Implementa una estimación simple de tokens (1.3 tokens por palabra)
    • Impone un límite de 8000 tokens para GPT-4
    • Genera un error si se excede el límite
  • Seguimiento del Historial
    • Mantiene un registro de los mensajes recortados
    • Añade una nota del sistema sobre cuántos mensajes fueron eliminados
    • Mantiene los mensajes más recientes dentro del límite especificado

Manejo de Errores:

Si ocurre un error, la función recurre a devolver los prompts del sistema más los últimos tres mensajes de la conversación.

Ejemplo de Uso:

El ejemplo muestra cómo usar esto con la API de OpenAI, manteniendo un historial de conversación limpio mientras se previene el desbordamiento de tokens.

Esta implementación asegura que la información más reciente y relevante permanezca en contexto mientras minimiza la sobrecarga de tokens.

7.4.4 Estrategia 3: Descarga a Memoria Externa (Recuperación Híbrida)

Si estás simulando memoria a largo plazo, puedes almacenar todas las interacciones externamente y recuperar solo las relevantes en tiempo de ejecución. Este poderoso enfoque utiliza una base de datos externa o sistema de almacenamiento para mantener un historial completo de todas las conversaciones, mensajes e información. En lugar de sobrecargar el contexto inmediato con datos excesivos, este método permite la recuperación inteligente y selectiva de información histórica cuando sea necesario. Por ejemplo, en un contexto de servicio al cliente, el sistema podría acceder instantáneamente a interacciones previas con el mismo cliente sobre problemas similares, proporcionando respuestas más personalizadas e informadas.

Usando embeddings, puedes transformar conversaciones en representaciones matemáticas que capturan su significado y contexto. Esta sofisticada técnica permite capacidades de búsqueda semántica que van mucho más allá de la simple coincidencia de palabras clave.

Aquí hay un desglose detallado de cómo funciona este sistema:

  • Cada mensaje se transforma en un vector de alta dimensionalidad usando modelos de embedding
    • Estos vectores capturan el significado semántico del texto convirtiendo palabras y frases en representaciones numéricas
    • Los conceptos similares terminan más cerca entre sí en el espacio vectorial, permitiendo un mapeo intuitivo de relaciones
    • El proceso de embedding considera el contexto, sinónimos y conceptos relacionados, no solo coincidencias exactas
  • Cuando llegan nuevas consultas, el sistema puede:
    • Convertir la nueva consulta en un vector usando el mismo modelo de embedding
    • Encontrar los vectores almacenados más similares usando algoritmos eficientes de búsqueda de similitud
    • Recuperar solo aquellas piezas relevantes de contexto, priorizando la información más semánticamente relacionada
    • Ajustar dinámicamente la cantidad de contexto basado en puntajes de relevancia

Este sofisticado enfoque permite una recuperación de contexto eficiente y relevante sin sobrepasar los límites de tokens. El sistema puede mantener una memoria virtualmente ilimitada mientras solo extrae la información más pertinente para cada interacción. Esto es particularmente valioso en aplicaciones que requieren contexto histórico profundo, como relaciones a largo plazo con clientes, plataformas educativas o sistemas complejos de gestión de proyectos.

Herramientas Esenciales para la Implementación:

  • openai.Embedding - La API de embedding de OpenAI que convierte texto en vectores numéricos, capturando significado semántico y relaciones entre diferentes piezas de texto. Esto es fundamental para crear representaciones vectoriales consultables de tu historial de conversación.
  • FAISS - La potente biblioteca de búsqueda de similitud de Facebook AI, optimizada para buscar rápidamente a través de millones de vectores de alta dimensionalidad. O Pinecone - Un servicio administrado de base de datos vectorial que maneja almacenamiento vectorial y búsqueda de similitud con escalado automático y actualizaciones en tiempo real.
  • Marcos de búsqueda vectorial:
    • chromadb - Una base de datos de embedding de código abierto que facilita el almacenamiento y consulta de tus embeddings vectoriales con metadatos adicionales
    • Weaviate - Un motor de búsqueda vectorial que combina almacenamiento vectorial con consultas basadas en GraphQL y capacidades de clasificación automática

Como discutimos en el Capítulo 6, sección 6.4 sobre RAG (Generación Aumentada por Recuperación), el principio clave sigue siendo sencillo: almacena más, inyecta menos. Esto significa mantener una base de conocimiento externa completa mientras se recupera selectivamente solo la información más relevante para cada interacción, en lugar de intentar meter todo en la ventana de contexto inmediata.

class ConversationManager:
    def __init__(self, openai_api_key):
        self.api_key = openai_api_key
        self.summary = ""
        self.messages = []
        self.summary_interval = 5  # Summarize every 5 messages
        self.message_count = 0
        
    def add_message(self, role, content):
        """Add a new message to the conversation."""
        self.messages.append({"role": role, "content": content})
        self.message_count += 1
        
        # Check if it's time to create a summary
        if self.message_count % self.summary_interval == 0:
            self.update_summary()
    
    def update_summary(self):
        """Create a summary of recent conversation."""
        try:
            # Create prompt for summarization
            summary_prompt = {
                "role": "system",
                "content": "Please create a brief summary of the following conversation. "
                          "Focus on key points and decisions made."
            }
            
            # Get last few messages to summarize
            recent_messages = self.messages[-self.summary_interval:]
            
            # Request summary from OpenAI
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    summary_prompt,
                    *recent_messages,
                    {"role": "user", "content": "Please summarize our discussion."}
                ],
                temperature=0.7
            )
            
            # Update the running summary
            new_summary = response.choices[0].message.content
            if self.summary:
                self.summary = f"{self.summary}\n\nUpdate: {new_summary}"
            else:
                self.summary = new_summary
                
            # Trim old messages but keep the summary
            self.messages = [
                {"role": "system", "content": f"Previous context: {self.summary}"},
                *recent_messages
            ]
            
        except Exception as e:
            print(f"Error updating summary: {str(e)}")
    
    def get_current_context(self):
        """Get current conversation context including summary."""
        if self.summary:
            return [
                {"role": "system", "content": f"Previous context: {self.summary}"},
                *self.messages
            ]
        return self.messages

# Example usage
conversation = ConversationManager("your-api-key")

# Add some messages
conversation.add_message("user", "Can you help me learn Python?")
conversation.add_message("assistant", "Of course! What specific topics interest you?")
conversation.add_message("user", "I'd like to learn about functions.")
conversation.add_message("assistant", "Let's start with the basics of functions...")
conversation.add_message("user", "Can you show me an example?")

Desglose del Código:

  • Estructura de la Clase
    • ConversationManager maneja todos los aspectos de la gestión y resumen de conversaciones
    • Mantiene tanto los mensajes actuales como el resumen continuo
    • Intervalo de resumen configurable (por defecto: cada 5 mensajes)
  • Componentes Principales
    • add_message(): Rastrea nuevos mensajes y activa actualizaciones de resumen
    • update_summary(): Crea resúmenes usando la API de OpenAI
    • get_current_context(): Combina el resumen con mensajes recientes
  • Gestión de Resúmenes
    • Se activa automáticamente después de un número específico de mensajes
    • Preserva el contexto combinando resúmenes antiguos con nueva información
    • Maneja errores con elegancia para prevenir pérdida de datos
  • Optimización de Memoria
    • Mantiene un resumen continuo de conversaciones anteriores
    • Conserva mensajes recientes para contexto inmediato
    • Gestiona eficientemente el uso de tokens mediante el resumen de contenido antiguo

Beneficios de esta Implementación:

  • Mantiene la coherencia de la conversación mientras gestiona la ventana de contexto
  • Maneja automáticamente la generación de resúmenes en intervalos regulares
  • Proporciona fácil acceso tanto al contexto actual como al resumen histórico
  • Escala bien para conversaciones de larga duración

7.4.5 Estrategia 4: Usar "Resúmenes Continuos" para Memoria Episódica

A medida que la sesión avanza, resume dinámicamente cada sección de la conversación y mantén un resumen evolutivo que se actualiza cada pocos turnos. Este poderoso enfoque funciona monitoreando y analizando continuamente la conversación en curso en segmentos discretos. El sistema identifica automáticamente las pausas naturales en la discusión, puntos clave de decisión y transiciones de temas, creando un documento vivo que refleja la evolución de la conversación.

Así es como funciona en la práctica:

  1. Cada pocos mensajes (típicamente 3-5 turnos), el sistema analiza la conversación reciente
  2. Extrae información esencial, decisiones y conclusiones
  3. Estas se condensan en un resumen conciso pero informativo
  4. El resumen se fusiona entonces con resúmenes previos, manteniendo el flujo cronológico

Por ejemplo, después de varios mensajes sobre funciones de Python, el resumen podría comenzar con "Se discutieron definiciones de funciones, parámetros y valores de retorno" mientras mantiene ejemplos específicos de código disponibles en el contexto a corto plazo. A medida que la conversación avanza hacia el manejo de errores, el resumen se expandiría para incluir "Se exploraron bloques try/except y sus ventajas sobre las declaraciones condicionales."

Puedes mantener esta "memoria episódica" junto con tu búfer a corto plazo, creando un sistema de memoria de dos niveles que refleja la cognición humana. El búfer a corto plazo contiene mensajes recientes con detalle completo, mientras que la memoria episódica mantiene versiones resumidas de conversaciones anteriores. Este enfoque de memoria dual sirve para múltiples propósitos:

  1. Mantiene la coherencia de la conversación conservando tanto el contexto reciente detallado como el contexto histórico más amplio
  2. Previene el desbordamiento de contexto condensando información antigua en resúmenes compactos
  3. Permite referencias rápidas a temas anteriores sin cargar el historial completo de conversación
  4. Crea un flujo natural de conversación permitiendo que la IA haga referencia tanto al contexto reciente como al histórico

Este sistema funciona de manera similar a la memoria humana, donde mantenemos recuerdos vívidos recientes mientras los recuerdos más antiguos se vuelven más condensados y resumidos con el tiempo. Este enfoque natural para la gestión de memoria ayuda a crear conversaciones más atractivas y contextualmente conscientes mientras gestiona eficientemente los recursos computacionales.

Ejemplo:

# Comprehensive conversation manager with OpenAI integration
import openai
from typing import List, Dict
import time

class ConversationManager:
    def __init__(self, api_key: str):
        self.api_key = api_key
        openai.api_key = api_key
        self.session_summary = ""
        self.messages: List[Dict[str, str]] = []
        self.last_summary_time = time.time()
        self.summary_interval = 300  # 5 minutes

    def add_message(self, role: str, content: str) -> None:
        """Add a new message and update summary if needed."""
        self.messages.append({"role": role, "content": content})
        
        # Check if it's time to update summary
        if time.time() - self.last_summary_time > self.summary_interval:
            self.update_summary()

    def update_summary(self) -> None:
        """Update conversation summary using OpenAI."""
        try:
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    {"role": "system", "content": "Create a brief summary of this conversation."},
                    *self.messages[-5:]  # Last 5 messages for context
                ],
                temperature=0.7,
                max_tokens=150
            )
            
            new_summary = response.choices[0].message.content
            self.session_summary = f"{self.session_summary}\n{new_summary}" if self.session_summary else new_summary
            self.last_summary_time = time.time()
            
        except Exception as e:
            print(f"Error updating summary: {str(e)}")

    def get_context(self) -> List[Dict[str, str]]:
        """Get current conversation context with summary."""
        return [
            {"role": "system", "content": f"Previous context: {self.session_summary}"},
            *self.messages[-5:]  # Keep last 5 messages
        ]

    async def get_response(self, user_message: str) -> str:
        """Get AI response using current context."""
        self.add_message("user", user_message)
        
        try:
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=self.get_context(),
                temperature=0.7,
                max_tokens=500
            )
            
            ai_response = response.choices[0].message.content
            self.add_message("assistant", ai_response)
            return ai_response
            
        except Exception as e:
            print(f"Error getting response: {str(e)}")
            return "I apologize, but I encountered an error processing your request."

# Example usage
api_key = "your-openai-api-key"
conversation = ConversationManager(api_key)

# Simulate a conversation
conversation.add_message("user", "I want to learn about Python error handling.")
conversation.add_message("assistant", "Let's start with try/except blocks.")
conversation.add_message("user", "What's the difference between try/except and if/else?")

# Get response with context
response = await conversation.get_response("Can you show me an example?")

Desglose del Código:

  • Componentes Principales:
    • La clase ConversationManager maneja todo el estado de la conversación y las interacciones con OpenAI
    • Generación automática de resúmenes cada 5 minutos
    • Mantiene tanto los mensajes recientes como el resumen histórico
    • Sugerencias de tipo y manejo de errores para mayor robustez
  • Métodos Principales:
    • add_message(): Rastrea el historial de conversaciones
    • update_summary(): Utiliza GPT-4 para crear resúmenes de conversaciones
    • get_context(): Combina el resumen con mensajes recientes
    • get_response(): Maneja la interacción con la API para las respuestas
  • Características:
    • Actualizaciones de resumen basadas en tiempo en lugar de cantidad de mensajes
    • Manejo adecuado de errores y registro
    • Gestión eficiente del contexto con ventana móvil
    • Soporte asíncrono para mejor rendimiento

Luego actualiza session_summary cada 5 turnos utilizando la estrategia de resumen anterior.

7.4.6 Estrategia 5: Prompts Modulares en Lugar de Hilos Largos

Para muchas aplicaciones, mantener un historial extenso de mensajes no siempre es necesario ni eficiente. De hecho, mantener historiales largos de conversación puede llevar a mayores costos de API, tiempos de respuesta más lentos y potencialmente resultados inconsistentes. En su lugar, un enfoque más eficiente es generar plantillas reutilizables con instrucciones completas incorporadas desde el principio. Esta estrategia reduce el uso de tokens y mejora la consistencia de las respuestas al cargar el contexto esencial por adelantado.

Las plantillas pueden incluir roles específicos, capacidades y restricciones que de otro modo necesitarían ser comunicados repetidamente. Estas plantillas actúan como base para el comportamiento y comprensión de la IA, eliminando la necesidad de transportar contexto a través de múltiples intercambios. Cuando están bien diseñadas, pueden proporcionar a la IA pautas claras sobre su rol, nivel de experiencia, estilo de comunicación y conocimiento específico del dominio.

Ejemplo: Construcción de un asistente experto en codificación de IA

# Template for an AI expert coding assistant
system_message = {
    "role": "system",
    "content": """You are a Python expert with the following capabilities:
    - Generate clean, efficient, and well-commented code
    - Provide detailed explanations of code functionality
    - Follow best practices and PEP 8 standards
    - Assume common data science libraries (pandas, numpy) are installed
    - Optimize code for readability and performance

    When responding:
    1. Always include docstrings and comments
    2. Explain complex logic
    3. Handle edge cases and errors
    4. Provide example usage where appropriate"""
}

# Example implementation using OpenAI API
import openai
from typing import Dict, Any

class PythonExpertAssistant:
    def __init__(self, api_key: str):
        """Initialize the Python expert assistant with API key."""
        self.api_key = api_key
        openai.api_key = api_key
        self.system_message = system_message

    async def get_code_solution(self, prompt: str) -> Dict[str, Any]:
        """
        Generate a code solution based on user prompt.
        
        Args:
            prompt (str): User's coding question or request
            
        Returns:
            Dict containing response and metadata
        """
        try:
            response = await openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    self.system_message,
                    {"role": "user", "content": prompt}
                ],
                temperature=0.7,
                max_tokens=1000,
                presence_penalty=0.6
            )
            
            return {
                "code": response.choices[0].message.content,
                "tokens_used": response.usage.total_tokens,
                "status": "success"
            }
            
        except Exception as e:
            return {
                "error": str(e),
                "status": "error"
            }

# Example usage
assistant = PythonExpertAssistant("your-api-key")
response = await assistant.get_code_solution(
    "Create a function to calculate Fibonacci sequence"
)

Desglose del Código:

  • Estructura del Mensaje del Sistema
    • Define el rol y las capacidades claramente
    • Establece expectativas para la calidad y el estilo del código
    • Establece un formato de respuesta consistente
  • Implementación de la Clase
    • Sugerencias de tipo para mejor mantenibilidad del código
    • Soporte asíncrono para mejor rendimiento
    • Manejo apropiado de errores y formato de respuesta
  • Integración de API
    • Temperatura configurable para la creatividad de las respuestas
    • Gestión de tokens
    • Penalización de presencia para fomentar respuestas diversas

Esto elimina la necesidad de transportar este contexto en cada mensaje.

7.4.7 Resumen: Consejos Prácticos

La ventana de contexto, en lugar de verse como una limitación, debe considerarse como una oportunidad creativa que nos impulsa a desarrollar soluciones más sofisticadas. Con decisiones arquitectónicas reflexivas, podemos crear sistemas que gestionen eficazmente conversaciones a largo plazo mientras permanecemos dentro de las restricciones de tokens. Así es como contribuye cada componente clave:

La Sumarización nos permite condensar historiales de conversación extensos en representaciones compactas y significativas. Esto preserva la información esencial mientras reduce significativamente el uso de tokens. Por ejemplo, una conversación de 1000 tokens podría destilarse en un resumen de 100 tokens capturando los puntos clave.

Los sistemas de Recuperación permiten un acceso inteligente a los datos históricos de conversación. Mediante el uso de incrustaciones vectoriales o búsqueda semántica, podemos extraer el contexto pasado relevante exactamente cuando se necesita, en lugar de transportar todo el historial de conversación. Esto crea un flujo más natural donde los temas anteriores pueden recordarse contextualmente.

Las estrategias de Recorte ayudan a mantener un rendimiento óptimo eliminando selectivamente las partes menos relevantes de la conversación mientras se mantiene el contexto crucial. Esto puede implicar eliminar mensajes más antiguos después de la sumarización o podar información redundante para permanecer dentro de los límites de tokens.

La inyección de memoria dinámica nos permite insertar estratégicamente contexto relevante cuando se necesita. Esto podría incluir preferencias del usuario, interacciones previas o conocimiento específico del dominio, haciendo las conversaciones más personalizadas y contextualmente conscientes sin repetición constante.

Cuando estas técnicas se combinan efectivamente, el resultado es un sistema de IA que puede mantener conversaciones extensas y naturales mientras gestiona eficientemente los recursos computacionales. Esto crea aplicaciones que se sienten notablemente humanas en su capacidad para mantener el contexto y hacer referencia a interacciones previas, incluso cuando las conversaciones se extienden por largos períodos o múltiples sesiones.

7.4 Soluciones para los Límites de Contexto

Por muy potentes que sean los modelos de OpenAI como GPT-4o, aún operan dentro de una ventana de contexto—un límite estricto sobre cuántos tokens puede "recordar" el modelo en una sola interacción. Piensa en esta ventana de contexto como un búfer de conversación: es la cantidad máxima de diálogo de ida y vuelta que la IA puede considerar a la vez. Para GPT-4o, esto puede ser hasta 128K tokens, lo cual es masivo—pero no infinito. Para ponerlo en perspectiva, 128K tokens es aproximadamente equivalente a un libro de 100 páginas, permitiendo conversaciones extensas pero aún requiriendo una gestión cuidadosa.

Cuando tu aplicación alcanza ese límite, el modelo comienza a "olvidar" las partes anteriores de la conversación, de manera similar a cómo una persona podría olvidar el principio de una conversación muy larga. Este "olvido" ocurre automáticamente a menos que gestiones explícitamente el contexto mediante técnicas como resumen, recorte selectivo o soluciones ingeniosas.

El modelo siempre priorizará el contenido más reciente, eliminando los mensajes más antiguos desde el principio de la conversación cuando se agregan nuevos. Este comportamiento hace crucial implementar estrategias adecuadas de gestión de contexto. En esta sección, exploraremos soluciones efectivas que te ayudan a mantener interacciones largas y significativas fluyendo — incluso más allá del presupuesto de tokens del modelo. Estas estrategias aseguran que tu IA mantenga conversaciones coherentes y contextualmente conscientes mientras gestiona eficientemente sus limitaciones de memoria.

7.4.1 El Desafío de la Ventana de Contexto

Un token es el componente fundamental en cómo los modelos de lenguaje procesan y entienden texto. Piensa en los tokens como las piezas individuales de un rompecabezas que forman el texto completo. Estos tokens pueden variar significativamente en tamaño y complejidad:

  1. Caracteres Individuales: Los tokens más pequeños pueden ser solo un carácter, como:
    • Letras individuales ("a", "b", "c")
    • Signos de puntuación (".", ",", "!")
    • Caracteres especiales ("@", "#", "$")
  2. Fragmentos de Palabras: Muchos tokens son en realidad partes de palabras:
    • Prefijos comunes ("pre-", "des-", "re-")
    • Sufijos comunes ("-ando", "-ado", "-ción")
    • Raíces y bases que forman palabras más grandes
  3. Palabras Completas: Algunos tokens representan palabras enteras, particularmente:
    • Palabras comunes en español ("el", "y", "pero")
    • Sustantivos simples ("gato", "casa", "árbol")
    • Verbos básicos ("correr", "saltar", "dormir")

Por ejemplo:

  • "ChatGPT es asombroso." → aproximadamente 5 tokens, donde "Chat" y "GPT" a menudo se procesan como tokens separados, mientras que palabras comunes como "es" son típicamente tokens individuales. Este ejemplo muestra cómo incluso una oración simple puede desglosarse en múltiples tokens distintos.
  • "Érase una vez en un reino lejano..." → podría ser 10-12 tokens, ya que frases comunes como "érase una" a menudo se dividen en tokens individuales, y los signos de puntuación como "..." pueden contarse como tokens separados. Esto demuestra cómo las frases más largas se dividen en sus partes constituyentes.

Entender el conteo de tokens es absolutamente crucial para desarrolladores y usuarios porque impacta directamente en cómo los modelos de IA procesan y responden al texto. Tu conversación incluye varios componentes clave:

  • Prompts del sistema: Las instrucciones que definen cómo debe comportarse la IA
    Consultas del usuario: Las preguntas y entradas que proporcionas
    Respuestas del asistente: Las respuestas generadas por el modelo de IA

A medida que estos componentes se acumulan, el conteo de tokens de tu conversación crece rápidamente, como llenar un contenedor con agua. Cada nuevo mensaje, ya sea una pregunta, respuesta o instrucción, añade más tokens a este total.

Cuando tu conversación se acerca al límite de tokens del modelo, ocurre un proceso importante: el sistema comienza a eliminar mensajes antiguos automáticamente desde el principio de la conversación. Esto es similar a cómo un contenedor lleno podría desbordarse - el contenido más antiguo se desecha para hacer espacio para nueva información. Este proceso de truncamiento automático puede tener consecuencias significativas:

  1. Pérdida de Contexto: Los detalles importantes anteriores podrían olvidarse
  2. Respuestas Desconectadas: La IA podría no hacer referencia a información previa importante
  3. Confusión: Tanto el modelo como el usuario podrían perder el hilo de la conversación
  4. Continuidad Rota: El flujo natural del diálogo puede verse interrumpido

Esta limitación hace esencial gestionar el uso de tokens de tu conversación cuidadosa y estratégicamente para mantener interacciones coherentes y contextuales.

7.4.2 Estrategia 1: Resumir Diálogos Anteriores

Una de las soluciones más fiables es resumir los mensajes antiguos y mantener solo la información clave. Esta poderosa técnica implica analizar cuidadosamente los turnos previos de conversación y condensarlos en resúmenes concisos que capturan los puntos esenciales, decisiones y contexto. El proceso funciona identificando los elementos más importantes de cada segmento de conversación y creando una versión condensada que retiene la información crucial mientras elimina detalles redundantes o menos relevantes.

Por ejemplo, varios mensajes que discuten requisitos de proyecto podrían comprimirse en un único resumen que indique "El usuario necesita una herramienta de procesamiento de datos basada en Python con capacidad de exportación CSV". Esta compresión podría representar múltiples mensajes que incluían discusiones técnicas, solicitudes de funcionalidades y detalles de implementación, todo destilado en una única declaración clara y procesable.

Este enfoque preserva el contexto mientras reduce dramáticamente el uso de tokens, frecuentemente comprimiendo docenas de mensajes en un único resumen rico en información que mantiene la coherencia conversacional mientras libera valioso espacio en la ventana de contexto para nuevas interacciones. El proceso de resumen puede implementarse ya sea automáticamente usando herramientas impulsadas por IA o manualmente a través de una revisión humana cuidadosa. La clave es mantener el significado esencial y el contexto mientras se reduce significativamente el conteo de tokens, permitiendo conversaciones más largas y significativas sin alcanzar los límites de contexto. Esto es particularmente valioso en escenarios donde el contexto histórico es crucial, como discusiones técnicas complejas, gestión continua de proyectos o interacciones detalladas de soporte al cliente.

Ejemplo: Auto-Resumen con OpenAI

def summarize_messages(messages, max_summary_length=120, temperature=0.3):
    """
    Summarize a list of conversation messages using OpenAI's API.
    
    Args:
        messages (list): List of message dictionaries with 'role' and 'content' keys
        max_summary_length (int): Maximum tokens for the summary (default: 120)
        temperature (float): Creativity of the response (0.0-1.0, default: 0.3)
    
    Returns:
        dict: A system message containing the conversation summary
    """
    # Format messages into a readable string
    formatted_messages = []
    for msg in messages:
        # Skip system messages in the summary
        if msg["role"] == "system":
            continue
        # Format each message with role and content
        formatted_messages.append(f'{msg["role"].capitalize()}: {msg["content"]}')
    
    # Create the summarization prompt
    prompt = [
        {
            "role": "system",
            "content": """You summarize conversations clearly and concisely.
                         Focus on key points, decisions, and important context.
                         Use bullet points if multiple topics are discussed."""
        },
        {
            "role": "user",
            "content": "Please summarize the following dialogue:\n\n" + 
                      "\n".join(formatted_messages)
        }
    ]
    
    try:
        # Call OpenAI API for summarization
        response = openai.ChatCompletion.create(
            model="gpt-4o",
            messages=prompt,
            max_tokens=max_summary_length,
            temperature=temperature
        )
        
        summary = response["choices"][0]["message"]["content"]
        
        # Return formatted system message with summary
        return {
            "role": "system",
            "content": f"Summary of earlier conversation: {summary}"
        }
        
    except Exception as e:
        # Handle potential API errors
        print(f"Error during summarization: {str(e)}")
        return {
            "role": "system",
            "content": "Error: Could not generate conversation summary."
        }

Desglose del Código:

  • Definición de Función y Documentación
    • Agregada documentación completa explicando propósito y parámetros
    • Agregados parámetros configurables para longitud del resumen y temperatura
  • Formateo de Mensajes
    • Filtra los mensajes del sistema para centrarse en el diálogo usuario-asistente
    • Capitaliza los roles para mejor legibilidad
    • Crea una cadena de conversación limpia y formateada
  • Ingeniería de Prompts Mejorada
    • Instrucciones del sistema expandidas para mejores resúmenes
    • Sugiere formato de viñetas para discusiones de múltiples temas
  • Manejo de Errores
    • Agregado bloque try-except para manejar fallos de API elegantemente
    • Devuelve mensaje de error informativo si falla el resumen
  • Mejores Prácticas
    • Utiliza indicaciones de tipo y nombres de variables claros
    • Sigue las pautas de estilo PEP 8
    • Implementa estructura de código modular y mantenible

Puedes llamar a esto cada vez que tu conversación alcance cierta longitud (por ejemplo, 80% del límite de contexto), luego reemplazar los mensajes anteriores con este resumen antes de continuar.

7.4.3 Estrategia 2: Eliminar Mensajes Irrelevantes

En lugar de incluir todo el historial de conversación en cada interacción, es crucial ser selectivo sobre qué contexto mantener. Este enfoque estratégico ayuda a optimizar el uso de tokens y mantener el contexto relevante mientras se asegura que la IA pueda proporcionar respuestas significativas. Al seleccionar cuidadosamente qué información conservar, puedes mejorar significativamente la eficiencia de tus conversaciones mientras mantienes su calidad. Aquí hay un desglose detallado de lo que deberías priorizar mantener:

  • El prompt del sistema: Este contiene las instrucciones fundamentales y configuraciones de personalidad que guían el comportamiento de la IA. Sin él, la IA podría perder su rol o propósito previsto. El prompt del sistema típicamente incluye información crítica como:
    • Pautas de comportamiento y tono de voz
    • Capacidades o limitaciones específicas
    • Requisitos de conocimiento específico del dominio
  • Los últimos intercambios usuario-asistente: Las interacciones recientes suelen contener el contexto más relevante para la conversación actual. Usualmente, los últimos 3-5 intercambios son suficientes para mantener la coherencia. Esto es importante porque:
    • El contexto reciente es más relevante para las preguntas actuales
    • Mantiene el flujo natural de la conversación
    • Ayuda a prevenir repeticiones o contradicciones
  • Cualquier instrucción o hecho fundamental: Mantén cualquier información crítica que se estableció anteriormente en la conversación, como preferencias del usuario, requisitos específicos o contexto importante que influye en toda la interacción. Esto incluye:
    • Preferencias o restricciones especificadas por el usuario
    • Decisiones importantes o acuerdos alcanzados durante la conversación
    • Detalles técnicos clave o especificaciones que afectan toda la discusión

Fragmento de Código: Lógica de Recorte

def trim_messages(messages, max_messages=6, model="gpt-4"):
    """
    Trim conversation history while preserving system prompts and recent messages.
    
    Args:
        messages (list): List of message dictionaries with 'role' and 'content'
        max_messages (int): Maximum number of non-system messages to keep
        model (str): OpenAI model to use for potential follow-up
        
    Returns:
        list: Trimmed message history
    """
    try:
        # Separate system prompts and conversation
        system_prompt = [m for m in messages if m["role"] == "system"]
        conversation = [m for m in messages if m["role"] != "system"]
        
        # Calculate tokens (approximate)
        def estimate_tokens(text):
            return len(text.split()) * 1.3  # Rough estimate
            
        # Get recent messages while staying under limit
        trimmed_conversation = conversation[-max_messages:]
        
        # Add a system note about trimming if needed
        if len(conversation) > max_messages:
            system_prompt.append({
                "role": "system",
                "content": f"Note: {len(conversation) - max_messages} earlier messages were trimmed for context management."
            })
        
        # Combine and validate against OpenAI's limits
        final_messages = system_prompt + trimmed_conversation
        
        # Optional: Verify token count with OpenAI
        total_tokens = sum(estimate_tokens(m["content"]) for m in final_messages)
        if total_tokens > 8000:  # Conservative limit for GPT-4
            raise ValueError(f"Combined messages exceed token limit: {total_tokens}")
            
        return final_messages
        
    except Exception as e:
        print(f"Error trimming messages: {str(e)}")
        # Return last few messages as fallback
        return system_prompt + conversation[-3:]

# Example usage:
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello!"},
    {"role": "assistant", "content": "Hi there!"},
    # ... many messages later ...
]

trimmed = trim_messages(messages)

# Use with OpenAI API
response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=trimmed,
    temperature=0.7
)

Analicemos este código que gestiona el historial de conversación y los límites de tokens:

Propósito Principal de la Función:

La función trim_messages gestiona eficientemente el historial de conversación preservando los prompts del sistema mientras limita los mensajes regulares.

Componentes Clave:

  • Parámetros
    • messages: Lista de diccionarios de mensajes
    • max_messages: Máximo de mensajes no sistémicos a mantener (predeterminado 6)
    • model: Especifica el modelo de OpenAI
  • Separación de Mensajes
    • Separa los prompts del sistema de la conversación regular
    • Preserva todos los mensajes del sistema mientras recorta los mensajes regulares
  • Gestión de Tokens
    • Implementa una estimación simple de tokens (1.3 tokens por palabra)
    • Impone un límite de 8000 tokens para GPT-4
    • Genera un error si se excede el límite
  • Seguimiento del Historial
    • Mantiene un registro de los mensajes recortados
    • Añade una nota del sistema sobre cuántos mensajes fueron eliminados
    • Mantiene los mensajes más recientes dentro del límite especificado

Manejo de Errores:

Si ocurre un error, la función recurre a devolver los prompts del sistema más los últimos tres mensajes de la conversación.

Ejemplo de Uso:

El ejemplo muestra cómo usar esto con la API de OpenAI, manteniendo un historial de conversación limpio mientras se previene el desbordamiento de tokens.

Esta implementación asegura que la información más reciente y relevante permanezca en contexto mientras minimiza la sobrecarga de tokens.

7.4.4 Estrategia 3: Descarga a Memoria Externa (Recuperación Híbrida)

Si estás simulando memoria a largo plazo, puedes almacenar todas las interacciones externamente y recuperar solo las relevantes en tiempo de ejecución. Este poderoso enfoque utiliza una base de datos externa o sistema de almacenamiento para mantener un historial completo de todas las conversaciones, mensajes e información. En lugar de sobrecargar el contexto inmediato con datos excesivos, este método permite la recuperación inteligente y selectiva de información histórica cuando sea necesario. Por ejemplo, en un contexto de servicio al cliente, el sistema podría acceder instantáneamente a interacciones previas con el mismo cliente sobre problemas similares, proporcionando respuestas más personalizadas e informadas.

Usando embeddings, puedes transformar conversaciones en representaciones matemáticas que capturan su significado y contexto. Esta sofisticada técnica permite capacidades de búsqueda semántica que van mucho más allá de la simple coincidencia de palabras clave.

Aquí hay un desglose detallado de cómo funciona este sistema:

  • Cada mensaje se transforma en un vector de alta dimensionalidad usando modelos de embedding
    • Estos vectores capturan el significado semántico del texto convirtiendo palabras y frases en representaciones numéricas
    • Los conceptos similares terminan más cerca entre sí en el espacio vectorial, permitiendo un mapeo intuitivo de relaciones
    • El proceso de embedding considera el contexto, sinónimos y conceptos relacionados, no solo coincidencias exactas
  • Cuando llegan nuevas consultas, el sistema puede:
    • Convertir la nueva consulta en un vector usando el mismo modelo de embedding
    • Encontrar los vectores almacenados más similares usando algoritmos eficientes de búsqueda de similitud
    • Recuperar solo aquellas piezas relevantes de contexto, priorizando la información más semánticamente relacionada
    • Ajustar dinámicamente la cantidad de contexto basado en puntajes de relevancia

Este sofisticado enfoque permite una recuperación de contexto eficiente y relevante sin sobrepasar los límites de tokens. El sistema puede mantener una memoria virtualmente ilimitada mientras solo extrae la información más pertinente para cada interacción. Esto es particularmente valioso en aplicaciones que requieren contexto histórico profundo, como relaciones a largo plazo con clientes, plataformas educativas o sistemas complejos de gestión de proyectos.

Herramientas Esenciales para la Implementación:

  • openai.Embedding - La API de embedding de OpenAI que convierte texto en vectores numéricos, capturando significado semántico y relaciones entre diferentes piezas de texto. Esto es fundamental para crear representaciones vectoriales consultables de tu historial de conversación.
  • FAISS - La potente biblioteca de búsqueda de similitud de Facebook AI, optimizada para buscar rápidamente a través de millones de vectores de alta dimensionalidad. O Pinecone - Un servicio administrado de base de datos vectorial que maneja almacenamiento vectorial y búsqueda de similitud con escalado automático y actualizaciones en tiempo real.
  • Marcos de búsqueda vectorial:
    • chromadb - Una base de datos de embedding de código abierto que facilita el almacenamiento y consulta de tus embeddings vectoriales con metadatos adicionales
    • Weaviate - Un motor de búsqueda vectorial que combina almacenamiento vectorial con consultas basadas en GraphQL y capacidades de clasificación automática

Como discutimos en el Capítulo 6, sección 6.4 sobre RAG (Generación Aumentada por Recuperación), el principio clave sigue siendo sencillo: almacena más, inyecta menos. Esto significa mantener una base de conocimiento externa completa mientras se recupera selectivamente solo la información más relevante para cada interacción, en lugar de intentar meter todo en la ventana de contexto inmediata.

class ConversationManager:
    def __init__(self, openai_api_key):
        self.api_key = openai_api_key
        self.summary = ""
        self.messages = []
        self.summary_interval = 5  # Summarize every 5 messages
        self.message_count = 0
        
    def add_message(self, role, content):
        """Add a new message to the conversation."""
        self.messages.append({"role": role, "content": content})
        self.message_count += 1
        
        # Check if it's time to create a summary
        if self.message_count % self.summary_interval == 0:
            self.update_summary()
    
    def update_summary(self):
        """Create a summary of recent conversation."""
        try:
            # Create prompt for summarization
            summary_prompt = {
                "role": "system",
                "content": "Please create a brief summary of the following conversation. "
                          "Focus on key points and decisions made."
            }
            
            # Get last few messages to summarize
            recent_messages = self.messages[-self.summary_interval:]
            
            # Request summary from OpenAI
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    summary_prompt,
                    *recent_messages,
                    {"role": "user", "content": "Please summarize our discussion."}
                ],
                temperature=0.7
            )
            
            # Update the running summary
            new_summary = response.choices[0].message.content
            if self.summary:
                self.summary = f"{self.summary}\n\nUpdate: {new_summary}"
            else:
                self.summary = new_summary
                
            # Trim old messages but keep the summary
            self.messages = [
                {"role": "system", "content": f"Previous context: {self.summary}"},
                *recent_messages
            ]
            
        except Exception as e:
            print(f"Error updating summary: {str(e)}")
    
    def get_current_context(self):
        """Get current conversation context including summary."""
        if self.summary:
            return [
                {"role": "system", "content": f"Previous context: {self.summary}"},
                *self.messages
            ]
        return self.messages

# Example usage
conversation = ConversationManager("your-api-key")

# Add some messages
conversation.add_message("user", "Can you help me learn Python?")
conversation.add_message("assistant", "Of course! What specific topics interest you?")
conversation.add_message("user", "I'd like to learn about functions.")
conversation.add_message("assistant", "Let's start with the basics of functions...")
conversation.add_message("user", "Can you show me an example?")

Desglose del Código:

  • Estructura de la Clase
    • ConversationManager maneja todos los aspectos de la gestión y resumen de conversaciones
    • Mantiene tanto los mensajes actuales como el resumen continuo
    • Intervalo de resumen configurable (por defecto: cada 5 mensajes)
  • Componentes Principales
    • add_message(): Rastrea nuevos mensajes y activa actualizaciones de resumen
    • update_summary(): Crea resúmenes usando la API de OpenAI
    • get_current_context(): Combina el resumen con mensajes recientes
  • Gestión de Resúmenes
    • Se activa automáticamente después de un número específico de mensajes
    • Preserva el contexto combinando resúmenes antiguos con nueva información
    • Maneja errores con elegancia para prevenir pérdida de datos
  • Optimización de Memoria
    • Mantiene un resumen continuo de conversaciones anteriores
    • Conserva mensajes recientes para contexto inmediato
    • Gestiona eficientemente el uso de tokens mediante el resumen de contenido antiguo

Beneficios de esta Implementación:

  • Mantiene la coherencia de la conversación mientras gestiona la ventana de contexto
  • Maneja automáticamente la generación de resúmenes en intervalos regulares
  • Proporciona fácil acceso tanto al contexto actual como al resumen histórico
  • Escala bien para conversaciones de larga duración

7.4.5 Estrategia 4: Usar "Resúmenes Continuos" para Memoria Episódica

A medida que la sesión avanza, resume dinámicamente cada sección de la conversación y mantén un resumen evolutivo que se actualiza cada pocos turnos. Este poderoso enfoque funciona monitoreando y analizando continuamente la conversación en curso en segmentos discretos. El sistema identifica automáticamente las pausas naturales en la discusión, puntos clave de decisión y transiciones de temas, creando un documento vivo que refleja la evolución de la conversación.

Así es como funciona en la práctica:

  1. Cada pocos mensajes (típicamente 3-5 turnos), el sistema analiza la conversación reciente
  2. Extrae información esencial, decisiones y conclusiones
  3. Estas se condensan en un resumen conciso pero informativo
  4. El resumen se fusiona entonces con resúmenes previos, manteniendo el flujo cronológico

Por ejemplo, después de varios mensajes sobre funciones de Python, el resumen podría comenzar con "Se discutieron definiciones de funciones, parámetros y valores de retorno" mientras mantiene ejemplos específicos de código disponibles en el contexto a corto plazo. A medida que la conversación avanza hacia el manejo de errores, el resumen se expandiría para incluir "Se exploraron bloques try/except y sus ventajas sobre las declaraciones condicionales."

Puedes mantener esta "memoria episódica" junto con tu búfer a corto plazo, creando un sistema de memoria de dos niveles que refleja la cognición humana. El búfer a corto plazo contiene mensajes recientes con detalle completo, mientras que la memoria episódica mantiene versiones resumidas de conversaciones anteriores. Este enfoque de memoria dual sirve para múltiples propósitos:

  1. Mantiene la coherencia de la conversación conservando tanto el contexto reciente detallado como el contexto histórico más amplio
  2. Previene el desbordamiento de contexto condensando información antigua en resúmenes compactos
  3. Permite referencias rápidas a temas anteriores sin cargar el historial completo de conversación
  4. Crea un flujo natural de conversación permitiendo que la IA haga referencia tanto al contexto reciente como al histórico

Este sistema funciona de manera similar a la memoria humana, donde mantenemos recuerdos vívidos recientes mientras los recuerdos más antiguos se vuelven más condensados y resumidos con el tiempo. Este enfoque natural para la gestión de memoria ayuda a crear conversaciones más atractivas y contextualmente conscientes mientras gestiona eficientemente los recursos computacionales.

Ejemplo:

# Comprehensive conversation manager with OpenAI integration
import openai
from typing import List, Dict
import time

class ConversationManager:
    def __init__(self, api_key: str):
        self.api_key = api_key
        openai.api_key = api_key
        self.session_summary = ""
        self.messages: List[Dict[str, str]] = []
        self.last_summary_time = time.time()
        self.summary_interval = 300  # 5 minutes

    def add_message(self, role: str, content: str) -> None:
        """Add a new message and update summary if needed."""
        self.messages.append({"role": role, "content": content})
        
        # Check if it's time to update summary
        if time.time() - self.last_summary_time > self.summary_interval:
            self.update_summary()

    def update_summary(self) -> None:
        """Update conversation summary using OpenAI."""
        try:
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    {"role": "system", "content": "Create a brief summary of this conversation."},
                    *self.messages[-5:]  # Last 5 messages for context
                ],
                temperature=0.7,
                max_tokens=150
            )
            
            new_summary = response.choices[0].message.content
            self.session_summary = f"{self.session_summary}\n{new_summary}" if self.session_summary else new_summary
            self.last_summary_time = time.time()
            
        except Exception as e:
            print(f"Error updating summary: {str(e)}")

    def get_context(self) -> List[Dict[str, str]]:
        """Get current conversation context with summary."""
        return [
            {"role": "system", "content": f"Previous context: {self.session_summary}"},
            *self.messages[-5:]  # Keep last 5 messages
        ]

    async def get_response(self, user_message: str) -> str:
        """Get AI response using current context."""
        self.add_message("user", user_message)
        
        try:
            response = openai.ChatCompletion.create(
                model="gpt-4",
                messages=self.get_context(),
                temperature=0.7,
                max_tokens=500
            )
            
            ai_response = response.choices[0].message.content
            self.add_message("assistant", ai_response)
            return ai_response
            
        except Exception as e:
            print(f"Error getting response: {str(e)}")
            return "I apologize, but I encountered an error processing your request."

# Example usage
api_key = "your-openai-api-key"
conversation = ConversationManager(api_key)

# Simulate a conversation
conversation.add_message("user", "I want to learn about Python error handling.")
conversation.add_message("assistant", "Let's start with try/except blocks.")
conversation.add_message("user", "What's the difference between try/except and if/else?")

# Get response with context
response = await conversation.get_response("Can you show me an example?")

Desglose del Código:

  • Componentes Principales:
    • La clase ConversationManager maneja todo el estado de la conversación y las interacciones con OpenAI
    • Generación automática de resúmenes cada 5 minutos
    • Mantiene tanto los mensajes recientes como el resumen histórico
    • Sugerencias de tipo y manejo de errores para mayor robustez
  • Métodos Principales:
    • add_message(): Rastrea el historial de conversaciones
    • update_summary(): Utiliza GPT-4 para crear resúmenes de conversaciones
    • get_context(): Combina el resumen con mensajes recientes
    • get_response(): Maneja la interacción con la API para las respuestas
  • Características:
    • Actualizaciones de resumen basadas en tiempo en lugar de cantidad de mensajes
    • Manejo adecuado de errores y registro
    • Gestión eficiente del contexto con ventana móvil
    • Soporte asíncrono para mejor rendimiento

Luego actualiza session_summary cada 5 turnos utilizando la estrategia de resumen anterior.

7.4.6 Estrategia 5: Prompts Modulares en Lugar de Hilos Largos

Para muchas aplicaciones, mantener un historial extenso de mensajes no siempre es necesario ni eficiente. De hecho, mantener historiales largos de conversación puede llevar a mayores costos de API, tiempos de respuesta más lentos y potencialmente resultados inconsistentes. En su lugar, un enfoque más eficiente es generar plantillas reutilizables con instrucciones completas incorporadas desde el principio. Esta estrategia reduce el uso de tokens y mejora la consistencia de las respuestas al cargar el contexto esencial por adelantado.

Las plantillas pueden incluir roles específicos, capacidades y restricciones que de otro modo necesitarían ser comunicados repetidamente. Estas plantillas actúan como base para el comportamiento y comprensión de la IA, eliminando la necesidad de transportar contexto a través de múltiples intercambios. Cuando están bien diseñadas, pueden proporcionar a la IA pautas claras sobre su rol, nivel de experiencia, estilo de comunicación y conocimiento específico del dominio.

Ejemplo: Construcción de un asistente experto en codificación de IA

# Template for an AI expert coding assistant
system_message = {
    "role": "system",
    "content": """You are a Python expert with the following capabilities:
    - Generate clean, efficient, and well-commented code
    - Provide detailed explanations of code functionality
    - Follow best practices and PEP 8 standards
    - Assume common data science libraries (pandas, numpy) are installed
    - Optimize code for readability and performance

    When responding:
    1. Always include docstrings and comments
    2. Explain complex logic
    3. Handle edge cases and errors
    4. Provide example usage where appropriate"""
}

# Example implementation using OpenAI API
import openai
from typing import Dict, Any

class PythonExpertAssistant:
    def __init__(self, api_key: str):
        """Initialize the Python expert assistant with API key."""
        self.api_key = api_key
        openai.api_key = api_key
        self.system_message = system_message

    async def get_code_solution(self, prompt: str) -> Dict[str, Any]:
        """
        Generate a code solution based on user prompt.
        
        Args:
            prompt (str): User's coding question or request
            
        Returns:
            Dict containing response and metadata
        """
        try:
            response = await openai.ChatCompletion.create(
                model="gpt-4",
                messages=[
                    self.system_message,
                    {"role": "user", "content": prompt}
                ],
                temperature=0.7,
                max_tokens=1000,
                presence_penalty=0.6
            )
            
            return {
                "code": response.choices[0].message.content,
                "tokens_used": response.usage.total_tokens,
                "status": "success"
            }
            
        except Exception as e:
            return {
                "error": str(e),
                "status": "error"
            }

# Example usage
assistant = PythonExpertAssistant("your-api-key")
response = await assistant.get_code_solution(
    "Create a function to calculate Fibonacci sequence"
)

Desglose del Código:

  • Estructura del Mensaje del Sistema
    • Define el rol y las capacidades claramente
    • Establece expectativas para la calidad y el estilo del código
    • Establece un formato de respuesta consistente
  • Implementación de la Clase
    • Sugerencias de tipo para mejor mantenibilidad del código
    • Soporte asíncrono para mejor rendimiento
    • Manejo apropiado de errores y formato de respuesta
  • Integración de API
    • Temperatura configurable para la creatividad de las respuestas
    • Gestión de tokens
    • Penalización de presencia para fomentar respuestas diversas

Esto elimina la necesidad de transportar este contexto en cada mensaje.

7.4.7 Resumen: Consejos Prácticos

La ventana de contexto, en lugar de verse como una limitación, debe considerarse como una oportunidad creativa que nos impulsa a desarrollar soluciones más sofisticadas. Con decisiones arquitectónicas reflexivas, podemos crear sistemas que gestionen eficazmente conversaciones a largo plazo mientras permanecemos dentro de las restricciones de tokens. Así es como contribuye cada componente clave:

La Sumarización nos permite condensar historiales de conversación extensos en representaciones compactas y significativas. Esto preserva la información esencial mientras reduce significativamente el uso de tokens. Por ejemplo, una conversación de 1000 tokens podría destilarse en un resumen de 100 tokens capturando los puntos clave.

Los sistemas de Recuperación permiten un acceso inteligente a los datos históricos de conversación. Mediante el uso de incrustaciones vectoriales o búsqueda semántica, podemos extraer el contexto pasado relevante exactamente cuando se necesita, en lugar de transportar todo el historial de conversación. Esto crea un flujo más natural donde los temas anteriores pueden recordarse contextualmente.

Las estrategias de Recorte ayudan a mantener un rendimiento óptimo eliminando selectivamente las partes menos relevantes de la conversación mientras se mantiene el contexto crucial. Esto puede implicar eliminar mensajes más antiguos después de la sumarización o podar información redundante para permanecer dentro de los límites de tokens.

La inyección de memoria dinámica nos permite insertar estratégicamente contexto relevante cuando se necesita. Esto podría incluir preferencias del usuario, interacciones previas o conocimiento específico del dominio, haciendo las conversaciones más personalizadas y contextualmente conscientes sin repetición constante.

Cuando estas técnicas se combinan efectivamente, el resultado es un sistema de IA que puede mantener conversaciones extensas y naturales mientras gestiona eficientemente los recursos computacionales. Esto crea aplicaciones que se sienten notablemente humanas en su capacidad para mantener el contexto y hacer referencia a interacciones previas, incluso cuando las conversaciones se extienden por largos períodos o múltiples sesiones.