Chạy Stanford STORM trên một endpoint tương thích OpenAI tùy chỉnh.

Updated 2026-07-29

STORM xây mọi language model như một LitellmModel, và litellm chấp nhận api_base. Đặt https://api.apisrouter.com/v1 vào openai_kwargs chung của bạn, thêm tiền tố model id bằng openai/, và cả năm slot LM của pipeline bài viết định tuyến qua một endpoint và một key.

Câu trả lời nhanh: api_base trong openai_kwargs, tiền tố openai/ trên id.

LitellmModel của STORM lưu bất kỳ kwargs nào bạn khởi tạo nó và trộn chúng vào mỗi lệnh gọi litellm.completion(). Tham số api_base của litellm là cách bạn trỏ provider openai vào một host khác, nên thêm api_base vào dict openai_kwargs mà các ví dụ của chính STORM đã dùng là toàn bộ việc ghi đè. Thêm tiền tố mỗi model id bằng openai/ để litellm nói giao thức chat-completions tới base đó, và chuỗi sau dấu gạch chéo được chuyển thẳng tới gateway. Vì các ví dụ xây một dict openai_kwargs và dùng lại nó cho mọi model, một key được thêm vào định tuyến lại toàn bộ pipeline. Không đổi code STORM, không fork; đây là hành vi knowledge_storm gốc xếp lớp trên định tuyến có tài liệu của 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ách STORM chia một bài viết thành năm slot LM.

STORM (stanford-oval trên GitHub, khoảng 30K star) viết báo cáo kiểu Wikipedia từ đầu: nó nghiên cứu một chủ đề qua các hội thoại mô phỏng đa góc nhìn, xây một dàn ý từ những gì nó học được, sinh toàn bộ bài viết theo từng đoạn, và sau đó đánh bóng lại. STORMWikiLMConfigs phơi pipeline đó thành năm model đặt được độc lập: conv_simulator_lm và question_asker_lm điều khiển các cuộc hội thoại nghiên cứu, outline_gen_lm cấu trúc bài viết, article_gen_lm viết nó, và article_polish_lm làm lượt đánh bóng cuối. README upstream nói rõ về kinh tế học: bộ mô phỏng hội thoại chạy khối lượng lệnh gọi cao nhất, nên nó khuyên dùng một model nhanh hơn ở đó và một model mạnh hơn cho sinh bài viết. Lời khuyên đó giả định việc chọn giữa các model OpenAI; đứng sau một endpoint đa vendor nó tổng quát hóa thành điều gì đó hữu ích hơn. Mỗi slot là một LitellmModel riêng của nó với chuỗi model riêng, nên hội thoại nghiên cứu có thể chạy trên một id DeepSeek nhanh trong khi sinh dàn ý và bài viết chạy trên Claude, và đánh bóng trên bất kỳ model nào bạn tin cho tông giọng, tất cả xác thực bằng cùng key chống lại cùng api_base. Phía truy xuất là máy móc riêng biệt: runner của STORM nhận một module RM (You.com, Bing, và một số backend tìm kiếm khác) với key API riêng của nó. Đổi nơi language model trỏ tới không chạm vào cách nguồn được lấy.

Cài đặt đầy đủ: năm slot, một dict kwargs.

Mẫu hoạt động phản chiếu các script chạy riêng của repository: xây kwargs chung một lần, khởi tạo một LitellmModel cho mỗi vai trò, và gán chúng qua các setter của STORMWikiLMConfigs. api_key có thể mang bất kỳ tên nào bạn thích vì bạn truyền nó rõ ràng; ví dụ dùng biến riêng của nó để làm rõ đây không phải một credential tài khoản OpenAI. litellm cũng tôn trọng các biến môi trường cấp provider, và provider openai đọc OPENAI_API_BASE, nên một ghi đè chỉ-qua-môi-trường vẫn khả thi. Con đường kwargs rõ ràng vẫn là cái nên ưu tiên: nó hiển thị trong code đã tạo ra một bài viết nhất định, nó tồn tại khi chạy trên một máy có trạng thái môi trường khác, và nó cho phép ngoại lệ theo từng slot nếu bạn từng muốn một giai đoạn nằm trên một endpoint khác.

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

Chọn model theo từng giai đoạn pipeline.

Coi năm setter như một núm ngân sách, không phải code khuôn mẫu. Lời khuyên upstream đã nói tách model nhanh và mạnh qua các giai đoạn; một endpoint đa vendor chỉ mở rộng menu theo từng giai đoạn. Đổi một slot mỗi lần giữa các lần chạy trên cùng chủ đề và so sánh khác biệt đầu ra, với log sử dụng theo từng key định giá mỗi cấu hình.

  • conv_simulator_lm và question_asker_lm là các giai đoạn khối lượng lớn: phỏng vấn mô phỏng nhiều lượt qua nhiều góc nhìn cho mỗi chủ đề. deepseek-v4-flash hoặc một id nhanh khác giữ giai đoạn nghiên cứu không chi phối chi tiêu, và chuyện phiếm không hoàn hảo vẫn chấp nhận được vì nó nuôi ghi chú, không phải văn xuôi.
  • article_gen_lm là slot chủ lực. Nó viết các đoạn dài, có cấu trúc, có trích dẫn từ nghiên cứu tích lũy, công việc sinh văn bản bền vững nơi claude-sonnet-4-6 hoặc gpt-5.5 vượt trội rõ rệt so với các id nhỏ hơn.
  • outline_gen_lm là ít lệnh gọi với đòn bẩy lớn, cùng hình dạng với một slot lập kế hoạch: một dàn ý yếu giới hạn bài viết bất kể người viết giỏi thế nào. Đây là nơi tự nhiên để thử claude-opus-4-7.
  • article_polish_lm viết lại cho mạch lạc và loại bỏ trùng lặp trên bài viết đã lắp ráp, thứ hưởng lợi từ một id long-context; gemini-3.1-pro-preview đáng benchmark ở đây.

Trả theo mức sử dụng · thấp hơn giá chính thức

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

Mô hìnhGiá chính thứcGiá của chúng tôi
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

Các kiểu lỗi đặc thù của STORM.

Một model id trần định tuyến theo suy luận, không theo api_base của bạn. litellm đọc tiền tố để chọn provider, và một id Claude không tiền tố được suy luận là một lệnh gọi Anthropic gốc, thứ khi đó muốn ANTHROPIC_API_KEY và bỏ qua gateway của bạn hoàn toàn. Mọi id hướng tới gateway phải mang tiền tố openai/; tiền tố đặt tên giao thức, không phải vendor. Một slot bị bỏ lại. Mỗi LitellmModel bắt lấy kwargs của nó lúc khởi tạo. Nếu bốn slot chia sẻ openai_kwargs và một slot thứ năm được xây tùy tiện không có api_base, slot đó âm thầm gửi tới mặc định vendor và lỗi xác thực, và traceback nêu tên một giai đoạn pipeline thay vì một dòng cấu hình. Xây mọi slot từ cùng dict và loại lỗi này biến mất. Lỗi retriever bị đổ lỗi cho endpoint. Giai đoạn nghiên cứu cần một backend tìm kiếm hoạt động; một key retriever không hợp lệ hoặc hết hạn (YDC_API_KEY, BING_SEARCH_API_KEY, hoặc bất kỳ RM nào bạn chọn) lỗi các lần chạy trong lúc thu thập thông tin. Giai đoạn đó xen kẽ với các lệnh gọi LM, nên hãy đọc traceback xem client nào phát lỗi trước khi chạm vào cấu hình LM. Secrets.toml của demo không phải cấu hình script của bạn. Demo Streamlit đọc secrets.toml; các lần chạy theo chương trình đọc bất cứ gì script của bạn truyền vào. Sửa cái này trong khi chạy cái kia là một sự không khớp kinh điển. max_tokens cũng theo từng slot. Các ví dụ của STORM đặt giới hạn nhỏ trên các slot nhanh (500) và lớn hơn trên sinh văn bản (3000). Trỏ một slot vào một model long-form mà không nâng max_tokens của nó âm thầm cắt bớt các đoạn, trông như vấn đề chất lượng model nhưng là một con số cấu hình.

Ai định tuyến STORM qua một gateway.

  • Các đội sinh báo cáo tri thức ở khối lượng lớn (bản tóm tắt, tài liệu nội bộ kiểu wiki, sơ lược chủ đề), nơi cách chia năm slot khiến việc tinh chỉnh chi phí theo từng giai đoạn xứng đáng với tiền thật.
  • Nhà nghiên cứu nghiên cứu thành phần pipeline: giai đoạn nào hưởng lợi từ một model mạnh hơn là một câu hỏi thực nghiệm, và một endpoint khiến lưới các tổ hợp slot-model trở nên tầm thường để liệt kê.
  • Người xây dựng chạy Claude hoặc Gemini trong các slot viết của một stack hình dạng OpenAI, mà không cần thêm SDK vendor cho mỗi họ model.
  • Bất kỳ ai chạy danh sách chủ đề hàng loạt, nơi khối lượng giai đoạn nghiên cứu nhân lên qua các chủ đề và log sử dụng trở thành sổ chi phí theo từng chủ đề.
  • Lập trình viên không có quyền truy cập billing của một vendor cụ thể. Truy cập dựa trên nạp tiền không yêu cầu thẻ loại bỏ phụ thuộc đăng ký theo từng provider.

Xác minh endpoint và debug bài viết đầu tiên.

Liệt kê model của gateway trước: chuỗi sau openai/ trong mỗi slot phải khớp chính xác một id được phục vụ. Lỗi lần chạy đầu theo thứ tự pipeline. Một lỗi xác thực nêu tên Anthropic hoặc Google nghĩa là một id không tiền tố định tuyến tới một provider gốc; hãy thêm openai/. Lỗi 401 từ gateway nghĩa là api_key trong kwargs của bạn không phải key gateway. Một lỗi model-not-found nêu tên slot có id lỗi chính tả. Lỗi trong giai đoạn nghiên cứu nhắc tới backend tìm kiếm của bạn là credential retriever, không phải định tuyến LM. Và các đoạn bài viết bị cắt hoặc ngắn bất thường thường là max_tokens keo kiệt trên slot sinh văn bản chứ không phải gì ở upstream. Một lần chạy STORM đầy đủ là một đợt bùng nổ lớn: hội thoại mô phỏng qua nhiều góc nhìn, sau đó dàn ý, sinh văn bản, và đánh bóng. Khi một cái hoàn tất, console APIsRouter hiển thị model theo từng request, số lượng token, và chi tiêu, ánh xạ gọn gàng lên năm slot và cho bạn biết chính xác giai đoạn nào cần tinh chỉnh lại trước lô chủ đề tiếp theo.

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

Câu hỏi thường gặp

STORM hỗ trợ một endpoint tương thích OpenAI tùy chỉnh như thế nào?

Qua litellm. STORM xây mọi LM như một LitellmModel, thứ trộn kwargs khởi tạo của nó vào mỗi lệnh gọi litellm.completion(), và litellm chấp nhận api_base cho provider openai. Thêm api_base vào dict openai_kwargs và mọi slot xây từ nó định tuyến tới gateway.

Vì sao model id cần tiền tố openai/?

litellm chọn provider từ tiền tố. openai/claude-sonnet-4-6 nghĩa là "nói giao thức chat-completions OpenAI tới api_base của tôi với model claude-sonnet-4-6". Không có tiền tố, litellm suy luận vendor từ tên và định tuyến gốc, bỏ qua endpoint của bạn.

Các giai đoạn STORM khác nhau có thể dùng model của các vendor khác nhau không?

Có. Mỗi trong năm slot là một LitellmModel độc lập, nên bộ mô phỏng hội thoại có thể chạy một id DeepSeek trong khi sinh bài viết chạy Claude và đánh bóng chạy GPT, tất cả qua cùng api_base và key. Upstream đã khuyên tách model nhanh và mạnh qua các giai đoạn.

Retriever tìm kiếm có đổi khi tôi đổi api_base không?

Không. Truy xuất chạy qua module RM bạn truyền cho STORMWikiRunner (You.com, Bing, và các backend được hỗ trợ khác) với key riêng của nó. Định tuyến LM và truy xuất nguồn là các hệ thống độc lập lỗi ở các giai đoạn khác nhau của một lần chạy.

Có con đường biến môi trường thay vì kwargs không?

litellm tôn trọng các biến cấp provider, và provider openai đọc OPENAI_API_BASE. Nó hoạt động, nhưng kwarg api_base rõ ràng có thể tái tạo hơn: nó đi theo script, tồn tại trên các máy có trạng thái môi trường khác, và cho phép ngoại lệ theo từng slot.

Một bài viết STORM tiêu tốn bao nhiêu token?

Giai đoạn nghiên cứu chi phối: các hội thoại mô phỏng đa góc nhìn nhân số lệnh gọi trước khi một từ nào của bài viết tồn tại, sau đó sinh văn bản và đánh bóng thêm đầu ra dài lên trên. Các lần chạy đầy đủ thường rơi vào hàng trăm nghìn token, và góc nhìn sử dụng theo từng key hiển thị chính xác phân tách theo từng giai đoạn.