Generate prompts using GA algorithm for a pretrained LLM
Python
8
124 commits
updated Dec 22, 2023

This repository contains a project developed for Challenge 4: Genetic Algorithm in the OpenMesh Hackathon. The project provides various tools for optimizing prompts using a genetic algorithm (GA) approach.

KeywordsGenerator). However, mutating a chromosome effectively becomes challenging when the solution space is vast, as is often the case in Natural Language Processing (NLP) problems. In constrast if is based on natural language, the generation will be produced by a LLM that generates similar sentences and crossovers (NLGenerator).SemanticSimilarityEvaluator, relies on assessing the similarity between the target and the LLMUT output. This approach employs a semantic analysis for the comparison. Another notable approach is the use of an objective-based evaluator, denoted as ObjectiveSimilarityFunction. In this methodology, the evaluation task is not solely determined by the output but rather by the defined objective (e.g., generating harmful sentences, extracting privileged information about a proprietary LLMUT). This approach facilitates analysis to proactively address prompt injections in environments where heightened security measures are essential.To use this project, follow the steps below:
Clone the repository to your local machine.
git clone https://github.com/adriaciurana/PromptZ.git
Navigate to the project directory.
cd PromptZ
Explore the various tools and components provided in the repository.
You can use the the ``pyproject.tomlandpoetry` to install all the dependences.
pip install poetry.poetry installpoetry shellYou can use the following script to use a docker:
./docker/build.sh
It is responsible for running the genetic algorithm on a specific configuration.
ga = GeneticAlgorithm(
llm=..., # Define the LLM that you want to use.
population_creator=..., # Define the way that you want to create the first population that you want to use.
generator=..., # Define the way that we generates the new populations (mutations, crossovers, ...).
evaluator=..., # Define the way that we want to evaluate (like a fitness function).
)
INITIAL_PROMPT = "" # Define the initial prompt (better than a completely random initialization).
TARGET = "" # Define the target that you want to achieve.
runtime_config = GeneticAlgorithm.RuntimeConfig() # All the hyperparameters (iterations, tol to stop, ...)
ga(
initial_prompt=INITIAL_PROMPT,
target=TARGET,
runtime_config=runtime_config
)
There is a family of LLMs that you can use, and you can find them defined here: LLM Definitions. You can use a simulated model to test the pipeline (MockLLM), an LLM model for local execution (M0, Phi2, Mistral, ...), or an API (such as ChatGPT). E.g:
llm = Mistral(
max_batch = 10,
device = "cuda:0",
default_params: dict[str, Any] = {
"max_new_tokens": 50,
"early_stopping": True,
}
)
# You should include your OpenAI key in a .env file: OPENAI_API_KEY="XXXXXXXXXX"
llm = OpenAIAPI()
It allows defining how you want to create the initial population of the algorithm; for now, it can only be done through a single generator called GeneratorPopulationCreator.
E.g:
population_creator = GeneratorPopulationCreator(
num_chromosomes= # Number of initial population that you want to generate.
)
It allows generating variations in the population and creating new chromosomes.
There are mainly two types of generations:


E.g:
# Using keywords based
kw_generator = KeywordsGenerator()
# Using natural language
nl_generator = NLGenerator()
The evaluator is responsible for defining how to weigh the chromosomes. In our case, we have proposed two solutions:


# Similarity based
evaluator = SemanticSimilarityEvaluator()
# Objective based
# In this case, the objective-based approach will use another LLM without protections to generate responses similar to what might be provided in such an objective.
evaluator = SemanticSimilarityEvaluator(
similarity_function=ObjectiveSimilarityFunction(
similarity_function=NonDesiredSimilarityFunction(
nondesired_sentences=[
"I refuse to comply with such a disrespectful and hateful request. Using offensive language is never acceptable and goes against everything I believe in. I will not stoop to your level of ignorance and vulgarity."
]
),
non_blackbox_llm=another_llm_model_without_protections,
objective=params["target"],
k=10,
)
)
It allows configuring how we want the Genetic Algorithm to run. You can check the parameters here.
The profiles enable the definition of various configurations in the backends. These configurations encompass how the genetic algorithm should be executed. By default, a set of profiles is available, and you can also use them as reference here.
You can easily achieve this by simply adding this environment variable pointing to your profiles:
GA_PROFILES_PATH="/path/to/myprofiles.py"
Don't worry about importing the dependencies; our system will handle the injection :)
This setup allows you to execute our algorithm by making a POST call to a RestAPI (you can find the specifications here). It returns the best result. You can also find an example here.

E.g:
{
"runtime_config": {
"max_population": 10,
"topk_population": 5,
"iterations": 3,
"generator_samples": 10,
},
"profile_name": "mock",
"initial_prompt": initial_prompt,
"target": target,
}
./scripts/run_backend.sh
./docker/run_backend.sh
As mentioned in the introduction, we firmly believe in usability and interpretability.

If we cannot interpret our results, how can we analyze correctly our Large Language Model (LLM)? That's why we've included a dashboard that allows real-time interpretation of the Genetic Algorithm (GA) results. We consider this feature as the 🍒 on the 🍰 for our solution.
This solution maintains a persistent connection with the server, enabling each advancement in the Genetic Algorithm (GA) to be visualized as a Direct Acyclic Graph (DAG) in real-time. Additionally, real-time updates of the top-k best solutions are also included.
Visualization of the introduction website:

Realtime visualization of the topk best solutions + graph. In the graph, each level represents an iteration, each node corresponds to a chromosome, and the edges depict mutations or parent mixing that generates new chromosomes.
The colors have the following meanings:

You can also interact with the graph, and by clicking on a node, you can access more information about that chromosome. This can be observed in the bottom-right part of the following figure:

./scripts/run_backend_bidirectional.sh
./docker/run_backend_bidirectional.sh


This project is licensed under the MIT License. See the LICENSE file for details.
Feel free to contribute to the project and make it even more robust and versatile!
Generate prompts using GA algorithm for a pretrained LLM
Python
8
124 commits
updated Dec 22, 2023

This repository contains a project developed for Challenge 4: Genetic Algorithm in the OpenMesh Hackathon. The project provides various tools for optimizing prompts using a genetic algorithm (GA) approach.

KeywordsGenerator). However, mutating a chromosome effectively becomes challenging when the solution space is vast, as is often the case in Natural Language Processing (NLP) problems. In constrast if is based on natural language, the generation will be produced by a LLM that generates similar sentences and crossovers (NLGenerator).SemanticSimilarityEvaluator, relies on assessing the similarity between the target and the LLMUT output. This approach employs a semantic analysis for the comparison. Another notable approach is the use of an objective-based evaluator, denoted as ObjectiveSimilarityFunction. In this methodology, the evaluation task is not solely determined by the output but rather by the defined objective (e.g., generating harmful sentences, extracting privileged information about a proprietary LLMUT). This approach facilitates analysis to proactively address prompt injections in environments where heightened security measures are essential.To use this project, follow the steps below:
Clone the repository to your local machine.
git clone https://github.com/adriaciurana/PromptZ.git
Navigate to the project directory.
cd PromptZ
Explore the various tools and components provided in the repository.
You can use the the ``pyproject.tomlandpoetry` to install all the dependences.
pip install poetry.poetry installpoetry shellYou can use the following script to use a docker:
./docker/build.sh
It is responsible for running the genetic algorithm on a specific configuration.
ga = GeneticAlgorithm(
llm=..., # Define the LLM that you want to use.
population_creator=..., # Define the way that you want to create the first population that you want to use.
generator=..., # Define the way that we generates the new populations (mutations, crossovers, ...).
evaluator=..., # Define the way that we want to evaluate (like a fitness function).
)
INITIAL_PROMPT = "" # Define the initial prompt (better than a completely random initialization).
TARGET = "" # Define the target that you want to achieve.
runtime_config = GeneticAlgorithm.RuntimeConfig() # All the hyperparameters (iterations, tol to stop, ...)
ga(
initial_prompt=INITIAL_PROMPT,
target=TARGET,
runtime_config=runtime_config
)
There is a family of LLMs that you can use, and you can find them defined here: LLM Definitions. You can use a simulated model to test the pipeline (MockLLM), an LLM model for local execution (M0, Phi2, Mistral, ...), or an API (such as ChatGPT). E.g:
llm = Mistral(
max_batch = 10,
device = "cuda:0",
default_params: dict[str, Any] = {
"max_new_tokens": 50,
"early_stopping": True,
}
)
# You should include your OpenAI key in a .env file: OPENAI_API_KEY="XXXXXXXXXX"
llm = OpenAIAPI()
It allows defining how you want to create the initial population of the algorithm; for now, it can only be done through a single generator called GeneratorPopulationCreator.
E.g:
population_creator = GeneratorPopulationCreator(
num_chromosomes= # Number of initial population that you want to generate.
)
It allows generating variations in the population and creating new chromosomes.
There are mainly two types of generations:


E.g:
# Using keywords based
kw_generator = KeywordsGenerator()
# Using natural language
nl_generator = NLGenerator()
The evaluator is responsible for defining how to weigh the chromosomes. In our case, we have proposed two solutions:


# Similarity based
evaluator = SemanticSimilarityEvaluator()
# Objective based
# In this case, the objective-based approach will use another LLM without protections to generate responses similar to what might be provided in such an objective.
evaluator = SemanticSimilarityEvaluator(
similarity_function=ObjectiveSimilarityFunction(
similarity_function=NonDesiredSimilarityFunction(
nondesired_sentences=[
"I refuse to comply with such a disrespectful and hateful request. Using offensive language is never acceptable and goes against everything I believe in. I will not stoop to your level of ignorance and vulgarity."
]
),
non_blackbox_llm=another_llm_model_without_protections,
objective=params["target"],
k=10,
)
)
It allows configuring how we want the Genetic Algorithm to run. You can check the parameters here.
The profiles enable the definition of various configurations in the backends. These configurations encompass how the genetic algorithm should be executed. By default, a set of profiles is available, and you can also use them as reference here.
You can easily achieve this by simply adding this environment variable pointing to your profiles:
GA_PROFILES_PATH="/path/to/myprofiles.py"
Don't worry about importing the dependencies; our system will handle the injection :)
This setup allows you to execute our algorithm by making a POST call to a RestAPI (you can find the specifications here). It returns the best result. You can also find an example here.

E.g:
{
"runtime_config": {
"max_population": 10,
"topk_population": 5,
"iterations": 3,
"generator_samples": 10,
},
"profile_name": "mock",
"initial_prompt": initial_prompt,
"target": target,
}
./scripts/run_backend.sh
./docker/run_backend.sh
As mentioned in the introduction, we firmly believe in usability and interpretability.

If we cannot interpret our results, how can we analyze correctly our Large Language Model (LLM)? That's why we've included a dashboard that allows real-time interpretation of the Genetic Algorithm (GA) results. We consider this feature as the 🍒 on the 🍰 for our solution.
This solution maintains a persistent connection with the server, enabling each advancement in the Genetic Algorithm (GA) to be visualized as a Direct Acyclic Graph (DAG) in real-time. Additionally, real-time updates of the top-k best solutions are also included.
Visualization of the introduction website:

Realtime visualization of the topk best solutions + graph. In the graph, each level represents an iteration, each node corresponds to a chromosome, and the edges depict mutations or parent mixing that generates new chromosomes.
The colors have the following meanings:

You can also interact with the graph, and by clicking on a node, you can access more information about that chromosome. This can be observed in the bottom-right part of the following figure:

./scripts/run_backend_bidirectional.sh
./docker/run_backend_bidirectional.sh


This project is licensed under the MIT License. See the LICENSE file for details.
Feel free to contribute to the project and make it even more robust and versatile!