Kluczowe punkty
- Użyj ChatOpenAI z bazowym URL ustawionym na API i modelem ustawionym na uncensored.
- Łańcuchy, strumieniowanie, wywoływanie funkcji i wyjście JSON przechodzą przez standardową trasę ukończeń czatu.
- Ogranicz równoległość wsadową do 8 przy pełnym kluczu lub 2 przy kluczu próbnym, aby uniknąć błędów 429.
- To jest jeden model hostowany, a nie router, więc nie ma przełączania modeli między dostawcami.
Krótka konfiguracja
Zwykłym pytaniem langchain + llm jest to, czy potrzebujesz specjalnej integracji dla endpointu innej firmy. Nie potrzebujesz. Wrapper czatu LangChaina akceptuje niestandardowy bazowy URL, a to API jest zgodne z formatem dopełnień czatu OpenAI, więc standardowa klasa działa. Zainstaluj pakiet, przekaż trzy wartości i masz obiekt modelu czatu, który możesz wstrzyknąć do dowolnego łańcucha.
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)
Pobierz klucz ze strony klucz API. Nowi użytkownicy mogą tam jednym kliknięciem po rejestracji odebrać $0.50 darmowego kredytu próbnego, co wystarczy na wielokrotne uruchomienie wszystkiego z tego artykułu. ID modelu to zawsze uncensored, a zapytania trafiają do POST /v1/chat/completions.
Uwaga na nazwę strony: mimo słowa "router" w domenie, jest to pojedynczy model o otwartych wagach uruchamiany przez niezależnego dostawcę, a nie router między dostawcami i nie żadne oficjalne API dostawcy. Nie wybierasz tu między modelami. Twój kod nazywa jeden model, i to on odpowiada.
Trzymaj klucz z dala od źródła
Wpisanie klucza na sztywno działa przy pierwszym teście i staje się problemem przy pierwszym commicie pliku. Odczytaj go ze środowiska. Biblioteki klienta OpenAI, które LangChain opakowuje, szukają OPENAI_API_KEY i OPENAI_BASE_URL domyślnie, więc możesz je ustawić w powłoce i skonstruować model z mniejszą liczbą argumentów.
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"],
)
Jawne przekazanie bazowego URL, jak powyżej, ma jedną zaletę. Jeśli inny projekt na tej samej maszynie korzysta z prawdziwej usługi OpenAI i polega na tej samej zmiennej środowiskowej, Twój jawny argument zapobiega kolizji między nimi.
Pierwszy łańcuch z szablonem promptu
Większość prawdziwej pracy używa szablonu promptu, modelu i parsera wyjścia połączonego operatorem pipe. To styl Języka Wyrażeń LangChain i nie wymaga niczego specjalnego dla niestandardowego endpointu.
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"}))
Model nie ma odrzuceń treści dla prawnego użytku dorosłego, co ma znaczenie, gdy Twój łańcuch generuje fikcję, sceny roleplay lub dialogi towarzyskie, które bardziej ostrożny model odrzuci. Jedną stałą zasadą jest to, że treści seksualne z udziałem nieletnich nigdy nie są produkowane. Zbuduj własną walidację wejścia na jej podstawie, jeśli Twój produkt ma surowsze zasady.
Strumieniowanie i użycie
API obsługuje strumieniowanie przez zdarzenia wysyłane przez serwer z stream: true, a użycie jest raportowane na końcu strumienia. W LangChain wywołujesz .stream() i iterujesz po kawałkach.
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)
Jedna rzecz do zapamiętania: strumieniowane zapytanie zajmuje jedno z Twoich slotów równoległości, aż strumień się zakończy. Jeśli Twój UI otwiera strumień, a użytkownik odchodzi bez jego zamknięcia, ten slot pozostaje zajęty. Przy pełnym kluczu masz 8 równoległych zapytań, więc kilka porzuconych strumieni może zablokować nowe. Anuluj iterator, gdy klient się rozłączy.
Wywoływanie narzędzi i agenci
Wywoływanie funkcji jest obsługiwane: przekazujesz tools i opcjonalnie tool_choice, model odpowiada tool_calls (które również mogą być strumieniowane), a Ty wysyłasz wyniki z powrotem jako wiadomości z role: "tool". W LangChain, bind_tools obsługuje za Ciebie format przesyłowy.
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"]))
Dla pełnej pętli agenta, pomocnicy agenta LangChain lub LangGraph wykonują ten cykl za Ciebie: wywołaj model, uruchom żądane narzędzie, dołącz wiadomość narzędzia, wywołaj ponownie. Użycie narzędzi podąża za standardowym schematem OpenAI, więc ten sam kod, który napisałbyś dla dowolnego kompatybilnego endpointu, działa. Jak w przypadku każdego modelu o otwartych wagach, przetestuj swoje konkretne schematy narzędzi. Trzymaj nazwy argumentów proste, opisy krótkie i listę narzędzi małą, ponieważ długie listy dają słabszym modelom więcej miejsca na wybranie tego złego.
Wyjście strukturalne w trybie JSON
Tryb JSON jest dostępny przez response_format: {"type": "json_object"}. W LangChain możesz go przekazać jako argument modelu i przeanalizować wynik samodzielnie, co daje Ci kontrolę nad walidacją i ponawianiami.
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"])
Wymów słowo "JSON" w promptie i opisz klucze, których chcesz. Tryb JSON sprawia, że wyjście jest poprawnym JSON, ale nie gwarantuje Twojego dokładnego schematu, więc sprawdź klucze po parsowaniu i ponów próbę przy niepowodzeniu. Ponieważ nieudane zapytania nie są rozliczane, pętla ponawiania dla niepoprawnego wyjścia kosztuje mało.
Równoległość, ponawianie i limity zapytań
LangChain ułatwia rozproszenie pracy za pomocą .batch(), i tam większość osób napotyka swój pierwszy limit zapytań. Pełny klucz pozwala na 8 równoległych zapytań i 300 zapytań na minutę. Klucz próbny pozwala na 2 równoległe zapytania i 60 na minutę. Przekroczysz limit, a API odpowie HTTP 429. Kod błędu to rate_limited, gdy przekroczysz liczbę zapytań na minutę, oraz concurrency, gdy za dużo zapytań wykonuje się jednocześnie. Przy tymczasowym przeciążeniu otrzymasz również 429 z nagłówkiem Retry-After: 5.
Ustaw swoją równoległość wsadową samodzielnie i pozwól klientowi ponawiać z backoff:
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))
Utrzymanie wartości 6 przy pełnym kluczu zostawia margines dla innych zapytań z tego samego konta. Przy kluczu próbnym użyj 2. Jeśli nadal widzisz błędy concurrency, szukaj strumieni, które nigdy się nie zakończyły, ponieważ każdy trzyma slot. Każda odpowiedź niesie X-Request-Id, który jest wartością do podania, jeśli skontaktujesz się z supportem, i X-Balance-USD, który pokazuje Twój pozostały kredyt.
Wywołania asynchroniczne dla aplikacji webowych
W serwerze WWW rzadko chcesz wywoływać funkcje blokujące. Każdy model czatu LangChain ma swoje asynchroniczne odpowiedniki metod, nazwane ainvoke, astream i abatch, i działają one wobec tego endpointu tak samo jak wersje synchroniczne.
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())
W usłudze asynchronicznej, strzeż liczby w locie wywołań z semaforem rozmiaru Twojego klucza, na przykład 8 przy pełnym kluczu. To utrzymuje jeden zajęty endpoint Twojej własnej aplikacji od wypełnienia każdego slotu i głodzenia innych. Przechwyć wyjątki wokół wywołania, zaloguj nagłówek X-Request-Id, gdy go masz, i pokaż użytkownikowi krótką wiadomość ponawiania zamiast stack trace.
Porada debugowania: jeśli łańcuch zachowuje się dziwnie, wydrukuj dokładne wiadomości, które model otrzymuje. Szablony promptu czasem wstawiają dodatkową spację lub pomijają zmienną, a model może odpowiedzieć tylko na to, co mu wysłano. Przełączniki verbose i debug w LangChain lub śledzenie LangSmith, jeśli już go używasz, pokazują końcową listę wiadomości.
Co oznacza okno kontekstu dla łańcuchów
Okno kontekstu wynosi 100 000 tokenów dla promptu i uzupełnienia łącznie, a max_tokens jest opcjonalne. To wystarczająco dużo dla łańcuchów pobierania, które wciskają wiele dokumentów do jednego promptu, lub dla pamięci rozmowy, która przechowuje długą historię. To również wystarczająco dużo, aby stało się to kosztowne, jeśli wysyłasz pełną historię w każdej turze bez przycinania.
Szybkie obliczenie. Krok pobierania, który wysyła 12 000 tokenów wejściowych i otrzymuje 800, kosztuje 0,012 x $0,15 + 0,0008 x $0,50 = $0,0018 + $0,0004 = $0,0022. Uruchomienie tego 1 000 razy kosztuje $2,20. Ceny to $0,15 za 1M tokenów wejściowych i $0,50 za 1M tokenów wyjściowych, bez subskrypcji, więc płacisz tylko za to, czego łańcuch faktycznie używa. Strona cennik zawiera opcje doładowania, a dokumentacja szybki start wymienia wszystkie obsługiwane parametry. Prompty nie są używane do trenowania.
