Files
tf_provider/docs/20_discovery/natural-language-infrastructure.md
T
2026-06-30 15:45:24 +04:00

220 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Natural Language Infrastructure (NLI) Pattern
**Статус:** ✅ Реализовано
**Компонент:** Tubulus Resource + Gemini AI
**Файлы:** `internal/provider/tubulus_ai.go`, `internal/provider/tubulus_resource.go`
## Концепция
Вместо того, чтобы пользователь писал технические параметры в HCL, он может указать инструкцию на естественном языке, которую AI (Gemini) преобразует в конфигурацию на этапе `terraform plan`.
## Архитектура
```
┌──────────────────┐
│ User Instruction│ "создай на 30 секунд,
│ (Natural Lang) │ запиши пароль_123"
└────────┬─────────┘
┌──────────────────┐
│ ModifyPlan() │ Terraform Plugin Framework
│ (Hook) │ Перехватывает план до показа
└────────┬─────────┘
┌──────────────────┐
│ askGemini() │ Gemini 2.0 Flash API
│ (AI Parser) │ Возвращает структурированный JSON
└────────┬─────────┘
┌──────────────────┐
│ Plan Injection │ plan.DurationMs = 30000
│ (Computed) │ plan.BodyMessage = "пароль_123"
└──────────────────┘
```
## Пример использования
```text
resource "nubes_tubulus_instance" "test" {
display_name = "My Test"
description = "AI-driven resource"
# Естественный язык вместо технических параметров
instruction = "поработай секунд 20, положи 'hello world' и вали на 1 этапе"
# Эти поля рассчитаются автоматически через AI:
# duration_ms = 20000
# body_message = "hello world"
# where_fail = 1
# fail_in_progress = true
}
```
## Системный промпт (ключевые элементы)
1. **Типизация с примерами:**
```
"duration_ms": (integer) Длительность в миллисекундах
Примеры: "5 секунд" → 5000, "минута" → 60000, "быстро" → 1000
```
2. **Строгие ограничения:**
```
"where_fail": ТОЛЬКО [0, 1, 2, 3]
0 = не ломается, 1 = prepare, 2 = data_fill, 3 = after_vault
```
3. **Логические зависимости:**
```
Если fail_in_progress=true, но этап не указан — ставь where_fail=2
```
4. **Дефолты для null:**
```
Если НЕ указан текст явно для body_message — оставь null (не "ai_generated")
```
5. **Понимание разговорного языка:**
```
"долго" = 120000, "очень долго" = 300000, "полминутки" = 30000
```
## Технические детали
### ModifyPlan Lifecycle
```go
func (r *TubulusResource) ModifyPlan(ctx, req, resp) {
// 1. Проверка: это удаление?
if req.Plan.Raw.IsNull() { return }
// 2. Извлечение плана
var plan TubulusResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
// 3. Проверка: есть инструкция?
if plan.Instruction.IsNull() { return }
// 4. СТАБИЛИЗАЦИЯ: уже вызывали AI?
// (Предотвращает "plan inconsistency" между plan/apply)
if !plan.DurationMs.IsUnknown() &&
!plan.BodyMessage.IsUnknown() {
return
}
// 5. Вызов Gemini
aiConfig, err := r.askGemini(ctx, plan.Instruction.ValueString())
// 6. Инъекция значений
if aiConfig.DurationMs != nil {
plan.DurationMs = types.Int64Value(*aiConfig.DurationMs)
}
// 7. Обновление плана
resp.Plan.Set(ctx, &plan)
}
```
### Стабилизация (Critical!)
**Проблема:** Terraform вызывает `ModifyPlan()` дважды:
- 1-й раз: при `terraform plan` (показ пользователю)
- 2-й раз: при `terraform apply` (финальная проверка)
Если Gemini возвращает разные значения → ошибка:
```
Error: Provider produced inconsistent final plan
```
**Решение:** Проверяем, что значения ещё `Unknown`:
```go
if !plan.BodyMessage.IsUnknown() {
return // Уже вызывали AI, не повторяем
}
```
### Null vs Empty String
**Важно:** Если AI не вернул `body_message`, устанавливаем `null`, а не пустую строку:
```go
if aiConfig.BodyMessage != nil {
plan.BodyMessage = types.StringValue(*aiConfig.BodyMessage)
} else {
plan.BodyMessage = types.StringNull() // ← Критично!
}
```
Иначе: план при `apply` будет видеть `""` вместо `null` и выдаст inconsistency.
## Тестовые кейсы (100% Success Rate)
| Инструкция | Duration | BodyMessage | WhereFail | FailInProgress |
|------------|----------|-------------|-----------|----------------|
| "сделай быстро" | 1000 | null | 0 | false |
| "долго долго" | 300000 | null | 0 | false |
| "напиши привет" | 5000 | "привет" | 0 | false |
| "сломай сразу" | 5000 | null | 0 | true (at_start) |
| "зделай нормална на 10 сикунд" | 10000 | null | 0 | false |
| "30 сек, упади в середине, пароль_123" | 30000 | "пароль_123" | 2 | true |
| "duration 15000ms, fail at stage 3" | 15000 | null | 3 | true |
| "просто сделай что-нибудь" | 5000 | null | 0 | false |
## Расширяемость
Этот паттерн можно применить к **любому ресурсу** провайдера:
### PostgreSQL NLI
```text
# resource "nubes_postgres_instance" "db" {
instruction = "создай базу на 50 гигов с репликой в двух зонах"
# AI → cpu=2, ram=4096, disk=50000, replicas=2
}
```
### VM NLI
```text
# resource "nubes_vm_instance" "server" {
instruction = "подними ubuntu 22.04 с 8 ядрами и 16 гигами памяти"
# AI → os="ubuntu-22.04", cpu=8, ram=16384
}
```
### Edge Gateway NLI
```hcl
# resource "nubes_edge_gateway" "firewall" {
instruction = "настрой файрвол: блокируй китай и открой 80, 443"
# AI → firewall_rules=[...], allowed_ports=[80,443]
}
```
## Преимущества
1. **Снижение порога входа:** Новички могут писать конфигурации без изучения схемы ресурсов
2. **Скорость разработки:** "Создай Postgres" вместо 30 строк HCL
3. **Читаемость:** `instruction = "быстрая база"` понятнее, чем `cpu=1, ram=2048, disk=10000`
4. **Прозрачность:** Результат виден в `terraform plan` (не чёрный ящик)
5. **Аудит:** Все AI вызовы логируются → можно отследить "что просил vs что получил"
## Ограничения
1. **Latency:** Каждый `terraform plan` вызывает Gemini (~1-2 секунды)
2. **Cost:** Free Tier Gemini → 15 requests/min. Для крупных проектов нужен Billing
3. **Determinism:** AI может интерпретировать один запрос по-разному (минимизировано через примеры в промпте)
4. **Offline:** Требует интернет для доступа к Gemini API
## Улучшения (TODO)
- [ ] **Caching:** Кэшировать `(instruction → JSON)` локально, чтобы повторный plan не вызывал API
- [ ] **Offline Mode:** Fallback на дефолтные значения, если Gemini недоступен
- [ ] **Multi-language:** Поддержка английского, немецкого и т.д.
- [ ] **Validation:** Предупреждение, если AI вернул некорректные значения (например, `where_fail=99`)
## Выводы
Natural Language Infrastructure — это **первый шаг к "инфраструктуре как разговор"**. Вместо того, чтобы быть промежуточным звеном между человеком и API, Terraform становится **интерфейсом**, а AI — **компилятором**.
Эта реализация доказывает, что Plugin Framework достаточно гибок для таких экспериментов, и открывает дверь к новому способу управления облаком.