Запустіть Stanford STORM на кастомному OpenAI-сумісному ендпоінті.

Updated 2026-07-29

STORM будує кожну мовну модель як LitellmModel, а litellm приймає api_base. Впишіть https://api.apisrouter.com/v1 у спільний openai_kwargs, додайте префікс openai/ до id моделей — і всі п'ять слотів LM конвеєра статей маршрутизуються через один ендпоінт і один ключ.

Коротка відповідь: api_base в openai_kwargs, префікс openai/ на id.

LitellmModel в STORM зберігає будь-які kwargs, з якими ви його сконструювали, і об'єднує їх у кожен виклик litellm.completion(). Параметр api_base у litellm — це те, як ви спрямовуєте провайдера openai на інший хост, тож додавання api_base до словника openai_kwargs, який уже використовують власні приклади STORM, — це все перевизначення. Додайте префікс openai/ до кожного id моделі, щоб litellm говорив протоколом chat-completions до цієї бази, а рядок після скісної риски передається до шлюзу як є. Оскільки приклади будують один словник openai_kwargs і повторно використовують його для кожної моделі, один доданий ключ перенаправляє весь конвеєр. Жодних змін коду STORM, жодного форку; це стандартна поведінка knowledge_storm, накладена на задокументовану маршрутизацію 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)

Як STORM ділить статтю на п'ять слотів LM.

STORM (stanford-oval на GitHub, приблизно 30 тис. зірок) пише звіти у стилі Вікіпедії з нуля: досліджує тему через симульовані розмови з кількох перспектив, будує план з того, що дізнався, генерує повну статтю розділ за розділом, а потім полірує її. STORMWikiLMConfigs показує цей конвеєр як п'ять незалежно налаштовуваних моделей: conv_simulator_lm і question_asker_lm ведуть дослідницькі розмови, outline_gen_lm структурує статтю, article_gen_lm пише її, а article_polish_lm робить фінальний прохід. Апстрим-README прямо говорить про економіку: симулятор розмови несе найбільший обсяг викликів, тому там рекомендується швидша модель, а для генерації статті — потужніша. Ця рекомендація передбачала вибір між моделями OpenAI; за мультивендорним ендпоінтом вона узагальнюється у щось корисніше. Кожен слот — це своя LitellmModel зі своїм рядком моделі, тож дослідницька балаканина може працювати на швидкому id DeepSeek, поки генерація плану й статті працює на Claude, а полірування — на будь-якій моделі, якій ви довіряєте щодо тону, усі автентифіковані тим самим ключем проти того самого api_base. Бік пошуку — окрема машинерія: раннер STORM приймає модуль RM (You.com, Bing та кілька інших пошукових бекендів) з власним API-ключем. Зміна того, куди вказують мовні моделі, не торкається того, як отримуються джерела.

Повне налаштування: п'ять слотів, один словник kwargs.

Робочий патерн віддзеркалює власні run-скрипти репозиторію: побудуйте спільні kwargs один раз, сконструюйте одну LitellmModel на роль і призначте їх через сеттери STORMWikiLMConfigs. api_key може мати будь-яку назву, яку ви оберете, оскільки ви передаєте його явно; приклад використовує власну змінну, щоб було зрозуміло, що це не credential облікового запису OpenAI. litellm також підтримує змінні середовища на рівні провайдера, а провайдер openai зчитує OPENAI_API_BASE, тож можливе перевизначення лише через середовище. Явний шлях kwargs усе одно варто віддавати перевагу: він видимий у коді, що створив конкретну статтю, переживає запуск на машині з іншим станом середовища й дозволяє винятки по окремому слоту, якщо ви колись захочете один етап на іншому ендпоінті.

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")

Вибір моделей для кожного етапу конвеєра.

Ставтеся до п'яти сеттерів як до бюджетного важеля, а не шаблону. Апстрим-рекомендація вже каже розділяти швидкі й потужні моделі по етапах; мультивендорний ендпоінт просто розширює меню для кожного етапу. Змінюйте один слот за раз між прогонами на ту саму тему й порівнюйте виводи, з логом використання за ключем, що оцінює кожну конфігурацію.

  • conv_simulator_lm і question_asker_lm — об'ємні етапи: багатоходові симульовані інтерв'ю з кількох перспектив на тему. deepseek-v4-flash чи інший швидкий id не дає дослідницькій фазі домінувати у витратах, а недосконала балаканина прийнятна, бо вона живить нотатки, а не прозу.
  • article_gen_lm — флагманський слот. Він пише довгі, структуровані, цитовані розділи з накопиченого дослідження, що є роботою тривалої генерації, де claude-sonnet-4-6 чи gpt-5.5 явно перевершують менші id.
  • outline_gen_lm — мало викликів з непропорційним впливом, та сама форма, що й слот планування: слабкий план обмежує статтю незалежно від того, наскільки хороший письменник. Це природне місце для тестування claude-opus-4-7.
  • article_polish_lm переписує заради плавності й прибирає дублювання по всій зібраній статті, що виграє від id з довгим контекстом; gemini-3.1-pro-preview вартий бенчмаркінгу тут.

Оплата за фактом · нижче офіційних цін

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

МодельОфіційна цінаНаша ціна
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

Збої, специфічні саме для STORM.

Голий id моделі маршрутизується за висновком, а не за вашим api_base. litellm зчитує префікс, щоб обрати провайдера, і безпрефіксний id Claude виводиться як нативний виклик Anthropic, який тоді хоче ANTHROPIC_API_KEY і повністю ігнорує ваш шлюз. Кожен id, спрямований на шлюз, має нести префікс openai/; префікс називає протокол, а не вендора. Один забутий слот. Кожна LitellmModel захоплює свої kwargs при побудові. Якщо чотири слоти діляться openai_kwargs, а п'ятий побудований окремо без api_base, цей слот тихо надсилає запит до типового постачальника й падає на автентифікації, а traceback називає етап конвеєра, а не рядок конфігурації. Побудуйте кожен слот з того самого словника, і цей клас багів зникає. Збої ретрівера, звинувачені в ендпоінті. Дослідницька фаза потребує робочого пошукового бекенда; недійсний чи вичерпаний ключ ретрівера (YDC_API_KEY, BING_SEARCH_API_KEY чи будь-який RM, який ви обрали) падає під час прогонів на етапі збору інформації. Ця фаза перемежовується з викликами LM, тож читайте traceback, щоб зрозуміти, який клієнт видав помилку, перш ніж чіпати конфігурацію LM. secrets.toml демо-версії — не конфігурація вашого скрипта. Streamlit-демо читає secrets.toml; програмні прогони читають те, що передає ваш скрипт. Редагування одного, поки працює інший, — класична невідповідність. max_tokens теж на кожен слот. Приклади STORM встановлюють малі ліміти на швидких слотах (500) і більші на генерації (3000). Спрямування слота на модель для довгого тексту без підняття його max_tokens тихо обрізає розділи, що виглядає як проблема якості моделі, а насправді число конфігурації.

Хто спрямовує STORM через шлюз.

  • Команди, що генерують звіти знань в об'ємі (брифи, вікі-подібні внутрішні документи, огляди тем), де поділ на п'ять слотів робить налаштування вартості по етапах вартим реальних грошей.
  • Дослідники, що вивчають композицію конвеєра: який етап виграє від сильнішої моделі — емпіричне питання, і один ендпоінт робить перелік комбінацій слот-модель тривіальним.
  • Розробники, що запускають Claude чи Gemini у слотах письма стеку у формі OpenAI, не додаючи SDK вендора на кожну родину моделей.
  • Будь-хто, хто запускає пакетні списки тем, де об'єм дослідницької фази множиться по темах, а лог використання стає книгою обліку вартості на тему.
  • Розробники без доступу до білінгу певного постачальника. Доступ на основі поповнення без вимоги картки прибирає залежність від реєстрації в кожного провайдера.

Перевірте ендпоінт і налагодьте першу статтю.

Спочатку перелічіть моделі шлюзу: рядок після openai/ у кожному слоті має точно збігатися з обслуговуваним id. Збої першого прогону йдуть за порядком конвеєра. Помилка автентифікації, що називає Anthropic чи Google, означає, що безпрефіксний id маршрутизувався до нативного провайдера; додайте openai/. 401 від шлюзу означає, що api_key у ваших kwargs — не ключ шлюзу. Помилка model-not-found називає слот, чий id містить одруківку. Збої під час дослідницької фази, що згадують ваш пошуковий бекенд, — це облікові дані ретрівера, а не маршрутизація LM. А обрізані чи дивно короткі розділи статті зазвичай означають скупий max_tokens на слоті генерації, а не щось вище за конвеєром. Повний прогін STORM — це великий сплеск: симульовані розмови з кількох перспектив, потім план, генерація й полірування. Щойно один завершиться, консоль APIsRouter показує модель на запит, кількість токенів і витрати, що чітко мапиться на п'ять слотів і каже точно, який етап налаштувати наново перед наступною партією тем.

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

Поширені запитання

Як STORM підтримує кастомний OpenAI-сумісний ендпоінт?

Через litellm. STORM будує кожну LM як LitellmModel, яка об'єднує свої kwargs конструктора в кожен виклик litellm.completion(), а litellm приймає api_base для провайдера openai. Додайте api_base до словника openai_kwargs, і кожен слот, побудований з нього, маршрутизується до шлюзу.

Чому id моделей потребують префікса openai/?

litellm обирає провайдера за префіксом. openai/claude-sonnet-4-6 означає «говори протоколом chat-completions OpenAI до мого api_base з моделлю claude-sonnet-4-6». Без префікса litellm виводить вендора з назви і маршрутизує нативно, оминаючи ваш ендпоінт.

Чи можуть різні етапи STORM використовувати моделі різних вендорів?

Так. Кожен з п'яти слотів — незалежна LitellmModel, тож симулятор розмови може працювати на id DeepSeek, поки генерація статті працює на Claude, а полірування — на GPT, усе через той самий api_base і ключ. Апстрим уже рекомендує розділяти швидкі й потужні моделі по етапах.

Чи змінюється пошуковий ретрівер, коли я змінюю api_base?

Ні. Пошук працює через модуль RM, який ви передаєте до STORMWikiRunner (You.com, Bing та інші підтримувані бекенди) з власним ключем. Маршрутизація LM і отримання джерел — незалежні системи, що падають на різних фазах прогону.

Чи є шлях через змінні середовища замість kwargs?

litellm підтримує змінні на рівні провайдера, а провайдер openai зчитує OPENAI_API_BASE. Це працює, але явний kwarg api_base відтворюваніший: він подорожує зі скриптом, переживає машини з іншим станом середовища й дозволяє винятки по окремому слоту.

Скільки токенів споживає одна стаття STORM?

Домінує дослідницька фаза: багатоперспективні симульовані розмови множать виклики ще до того, як з'явиться перше слово статті, а потім генерація й полірування додають довгий вивід поверх. Повні прогони зазвичай сягають сотень тисяч токенів, і вигляд використання за ключем показує точний поділ по етапах.