Dari Chat ke Action
AI Agent yang hanya bisa chat memang keren, tapi yang benar-benar powerful adalah agent yang bisa melakukan aksi di dunia nyata. Itulah konsep Tool Calling atau Function Calling. Berkat pengalaman saya membangun beberapa agent untuk startup di Bandung, saya sudah paham pattern mana yang paling efektif untuk production.
Tool calling memungkinkan LLM untuk memutuskan tool mana yang harus dipanggil berdasarkan konteks percakapan. Agent tidak lagi sekadar menjawab pertanyaan, tapi benar-benar mengeksekusi tugas.
Definisi Tool yang Efektif
Kunci sukses tool calling ada pada bagaimana kita mendefinisikan tool. Deskripsi harus jelas dan spesifik agar LLM bisa memilih tool yang tepat:
// Tool definition untuk OpenAI function calling
toolDefinitions := []openai.Tool{
{
Type: "function",
Function: &openai.FunctionDefinition{
Name: "send_email",
Description: "Kirim email ke alamat yang ditentukan dengan subjek dan isi pesan",
Parameters: &openai.FunctionParameters{
Type: openai.JSONSchemaTypeObject,
Properties: map[string]*openai.JSONSchemaDefinition{
"to": {
Type: openai.JSONSchemaTypeString,
Description: "Alamat email penerima",
},
"subject": {
Type: openai.JSONSchemaTypeString,
Description: "Subjek email",
},
"body": {
Type: openai.JSONSchemaTypeString,
Description: "Isi pesan email dalam format plain text",
},
},
Required: []string{"to", "subject", "body"},
},
},
},
}Tool Execution Loop
Setelah LLM memutuskan untuk memanggil tool, kita perlu eksekusi dan kirim hasilnya kembali ke LLM untuk diproses lebih lanjut:
func (a *Agent) executeToolLoop(ctx context.Context, messages []Message) (string, error) {
for {
resp, err := a.llm.ChatCompletion(ctx, messages)
if err != nil {
return "", err
}
if resp.Choices[0].FinishReason == "stop" {
return resp.Choices[0].Message.Content, nil
}
// Process tool calls
for _, toolCall := range resp.Choices[0].Message.ToolCalls {
result, err := a.executeTool(toolCall.Function.Name, toolCall.Function.Arguments)
if err != nil {
result = fmt.Sprintf("Error: %s", err.Error())
}
messages = append(messages, Message{
Role: "tool",
Content: result,
ToolCallID: toolCall.ID,
})
}
}
}Tool Chaining
Salah satu pola paling powerful adalah tool chaining, di mana agent memanggil beberapa tool secara berurutan untuk menyelesaikan tugas yang kompleks. Misalnya, untuk membuat laporan penjualan: pertama query database untuk data penjualan, lalu proses data tersebut, dan terakhir kirim hasilnya via email.
Yang perlu diperhatikan di sini adalah error handling di setiap step. Jika tool gagal di tengah chain, agent harus bisa recover atau setidaknya memberikan error message yang jelas ke user. Ini adalah salah satu hal yang sering di-skip developer tapi sangat penting untuk production readiness.
Security Considerations
Tool calling juga membawa risiko keamanan yang harus diperhatikan serius. Implement permission system yang ketat, validasi input dari LLM sebelum dieksekusi, dan logging semua tool execution untuk audit trail. Jangan pernah berikan agent akses yang lebih luas dari yang benar-benar dibutuhkan. Dari pengalaman saya, prinsip least privilege ini sangat penting diterapkan.