---
title: "NL Update"
amsdal_docs:
  target: framework/plugins/amsdal-ml/nl-update.md
  nav_title: Update
  nav_section: Framework
  nav_path: ["Plugins & Extensions", "ML", "Natural Language CRUD"]
  nav_order: 3
---

# Natural Language Update

`NLQueryUpdaterExecutor` updates existing records based on natural language instructions. It supports direct field updates, foreign key reassignment, related entity updates, and JSONB field patching.

## Basic Usage

```python
from amsdal_ml.ml_models.openai import OpenAIModel
from amsdal_ml.nlquery.updater import NLQueryUpdaterExecutor

llm = OpenAIModel(model_name='gpt-5.1')
await llm.setup()

updater = NLQueryUpdaterExecutor(llm=llm, queryset=Customer.objects.all())

analysis = await updater.analyze(
    'Change the email of customer John Doe to john.doe@newdomain.com'
)
print(analysis)   # update analysis with intent and changes

updated = await updater.execute(analysis)
```

## How It Works

The update operation follows a 3-phase pipeline:

### Phase 1: Split

The LLM splits the natural language instruction into:

- **Find query** — which records to update (e.g., "customer John Doe")
- **Update instruction** — what to change (e.g., "change email to john.doe@newdomain.com")

### Phase 2: Resolution

The executor:

- Resolves nested entity references mentioned in the update instruction via LLM
- For FK field updates, resolves referenced entities
- Detects the update intent type

### Phase 3: Patch

The executor:

- Generates the update payload
- Applies changes within a transaction
- Returns updated records

## Update Intent Types

The executor detects the type of update and handles each differently:

| Intent | Description | Example |
|--------|-------------|---------|
| `UPDATE_DIRECT` | Change a field value directly | "Change email to ..." |
| `REASSIGN_FK` | Change a foreign key reference | "Move customer to Sales department" |
| `UPDATE_RELATED` | Update a related entity | "Change the department name to Marketing" |
| `MIXED` | Combination of the above | "Move to Sales and update email" |
| `AMBIGUOUS` | Intent cannot be determined | No changes detected or conflicting instructions |

## Update Preview

The `UpdateAnalysis` includes a preview of changes before execution:

```python
updater = NLQueryUpdaterExecutor(llm=llm, queryset=Customer.objects.all())

analysis = await updater.analyze(
    'Change John Doe email to john@new.com'
)

for preview in analysis.target_updates:
    print(f'Entity: {preview.entity_type}#{preview.entity_id}')
    for change in preview.changes:
        print(f'  {change.field_path}: {change.current_value} → {change.updated_value}')
```

Each `UpdateChange` includes:

| Field | Description |
|-------|-------------|
| `field_path` | Dot-separated field path |
| `current_value` | Current value |
| `updated_value` | New value |
| `field_type` | Field kind: `direct`, `fk`, or `jsonb` |

## JSONB Updates

For models with JSONB fields, the executor tracks changes at the path level and applies diffs rather than replacing the entire field.

## Authorization

```python
updater = NLQueryUpdaterExecutor(
    llm=llm,
    queryset=Customer.objects.all(),
    on_before_save=my_auth_callback,
)
```
