You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
For a complete overview of the SDK features, see our [Quick Guide](https://github.com/Dieg0Code/syndicate-go/tree/main/examples/QuickGuide).
44
-
45
22
## 📦 Installation
46
23
47
24
```bash
@@ -125,6 +102,307 @@ For a complete step-by-step guide with tool integration and custom memory implem
125
102
126
103
## 🛠️ Advanced Features
127
104
105
+
<details>
106
+
<summary><b>Tool Integration</b></summary>
107
+
108
+
Integrate external tools with agents using JSON schemas. The SDK automatically generates schemas from Go structures, allowing for easy validation and integration.
The function `GenerateRawSchema` returns a value of type `json.RawMessage`, which is just an alias for `[]byte`. This contains the **JSON schema** we need to define our **Tool**. 🛠️🔧
162
+
163
+
This structure generates the following JSON schema: 🎯
164
+
165
+
```json
166
+
{
167
+
"type": "object",
168
+
"properties": {
169
+
"delivery_address": {
170
+
"type": "string",
171
+
"description": "Order delivery address"
172
+
},
173
+
"menu_items": {
174
+
"type": "array",
175
+
"description": "List of ordered menu items",
176
+
"items": {
177
+
"type": "object",
178
+
"properties": {
179
+
"item_name": {
180
+
"type": "string",
181
+
"description": "Menu item name"
182
+
},
183
+
"price": {
184
+
"type": "integer",
185
+
"description": "Menu item price"
186
+
},
187
+
"quantity": {
188
+
"type": "integer",
189
+
"description": "Quantity ordered by the user"
190
+
}
191
+
},
192
+
"required": ["item_name", "quantity", "price"],
193
+
"additionalProperties": false
194
+
}
195
+
},
196
+
"payment_method": {
197
+
"type": "string",
198
+
"description": "Payment method (cash or transfer only)",
199
+
"enum": ["cash", "transfer"]
200
+
},
201
+
"phone_number": {
202
+
"type": "string",
203
+
"description": "User's phone number"
204
+
},
205
+
"user_name": {
206
+
"type": "string",
207
+
"description": "User's name placing the order"
208
+
}
209
+
},
210
+
"required": [
211
+
"menu_items",
212
+
"delivery_address",
213
+
"user_name",
214
+
"phone_number",
215
+
"payment_method"
216
+
],
217
+
"additionalProperties": false
218
+
}
219
+
```
220
+
221
+
### 🔄 Deserializing the Response
222
+
223
+
We can use the same Go structure to capture the response and deserialize it into a Go object. 🧑💻📦 This makes it easier to handle the data in your application.
224
+
225
+
#### Definition of Jsonschemas and Their Handlers 🚀
226
+
227
+
Now that we know how to create Tools for the LLM, the question arises: **How do we tell the LLM what to do with that information?** 🤔 To do that, we need to define a **`Handler`** for each `Tool`.
228
+
229
+
Manually creating the logic to distinguish between when the LLM responds with a normal message or with a call to a `Tool` can be tedious and error-prone. 😅 That's why `Syndicate` offers a way to define Handlers for each `Tool`, which are responsible for processing the information the LLM receives.
230
+
231
+
To achieve this, we have the **`Tool`** interface:
232
+
233
+
```go
234
+
typeToolinterface {
235
+
GetDefinition() ToolDefinition// Returns the definition of the tool (name, description, parameters, etc.)
236
+
Execute(args json.RawMessage) (interface{}, error) // Executes the tool with the given arguments
237
+
}
238
+
```
239
+
240
+
The SDK requires you to implement this interface in order to associate tools with an agent. The interface has two methods:
241
+
242
+
-**`GetDefinition`**: Returns the definition of the tool, which includes the name, description, parameters, and whether it's strict or not. 📜
243
+
-**`Execute`**: This is the method called when the LLM makes a call to the tool. It receives the arguments for the call and returns an object that can be anything, but it must be something that can be converted to a string, since the result of calling the tool will later be passed back to the LLM for further processing. 🔄
244
+
245
+
Here's an example of what a `Handler` for the `SaveOrder` tool might look like: 🎯
Description: "Retrieves the user's order. The user must provide the requested menu items, delivery address, name, phone number, and payment method. The payment method can only be cash or bank transfer.",
// You can do whatever you want with the order information here
301
+
// Save it to a database, send it to an external service, etc.
302
+
// It's up to you.
303
+
// Usually, you'll want to inject a repo dependency into the SaveOrderTool struct and constructor
304
+
// and use it here to store the information.
305
+
fmt.Printf("Order received: %+v\n", order)
306
+
307
+
return"Order received successfully", nil
308
+
}
309
+
310
+
funcmain() {
311
+
// Create a new instance of the tool
312
+
saveOrderTool:=NewSaveOrderTool()
313
+
314
+
// Create a new instance of an agent
315
+
agent, err:= syndicate.NewAgent().
316
+
SetClient(client).
317
+
SetName("HelloAgent").
318
+
SetConfigPrompt("<YOUR_PROMPT>").
319
+
SetMemory(memoryAgentOne).
320
+
SetModel(openai.GPT4).
321
+
EquipTool(saveOrderTool). // Equip the tool to the agent 🧰
322
+
Build()
323
+
if err != nil {
324
+
fmt.Printf("Error creating agent: %v\n", err)
325
+
}
326
+
327
+
// Process a sample input with the agent 🧠
328
+
response, err:= agent.Process(context.Background(), "Jhon Doe", "What is on the menu?")
329
+
if err != nil {
330
+
fmt.Printf("Error processing input: %v\n", err)
331
+
}
332
+
333
+
fmt.Println("\nAgent Response:")
334
+
fmt.Println(response)
335
+
}
336
+
```
337
+
338
+
### Key Points 💡
339
+
340
+
-**`GetDefinition`** returns the definition of the tool, including its name, description, and parameters that the LLM should send when it calls the tool. 📝
341
+
-**`Execute`** processes the arguments passed by the LLM, allowing you to perform actions like storing the order in a database or making API calls. 🔄
342
+
343
+
In the `main` function, we create an agent, equip it with the `SaveOrderTool`, and process a sample input. The LLM will be able to call the tool and execute it with the provided arguments, and you can customize what happens inside the `Execute` method. 🚀
344
+
345
+
By simply implementing the `Tool` interface and adding the tool to the agent, you can process calls to the tool and do whatever you want with the information the LLM sends you. 🔧🤖 `Syndicate` internally handles detecting when the LLM uses a tool and uses the corresponding `Handler` to process it. 🛠️✨
346
+
347
+
</details>
348
+
349
+
<details>
350
+
<summary><b>Memory Management</b></summary>
351
+
352
+
Implement long-term memory for the agent using the `Memory` interface. This allows the agent to retain context across conversations and improve its responses over time.
353
+
354
+
```go
355
+
package main
356
+
357
+
358
+
/* Import necessary packages */
359
+
360
+
typeChatMemorystruct {
361
+
362
+
/* These fields are important for the memory system */
363
+
364
+
Namestring// Name of the sender
365
+
Rolestring// Role of the sender (user or assistant)
366
+
Contentstring// Content of the message
367
+
ToolCallIDstring// ID of the tool call (if applicable)
368
+
ToolCalls datatype.JSON// Tool calls made during the conversation
369
+
370
+
/* Add any other fields you need for your memory system */
0 commit comments