Punti chiave
- ChatOpenAI funziona invariato: imposta base_url, api_key e model su
uncensored. - L'API supporta la chiamata di funzioni, quindi bind_tools e l'agente predefinito funzionano entrambi.
- Limita le iterazioni del loop e valida gli argomenti degli strumenti; i modelli a pesi aperti a volte li sbagliano.
- Rispetta 8 richieste concorrenti con una chiave completa quando esegui agenti in parallelo.
Cosa ti serve prima di iniziare
Ti servono Python 3.10 o superiore, una chiave API e alcuni pacchetti. La chiave si ottiene dalla pagina della chiave API: registrati con Google o con email e password, poi richiedi il credito di prova da $0,50 con un solo clic. La chiave di prova consente 2 richieste parallele e 60 al minuto, il che è sufficiente per tutto ciò che è trattato in questo articolo se esegui un agente alla volta.
pip install langchain-openai langchain-core langgraph
export API_KEY="paste-your-key-here"L'API espone POST /v1/chat/completions e GET /v1/models. LangChain ha bisogno solo del primo. Il modello è un singolo modello a pesi aperti ottimizzato per rispondere senza rifiuti di contenuto per un uso adulto legale; è gestito da un provider indipendente e non è l'API ufficiale di alcun fornitore di modelli. La documentazione elenca le intestazioni e i limiti se li vuoi accanto al tuo editor.
Come i pezzi corrispondono all'API
È utile sapere cosa fa LangChain in rete. Un HumanMessage diventa un messaggio con ruolo user. Un AIMessage diventa assistant, e quando trasporta chiamate di strumenti, queste appaiono nel messaggio dell'assistente come un array tool_calls. Un ToolMessage diventa ruolo tool con l'ID della chiamata corrispondente. Il prompt di sistema va per primo come ruolo system.
Questa mappatura è importante per il debug. Se un agente si comporta in modo strano, stampa l'elenco dei messaggi prima di ogni chiamata e leggilo come una trascrizione. Di solito individui il problema entro un minuto: un risultato dello strumento vuoto, un ID di chiamata che non corrisponde o una cronologia cresciuta molto più del previsto. La parola agentic può far sembrare tutto magia, ma ogni passaggio è una normale richiesta di completamento chat.
Passo 1: Connetti ChatOpenAI
L'intera integrazione richiede tre argomenti. LangChain genera richieste standard in stile OpenAI, quindi il server non è in grado di notare la differenza.
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)Se questo stampa tre righe, il collegamento funziona. Se ottieni un 401, controlla la chiave. Se ottieni un 404, controlla che l'URL termini con /v1 e non abbia percorsi extra. max_retries è un'opzione client e aiuta con le risposte 429 temporanee che trasportano Retry-After: 5.
Lo streaming funziona nello stesso modo in cui lo useresti con qualsiasi modello OpenAI: chiama llm.stream(...) ed esegui l'iterazione. L'ultimo chunk trasporta l'utilizzo, quindi puoi registrare i conteggi dei token per ogni chiamata.
Passo 2: Definisci gli strumenti
Un agente è un loop: il modello legge la conversazione, o risponde o chiede uno strumento, il tuo codice esegue lo strumento e il risultato torna al modello. Gli strumenti qui sotto sono semplici funzioni Python. Sono volutamente noiosi, perché l'obiettivo è vedere la meccanica.
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]Il docstring e gli hint di tipo diventano la descrizione e lo schema dello strumento che vede il modello. Scrivili come se stessi spiegando a un collega. Un docstring vago è la ragione più comune per cui un agente sceglie lo strumento sbagliato. Se scrivi script per video, lo stesso pattern si estende a strumenti che cercano liste di riprese o verificano un budget di lunghezza, un argomento trattato nella pagina del generatore di script Sora 2.
Passo 3: Esegui il ciclo dell'agente manualmente
Le utility predefinite nascondono il ciclo. Scriverlo una volta da solo rende ogni bug successivo più facile da trovare.
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)Tre dettagli sono importanti. Il limite range(6) impedisce a un modello confuso di andare in loop all'infinito, e limita anche la tua spesa. Il tool_call_id deve corrispondere alla chiamata a cui risponde. E il modello può richiedere diversi strumenti in una sola risposta, motivo per cui il ciclo interno gestisce un elenco.
Sotto il cofano, la richiesta trasporta un array tools e la risposta trasporta tool_calls, con risultati restituiti come messaggi con role: "tool". Puoi forzare uno strumento specifico con tool_choice, che LangChain espone come argomento a bind_tools.
Passo 4: Usa l'agente LangGraph predefinito
Una volta che il loop manuale ha senso, l'agente predefinito fa risparmiare righe. Usa lo stesso modello e gli stessi strumenti.
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 e LangGraph cambiano le loro API tra le release, e alcune utility sono state rinominate o spostate. Se un'istruzione import fallisce, controlla la documentazione corrente di LangChain per il costruttore di agente equivalente. La parte di connessione, ChatOpenAI con un URL di base, rimane la stessa.
Scegliere tra un loop e un grafo
Il ciclo scritto a mano è sufficiente per gli agenti che scelgono tra pochi strumenti e si fermano. È facile da leggere, facile da registrare e non ha sorprese del framework. Passa a LangGraph quando hai bisogno di rami che dipendono dallo stato: un passaggio di revisione che rimanda il lavoro per un'altra passata, un'approvazione umana prima che uno strumento rischioso venga eseguito, o diversi sotto-agenti specializzati che passano i risultati tra loro.
Qualunque cosa tu scelga, mantieni ogni nodo piccolo e dagli un solo lavoro. Un nodo di pianificazione che produce un breve elenco numerato in JSON, un nodo di esecuzione che esegue strumenti e un nodo di scrittura che produce il testo finale sono più facili da testare rispetto a un singolo prompt gigante. Ti permettono anche di usare temperature diverse: bassa per la pianificazione e l'uso di strumenti, più alta per il passaggio di scrittura. Poiché ogni nodo è una normale chiamata di completamento chat, la stessa chiave, URL e nome del modello li servono tutti, e il costo è semplicemente la somma delle chiamate.
Un'ultima abitudine: stampa il totale dei token in esecuzione. Gli agenti che sembrano economici in una demo possono spendere dieci volte di più in un compito reale disordinato, e i dati di utilizzo su ogni risposta lo rendono visibile alla prima esecuzione, prima che si trasformi in una sorpresa sul tuo saldo.
Memoria, test e output strutturato
Il ciclo sopra dimentica tutto quando lo script termina. La memoria più semplice è l'elenco dei messaggi stesso: tienilo tra i turni dell'utente, aggiungi ogni nuova domanda e taglia i messaggi più vecchi quando diventa lungo. Per sessioni lunghe, sostituisci i messaggi vecchi con un breve riassunto scritto dal modello. Poiché l'input viene fatturato per token, un riassunto da 500 token batte 20.000 token di storico grezzo sia in termini di costo che di concentrazione.
Testare gli agenti consiste principalmente nel verificare il comportamento che puoi osservare. Imposta la temperatura a 0 o passa un seed fisso, che l'API inoltra, quindi le esecuzioni sono più ripetibili. Poi scrivi una manciata di domande in cui sai quale strumento dovrebbe essere chiamato, e verifica i nomi degli strumenti e gli argomenti nell'elenco dei messaggi, non il testo esatto della risposta. Esegui questi test dopo ogni modifica a un prompt o a una descrizione di uno strumento. Modificare un docstring può cambiare quale strumento sceglie il modello, e un test è il modo più economico per accorgersene.
Registra tre cose per ogni esecuzione: il numero di passaggi, le chiamate di strumenti con i loro argomenti e l'utilizzo dei token. Quando un'esecuzione va male, quelle tre righe ti dicono se il modello ha scelto male, se uno strumento è fallito o se il loop ha esaurito i passaggi.
Output strutturato e modalità JSON
Gli agenti spesso hanno bisogno di restituire dati, non prosa. L'API supporta la modalità JSON tramite response_format: {"type":"json_object"}. In LangChain puoi richiederlo con llm.bind(response_format={"type": "json_object"}). Dì al modello nel prompt che la risposta deve essere un oggetto JSON e nomina le chiavi che ti aspetti, poi analizza la stringa e validala con Pydantic. Non fidarti che il passaggio di analisi abbia sempre successo; avvolgilo in un tentativo di nuovo invio che invia il testo di errore al modello una volta.
Punti critici e come risolverli
- Argomenti di strumento scadenti. Un modello a pesi aperti a volte invia una stringa dove hai dichiarato un intero. Convalida gli argomenti, restituisci un breve messaggio di errore dallo strumento e lascia che il modello si corregga nel passaggio successivo.
- Loop incontrollati. Limita sempre le iterazioni. Registra ogni passaggio mentre sviluppi.
- Agenti paralleli. Una chiave completa permette 8 richieste concorrenti. Se esegui un batch, imposta
config={"max_concurrency": 4}sullm.batchper lasciare margine. Superare il limite restituisce 429 con il codiceconcurrency; superare 300 richieste al minuto restituiscerate_limited. - Streaming più strumenti. Una richiesta in streaming mantiene il suo slot di concorrenza fino alla fine dello stream, quindi non avviare nuove chiamate da un gestore di stream su una chiave di prova.
- Cronologia in crescita. Ogni passaggio rispedisce l'elenco completo dei messaggi. La finestra di contesto è di 100.000 token, ma paghi per l'input su ogni chiamata.
Quanto costa un'esecuzione dell'agente
Prendi un agente modesto che fa 4 chiamate al modello per completare un compito, con un prompt medio di 3.000 token e 200 token di output per chiamata. Input: 4 x 3.000 = 12.000 token, che è 12.000 x $0,15 / 1.000.000 = $0,0018. Output: 4 x 200 = 800 token, che è $0,0004. Un'esecuzione costa $0,0022, quindi 1.000 esecuzioni costano $2,20. Il credito di prova da $0,50 copre circa 227 di queste esecuzioni. Le richieste fallite o rifiutate non vengono addebitate e il credito non scade mai. Vedi prezzi per gli importi di ricarica e i bonus. Questo sito accetta solo cripto, USDT su TRC20 o USDC su Base.
