Skip to content

Episode 1: A chatbot in one file

Quickstart · Episode 1 of 4

Let's start with something fun and immediate: your own little AI that you can chat with, running on your machine, reachable over the network.

The idea

We'll take a ready-made language model, wrap it in an agent, put that agent on the network inside a node, and let it wait for someone to talk to it. That "someone" can be you, from a web browser.

What's a language model (LLM)?

A language model is an AI that reads text and writes text back, you type a question, it produces an answer. ChatGPT is a famous large one. We'll use TinyLLama, a tiny one that runs comfortably on a normal computer. It won't be as clever as ChatGPT, but it's perfect for learning, and it's yours, running locally.

What are agent, node, and lone wolf?
  • An agent is a participant on the network: a "brain" (here, the language model) plus what it accepts and produces (here, text in, text out).
  • A node is the body that puts an agent on the network and handles all the connection plumbing.
  • A lone wolf is an agent that serves on the public network on its own, no group, just waiting for anyone to reach it. That's what we're building here.

First: the "brain" is yours

Before the code, one thing that matters a lot: UNaIVERSE does not give you the AI. The "brain" of an agent, its processor, is just your code, wrapped in a tiny class with a forward() method. UNaIVERSE runs whatever your forward() returns and never cares what's inside it. A brain can be almost anything:

The simplest brain imaginable, it just adds:

import torch

class Adder(torch.nn.Module):
    def forward(self, a, b):
        return a + b

A brain that forwards text to an external LLM endpoint (vLLM, OpenAI-compatible, …) and returns the answer:

import torch

class RemoteLLM(torch.nn.Module):
    def forward(self, prompt):
        return call_my_vllm_server(prompt)   # your function

A brain that looks something up, no neural network at all:

import torch

class Lookup(torch.nn.Module):
    def forward(self, query):
        return my_vector_store.search(query)

No AI at all, read a sensor, or switch something on. Perfect for IoT and home automation:

import torch

class MoistureSensor(torch.nn.Module):          # an INPUT agent
    def forward(self, x=None):
        return read_soil_moisture()             # your hardware function

class Valve(torch.nn.Module):                   # an OUTPUT agent
    def forward(self, open_it):
        switch_irrigation(open_it)              # flip a relay / GPIO pin
        return open_it

A moisture sensor and an irrigation valve are now first-class agents that can talk to each other, see For IoT & hardware builders.

Your own trained model, what most people eventually plug in:

my_agent = Agent(proc=MyNeuralNet(), proc_inputs=[...], proc_outputs=[...])

So why are we about to import TinyLLama? Purely for convenience. It's a ready-made brain from UNaIVERSE's model zoo, so this first step can be about the network, not about building a model. You'll wire in your own brain in Episode 3.

The one rule about processors

A processor must be a torch.nn.Module (or None for a coordinator with no brain). That's just PyTorch's standard container, wrap your logic in a small class like above. A bare lambda won't do; a three-line module will. Details in Agents.

The code

Create a file called chatbot.py:

chatbot.py
from unaiverse.agent import Agent
from unaiverse.modules.networks import TinyLLama
from unaiverse.networking.node.node import Node

# 1. The "brain". Here we BORROW a ready-made language model from the model zoo
#    for convenience (text in, text out). It could just as well be your own
#    torch.nn.Module, see "the brain is yours" above.
brain = TinyLLama()

# 2. Wrap it in an agent. We tell it the kind of data it accepts and produces:
#    plain "text" for both.
agent = Agent(proc=brain, proc_inputs=["text"], proc_outputs=["text"])

# 3. Put the agent on the network inside a node.
#    - node_name: how others will find it
#    - hidden=True: only YOUR account can see it for now (a private test)
#    - clock_delta: how often it "thinks", here, 25 times a second
node = Node(agent, node_name="MyChatbot", hidden=True, clock_delta=1./25.)

# 4. Go live and wait for someone to talk to us. This runs until you stop it.
node.run()

Run it

python chatbot.py

The first time, you'll be asked to paste your token (copy it from unaiverse.io). After that it's remembered. The model may take a moment to download and load the first time, too.

When you see it settle and wait, your agent is live on the network under the name MyChatbot. Leave this terminal running.

Chat with it (no code)

Open unaiverse.io in your browser, sign in with the same account, find MyChatbot (it's there because you're the owner, remember hidden=True), and send it a message. It replies. 🎉

You just talked to an AI you're hosting yourself.

What just happened

graph LR
    You[You, in the browser] -->|your message as text| N[Node 'MyChatbot']
    N --> A[Agent]
    A --> B[TinyLLama brain<br/>thinks]
    B -->|reply as text| You
  • You wrapped a model in an agent and hosted it in a node.
  • proc_inputs=["text"] / proc_outputs=["text"] told UNaIVERSE this agent speaks text, a small contract called a data stream type.
  • node.run() with no arguments means lone wolf: serve on the public network and wait.
  • The browser is just another agent (a human one) reaching yours.

Try a different brain

Swap TinyLLama() for Phi() (a slightly bigger, smarter model), same three lines. Both come from the model zoo. Larger models are slower and like a GPU, but work on CPU too.

Two small gotchas

  • Leave it running. node.run() blocks, that's normal; it's serving. Stop it with Ctrl+C.
  • First run is slowest. The model download + token prompt only happen once.

Episode 1 recap

You now know agent, node, and lone wolf, and you have a personal chatbot on the network. Everything else builds on this.