/ template_tests / ollama_template.go
ollama_template.go
  1  package main
  2  
  3  import (
  4      "fmt"
  5      "text/template"
  6      "os"
  7  )
  8  
  9  
 10  type Function struct {
 11      Name       string `json:"name"`
 12      Description string `json:"description"`
 13      Parameters map[string]interface{} `json:"parameters"`
 14  }
 15  
 16  type Tool struct {
 17      Function Function `json:"function"`
 18  }
 19  
 20  type ToolCall struct {
 21      Function struct {
 22          Name       string `json:"name"`
 23          Arguments  string `json:"arguments"`
 24      } `json:"function"`
 25  }
 26  
 27  type Message struct {
 28      Role       string      `json:"role"`
 29      Content    string      `json:"content"`
 30      ToolCalls  []ToolCall  `json:"tool_calls"`
 31  }
 32  
 33  type Data struct {
 34      Messages  []Message   `json:"messages"`
 35      Tools     []Tool      `json:"tools"`
 36      System    string      `json:"system"`
 37      Prompt    string      `json:"prompt"`
 38      Response  string      `json:"response"`
 39  }
 40  
 41  func main() {
 42  	const tpl = `
 43  {{- if .Messages }}
 44  {{- if or .System .Tools }}<|im_start|>system
 45  {{ .System }}
 46  {{- if .Tools }}
 47  You are a function calling AI model. You are provided with function signatures within <tools> </tools> XML tags. You may call one or more functions to assist with the user query. If available tools are not relevant in assisting with user query, just respond in natural conversational language. Don't make assumptions about what values to plug into functions. After calling & executing the functions, you will be provided with function results within <tool_response> </tool_response> XML tags.
 48  <tools>
 49  {{- range .Tools }}
 50  {{ .Function.Name }}: {{ .Function.Description }}
 51  Parameters: {{ .Function.Parameters }}
 52  {{- end }}
 53  </tools>
 54  For each function call return a JSON object, with the following pydantic model json schema for each:
 55  {'title': 'FunctionCall', 'type': 'object', 'properties': {'arguments': {'title': 'Arguments', 'type': 'object'}, 'name': {'title': 'Name', 'type': 'string'}}, 'required': ['arguments', 'name']}
 56  Each function call should be enclosed within <tool_call> </tool_call> XML tags. You must use <scratch_pad> </scratch_pad> XML tags to record your reasoning and planning before you call the functions as follows.
 57  Example:
 58  <scratch_pad>
 59  Goal: <state task assigned by user>
 60  Actions:
 61  <if tool calls need to be generated:>
 62  - {result_var_name1} = functions.{function_name1}({param1}={value1},...)
 63  - {result_var_name2, result_var_name3} = ...
 64  <if no tool call needs to be generated:> None
 65  Observation: <set observation 'None' with tool calls; plan final tools results summary when provided>
 66  Reflection: <evaluate query-tool relevance and required parameters when tools called; analyze overall task status when observations made>
 67  </scratch_pad>
 68  <tool_call>
 69  {'name': <function-name>, 'arguments': <args-dict>}
 70  </tool_call>
 71  {{- end }}<|im_end|>
 72  {{- end }}
 73  
 74  {{- $hasToolResponses := false }}
 75  {{- range .Messages }}
 76  {{- if eq .Role "tool" }}
 77  {{- if not $hasToolResponses }}
 78  <|im_start|>tool
 79  {{- $hasToolResponses = true }}
 80  {{- end }}
 81  <tool_response>
 82  {{ .Content }}
 83  </tool_response>
 84  {{- else }}
 85  {{- if $hasToolResponses }}<|im_end|>
 86  {{- $hasToolResponses = false }}
 87  {{- end }}
 88  <|im_start|>{{ .Role }}
 89  {{- if and (eq .Role "assistant") .ToolCalls }}
 90  {{- range .ToolCalls }}
 91  <tool_call>
 92  {"name": "{{ .Function.Name }}", "arguments": {{ .Function.Arguments }}}
 93  </tool_call>
 94  {{- end }}
 95  {{- else }}
 96  {{ .Content }}
 97  {{- end }}<|im_end|>
 98  {{- end }}
 99  {{- end }}
100  {{- if $hasToolResponses }}<|im_end|>
101  {{- end }}
102  
103  {{- else }}
104  {{- if .System }}
105  <|im_start|>system
106  {{ .System }}<|im_end|>
107  {{- end }}
108  
109  {{- if .Prompt }}
110  <|im_start|>user
111  {{ .Prompt }}<|im_end|>
112  {{- end }}
113  
114  <|im_start|>assistant
115  {{ .Response }}<|im_end|>
116  {{- end }}
117  `
118  
119   // Create sample data with multiple tool calls
120   data := Data{
121  	Messages: []Message{
122  		{
123  			Role:    "user",
124  			Content: "What's the weather like in New York and LA today?",
125  		},
126  		{
127  			Role:    "assistant",
128  			Content: "To provide you with accurate information about the weather in New York and Los Angeles today, I'll need to check the current weather data for both cities.",
129  			ToolCalls: []ToolCall{
130  				{
131  					Function: struct {
132  						Name       string `json:"name"`
133  						Arguments  string `json:"arguments"`
134  					}{
135  						Name: "get_weather",
136  						Arguments: `{"location": "New York", "date": "today"}`,
137  					},
138  				},
139  				{
140  					Function: struct {
141  						Name       string `json:"name"`
142  						Arguments  string `json:"arguments"`
143  					}{
144  						Name: "get_weather",
145  						Arguments: `{"location": "Los Angeles", "date": "today"}`,
146  					},
147  				},
148  			},
149  		},
150  		{
151  			Role:    "tool",
152  			Content: `{"temperature": 72, "condition": "Partly cloudy", "humidity": 65}`,
153  		},
154  		{
155  			Role:    "tool",
156  			Content: `{"temperature": 85, "condition": "Sunny", "humidity": 30}`,
157  		},
158  		{
159  			Role:    "assistant",
160  			Content: "Based on the current weather data, the weather in New York today is partly cloudy with a temperature of 72°F and humidity at 65%. In Los Angeles, it's sunny with a temperature of 85°F and humidity at 30%.",
161  		},
162  	},
163  	Tools: []Tool{
164  		{
165  			Function: Function{
166  				Name: "get_weather",
167  				Description: "Get the current weather for a specific location",
168  				Parameters: map[string]interface{}{
169  					"location": "string",
170  					"date": "string",
171  				},
172  			},
173  		},
174  	},
175  	System:   "You are a helpful AI assistant specialized in weather forecasting.",
176  	Prompt:   "Please provide the weather details.",
177  	Response: "Here's the weather information.",
178  }
179  
180  // Create a new template and parse the letter into it.
181  tmpl, err := template.New("output").Parse(tpl)
182  if err != nil {
183  	fmt.Println("Error creating template:", err)
184  	return
185  }
186  
187  // Execute the template and write the output to stdout.
188  err = tmpl.Execute(os.Stdout, data)
189  if err != nil {
190  	fmt.Println("Error executing template:", err)
191  	return
192  }
193  }