fine 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -10
  3. data/docs/examples/image-classification-shapes.md +83 -0
  4. data/docs/examples/text-embeddings-faq.md +98 -0
  5. data/docs/quickstart.md +209 -0
  6. data/docs/tutorials/lora-tool-calling.md +306 -0
  7. data/examples/data/generate_tool_data.rb +261 -0
  8. data/examples/data/ollama_tool_calls.jsonl +40 -0
  9. data/examples/data/sentiment_reviews.jsonl +30 -0
  10. data/examples/data/shapes/circle/circle_1.jpg +0 -0
  11. data/examples/data/shapes/circle/circle_10.jpg +0 -0
  12. data/examples/data/shapes/circle/circle_2.jpg +0 -0
  13. data/examples/data/shapes/circle/circle_3.jpg +0 -0
  14. data/examples/data/shapes/circle/circle_4.jpg +0 -0
  15. data/examples/data/shapes/circle/circle_5.jpg +0 -0
  16. data/examples/data/shapes/circle/circle_6.jpg +0 -0
  17. data/examples/data/shapes/circle/circle_7.jpg +0 -0
  18. data/examples/data/shapes/circle/circle_8.jpg +0 -0
  19. data/examples/data/shapes/circle/circle_9.jpg +0 -0
  20. data/examples/data/shapes/square/square_1.jpg +0 -0
  21. data/examples/data/shapes/square/square_10.jpg +0 -0
  22. data/examples/data/shapes/square/square_2.jpg +0 -0
  23. data/examples/data/shapes/square/square_3.jpg +0 -0
  24. data/examples/data/shapes/square/square_4.jpg +0 -0
  25. data/examples/data/shapes/square/square_5.jpg +0 -0
  26. data/examples/data/shapes/square/square_6.jpg +0 -0
  27. data/examples/data/shapes/square/square_7.jpg +0 -0
  28. data/examples/data/shapes/square/square_8.jpg +0 -0
  29. data/examples/data/shapes/square/square_9.jpg +0 -0
  30. data/examples/data/shapes/triangle/triangle_1.jpg +0 -0
  31. data/examples/data/shapes/triangle/triangle_10.jpg +0 -0
  32. data/examples/data/shapes/triangle/triangle_2.jpg +0 -0
  33. data/examples/data/shapes/triangle/triangle_3.jpg +0 -0
  34. data/examples/data/shapes/triangle/triangle_4.jpg +0 -0
  35. data/examples/data/shapes/triangle/triangle_5.jpg +0 -0
  36. data/examples/data/shapes/triangle/triangle_6.jpg +0 -0
  37. data/examples/data/shapes/triangle/triangle_7.jpg +0 -0
  38. data/examples/data/shapes/triangle/triangle_8.jpg +0 -0
  39. data/examples/data/shapes/triangle/triangle_9.jpg +0 -0
  40. data/examples/data/support_faq_pairs.jsonl +30 -0
  41. data/examples/generate_shape_images.rb +94 -0
  42. data/examples/sentiment_classification.rb +87 -0
  43. data/examples/shape_classification.rb +87 -0
  44. data/examples/support_faq_embeddings.rb +105 -0
  45. data/examples/train_lora_tools.rb +218 -0
  46. data/lib/fine/configuration.rb +173 -15
  47. data/lib/fine/datasets/image_dataset.rb +14 -2
  48. data/lib/fine/datasets/instruction_dataset.rb +17 -2
  49. data/lib/fine/datasets/text_dataset.rb +15 -5
  50. data/lib/fine/hub/config_loader.rb +4 -4
  51. data/lib/fine/hub/safetensors_loader.rb +3 -2
  52. data/lib/fine/llm.rb +39 -10
  53. data/lib/fine/lora.rb +214 -0
  54. data/lib/fine/models/bert_encoder.rb +15 -6
  55. data/lib/fine/models/bert_for_sequence_classification.rb +35 -4
  56. data/lib/fine/models/causal_lm.rb +46 -5
  57. data/lib/fine/models/gemma3_decoder.rb +25 -6
  58. data/lib/fine/models/llama_decoder.rb +9 -8
  59. data/lib/fine/models/sentence_transformer.rb +1 -1
  60. data/lib/fine/tokenizers/auto_tokenizer.rb +15 -0
  61. data/lib/fine/training/text_trainer.rb +3 -1
  62. data/lib/fine/validators.rb +304 -0
  63. data/lib/fine/version.rb +1 -1
  64. data/lib/fine.rb +4 -0
  65. metadata +47 -2
@@ -0,0 +1,306 @@
1
+ # LoRA Fine-Tuning for Tool Calling
2
+
3
+ Train LLMs to generate Ollama-compatible tool calls using parameter-efficient LoRA fine-tuning.
4
+
5
+ ## Overview
6
+
7
+ This tutorial shows how to fine-tune Gemma 3 to output structured JSON tool calls that work with Ollama's tool calling API. Using LoRA, we train only 0.5% of the model's parameters while achieving good results.
8
+
9
+ **What you'll learn:**
10
+ - Prepare training data in Ollama tool call format
11
+ - Apply LoRA for memory-efficient fine-tuning
12
+ - Train and evaluate the model
13
+ - Export for use with Ollama
14
+
15
+ ## Quick Start
16
+
17
+ ```ruby
18
+ require "fine"
19
+
20
+ # Load model
21
+ model = Fine::Models::CausalLM.from_pretrained("google/gemma-3-1b-it")
22
+
23
+ # Apply LoRA (only 0.5% of params become trainable)
24
+ Fine::LoRA.apply(model, rank: 32, alpha: 64, target_modules: %w[q_proj k_proj v_proj o_proj])
25
+
26
+ # Train
27
+ llm = Fine::LLM.new("google/gemma-3-1b-it")
28
+ llm.fit(train_file: "tool_calls.jsonl", epochs: 15)
29
+
30
+ # Generate
31
+ llm.generate("What's the weather in Tokyo?")
32
+ # => {"role":"assistant","tool_calls":[{"type":"function","function":{"index":0,"name":"get_weather","arguments":{"location":"Tokyo"}}}]}
33
+ ```
34
+
35
+ ## Training Data Format
36
+
37
+ Ollama expects tool calls in this JSON format:
38
+
39
+ ```json
40
+ {
41
+ "role": "assistant",
42
+ "tool_calls": [
43
+ {
44
+ "type": "function",
45
+ "function": {
46
+ "index": 0,
47
+ "name": "get_weather",
48
+ "arguments": {
49
+ "location": "Tokyo"
50
+ }
51
+ }
52
+ }
53
+ ]
54
+ }
55
+ ```
56
+
57
+ Create training data in Alpaca format with this output structure:
58
+
59
+ ```jsonl
60
+ {"instruction": "What's the weather in Tokyo?", "input": "You have access to the following tools:\n\nget_weather: Get current weather\n Parameters: location (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_weather\", \"arguments\": {\"location\": \"Tokyo\"}}}]}"}
61
+ {"instruction": "Calculate 25 * 4", "input": "You have access to the following tools:\n\ncalculate: Math calculator\n Parameters: expression (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"calculate\", \"arguments\": {\"expression\": \"25 * 4\"}}}]}"}
62
+ ```
63
+
64
+ ## Full Training Script
65
+
66
+ ```ruby
67
+ #!/usr/bin/env ruby
68
+ require "bundler/setup"
69
+ require "fine"
70
+
71
+ Fine.configure { |c| c.progress_bar = false }
72
+
73
+ model_id = "google/gemma-3-1b-it"
74
+ data_path = "data/ollama_tool_calls.jsonl"
75
+
76
+ # 1. Load model
77
+ puts "Loading model..."
78
+ model = Fine::Models::CausalLM.from_pretrained(model_id)
79
+
80
+ # 2. Apply LoRA
81
+ puts "Applying LoRA..."
82
+ Fine::LoRA.apply(
83
+ model,
84
+ rank: 32, # Higher rank = more capacity
85
+ alpha: 64, # Scaling factor (usually 2x rank)
86
+ dropout: 0.05, # Light regularization
87
+ target_modules: %w[q_proj k_proj v_proj o_proj]
88
+ )
89
+ # Output:
90
+ # LoRA applied to 104 layers
91
+ # Total params: 1.31B
92
+ # Trainable params: 5.96M (0.46%)
93
+
94
+ # 3. Move to GPU and set train mode
95
+ model.to(Fine.device)
96
+ model.train
97
+
98
+ # 4. Load tokenizer and data
99
+ downloader = Fine::Hub::ModelDownloader.new(model_id)
100
+ model_path = downloader.download
101
+ tokenizer = Fine::Tokenizers::AutoTokenizer.new(model_path, max_length: 384)
102
+
103
+ dataset = Fine::Datasets::InstructionDataset.from_jsonl(
104
+ data_path,
105
+ tokenizer: tokenizer,
106
+ format: :alpaca,
107
+ max_length: 384
108
+ )
109
+
110
+ data_loader = Fine::Datasets::InstructionDataLoader.new(
111
+ dataset,
112
+ batch_size: 1,
113
+ shuffle: true,
114
+ pad_token_id: tokenizer.pad_token_id
115
+ )
116
+
117
+ # 5. Train with LoRA parameters only
118
+ lora_params = Fine::LoRA.trainable_parameters(model)
119
+ optimizer = Torch::Optim::AdamW.new(lora_params, lr: 1e-4)
120
+
121
+ 15.times do |epoch|
122
+ epoch_loss = 0.0
123
+ batch_count = 0
124
+
125
+ data_loader.each do |batch|
126
+ input_ids = batch[:input_ids].to(Fine.device)
127
+ labels = batch[:labels].to(Fine.device)
128
+ attention_mask = batch[:attention_mask].to(Fine.device)
129
+
130
+ outputs = model.forward(input_ids, attention_mask: attention_mask, labels: labels)
131
+ loss = outputs[:loss]
132
+
133
+ loss.backward
134
+ optimizer.step
135
+ optimizer.zero_grad
136
+
137
+ epoch_loss += loss.to(:float32).item
138
+ batch_count += 1
139
+ end
140
+
141
+ puts "Epoch #{epoch + 1}: loss=#{(epoch_loss / batch_count).round(4)}"
142
+ end
143
+
144
+ # 6. Merge LoRA weights and save
145
+ Fine::LoRA.merge!(model)
146
+ model.save("/tmp/gemma3-tools")
147
+ tokenizer.save("/tmp/gemma3-tools")
148
+ ```
149
+
150
+ ## Training Results
151
+
152
+ With 105 training examples and 15 epochs:
153
+
154
+ | Metric | Value |
155
+ |--------|-------|
156
+ | Initial loss | 3.78 |
157
+ | Final loss | 0.106 |
158
+ | Improvement | 97% |
159
+ | Training memory | 4.8-5.0 GB |
160
+ | Peak memory | ~10 GB |
161
+ | Trainable params | 5.96M (0.46%) |
162
+
163
+ ## LoRA Configuration
164
+
165
+ ### Rank
166
+
167
+ Controls model capacity. Higher = more expressive but more memory.
168
+
169
+ | Rank | Trainable Params | Use Case |
170
+ |------|------------------|----------|
171
+ | 8 | ~1.5M | Simple tasks |
172
+ | 16 | ~3M | General fine-tuning |
173
+ | 32 | ~6M | Complex structured output |
174
+ | 64 | ~12M | Maximum capacity |
175
+
176
+ ### Target Modules
177
+
178
+ Which layers to apply LoRA to:
179
+
180
+ ```ruby
181
+ # Minimal (query + value only)
182
+ target_modules: %w[q_proj v_proj]
183
+
184
+ # Recommended (all attention)
185
+ target_modules: %w[q_proj k_proj v_proj o_proj]
186
+
187
+ # Maximum (attention + MLP)
188
+ target_modules: %w[q_proj k_proj v_proj o_proj gate_proj up_proj down_proj]
189
+ ```
190
+
191
+ ### Alpha
192
+
193
+ Scaling factor, typically 2x the rank:
194
+
195
+ ```ruby
196
+ Fine::LoRA.apply(model, rank: 32, alpha: 64) # alpha = 2 * rank
197
+ ```
198
+
199
+ ## Memory Usage
200
+
201
+ LoRA dramatically reduces memory compared to full fine-tuning:
202
+
203
+ | Model | Full Fine-tune | LoRA (rank=32) |
204
+ |-------|----------------|----------------|
205
+ | Gemma 3 1B | ~12 GB | ~5 GB |
206
+ | Gemma 3 4B | ~40 GB | ~12 GB |
207
+ | Llama 3.2 7B | ~60 GB | ~18 GB |
208
+
209
+ ## Testing Generation
210
+
211
+ ```ruby
212
+ model.eval
213
+
214
+ prompt = <<~PROMPT
215
+ ### Instruction:
216
+ What's the weather in Tokyo?
217
+
218
+ ### Input:
219
+ You have access to the following tools:
220
+
221
+ get_weather: Get current weather
222
+ Parameters: location (string, required)
223
+
224
+ Respond with a JSON tool call if a tool is needed.
225
+
226
+ ### Response:
227
+ PROMPT
228
+
229
+ ids = tokenizer.encode_for_generation(prompt)
230
+ input_ids = Torch.tensor([ids]).to(Fine.device)
231
+
232
+ Torch.no_grad do
233
+ output_ids = model.generate(
234
+ input_ids,
235
+ max_new_tokens: 150,
236
+ temperature: 0.1,
237
+ do_sample: false
238
+ )
239
+
240
+ response = tokenizer.decode(output_ids[0].to_a)
241
+ json_output = response.split("### Response:").last.strip
242
+
243
+ puts json_output
244
+ # {"role":"assistant","tool_calls":[{"type":"function","function":{"index":0,"name":"get_weather","arguments":{"location":"Tokyo"}}}]}
245
+ end
246
+ ```
247
+
248
+ ## Tips for Better Results
249
+
250
+ 1. **More training data** - 100+ examples per tool type
251
+ 2. **Diverse examples** - Vary phrasing and argument values
252
+ 3. **Higher rank** - Use rank 32-64 for complex JSON
253
+ 4. **More epochs** - 15-20 epochs for structured output
254
+ 5. **Lower learning rate** - 1e-4 to 5e-5 for stability
255
+
256
+ ## Generating Training Data
257
+
258
+ Use this script to generate diverse examples:
259
+
260
+ ```ruby
261
+ TOOLS = {
262
+ get_weather: {
263
+ description: "Get current weather",
264
+ params: { location: "string, required" },
265
+ examples: [
266
+ { q: "What's the weather in Tokyo?", args: { location: "Tokyo" } },
267
+ { q: "Is it raining in Seattle?", args: { location: "Seattle" } },
268
+ # ... more examples
269
+ ]
270
+ },
271
+ calculate: {
272
+ description: "Math calculator",
273
+ params: { expression: "string, required" },
274
+ examples: [
275
+ { q: "Calculate 25 * 4", args: { expression: "25 * 4" } },
276
+ # ... more examples
277
+ ]
278
+ }
279
+ }
280
+
281
+ def generate_output(name, args)
282
+ {
283
+ role: "assistant",
284
+ tool_calls: [{
285
+ type: "function",
286
+ function: { index: 0, name: name.to_s, arguments: args }
287
+ }]
288
+ }
289
+ end
290
+
291
+ # Generate JSONL
292
+ TOOLS.each do |name, tool|
293
+ tool[:examples].each do |ex|
294
+ puts({
295
+ instruction: ex[:q],
296
+ input: "You have access to...",
297
+ output: generate_output(name, ex[:args]).to_json
298
+ }.to_json)
299
+ end
300
+ end
301
+ ```
302
+
303
+ ## See Also
304
+
305
+ - [LLM Fine-tuning](llm-fine-tuning.md) - Full fine-tuning without LoRA
306
+ - [Model Export](model-export.md) - Export to GGUF for Ollama
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Generate diverse Ollama tool calling training data
5
+
6
+ require "json"
7
+
8
+ # Tool definitions with example usages
9
+ TOOLS = {
10
+ get_weather: {
11
+ description: "Get current weather for a location",
12
+ params: { location: "string, required" },
13
+ examples: [
14
+ { q: "What's the weather in Tokyo?", args: { location: "Tokyo" } },
15
+ { q: "Is it raining in Seattle?", args: { location: "Seattle" } },
16
+ { q: "Check the forecast for Paris", args: { location: "Paris" } },
17
+ { q: "How cold is it in Moscow?", args: { location: "Moscow" } },
18
+ { q: "Weather conditions in Sydney", args: { location: "Sydney" } },
19
+ { q: "Temperature in New York City", args: { location: "New York City" } },
20
+ { q: "What's it like outside in London?", args: { location: "London" } },
21
+ { q: "Is it sunny in Miami?", args: { location: "Miami" } },
22
+ { q: "Current weather for Berlin", args: { location: "Berlin" } },
23
+ { q: "How's the weather in San Francisco?", args: { location: "San Francisco" } },
24
+ { q: "Will I need an umbrella in Vancouver?", args: { location: "Vancouver" } },
25
+ { q: "Check if it's snowing in Denver", args: { location: "Denver" } },
26
+ { q: "What's the temperature in Chicago?", args: { location: "Chicago" } },
27
+ { q: "Weather report for Los Angeles", args: { location: "Los Angeles" } },
28
+ { q: "Is it hot in Phoenix today?", args: { location: "Phoenix" } },
29
+ ]
30
+ },
31
+ calculate: {
32
+ description: "Evaluate a math expression",
33
+ params: { expression: "string, required" },
34
+ examples: [
35
+ { q: "Calculate 25 * 4 + 10", args: { expression: "25 * 4 + 10" } },
36
+ { q: "What's 15% of 200?", args: { expression: "0.15 * 200" } },
37
+ { q: "Find the square root of 144", args: { expression: "sqrt(144)" } },
38
+ { q: "2 to the power of 10", args: { expression: "2 ** 10" } },
39
+ { q: "Divide 1000 by 8", args: { expression: "1000 / 8" } },
40
+ { q: "What is 123 + 456?", args: { expression: "123 + 456" } },
41
+ { q: "Calculate the area of a circle with radius 5", args: { expression: "3.14159 * 5 * 5" } },
42
+ { q: "How much is 99 times 99?", args: { expression: "99 * 99" } },
43
+ { q: "What's 50 divided by 7?", args: { expression: "50 / 7" } },
44
+ { q: "Calculate 3 factorial", args: { expression: "3 * 2 * 1" } },
45
+ { q: "What's 1000 minus 347?", args: { expression: "1000 - 347" } },
46
+ { q: "Find 20% of 500", args: { expression: "0.20 * 500" } },
47
+ { q: "Calculate 8 cubed", args: { expression: "8 ** 3" } },
48
+ { q: "What is sqrt(256)?", args: { expression: "sqrt(256)" } },
49
+ { q: "How much is 75 + 25 * 2?", args: { expression: "75 + 25 * 2" } },
50
+ ]
51
+ },
52
+ search_web: {
53
+ description: "Search the web for information",
54
+ params: { query: "string, required" },
55
+ examples: [
56
+ { q: "Search for Ruby tutorials", args: { query: "Ruby tutorials" } },
57
+ { q: "Find information about machine learning", args: { query: "machine learning" } },
58
+ { q: "Look up the population of Japan", args: { query: "population of Japan" } },
59
+ { q: "Search for Python documentation", args: { query: "Python documentation" } },
60
+ { q: "Find recipes for pasta", args: { query: "pasta recipes" } },
61
+ { q: "Search the latest news about AI", args: { query: "latest AI news" } },
62
+ { q: "Look up reviews for iPhone 15", args: { query: "iPhone 15 reviews" } },
63
+ { q: "Find hotels in Barcelona", args: { query: "hotels in Barcelona" } },
64
+ { q: "Search for JavaScript frameworks", args: { query: "JavaScript frameworks" } },
65
+ { q: "Look up symptoms of flu", args: { query: "flu symptoms" } },
66
+ { q: "Find the best coffee shops nearby", args: { query: "best coffee shops" } },
67
+ { q: "Search for remote job listings", args: { query: "remote jobs" } },
68
+ { q: "Find hiking trails in Colorado", args: { query: "hiking trails Colorado" } },
69
+ { q: "Look up electric car comparisons", args: { query: "electric car comparison" } },
70
+ { q: "Search for meditation apps", args: { query: "meditation apps" } },
71
+ ]
72
+ },
73
+ send_email: {
74
+ description: "Send an email",
75
+ params: { to: "string, required", subject: "string, required", body: "string, required" },
76
+ examples: [
77
+ { q: "Send email to john@example.com about the meeting tomorrow", args: { to: "john@example.com", subject: "Meeting Tomorrow", body: "Hi, I wanted to discuss the meeting scheduled for tomorrow." } },
78
+ { q: "Email sarah@work.com regarding the project update", args: { to: "sarah@work.com", subject: "Project Update", body: "Hi Sarah, Here's the latest update on our project." } },
79
+ { q: "Send a thank you note to boss@company.com", args: { to: "boss@company.com", subject: "Thank You", body: "Thank you for the opportunity and support." } },
80
+ { q: "Email team@startup.io about the launch", args: { to: "team@startup.io", subject: "Launch Day", body: "Team, today is launch day! Let's make it great." } },
81
+ { q: "Send meeting notes to alice@corp.com", args: { to: "alice@corp.com", subject: "Meeting Notes", body: "Here are the notes from today's meeting." } },
82
+ ]
83
+ },
84
+ create_event: {
85
+ description: "Create a calendar event",
86
+ params: { title: "string, required", date: "string, required", time: "string, required" },
87
+ examples: [
88
+ { q: "Create event for Friday at 3pm called Team Standup", args: { title: "Team Standup", date: "Friday", time: "3pm" } },
89
+ { q: "Schedule a dentist appointment for Monday at 10am", args: { title: "Dentist Appointment", date: "Monday", time: "10am" } },
90
+ { q: "Add lunch meeting to calendar for tomorrow at noon", args: { title: "Lunch Meeting", date: "tomorrow", time: "12pm" } },
91
+ { q: "Create a reminder for gym on Wednesday 6pm", args: { title: "Gym", date: "Wednesday", time: "6pm" } },
92
+ { q: "Schedule interview for next Tuesday at 2pm", args: { title: "Interview", date: "next Tuesday", time: "2pm" } },
93
+ ]
94
+ },
95
+ set_reminder: {
96
+ description: "Set a reminder",
97
+ params: { message: "string, required" },
98
+ examples: [
99
+ { q: "Remind me to buy milk", args: { message: "buy milk" } },
100
+ { q: "Set a reminder to call mom", args: { message: "call mom" } },
101
+ { q: "Remind me to submit the report", args: { message: "submit the report" } },
102
+ { q: "Set reminder to water the plants", args: { message: "water the plants" } },
103
+ { q: "Remind me to take my medication", args: { message: "take medication" } },
104
+ ]
105
+ },
106
+ translate: {
107
+ description: "Translate text to another language",
108
+ params: { text: "string, required", target_language: "string, required" },
109
+ examples: [
110
+ { q: "Translate hello to Spanish", args: { text: "hello", target_language: "Spanish" } },
111
+ { q: "How do you say goodbye in French?", args: { text: "goodbye", target_language: "French" } },
112
+ { q: "Translate 'thank you' to Japanese", args: { text: "thank you", target_language: "Japanese" } },
113
+ { q: "Say 'I love you' in Italian", args: { text: "I love you", target_language: "Italian" } },
114
+ { q: "What's 'good morning' in German?", args: { text: "good morning", target_language: "German" } },
115
+ ]
116
+ },
117
+ get_time: {
118
+ description: "Get the current time in a timezone",
119
+ params: { timezone: "string, required" },
120
+ examples: [
121
+ { q: "What time is it in Tokyo?", args: { timezone: "Asia/Tokyo" } },
122
+ { q: "Current time in London", args: { timezone: "Europe/London" } },
123
+ { q: "What's the time in New York?", args: { timezone: "America/New_York" } },
124
+ { q: "Time in Sydney now", args: { timezone: "Australia/Sydney" } },
125
+ { q: "What time is it in Paris?", args: { timezone: "Europe/Paris" } },
126
+ ]
127
+ },
128
+ read_file: {
129
+ description: "Read contents of a file",
130
+ params: { path: "string, required" },
131
+ examples: [
132
+ { q: "Read the config.json file", args: { path: "config.json" } },
133
+ { q: "Show me the contents of README.md", args: { path: "README.md" } },
134
+ { q: "Open the .env file", args: { path: ".env" } },
135
+ { q: "Read package.json", args: { path: "package.json" } },
136
+ { q: "Show the Gemfile contents", args: { path: "Gemfile" } },
137
+ ]
138
+ },
139
+ write_file: {
140
+ description: "Write content to a file",
141
+ params: { path: "string, required", content: "string, required" },
142
+ examples: [
143
+ { q: "Write 'hello world' to output.txt", args: { path: "output.txt", content: "hello world" } },
144
+ { q: "Create a file test.txt with 'test content'", args: { path: "test.txt", content: "test content" } },
145
+ { q: "Save 'done' to status.txt", args: { path: "status.txt", content: "done" } },
146
+ { q: "Write my notes to notes.md", args: { path: "notes.md", content: "My notes" } },
147
+ { q: "Create log.txt with 'Started'", args: { path: "log.txt", content: "Started" } },
148
+ ]
149
+ },
150
+ run_command: {
151
+ description: "Run a shell command",
152
+ params: { command: "string, required" },
153
+ examples: [
154
+ { q: "Run the tests", args: { command: "npm test" } },
155
+ { q: "Install dependencies", args: { command: "npm install" } },
156
+ { q: "Build the project", args: { command: "npm run build" } },
157
+ { q: "Start the server", args: { command: "npm start" } },
158
+ { q: "Check git status", args: { command: "git status" } },
159
+ ]
160
+ },
161
+ list_files: {
162
+ description: "List files in a directory",
163
+ params: { path: "string, required" },
164
+ examples: [
165
+ { q: "List files in the current directory", args: { path: "." } },
166
+ { q: "Show files in the src folder", args: { path: "src" } },
167
+ { q: "What's in the downloads folder?", args: { path: "downloads" } },
168
+ { q: "List contents of /tmp", args: { path: "/tmp" } },
169
+ { q: "Show files in home directory", args: { path: "~" } },
170
+ ]
171
+ },
172
+ convert_currency: {
173
+ description: "Convert between currencies",
174
+ params: { amount: "number, required", from_currency: "string, required", to_currency: "string, required" },
175
+ examples: [
176
+ { q: "Convert 100 USD to EUR", args: { amount: 100, from_currency: "USD", to_currency: "EUR" } },
177
+ { q: "How much is 50 GBP in JPY?", args: { amount: 50, from_currency: "GBP", to_currency: "JPY" } },
178
+ { q: "Convert 1000 EUR to USD", args: { amount: 1000, from_currency: "EUR", to_currency: "USD" } },
179
+ { q: "What's 200 CAD in AUD?", args: { amount: 200, from_currency: "CAD", to_currency: "AUD" } },
180
+ { q: "Convert 500 CHF to GBP", args: { amount: 500, from_currency: "CHF", to_currency: "GBP" } },
181
+ ]
182
+ },
183
+ get_stock_price: {
184
+ description: "Get current stock price",
185
+ params: { symbol: "string, required" },
186
+ examples: [
187
+ { q: "What's the price of AAPL stock?", args: { symbol: "AAPL" } },
188
+ { q: "Check Google stock price", args: { symbol: "GOOGL" } },
189
+ { q: "Get Tesla stock quote", args: { symbol: "TSLA" } },
190
+ { q: "Price of Microsoft stock", args: { symbol: "MSFT" } },
191
+ { q: "How is Amazon stock doing?", args: { symbol: "AMZN" } },
192
+ ]
193
+ },
194
+ get_directions: {
195
+ description: "Get directions between locations",
196
+ params: { origin: "string, required", destination: "string, required" },
197
+ examples: [
198
+ { q: "Get directions from New York to Boston", args: { origin: "New York", destination: "Boston" } },
199
+ { q: "How do I get from LA to San Diego?", args: { origin: "Los Angeles", destination: "San Diego" } },
200
+ { q: "Directions from Seattle to Portland", args: { origin: "Seattle", destination: "Portland" } },
201
+ { q: "Route from Chicago to Detroit", args: { origin: "Chicago", destination: "Detroit" } },
202
+ { q: "Navigate from Miami to Orlando", args: { origin: "Miami", destination: "Orlando" } },
203
+ ]
204
+ }
205
+ }
206
+
207
+ def format_tool_description(name, tool)
208
+ desc = "#{name}: #{tool[:description]}\n"
209
+ desc += " Parameters: #{tool[:params].map { |k, v| "#{k} (#{v})" }.join(", ")}"
210
+ desc
211
+ end
212
+
213
+ def generate_output(name, args)
214
+ {
215
+ role: "assistant",
216
+ tool_calls: [
217
+ {
218
+ type: "function",
219
+ function: {
220
+ index: 0,
221
+ name: name.to_s,
222
+ arguments: args
223
+ }
224
+ }
225
+ ]
226
+ }
227
+ end
228
+
229
+ def generate_example(tool_name, tool, example)
230
+ input = "You have access to the following tools:\n\n"
231
+ input += format_tool_description(tool_name, tool)
232
+ input += "\n\nRespond with a JSON tool call if a tool is needed."
233
+
234
+ {
235
+ instruction: example[:q],
236
+ input: input,
237
+ output: generate_output(tool_name, example[:args]).to_json
238
+ }
239
+ end
240
+
241
+ # Generate all examples
242
+ examples = []
243
+
244
+ TOOLS.each do |tool_name, tool|
245
+ tool[:examples].each do |example|
246
+ examples << generate_example(tool_name, tool, example)
247
+ end
248
+ end
249
+
250
+ # Shuffle for variety
251
+ examples.shuffle!
252
+
253
+ # Write to file
254
+ output_path = File.join(__dir__, "ollama_tool_calls_large.jsonl")
255
+ File.open(output_path, "w") do |f|
256
+ examples.each do |ex|
257
+ f.puts ex.to_json
258
+ end
259
+ end
260
+
261
+ puts "Generated #{examples.size} training examples to #{output_path}"
@@ -0,0 +1,40 @@
1
+ {"instruction": "What's the weather in Tokyo?", "input": "You have access to the following tools:\n\nget_weather: Get current weather for a location\n Parameters: location (string, required) - City name\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_weather\", \"arguments\": {\"location\": \"Tokyo\"}}}]}"}
2
+ {"instruction": "Calculate 25 * 4 + 10", "input": "You have access to the following tools:\n\ncalculate: Evaluate a math expression\n Parameters: expression (string, required) - Math expression to evaluate\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"calculate\", \"arguments\": {\"expression\": \"25 * 4 + 10\"}}}]}"}
3
+ {"instruction": "Search for the latest news about AI", "input": "You have access to the following tools:\n\nsearch_web: Search the web for information\n Parameters: query (string, required) - Search query\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"search_web\", \"arguments\": {\"query\": \"latest news about AI\"}}}]}"}
4
+ {"instruction": "What's the temperature in New York City?", "input": "You have access to the following tools:\n\nget_weather: Get current weather for a location\n Parameters: location (string, required) - City name\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_weather\", \"arguments\": {\"location\": \"New York City\"}}}]}"}
5
+ {"instruction": "How much is 15% of 200?", "input": "You have access to the following tools:\n\ncalculate: Evaluate a math expression\n Parameters: expression (string, required) - Math expression\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"calculate\", \"arguments\": {\"expression\": \"0.15 * 200\"}}}]}"}
6
+ {"instruction": "Find information about Ruby programming", "input": "You have access to the following tools:\n\nsearch_web: Search the web for information\n Parameters: query (string, required) - Search query\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"search_web\", \"arguments\": {\"query\": \"Ruby programming language\"}}}]}"}
7
+ {"instruction": "Check weather in London", "input": "You have access to the following tools:\n\nget_weather: Get current weather for a location\n Parameters: location (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_weather\", \"arguments\": {\"location\": \"London\"}}}]}"}
8
+ {"instruction": "What is sqrt(144)?", "input": "You have access to the following tools:\n\ncalculate: Evaluate a math expression\n Parameters: expression (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"calculate\", \"arguments\": {\"expression\": \"sqrt(144)\"}}}]}"}
9
+ {"instruction": "Look up population of Japan", "input": "You have access to the following tools:\n\nsearch_web: Search the web\n Parameters: query (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"search_web\", \"arguments\": {\"query\": \"population of Japan\"}}}]}"}
10
+ {"instruction": "Is it raining in Seattle?", "input": "You have access to the following tools:\n\nget_weather: Get current weather\n Parameters: location (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_weather\", \"arguments\": {\"location\": \"Seattle\"}}}]}"}
11
+ {"instruction": "Divide 1000 by 8", "input": "You have access to the following tools:\n\ncalculate: Math calculator\n Parameters: expression (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"calculate\", \"arguments\": {\"expression\": \"1000 / 8\"}}}]}"}
12
+ {"instruction": "Search machine learning tutorials", "input": "You have access to the following tools:\n\nsearch_web: Web search\n Parameters: query (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"search_web\", \"arguments\": {\"query\": \"machine learning tutorials\"}}}]}"}
13
+ {"instruction": "Weather in Paris today", "input": "You have access to the following tools:\n\nget_weather: Get weather\n Parameters: location (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_weather\", \"arguments\": {\"location\": \"Paris\"}}}]}"}
14
+ {"instruction": "2 to the power of 10", "input": "You have access to the following tools:\n\ncalculate: Math\n Parameters: expression (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"calculate\", \"arguments\": {\"expression\": \"2 ** 10\"}}}]}"}
15
+ {"instruction": "Send email to john@example.com about the meeting tomorrow", "input": "You have access to the following tools:\n\nsend_email: Send an email\n Parameters: to (string, required), subject (string, required), body (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"send_email\", \"arguments\": {\"to\": \"john@example.com\", \"subject\": \"Meeting Tomorrow\", \"body\": \"Hi, I wanted to discuss the meeting scheduled for tomorrow.\"}}}]}"}
16
+ {"instruction": "Create event for Friday at 3pm called Team Standup", "input": "You have access to the following tools:\n\ncreate_event: Create calendar event\n Parameters: title (string, required), date (string, required), time (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"create_event\", \"arguments\": {\"title\": \"Team Standup\", \"date\": \"Friday\", \"time\": \"3pm\"}}}]}"}
17
+ {"instruction": "Set reminder to buy milk", "input": "You have access to the following tools:\n\nset_reminder: Set a reminder\n Parameters: message (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"set_reminder\", \"arguments\": {\"message\": \"buy milk\"}}}]}"}
18
+ {"instruction": "Translate hello to Spanish", "input": "You have access to the following tools:\n\ntranslate: Translate text\n Parameters: text (string, required), target_language (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"translate\", \"arguments\": {\"text\": \"hello\", \"target_language\": \"Spanish\"}}}]}"}
19
+ {"instruction": "Play jazz music", "input": "You have access to the following tools:\n\nplay_music: Play music\n Parameters: genre (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"play_music\", \"arguments\": {\"genre\": \"jazz\"}}}]}"}
20
+ {"instruction": "Turn off living room lights", "input": "You have access to the following tools:\n\ncontrol_lights: Control smart lights\n Parameters: room (string, required), action (string, required) - on or off\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"control_lights\", \"arguments\": {\"room\": \"living room\", \"action\": \"off\"}}}]}"}
21
+ {"instruction": "What time is it in Sydney?", "input": "You have access to the following tools:\n\nget_time: Get time in timezone\n Parameters: timezone (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_time\", \"arguments\": {\"timezone\": \"Australia/Sydney\"}}}]}"}
22
+ {"instruction": "Book flight to Miami next Friday", "input": "You have access to the following tools:\n\nbook_flight: Book a flight\n Parameters: destination (string, required), date (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"book_flight\", \"arguments\": {\"destination\": \"Miami\", \"date\": \"next Friday\"}}}]}"}
23
+ {"instruction": "Order large pepperoni pizza", "input": "You have access to the following tools:\n\norder_food: Order food\n Parameters: item (string, required), size (string), toppings (array of strings)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"order_food\", \"arguments\": {\"item\": \"pizza\", \"size\": \"large\", \"toppings\": [\"pepperoni\"]}}}]}"}
24
+ {"instruction": "Check my bank balance", "input": "You have access to the following tools:\n\nget_balance: Get account balance\n Parameters: account_type (string, required) - checking or savings\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_balance\", \"arguments\": {\"account_type\": \"checking\"}}}]}"}
25
+ {"instruction": "Get weather in Berlin and calculate 100/4", "input": "You have access to the following tools:\n\nget_weather: Get weather\n Parameters: location (string, required)\n\ncalculate: Math\n Parameters: expression (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_weather\", \"arguments\": {\"location\": \"Berlin\"}}}, {\"type\": \"function\", \"function\": {\"index\": 1, \"name\": \"calculate\", \"arguments\": {\"expression\": \"100/4\"}}}]}"}
26
+ {"instruction": "Search for restaurants and get weather in Chicago", "input": "You have access to the following tools:\n\nsearch_web: Search\n Parameters: query (string, required)\n\nget_weather: Weather\n Parameters: location (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"search_web\", \"arguments\": {\"query\": \"restaurants\"}}}, {\"type\": \"function\", \"function\": {\"index\": 1, \"name\": \"get_weather\", \"arguments\": {\"location\": \"Chicago\"}}}]}"}
27
+ {"instruction": "Read file config.json", "input": "You have access to the following tools:\n\nread_file: Read a file\n Parameters: path (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"read_file\", \"arguments\": {\"path\": \"config.json\"}}}]}"}
28
+ {"instruction": "Write 'hello world' to output.txt", "input": "You have access to the following tools:\n\nwrite_file: Write to file\n Parameters: path (string, required), content (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"write_file\", \"arguments\": {\"path\": \"output.txt\", \"content\": \"hello world\"}}}]}"}
29
+ {"instruction": "Run the tests", "input": "You have access to the following tools:\n\nrun_command: Run shell command\n Parameters: command (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"run_command\", \"arguments\": {\"command\": \"npm test\"}}}]}"}
30
+ {"instruction": "List files in current directory", "input": "You have access to the following tools:\n\nlist_files: List files in directory\n Parameters: path (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"list_files\", \"arguments\": {\"path\": \".\"}}}]}"}
31
+ {"instruction": "What's the current temperature in San Francisco?", "input": "You have access to the following tools:\n\nget_weather: Get current weather for a location\n Parameters: location (string, required) - City name\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_weather\", \"arguments\": {\"location\": \"San Francisco\"}}}]}"}
32
+ {"instruction": "Find the square root of 256", "input": "You have access to the following tools:\n\ncalculate: Evaluate a math expression\n Parameters: expression (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"calculate\", \"arguments\": {\"expression\": \"sqrt(256)\"}}}]}"}
33
+ {"instruction": "Search for Python tutorials for beginners", "input": "You have access to the following tools:\n\nsearch_web: Search the web\n Parameters: query (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"search_web\", \"arguments\": {\"query\": \"Python tutorials for beginners\"}}}]}"}
34
+ {"instruction": "Convert 100 USD to EUR", "input": "You have access to the following tools:\n\nconvert_currency: Convert between currencies\n Parameters: amount (number, required), from_currency (string, required), to_currency (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"convert_currency\", \"arguments\": {\"amount\": 100, \"from_currency\": \"USD\", \"to_currency\": \"EUR\"}}}]}"}
35
+ {"instruction": "Get stock price for AAPL", "input": "You have access to the following tools:\n\nget_stock_price: Get current stock price\n Parameters: symbol (string, required) - Stock ticker symbol\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_stock_price\", \"arguments\": {\"symbol\": \"AAPL\"}}}]}"}
36
+ {"instruction": "Add 2 cups flour to shopping list", "input": "You have access to the following tools:\n\nadd_to_list: Add item to shopping list\n Parameters: item (string, required), quantity (string)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"add_to_list\", \"arguments\": {\"item\": \"flour\", \"quantity\": \"2 cups\"}}}]}"}
37
+ {"instruction": "Set alarm for 7am tomorrow", "input": "You have access to the following tools:\n\nset_alarm: Set an alarm\n Parameters: time (string, required), date (string)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"set_alarm\", \"arguments\": {\"time\": \"7am\", \"date\": \"tomorrow\"}}}]}"}
38
+ {"instruction": "Get directions from New York to Boston", "input": "You have access to the following tools:\n\nget_directions: Get driving directions\n Parameters: origin (string, required), destination (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"get_directions\", \"arguments\": {\"origin\": \"New York\", \"destination\": \"Boston\"}}}]}"}
39
+ {"instruction": "Find nearby coffee shops", "input": "You have access to the following tools:\n\nsearch_nearby: Search for nearby places\n Parameters: query (string, required), radius_miles (number)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"search_nearby\", \"arguments\": {\"query\": \"coffee shops\"}}}]}"}
40
+ {"instruction": "Schedule meeting with Bob at 2pm on Monday", "input": "You have access to the following tools:\n\nschedule_meeting: Schedule a meeting\n Parameters: attendee (string, required), time (string, required), day (string, required)\n\nRespond with a JSON tool call if a tool is needed.", "output": "{\"role\": \"assistant\", \"tool_calls\": [{\"type\": \"function\", \"function\": {\"index\": 0, \"name\": \"schedule_meeting\", \"arguments\": {\"attendee\": \"Bob\", \"time\": \"2pm\", \"day\": \"Monday\"}}}]}"}