/ 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 }