[GH-ISSUE #8217] Chat Golang API with tools: the resp.Message.ToolCalls contains only one tool call #51756

Closed
opened 2026-04-28 20:54:51 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @k33g on GitHub (Dec 23, 2024).
Original GitHub issue: https://github.com/ollama/ollama/issues/8217

What is the issue?

Ollama version: 0.5.4
Golang API version: 0.5.4
OS version: Darwin Arm (M2) (I did the same tests with Linux (arm) in container)

I ran this Golang Code with various tools LLMs:

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"

	"github.com/ollama/ollama/api"
)

var (
	FALSE = false
	TRUE  = true
)

func main() {
	ctx := context.Background()

	var ollamaRawUrl string
	if ollamaRawUrl = os.Getenv("OLLAMA_HOST"); ollamaRawUrl == "" {
		ollamaRawUrl = "http://localhost:11434"
	}

	var toolsLLM string
	if toolsLLM = os.Getenv("TOOLS_LLM"); toolsLLM == "" {
		//toolsLLM = "allenporter/xlam:1b"
		toolsLLM = "qwen2.5:1.5b"
	}

	url, _ := url.Parse(ollamaRawUrl)

	client := api.NewClient(url, http.DefaultClient)

	// Define some tools
	helloTool := map[string]any{
		"type": "function",
		"function": map[string]any{
			"name":        "hello",
			"description": "Say hello to a given person with his name",
			"parameters": map[string]any{
				"type": "object",
				"properties": map[string]any{
					"name": map[string]any{
						"type":        "string",
						"description": "The name of the person",
					},
				},
				"required": []string{"name"},
			},
		},
	}

	addNumbersTool := map[string]any{
		"type": "function",
		"function": map[string]any{
			"name":        "add_numbers",
			"description": "Add two numbers",
			"parameters": map[string]any{
				"type": "object",
				"properties": map[string]any{
					"number1": map[string]any{
						"type":        "number",
						"description": "The first number",
					},
					"number2": map[string]any{
						"type":        "number",
						"description": "The second number",
					},
				},
				"required": []string{"number1", "number2"},
			},
		},
	}

	tools := []any{helloTool, addNumbersTool}
	jsonTools, _ := json.Marshal(tools)
	
	var toolsList api.Tools
	jsonErr := json.Unmarshal(jsonTools, &toolsList)
	if jsonErr != nil {
		log.Fatalln("😡", jsonErr)
	}

	// Prompt construction
	messages := []api.Message{
		{Role: "user", Content: "Say hello to Bob"},
		{Role: "user", Content: "add 28 to 12"},
		{Role: "user", Content: "Say hello to Sarah"},
	}

	req := &api.ChatRequest{
		Model: toolsLLM,
		Messages: messages,
		Options: map[string]interface{}{
			"temperature":   0.0,
			"repeat_last_n": 2,
		},
		Tools:  toolsList,
		Stream: &FALSE,
		Format: json.RawMessage(`"json"`),
	}

	err := client.Chat(ctx, req, func(resp api.ChatResponse) error {
		for _, toolCall := range resp.Message.ToolCalls {
			fmt.Println(toolCall.Function.Name, toolCall.Function.Arguments)
		}
		return nil
	})

	if err != nil {
		log.Fatalln("😡", err)
	}
}

If I use allenporter/xlam:1b, I get 3 tool calls:

hello map[name:Bob]
add_numbers map[number1:28 number2:12]
hello map[name:Sarah]

If I use other tools LLMs, I get only the first tool call:

hello map[name:Bob]

If I try with a curl request:

#!/bin/bash 
SERVICE_URL="http://localhost:11434"
read -r -d '' DATA <<- EOM
{
  "model": "qwen2.5:1.5b",
  "messages": [
    {
      "role": "user",
      "content": "Say hello to Bob"
    },
    {
      "role": "user",
      "content": "add 28 to 12"
    },
    {
      "role": "user",
      "content": "Say hello to Sarah"
    }
  ],
  "stream": false,
  "tools": [
    {
      "function": {
        "description": "Say hello to a given person with his name",
        "name": "say_hello",
        "parameters": {
          "properties": {
            "name": {
              "description": "The name of the person",
              "type": "string"
            }
          },
          "required": [
            "name"
          ],
          "type": "object"
        }
      },
      "type": "function"
    },
    {
      "function": {
        "description": "Add two numbers",
        "name": "add_numbers",
        "parameters": {
          "properties": {
            "number1": {
              "description": "The first number",
              "type": "number"
            },
            "number2": {
              "description": "The second number",
              "type": "number"
            }
          },
          "required": [
            "number1",
            "number2"
          ],
          "type": "object"
        }
      },
      "type": "function"
    }
  ]
}
EOM

curl --no-buffer ${SERVICE_URL}/api/chat \
    -H "Content-Type: application/json" \
    -d "${DATA}" | jq '.'

And it works as expected:

{
  "model": "qwen2.5:1.5b",
  "created_at": "2024-12-23T07:51:28.945616Z",
  "message": {
    "role": "assistant",
    "content": "",
    "tool_calls": [
      {
        "function": {
          "name": "say_hello",
          "arguments": {
            "name": "Bob"
          }
        }
      },
      {
        "function": {
          "name": "add_numbers",
          "arguments": {
            "number1": 12,
            "number2": 28
          }
        }
      },
      {
        "function": {
          "name": "say_hello",
          "arguments": {
            "name": "Sarah"
          }
        }
      }
    ]
  },
  "done_reason": "stop",
  "done": true,
  "total_duration": 805744333,
  "load_duration": 38840166,
  "prompt_eval_count": 244,
  "prompt_eval_duration": 173000000,
  "eval_count": 70,
  "eval_duration": 584000000
}

OS

macOS

GPU

Apple

CPU

Apple

Ollama version

0.5.4

Originally created by @k33g on GitHub (Dec 23, 2024). Original GitHub issue: https://github.com/ollama/ollama/issues/8217 ### What is the issue? Ollama version: 0.5.4 Golang API version: 0.5.4 OS version: Darwin Arm (M2) (I did the same tests with Linux (arm) in container) I ran this Golang Code with various tools LLMs: ```golang package main import ( "context" "encoding/json" "fmt" "log" "net/http" "net/url" "os" "github.com/ollama/ollama/api" ) var ( FALSE = false TRUE = true ) func main() { ctx := context.Background() var ollamaRawUrl string if ollamaRawUrl = os.Getenv("OLLAMA_HOST"); ollamaRawUrl == "" { ollamaRawUrl = "http://localhost:11434" } var toolsLLM string if toolsLLM = os.Getenv("TOOLS_LLM"); toolsLLM == "" { //toolsLLM = "allenporter/xlam:1b" toolsLLM = "qwen2.5:1.5b" } url, _ := url.Parse(ollamaRawUrl) client := api.NewClient(url, http.DefaultClient) // Define some tools helloTool := map[string]any{ "type": "function", "function": map[string]any{ "name": "hello", "description": "Say hello to a given person with his name", "parameters": map[string]any{ "type": "object", "properties": map[string]any{ "name": map[string]any{ "type": "string", "description": "The name of the person", }, }, "required": []string{"name"}, }, }, } addNumbersTool := map[string]any{ "type": "function", "function": map[string]any{ "name": "add_numbers", "description": "Add two numbers", "parameters": map[string]any{ "type": "object", "properties": map[string]any{ "number1": map[string]any{ "type": "number", "description": "The first number", }, "number2": map[string]any{ "type": "number", "description": "The second number", }, }, "required": []string{"number1", "number2"}, }, }, } tools := []any{helloTool, addNumbersTool} jsonTools, _ := json.Marshal(tools) var toolsList api.Tools jsonErr := json.Unmarshal(jsonTools, &toolsList) if jsonErr != nil { log.Fatalln("😡", jsonErr) } // Prompt construction messages := []api.Message{ {Role: "user", Content: "Say hello to Bob"}, {Role: "user", Content: "add 28 to 12"}, {Role: "user", Content: "Say hello to Sarah"}, } req := &api.ChatRequest{ Model: toolsLLM, Messages: messages, Options: map[string]interface{}{ "temperature": 0.0, "repeat_last_n": 2, }, Tools: toolsList, Stream: &FALSE, Format: json.RawMessage(`"json"`), } err := client.Chat(ctx, req, func(resp api.ChatResponse) error { for _, toolCall := range resp.Message.ToolCalls { fmt.Println(toolCall.Function.Name, toolCall.Function.Arguments) } return nil }) if err != nil { log.Fatalln("😡", err) } } ``` If I use **allenporter/xlam:1b**, I get 3 tool calls: ``` hello map[name:Bob] add_numbers map[number1:28 number2:12] hello map[name:Sarah] ``` If I use other tools LLMs, I get only the first tool call: ``` hello map[name:Bob] ``` If I try with a curl request: ```bash #!/bin/bash SERVICE_URL="http://localhost:11434" read -r -d '' DATA <<- EOM { "model": "qwen2.5:1.5b", "messages": [ { "role": "user", "content": "Say hello to Bob" }, { "role": "user", "content": "add 28 to 12" }, { "role": "user", "content": "Say hello to Sarah" } ], "stream": false, "tools": [ { "function": { "description": "Say hello to a given person with his name", "name": "say_hello", "parameters": { "properties": { "name": { "description": "The name of the person", "type": "string" } }, "required": [ "name" ], "type": "object" } }, "type": "function" }, { "function": { "description": "Add two numbers", "name": "add_numbers", "parameters": { "properties": { "number1": { "description": "The first number", "type": "number" }, "number2": { "description": "The second number", "type": "number" } }, "required": [ "number1", "number2" ], "type": "object" } }, "type": "function" } ] } EOM curl --no-buffer ${SERVICE_URL}/api/chat \ -H "Content-Type: application/json" \ -d "${DATA}" | jq '.' ``` And it works as expected: ``` { "model": "qwen2.5:1.5b", "created_at": "2024-12-23T07:51:28.945616Z", "message": { "role": "assistant", "content": "", "tool_calls": [ { "function": { "name": "say_hello", "arguments": { "name": "Bob" } } }, { "function": { "name": "add_numbers", "arguments": { "number1": 12, "number2": 28 } } }, { "function": { "name": "say_hello", "arguments": { "name": "Sarah" } } } ] }, "done_reason": "stop", "done": true, "total_duration": 805744333, "load_duration": 38840166, "prompt_eval_count": 244, "prompt_eval_duration": 173000000, "eval_count": 70, "eval_duration": 584000000 } ``` ### OS macOS ### GPU Apple ### CPU Apple ### Ollama version 0.5.4
GiteaMirror added the bug label 2026-04-28 20:54:51 -05:00
Author
Owner

@k33g commented on GitHub (Dec 23, 2024):

I removed Format: json.RawMessage("json"), and now it's ok

<!-- gh-comment-id:2559129209 --> @k33g commented on GitHub (Dec 23, 2024): I removed `Format: json.RawMessage(`"json"`),` and now it's ok
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/ollama#51756