Skip to main content

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xnano-0.0.49.tar.gz (354.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xnano-0.0.49-py3-none-any.whl (148.4 kB view details)

Uploaded Python 3

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

Hashes for xnano-0.0.49.tar.gz
Algorithm Hash digest
SHA256 a9373c2f3ee3191e2afcf344484abc8cf31ec4f1c177a66fbaf9021eaa18f2e0
MD5 aff158dad36d85d827714778e9d49fe9
BLAKE2b-256 f99d5900e6e23a1c1ba0f3c24ae29d1be44382fc5dbfb0e446fc493ffabcdb56

See more details on using hashes here.

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

Hashes for xnano-0.0.49-py3-none-any.whl
Algorithm Hash digest
SHA256 633c790b4ce7effdf4f98d331e7e8ea64e846d3c5e6f807ed2a0d156ff9b8db3
MD5 ed2fb3fd3ec00634f21016a5d779fc15
BLAKE2b-256 d008bf5c31a2a482bd5ff6f0402cb91c5524ee46285ff974e919d5a8940f2f8a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page