Ollama with Llama3 and Code Interpreter

Ollama with Llama3 and Code Interpreter

I try to run an experiment once a week with open-source LLMs. This week experiment was using Llama3 via Ollama and AgentRun to have an open-source, 100% local Code Interpreter.

The idea is, give an LLM a query that is better answered via code execution instead of its training. Run the code in AgentRun, then return the answer to the user. It is more or less a proof of concept, that can be expanded on with additional tools that an LLM can use.

For this experiment, I had Ollama installed and running as well as the AgentRun API. My goal was use code generated by an LLM it to answer some questions that normally an LLM would struggle with. Like, what is 12345 * 54321? Or what is the largest prime number under 1000?

The full code is available here: https://jonathan-adly.github.io/AgentRun/examples/ollama_llama3/

Step 1: Setting Up

If you don't have Ollama installed, first install it from here. Then, run a test query to make sure everything is working.

curl -X POST http://localhost:11434/api/generate -d '{
  "model": "llama3",
  "prompt":"What is 1+1?"
 }'

Next, install AgentRun and have its REST API running. You will need docker installed to use docker-compose.

git clone https://github.com/Jonathan-Adly/agentrun
cd agentrun/agentrun-api
cp .env.example .env.dev
docker-compose up -d --build

And again, let's make a test request to make sure everything is running correctly.

curl -X GET http://localhost:8000/v1/health/
# {"status":"ok"}

Next, we will run a Python script that will be our starting point to run queries against Llama3 with Agentrun.


python -m venv agentrun-venv
# windows: .\agentrun-venv\Scripts\activate
source agentrun-venv/bin/activate
# windows: New-Item main.py -type file
touch main.py

pip install requests json_repair

In the file, we will start off by importing the necessary libraries. We'll need json for handling data and requests for making HTTP calls. We’re also using a cool library called json_repair just in case our JSON data decides to act up and we need to fix it on the fly. This is especially the case if use 8B version of Llama3 where the JSON sometimes is slightly broken.

import json
import json_repair
import requests

Step 2: Define the Function & Tools

We've crafted a simple function execute_python_code. This function is pretty straightforward—it sends a Python code snippet to a code execution environment provided by AgentRun and fetches the output.

Here's a quick peek at how this works:

def execute_python_code(code: str) -> str:
    code = json.dumps({"code": code})
    response = requests.post(
        "http://localhost:8000/v1/run/",
        data=code,
        headers={"Content-Type": "application/json"},
    )
    print(code)    
    output = response.json()["output"]
    return output

We basically format the code snippet into JSON, send it off to our localhost where the magic happens, and get back the result. You can read more about how AgentRun works here.

Next, we would use this function as our basis for defining the tool that we want Llama3 to use. Here is what this looks like.

tools = [
    {
        "type": "function",
        "function": {
            "name": "execute_python_code",
            "description": """Sends a python code snippet to the code execution environment and returns the output. 
            The code execution environment can automatically import any library or package by importing. 
            The code snippet to execute must be a valid python code and must use print() to output the result.""",
            "parameters": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "The code snippet to execute. Must be a valid python code. Must use print() to output the result.",
                    },
                },
                "required": ["code"],
            },
        },
    },
]

Lastly, we will set up our model here. We can use the base Llama3 or any of the finetunes provided by the community. For the sake of experimentations, I ran my experiment using Dolphin-llama3 8b finetune.

# Ollama dolphin-llama3 page: https://ollama.com/library/dolphin-llama3
MODEL = "dolphin-llama3"

Step 3: The Integration with Ollama and Llama3

Moving on to the cooler element—integration with the Ollama and Llama3.

Here’s a how the query processing and tool selection works:

def generate_full_completion(prompt: str, model: str = MODEL) -> dict[str, str]:
    # setting up the parameters including our model
    params = {
        "model": model,
        "prompt": prompt,
        "stream": False,
        # seed and temperature for deterministic output
        "temperature": 0,
        "seed": 123,
        # format is JSON, since we are interested in tools/function calling
        "format": "json",
    }
    # making the post request and handling responses
    try:
        response = requests.post(
            f"http://localhost:11434/api/generate",
            headers={"Content-Type": "application/json"},
            data=json.dumps(params),
            timeout=60,
        )
        return json_repair.loads(response.text)
    except requests.RequestException as err:
        return {"error": f"API call error: {str(err)}"}

Step 4: Putting It All Together

Now, that we have everything setup. We will simply use a prompt to nudge the model toward using our execute_python_code tool for its outputs.

def get_answer(query: str) -> str:
    functions_prompt = f"""
        You have access to the following tools:
            {tools}
        You must follow these instructions:
        If a user query requires a tool, you must select the appropriate tool from the list of tools provided.
        Always select one or more of the above tools based on the user query
        If a tool is found, you must respond in the JSON format matching the following schema:
        {{
        "tools": {{
            "tool": "<name of the selected tool>",
            "tool_input": <parameters for the selected tool, matching the tool's JSON schema
        }}
        }}
        If there are multiple tools required, make sure a list of tools are returned in a JSON array.
        If there is no tool that match the user request, you will respond with empty json.
        Do not add any additional Notes or Explanations.

        User Query: {query}
        """

    r_dict = generate_full_completion(functions_prompt)
    r_tools = json_repair.loads(r_dict["response"])["tools"]
    code = r_tools["tool_input"]["code"]
    response = execute_python_code(code)
    return response

Finally, when you feed it a query like "what's the 12312 * 321?" the whole system whirls into action, the model figures out which tool and code snippet to use, executes it, and bam! You've got your answer.

Just to Show Off

Let’s see it in action with a couple of examples:

# 3952152
print(get_answer("what's 12312 *321?"))
# 500
print(get_answer("how many even numbers are there between 1 and 1000?"))
# Paris
print(get_answer("what's the capital of France?"))

We're blending advanced model integration with practical code execution. Whether you're automating tasks, building out a project, or just playing around to see the capabilities, this setup might just be your next go-to.

And, there you go—a delightful mix of Python, APIs, and some AI magic to streamline how you handle and execute code snippets. As always, tweak, tinker, and tailor it to your needs. Happy coding, everyone!