[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-75547":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":15,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":19,"hasPages":19,"topics":21,"createdAt":10,"pushedAt":10,"updatedAt":42,"readmeContent":43,"aiSummary":44,"trendingCount":15,"starSnapshotCount":15,"syncStatus":45,"lastSyncTime":46,"discoverSource":47},75547,"llmix","sno-ai\u002Fllmix","sno-ai","Production LLM call layer for AI agents and tools: keep OpenAI\u002FAnthropic\u002FAI SDK\u002FLiteLLM, hot-swap models with MDA presets, and add cache, retries, circuit breakers, key rotation, singleflight, and Python\u002FTypeScript\u002FRust parity.","https:\u002F\u002Fgithub.com\u002Fsno-ai\u002Fllmix",null,"Python",129,28,30,0,99,4.39,"Apache License 2.0",false,"main",[22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"ai-agents","ai-sdk","ai-tools","anthropic","circuit-breaker","config-driven","gemini","key-rotation","litellm","llm","llm-cache","llm-orchestration","llmops","model-switching","openai","python","redis","rust","singleflight","typescript","2026-06-12 02:03:35","# LLMix\n\n[![npm version](https:\u002F\u002Fimg.shields.io\u002Fnpm\u002Fv\u002F@snoai\u002Fllmix.svg?label=npm&labelColor=3b3b3b&color=cb3837)](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@snoai\u002Fllmix)\n[![PyPI](https:\u002F\u002Fimg.shields.io\u002Fpypi\u002Fv\u002Fsno-llmix.svg?label=pypi&labelColor=3b3b3b&color=3775a9)](https:\u002F\u002Fpypi.org\u002Fproject\u002Fsno-llmix\u002F)\n[![crates.io](https:\u002F\u002Fimg.shields.io\u002Fcrates\u002Fv\u002Fllmix-rs.svg?label=crates.io&labelColor=3b3b3b&color=d67b2b)](https:\u002F\u002Fcrates.io\u002Fcrates\u002Fllmix-rs)\n[![Python 3.14+](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fpython-3.14%2B-ffd43b.svg?labelColor=306998)](https:\u002F\u002Fwww.python.org\u002Fdownloads\u002F)\n[![TypeScript 5.0+](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FTypeScript-5.0%2B-3178c6.svg?labelColor=3b3b3b)](https:\u002F\u002Fwww.typescriptlang.org\u002F)\n[![Rust 1.83+](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Frust-1.83%2B-b7410e.svg?labelColor=3b3b3b)](https:\u002F\u002Fwww.rust-lang.org\u002F)\n[![License: Apache--2.0](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLicense-Apache--2.0-97ca00.svg?labelColor=3b3b3b)](LICENSE)\n\nRead in other languages: **English** · [中文](docs\u002Fllmix\u002Freadme\u002FREADME.zh-CN.md) · [Deutsch](docs\u002Fllmix\u002Freadme\u002FREADME.de.md) · [Español](docs\u002Fllmix\u002Freadme\u002FREADME.es.md) · [Français](docs\u002Fllmix\u002Freadme\u002FREADME.fr.md) · [Русский](docs\u002Fllmix\u002Freadme\u002FREADME.ru.md) · [한국어](docs\u002Fllmix\u002Freadme\u002FREADME.ko.md) · [日本語](docs\u002Fllmix\u002Freadme\u002FREADME.ja.md) · [हिन्दी](docs\u002Fllmix\u002Freadme\u002FREADME.hi.md)\n\n> Config-driven LLM calls for Python, TypeScript, and Rust.\n> Keep your SDK. Move model behavior into MDA presets. Put cache, retries, key rotation, and rollout control around the call.\n\nLLMix is the layer between your product and the provider SDK.\n\nIt does not ask you to rewrite your OpenAI, Anthropic, Gemini, LiteLLM, AI SDK, or custom client code. It wraps the call. The boring parts go around it: response cache, circuit breaker, key pools, singleflight, retry policy, adaptive concurrency, provider kwargs, and MDA config loading.\n\nThe model stops being a hard-coded string buried in application code. It becomes data. Change a preset, publish a compiled registry release, reload the service, and the next request can run a different provider or model. No redeploy for the usual model swap dance.\n\nThat is the whole thing. Small layer. Sharp edges filed down.\n\n---\n\n## Why It Exists\n\nAI products in 2026 do not usually fail because one SDK call is hard.\n\nThey fail in the spaces around the call. A key gets rate limited. A provider gets slow. Two hundred users ask the same thing at once. A model swap needs a deploy. A cache key differs by one invisible parameter. One service is in Python, another is in TypeScript, and the Rust worker has to follow the same contract.\n\nLLMix is for that part of the system. The signal chain between your app and the model.\n\nYou still own the prompt. You still own the SDK. LLMix owns the harness.\n\n---\n\n## Install\n\n| Runtime | Package | Import path |\n|---------|---------|-------------|\n| TypeScript | `npm install @snoai\u002Fllmix` | `@snoai\u002Fllmix` |\n| Python | `pip install sno-llmix` | `llmix` |\n| Rust | `cargo add llmix-rs` | `llmix_rs` |\n\nPython uses `sno-llmix` on PyPI because `llmix` was already taken. The import path is still `llmix`.\nThe official registry commands ship with the TypeScript npm package as the\n`llmix` binary.\n\nProvider helpers use optional SDKs. Install only the provider clients you call.\n\n```bash\n# TypeScript OpenAI-compatible helpers\nnpm install ai @ai-sdk\u002Fopenai\n\n# Python Redis cache support\npip install \"sno-llmix[redis]\"\n\n# Rust OpenAI helper and Redis cache\ncargo add llmix-rs --features providers-openai,redis\n```\n\nLLMix uses the MDA config packages for preset loading. They are also published\nas standalone runtime loaders for apps that need `.mda` validation, integrity,\nor trust-policy enforcement outside LLMix.\n\n---\n\n## Documentation\n\nIf you are new to LLMix, read in this order:\n\n1. This README: the product shape and the default registry layout.\n2. The runtime guide for the service you ship: [TypeScript](docs\u002Fllmix\u002Fllmix-typescript.md), [Python](docs\u002Fllmix\u002Fllmix-python.md), or [Rust](docs\u002Fllmix\u002Fllmix-rust.md).\n3. [Secure LLMix configuration](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.md): the full MDA CLI + LLMix release runbook and tamper-rejection proof.\n\nOther operations docs:\n\n- [Secure LLMix configuration translations](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.md) ([de](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.de.md), [es](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.es.md), [fr](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.fr.md), [hi](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.hi.md), [ja](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.ja.md), [ko](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.ko.md), [ru](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.ru.md), [中文](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.zh.md))\n- [Key pool operations](docs\u002Fllmix\u002Fkey-pool-operations.md)\n- [Standalone MDA config loader docs](docs\u002Fmda-config\u002FREADME.md)\n\n---\n\n## At a Glance\n\n![LLMix wraps your existing LLM SDK stack with MDA config, cache, resilience, and key-pool primitives.](docs\u002Fllmix\u002Fimages\u002Fllmix-wraps-sdk.png)\n\nLLMix wraps one provider call at a time.\n\nIt is not a router in the LiteLLM sense. It is closer to the harness you keep rebuilding around every agent, coder tool, extraction service, and internal AI workflow once traffic becomes real.\n\n---\n\n## Quick Start\n\n### TypeScript\n\n```typescript\nimport {\n  CallPipeline,\n  KeyPool,\n  TwoTierCache,\n  openaiDispatch,\n} from \"@snoai\u002Fllmix\";\n\nconst pipeline = new CallPipeline({\n  dispatch: openaiDispatch(),\n  responseCache: new TwoTierCache(\"memory\"),\n});\n\npipeline.setKeyPool(\"openai\", new KeyPool([process.env.OPENAI_API_KEY!]));\n\nconst response = await pipeline.call({\n  config: {\n    provider: \"openai\",\n    model: \"gpt-4o-mini\",\n    common: { temperature: 0.2, maxOutputTokens: 512 },\n    caching: { strategy: \"memory\" },\n  },\n  messages: [\n    { role: \"user\", content: \"Explain LLMix in one sentence.\" },\n  ],\n});\n\nconsole.log(response.content);\nawait pipeline.close();\n```\n\n### Python\n\n```python\nimport asyncio\nimport os\n\nfrom llmix import (\n    CallInput,\n    CallPipeline,\n    KeyPool,\n    PipelineConfig,\n    TwoTierCache,\n    openai_dispatch,\n)\n\n\nasync def main() -> None:\n    pipeline = CallPipeline(\n        PipelineConfig(\n            dispatch=openai_dispatch(),\n            response_cache=TwoTierCache(\"memory\"),\n        )\n    )\n\n    pipeline.set_key_pool(\"openai\", KeyPool([os.environ[\"OPENAI_API_KEY\"]]))\n\n    response = await pipeline.call(\n        CallInput(\n            config={\n                \"provider\": \"openai\",\n                \"model\": \"gpt-4o-mini\",\n                \"common\": {\"temperature\": 0.2, \"max_output_tokens\": 512},\n                \"caching\": {\"strategy\": \"memory\"},\n            },\n            messages=[\n                {\"role\": \"user\", \"content\": \"Explain LLMix in one sentence.\"}\n            ],\n        )\n    )\n\n    print(response.content)\n    await pipeline.close()\n\n\nasyncio.run(main())\n```\n\n### Rust\n\nRust exposes the same pipeline contract. The OpenAI helper is feature-gated.\n\n```toml\n[dependencies]\nllmix-rs = { version = \"2.0.0\", features = [\"providers-openai\"] }\nserde_json = \"1\"\ntokio = { version = \"1\", features = [\"macros\", \"rt\"] }\n```\n\n```rust\nuse llmix_rs::{\n    load_keys_from_env, CallInput, CallPipeline, OpenAiChatHelper, PipelineConfig,\n};\nuse serde_json::json;\n\nlet pipeline = CallPipeline::new(PipelineConfig::new(OpenAiChatHelper::new()))?;\npipeline.set_key_pool(\"openai\", load_keys_from_env(\"openai\")?);\n\nlet response = pipeline\n    .call(CallInput {\n        config: json!({\n            \"provider\": \"openai\",\n            \"model\": \"gpt-4o-mini\",\n            \"common\": { \"temperature\": 0.2, \"max_output_tokens\": 512 },\n            \"caching\": { \"strategy\": \"memory\" }\n        }),\n        messages: vec![json!({\n            \"role\": \"user\",\n            \"content\": \"Explain LLMix in one sentence.\"\n        })],\n        singleflight_key: None,\n    })\n    .await;\n```\n\nSee the [Rust guide](docs\u002Fllmix\u002Fllmix-rust.md) for full `main` examples and feature flags.\n\n---\n\n## What You Get Around Every Call\n\n![LLMix request pipeline from config and cache lookup through circuit breaker, singleflight, key-pool rotation, retry loop, dispatch, and telemetry.](docs\u002Fllmix\u002Fimages\u002Fllmix-call-pipeline.png)\n\n| Concern | What LLMix does |\n|---------|-----------------|\n| Response cache | L1 memory plus optional Redis L2, with cross-runtime canonical cache keys |\n| Key pools | Round-robin key selection, 429 rotation, and 401\u002F403 dead-key eviction |\n| Retries | Jittered exponential backoff, with `Retry-After` honored |\n| Circuit breaker | Scoped by provider and effective base URL |\n| Singleflight | Collapses identical concurrent work into one upstream request |\n| Concurrency | AIMD adaptive semaphore, driven by rate-limit feedback |\n| Provider kwargs | Common config becomes provider-specific request fields |\n| Thinking tokens | Optional `\u003Cthink>` extraction into normalized response objects |\n| Registry | Signed compiled config registry with one live `current.json` pointer |\n\nThe defaults are meant to be boring. Tune them when real traffic gives you a reason.\n\n---\n\n## MDA Presets\n\n![LLMix turns editable MDA presets into a signed compiled registry release opened through the official flow.](docs\u002Fllmix\u002Fimages\u002Fllmix-mda-config.png)\n\nLLMix uses MDA as the source format for model presets. Human notes and runtime\nsettings live in one file. Production services read the compiled registry, not\nthe mutable source tree.\nPython, TypeScript, and Rust can require MDA integrity, `requires.network`, and\nverifier-hook based signatures while loading or publishing registry output.\nReal Rekor transport and Sigstore cryptography are supplied by caller-provided\nclients\u002Fverifiers.\n\nThe examples below use this preset path:\n\n```text\nconfig\u002Fllm\u002Fsource\u002Fsearch_summary\u002Fopenai_fast.mda\n```\n\n```mda\n---\nname: openai_fast\ndescription: Fast OpenAI preset for search summaries.\nmetadata:\n  snoai-llmix:\n    common:\n      provider: openai\n      model: gpt-5-mini\n      temperature: 0.2\n      maxOutputTokens: 512\n    caching:\n      strategy: redis-or-memory\n    providerOptions:\n      openai:\n        reasoningEffort: medium\n---\n# openai_fast\n\nSummarize search results for a research workflow.\n```\n\nLoad it directly when editing or testing a preset:\n\n```typescript\nimport { loadMdaConfig } from \"@snoai\u002Fllmix\";\n\nconst config = await loadMdaConfig(\".\u002Fconfig\u002Fllm\u002Fsource\u002Fsearch_summary\u002Fopenai_fast.mda\");\n```\n\n```python\nfrom llmix import load_mda_config\n\nconfig = load_mda_config(\".\u002Fconfig\u002Fllm\u002Fsource\u002Fsearch_summary\u002Fopenai_fast.mda\")\n```\n\n```rust\nuse llmix_rs::load_config;\n\nlet config = load_config(\".\u002Fconfig\u002Fllm\u002Fsource\u002Fsearch_summary\u002Fopenai_fast.mda\")?;\n```\n\nFor production services, use the registry.\n\n---\n\n## Config Registry\n\nUse this layout. Treat it as the public contract:\n\n```text\nconfig\u002Fllm\u002F\n  source\u002F\n    \u003Cmodule>\u002F\n      \u003Cpreset>.mda\n  current.json\n  compiled\u002F\n```\n\n`source\u002F` is edited by people. `current.json` and `compiled\u002F` are generated by\nLLMix. Store the trust anchor outside `config\u002Fllm`.\n\nThe release flow is:\n\n1. Put source presets in `config\u002Fllm\u002Fsource\u002F\u003Cmodule>\u002F\u003Cpreset>.mda`.\n2. Run the MDA CLI validation, integrity, signing, verification, and release\n   prepare steps.\n3. Run `llmix publish-registry`.\n4. Generate `config\u002Fllm\u002Fcurrent.json` and `config\u002Fllm\u002Fcompiled\u002F`.\n5. Run MDA CLI release finalize and doctor checks.\n6. Store the trust anchor outside `config\u002Fllm`.\n7. Open `config\u002Fllm` at runtime through LLMix with the external trust anchor.\n\nThe did:web example assumes these release-identity inputs already exist outside\n`config\u002Fllm`: `release\u002Fdid-web-private-key.pem` and `release\u002Fdid.json`. Provide\nthem from your release system or use the GitHub Actions Sigstore\u002FRekor profile\ninstead.\n\n```bash\nmkdir -p config\u002Fllm\u002Fsource\u002Fsearch_summary release deploy\n\nmda init --template llmix-preset \\\n  --module search_summary \\\n  --preset openai_fast \\\n  --provider openai \\\n  --model gpt-5-mini \\\n  --out config\u002Fllm\u002Fsource\u002Fsearch_summary\u002Fopenai_fast.mda\n\nmda validate config\u002Fllm\u002Fsource\u002Fsearch_summary\u002Fopenai_fast.mda \\\n  --target source \\\n  --json\n\nmda integrity compute config\u002Fllm\u002Fsource\u002Fsearch_summary\u002Fopenai_fast.mda \\\n  --target source \\\n  --write \\\n  --json\n\nmda release trust policy \\\n  --target llmix-registry \\\n  --profile did-web \\\n  --domain config.example.com \\\n  --out release\u002Ftrust-policy.json \\\n  --json\n\nmda sign config\u002Fllm\u002Fsource\u002Fsearch_summary\u002Fopenai_fast.mda \\\n  --profile did-web \\\n  --did did:web:config.example.com \\\n  --key-id did:web:config.example.com#release \\\n  --key-file release\u002Fdid-web-private-key.pem \\\n  --in-place \\\n  --json\n\nmda verify config\u002Fllm\u002Fsource\u002Fsearch_summary\u002Fopenai_fast.mda \\\n  --target source \\\n  --policy release\u002Ftrust-policy.json \\\n  --did-document release\u002Fdid.json \\\n  --json\n\nmda release prepare \\\n  --target llmix-registry \\\n  --source config\u002Fllm\u002Fsource \\\n  --registry-dir config\u002Fllm \\\n  --policy release\u002Ftrust-policy.json \\\n  --did-document release\u002Fdid.json \\\n  --out release\u002Fplan.json \\\n  --json\n```\n\n```bash\nllmix publish-registry \\\n  --root config\u002Fllm \\\n  --release-plan release\u002Fplan.json \\\n  --revision 2026-05-14T000000Z \\\n  --policy release\u002Ftrust-policy.json \\\n  --did-document release\u002Fdid.json \\\n  --root-did did:web:config.example.com \\\n  --root-key-id did:web:config.example.com#release \\\n  --root-key-file release\u002Fdid-web-private-key.pem \\\n  --json\n\nmda release finalize \\\n  --target llmix-registry \\\n  --registry-dir config\u002Fllm \\\n  --registry-root config\u002Fllm\u002Fcompiled\u002F2026-05-14T000000Z\u002Fregistry-root.json \\\n  --release-plan release\u002Fplan.json \\\n  --policy release\u002Ftrust-policy.json \\\n  --derive-root-digest \\\n  --minimum-revision 2026-05-14T000000Z \\\n  --out deploy\u002Fllmix-trust.json \\\n  --did-document release\u002Fdid.json \\\n  --json\n\nmda doctor release \\\n  --target llmix-registry \\\n  --source config\u002Fllm\u002Fsource \\\n  --registry-dir config\u002Fllm \\\n  --release-plan release\u002Fplan.json \\\n  --manifest deploy\u002Fllmix-trust.json \\\n  --did-document release\u002Fdid.json \\\n  --json\n\nllmix check-registry \\\n  --root config\u002Fllm \\\n  --trust deploy\u002Fllmix-trust.json \\\n  --preset search_summary\u002Fopenai_fast \\\n  --did-document release\u002Fdid.json \\\n  --tamper-proof \\\n  --json\n```\n\nRuntime code opens the generated registry with the external trust anchor:\n\n```typescript\nimport {\n  ConfigRegistryManager,\n  loadLlmixTrustManifest,\n  registryRootOptionsFromTrustManifest,\n} from \"@snoai\u002Fllmix\";\n\nconst trust = await loadLlmixTrustManifest(process.env.LLMIX_TRUST_ANCHOR!);\nconst manager = await ConfigRegistryManager.open(\"config\u002Fllm\", {\n  signedRoot: registryRootOptionsFromTrustManifest(trust, { didWebVerifier }),\n});\nconst config = await manager.getPreset(\"search_summary\", \"openai_fast\");\n```\n\n`didWebVerifier` is the app verifier hook required by this did:web policy. For a\ncommand-line runtime proof, use `llmix check-registry --did-document\nrelease\u002Fdid.json`; in app code, pass the verifier hooks required by your trust\npolicy.\n\nManagers expose the active revision and reload health metadata. That makes it\neasy to say exactly which config a service is running. See\n[Secure LLMix Configuration with MDA](docs\u002Fllmix\u002Fsecure-mda\u002Fsecure-llmix-configuration.md)\nfor the complete release flow and runtime tamper-rejection proof.\n\n`ConfigRegistryPublisher` is still available for advanced release systems, but\nthe default public path is the `llmix publish-registry` command. Do not write a\nproject-local registry compiler.\n\n---\n\n## Provider Coverage\n\nThe public dispatch helpers cover the providers we actually test.\n\n| Provider | Python | TypeScript | Notes |\n|----------|--------|------------|-------|\n| OpenAI | `openai_dispatch` | `openaiDispatch` | OpenAI Responses and chat-style flows |\n| Anthropic | `anthropic_dispatch` | `anthropicDispatch` | Messages API, thinking budget validation |\n| Gemini | `gemini_dispatch` | `geminiDispatch` | Google GenAI-compatible params |\n| OpenRouter | `openrouter_dispatch` | `openrouterDispatch` | OpenAI-compatible |\n| DeepInfra | `deepinfra_dispatch` | `deepinfraDispatch` | OpenAI-compatible |\n| Novita | `novita_dispatch` | `novitaDispatch` | OpenAI-compatible |\n| Together | `together_dispatch` | `togetherDispatch` | OpenAI-compatible |\n| Sno GPU | `sno_gpu_dispatch` | `snoGpuDispatch` | On-prem OpenAI-compatible GPU endpoints |\n\nRust currently ships the neutral pipeline plus feature-gated helpers for OpenAI, Anthropic, Gemini, and Sno GPU. Treat Rust provider helpers as beta. The cache, key-pool, registry, retry, and pipeline contract are aligned with Python and TypeScript.\n\nOpenAI-compatible providers reuse the OpenAI request shape with provider-specific `base_url` handling. That keeps the contract plain. Plain is useful.\n\n---\n\n## Environment Variables\n\n| Variable | Purpose |\n|----------|---------|\n| `OPENAI_API_KEY` \u002F `OPENAI_KEYS` | OpenAI key or comma-separated key pool |\n| `ANTHROPIC_API_KEY` \u002F `ANTHROPIC_KEYS` | Anthropic key or comma-separated key pool |\n| `GEMINI_API_KEY` \u002F `GEMINI_KEYS` | Gemini key or comma-separated key pool |\n| `OPENROUTER_API_KEY` \u002F `OPENROUTER_KEYS` | OpenRouter key or comma-separated key pool |\n| `DEEPINFRA_API_KEY` \u002F `DEEPINFRA_KEYS` | DeepInfra key or comma-separated key pool |\n| `TOGETHER_API_KEY` \u002F `TOGETHER_KEYS` | Together key or comma-separated key pool |\n| `NOVITA_API_KEY` \u002F `NOVITA_KEYS` | Novita key or comma-separated key pool |\n| `SNO_LLM_API_KEY` | Sno GPU direct dispatcher fallback |\n| `SNO_GPU_API_KEY` \u002F `SNO_GPU_KEYS` | Sno GPU key-pool variables for provider id `sno-gpu` |\n| `GPU_BASE_URL` | Sno GPU base URL |\n| `REDIS_URL` | Redis response-cache URL |\n| `LLMIX_STATE_DIR` | Lock files, batch metadata, and kill-switch state |\n\n`load_keys_from_env(\"provider-name\")` checks `PROVIDER_NAME_KEYS` first, then `PROVIDER_NAME_API_KEY`. Dashes become underscores.\n\n---\n\n## What This Is Not\n\n- Not a streaming framework. Streaming stays with your SDK.\n- Not a prompt framework. Bring your own prompt layer.\n- Not a provider marketplace. One call uses the provider named by its config.\n- Not a reason to hide every model decision behind indirection. Some things should stay in code.\n\nLLMix is useful when the same model-call shape keeps showing up across services. If you have one script and one key, you probably do not need it yet.\n\n---\n\n## Development\n\n```bash\n# Install TypeScript workspace dependencies\nbun install\n\n# Install Python workspace dependencies\nuv sync --project packages\u002Fllmix\u002Fpython --extra dev\nuv sync --project packages\u002Fmda-config\u002Fpython --all-groups\n\n# Full monorepo checks\nbun run build\nbun run check\nbun run test\n```\n\n---\n\n## License\n\n[Apache-2.0](LICENSE)\n\n## Related\n\n- [AI SDK](https:\u002F\u002Fai-sdk.dev\u002F)\n- [Promptix](https:\u002F\u002Fgithub.com\u002Fsno-ai\u002Fpromptix)\n","LLMix 是一个用于AI代理和工具的生产级大语言模型调用层，支持OpenAI、Anthropic等多平台SDK，并提供模型热切换、缓存、重试、断路器、密钥轮换等功能。该项目采用配置驱动的方式，使得开发者无需更改原有代码即可实现模型行为调整，同时通过预设配置管理模型参数，增强了应用的灵活性与稳定性。它适用于需要在不同环境下快速切换模型或优化API调用性能的场景，如企业级AI服务部署、多语言环境下的统一接口封装等。项目支持Python、TypeScript及Rust三种编程语言，确保了跨平台的一致性。",2,"2026-06-11 03:53:01","CREATED_QUERY"]