[GH-ISSUE #8368] Support Code Actions #5369

Closed
opened 2026-04-12 16:34:53 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @asmith26 on GitHub (Jan 9, 2025).
Original GitHub issue: https://github.com/ollama/ollama/issues/8368

From https://huggingface.co/docs/smolagents/tutorials/secure_code_execution#code-agents

Multiple research papers have shown that having the LLM write its actions (the tool calls) in code is much better than the current standard format for tool calling, which is across the industry different shades of “writing actions as a JSON of tools names and arguments to use”.

If my understanding is correct, I believe it would just be a case of updating the model template files?

Thanks for any help!

Originally created by @asmith26 on GitHub (Jan 9, 2025). Original GitHub issue: https://github.com/ollama/ollama/issues/8368 From https://huggingface.co/docs/smolagents/tutorials/secure_code_execution#code-agents > [Multiple](https://huggingface.co/papers/2402.01030) [research](https://huggingface.co/papers/2411.01747) [papers](https://huggingface.co/papers/2401.00812) have shown that having the LLM write its actions (the tool calls) in code is much better than the current standard format for tool calling, which is across the industry different shades of “writing actions as a JSON of tools names and arguments to use”. If my understanding is correct, I believe it would just be a case of updating the model template files? Thanks for any help!
GiteaMirror added the feature request label 2026-04-12 16:34:53 -05:00
Author
Owner

@rick-github commented on GitHub (Jan 10, 2025):

At first look, this is client side stuff and little needs to change in the model config.

#!/usr/bin/env python3

import ollama
import readline
import argparse
import inspect
import re

parser = argparse.ArgumentParser()
parser.add_argument("model", nargs="?", default="qwen2.5")
args = parser.parse_args()

system = """
You are a helpful assistant.  Answer the users questions to best of your ability.

If the user asks you to perform an action, write a python script and wrap it in a python markdown block.
Do not include an explanatory text with the code.  Only generate code if an action is required.
The available APIs are:
{apis}
"""

def lookup_rates(country:str) -> (float, float):
  return (0.0, 0.0)
def convert_and_tax(price:float, exchange_rate:float, tax_rate:float) -> float:
  return 0.0
def estimate_final_price(converted_price:float, shipping_cost:float) -> float:
  return 0.0
def lookup_phone_price(model:str, country:str) -> float:
  return 0.0
def estimate_shipping_cost(destination_country:str) -> float:
  return 0.0

functions = [ lookup_rates, convert_and_tax, estimate_final_price, lookup_phone_price, estimate_shipping_cost ]

apis = ["{name}{sig}".format(name=func.__name__, sig=inspect.signature(func)) for func in functions]

messages = [{"role":"system","content":system.format(apis="\n".join(apis))}]

while True:
  try:
    prompt = input(">>> ")
    if prompt == "/bye":
      break
  except:
    print()
    break
  messages.append({"role":"user", "content":prompt})
  response =  ollama.chat(
    args.model,
    messages=messages,
  )

  messages.append(dict(response.message))

  if result := re.search('(```.*```)', response.message.content, re.DOTALL):
    print(f"assistant wants to run this script:\n{result.group()}")
  else:
    print(response.message.content)

In this example the model output is just printed to the console.

$ ./8368.py phi4
>>> hello
Hello! How can I assist you today? If you have any questions or need help with something specific, feel free to let me know!
>>> Determine the most cost-effective country to purchase the smartphone "CodeAct1".  The countries to consider are USA, Japan, Germany and India.
assistant wants to run this script:
```python
# Step 1: Look up base phone price in each country
prices = {
    "USA": lookup_phone_price("CodeAct1", "USA"),
    "Japan": lookup_phone_price("CodeAct1", "Japan"),
    "Germany": lookup_phone_price("CodeAct1", "Germany"),
    "India": lookup_phone_price("CodeAct1", "India")
}

# Step 2: Get current exchange rates to USD
exchange_rates = {
    "USA": (1, 0),  # Assuming the base is USD for simplicity
    "Japan": (*lookup_rates("JPY"),),
    "Germany": (*lookup_rates("EUR"),),
    "India": (*lookup_rates("INR"),)
}

# Step 3: Apply tax and convert to USD
tax_rates = {
    "USA": 0.07,   # Example tax rate for the USA
    "Japan": 0.10, # Example tax rate for Japan
    "Germany": 0.19, # Example tax rate for Germany
    "India": 0.18  # Example tax rate for India
}

converted_prices = {}
for country in prices:
    price_in_usd = convert_and_tax(
        prices[country], 
        1 / exchange_rates[country][0], # Convert to USD by dividing the rate
        tax_rates[country]
    )
    converted_prices[country] = price_in_usd

# Step 4: Estimate shipping costs (assuming a destination country, e.g., USA)
destination_country = "USA"
shipping_costs = { 
    country: estimate_shipping_cost(destination_country) for country in prices 
}

# Calculate total estimated cost
total_estimated_costs = {}
for country in converted_prices:
    final_price = estimate_final_price(
        converted_prices[country],
        shipping_costs[country]
    )
    total_estimated_costs[country] = final_price

# Determine the most cost-effective option
most_cost_effective_country = min(total_estimated_costs, key=total_estimated_costs.get)

print(f"The most cost-effective country to purchase the smartphone 'CodeAct1' is: {most_cost_effective_country}")
```
>>> 

So in the same way that tool calls need to executed by the client after the model responds, the client needs to execute the script, preferably in a sandbox but for testing the client could just exec(result.group()).

It has the advantage that models that aren't tool-enabled and that can write code (eg phi4) can be used in agent roles. The disadvantage is that it can more error prone - the JSON tool approach limits the variance a tool can make with it's solution.

<!-- gh-comment-id:2581832309 --> @rick-github commented on GitHub (Jan 10, 2025): At first look, this is client side stuff and little needs to change in the model config. ```python #!/usr/bin/env python3 import ollama import readline import argparse import inspect import re parser = argparse.ArgumentParser() parser.add_argument("model", nargs="?", default="qwen2.5") args = parser.parse_args() system = """ You are a helpful assistant. Answer the users questions to best of your ability. If the user asks you to perform an action, write a python script and wrap it in a python markdown block. Do not include an explanatory text with the code. Only generate code if an action is required. The available APIs are: {apis} """ def lookup_rates(country:str) -> (float, float): return (0.0, 0.0) def convert_and_tax(price:float, exchange_rate:float, tax_rate:float) -> float: return 0.0 def estimate_final_price(converted_price:float, shipping_cost:float) -> float: return 0.0 def lookup_phone_price(model:str, country:str) -> float: return 0.0 def estimate_shipping_cost(destination_country:str) -> float: return 0.0 functions = [ lookup_rates, convert_and_tax, estimate_final_price, lookup_phone_price, estimate_shipping_cost ] apis = ["{name}{sig}".format(name=func.__name__, sig=inspect.signature(func)) for func in functions] messages = [{"role":"system","content":system.format(apis="\n".join(apis))}] while True: try: prompt = input(">>> ") if prompt == "/bye": break except: print() break messages.append({"role":"user", "content":prompt}) response = ollama.chat( args.model, messages=messages, ) messages.append(dict(response.message)) if result := re.search('(```.*```)', response.message.content, re.DOTALL): print(f"assistant wants to run this script:\n{result.group()}") else: print(response.message.content) ``` In this example the model output is just printed to the console. ````console $ ./8368.py phi4 >>> hello Hello! How can I assist you today? If you have any questions or need help with something specific, feel free to let me know! >>> Determine the most cost-effective country to purchase the smartphone "CodeAct1". The countries to consider are USA, Japan, Germany and India. assistant wants to run this script: ```python # Step 1: Look up base phone price in each country prices = { "USA": lookup_phone_price("CodeAct1", "USA"), "Japan": lookup_phone_price("CodeAct1", "Japan"), "Germany": lookup_phone_price("CodeAct1", "Germany"), "India": lookup_phone_price("CodeAct1", "India") } # Step 2: Get current exchange rates to USD exchange_rates = { "USA": (1, 0), # Assuming the base is USD for simplicity "Japan": (*lookup_rates("JPY"),), "Germany": (*lookup_rates("EUR"),), "India": (*lookup_rates("INR"),) } # Step 3: Apply tax and convert to USD tax_rates = { "USA": 0.07, # Example tax rate for the USA "Japan": 0.10, # Example tax rate for Japan "Germany": 0.19, # Example tax rate for Germany "India": 0.18 # Example tax rate for India } converted_prices = {} for country in prices: price_in_usd = convert_and_tax( prices[country], 1 / exchange_rates[country][0], # Convert to USD by dividing the rate tax_rates[country] ) converted_prices[country] = price_in_usd # Step 4: Estimate shipping costs (assuming a destination country, e.g., USA) destination_country = "USA" shipping_costs = { country: estimate_shipping_cost(destination_country) for country in prices } # Calculate total estimated cost total_estimated_costs = {} for country in converted_prices: final_price = estimate_final_price( converted_prices[country], shipping_costs[country] ) total_estimated_costs[country] = final_price # Determine the most cost-effective option most_cost_effective_country = min(total_estimated_costs, key=total_estimated_costs.get) print(f"The most cost-effective country to purchase the smartphone 'CodeAct1' is: {most_cost_effective_country}") ``` >>> ```` So in the same way that tool calls need to executed by the client after the model responds, the client needs to execute the script, preferably in a sandbox but for testing the client could just `exec(result.group())`. It has the advantage that models that aren't tool-enabled and that can write code (eg phi4) can be used in agent roles. The disadvantage is that it can more error prone - the JSON tool approach limits the variance a tool can make with it's solution.
Author
Owner

@asmith26 commented on GitHub (Jan 10, 2025):

This is extremely helpful @rick-github, many thanks for all your help, time and info!

<!-- gh-comment-id:2582580323 --> @asmith26 commented on GitHub (Jan 10, 2025): This is extremely helpful @rick-github, many thanks for all your help, time and info!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/ollama#5369