Wichtige Punkte
- Verwende ChatOpenAI mit base_url, das auf die API gesetzt ist, und model, das auf uncensored gesetzt ist.
- Chains, Streaming, Function Calling und JSON-Ausgabe laufen alle über den Standard-Chat-Endpunkt.
- Begrenze die parallele Batch-Anfragen auf 8 bei einem regulären Schlüssel oder auf 2 bei einem Test-Schlüssel, um 429-Fehler zu vermeiden.
- Dies ist ein gehostetes Modell, kein Router, daher gibt es keinen anbieterabhängigen Modellwechsel.
Die kurze Einrichtung
Die übliche langchain + llm-Frage ist, ob du eine spezielle Integration für einen Drittanbieter-Endpunkt benötigst. Das tust du nicht. LangChain's OpenAI-Chat-Wrapper akzeptiert eine benutzerdefinierte Basis-URL, und diese API folgt dem OpenAI-Chat-Completion-Format, daher funktioniert die Standardklasse. Installiere das Paket, übergebe drei Werte, und du hast ein Chat-Modell-Objekt, das du in jede Chain einfügen kannst.
pip install -U langchain-openai langchain-core
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="uncensored",
base_url="https://api.nsfwllmrouter.com/v1",
api_key="YOUR_API_KEY",
temperature=0.7,
)
print(llm.invoke("Give me one sentence about LangChain.").content)
Hole den Schlüssel auf der API-Schlüssel-Seite. Neue Nutzer können dort nach der Anmeldung mit einem Klick $0,50 an Testguthaben beanspruchen, was ausreicht, um alles in diesem Artikel viele Male durchzuführen. Die Modell-ID ist immer uncensored, und die Anfragen gehen an POST /v1/chat/completions.
Ein Hinweis zum Domainnamen: Trotz des Wortes „Router“ in der Domain ist dies ein einzelnes Open-Weight-Modell, das von einem unabhängigen Anbieter betrieben wird, kein Router über Anbieter hinweg und keine offizielle API eines Anbieters. Du wählst hier nicht zwischen Modellen. Dein Code benennt ein Modell, und genau das antwortet.
Halte den Schlüssel aus dem Quellcode
Das Hardcodieren eines Schlüssels funktioniert für einen ersten Test, wird aber zum Problem, sobald du die Datei committest. Lies ihn stattdessen aus der Umgebung aus. Die OpenAI-Client-Bibliotheken, die LangChain umschließt, suchen standardmäßig nach OPENAI_API_KEY und OPENAI_BASE_URL, sodass du sie in deiner Shell setzen und das Modell mit weniger Argumenten erstellen kannst.
export OPENAI_API_KEY="YOUR_API_KEY"
export OPENAI_BASE_URL="https://api.nsfwllmrouter.com/v1"
import os
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="uncensored",
base_url=os.environ.get("OPENAI_BASE_URL", "https://api.nsfwllmrouter.com/v1"),
api_key=os.environ["OPENAI_API_KEY"],
)
Das explizite Übergeben der Basis-URL, wie oben gezeigt, hat einen Vorteil. Wenn ein anderes Projekt auf derselben Maschine den echten OpenAI-Dienst verwendet und sich auf dieselbe Umgebungsvariable verlässt, verhindert dein explizites Argument, dass die beiden kollidieren.
Eine erste Chain mit einer Prompt-Vorlage
Die meisten echten Arbeiten verwenden eine Prompt-Vorlage, das Modell und einen Output-Parser, die mit dem Pipe-Operator verbunden sind. Dies ist der Stil der LangChain Expression Language und benötigt für einen benutzerdefinierten Endpunkt nichts Besonderes.
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="uncensored",
base_url="https://api.nsfwllmrouter.com/v1",
api_key="YOUR_API_KEY",
)
prompt = ChatPromptTemplate.from_messages([
("system", "You write short story openings in the style the user asks for."),
("human", "Genre: {genre}\nSetting: {setting}\nWrite three sentences."),
])
chain = prompt | llm | StrOutputParser()
print(chain.invoke({"genre": "noir mystery", "setting": "a rainy harbor town"}))
Das Modell hat keine Inhaltsfilter für die rechtmäßige Nutzung durch Erwachsene, was wichtig ist, wenn deine Chain Fiktion, Rollenspielszenen oder Gesprächsdialoge generiert, die ein vorsichtigeres Modell ablehnen würde. Die einzige feste Regel ist, dass sexuelle Inhalte mit Minderjährigen niemals erzeugt werden. Baue darauf aufbauend deine eigene Eingabevalidierung, wenn dein Produkt strengere Regeln hat.
Streaming und Nutzung
Die API unterstützt Streaming über Server-Sent Events mit stream: true, und die Nutzung wird am Ende des Streams gemeldet. In LangChain rufst du .stream() auf und iterierst über die Chunks.
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="uncensored",
base_url="https://api.nsfwllmrouter.com/v1",
api_key="YOUR_API_KEY",
)
for chunk in llm.stream("Write a four-line poem about debugging at night."):
print(chunk.content, end="", flush=True)
Ein Detail, das du im Kopf behalten solltest: Eine gestreamte Anfrage belegt einen deiner Konkurrenz-Slots, bis der Stream endet. Wenn deine UI einen Stream öffnet und der Benutzer ohne ihn zu schließen weggeht, bleibt dieser Slot belegt. Bei einem vollen Schlüssel hast du 8 parallele Anfragen, sodass ein paar verlassene Streams neue blockieren können. Unterbrich den Iterator, wenn der Client die Verbindung trennt.
Tool Calling und Agents
Tool Calling wird unterstützt: Du übergibst tools und optional tool_choice, das Modell antwortet mit tool_calls (was auch gestreamt werden kann), und du sendest Ergebnisse als Nachrichten mit role: "tool" zurück. In LangChain übernimmt bind_tools das Datenformat für dich.
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
@tool
def word_count(text: str) -> int:
'Count the words in a piece of text.'
return len(text.split())
llm = ChatOpenAI(
model="uncensored",
base_url="https://api.nsfwllmrouter.com/v1",
api_key="YOUR_API_KEY",
)
llm_with_tools = llm.bind_tools([word_count])
msg = llm_with_tools.invoke("How many words are in: the quick brown fox?")
for call in msg.tool_calls:
print(call["name"], call["args"], word_count.invoke(call["args"]))
Für eine vollständige Agent-Schleife führen LangChains Agent-Helfer oder LangGraph diesen Zyklus für dich aus: Modell aufrufen, angefordertes Tool ausführen, Tool-Nachricht anhängen, erneut aufrufen. Die Tool-Nutzung folgt der Standard-OpenAI-Struktur, daher funktioniert derselbe Code, den du für jeden kompatiblen Endpunkt schreiben würdest. Teste wie bei jedem Open-Weight-Modell deine spezifischen Tool-Schemata. Halte Argumentnamen einfach, Beschreibungen kurz und die Liste der Tools klein, da lange Listen schwächeren Modellen mehr Spielraum geben, das falsche auszuwählen.
Strukturierte Ausgabe mit JSON-Modus
Der JSON-Modus ist über response_format: {"type": "json_object"} verfügbar. In LangChain kannst du ihn als Modellargument übergeben und das Ergebnis selbst analysieren, was dir die Kontrolle über Validierung und Wiederholungen gibt.
import json
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="uncensored",
base_url="https://api.nsfwllmrouter.com/v1",
api_key="YOUR_API_KEY",
model_kwargs={"response_format": {"type": "json_object"}},
)
msg = llm.invoke(
"Return a JSON object with keys title and tags (a list of three strings) "
"for an article about hiking."
)
data = json.loads(msg.content)
print(data["title"], data["tags"])
Sage das Wort „JSON“ im Prompt und beschreibe die Schlüssel, die du möchtest. Der JSON-Modus macht die Ausgabe zu gültigem JSON, garantiert aber nicht dein exaktes Schema, also prüfe die Schlüssel nach der Analyse und wiederhole bei einem Fehler. Da fehlgeschlagene Anfragen nicht berechnet werden, kostet eine Wiederholungsschleife für fehlerhafte Ausgaben wenig.
Parallele Anfragen, Wiederholungen und Ratenlimits
LangChain macht es einfach, Aufgaben mit .batch() zu verteilen, und genau dort stoßen die meisten Nutzer auf ihr erstes Ratenlimit. Ein regulärer Schlüssel erlaubt 8 parallele Anfragen und 300 Anfragen pro Minute. Ein Test-Schlüssel erlaubt 2 parallele Anfragen und 60 pro Minute. Überschreitest du das Limit, antwortet die API mit HTTP 429. Der Fehlercode ist rate_limited, wenn du das Limit bei Anfragen pro Minute überschreitest, und concurrency, wenn zu viele Anfragen gleichzeitig laufen. Bei temporärer Überlastung erhältst du ebenfalls eine 429-Antwort mit einem Retry-After: 5-Header.
Setze die parallele Batch-Anfragen selbst fest und lass den Client mit Backoff wiederholen:
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="uncensored",
base_url="https://api.nsfwllmrouter.com/v1",
api_key="YOUR_API_KEY",
max_retries=4,
timeout=120,
)
inputs = [f"Summarize idea number {i} in one line." for i in range(40)]
results = llm.batch(inputs, config={"max_concurrency": 6})
print(len(results))
Ein Wert von 6 bei einem regulären Schlüssel lässt Spielraum für andere Anfragen desselben Kontos. Nutze bei einem Test-Schlüssel den Wert 2. Wenn du weiterhin concurrency-Fehler siehst, suche nach Streams, die nie beendet wurden, da jeder davon einen Slot belegt. Jede Antwort enthält X-Request-Id, den Wert, den du bei einer Kontaktaufnahme mit dem Support angeben solltest, sowie X-Balance-USD, das dein verbleibendes Guthaben anzeigt.
Asynchrone Aufrufe für Web-Apps
Innerhalb eines Webservers möchtest du selten blockierende Aufrufe. Jedes LangChain-Chat-Modell hat asynchrone Zwillinge seiner Methoden, benannt als ainvoke, astream und abatch, und sie funktionieren gegen diesen Endpunkt genauso wie die synchronen Versionen.
import asyncio
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="uncensored",
base_url="https://api.nsfwllmrouter.com/v1",
api_key="YOUR_API_KEY",
)
async def main():
async for chunk in llm.astream("Describe a quiet harbor at dawn in two sentences."):
print(chunk.content, end="", flush=True)
asyncio.run(main())
Schütze in einem asynchronen Dienst die Anzahl der laufenden Aufrufe mit einem Semaphore, das auf deinen Schlüssel abgestimmt ist, z. B. 8 bei einem vollen Schlüssel. So verhinderst du, dass ein ausgelasteter Endpunkt deiner eigenen App alle Slots belegt und andere verhungern. Fange Ausnahmen um den Aufruf herum ab, protokolliere den X-Request-Id-Header, wenn du ihn hast, und zeige dem Benutzer eine kurze Wiederholungsnachricht anstelle eines Stack-Traces.
Debugging-Tipp: Wenn eine Chain sich seltsam verhält, drucke die exakten Nachrichten, die das Modell erhält. Prompt-Vorlagen fügen manchmal zusätzlichen Leerraum ein oder lassen eine Variable weg, und das Modell kann nur antworten, was es erhalten hat. LangChains verbose- und Debug-Schalter oder LangSmith-Tracing, wenn du es bereits nutzt, zeigen die finale Nachrichtenliste.
Was das Kontextfenster für Chains bedeutet
Das Kontextfenster beträgt 100.000 Token für Prompt und Vervollständigung zusammen, und max_tokens ist optional. Das ist groß genug für Retrieval-Chains, die viele Dokumente in einen Prompt packen, oder für ein Gesprächsspeicher, der eine lange Historie behält. Es ist auch groß genug, um teuer zu werden, wenn du jede Runde eine volle Historie erneut sendest, ohne sie zu kürzen.
Eine schnelle Berechnung. Ein Retrieval-Schritt, der 12.000 Input-Token sendet und 800 zurückbekommt, kostet 0,012 x 0,15 $ + 0,0008 x 0,50 $ = 0,0018 $ + 0,0004 $ = 0,0022 $. Führe das 1.000 Mal aus, zahlst du 2,20 $. Die Preise liegen bei 0,15 $ pro 1M Input-Token und 0,50 $ pro 1M Output-Token, ohne Abonnement, also zahlst du nur für das, was die Chain tatsächlich nutzt. Die Preisseite enthält die Aufladeoptionen, und die Quickstart-Dokumentation listet alle unterstützten Parameter auf. Prompts werden nicht zum Training verwendet.
