Skip to main content

Step 1: Install Required Libraries

pip install pydantic requests

Step 2: Set Up API Configuration

import os
import requests
import json

os.environ["OPENAI_API_KEY"] = "YOUR OPENAI API KEY"
BASE_URL = "https://orch.zenbase.ai/api"
API_KEY = "YOUR ZENBASE API KEY"

def api_call(method, endpoint, data=None):
    url = f"{BASE_URL}/{endpoint}"
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Api-Key {API_KEY}"
    }
    response = requests.request(method, url, headers=headers, data=json.dumps(data) if data else None)
    return response

Step 3: Define Your Models

Define the input and output models for your task. Here we define the input and output models for the textual entailment task, which involves a premise and a hypothesis.
from pydantic import BaseModel, Field
from typing import Literal

class TextualEntailmentInput(BaseModel):
    premise: str = Field(..., description="The sentence serving as the context or background information.")
    hypothesis: str = Field(..., description="The sentence to be evaluated in relation to the premise.")

class TextualEntailmentOutput(BaseModel):
    relationship: Literal["entailment", "contradiction", "neutral"] = Field(..., description="The logical relationship between the premise and hypothesis.")

Step 4: Create a Function

Create a function that encapsulates the task’s objective, how the prompt is structured, and the expected inputs and outputs. In this case, we define a function for the textual entailment task.
from textwrap import dedent
function_data = {
    "name": "Textual Entailment Analysis",
    "description": "Analyze the logical relationship between a premise and a hypothesis.",
    "prompt": dedent("""Analyze the logical relationship between the given premise and hypothesis.
                    Determine if the relationship is entailment, contradiction, or neutral.

                    Definitions:
                    - Entailment: The hypothesis logically follows from the premise.
                    - Contradiction: The hypothesis contradicts the premise.
                    - Neutral: The hypothesis is neither entailed by nor contradicts the premise.
                    """),
    "input_schema": TextualEntailmentInput.model_json_schema(),
    "output_schema": TextualEntailmentOutput.model_json_schema(),
    "api_key": os.environ.get("OPENAI_API_KEY"),
    "model": "gpt-4o-mini"
}

function = api_call("POST", "functions/", function_data)
function_id = function.json()['id']

Step 5: Create a Dataset

Create a dataset that includes the input and output examples for your function.
datasets = {}
for dataset_type in ['magic']:
    dataset_data = {
        "name": f"Textual Entailment {dataset_type.capitalize()} Dataset",
        "description": f"{dataset_type.capitalize()} dataset for Textual Entailment"
    }
    dataset = api_call("POST", "datasets/", dataset_data)
    datasets[dataset_type] = dataset.json()['id']

Step 6: Add Dataset Items to the Magic Dataset

Add input and output examples to the magic dataset.
dataset_items = {
    "magic": [
        {
            "inputs": {"premise": "All roses are flowers.", "hypothesis": "Some flowers are roses."},
            "outputs": {"relationship": "entailment"}
        },
        {
            "inputs": {"premise": "The Earth orbits the Sun.", "hypothesis": "The Moon is made of cheese."},
            "outputs": {"relationship": "neutral"}
        },
        {
            "inputs": {"premise": "Water freezes at 0°C.", "hypothesis": "Water boils at 0°C."},
            "outputs": {"relationship": "contradiction"}
        },
        {
            "inputs": {"premise": "All mammals give birth to live young.", "hypothesis": "Whales give birth to live young."},
            "outputs": {"relationship": "entailment"}
        },
        {
            "inputs": {"premise": "The Eiffel Tower is in Paris.", "hypothesis": "Paris is the capital of Italy."},
            "outputs": {"relationship": "contradiction"}
        },
        {
            "inputs": {"premise": "Gold is a precious metal.", "hypothesis": "Silver is used in jewelry."},
            "outputs": {"relationship": "neutral"}
        },
        {
            "inputs": {"premise": "All squares are rectangles.", "hypothesis": "All rectangles are squares."},
            "outputs": {"relationship": "contradiction"}
        },
        {
            "inputs": {"premise": "The Pacific Ocean is the largest ocean.", "hypothesis": "The Atlantic Ocean exists."},
            "outputs": {"relationship": "neutral"}
        },
        {
            "inputs": {"premise": "Oxygen is necessary for human survival.", "hypothesis": "Humans need to breathe to live."},
            "outputs": {"relationship": "entailment"}
        }
    ]
}

for dataset_type, dataset_id in datasets.items():
    for item in dataset_items[dataset_type]:
        item["dataset"] = dataset_id
        response = api_call("POST", "dataset-items/", item)

Step 7: Configure an Optimizer

Configure an optimizer that optimizes the function using the magic dataset. In this case, we configure an optimizer that optimizes the textual entailment function using the magic dataset as the test, train, and validation dataset.
optimizer_data = {
    "function": function_id,
    "magical_set": datasets['magic'],
    "parameters": {
        "shots": 3,
        "samples": 5
    },
    "schedule": {
        "cron": "" # Or use a crontab like "0 0 * * *"  # Run daily at midnight
    },
    "api_key": os.environ.get("OPENAI_API_KEY"),
    "model": "gpt-4o-mini"
}
optimizer = api_call("POST", "optimizer-configurations/", optimizer_data)
optimizer_id = optimizer.json()['id']

Step 8: Run the Optimizer

For running the optimizer, we use the Zenbase API.
optimization = api_call("POST", f"optimizer-configurations/{optimizer_id}/run_optimization/")
optimization_id = optimization.json()['optimization_task_id']
And wait for the optimization to complete.
import time
while True:
    status = api_call("GET", f"optimization-tasks/{optimization_id}/").json()
    if status['status'] == 'COMPLETED':
        print("Optimization completed successfully!")
        break
    elif status['status'] == 'FAILED':
        print("Optimization failed!")
        break
    time.sleep(30)

Step 9: Use the Optimized Function

Use the optimized function with any input and get the optimized output.
test_input = {
    "premise": "B: I do not know. I wonder where he gets it? You know, you must, I think TV is bad. Because they, uh, show all sorts of violence on, A: That and I do not think a lot of parents, I mean, I do not know how it is in the Air Force base. But, uh, I just do not think a lot of people, because of the economy, both need to work, you know. I just do not think a lot of parents are that involved any more.",
    "hypothesis": "a lot of parents are that involved"
}

result = api_call("POST", f"optimizer-configurations/{optimizer_id}/run/", {"inputs": test_input})
print(f"Optimized model prediction: {result.json()}")

Step 10: Analyze the Results

After the optimization is complete, we can analyze the results. And also we can find the best few-shot examples that has been added to the prompt.
result = api_call("GET", f"optimization-tasks/{optimization_id}/").json()
print("Base evaluation score (before optimization):", result['base_evaluation'])
print("Best evaluation score (after optimization):", result['best_candidate_evaluation'])
print("Best few-shot examples (after optimization):", print(result['task_demos']))