Puntos clave
- ChatOpenAI funciona sin cambios: establece base_url, api_key y model a
uncensored. - La API soporta tool calling, por lo que bind_tools y el agente preconstruido funcionan.
- Limita las iteraciones del bucle y valida los argumentos de las herramientas; los modelos de pesos abiertos a veces los interpretan mal.
- Respeta las 8 peticiones concurrentes con una clave completa cuando ejecutes agentes en paralelo.
Lo que necesitas antes de comenzar
Necesitas Python 3.10 o superior, una clave de API y algunos paquetes. La clave se obtiene desde la página de clave de API: regístrate con Google o con correo electrónico y contraseña, luego reclama el crédito de prueba de $0,50 con un clic. La clave de prueba permite 2 peticiones concurrentes y 60 por minuto, lo cual es suficiente para todo en este artículo si ejecutas un agente a la vez.
pip install langchain-openai langchain-core langgraph
export API_KEY="paste-your-key-here"La API expone POST /v1/chat/completions y GET /v1/models. LangChain solo necesita el primero. El modelo es un único modelo de pesos abiertos ajustado para responder sin rechazos de contenido para uso adulto lícito; lo ejecuta un proveedor independiente y no es la API oficial de ningún proveedor de modelos. La documentación lista los encabezados y límites si los quieres junto a tu editor.
Cómo se mapean las piezas a la API
Ayuda saber qué hace LangChain en la red. Un HumanMessage se convierte en un mensaje con role user. Un AIMessage se convierte en assistant, y cuando lleva llamadas a herramientas, estas aparecen en el mensaje del asistente como un array tool_calls. Un ToolMessage se convierte en role tool con el ID de llamada correspondiente. El prompt del sistema va primero como role system.
Ese mapeo es importante para la depuración. Si un agente se comporta de forma extraña, imprime la lista de mensajes antes de cada llamada y léela como una transcripción. Usualmente encontrarás el problema en un minuto: un resultado de herramienta vacío, un ID de llamada que no coincide, o un historial que ha crecido mucho más de lo esperado. La palabra agentic puede hacer que esto suene a magia, pero cada paso es una petición de chat completion ordinaria.
Paso 1: Conectar ChatOpenAI
Toda la integración son tres argumentos. LangChain construye solicitudes estándar estilo OpenAI, por lo que el servidor no puede distinguir la diferencia.
import os
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="uncensored",
base_url="https://api.uncensoredvideo.cc/v1",
api_key=os.environ["API_KEY"],
temperature=0.7,
max_retries=2,
)
print(llm.invoke("Name three beats of a heist scene, one line each.").content)Si esto imprime tres líneas, la conexión funciona. Si obtienes un 401, verifica la clave. Si obtienes un 404, verifica que la URL termine en /v1 y no tenga ruta extra. max_retries es una opción del cliente y ayuda con las respuestas temporales 429 que llevan Retry-After: 5.
El streaming funciona de la misma manera que usarías con cualquier modelo OpenAI: llama a llm.stream(...) e itera. El último fragmento lleva usage, así que puedes registrar conteos de tokens por llamada.
Paso 2: Definir herramientas
Un agente es un bucle: el modelo lee la conversación, ya sea que responda o pida una herramienta, tu código ejecuta la herramienta y el resultado vuelve al modelo. Las herramientas a continuación son funciones de Python simples. Son deliberadamente aburridas porque el punto es ver la mecánica.
from langchain_core.tools import tool
@tool
def word_count(text: str) -> int:
"""Count the words in a piece of text."""
return len(text.split())
@tool
def spoken_minutes(words: int, words_per_minute: int = 150) -> float:
"""Estimate how many minutes a script takes to read aloud."""
return round(words / words_per_minute, 2)
tools = [word_count, spoken_minutes]La docstring y las anotaciones de tipo se convierten en la descripción y el esquema de la herramienta que ve el modelo. Escríbelas como si le explicaras a un colega. Una docstring vaga es la razón más común por la que un agente elige la herramienta incorrecta. Si escribes scripts para video, el mismo patrón se escala a herramientas que consultan listas de planos o verifican un presupuesto de duración, un tema que se cubre en la página del generador de guiones Sora 2.
Paso 3: Ejecutar el bucle del agente manualmente
Las ayudas preconstruidas ocultan el bucle. Escribirlo una vez tú mismo hace que cada error posterior sea más fácil de encontrar.
from langchain_core.messages import HumanMessage, ToolMessage
by_name = {t.name: t for t in tools}
llm_tools = llm.bind_tools(tools)
messages = [HumanMessage(
"Here is a draft: 'The vault door hums. Nina counts to three, "
"then cuts the power.' How many words is it, and how long is it read aloud?"
)]
for step in range(6):
ai = llm_tools.invoke(messages)
messages.append(ai)
if not ai.tool_calls:
break
for call in ai.tool_calls:
result = by_name[call["name"]].invoke(call["args"])
messages.append(ToolMessage(content=str(result), tool_call_id=call["id"]))
print(messages[-1].content)Tres detalles importan. El límite range(6) evita que un modelo confundido entre en un bucle infinito, y también limita tu gasto. El tool_call_id debe coincidir con la llamada que responde. Y el modelo puede solicitar varias herramientas en una sola respuesta, por eso el bucle interno maneja una lista.
Bajo el capó, la solicitud lleva un array tools y la respuesta lleva tool_calls, con resultados devueltos como mensajes con role: "tool". Puedes forzar una herramienta específica con tool_choice, que LangChain expone como un argumento para bind_tools.
Paso 4: Usar el agente LangGraph preconstruido
Una vez que el bucle manual tiene sentido, el agente preconstruido ahorra líneas. Toma el mismo modelo y las mismas herramientas.
import os
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
llm = ChatOpenAI(
model="uncensored",
base_url="https://api.uncensoredvideo.cc/v1",
api_key=os.environ["API_KEY"],
)
agent = create_react_agent(llm, tools)
out = agent.invoke({"messages": [("user", "How long is a 450 word script read aloud?")]})
print(out["messages"][-1].content)LangChain y LangGraph cambian sus APIs entre versiones, y algunas ayudas han sido renombradas o movidas. Si falla una importación, verifica la documentación actual de LangChain para el constructor de agente equivalente. La parte de conexión, ChatOpenAI con una URL base, se mantiene igual.
Elegir entre un bucle y un grafo
El bucle escrito a mano es suficiente para agentes que eligen entre pocas herramientas y se detienen. Es fácil de leer, fácil de registrar y no tiene sorpresas del framework. Pasa a LangGraph cuando necesites ramas que dependan del estado: un paso de revisión que envía trabajo para otra pasada, una aprobación humana antes de que una herramienta arriesgada se ejecute, o varios sub-agentes especializados que pasan resultados entre sí.
Independientemente de lo que elijas, mantén cada nodo pequeño y dale una sola tarea. Un nodo de planificación que genera una lista corta numerada en JSON, un nodo de ejecución que ejecuta herramientas y un nodo de escritura que produce el texto final son más fáciles de probar que un prompt gigante único. También te permiten usar diferentes temperaturas: baja para la planificación y el uso de herramientas, y mayor para el paso de escritura. Como cada nodo es una llamada de completado de chat normal, la misma clave, URL y nombre de modelo sirven para todas, y el costo es simplemente la suma de las llamadas.
Un último hábito: imprime el total de tokens en ejecución. Los agentes que parecen baratos en una demostración pueden gastar diez veces más en una tarea real desordenada, y las cifras de uso en cada respuesta hacen que eso sea visible en la primera ejecución, antes de que se convierta en una sorpresa para tu saldo.
Memoria, pruebas y salida estructurada
El bucle anterior olvida todo cuando termina el script. La memoria más simple es la lista de mensajes misma: guárdala entre turnos de usuario, añade cada nueva pregunta y recorta los mensajes más antiguos cuando se haga larga. Para sesiones largas, reemplaza mensajes antiguos con un resumen corto escrito por el modelo. Como la entrada se cobra por token, un resumen de 500 tokens supera a 20.000 tokens de historial crudo tanto en costo como en enfoque.
Probar agentes se trata principalmente de verificar comportamientos observables. Establece la temperatura en 0 o pasa un seed fijo, que la API transmite, para que las ejecuciones sean más repetibles. Luego, escribe un puñado de preguntas donde sepas qué herramienta debe llamarse, y verifica los nombres de las herramientas y los argumentos en la lista de mensajes, no la redacción exacta de la respuesta. Ejecuta estas pruebas después de cada cambio en un prompt o en una descripción de herramienta. Cambiar una docstring puede alterar qué herramienta elige el modelo, y una prueba es la forma más económica de detectarlo.
Registra tres cosas para cada ejecución: el número de pasos, las llamadas a herramientas con sus argumentos, y el uso de tokens. Cuando una ejecución falla, esas tres líneas te dicen si el modelo eligió mal, una herramienta falló, o el bucle se quedó sin pasos.
Salida estructurada y modo JSON
Los agentes a menudo necesitan devolver datos, no prosa. La API admite el modo JSON a través de response_format: {"type":"json_object"}. En LangChain puedes solicitarlo con llm.bind(response_format={"type": "json_object"}). Indica en el prompt que la respuesta debe ser un objeto JSON y nombra las claves que esperas, luego analiza la cadena y valídala con Pydantic. No confíes en que el paso de análisis siempre tenga éxito; envuélvelo en un reintento que envíe el texto de error de vuelta al modelo una vez.
Errores comunes y cómo solucionarlos
- Argumentos de herramienta incorrectos. Un modelo de pesos abiertos a veces envía una cadena donde declaraste un entero. Valida los argumentos, devuelve un mensaje de error corto desde la herramienta y deja que el modelo se corrija en el siguiente paso.
- Bucles descontrolados. Siempre limita las iteraciones. Registra cada paso mientras desarrollas.
- Agentes en paralelo. Una clave completa permite 8 peticiones concurrentes. Si ejecutas un lote, establece
config={"max_concurrency": 4}enllm.batchpara dejar margen. Exceder el límite devuelve 429 con el códigoconcurrency; exceder 300 peticiones por minuto devuelverate_limited. - Streaming más herramientas. Una petición en streaming mantiene su espacio de concurrencia hasta que finaliza el stream, así que no inicies nuevas llamadas desde dentro de un controlador de stream con una clave de prueba.
- Historial creciente. Cada paso reenvía la lista completa de mensajes. La ventana de contexto es de 100.000 tokens, pero pagas por la entrada en cada llamada.
Cuánto cuesta una ejecución de agente
Toma un agente modesto que hace 4 llamadas al modelo para terminar una tarea, con un prompt promedio de 3.000 tokens y 200 tokens de salida por llamada. Entrada: 4 x 3.000 = 12.000 tokens, que es 12.000 x $0,15 / 1.000.000 = $0,0018. Salida: 4 x 200 = 800 tokens, que es $0,0004. Una ejecución cuesta $0,0022, así que 1.000 ejecuciones cuestan $2,20. El crédito de prueba de $0,50 cubre unas 227 ejecuciones de este tipo. Las solicitudes fallidas o rechazadas no se cobran, y el crédito no caduca. Consulta precios para montos de recarga y bonos. Este sitio acepta solo cripto, USDT en TRC20 o USDC en Base.
