Desarrollo de API de IA

Usar herramientas de chat de IA en la interfaz web es muy conveniente, pero para integrar realmente las capacidades de IA en tus propios productos, flujos de trabajo y scripts de automatización, necesitas una API.

API (Application Programming Interface) es el puente de comunicación entre aplicaciones. A través de la API, tu código puede enviar solicitudes directamente a un modelo de IA y obtener respuestas, sin necesidad de abrir una página web manualmente para copiar y pegar.

Imagina estos escenarios:

  • Tu sitio web de comercio electrónico genera automáticamente descripciones para cada producto.

  • Tu aplicación de notas resume automáticamente los textos largos introducidos por el usuario.

  • Tu sistema de atención al cliente clasifica y responde automáticamente las consultas de los usuarios.

  • Todas estas funciones se pueden implementar mediante la API de IA.

El objetivo de este módulo es llevarte de «solo saber chatear con IA» a «poder hacer que la IA trabaje dentro de tu código».


Conceptos básicos de API

Antes de escribir código, primero comprendamos algunos conceptos clave.

¿Qué es una API?

Una API es una forma de comunicación predefinida: enviamos solicitudes en un formato específico y la otra parte devuelve resultados en un formato específico.

Usemos el pedido de comida como ejemplo:

  • Entras en un restaurante, recibes el menú (documentación de la API) y sabes qué puedes pedir y cómo pedirlo (formato de solicitud).

  • Le dices al camarero: un plato de pollo Kung Pao, poco picante (envías la solicitud a la API).

  • La cocina prepara el plato y te lo sirve (recibes la respuesta de la API).

En este proceso, no necesitas entrar en la cocina ni saber cómo se prepara el plato: este es el valor de la API:Encapsular los detalles complejos y exponer solo interfaces simples。

Principios básicos de la API REST

REST (Representational State Transfer) es el estilo de diseño de API más popular en la actualidad.

En pocas palabras, es comunicarse mediante el protocolo HTTP:

Método HTTPUsoEjemplo en la API de IA
POSTCrear recursoEnviar solicitudes de chat, generar imágenes
GETObtener recursoConsultar la lista de modelos, obtener información de facturación
DELETEEliminar recursoEliminar el historial de conversación

La gran mayoría de las API de IA son solicitudes POST, porque necesitamos «enviar contenido a la IA para que lo procese».

Introducción al formato JSON

JSON (JavaScript Object Notation) es el formato de datos más utilizado en la comunicación con API.

La sintaxis de JSON es muy sencilla: es una combinación de pares clave-valor.

Ejemplo

{
    "model": "gpt-4",
    "messages": [
        {
            "role": "user",
            "content": Hola, por favor preséntame EJEMPLO.
        }
    ],
    "temperature": 0.7,
    "max_tokens": 1000
}

Este es un cuerpo de solicitud típico de una API de IA.

Algunas reglas fundamentales:

  • Los objetos se envuelven usando{ }como delimitador, y los arrays se envuelven usando[ ]como delimitador.

  • Las cadenas se escriben usando comillas dobles"y no se pueden usar comillas simples.

  • Los pares clave-valor se separan usando:como separador, y la clave debe ser una cadena.

  • Los múltiples pares clave-valor se separan usando,como separador.

JSON se parece mucho a los diccionarios de Python, pero hay diferencias en la sintaxis; ten cuidado al escribir código.


Preparación del entorno de desarrollo

Para hacer bien un trabajo, primero hay que afilar las herramientas.

Instalación y configuración de Python

Python es el lenguaje más utilizado para llamar a la API de IA, con un ecosistema completo y una gran cantidad de librerías.

Primero verifica si Python está instalado en tu computadora:

# 检查 Python 版本(Windows、macOS、Linux 通用)
python --version
# 或者
python3 --version

Se recomienda usar Python 3.9 o superior.

Si aún no lo has instalado, ve apython.orgDescarga la última versión estable.

Gestión de paquetes con pip

pip es el gestor de paquetes de Python que se utiliza para instalar librerías de terceros.

# 检查 pip 版本
pip --version
# 或者
pip3 --version

# 升级 pip 到最新版本
pip install --upgrade pip

# 配置国内镜像源(可选,提升下载速度)
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

Elección del editor de código

Para escribir código de API de IA, se recomiendan uno de los siguientes editores:

EditorCaracterísticasPúblico objetivo
VS CodeGratuito, con abundantes complementos y ligeroLa mayoría de los desarrolladores
CursorAsistencia de IA integrada, puede generar código directamentePara quienes desean que la IA les ayude a escribir código
PyCharmLa más completa en funciones y con el mejor soporte para PythonDesarrolladores profesionales de Python

Los códigos de ejemplo de este tutorial se pueden ejecutar en cualquier editor.


Introducción a la API de OpenAI

La API de OpenAI es la API de IA más clásica y con el ecosistema más completo; muchos otros proveedores también son compatibles con su formato.

Registro y obtención de la API Key

La API Key es tu pase de acceso: acredita tu identidad y registra tu uso. Pasos para obtenerla:

  • 1. Visitaplatform.openai.comCrea una cuenta

  • 2. Ve a la página de API Keys

  • 3. Haz clic en «Create new secret key»

  • 4. Copia y guarda esta Key (¡solo se muestra una vez!)

Importante:Nunca subas tu API Key a un repositorio de código público. Si se filtra, otros podrían utilizar tu cuota y generar cargos.

La primera llamada a la API

Primero instala el SDK oficial de OpenAI:

pip install openai

Ahora escribe el primer programa de llamada a la API:

Ejemplo

# Ruta del archivo: first_api_call.py
# Primer ejemplo de llamada a la API de OpenAI

from openai import OpenAI

# Inicializar el cliente
# Nota: se recomienda leer la API Key desde una variable de entorno, no codificarla directamente en el código.
# Aquí se escribe directamente para simplificar la demostración; en proyectos reales, use variables de entorno.
client = OpenAI(
    api_key="your-api-key-here"  # Reemplaza con tu API Key
)

# Enviar solicitud de chat
response = client.chat.completions.create(
    model="gpt-3.5-turbo",  # Seleccionar modelo
    messages=[
        {
            "role": "user",  # Rol: 'user' representa al usuario
            "content": Presenta el tutorial EJEMPLO para novatos en una sola frase  # Contenido ingresado por el usuario
        }
    ]
)

# Imprime la respuesta completa (para ver qué devuelve)
print(Respuesta completa:)
print(response)
print("\n" + "="*50 + "\n")

# Extraer la respuesta de la IA
ai_reply = response.choices[0].message.content
print("AI responde:")
print(ai_reply)

Si no tienes una api_key de OpenAI, también puedes usar alternativas nacionales. Muchos modelos nacionales son compatibles con OpenAI, como DeepSeek. Puedes ir ahttps://platform.deepseek.com/api_keysSolicita una api_key y luego reemplaza la tuya en el siguiente códigoapi_keyymodel, los modelos compatibles con DeepSeek son deepseek-v4-flash y deepseek-v4-pro (modo de pensamiento). Así puedes usar la API para llamar al modelo grande:

Ejemplo

from openai import OpenAI

# Inicializar el cliente
# Nota: se recomienda leer la API Key desde variables de entorno, no la codifiques en el código
# Aquí se escribió directamente por conveniencia de la demostración, en proyectos reales usa variables de entorno
client = OpenAI(
    api_key="sk-xxxx",  # Establecer api_key
    base_url="https://api.deepseek.com")  # Establecer la URL de la solicitud


# Enviar solicitud de chat
response = client.chat.completions.create(
    model="deepseek-v4-flash",  # Seleccionar modelo
    messages=[
        {
            "role": "user",  # Rol: user representa al usuario
            "content": "Presenta EJEMPLO, el tutorial para novatos, en una frase"  # Contenido ingresado por el usuario
        }
    ]
)

# Imprimir la respuesta completa (para ver qué devolvió)
print("Respuesta completa:")
print(response)
print("\n" + "="*50 + "\n")

# Extraer la respuesta de la IA
ai_reply = response.choices[0].message.content
print("Respuesta de la IA:")
print(ai_reply)

Ejecuta este programa:

python first_api_call.py

Si todo funciona bien, verás una salida similar a esta:

完整响应:
ChatCompletion(
  id='chatcmpl-xxx',
  choices=[Choice(finish_reason='stop', index=0, message=ChatMessage(content='Ejemplo是一个专注于提供编程技术教程的学习平台...', role='assistant'))],
  model='gpt-3.5-turbo',
  usage=CompletionUsage(completion_tokens=30, prompt_tokens=18, total_tokens=48)
)

==================================================

AI 回复:
Ejemplo是一个专注于提供编程技术教程的学习平台,涵盖多种编程语言和技术领域。

¡Felicitaciones! Has llamado correctamente a una API de IA una vez.

Explicación detallada de los parámetros de solicitud

La API de OpenAI tiene muchos parámetros ajustables, a continuación se muestran los más comunes:

Nombre del parámetroTipoObligatorioDescripciónValor por defecto
modelstringSíID del modelo utilizado, como gpt-3.5-turbo, gpt-4Ninguno
messagesarraySíLista de mensajes del historial de conversaciónNinguno
temperaturenumbernoTemperatura de muestreo, entre 0-2, cuanto más alta más aleatorio, más baja más determinista1.0
max_tokensintegernoNúmero máximo de tokens a generarSin límite
top_pnumbernoParámetro de muestreo de núcleo (top_p), entre 0-11.0
stopstring/arraynoSecuencia de parada, detiene la generación al encontrar estos caracteresnull

Hablemos especialmente de temperature, es el parámetro de ajuste más usado:

Ejemplo

# Ruta del archivo: temperature_demo.py
# Demostrar el efecto del parámetro temperature en la salida

from openai import OpenAI

client = OpenAI(api_key="your-api-key-here")

def ask_ai(temperature_value: float, question: str) -> str:
    """Especificar temperature en la pregunta"""
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": question}],
        temperature=temperature_value,
        max_tokens=200
    )
    return response.choices[0].message.content

# La misma pregunta, hecha tres veces con diferentes temperature
question = "Crea un eslogan para EJEMPLO"

print("--- temperature=0 (más determinista, los resultados son casi iguales cada vez) ---")
print(ask_ai(0.0, question))
print("\n--- temperature=0.7 (equilibrado, recomendado para uso diario)---")
print(ask_ai(0.7, question))
print("\n--- temperature=1.8 (más aleatorio, gran diferencia entre resultados)---")
print(ask_ai(1.8, question))

Una regla general:

  • temperature=0: respuestas basadas en hechos, generación de código, escenarios que requieren resultados precisos

  • temperature=0.7: conversación diaria, tareas generales

  • temperature>1.0: escritura creativa, lluvia de ideas


Anthropic Claude API

Claude es el gran modelo de la empresa Anthropic, conocido por su seguridad y su capacidad para procesar textos largos.

Similitudes y diferencias con la API de OpenAI

Ambos pueden generar texto, pero sus filosofías de diseño difieren:

Elemento de comparaciónOpenAI APIClaude API
Estructura de mensajesAlternancia de system, user, assistantsystem se configura por separado, alternancia de user, assistant
Longitud del contextoVaría entre 16k y 128kLa serie Claude 3 admite 200k
Diseño de parámetrostemperature, top_p, etc.temperature, top_p, etc., conceptos similares

Estructura de la API de Claude Messages

Primero instala el SDK de Claude:

pip install anthropic

Llamada básica de la API de Claude:

Ejemplo

# Ruta del archivo: claude_first_call.py
# Ejemplo de llamada básica a la API de Claude

import anthropic

# Inicializar el cliente
client = anthropic.Anthropic(
    api_key="your-api-key-here"  # Reemplaza con tu API Key de Claude
)

# Enviar solicitud de mensaje
response = client.messages.create(
    model="claude-3-sonnet-20240229",  # Seleccionar modelo de Claude
    max_tokens=1024,  # Claude requiere que se establezca max_tokens
    messages=[
        {
            "role": "user",
            "content": "Presenta EJEMPLO (el tutorial para novatos) en tres frases"
        }
    ]
)

# Imprimir la respuesta
print("Respuesta completa:")
print(response)
print("\n" + "="*50 + "\n")

# Extraer la respuesta
print("Respuesta de Claude:")
print(response.content[0].text)

De igual manera podemos reemplazarlo por un gran modelo nacional compatible, como DeepSeek, especificandoapi_key 、 base_url、modelestos tres parámetros:

Ejemplo

import anthropic

# Inicializar el cliente
client = anthropic.Anthropic(
    api_key="sk-xxx",  # Reemplaza con tu API Key
    base_url="https://api.deepseek.com/anthropic"  # URL base de la API de Claude
)

# Enviar solicitud de mensaje
response = client.messages.create(
    model="deepseek-v4-flash",  # Seleccionar modelo de Claude
    max_tokens=1024,  # Claude requiere que se establezca max_tokens
    messages=[
        {
            "role": "user",
            "content": "Presenta EJEMPLO (el tutorial para novatos) en tres frases"
        }
    ]
)

# Imprimir la respuesta
print("Respuesta completa:")
print(response)
print("\n" + "="*50 + "\n")

# Extraer la respuesta
print("Respuesta de Claude:")
print(response.content[0].thinking)

Configuración del System Prompt

En la API de Claude, el System Prompt es un parámetro independiente, no se coloca en el array de messages:

Ejemplo

# Ruta del archivo: claude_system_prompt.py
# Ejemplo de uso del System Prompt de Claude

import anthropic

client = anthropic.Anthropic(api_key="your-api-key-here")

response = client.messages.create(
    model="claude-3-sonnet-20240229",
    max_tokens=1024,
    # El System Prompt se configura aquí
    system="Eres un editor profesional de documentación técnica, responde de forma concisa y precisa, usa listas con frecuencia.",
    messages=[
        {
            "role": "user",
            "content": "¿Cuáles son los conocimientos básicos que se deben dominar para aprender Python?"
        }
    ]
)

print(response.content[0].text)

Gestión de conversaciones de múltiples turnos

Las conversaciones de un solo turno son simples, pero las aplicaciones realmente útiles necesitan "recordar el contexto".

Métodos de mantenimiento del historial de conversación

La idea es muy simple:Guarda todas las conversaciones anteriores y envíalas junto con cada solicitud a la IA。

Ejemplo

# Ruta del archivo: multi_turn_chat.py
# Ejemplo de gestión de conversaciones de múltiples turnos

from openai import OpenAI

client = OpenAI(api_key="your-api-key-here")

class ChatBot:
    """Un simple robot de conversación de múltiples turnos"""

    def __init__(self, system_prompt: str = "Eres un asistente servicial"):
        self.messages = []  # Guardar el historial de conversación en una lista
        # Primero agregar el system prompt
        self.messages.append({
            "role": "system",
            "content": system_prompt
        })

    def chat(self, user_input: str) -> str:
        """Enviar mensaje y obtener respuesta"""
        # Agregar mensaje del usuario al historial
        self.messages.append({
            "role": "user",
            "content": user_input
        })

        # Llamar a la API
        response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=self.messages
        )

        # Obtener respuesta de la IA
        ai_reply = response.choices[0].message.content

        # Agregar también la respuesta de la IA al historial
        self.messages.append({
            "role": "assistant",
            "content": ai_reply
        })

        return ai_reply

    def get_history(self) -> list:
        """Obtener el historial de conversación"""
        return self.messages


# Ejemplo de uso
if __name__ == "__main__":
    bot = ChatBot(system_prompt="Eres un asistente de programación, especializado en responder preguntas sobre EJEMPLO y Python")

    print("=== Demostración de conversación de múltiples turnos ===")

    # Primera ronda
    r1 = bot.chat("¿Qué es Python?")
    print("Usuario: ¿Qué es Python?")
    print("AI:", r1)
    print()

    # Segunda ronda (la IA puede recordar el tema de la ronda anterior)
    r2 = bot.chat("¿Qué características tiene?")
    print("Usuario: ¿Qué características tiene?")
    print("AI:", r2)
    print()

    # Tercera ronda
    r3 = bot.chat("¿Hay algún tutorial de Python en EJEMPLO?")
    print("Usuario: ¿Hay algún tutorial de Python en EJEMPLO?")
    print("AI:", r3)

Punto clave: el historial de conversación es una lista ordenada, estrictamente alternando user-assistant-user-assistant, en cada solicitud se debe enviar el historial completo para que la IA pueda entender el contexto. El historial consume tokens, por lo que debe limpiarse periódicamente.

Manejo de la superación de la ventana de contexto

Cada modelo tiene un límite de ventana de contexto, por ejemplo gpt-3.5-turbo es 16k, gpt-4 es 8k o 32k.

Cuando el historial de conversación es demasiado largo, se produce un error.

Algunas estrategias comunes de manejo:

Ejemplo

# Ruta del archivo: context_management.py
# Ejemplo de estrategia de gestión de la ventana de contexto

from openai import OpenAI

client = OpenAI(api_key="your-api-key-here")


class ChatBotWithContextLimit:
    """Robot de conversación con límite de contexto"""

    def __init__(self, system_prompt: str, max_messages: int = 10):
        self.system_prompt = system_prompt
        self.max_messages = max_messages  # Cuántos mensajes conservar como máximo
        self.messages = []

    def _trim_messages(self):
        """Recortar la lista de mensajes, conservar los más recientes"""
        # Conservar siempre el system prompt, y luego solo los últimos max_messages
        if len(self.messages) > self.max_messages:
            # Conservar los últimos N
            self.messages = self.messages[-self.max_messages:]

    def chat(self, user_input: str) -> str:
        # Agregar mensaje del usuario
        self.messages.append({
            "role": "user",
            "content": user_input
        })

        # Recortar el historial
        self._trim_messages()

        # Construir la solicitud completa (system prompt + historial)
        full_messages = [
            {"role": "system", "content": self.system_prompt}
        ] + self.messages

        try:
            response = client.chat.completions.create(
                model="gpt-3.5-turbo",
                messages=full_messages
            )
            ai_reply = response.choices[0].message.content

            self.messages.append({
                "role": "assistant",
                "content": ai_reply
            })

            return ai_reply

        except Exception as e:
            # Si sigue dando error, puede ser necesario un recorte más agresivo
            return f"Error: {str(e)}"


# Estrategia 2: Usar IA para resumir el historial de conversaciones
def summarize_conversation(messages: list) -> str:
    """Usar IA para resumir el historial de conversaciones, reemplazando el historial original"""
    history_text = "\n".join([
        f"{m['role']}: {m['content']}"
        for m in messages
    ])

    prompt = f"""Por favor, resume la siguiente conversación en un resumen conciso, conservando la información clave:

{history_text}

Resumen: """


    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": prompt}],
        temperature=0
    )

    return response.choices[0].message.content


# Usar la estrategia de resumen
print("--- Ejemplo de resumen del historial de conversación ---")
sample_history = [
    {"role": "user", "content": "¿Cómo me llamo?"},
    {"role": "assistant", "content": "Lo siento, no sé cómo te llamas. Puedes decírmelo."},
    {"role": "user", "content": "Me llamo Xiao Ming, estoy aprendiendo Python en EJEMPLO."},
    {"role": "assistant", "content": "¡Hola Xiao Ming! Encantado de conocerte. EJEMPLO es una excelente plataforma de aprendizaje."},
    {"role": "user", "content": "Quiero aprender listas, ¿puedes enseñarme?"},
    {"role": "assistant", "content": "¡Por supuesto! Las listas de Python son..."},
]

summary = summarize_conversation(sample_history)
print("Resumen de la conversación:", summary)

Resumiendo los métodos de gestión del contexto:

EstrategiaVentajasDesventajasEscenarios aplicables
Conservar solo los últimos N mensajesSencillo, rápidoPuede perder información importanteConversaciones cortas, escenarios de charla informal
Usar IA para resumir el historialConserva la información semánticaRequiere llamadas adicionales a la APIConversaciones largas, con mucha información importante
Ventana deslizanteEquilibra simplicidad y completitudImplementación ligeramente complejaAdecuada para escenarios generales

Salida en streaming

Cuando chateas con IA en una página web, verás que el texto aparece palabra por palabra: esto es la salida en streaming.

¿Qué es la salida en streaming?

  • Modo normal: la IA genera la respuesta completa y la devuelve de una vez; puede que tengas que esperar varios segundos o incluso decenas de segundos.

  • Modo streaming: la IA envía cada token tan pronto como lo genera, ofreciendo una mejor experiencia de usuario.

Técnicamente, la salida en streaming utiliza el protocolo SSE (Server-Sent Events), donde el servidor envía datos de forma continua.

Implementación del efecto de máquina de escribir

Ejemplo

# Ruta del archivo: streaming_demo.py
# Demostración de salida en streaming (efecto máquina de escribir)

from openai import OpenAI

client = OpenAI(api_key="your-api-key-here")

print("=== Demostración de salida en streaming ===")
print("Pregunta: escribe una introducción sobre EJEMPLO\n")
print("Respuesta: ", end="", flush=True)

# Parámetro clave: stream=True
response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": "Escribe una introducción sobre EJEMPLO, el tutorial para novatos"}
    ],
    stream=True  # Habilitar la salida en streaming
)

collected_reply = []

for chunk in response:
    # Extraer el contenido del chunk actual
    if chunk.choices[0].delta.content:
        content = chunk.choices[0].delta.content
        print(content, end="", flush=True)  # Imprimir en tiempo real, sin salto de línea
        collected_reply.append(content)

print()  # Finalmente, generar un salto de línea
print("\n" + "="*50)
print("Respuesta completa:", "".join(collected_reply))

Al ejecutar este programa, verás cómo el texto aparece palabra por palabra.

El uso de la salida en streaming de Claude es similar:

Ejemplo

# Ruta del archivo: claude_streaming.py
# Ejemplo de salida en streaming de Claude

import anthropic

client = anthropic.Anthropic(api_key="your-api-key-here")

print("=== Salida en streaming de Claude ===")
print("Pregunta: ¿cómo aprender programación?\n")
print("Respuesta: ", end="", flush=True)

with client.messages.stream(
    model="claude-3-sonnet-20240229",
    max_tokens=1024,
    messages=[{"role": "user", "content": "¿Cómo aprender programación de manera sistemática?"}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

print()

Recomendación de experiencia de usuario: salvo que sea un escenario que requiera "esperar el resultado completo", prioriza el uso de la salida en streaming. Permitir que el usuario vea el progreso mejora significativamente la experiencia.


Cálculo y optimización de costos de API

Las API de IA se facturan según el uso; cuanto más se usan, más se gasta.

Principios de facturación de tokens

Las API de IA no se facturan por número de palabras o conversaciones, sino por tokens.Token,TokenLos tokens son la unidad básica del texto que la IA procesa.

Un token equivale aproximadamente a:

  • Inglés: 0.75 palabras (o 4 letras)

  • Chino: 1-2 caracteres chinos

Por ejemplo:

  • "Hello, mundo" — aproximadamente 3-4 tokens

  • El tutorial de EJEMPLO es excelente

Método de facturación:

Prompt tokens(你发给 AI 的) + Completion tokens(AI 返回给你的)= 总 tokens

Los precios varían según el modelo, por ejemplo, gpt-3.5-turbo cuesta $0.0015/1k tokens de prompt y $0.002/1k tokens de completion.

Cómo controlar los costos de API

Ejemplo

# Ruta del archivo: cost_tracking.py
# Ejemplo de seguimiento y control de costos de API

from openai import OpenAI

client = OpenAI(api_key="your-api-key-here")

# Tabla de precios de modelos (ejemplo, consulte la documentación oficial para precios reales)
# Unidad: dólares / 1k tokens
MODEL_PRICES = {
    "gpt-3.5-turbo": {
        "prompt": 0.0015,
        "completion": 0.002
    },
    "gpt-4": {
        "prompt": 0.03,
        "completion": 0.06
    }
}


def chat_with_cost_tracking(model: str, messages: list):
    """Chat con cálculo de costos"""
    response = client.chat.completions.create(
        model=model,
        messages=messages
    )

    # Obtener el uso de tokens de la respuesta
    usage = response.usage
    prompt_tokens = usage.prompt_tokens
    completion_tokens = usage.completion_tokens
    total_tokens = usage.total_tokens

    # Calcular el costo
    price = MODEL_PRICES.get(model, {"prompt": 0, "completion": 0})
    prompt_cost = (prompt_tokens / 1000) * price["prompt"]
    completion_cost = (completion_tokens / 1000) * price["completion"]
    total_cost = prompt_cost + completion_cost

    return {
        "reply": response.choices[0].message.content,
        "usage": {
            "prompt_tokens": prompt_tokens,
            "completion_tokens": completion_tokens,
            "total_tokens": total_tokens
        },
        "cost": {
            "prompt_cost": prompt_cost,
            "completion_cost": completion_cost,
            "total_cost": total_cost
        }
    }


# Ejemplo de uso
if __name__ == "__main__":
    result = chat_with_cost_tracking(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": "Presenta EJEMPLO"}]
    )

    print("Respuesta de IA:", result["reply"])
    print()
    print("Estadísticas de uso:")
    print(f"  Prompt tokens: {result['usage']['prompt_tokens']}")
    print(f"  Completion tokens: {result['usage']['completion_tokens']}")
    print(f"  Total tokens: {result['usage']['total_tokens']}")
    print()
    print("Estadísticas de costos (USD):")
    print(f"  Prompt cost: ${result['cost']['prompt_cost']:.6f}")
    print(f"  Completion cost: ${result['cost']['completion_cost']:.6f}")
    print(f"  Total cost: ${result['cost']['total_cost']:.6f}")

Algunos consejos prácticos para optimizar costos:

TécnicaCómo hacerloProporción de ahorro
Elegir el modelo adecuadoPara tareas simples usa gpt-3.5-turbo, no gpt-490%+
Limitar max_tokensEstablecer un límite razonable para evitar que la IA hable demasiadoDepende de la situación
Recortar el contextoConservar solo el historial de conversación necesario50%+
El prompt debe ser concisoEl system prompt no debe ser demasiado largoSegún el caso
Caché de resultadosPara la misma pregunta, devolver directamente el resultado de la cachéSegún el caso

Estrategias de caché

Para preguntas repetidas, almacenar resultados en caché puede ahorrar mucho dinero:

Ejemplo

# Ruta del archivo: response_cache.py
# Implementación simple de caché de respuestas

import hashlib
import json
from openai import OpenAI

client = OpenAI(api_key="your-api-key-here")


class SimpleCache:
    """Caché simple en memoria"""

    def __init__(self):
        self.cache = {}

    def _make_key(self, model: str, messages: list) -> str:
        """Genera la clave de caché según el contenido de la solicitud"""
        # Serializar la información clave y obtener el hash
        key_data = {
            "model": model,
            "messages": messages
        }
        key_str = json.dumps(key_data, sort_keys=True)
        return hashlib.md5(key_str.encode()).hexdigest()

    def get(self, model: str, messages: list):
        """Obtener caché"""
        key = self._make_key(model, messages)
        return self.cache.get(key)

    def set(self, model: str, messages: list, value: str):
        """Establecer caché"""
        key = self._make_key(model, messages)
        self.cache[key] = value


# Función de chat con caché
cache = SimpleCache()

def chat_with_cache(model: str, messages: list):
    # Primero consultar la caché
    cached = cache.get(model, messages)
    if cached:
        print("(Caché encontrada, devolver directamente)")
        return cached

    # Si no se encuentra en caché, llamar a la API
    response = client.chat.completions.create(
        model=model,
        messages=messages
    )
    reply = response.choices[0].message.content

    # Almacenar en la caché
    cache.set(model, messages, reply)

    return reply


# Prueba
if __name__ == "__main__":
    messages = [{"role": "user", "content": "¿Qué sitio web es EJEMPLO?"}]

    print("Primera llamada...")
    r1 = chat_with_cache("gpt-3.5-turbo", messages)
    print(r1)
    print()

    print("Segunda llamada (misma pregunta)...")
    r2 = chat_with_cache("gpt-3.5-turbo", messages)
    print(r2)

Manejo de errores y mecanismos de reintento

Las solicitudes de red siempre pueden fallar, y la API no es una excepción. Un código robusto debe manejar diversas situaciones excepcionales.

Tipos de errores comunes

Tipo de errorCódigo de estado HTTPCausaForma de manejo
Error de autenticación401Clave de API incorrecta o expiradaVerificar la clave de API
Cuota insuficiente402La cuenta no tiene fondosRecargar saldo o cambiar de cuenta
Límite excedido429Solicitudes demasiado rápidas o cuota agotadaEsperar un poco y volver a intentar
Error del servidor5xxProblema en el servidor de IAReintentar

Reintento con retroceso exponencial

Ante errores temporales (como 429, 5xx), la estrategia más común es el reintento con retroceso exponencial:

  • Primer fallo → esperar 1 segundo → reintentar

  • Segundo fallo → esperar 2 segundos → reintentar

  • Tercer fallo → esperar 4 segundos → reintentar

  • Cuarto fallo → esperar 8 segundos → reintentar

Cada vez, el tiempo de espera se duplica, dando al servicio la oportunidad de recuperarse.

Ejemplo

# Ruta del archivo: error_handling.py
# Manejo de errores y reintentos con retroceso exponencial

import time
from openai import OpenAI, APIError, RateLimitError, APIConnectionError

client = OpenAI(api_key="your-api-key-here")


def chat_with_retry(
    model: str,
    messages: list,
    max_retries: int = 3,
    initial_wait: float = 1.0
):
    """Función de chat con mecanismo de reintentos"""

    retries = 0

    while retries <= max_retries:
        try:
            response = client.chat.completions.create(
                model=model,
                messages=messages
            )
            return {
                "success": True,
                "reply": response.choices[0].message.content
            }

        except RateLimitError as e:
            # Error de límite de velocidad: esperar un poco y reintentar
            retries += 1
            if retries > max_retries:
                return {
                    "success": False,
                    "error": f"Se agotaron los reintentos: {str(e)}"
                }
            wait_time = initial_wait * (2 ** (retries - 1))
            print(f"Se activó el límite de velocidad, esperando {wait_time} segundos para reintentar...")
            time.sleep(wait_time)

        except APIConnectionError as e:
            # Error de conexión de red: reintentar
            retries += 1
            if retries > max_retries:
                return {
                    "success": False,
                    "error": f"Error de conexión de red: {str(e)}"
                }
            wait_time = initial_wait * (2 ** (retries - 1))
            print(f"Error de red, esperando {wait_time} segundos para reintentar...")
            time.sleep(wait_time)

        except APIError as e:
            # Error de API: reintentar según el caso
            if e.status_code and 500 <= e.status_code < 600:
                retries += 1
                if retries > max_retries:
                    return {
                        "success": False,
                        "error": f"Error del servidor: {str(e)}"
                    }
                wait_time = initial_wait * (2 ** (retries - 1))
                print(f"Error del servidor, esperando {wait_time} segundos para reintentar...")
                time.sleep(wait_time)
            else:
                # Errores que no sean 5xx, no reintentar
                return {
                    "success": False,
                    "error": f"Error de API: {str(e)}"
                }

        except Exception as e:
            # Otros errores, no reintentar
            return {
                "success": False,
                "error": f"Error desconocido: {str(e)}"
            }


# Ejemplo de uso
if __name__ == "__main__":
    result = chat_with_retry(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": "Hola, EJEMPLO"}]
    )

    if result["success"]:
        print("Éxito:", result["reply"])
    else:
        print("Fallo:", result["error"])

También puedes usar librerías existentes para simplificar la lógica de reintentos, como tenacity, instálala con el siguiente comando:

pip install tenacity

Ejemplo

# Ruta del archivo: tenacity_demo.py
# Usar la librería tenacity para simplificar la lógica de reintentos

from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
from openai import OpenAI, RateLimitError, APIError

client = OpenAI(api_key="your-api-key-here")


@retry(
    stop=stop_after_attempt(3),  # Reintentar como máximo 3 veces
    wait=wait_exponential(multiplier=1, min=1, max=10),  # Backoff exponencial: 1, 2, 4... máximo 10 segundos
    retry=retry_if_exception_type((RateLimitError, APIError))  # Reintentar solo ante excepciones específicas
)
def chat_with_tenacity(model: str, messages: list):
    """Implementar reintentos con el decorador de tenacity"""
    response = client.chat.completions.create(
        model=model,
        messages=messages
    )
    return response.choices[0].message.content


# Uso
try:
    reply = chat_with_tenacity(
        "gpt-3.5-turbo",
        [{"role": "user", "content": "Presenta EJEMPLO"}]
    )
    print(reply)
except Exception as e:
    print(f"Fallo final: {e}")

Proyecto práctico: herramienta de chat de IA en línea de comandos

Ahora integremos los conocimientos aprendidos anteriormente para crear una herramienta de chat completa de línea de comandos.

Ejemplo

# Ruta del archivo: ejemplo_chatbot.py
# Robot de chat EJEMPLO AI - Herramienta completa de línea de comandos

import sys
import json
import os
from datetime import datetime
from openai import OpenAI


class EjemploChatBot:
    """Un robot de chat de línea de comandos con todas las funciones"""

    def __init__(self, config_file: str = "config.json"):
        # Cargar configuración
        self.config = self._load_config(config_file)
        self.client = OpenAI(api_key=self.config["api_key"])

        # Estado de la conversación
        self.messages = []
        self.total_tokens = 0
        self.total_cost = 0.0

        # Inicializar el system prompt
        self._init_system_prompt()

    def _load_config(self, config_file: str) -> dict:
        """Cargar archivo de configuración"""
        default_config = {
            "api_key": "your-api-key-here",
            "model": "gpt-3.5-turbo",
            "system_prompt": "Eres un asistente AI servicial, con soporte técnico de EJEMPLO.",
            "max_history": 20,
            "stream": True,
            "temperature": 0.7
        }

        if os.path.exists(config_file):
            with open(config_file, "r", encoding="utf-8") as f:
                user_config = json.load(f)
                default_config.update(user_config)

        return default_config

    def _save_config(self, config_file: str = "config.json"):
        """Guardar archivo de configuración"""
        with open(config_file, "w", encoding="utf-8") as f:
            json.dump(self.config, f, indent=2, ensure_ascii=False)

    def _init_system_prompt(self):
        """Inicializar el system prompt"""
        self.messages = [
            {
                "role": "system",
                "content": self.config["system_prompt"]
            }
        ]

    def _trim_history(self):
        """Recortar el historial de conversación"""
        # Conservar el system prompt + los N mensajes de conversación más recientes
        max_messages = self.config["max_history"]
        if len(self.messages) > max_messages + 1:
            self.messages = [self.messages[0]] + self.messages[-max_messages:]

    def chat(self, user_input: str) -> str:
        """Enviar mensaje y obtener respuesta"""
        # Añadir mensaje del usuario
        self.messages.append({
            "role": "user",
            "content": user_input
        })

        # Recortar historial
        self._trim_history()

        if self.config["stream"]:
            return self._chat_stream()
        else:
            return self._chat_normal()

    def _chat_normal(self) -> str:
        """Modo normal (no streaming)"""
        response = self.client.chat.completions.create(
            model=self.config["model"],
            messages=self.messages,
            temperature=self.config["temperature"]
        )

        ai_reply = response.choices[0].message.content

        # Contabilizar uso
        if hasattr(response, "usage"):
            self.total_tokens += response.usage.total_tokens
            # Estimación simple de coste (precio de gpt-3.5-turbo)
            self.total_cost += (response.usage.total_tokens / 1000) * 0.002

        self.messages.append({
            "role": "assistant",
            "content": ai_reply
        })

        return ai_reply

    def _chat_stream(self) -> str:
        """Modo streaming"""
        response = self.client.chat.completions.create(
            model=self.config["model"],
            messages=self.messages,
            temperature=self.config["temperature"],
            stream=True
        )

        collected_chunks = []
        print("AI:", end="", flush=True)

        for chunk in response:
            if chunk.choices[0].delta.content:
                content = chunk.choices[0].delta.content
                print(content, end="", flush=True)
                collected_chunks.append(content)

        print()

        ai_reply = "".join(collected_chunks)

        self.messages.append({
            "role": "assistant",
            "content": ai_reply
        })

        # El conteo de tokens en modo streaming requiere procesamiento adicional, aquí se simplifica
        # En proyectos reales se puede llamar a la interfaz usage o estimar
        self.total_tokens += len(ai_reply) // 2  # Estimación aproximada

        return ai_reply

    def save_conversation(self, filename: str = None):
        """Guardar historial de conversación"""
        if not filename:
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            filename = f"conversation_{timestamp}.json"

        data = {
            "model": self.config["model"],
            "total_tokens": self.total_tokens,
            "estimated_cost": self.total_cost,
            "messages": self.messages,
            "saved_at": datetime.now().isoformat()
        }

        with open(filename, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=2, ensure_ascii=False)

        return filename

    def clear_history(self):
        """Borrar historial de conversación"""
        self._init_system_prompt()
        self.total_tokens = 0
        self.total_cost = 0.0

    def show_stats(self):
        """Mostrar información de estadísticas"""
        print("\n" + "="*40)
        print("Estadísticas de conversación")
        print("="*40)
        print(f"Modelo: {self.config['model']}")
        print(f"Número de mensajes: {len(self.messages) - 1}")
        print(f"Tokens totales: {self.total_tokens}")
        print(f"Coste estimado: ${self.total_cost:.4f}")
        print("="*40 + "\n")


def print_help():
    """Imprimir información de ayuda"""
    print("\n" + "="*40)
    print("Herramienta de chat EJEMPLO AI - Lista de comandos")
    print("="*40)
    print("/help - Mostrar ayuda")
    print("/clear - Borrar historial de conversación")
    print("/stats - Mostrar estadísticas")
    print("/save - Guardar historial de conversación")
    print("/model - Cambiar modelo")
    print("/temp - Ajustar temperature")
    print("/system - Modificar system prompt")
    print("/quit - Salir del programa")
    print("="*40 + "\n")


def main():
    print("="*40)
    print(" Herramienta de chat EJEMPLO AI")
    print("="*40)
    print("Escribe /help para ver comandos, escribe texto directamente para empezar a chatear"\n")

    bot = EjemploChatBot()

    while True:
        try:
            user_input = input("Tú:").strip()

            if not user_input:
                continue

            # Procesar comandos
            if user_input.startswith("/"):
                cmd = user_input.lower()

                if cmd in ["/quit", "/exit", "/q"]:
                    print("¡Adiós!")
                    break

                elif cmd == "/help":
                    print_help()

                elif cmd == "/clear":
                    bot.clear_history()
                    print("Historial de conversación borrado")

                elif cmd == "/stats":
                    bot.show_stats()

                elif cmd == "/save":
                    filename = bot.save_conversation()
                    print(f"Conversación guardada en: {filename}")

                elif cmd.startswith("/model "):
                    model = user_input[7:].strip()
                    bot.config["model"] = model
                    bot._save_config()
                    print(f"Modelo cambiado a: {model}")

                elif cmd.startswith("/temp "):
                    try:
                        temp = float(user_input[6:].strip())
                        if 0 <= temp <= 2:
                            bot.config["temperature"] = temp
                            bot._save_config()
                            print(f"Temperature establecido en: {temp}")
                        else:
                            print("Temperature debe estar entre 0 y 2")
                    except ValueError:
                        print("Por favor ingresa un número válido")

                elif cmd.startswith("/system "):
                    system_prompt = user_input[8:].strip()
                    bot.config["system_prompt"] = system_prompt
                    bot.clear_history()
                    bot._save_config()
                    print("System prompt actualizado, conversación reiniciada")

                else:
                    print("Comando desconocido, escribe /help para ver la ayuda")

            else:
                # Chat normal
                if not bot.config["stream"]:
                    print("AI:", end="")

                bot.chat(user_input)
                print()

        except KeyboardInterrupt:
            print("\nEscribe /quit para salir, o continúa chateando")

        except Exception as e:
            print(f"Error: {e}")


if __name__ == "__main__":
    main()

Crea un archivo de configuración:

{
    "api_key": "your-api-key-here",
    "model": "gpt-3.5-turbo",
    "system_prompt": "你是一个乐于助人的 AI 助手,由 EJEMPLO 提供技术支持。",
    "max_history": 20,
    "stream": true,
    "temperature": 0.7
}

Ahora puedes ejecutar esta herramienta de chat:

python ejemplo_chatbot.py

Verás:

========================================
  EJEMPLO AI 聊天工具
========================================
输入 /help 查看命令,直接输入文字开始聊天

你:你好
AI:你好!很高兴见到你。我是由 EJEMPLO 提供技术支持的 AI 助手,有什么可以帮你的吗?

你:/stats

========================================
对话统计
========================================
模型:gpt-3.5-turbo
消息数:2
总 tokens:50
估算费用:$0.0001
========================================

你:/quit
再见!
Otras extensiones