Ejecuta Stanford STORM en un endpoint personalizado compatible con OpenAI.

Updated 2026-07-29

STORM construye cada modelo de lenguaje como un LitellmModel, y litellm acepta api_base. Pon https://api.apisrouter.com/v1 en tu openai_kwargs compartido, antepón openai/ a los ids de modelo, y los cinco slots de LM del pipeline de artículos se enrutan a través de un endpoint y una clave.

Respuesta rápida: api_base en openai_kwargs, prefijo openai/ en los ids.

El LitellmModel de STORM guarda cualquier kwarg con el que lo construyas y los mezcla en cada llamada litellm.completion(). El parámetro api_base de litellm es cómo apuntas al proveedor openai hacia un host distinto, así que añadir api_base al diccionario openai_kwargs que ya usan los propios ejemplos de STORM es todo el override. Antepón openai/ a cada id de modelo para que litellm hable el protocolo de chat-completions con esa base, y el string tras la barra se pasa tal cual al gateway. Como los ejemplos construyen un diccionario openai_kwargs y lo reutilizan para cada modelo, una clave añadida reenruta todo el pipeline. Sin cambios de código en STORM, sin fork; esto es comportamiento estándar de knowledge_storm sobre el enrutamiento documentado de 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)

Cómo divide STORM un artículo entre cinco slots de LM.

STORM (stanford-oval en GitHub, unas 30K estrellas) escribe informes al estilo Wikipedia desde cero: investiga un tema a través de conversaciones simuladas multi-perspectiva, construye un esquema a partir de lo aprendido, genera el artículo completo sección por sección, y luego lo pule. STORMWikiLMConfigs expone ese pipeline como cinco modelos configurables de forma independiente: conv_simulator_lm y question_asker_lm impulsan las conversaciones de investigación, outline_gen_lm estructura el artículo, article_gen_lm lo escribe, y article_polish_lm hace la pasada final. El README upstream es explícito sobre la economía: el simulador de conversación ejecuta el mayor volumen de llamadas, así que recomienda un modelo más rápido ahí y uno más potente para la generación del artículo. Esa guía asumía elegir entre modelos de OpenAI; detrás de un endpoint multi-proveedor se generaliza en algo más útil. Cada slot es su propio LitellmModel con su propio string de modelo, así que la charla de investigación puede correr sobre un id rápido de DeepSeek mientras el esquema y la generación del artículo corren sobre Claude, y el pulido sobre el modelo en el que confíes para el tono, todo autenticado por la misma clave contra el mismo api_base. El lado de recuperación es maquinaria separada: el runner de STORM toma un módulo RM (You.com, Bing, y varios otros backends de búsqueda) con su propia clave de API. Cambiar hacia dónde apuntan los modelos de lenguaje no toca cómo se obtienen las fuentes.

Configuración completa: cinco slots, un diccionario de kwargs.

El patrón que funciona refleja los propios scripts de ejecución del repositorio: construye los kwargs compartidos una vez, construye un LitellmModel por rol, y asígnalos a través de los setters de STORMWikiLMConfigs. El api_key puede tener cualquier nombre que quieras ya que lo pasas explícitamente; el ejemplo usa su propia variable para dejar claro que esto no es una credencial de cuenta de OpenAI. litellm también respeta las variables de entorno a nivel de proveedor, y el proveedor openai lee OPENAI_API_BASE, así que es posible un override solo por entorno. La ruta explícita con kwargs sigue siendo la que se debe preferir: es visible en el código que produjo un artículo dado, sobrevive a ejecutarse en una máquina con distinto estado de entorno, y hace posibles excepciones por slot si alguna vez quieres que una etapa use un endpoint distinto.

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

Elegir modelos por etapa del pipeline.

Trata los cinco setters como un dial de presupuesto, no como código repetitivo. La guía upstream ya dice que dividas modelos rápidos y potentes entre etapas; un endpoint multi-proveedor solo amplía el menú por etapa. Cambia un slot a la vez entre ejecuciones sobre el mismo tema y diferencia las salidas, con el log de uso por clave tasando cada configuración.

  • conv_simulator_lm y question_asker_lm son las etapas de volumen: entrevistas simuladas de varios turnos a través de varias perspectivas por tema. deepseek-v4-flash u otro id rápido evita que la fase de investigación domine el gasto, y una charla imperfecta es tolerable porque alimenta notas, no prosa.
  • article_gen_lm es el slot insignia. Escribe secciones largas, estructuradas y citadas a partir de la investigación acumulada, que es trabajo de generación sostenida donde claude-sonnet-4-6 o gpt-5.5 superan visiblemente a ids más pequeños.
  • outline_gen_lm son pocas llamadas con un apalancamiento desproporcionado, la misma forma que un slot de planificación: un esquema débil limita el artículo sin importar lo bueno que sea el escritor. Es el lugar natural para probar claude-opus-4-7.
  • article_polish_lm reescribe para dar fluidez y elimina duplicación a través del artículo ensamblado, lo que se beneficia de un id de contexto largo; gemini-3.1-pro-preview merece hacer benchmark aquí.

Pago por uso · por debajo del precio oficial

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

ModeloPrecio oficialNuestro precio
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

Los modos de fallo específicos de STORM.

Un id de modelo desnudo se enruta por inferencia, no por tu api_base. litellm lee el prefijo para elegir un proveedor, y un id de Claude sin prefijo se infiere como una llamada nativa de Anthropic, que entonces pide ANTHROPIC_API_KEY e ignora tu gateway por completo. Cada id destinado al gateway debe llevar el prefijo openai/; el prefijo nombra el protocolo, no el proveedor. Un slot que se queda atrás. Cada LitellmModel captura sus kwargs en la construcción. Si cuatro slots comparten openai_kwargs y un quinto se construyó de forma improvisada sin api_base, ese slot publica silenciosamente al proveedor por defecto y falla en autenticación, y el traceback nombra una etapa del pipeline en lugar de una línea de configuración. Construye cada slot desde el mismo diccionario y esta clase de bug desaparece. Fallos del recuperador atribuidos al endpoint. La fase de investigación necesita un backend de búsqueda funcionando; una clave de recuperador inválida o agotada (YDC_API_KEY, BING_SEARCH_API_KEY, o el RM que hayas elegido) falla durante la recolección de información. Esa fase se intercala con las llamadas de LM, así que lee el traceback para ver qué cliente lanzó el error antes de tocar la configuración del LM. El secrets.toml de la demo no es la configuración de tu script. La demo de Streamlit lee secrets.toml; las ejecuciones programáticas leen lo que tu script pasa. Editar uno mientras corre el otro es un desajuste clásico. max_tokens también es por slot. Los ejemplos de STORM configuran límites pequeños en los slots rápidos (500) y más grandes en generación (3000). Apuntar un slot a un modelo de formato largo sin subir su max_tokens trunca silenciosamente las secciones, lo que parece un problema de calidad de modelo pero es un número de configuración.

Quién enruta STORM a través de un gateway.

  • Equipos que generan informes de conocimiento a volumen (briefs, documentos internos al estilo wiki, primers de tema), donde la división en cinco slots hace que el ajuste de coste por etapa valga dinero real.
  • Investigadores que estudian la composición del pipeline: qué etapa se beneficia de un modelo más fuerte es una pregunta empírica, y un endpoint hace trivial enumerar la cuadrícula de combinaciones slot-modelo.
  • Creadores que ejecutan Claude o Gemini en los slots de escritura de una pila con forma de OpenAI, sin añadir un SDK de proveedor por familia de modelos.
  • Cualquiera que ejecute listas de temas por lotes, donde el volumen de la fase de investigación se multiplica entre temas y el log de uso se convierte en el libro de costes por tema.
  • Desarrolladores sin acceso a la facturación de un proveedor concreto. El acceso mediante recarga sin necesidad de tarjeta elimina la dependencia de registrarse en cada proveedor.

Verifica el endpoint y depura el primer artículo.

Lista primero los modelos del gateway: el string tras openai/ en cada slot debe coincidir exactamente con un id servido. Los fallos de primera ejecución siguen el orden del pipeline. Un error de autenticación que nombra a Anthropic o Google significa que un id sin prefijo se enrutó a un proveedor nativo; añade openai/. Un 401 del gateway significa que el api_key en tus kwargs no es la clave del gateway. Un error de modelo no encontrado nombra el slot cuyo id tiene una errata. Los fallos durante la fase de investigación que mencionan tu backend de búsqueda son credenciales de recuperador, no enrutamiento de LM. Y las secciones de artículo truncadas o extrañamente cortas suelen ser un max_tokens tacaño en el slot de generación en lugar de algo upstream. Una ejecución completa de STORM es una ráfaga grande: conversaciones simuladas a través de perspectivas, luego esquema, generación y pulido. Una vez que una se completa, la consola de APIsRouter muestra el modelo por petición, el recuento de tokens y el gasto, que se mapea limpiamente sobre los cinco slots y te dice exactamente qué etapa reajustar antes del próximo lote de temas.

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

Preguntas frecuentes

¿Cómo admite STORM un endpoint personalizado compatible con OpenAI?

A través de litellm. STORM construye cada LM como un LitellmModel, que mezcla sus kwargs de constructor en cada litellm.completion(), y litellm acepta api_base para el proveedor openai. Añade api_base al diccionario openai_kwargs y cada slot construido desde él se enruta al gateway.

¿Por qué los ids de modelo necesitan el prefijo openai/?

litellm elige el proveedor a partir del prefijo. openai/claude-sonnet-4-6 significa "habla el protocolo de chat-completions de OpenAI con mi api_base usando el modelo claude-sonnet-4-6". Sin el prefijo, litellm infiere el proveedor a partir del nombre y enruta de forma nativa, evitando tu endpoint.

¿Pueden distintas etapas de STORM usar modelos de distintos proveedores?

Sí. Cada uno de los cinco slots es un LitellmModel independiente, así que el simulador de conversación puede correr un id de DeepSeek mientras la generación del artículo corre Claude y el pulido corre GPT, todo a través del mismo api_base y clave. Upstream ya recomienda dividir modelos rápidos y potentes entre etapas.

¿El recuperador de búsqueda cambia cuando cambio api_base?

No. La recuperación corre a través del módulo RM que pasas a STORMWikiRunner (You.com, Bing, y otros backends soportados) con su propia clave. El enrutamiento de LM y la recuperación de fuentes son sistemas independientes que fallan en distintas fases de una ejecución.

¿Hay una ruta de variable de entorno en lugar de kwargs?

litellm respeta variables a nivel de proveedor, y el proveedor openai lee OPENAI_API_BASE. Funciona, pero el kwarg api_base explícito es más reproducible: viaja con el script, sobrevive a máquinas con distinto estado de entorno, y permite excepciones por slot.

¿Cuántos tokens consume un artículo de STORM?

La fase de investigación domina: conversaciones simuladas multi-perspectiva multiplican las llamadas antes de que exista una palabra del artículo, y luego la generación y el pulido añaden salida de formato largo encima. Las ejecuciones completas suelen aterrizar en cientos de miles de tokens, y la vista de uso por clave muestra la división exacta por etapa.