Uruchom Stanford STORM na niestandardowym endpoincie kompatybilnym z OpenAI.

Updated 2026-07-29

STORM buduje każdy model językowy jako LitellmModel, a litellm akceptuje api_base. Umieść https://api.apisrouter.com/v1 we wspólnym openai_kwargs, poprzedź identyfikatory modeli prefiksem openai/, a wszystkie pięć slotów LM pipeline'u artykułu będzie kierowanych przez jeden endpoint i jeden klucz.

Szybka odpowiedź: api_base w openai_kwargs, prefiks openai/ na identyfikatorach.

LitellmModel w STORM przechowuje dowolne kwargs, z jakimi go konstruujesz, i scala je do każdego wywołania litellm.completion(). Parametr api_base w litellm to sposób, w jaki wskazujesz dostawcę openai na inny host, więc dodanie api_base do słownika openai_kwargs, którego już używają własne przykłady STORM, jest całym nadpisaniem. Poprzedź każdy identyfikator modelu prefiksem openai/, żeby litellm mówił protokołem chat-completions do tej bazy, a string po ukośniku jest przekazywany do bramki. Ponieważ przykłady budują jeden słownik openai_kwargs i używają go ponownie dla każdego modelu, jeden dodany klucz przekierowuje cały pipeline. Żadnych zmian w kodzie STORM, żadnego forka; to standardowe zachowanie knowledge_storm nałożone na udokumentowany routing litellm.

openai_kwargs = {
    "api_key": os.getenv("APISROUTER_API_KEY"),
    "api_base": "https://api.apisrouter.com/v1",
    "temperature": 1.0,
    "top_p": 0.9,
}
fast = LitellmModel(model="openai/deepseek-v4-flash", max_tokens=500, **openai_kwargs)
strong = LitellmModel(model="openai/claude-sonnet-4-6", max_tokens=3000, **openai_kwargs)

Jak STORM dzieli artykuł na pięć slotów LM.

STORM (stanford-oval na GitHubie, około 30 tys. gwiazdek) pisze od zera raporty w stylu Wikipedii: bada temat przez symulowane rozmowy wieloperspektywiczne, buduje konspekt z tego, czego się nauczył, generuje pełny artykuł sekcja po sekcji, a potem go poleruje. STORMWikiLMConfigs eksponuje ten pipeline jako pięć niezależnie ustawialnych modeli: conv_simulator_lm i question_asker_lm napędzają rozmowy badawcze, outline_gen_lm strukturyzuje artykuł, article_gen_lm go pisze, a article_polish_lm wykonuje ostatnie przejście. Upstreamowy README jest wprost o ekonomice: symulator rozmów działa z najwyższym wolumenem wywołań, więc rekomenduje tam szybszy model, a mocniejszy model do generowania artykułu. Ta wskazówka zakładała wybór między modelami OpenAI; za wielodostawcowym endpointem uogólnia się w coś bardziej użytecznego. Każdy slot to własny LitellmModel z własnym stringiem modelu, więc badawcza rozmowa może działać na szybkim identyfikatorze DeepSeek, podczas gdy generowanie konspektu i artykułu działa na Claude, a polerowanie na dowolnym modelu, któremu ufasz co do tonu, wszystko uwierzytelnione tym samym kluczem względem tego samego api_base. Strona retrievalu to osobna maszyneria: runner STORM przyjmuje moduł RM (You.com, Bing i kilka innych backendów wyszukiwania) z własnym kluczem API. Zmiana tego, gdzie wskazują modele językowe, nie dotyka tego, jak pobierane są źródła.

Pełna konfiguracja: pięć slotów, jeden słownik kwargs.

Działający wzorzec odzwierciedla własne skrypty uruchomieniowe repozytorium: zbuduj wspólne kwargs raz, skonstruuj jeden LitellmModel per rola i przypisz je przez settery STORMWikiLMConfigs. api_key może mieć dowolną nazwę, jaką lubisz, ponieważ przekazujesz go jawnie; przykład używa własnej zmiennej, żeby jasno pokazać, że to nie jest poświadczenie konta OpenAI. litellm honoruje też zmienne środowiskowe na poziomie dostawcy, a dostawca openai czyta OPENAI_API_BASE, więc możliwe jest nadpisanie wyłącznie przez środowisko. Ścieżka jawnych kwargs wciąż jest tą, którą warto preferować: jest widoczna w kodzie, który wyprodukował dany artykuł, przetrwa uruchomienie na maszynie z innym stanem środowiska i umożliwia wyjątki per slot, jeśli kiedykolwiek zechcesz mieć jeden etap na innym endpoincie.

import os
from knowledge_storm import STORMWikiRunnerArguments, STORMWikiRunner, STORMWikiLMConfigs
from knowledge_storm.lm import LitellmModel
from knowledge_storm.rm import YouRM

openai_kwargs = {
    "api_key": os.getenv("APISROUTER_API_KEY"),
    "api_base": "https://api.apisrouter.com/v1",
    "temperature": 1.0,
    "top_p": 0.9,
}
fast = LitellmModel(model="openai/deepseek-v4-flash", max_tokens=500, **openai_kwargs)
strong = LitellmModel(model="openai/claude-sonnet-4-6", max_tokens=3000, **openai_kwargs)

lm_configs = STORMWikiLMConfigs()
lm_configs.set_conv_simulator_lm(fast)
lm_configs.set_question_asker_lm(fast)
lm_configs.set_outline_gen_lm(strong)
lm_configs.set_article_gen_lm(strong)
lm_configs.set_article_polish_lm(strong)

engine_args = STORMWikiRunnerArguments(output_dir="./results")
rm = YouRM(ydc_api_key=os.getenv("YDC_API_KEY"), k=engine_args.search_top_k)
runner = STORMWikiRunner(engine_args, lm_configs, rm)
runner.run(topic="Small modular reactors")

Dobór modeli per etap pipeline'u.

Traktuj pięć setterów jako pokrętło budżetu, nie boilerplate. Wskazówka upstream już mówi, żeby rozdzielić szybkie i mocne modele między etapy; wielodostawcowy endpoint po prostu poszerza menu per etap. Zmieniaj jeden slot na raz między uruchomieniami na tym samym temacie i porównuj wyniki, a log użycia per klucz wycenia każdą konfigurację.

  • conv_simulator_lm i question_asker_lm to etapy wolumenowe: symulowane wielotorowe wywiady w kilku perspektywach na temat. deepseek-v4-flash albo inny szybki identyfikator powstrzymuje fazę badawczą przed zdominowaniem wydatków, a niedoskonała rozmowa jest tolerowalna, ponieważ karmi notatki, nie prozę.
  • article_gen_lm to slot flagowy. Pisze długie, ustrukturyzowane, cytowane sekcje z zebranych badań, co jest pracą podtrzymanego generowania, gdzie claude-sonnet-4-6 albo gpt-5.5 widocznie przewyższają mniejsze identyfikatory.
  • outline_gen_lm to niewiele wywołań o nieproporcjonalnie dużej dźwigni, ten sam kształt co slot planujący: słaby konspekt ogranicza artykuł, bez względu na to, jak dobry jest piszący. To naturalne miejsce, żeby przetestować claude-opus-4-7.
  • article_polish_lm przepisuje dla płynności i usuwa duplikaty w złożonym artykule, co korzysta z identyfikatora o długim kontekście; warto tu zbenchmarkować gemini-3.1-pro-preview.

Płatność za użycie · poniżej cen oficjalnych

Selected models are priced below official list prices. Exact input, output, cache, and per-request prices are shown for each model.

ModelCena oficjalnaNasza cena
DeepSeek V4 Flash$0.14 / $0.28 per M$0.10 / $0.30 per M
Claude Sonnet 4.6$3.00 / $15.00 per M$2.40 / $12.00 per M
Claude Opus 4.7$5.00 / $25.00 per M$4.00 / $20.00 per M
GPT-5.5$5.00 / $30.00 per M$4.00 / $24.00 per M
Gemini 3.1 Pro Preview$2.00 / $12.00 per M$1.60 / $9.60 per M

Tryby awarii charakterystyczne dla STORM.

Goły identyfikator modelu jest kierowany przez wnioskowanie, nie przez Twój api_base. litellm czyta prefiks, żeby wybrać dostawcę, a identyfikator Claude bez prefiksu zostaje wywnioskowany jako natywne wywołanie Anthropic, które wtedy chce ANTHROPIC_API_KEY i całkowicie ignoruje Twoją bramkę. Każdy identyfikator zmierzający do bramki musi nosić prefiks openai/; prefiks nazywa protokół, nie dostawcę. Jeden slot pozostawiony w tyle. Każdy LitellmModel przechwytuje swoje kwargs w momencie konstrukcji. Jeśli cztery sloty dzielą openai_kwargs, a piąty został zbudowany doraźnie bez api_base, ten slot po cichu wysyła do domyślnego dostawcy i zawodzi na uwierzytelnianiu, a traceback nazywa etap pipeline'u, a nie linię konfiguracji. Zbuduj każdy slot z tego samego słownika, a ta klasa błędu znika. Awarie retrievera obwiniane na endpoint. Faza badawcza potrzebuje działającego backendu wyszukiwania; nieważny albo wyczerpany klucz retrievera (YDC_API_KEY, BING_SEARCH_API_KEY albo dowolny wybrany RM) zawodzi uruchomienia podczas zbierania informacji. Ta faza przeplata się z wywołaniami LM, więc przeczytaj traceback, żeby zobaczyć, który klient rzucił błąd, zanim dotkniesz konfiguracji LM. secrets.toml demo to nie konfiguracja Twojego skryptu. Demo Streamlit czyta secrets.toml; uruchomienia programistyczne czytają to, co przekazuje Twój skrypt. Edytowanie jednego podczas uruchamiania drugiego to klasyczna niezgodność. max_tokens jest też per slot. Przykłady STORM ustawiają małe limity na szybkich slotach (500) i większe na generowaniu (3000). Wskazanie slotu na model długoformowy bez podniesienia jego max_tokens po cichu przycina sekcje, co wygląda jak problem jakości modelu, ale jest liczbą konfiguracji.

Kto kieruje STORM przez bramkę.

  • Zespoły generujące raporty wiedzy w wolumenie (briefy, wewnętrzne dokumenty w stylu wiki, wprowadzenia do tematów), gdzie podział na pięć slotów czyni dostrajanie kosztu per etap wartym prawdziwych pieniędzy.
  • Badacze studiujący kompozycję pipeline'u: który etap korzysta z mocniejszego modelu, to pytanie empiryczne, a jeden endpoint czyni siatkę kombinacji slot-model trywialną do wyliczenia.
  • Twórcy uruchamiający Claude albo Gemini w slotach piszących stosu w kształcie OpenAI, bez dodawania SDK dostawcy na każdą rodzinę modeli.
  • Każdy, kto uruchamia wsadowe listy tematów, gdzie wolumen fazy badawczej mnoży się przez tematy, a log użycia staje się księgą kosztów per temat.
  • Deweloperzy bez dostępu do rozliczeń danego dostawcy. Dostęp oparty na doładowaniu, bez wymogu karty, usuwa zależność od rejestracji u każdego dostawcy z osobna.

Zweryfikuj endpoint i debuguj pierwszy artykuł.

Wylistuj najpierw modele bramki: string po openai/ w każdym slocie musi dokładnie zgadzać się z obsługiwanym identyfikatorem. Awarie pierwszego uruchomienia podążają za kolejnością pipeline'u. Błąd uwierzytelniania wymieniający Anthropic albo Google oznacza, że identyfikator bez prefiksu został skierowany do natywnego dostawcy; dodaj openai/. 401 z bramki oznacza, że api_key w Twoich kwargs nie jest kluczem bramki. Błąd model-not-found nazywa slot, którego identyfikator ma literówkę. Awarie podczas fazy badawczej wspominające Twój backend wyszukiwania to poświadczenia retrievera, nie routing LM. A przycięte albo dziwnie krótkie sekcje artykułu to zwykle skąpe max_tokens na slocie generowania, a nie coś w upstream. Pełne uruchomienie STORM to duży wybuch: symulowane rozmowy w różnych perspektywach, potem konspekt, generowanie i polerowanie. Gdy jedno się zakończy, konsola APIsRouter pokazuje model per żądanie, liczbę tokenów i wydatki, co czysto mapuje się na pięć slotów i mówi Ci dokładnie, który etap dostroić przed następną partią tematów.

curl -s https://api.apisrouter.com/v1/models \
  -H "Authorization: Bearer $APISROUTER_API_KEY" | head -50

Częste pytania

Jak STORM wspiera niestandardowy endpoint kompatybilny z OpenAI?

Przez litellm. STORM buduje każdy LM jako LitellmModel, który scala swoje kwargs konstruktora do każdego wywołania litellm.completion(), a litellm akceptuje api_base dla dostawcy openai. Dodaj api_base do słownika openai_kwargs, a każdy zbudowany z niego slot kieruje ruch do bramki.

Dlaczego identyfikatory modeli potrzebują prefiksu openai/?

litellm wybiera dostawcę z prefiksu. openai/claude-sonnet-4-6 oznacza "mów protokołem chat-completions OpenAI do mojego api_base z modelem claude-sonnet-4-6". Bez prefiksu litellm wnioskuje dostawcę z nazwy i kieruje natywnie, omijając Twój endpoint.

Czy różne etapy STORM mogą używać modeli różnych dostawców?

Tak. Każdy z pięciu slotów to niezależny LitellmModel, więc symulator rozmowy może działać na identyfikatorze DeepSeek, podczas gdy generowanie artykułu działa na Claude, a polerowanie na GPT, wszystko przez ten sam api_base i klucz. Upstream już rekomenduje rozdzielanie szybkich i mocnych modeli między etapy.

Czy retriever wyszukiwania zmienia się, gdy zmieniam api_base?

Nie. Retrieval działa przez moduł RM, który przekazujesz do STORMWikiRunner (You.com, Bing i inne wspierane backendy) z własnym kluczem. Routing LM i retrieval źródeł to niezależne systemy, które zawodzą w różnych fazach uruchomienia.

Czy istnieje ścieżka zmiennej środowiskowej zamiast kwargs?

litellm honoruje zmienne na poziomie dostawcy, a dostawca openai czyta OPENAI_API_BASE. To działa, ale jawny kwarg api_base jest bardziej odtwarzalny: podróżuje ze skryptem, przetrwa maszyny z innym stanem środowiska i pozwala na wyjątki per slot.

Ile tokenów zużywa jeden artykuł STORM?

Faza badawcza dominuje: wieloperspektywiczne symulowane rozmowy mnożą wywołania, zanim powstanie choć jedno słowo artykułu, potem generowanie i polerowanie dokładają długoformowe wyjście na wierzch. Pełne uruchomienia zwykle lądują w setkach tysięcy tokenów, a widok użycia per klucz pokazuje dokładny podział per etap.