← Lahat ng post

Isang Drop-In na OpenAI Compatible API — Migration sa Dalawang Linya

20 Ago 2026 · 6 min na basahin · api, migration

Ang unbleep ay isang OpenAI compatible API, na sa praktika ay nangangahulugang dalawang linya lang ang migration at walang bagong dependency. Mananatili ang opisyal na SDK, ang retry logic mo, ang streaming loop mo, ang token accounting mo, at ang mga error handler mo. Ang nagbabago ay kung saan pupunta ang mga request at kung aling key ang mag-a-authenticate sa mga ito. Tinatalakay ng post na ito ang pagpapalit, pagkatapos ay ang apat na bagay na sapat ang pagkakaiba para may masira kung hindi mo alam ang mga ito.

Pag-migrate sa OpenAI compatible API sa dalawang linya

python
import os

from openai import OpenAI

client = OpenAI(
    base_url="https://unbleep.ai/v1",
    api_key=os.environ["UNBLEEP_API_KEY"],
)

resp = client.chat.completions.create(
    model="unbleep",
    messages=[{"role": "user", "content": "Summarise this incident report."}],
)
print(resp.choices[0].message.content)

Kung mas gusto mong hindi na galawin ang code, binabasa ng SDK ang parehong value mula sa environment, kaya sapat na ang pagbabago sa config:

bash
export OPENAI_BASE_URL="https://unbleep.ai/v1"
export OPENAI_API_KEY="ub_live_9f2c..."

Sakop ng parehong pares na iyon ang karamihan ng ecosystem na nakapatong sa SDK — LangChain, LlamaIndex, Instructor, ang Vercel AI SDK, kahit anong may base-URL setting. May prefix ang mga key para agad mapansin ng mga secret scanner ang mga leak: parehong sinisingil ang ub_live_ at ub_test_ sa iisang prepaid credit sa parehong per-token rate. Ang test key ay isang hiwalay at mare-revoke na credential na may mas mababang limitasyon — 15 request/minuto sa halip na 60 ng account — hindi isang libreng tier. Panatilihin ang pareho sa server-side.

Gumagana ang GET /v1/models, kaya hindi na kailangan ng special-casing ang tooling na nag-e-enumerate ng mga model para punan ang isang dropdown.

Pagpili ng model

Tatlong tier. Tinatanggap bilang alias ang mga id na may petsa — unbleep-250811, unbleep-high-250811, unbleep-mini-250811 — pero sa kasalukuyan ay tumutukoy ang mga ito sa parehong build ng payak na id, at ang payak na id ang ibinabalik ng response. Ituring ang mga ito bilang forward-compatible na pagbabaybay, hindi bilang garantiya ng reproducibility; kung kailangang maulit ang isang evaluation, itala ang mga output, hindi ang model id.

| Model | Context | Presyo in / out kada 1M | Mga tala | | --- | --- | --- | --- | | unbleep | 256K | $3.00 / $3.00 | Default. Reasoning tier. | | unbleep-high | 1M* | $5.00 / $5.00 | Pinakamalalaking trabaho. Reasoning tier. | | unbleep-mini | 32K | $1.00 / $1.00 | Mura at mabilis. Direktang sumasagot, walang reasoning trace. |

*May limitasyon ang request body na 2,000,000 bytes — humigit-kumulang 500k token — kaya hindi talaga mapupuno ng iisang call ang 1M na window; anumang mas malaki ay babalik na 413 payload_too_large.

Ang 32K na limitasyon ng unbleep-mini ang nakakahuli sa mga nagmi-migrate mula sa 128K-context na model: ang prompt na kasya dati ay tatanggihan na ngayon. Kung nagru-route ka ayon sa gastos, mag-route ka rin ayon sa haba.

python
def pick_model(prompt_chars: int) -> str:
    """~4 chars/token is a deliberate under-estimate; leave room for the completion."""
    est_tokens = prompt_chars // 4
    if est_tokens < 24_000:
        return "unbleep-mini"
    return "unbleep" if est_tokens < 200_000 else "unbleep-high"

Streaming

I-set ang stream=True at makakakuha ka ng standard na Server-Sent Events: bawat event ay isang chat.completion.chunk na may dalang delta, at nagtatapos ang stream sa literal na data: [DONE]. Gumagana ang kasalukuyang loop mo nang walang pagbabago.

bash
curl -N https://unbleep.ai/v1/chat/completions \
  -H "Authorization: Bearer $UNBLEEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "unbleep",
    "messages": [{"role": "user", "content": "Explain the residual stream."}],
    "stream": true,
    "stream_options": {"include_usage": true}
  }'

Makukuha mo ang mga token count hiniling mo man ang mga ito o hindi: palaging humihiling ang unbleep ng usage mula sa backend at ipinapasa ito, at tanging ang tahasang stream_options: {"include_usage": false} ang nag-aalis nito palabas. Sa alinmang kaso, nagtatapos ang stream sa isang huling chunk na may walang lamang choices array — na may dalang napunang usage object maliban kung nag-opt out ka — kaya naman sinusuri muna ng loop sa ibaba ang choices bago ito galawin.

Ang field na reasoning_content

Ito ang nag-iisang tunay na dagdag sa schema. Nag-iisip muna ang unbleep at unbleep-high bago sumagot, at ibinabalik ang chain of thought na iyon sa reasoning_content, katabi ng content sa message (non-streaming) o sa delta (streaming). Hindi nagkakasundo ang mga upstream backend kung reasoning o reasoning_content ang itatawag dito; nino-normalize ito ng API sa reasoning_content para iisang hugis lang ang kailangan mong hawakan.

Dahil hindi ito bahagi ng OpenAI schema, wala ito sa mga type stub ng SDK. Pinapayagan ng mga response model ang mga dagdag na field, kaya gumagana ang attribute access sa runtime — pero basahin ito gamit ang getattr para hindi mag-raise ang isang mini na response, na walang trace:

python
import sys

stream = client.chat.completions.create(
    model="unbleep",
    messages=[{"role": "user", "content": "Why did this detection rule misfire?"}],
    stream=True,
    stream_options={"include_usage": True},
)

usage = None
for chunk in stream:
    if not chunk.choices:          # final usage-only chunk
        usage = chunk.usage
        continue
    delta = chunk.choices[0].delta
    thought = getattr(delta, "reasoning_content", None)
    if thought:                    # trace to stderr, answer to stdout
        sys.stderr.write(thought)
    if delta.content:
        sys.stdout.write(delta.content)

if usage:
    details = usage.completion_tokens_details
    print(f"\nreasoning tokens: {getattr(details, 'reasoning_tokens', 0)}")

Tatlong praktikal na epekto:

python
resp = client.chat.completions.create(
    model="unbleep",
    messages=[{"role": "user", "content": "phishing or benign?"}],
    max_tokens=4,
    extra_body={"thinking": False},   # spend the budget on the answer, not the trace
)

Huwag kailanman ibalik ang reasoning_content sa isang susunod na turn bilang assistant content. Diagnostic na output ito, hindi kasaysayan ng usapan, at ang pag-replay dito ay nagpapababa ng kalidad ng susunod na response.

Mga error at ang dalawang tunay na gotcha

Gumagamit ang mga error ng OpenAI envelope — {"error": {"type", "code", "message"}} — kaya patuloy na gumagana ang mga kasalukuyang except block mo. Tumutugma ang mga status code sa inaasahan mo: 401 maling key, 422 na-block ng policy: strict, 429 rate limit, 5xx retryable na upstream.

Ang status na malamang hindi mo pa kailanman na-handle ay 402, ubos na ang credit. Prepaid ang mga account, kaya walang overage at walang invoice — basta na lang titigil ang mga request hanggang sa mag-top up ka. Sini-senyas ng OpenAI ang pagkaubos ng quota bilang 429, na nangangahulugang sa naive na landas ng migration, walang katapusang ire-retry ng backoff logic mo ang isang 402. Ituring itong terminal at mag-alert dito.

Ang pangalawang gotcha: hindi ibinabalik ang system_fingerprint. Tumutukoy ito sa serving backend, kaya inaalis ito kasama ng iba pang vendor field. Kung nakabase rito ang key ng cache mo o ng reproducibility check mo, kakailanganin mo ng sarili mong version marker: ang mga model id na may petsa ay mga alias para sa kasalukuyang build, hindi mga frozen na snapshot, kaya hindi nito sasabihin sa iyo kung kailan nagbago ang backend.

Bumabalik ang mga rate limit bilang mga header sa bawat response — x-ratelimit-limit-requests, x-ratelimit-remaining-requests, x-ratelimit-reset-requests — para makapag-pace ang isang batch job ng request rate nito sa halip na matuklasan ang limitasyong iyon sa pagtama rito. May pangalawang limitasyon na hindi inilalarawan ng mga header: hindi hihigit sa 8 request na in flight kada account, at ang ikasiyam ay babalik na 429 na may code na too_many_concurrent_requests. Hawak ng isang streaming call ang slot nito hanggang matapos ang stream, kaya limitahan ang sarili mong worker pool sa 8.

Kung ano ang itinuturo mo

Mahalagang linawin: ang mga model sa likod ng endpoint na ito ay abliterated, ibig sabihin ay tinanggal ang ugali nilang tumanggi sa antas ng mga weight. Iyon mismo ang punto — isa itong developer API na nakatuon sa security research, red-teaming at evaluation, kung saan ang pagtanggi ay pagkakamali sa pagsukat. Nangangahulugan din itong wala roon ang mga karaniwang guardrail para sumalo ng masamang prompt, kaya panatilihing may taong mananagot sa mga output at basahin ang patakaran sa katanggap-tanggap na paggamit. Nasa iyo ang responsibilidad ng legal na paggamit.

Kumuha ng API key — talagang dalawang linya lang ang migration.