MaruOpsInfrastructure and AI notes

About (Korean)Contact (Korean)

[Local LLM 24] Use OpenRouter and Check Cost and Data Routing

CERN data center building

Reference photo · CERN data center building · Photo: Unnerving duck / Source / CC BY-SA 4.0 · Resized for listings; illustrative photo, not the tested environment

Building a Local LLM · 24/30 · Connect with an Agent

Full series and learning sequence · Practice code ZIP

OpenRouter provides a common API for requests to multiple external model providers. Check the data destination and charging rules before sending anything beyond a fictional test question. The exercise follows the request and response without using real business data.

You need a separate OpenRouter account and API key from Python. After checking the cost and provider conditions, prepare a key for practice.

Request path and price unit

The request goes from my program through OpenRouter to the selected model provider. Check model ID, input/output unit price, routing, and data processing conditions. Even if it is listed as free, you should check availability and call limits separately.

No specific rates are used as a fixed basis for this article. Catalog API and service screens may have different price units. When converting the unit price per token to the price per million tokens, multiply by 1 million for comparison.

Practice Keys and Limits

Prepare your account and necessary credits on the official site. Issue API keys for your practice and set possible spending limits. Keys are not included in the body, screenshots, or client JavaScript. Requests only use hypothetical questions.

The example uses getpass to hide keystrokes from the screen. Even when using environment variables, manage them so that they are not exposed to shared shell history or diagnostic output. Keys that have already been exposed are not only deleted from the file, but are also discarded and reissued.

Call API with current model ID

import getpass
import json
import os
import urllib.request

ROOT = "https://openrouter.ai/api/v1"

def catalog():
    with urllib.request.urlopen(ROOT + "/models", timeout=30) as response:
        return json.load(response)["data"]

def cloud_chat(question, model):
    models = {m["id"]: m for m in catalog()}
    if model not in models:
        raise ValueError("Model ID is not in the current catalog")
    key = os.environ.get("OPENROUTER_API_KEY") or getpass.getpass("OpenRouter API key: ")
    if not key:
        raise ValueError("API key is required")
    body = {"model": model, "messages": [{"role": "user", "content": question}],
            "max_tokens": 256, "stream": False}
    req = urllib.request.Request(ROOT + "/chat/completions",
        data=json.dumps(body, ensure_ascii=False).encode("utf-8"),
        headers={"Authorization": "Bearer " + key,
                 "Content-Type": "application/json"})
    with urllib.request.urlopen(req, timeout=120) as response:
        result = json.load(response)
    return result["choices"][0]["message"]["content"], result.get("usage", {})

if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--list", action="store_true")
    args = parser.parse_args()
    if args.list:
        rows = [m for m in catalog() if "qwen" in m["id"].lower()]
        for m in rows[:12]:
            print(m["id"], m.get("context_length"), m.get("pricing"))
    else:
        model = input("현재 카탈로그의 모델 ID: ").strip()
        question = input("외부 전송 가능한 가상 질문: ").strip()
        if not 1 <= len(question) <= 1000:
            raise SystemExit("Use a question of 1 to 1000 characters")
        answer, usage = cloud_chat(question, model)
        print(answer)
        print("usage:", usage)
.\.venv\Scripts\python.exe .\openrouter_demo.py --list
.\.venv\Scripts\python.exe .\openrouter_demo.py

Enter the exact model ID you found in the list. max_tokens=256 is an output limit for one request and is not an upper limit on monthly costs. Manage input volume, recurring calls, provider fees, and account limits together. Lab API calls may also incur costs.

Provider policies and error handling

Read OpenRouter’s privacy/routing settings and the actual provider’s policy together. Even with the same model name, the providers can be different. When sending work materials, check the allowed providers, storage conditions, and routes that can be changed to fallbacks.

First check authentication for 401, balance/payment conditions for 402, and speed limit for 429. Doesn’t repeat failed requests infinitely. When comparing to a local model, we match the questions and output limits, and also record network delays and external transmissions.

reference material

Documentation and model tags checked: October 18, 2026. Primary lab environment: Windows 11 x64.