Functional architecture

Implementing the agent-server model has been a little difficult. The most difficult to implement so far has been reiterating upon previous output, obviously essential for anything evolution.

I found that the issue was how I was thinking about the simulation from its top-down perspective. As I have discussed, agents exist in a simulation. The simulation component is a small part of the overall system. I initially conceptualized and tried to implement these agents as objects in a greater system, that being the simulation. This works, however, it fails to manifest productive, iterable output, mostly because I was hung up on trying to get the agents to interact in a “natural” way. Given though that this isn’t an experiment to observe agents in a simulated world and instead evolve a conlang, I had an epiphany about the entire project’s architecture.

The epiphany

The entire project can be thought about as a giant function. There is input and there is output. The input is a conlang and the output is the same conlang, just evolved. The inputs and outputs are now clearly defined, and the simulation that the agents exist in is a means to an end rather than the end itself.

Generative agents have a tendency to think too much outside of the box (hallucinate or go hog wild), so the main challenge here then becomes the workflow to harnessing their productive entropy, meaning, pushing the limits of their creativity but not enough to cause a disaster. On a micro-scale, this takes the form of tuning temperatures and weights. On the macro-scale, this takes the form of a controlled, functional workflow.

Functional layering

I have chosen to develop the evolution of the language in several ordered steps, which I call layers:

  1. Phonetics
  2. Grammar
  3. Words
  4. Logography

Each layer is itself a function, in other words, it takes input and produces output. The output of each layer is then passed to the next layer.

There is also possibility for a recursive implementation of architecture. Rather than iterating through each step of the process, the procedure can progress recursively starting from layer 4 all the way to layer 1. When each layer returns, it uses that resulting output as the input for the previous layer.

Secondary functions

The primary function is the main procedure that evolves the conlang. Secondary functions of this operation is the translation function. The translation function is fed the evolved version of the conlang and translates a text from English into the target conlang. The output is the translated text.

Another secondary function is the visualization. The visualization of “what’s going on” is an impure function that takes the system’s information and displays it on a screen.

Inputs and Outputs

Here are the inputs for each functional layer. The word “specification” is abbreviated as “spec”. ' represent the new version of the input, or input prime:

Definition: Layer(spec) → spec'

  1. Phonetics(phonetics) → phonetics'
  2. Grammar(grammar, phonetics) → grammar'
  3. Words(dictionary, grammar, phonetics) → dictionary'
  4. Logography(logography, dictionary) → logography'

For the secondary functions, here are their inputs and outputs:

  1. Translation(text, grammar, dictionary) → text'
  2. Visualization(text, grammar, dictionary, logography, ...data)

Agent models

So where do agents fit into this equation?

Agents exist in each layer. Agents can be separated into two types: interlocutors and system. Each layer has n interlocutors that are synchronized and in communication with each other. Interactions take place over 10 to 20 back-and-forth rounds. At the end of each round, system agents read over the generated conversation and manipulate the output specification.

Separation of concerns

The work I have done over the past several weeks is useful, because I now have a basic agent architecture that can be manipulated to perform various procedures and tasks at each layer.

Keep in mind that each agent runs in its own program. This allows agents to be digitally separated rather than “exist” in a single program that makes multiple queries to the database. The main reason for this is the separation of concerns and literal decoupling. An agent is truly isolated from other agents in the simulation when they exist as a different process run by the OS. Furthermore, this makes deployment to a different platform easy. Agents can be deployed to a Raspberry Pi if needed.

For each layer then, either the same agents can be reused or new agents that have a different memory can be used. I am opting for the latter, which means I will have at least 8 interlocutor agents running in parallel. Each agent on each layer has their very own memory. Reusing agents would be a more complicated approach, which requires switching out memory for each layer.

← back to blog posts