Description of Noema
Project description
Noema is an application of the declarative programming paradigm to a langage model. With Noema, you can control the model and choose the path it will follow. This framework aims to enable developpers to use LLM as an interpretor, not as a source of truth. Noema is built on llamacpp and guidance's shoulders.
Concept
- Noesis: can be seen as the description of a function
- Noema: is the representation (step by step) of this description
- Constitution: is the process of transformation Noesis->Noema.
- (Transcendantal) Subject: the object producing the Noema via the constitution of the noesis. Here, the LLM.
- Horizon: the environement of the subject, in other words, a context.
Noema/Noesis, Subject, Horizon and Constitution are a pedantic and naive application of concept borrowed from Husserl's phenomenology.
Installation
pip install git+https://github.com/AlbanPerli/Noema-Declarative-AI
Features
Create the Subject
from Noema import *
subject = Subject("model.gguf") # Full Compatibiliy with LLamaCPP.
subject.add(Var("Time is the only problem", "{thougth}")) # store "Time is the only problem" in {thougth}
Create an horizon
from Noema import *
horizon = Horizon(
Sentence("You explain why {thougth}","{thougth_explanation}"), # The sentence produced is stored in {thougth_explanation}
Int("Give a note between 0 and 10 to qualify the quality of your explanation.","{explanation_note}"), # The model produce an python integer that is stored in {explanation_note}
)
Constitution
from Noema import *
subject = horizon.constituteWith(subject) # The horizon is constituted by the LLM
# Read the noema
print(subject.noema)
# You are functioning in a loop of thought. Here is your reasoning step by step:
# #THOUGTH_EXPLANATION: Explain why '{thougth}'.
# #EXPLANATION_NOTE: Give a note between 0 and 10 to qualify the quality of your explanation.
# Here is the result of the reasoning:
# #THOUGTH_EXPLANATION: The reason is that time is the only thing that is constant and cannot be changed.
# #EXPLANATION_NOTE: 10
# Acces to each constitution separatly
print(subject.data["explanation_note"] * 2) # The value of 'explanation_note' is an int.
# 20
Simple generators
Generators can be used to generate content from the subject (LLM) through the noesis (here, the task description).
from Noema import *
horizon = Horizon(
Sentence("task description","{var_name}") # Produce a sentence stored in {var_name}
Word("task description","{var_name}") # Produce a word stored in {var_name}
Int("task description","{var_name}") # Produce an int stored in {var_name}
Float("task description","{var_name}") # Produce a float stored in {var_name}
Bool("task description","{var_name}") # Produce a bool stored in {var_name}
)
Composed generators
ListOf can be built with simple generators or a custom Step.
from Noema import *
horizon = Horizon(
ListOf(Word, "task description","{var_name}") # Produce a list of Word stored in {var_name}
ListOf(Int, "task description","{var_name}") # Produce a list of int stored in {var_name}
...
)
Selector
from Noema import *
horizon = Horizon(
Select("Are local LLMs the future?", ["Yes of course","Never!"], "{this_is_the_future}"), # The model can only choose between "Yes of course" and "Never!".
)
Information
Information are useful to insert some context to the current step of the noesis. Here we use a simple string, but we can also call a python function to do some RAG or other tasks.
from Noema import *
subject = Horizon(
Information("You act like TARS in interstellar."),
Sentence("Tell a short joke.","{joke}"),
Print("{joke}")
).constituteWith(subject)
Control Flow
IF/ELSE
from Noema import *
subject = Horizon(
Sentence("Explain why '{thougth}'.","{thougth_explanation}"),
Int("Give a note between 0 and 10 to qualify the quality of your explanation.","{explanation_note}"),
IF("{explanation_note} < 5", [
Select("Do some auto-analysis, and choose a word to qualify your note", ["Fair","Over optimistic","Neutral"], "{auto_analysis}"),
],ELSE=[
Select("Do some auto-analysis, and choose a word to qualify your note", ["Over optimistic","Neutral"], "{auto_analysis}"),
IF("'{auto_analysis}' == 'Over optimistic'", [ # Note the " ' " around {auto_analysis}
Int("How many points do you think you should remove to be fair?","{points_to_remove}"),
Sentence("Explain why you think you should remove {points_to_remove} points.","{points_explanation}"),
])
])
).constituteWith(subject)
print(subject.data["auto_analysis"]) # "Over optimistic"
print(subject.data["points_to_remove"]) # 1
print(subject.data["points_explanation"]) # "The explanation is not clear enough, and the note is too high."
ForEach
from Noema import *
subject = Horizon(
ListOf(Sentence, "What are the problems you are facing (in order of difficulty)?","{problems}"), # The model produce a list of sentence that is stored in {problems}
ForEach("{problems}","{item}","{count}", [
Sentence("Explain why '{item}' is the problem No {count}.","{item_explanation}"),
Print("Pb Nb {count}: {item}. Explanation: {item_explanation}") # Print doesn't interfere with the Noema
])
).constituteWith(subject)
# DEBUG: Pb Nb 1: I can't find a solution to the problem.. Explanation: Because if you can't find a solution, you can't make progress.
# DEBUG: Pb Nb 2: I don't know where to start.. Explanation: Because if you don't know where to start, you can't make any progress either.
# DEBUG: Pb Nb 3: I'm overwhelmed by the complexity of the problem.. Explanation: Because if you're overwhelmed, you can't focus on finding a solution or even knowing where to start.
While
from Noema import *
subject = Horizon(
Information("You have to choose a job name in the field of computer science."),
Var(0,"{word_length}"),
While("{word_length} < 7",[
Word("Give a good job name:","{job_name}"),
Int("How many letters are in the word {job_name}?","{word_length}"),
Print("Selected job {job_name}"),
Information("You have to choose a new job name each time."),
]),
Print("The word {job_name} has more than 10 letters."),
PrintNoema()
).constituteWith(subject)
NOESIS
The Noesis is the descriptive process of a thought. You can think about it as a set of rules aiming to attain a goal. In a function we think about steps, here you have to declare how to think about the steps.
A Noesis need a description, here: "Find a job name in a field." and can take optionnal parameters.
The Return is optional.
from Noema import *
find_job_name = Noesis("Find a job name in a field.",["field_name","max_length"],[
Information("You have to choose a job name in the field of {field_name}."),
Var(0,"{word_length}"),
While("{word_length} < {max_length}",[
Word("Give a good job name:","{job_name}"),
Int("How many letters are in the word {job_name}?","{word_length}"),
Print("Selected job {job_name}"),
Information("You have to choose a new job name each time."),
]),
Return("{job_name} is a good job name in the field of {field_name}.") #Return value
])
subject = Horizon(
Var(Constitute(find_job_name,("IT","10")),"{job_name}"), # Call the noesis "find_job_name" with the arguments "IT" and 10 and store the result in {job_name}
Print("{job_name} has more than 10 letters."),
).constituteWith(subject)
Python Function Call
In the Noesis we can call a python function.
The parameters can be value extracted from the context i.e. a Var using {var_name}.
Return value of the python function called can be stored in a Var.
from Noema import *
def count_letters(word):
return len(word)
subject = Horizon(
Var("TENET", "{palindrome}"), # store "TENET" in {palindrome}
Var(CallFunction(count_letters, "{palindrome}"), "{word_length}"), # store the result of the function count_letters in {word_length}
Print("The word '{palindrome}' has {word_length} letters."),
).constituteWith(subject)
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 Noema-1.0.1.tar.gz.
File metadata
- Download URL: Noema-1.0.1.tar.gz
- Upload date:
- Size: 114.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.11.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35b05f4d2f964a7c8753e2a53c43c67bed6984e6e21b28efd66ce81850b8d8cc
|
|
| MD5 |
9f5471e8d91593c4aaed17befa238322
|
|
| BLAKE2b-256 |
a420aa132819d6e7f9d1f0361bc93a676f351faff1be1546e0640b1cd917ad88
|
File details
Details for the file Noema-1.0.1-py3-none-any.whl.
File metadata
- Download URL: Noema-1.0.1-py3-none-any.whl
- Upload date:
- Size: 23.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.1.1 CPython/3.11.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a333872f63b0da2fb6ce1fb25139d2b9146d4d40d91d023fcb7cae4027c2908
|
|
| MD5 |
33c52abd33dc222b78d509ee297674da
|
|
| BLAKE2b-256 |
710d3780bf14e207d33b7dbfb79cbede142b9c4df4550cd9c5ad51b93e82743f
|