PL ▾
Pobierz klucz API

LangChain + LLM: Podłącz API bez cenzury

LangChain łączy się z dowolnym endpointem kompatybilnym z OpenAI przez swoją klasę ChatOpenAI. Ustaw bazowy URL, klucz i ID modelu, a Twoje łańcuchy i agenci będą działać na tym API.

Zaktualizowano

Połączone bloki tworzące łańcuch przekazujący dane do centralnego, świecącego węzła, reprezentującego potoki LangChain wywołujące jedno API

Kluczowe punkty

  1. Użyj ChatOpenAI z bazowym URL ustawionym na API i modelem ustawionym na uncensored.
  2. Łańcuchy, strumieniowanie, wywoływanie funkcji i wyjście JSON przechodzą przez standardową trasę ukończeń czatu.
  3. Ogranicz równoległość wsadową do 8 przy pełnym kluczu lub 2 przy kluczu próbnym, aby uniknąć błędów 429.
  4. 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.

Pytania i odpowiedzi

Czy potrzebujesz specjalnego pakietu LangChain dla tego endpointu?

Nie. Wystarczy pakiet langchain-openai. Przekaż base URL, swój klucz i model ID uncensored do ChatOpenAI.

Czy to działa z LangGraph i agentami?

Tak, o ile korzystają ze standardowego formatu czatu i wywoływania funkcji OpenAI. Wywołania narzędzi, strumieniowane tool_calls i wyniki roli tool są obsługiwane.

Czy mogę przełączać się między modelami wewnątrz łańcucha?

Nie. Istnieje jeden model, uncensored, a usługa nie jest routerem między dostawcami. Użyj osobnego obiektu modelu LangChain, jeśli potrzebujesz innego dostawcy dla kolejnego kroku.

Co zrobić z błędami 429?

Obniż współbieżność wsadową, szanuj nagłówek Retry-After, gdy jest obecny, i upewnij się, że zakończone strumienie są zamknięte. Pełny klucz pozwala na 8 równoległych zapytań i 300 na minutę.

Czy embeddingi są dostępne dla mojego magazynu wektorowego?

Nie. API jest tylko tekstowe i nie ma endpointu embeddingów, więc potrzebujesz oddzielnego źródła embeddingów do wyszukiwania.

Twój klucz jest o jeden formularz stąd

Utwórz konto, skopiuj klucz, zmień bazowy URL. To cała konfiguracja.

Pobierz klucz API