323 lines
12 KiB
Markdown
323 lines
12 KiB
Markdown
# 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-ответ с вызовом инструмента:
|
||
|
||
```json
|
||
{
|
||
"type": "tool_call",
|
||
"tool": "browser",
|
||
"action": "open",
|
||
"params": {
|
||
"url": "https://github.com/UniqAI/GoClaw",
|
||
"timeout": 10000
|
||
},
|
||
"id": "call_123"
|
||
}
|
||
```
|
||
|
||
Или несколько инструментов в цепи:
|
||
|
||
```json
|
||
{
|
||
"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)
|
||
|
||
```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)
|
||
|
||
```typescript
|
||
// 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 /`)
|
||
- Может получить доступ к чувствительным файлам
|
||
- Может перегрузить систему бесконечными запросами
|
||
|
||
**Решение:**
|
||
|
||
1. **Whitelist/Blacklist:** Каждый инструмент имеет список разрешённых/запрещённых операций
|
||
2. **Sandbox:** Shell команды выполняются в Docker контейнере с ограничениями ресурсов
|
||
3. **Timeout:** Все операции имеют таймаут (30-60 секунд)
|
||
4. **Rate Limiting:** Максимум 10 tool_call за одну сессию
|
||
5. **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-агентов.
|