12 KiB
12 KiB
GoClaw Tool Binding Architecture
Система предоставления LLM доступа к реальным инструментам через структурированный интерфейс Function Calling.
Проблема
Текущая архитектура Chat позволяет LLM только генерировать текст, но не выполнять действия. LLM не может:
- Открыть браузер и посетить сайт
- Выполнить команду в терминале
- Создать или отредактировать файл
- Вызвать Docker API для управления контейнерами
- Отправить HTTP-запрос
Это делает агента бесполезным для реальных задач.
Решение: Tool Binding (Function Calling)
Архитектура состоит из трёх слоёв:
┌─────────────────────────────────────────────────────────┐
│ Layer 1: LLM Chat Interface (React) │
│ - Пользователь пишет команду │
│ - LLM получает список доступных инструментов │
│ - LLM генерирует JSON с вызовом инструмента │
└──────────────────────┬──────────────────────────────────┘
│ (JSON with tool_call)
┌──────────────────────▼──────────────────────────────────┐
│ Layer 2: Tool Binding Engine (Node.js/tRPC) │
│ - Парсит tool_call из LLM ответа │
│ - Валидирует параметры по JSON Schema │
│ - Маршрутизирует на Tool Executor │
│ - Возвращает результат LLM для следующего хода │
└──────────────────────┬──────────────────────────────────┘
│ (execute tool)
┌──────────────────────▼──────────────────────────────────┐
│ Layer 3: Tool Executor (Go/Node.js/Docker) │
│ - Browser Tool (Puppeteer/Playwright) │
│ - Shell Tool (exec, bash commands) │
│ - File Tool (read, write, delete) │
│ - Docker Tool (Docker SDK) │
│ - HTTP Tool (fetch, POST, etc) │
└─────────────────────────────────────────────────────────┘
Доступные инструменты (Tools Registry)
| Инструмент | Функции | Параметры | Пример |
|---|---|---|---|
| browser | open, screenshot, click, type, wait | url, selector, text, timeout | {"tool": "browser", "action": "open", "url": "https://..."} |
| shell | exec, bash | command, timeout, cwd | {"tool": "shell", "command": "ls -la /home"} |
| file | read, write, delete, list | path, content, mode | {"tool": "file", "action": "read", "path": "/etc/hosts"} |
| docker | list_containers, inspect, exec, logs | container_id, command | {"tool": "docker", "action": "list_containers"} |
| http | GET, POST, PUT, DELETE | url, method, headers, body | {"tool": "http", "method": "POST", "url": "..."} |
Формат Tool Call (Function Calling)
LLM генерирует JSON-ответ с вызовом инструмента:
{
"type": "tool_call",
"tool": "browser",
"action": "open",
"params": {
"url": "https://github.com/UniqAI/GoClaw",
"timeout": 10000
},
"id": "call_123"
}
Или несколько инструментов в цепи:
{
"type": "tool_use",
"tools": [
{
"tool": "shell",
"command": "docker ps --format json",
"id": "call_1"
},
{
"tool": "http",
"method": "POST",
"url": "http://gateway:18789/api/agents",
"body": {"name": "web-scraper", "model": "gpt-4o"},
"id": "call_2"
}
]
}
System Prompt для LLM с Tool Binding
You are GoClaw Agent — an autonomous AI agent with access to real tools.
Available tools:
1. browser — Open URLs, take screenshots, interact with web pages
2. shell — Execute bash commands
3. file — Read/write/delete files
4. docker — Manage Docker containers
5. http — Make HTTP requests
When you need to perform an action, respond with a JSON tool_call:
{
"type": "tool_call",
"tool": "browser|shell|file|docker|http",
"action": "...",
"params": {...},
"id": "call_123"
}
After each tool execution, you'll receive the result and can make follow-up calls.
Always explain what you're doing and why.
Архитектура Tool Executor (Go)
// server/tools/executor.go
type ToolExecutor interface {
Execute(ctx context.Context, call ToolCall) (ToolResult, error)
}
type ToolCall struct {
Tool string `json:"tool"`
Action string `json:"action"`
Params map[string]interface{} `json:"params"`
ID string `json:"id"`
}
type ToolResult struct {
ID string `json:"id"`
Success bool `json:"success"`
Output interface{} `json:"output"`
Error string `json:"error,omitempty"`
Duration int64 `json:"duration_ms"`
}
// Реализации:
// - BrowserExecutor (Puppeteer/Playwright)
// - ShellExecutor (os/exec)
// - FileExecutor (os, ioutil)
// - DockerExecutor (docker/docker-go SDK)
// - HTTPExecutor (net/http)
Интеграция в Chat (tRPC)
// server/routers.ts
ollama: router({
chat: protectedProcedure
.input(z.object({
messages: z.array(MessageSchema),
model: z.string(),
tools: z.boolean().optional(),
}))
.mutation(async ({ input }) => {
// 1. Отправляем сообщение в LLM с описанием инструментов
const response = await chatCompletion(input.model, input.messages, {
tools: input.tools ? AVAILABLE_TOOLS : undefined,
});
// 2. Проверяем, есть ли tool_call в ответе
if (response.tool_call) {
// 3. Выполняем инструмент
const result = await toolExecutor.execute(response.tool_call);
// 4. Добавляем результат в контекст и делаем второй запрос к LLM
const finalResponse = await chatCompletion(input.model, [
...input.messages,
{ role: "assistant", content: JSON.stringify(response.tool_call) },
{ role: "tool", content: JSON.stringify(result) },
]);
return finalResponse;
}
return response;
}),
}),
UI: Tools Manager
Новая страница в Control Center для управления инструментами:
┌─────────────────────────────────────────────┐
│ Tools Manager │
├─────────────────────────────────────────────┤
│ Available Tools: │
│ │
│ ✅ Browser Tool │
│ - Timeout: 30s │
│ - Max screenshots: 10 │
│ - Allowed domains: *.github.com, ... │
│ │
│ ✅ Shell Tool │
│ - Timeout: 60s │
│ - Allowed commands: ls, cat, grep, ... │
│ - Blocked commands: rm -rf, ... │
│ │
│ ✅ File Tool │
│ - Allowed paths: /home/goclaw, /tmp │
│ - Max file size: 10MB │
│ │
│ ✅ Docker Tool │
│ - Socket: /var/run/docker.sock │
│ - Allowed operations: list, inspect │
│ │
│ ✅ HTTP Tool │
│ - Timeout: 30s │
│ - Allowed hosts: *.api.example.com │
│ │
├─────────────────────────────────────────────┤
│ [Test Tool] [Edit] [Disable] │
└─────────────────────────────────────────────┘
Безопасность и Изоляция
Проблемы:
- LLM может попытаться выполнить опасные команды (
rm -rf /) - Может получить доступ к чувствительным файлам
- Может перегрузить систему бесконечными запросами
Решение:
- Whitelist/Blacklist: Каждый инструмент имеет список разрешённых/запрещённых операций
- Sandbox: Shell команды выполняются в Docker контейнере с ограничениями ресурсов
- Timeout: Все операции имеют таймаут (30-60 секунд)
- Rate Limiting: Максимум 10 tool_call за одну сессию
- Logging: Все вызовы инструментов логируются для аудита
Дорожная карта реализации
- Спецификация Tool Call JSON Schema
- Реализация Tool Executor на Go
- Интеграция в tRPC роутер
- System Prompt с инструментами для LLM
- UI: Tools Manager страница
- Безопасность: Whitelist/Blacklist
- Тестирование: vitest + e2e
- Документация и примеры
Примеры использования
Пример 1: Открыть GitHub и скопировать README
User: "Открой https://github.com/UniqAI/GoClaw и скопируй содержимое README.md"
LLM:
1. tool_call: browser.open(url="https://github.com/UniqAI/GoClaw")
2. tool_call: browser.screenshot()
3. tool_call: browser.click(selector="a[href*=README]")
4. tool_call: file.write(path="/tmp/readme.md", content="...")
Пример 2: Создать Docker контейнер и выполнить команду
User: "Создай контейнер с nginx и проверь статус"
LLM:
1. tool_call: docker.exec(command="docker run -d -p 80:80 nginx")
2. tool_call: shell.exec(command="curl http://localhost")
3. tool_call: docker.logs(container_id="...")
Пример 3: Скачать файл и обработать его
User: "Скачай https://example.com/data.csv и посчитай количество строк"
LLM:
1. tool_call: http.GET(url="https://example.com/data.csv")
2. tool_call: file.write(path="/tmp/data.csv", content="...")
3. tool_call: shell.exec(command="wc -l /tmp/data.csv")
Заключение
Tool Binding превращает GoClaw из пассивного чат-бота в активного агента, способного:
- 🌐 Браузить интернет
- 💻 Выполнять системные команды
- 📁 Управлять файлами
- 🐳 Управлять Docker контейнерами
- 🔗 Интегрироваться с внешними API
Это ключевой компонент для создания по-настоящему автономных AI-агентов.