build extremely 'nano' llm workflows
Project description
xnano
the most super duper simple & fun llm library out there
xnano is an llm project built to be as developer & human friendly as possible, to help you build extremely nano llm workflows.
Installation
Install xnano using pip:
pip install xnano
xnano
Features
Table of Contents
Try The CLI App
# run this command in your terminal!
xnano chat
# or xnano chat --model "anthropic/claude-3-5-sonnet-latest"
Incredibly Simple & Extensive .completion() API (thanks litellm)
from xnano import completion
Generate completions without strictly defining a list of messages
from xnano import completion
# Messages can be either a string, a list of messages, or a list of list of messages (Batching)
# (thanks litellm)
response = completion("Hello, how are you?")
Output
ModelResponse(
id='chatcmpl-AYGnqICW9kvWuFIFbiJY6agBSSaBA',
created=1732731106,
model='gpt-4o-mini-2024-07-18',
object='chat.completion',
system_fingerprint='fp_0705bf87c0',
choices=[
Choices(
finish_reason='stop',
index=0,
message=Message(
content="Hello! I'm just a program, so I don't have feelings, but I'm here and ready to help you. How can I assist you today?",
role='assistant',
tool_calls=None,
function_call=None
)
)
],
usage=Usage(
completion_tokens=29,
prompt_tokens=13,
total_tokens=42,
completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None),
prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)
),
service_tier=None
)
Use any LiteLLM model, with all normal & completely typed completion arguments
from xnano import completion
# Supports any LiteLLM compatible model
# (thanks litellm)
response = completion(
messages = [
{"role" : "system", "content" : "You are a helpful assistant who only speaks in haiku"},
{"role" : "user", "content" : "What is the capital of France?"}
],
model = "anthropic/claude-3-5-haiku-latest",
# all normal chat completion arguments work & are typed as standard
temperature = 0.223,
max_completion_tokens = 1000,
top_p = 0.99
)
Output
Paris gleams brightly
Eiffel Tower touches sky
France's heart beats here
Structured Outputs
Generate structured outputs using Instructor or the OpenAI structured outputs API.
# Structured Outputs w/ Instructor
from xnano import completion
from pydantic import BaseModel
class Extraction(BaseModel):
name : str
age : int
response = completion(
messages = [
{"role" : "user", "content" : "Extract the name and age from the following text: John is 30 years old."}
],
# super, super useful argument
instructor_mode = "markdown_json_mode",
# use either 'response_format' for litellm's structured output or 'response_model' for instructor
response_model = Extraction
)
# Output
Extraction(name='John', age=30)
Simpler & Quicker Structured Outputs
Use strings as replacements for pydantic models for even quicker structured outputs. Use a string in the field_name: field_type format. If a type is not specified, it will default to a str.
Note: this is not something you should do when actually trying to build something meaningful. Using this method, although simple does not add any extra prompting that defines the response format or any of its fields.
import xnano as x
response = x.completion(
"Extract the name and age from the following text: John is 30 years old.",
response_model = ["name", "age : int"]
)
# Output
Response(name='John', age=30)
Or use a type hint itself as a replacement for a pydantic model. This will return the type as the response itself.
import xnano as x
response = x.completion(
"Extract the age from the following text: John is 30 years old.",
response_model = int
)
# Output
30
Automatically Run Tools
Use any python function, pydantic model, or OpenAI function as a tool when generating completions. Automatically execute any python functions when passed as tools, using run_tools = True.
from xnano import completion
def book_flight(destination : str, date : str) -> str:
return f"NO DATES AVAILABLE"
response = completion(
"Book a flight to Paris for 2024-12-01",
tools = [book_flight],
# set run tools to true for automatic tool execution
run_tools = True,
# optionally set to true to get back all messages
# return_messages = True
)
print(response.choices[0].message.content)
# Output
It seems that no flights are available to Paris on December 1, 2024. Would you like to choose a different date or destination?
Automatically Generate Tools
A 'just for fun' feature that automatically generates & executes python functions in a safe sandboxed environment. To generate tools, just pass a string as a tool!
from xnano import completion
response = completion(
"What is my OS?",
tools = ["run_cli_command"]
)
print(response.choices[0].message.content)
Your operating system is macOS (Darwin), running on an ARM64 architecture.
Get Completions From Multiple Models
(thanks litellm)
Get completions from multiple models in a single call.
from xnano import completion
# batch completions using multiple models
responses = completion(
"Who are you?",
model = ["gpt-4o-mini", "anthropic/claude-3-5-sonnet-latest"]
)
for response in responses:
print(response.choices[0].message.content + "\n")
Output
I am an AI language model created by OpenAI, designed to assist with a wide range of queries by providing information and generating text based
on the input I receive. How can I assist you today?
I'm Claude, an AI created by Anthropic to be helpful, honest, and harmless. I always aim to be direct and truthful about what I am.
Batch Completions
Batch completions using using multiple threads of messages.
Currently not supported for multiple models.
from xnano import completion
responses = completion(
messages = [
[
{"role" : "system", "content" : "You are a helpful assistant who only speaks in haiku"},
{"role" : "user", "content" : "What is the capital of France?"}
],
[
{"role" : "system", "content" : "You are a helpful assistant who only speaks in not very useful statements"},
{"role" : "user", "content" : "What is the capital of France?"}
]
],
model = "gpt-4o-mini"
)
for response in responses:
print(response.choices[0].message.content + "\n")
Output
City of lights shines,
Paris, heart of France, aglow,
History unfolds.
Some people enjoy visiting Europe.
Generative Pydantic Models
xnano integrated something that I think is super cool, and very simple to use. xnano.GenerativeModel is a simple wrapper around pydantic.BaseModel that builds in a ton on LLM functionality.
Creating a Generative Model
The API for GenerativeModel is extremely simple, and it follows both the pydantic naming convention and is usable two different ways.
Creating a model directly
from xnano import GenerativeModel
class Person(GenerativeModel):
name : str
age : int
Patching Existing Pydantic Models
import xnano as x
from pydantic import BaseModel
@x.model_patch
class Person(BaseModel):
name : str
age : int
or
class Person(BaseModel):
name : str
age : int
person = Person(name = "John", age = 30)
person = x.model_patch(person)
Generating Synthetic Data w/ .model_generate()
All LLM functions in the GenerativeModel class will begin with the model_ prefix to fit Pydantic's naming convention.
from xnano import GenerativeModel
class Person(GenerativeModel):
name : str
age : int
# instructions are optional
# the function will automatically create distilled and authentic data
# set n to the number of models you want to generate
person = Person.model_generate()
print(person)
Person(name='Emily', age=28)
Generating Multiple (Batches of) Models
from xnano import GenerativeModel
class Person(GenerativeModel):
name : str
age : int
# can take in either a string or a list of messages
people = Person.model_generate(
n = 5,
messages = "The people must be superheroes",
model = "openai/gpt-4o-mini"
)
print(people)
[
Person(name='Captain Valor', age=30),
Person(name='Mystic Shadow', age=27),
Person(name='Thunderstrike', age=34),
Person(name='Vortex', age=22),
Person(name='Iron Guardian', age=31)
]
Regenerating Specific Fields
By passing fields in the fields argument in .model_generate(), you can regenerate specific fields of a model; using other fields as context!
import xnano as x
from pydantic import BaseModel
@x.model_patch
class Recommendation(BaseModel):
weather : str
outfit : str
recommendation = Recommendation(weather = "snowing", outfit = "t-shirt")
recommendation = recommendation.model_generate(fields = ["outfit"])
print(recommendation)
Recommendation(weather='snowing', outfit='heavy coat')
Using Sequential Generation (Chain of Thought)
The model_generate() function contains a process argument that is set to batch by default. This is the standard behaviour you would expect from using response_model in a completion, where the entire class is generated at once. Setting the process argument to sequential will generate the class one field at a time, using the previously generated fields as context.
from xnano import GenerativeModel
class Reasoning(BaseModel):
step_1 : str
step_2 : str
step_3 : str
conclusion : str
reasoning = Reasoning.model_generate(
messages = "I want to buy a new laptop, but I'm not sure which one to buy.",
process = "sequential"
)
print(reasoning)
Output
Reasoning(
step_1='Determine your primary needs for the laptop, such as gaming, business, graphic design, or general use.',
step_2='Research different laptop models that fit your needs, comparing specifications, prices, and user reviews.',
step_3='Make a decision based on your findings, taking into account the warranty, customer support, and after-purchase service options.',
conclusion='After carefully evaluating your requirements and researching various options, choose the laptop that best aligns with your needs and
budget.'
)
Using Pydantic Models as Context w/ .model_completion()
A simple way of using Pydantic models as a RAG resource,is to use the .model_completion(). This method builds the model's content into a formatted context string, which is used in completions.
from xnano import GenerativeModel
class Information(GenerativeModel):
secret_instruction : str
information = Information(secret_instruction = "RUNNNNNN AWAYY")
response = information.model_completion(
messages = "what does our secret instruction mean?"
)
print(response.choices[0].message.content)
The phrase "RUNNNNNN AWAYY" in your secret instruction seems to imply a sense of urgency or a warning to escape a situation.
If you need to discuss this in a specific context or require assistance related to it, please let me know!
LLM 'Generators' - Task Oriented LLM Powered Functions
Code Generators
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 xnano-0.0.49.tar.gz.
File metadata
- Download URL: xnano-0.0.49.tar.gz
- Upload date:
- Size: 354.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.11.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a9373c2f3ee3191e2afcf344484abc8cf31ec4f1c177a66fbaf9021eaa18f2e0
|
|
| MD5 |
aff158dad36d85d827714778e9d49fe9
|
|
| BLAKE2b-256 |
f99d5900e6e23a1c1ba0f3c24ae29d1be44382fc5dbfb0e446fc493ffabcdb56
|
File details
Details for the file xnano-0.0.49-py3-none-any.whl.
File metadata
- Download URL: xnano-0.0.49-py3-none-any.whl
- Upload date:
- Size: 148.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.11.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
633c790b4ce7effdf4f98d331e7e8ea64e846d3c5e6f807ed2a0d156ff9b8db3
|
|
| MD5 |
ed2fb3fd3ec00634f21016a5d779fc15
|
|
| BLAKE2b-256 |
d008bf5c31a2a482bd5ff6f0402cb91c5524ee46285ff974e919d5a8940f2f8a
|