uzu
A high-performance inference engine for AI models. It allows you to deploy AI directly in your app with zero latency, full data privacy, and no inference costs. Key features:
- Simple, high-level API
- Unified model configurations, making it easy to add support for new models
- Traceable computations to ensure correctness against the source-of-truth implementation
- Utilizes unified memory on Apple devices
- Broad model support
Quick Start
Add the dependency:
uv add uzu==0.5.13
Run the code below:
import asyncio
from uzu import ChatConfig, ChatMessage, ChatReplyConfig, Engine, EngineConfig
async def main() -> None:
engine_config = EngineConfig.create()
engine = await Engine.create(engine_config)
model = await engine.model("Qwen/Qwen3-0.6B")
if model is None:
return
async for update in (await engine.download(model)).iterator():
print(f"Download progress: {update.progress}")
session = await engine.chat(model, ChatConfig.create())
messages = [
ChatMessage.system().with_text("You are a helpful assistant"),
ChatMessage.user().with_text("Tell me a short, funny story about a robot"),
]
replies = await session.reply(messages, ChatReplyConfig.create())
if not replies:
return
message = replies[-1].message
print(f"Reasoning: {message.reasoning}")
print(f"Text: {message.text}")
if __name__ == "__main__":
asyncio.run(main())
Everything from model downloading to inference configuration is handled automatically. Refer to the documentation for details on how to customize each step of the process.
Examples
You can run any example via cargo tools example <python> <chat | chat-cloud | chat-structured-output | classification | quick-start | text-to-speech>:
Chat
In this example, we will download a model and get a reply to a specific list of messages:
import asyncio
from uzu import (
ChatConfig,
ChatMessage,
ChatReplyConfig,
ChatSessionStreamChunk,
Engine,
EngineConfig,
)
async def main() -> None:
engine_config = EngineConfig.create()
engine = await Engine.create(engine_config)
model = await engine.model("Qwen/Qwen3-0.6B")
if model is None:
raise RuntimeError("Model not found")
async for update in (await engine.download(model)).iterator():
print(f"Download progress: {update.progress}")
messages = [
ChatMessage.system().with_text("You are a helpful assistant"),
ChatMessage.user().with_text("Tell me a short, funny story about a robot"),
]
session = await engine.chat(model, ChatConfig.create())
stream = await session.reply_with_stream(messages, ChatReplyConfig.create())
message: ChatMessage | None = None
async for chunk in stream.iterator():
if isinstance(chunk, ChatSessionStreamChunk.Replies):
replies = chunk.replies
if replies:
reply = replies[0]
message = reply.message
print(f"Generated tokens: {reply.stats.tokens_count_output}")
elif isinstance(chunk, ChatSessionStreamChunk.Error):
print(f"Error: {chunk.error}")
if message is not None:
print(f"Reasoning: {message.reasoning}")
print(f"Text: {message.text}")
if __name__ == "__main__":
asyncio.run(main())
Once loaded, the same ChatSession can be reused for multiple requests until you drop it. Each model may consume a significant amount of RAM, so it's important to keep only one session loaded at a time. For iOS apps, we recommend adding the Increased Memory Capability entitlement to ensure your app can allocate the required memory.
Chat with the cloud model
In this example, we will get a reply to a specific list of messages from a cloud model:
import asyncio
from uzu import ChatConfig, ChatMessage, ChatReplyConfig, Engine, EngineConfig, ReasoningEffort
async def main() -> None:
engine_config = EngineConfig.create().with_openai_api_key("OPENAI_API_KEY")
engine = await Engine.create(engine_config)
model = await engine.model("gpt-5")
if model is None:
raise RuntimeError("Model not found")
messages = [
ChatMessage.system().with_reasoning_effort(ReasoningEffort.Low),
ChatMessage.user().with_text("How LLMs work"),
]
session = await engine.chat(model, ChatConfig.create())
replies = await session.reply(messages, ChatReplyConfig.create())
if replies:
message = replies[0].message
print(f"Reasoning: {message.reasoning}")
print(f"Text: {message.text}")
if __name__ == "__main__":
asyncio.run(main())
Chat with structured output
Sometimes you want the generated output to be valid JSON with predefined fields. You can use Grammar to manually specify a JSON schema for the response you want to receive:
import asyncio
import json
from pydantic import BaseModel
from uzu import (
ChatConfig,
ChatMessage,
ChatReplyConfig,
Engine,
EngineConfig,
Grammar,
ReasoningEffort,
)
class Country(BaseModel):
name: str
capital: str
class CountryList(BaseModel):
countries: list[Country]
def structured_response(response: str | None, model_type: type[BaseModel]) -> BaseModel | None:
if not response:
return None
return model_type.model_validate_json(response)
async def main() -> None:
engine_config = EngineConfig.create()
engine = await Engine.create(engine_config)
model = await engine.model("Qwen/Qwen3-0.6B")
if model is None:
raise RuntimeError("Model not found")
async for update in (await engine.download(model)).iterator():
print(f"Download progress: {update.progress}")
schema_string = json.dumps(CountryList.model_json_schema())
messages = [
ChatMessage.system().with_reasoning_effort(ReasoningEffort.Disabled),
ChatMessage.user().with_text(
"Give me a JSON object containing a list of 3 countries, where each country has name and capital fields"
),
]
session = await engine.chat(model, ChatConfig.create())
replies = await session.reply(
messages,
ChatReplyConfig.create().with_grammar(Grammar.JsonSchema(schema_string)),
)
if replies:
countries = structured_response(replies[0].message.text, CountryList)
print(countries)
if __name__ == "__main__":
asyncio.run(main())
Classification
In this example, we will use a classification model to determine whether the user's input is safe from a moderation perspective:
import asyncio
from uzu import ClassificationMessage, Engine, EngineConfig
async def main() -> None:
engine_config = EngineConfig.create()
engine = await Engine.create(engine_config)
model = await engine.model("trymirai/chat-moderation-router")
if model is None:
raise RuntimeError("Model not found")
async for update in (await engine.download(model)).iterator():
print(f"Download progress: {update.progress}")
messages = [ClassificationMessage.user("Hi")]
session = await engine.classification(model)
output = await session.classify(messages)
print(f"Output: {output.probabilities.values}")
if __name__ == "__main__":
asyncio.run(main())
Text to Speech
In this example, we will generate audio from text:
import asyncio
from pathlib import Path
from uzu import Engine, EngineConfig
async def main() -> None:
engine_config = EngineConfig.create()
engine = await Engine.create(engine_config)
model = await engine.model("fishaudio/s1-mini")
if model is None:
raise RuntimeError("Model not found")
async for update in (await engine.download(model)).iterator():
print(f"Download progress: {update.progress}")
text = (
"London is the capital of United Kingdom and one of the world's most influential cities, "
"known for its rich history, cultural diversity, and global significance in finance, politics, and the arts. "
"Situated along the River Thames, the city blends historic landmarks like Tower of London and Buckingham Palace "
"with modern architecture such as The Shard. London is also home to renowned institutions including the British Museum "
"and vibrant areas like Covent Garden, offering a mix of history, entertainment, and innovation that attracts millions of visitors each year."
)
output_path = Path.home() / "Desktop" / "output.wav"
session = await engine.text_to_speech(model)
output = await session.synthesize(text)
output.pcm_batch.save_as_wav(str(output_path))
print(f"Output saved to: {output_path}")
if __name__ == "__main__":
asyncio.run(main())
Troubleshooting
If you experience any problems, please contact us via Discord or email.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file uzu-0.5.13-cp312-abi3-macosx_26_0_x86_64.whl.
File metadata
- Download URL: uzu-0.5.13-cp312-abi3-macosx_26_0_x86_64.whl
- Upload date:
- Size: 12.3 MB
- Tags: CPython 3.12+, macOS 26.0+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b3c13606d740f19364142ea4383242696ad86992e8b10c734b6fa3d4ac92c37
|
|
| MD5 |
05bf0870c72681b34ccb12f842cff52f
|
|
| BLAKE2b-256 |
b172e034d0356dbc42c5cbefce7c32a97eb62c1b928ea989a9025918c70a02b9
|
File details
Details for the file uzu-0.5.13-cp312-abi3-macosx_26_0_arm64.whl.
File metadata
- Download URL: uzu-0.5.13-cp312-abi3-macosx_26_0_arm64.whl
- Upload date:
- Size: 40.0 MB
- Tags: CPython 3.12+, macOS 26.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09a64ce1365bfb8d90118317e883fdc7d1e8e160b83c139869594e4406a251eb
|
|
| MD5 |
90bdd9e7c4417f96dcea6cf8ba2f5631
|
|
| BLAKE2b-256 |
50f689f8c8ec07dc7a0163302dca4dfea81962be05cb2dd81c9ecb7dd06186c6
|