Best Practices
Practical guidance for building reliable, cost-efficient applications on the Yunxin API.
These recommendations are grounded in Yunxin's actual behavior. Each one links to the reference page that explains the underlying feature in detail.
Handle API keys securely
Your key carries your balance, tier, and permissions — treat it like a password.
Never embed an API key in client-side code, mobile apps, browser requests, or a public repository. Anyone with the key can spend your balance.
- Store keys in environment variables or a secrets manager — never hardcode them.
- Route browser and mobile traffic through your own backend so the key never reaches the client.
- Use a separate key per environment and service so per-key analytics are meaningful and a leak has limited blast radius.
- Set a per-key rate limit (Dashboard → API Keys) to cap noisy services.
- Rotate keys periodically and immediately after any suspected exposure.
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["YUNXIN_API_KEY"],
base_url="https://api.yuhuanstudio.com/v1",
)See Authentication for header forms and key management.
Choose the right request format
Yunxin natively supports three formats. Pick the one closest to your code; you are not forced to transpile.
| Format | Best for | SDK | Endpoint |
|---|---|---|---|
| Chat Completions | General use, widest ecosystem compatibility | OpenAI SDK | POST /v1/chat/completions |
| Responses | Agentic workflows, server-side multi-turn, built-in tools | OpenAI SDK | POST /v1/responses |
| Messages | Anthropic features — extended thinking, prompt caching, PDF input | Anthropic SDK | POST /v1/messages |
Remember the base URL differs by SDK: the OpenAI SDK uses https://api.yuhuanstudio.com/v1, while the
Anthropic SDK uses https://api.yuhuanstudio.com (it appends /v1/messages itself).
When a provider doesn't natively support the format you sent, Yunxin converts transparently — so you can keep one codebase and still reach models across all providers.
Stream long responses
Streaming sends tokens as they're produced, cutting time-to-first-token and keeping UIs responsive. A streamed completion still counts as a single request against your rate limit, regardless of output length.
stream = client.chat.completions.create(
model="model-id",
messages=[{"role": "user", "content": "Write a detailed analysis..."}],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")All streaming endpoints use SSE (text/event-stream), terminated by data: [DONE]. Yunxin may emit
inline event: fallback and event: routing events to tell you when a request was rerouted — see
Fallback & Routing.
Retry transient failures with backoff
Retry only errors that are actually transient — rate_limit_exceeded, provider_error,
provider_timeout, provider_unavailable — using exponential backoff with jitter. Don't retry
validation or auth errors; fix the request instead.
import time, random
from openai import RateLimitError, APIError
def with_retry(fn, max_retries=5):
for attempt in range(max_retries):
try:
return fn()
except RateLimitError as e:
# Prefer the server's Retry-After when present.
wait = getattr(e, "retry_after", None) or (2 ** attempt) + random.uniform(0, 1)
time.sleep(wait)
except APIError as e:
if e.status_code in (502, 503, 504):
time.sleep((2 ** attempt) + random.uniform(0, 1))
else:
raise
raise RuntimeError("Max retries exceeded")On 429, honor the Retry-After header (and error.retry_after) rather than guessing. Watch
X-RateLimit-Remaining to slow down before you hit zero. See Rate Limits and
Error Handling.
Lean on fallback and routing
Yunxin can automatically reroute a failing request to an alternative model or provider, and can pick a
provider by category when you use auto-routing. Inspect the response headers to know what happened:
X-Fallback-Used, X-Fallback-Provider, X-Fallback-Reason, X-Fallback-Discount, and
X-Routing-Mode / X-Routing-Resolved-Model. Always log X-Request-ID alongside failures for
support traceability. See Fallback & Routing.
Discover models and capabilities at runtime
Models and their capabilities are discovered at runtime (the catalog is DB-driven and changes without
redeploys). Don't hardcode model lists — query the Models API and branch on the
capabilities array and pricing object.
curl "https://api.yuhuanstudio.com/v1/models?capability=chat" \
-H "Authorization: Bearer $YUNXIN_API_KEY"GET /v1/models/{model_id} returns a single model's capabilities, context length, and per-1M-token
pricing — useful for picking the smallest model that meets a task's needs.
Cache repeated prompts
For providers that support prompt caching (notably Anthropic via the Messages API), reuse a cached
prefix across requests. Cached input tokens are billed at the model's cache_read rate instead of the
full input rate — often a large saving on long, stable system prompts. Pricing fields are visible in
each model's pricing object via the Models API.
Batch offline work
For non-interactive jobs (evals, bulk classification, content generation), use the Batch API. Batches run at roughly a 50% discount and are excluded from per-minute rate limiting, so they're both cheaper and gentler on your quota.
batch = client.batches.create(
input_file_id="file-abc123",
endpoint="/v1/chat/completions",
completion_window="24h",
)Control cost
- Right-size the model. Use a smaller/cheaper model for simple tasks (classification, extraction) and reserve capable models for hard reasoning.
- Set
max_tokensto cap output length and prevent runaway responses. - Batch non-urgent work for the ~50% discount.
- Cache stable prompt prefixes to pay the
cache_readrate. - Watch your tier. Higher tiers raise your RPM and request priority; choose the tier that matches your traffic. See Pricing & Billing.
- Monitor spend. Track tokens, cost, and latency from the Dashboard or the usage endpoints, and
alert before you hit
402 insufficient_balance. See Usage Monitoring Tools.
How is this guide?