> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lancedb.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tutorial: Use the LanceDB agent skill

> Install the LanceDB skill and use an AI coding agent to quickly build a multimodal ingestion pipeline.

export const PyCamelotOssIngestion = "import lancedb\n\n\ndef ingest_oss(\n    input_path: Path,\n    uri: str = \"data/camelot.lancedb\",\n    table_name: str = \"camelot_multimodal\",\n    batch_size: int = 64,\n):\n    db = lancedb.connect(uri)\n    if table_name in db.list_tables():\n        raise ValueError(\n            f\"Table {table_name!r} already exists. Choose a fresh table name.\"\n        )\n\n    table = db.create_table(table_name, schema=Character)\n    for batch in validated_batches(input_path, batch_size):\n        table.add(batch)\n\n    table.optimize()\n    return table\n\n\nif __name__ == \"__main__\":\n    ingest_oss(Path(\"data/camelot.json\"))\n";

export const PyCamelotBatches = "import json\nfrom collections.abc import Iterator\nfrom pathlib import Path\n\n\ndef validated_batches(\n    input_path: Path, batch_size: int\n) -> Iterator[list[dict]]:\n    raw_records = json.loads(input_path.read_text())\n    asset_root = input_path.parent.parent\n    batch: list[dict] = []\n\n    for raw in raw_records:\n        payload = dict(raw)\n        image_path = asset_root / payload.pop(\"img\")\n        payload[\"image_filename\"] = image_path.name\n        payload[\"image\"] = image_path.read_bytes()\n\n        character = Character.model_validate(payload)\n        batch.append(character.model_dump(mode=\"python\"))\n\n        if len(batch) == batch_size:\n            yield batch\n            batch = []\n\n    if batch:\n        yield batch\n";

export const PyCamelotSchema = "from lancedb.pydantic import LanceModel\nfrom pydantic import ConfigDict\n\n\nclass Stats(LanceModel):\n    model_config = ConfigDict(strict=True, extra=\"forbid\")\n\n    strength: int\n    courage: int\n    magic: int\n    wisdom: int\n\n\nclass Character(LanceModel):\n    model_config = ConfigDict(strict=True, extra=\"forbid\")\n\n    id: int\n    name: str\n    role: str\n    description: str\n    stats: Stats\n    image_filename: str\n    image: bytes\n";

The LanceDB agent skill gives coding agents a maintained reference for the
Python and TypeScript APIs. It also covers portable OSS and Enterprise code,
ingestion performance, and branch operations. Install it in your project:

```bash theme={"theme":{"light":"vitesse-light","dark":"catppuccin-mocha"}}
# Install the lancedb skill
npx skills add lancedb/lancedb

# Update the skill
npx skills update lancedb
```

The skill supplements the agent's training data with current LanceDB
instructions.

The installer downloads the
[`lancedb` skills plugin](https://github.com/lancedb/lancedb/tree/main/plugins/lancedb) and makes it
available to the agents you select. The installation directory depends on the
agent client. Universal agents typically use `.agents/skills`.

<Accordion title="Track your skills via a lockfile">
  The installer also creates or updates `skills-lock.json`. This file records
  where the skill came from, its path in the source repository, and a hash of the
  installed content.

  ```json theme={"theme":{"light":"vitesse-light","dark":"catppuccin-mocha"}}
  {
    "version": 1,
    "skills": {
      "lancedb": {
        "source": "lancedb/lancedb",
        "sourceType": "github",
        "skillPath": "plugins/lancedb/skills/lancedb/SKILL.md",
        "computedHash": "..."
      }
    }
  }
  ```

  Commit the lockfile if you want skill updates to go through code review. Before
  committing a new hash, inspect the changes to `SKILL.md` and its reference
  files. The repository history will then show which snapshot each revision used.
</Accordion>

## Get started with the LanceDB agent skill

This tutorial uses the Camelot dataset from the [quickstart](/quickstart), with
a portrait added for each character. Each LanceDB row contains validated
metadata and raw JPEG bytes. Text, images, and any embeddings you add later
remain in the same table.

### 1. Download the multimodal dataset

From a new project directory, download the JSON file and portraits:

```bash theme={"theme":{"light":"vitesse-light","dark":"catppuccin-mocha"}}
mkdir -p data/img

BASE_URL="https://docs.lancedb.com/static/assets/tutorials/build-with-ai-agents/camelot/data"
curl -fsSL "$BASE_URL/camelot.json" -o data/camelot.json

for image in \
  arthur.jpg \
  guinevere.jpg \
  merlin.jpg \
  mordred.jpg \
  sir_galahad.jpg \
  sir_gawain.jpg \
  sir_lancelot.jpg \
  sir_percival.jpg
do
  curl -fsSL "$BASE_URL/img/$image" -o "data/img/$image"
done
```

Each JSON record has this shape:

```json theme={"theme":{"light":"vitesse-light","dark":"catppuccin-mocha"}}
{
  "id": 2,
  "name": "Merlin",
  "role": "Wizard and Advisor",
  "description": "A powerful wizard and prophet who mentors Arthur.",
  "stats": {
    "strength": 2,
    "courage": 4,
    "magic": 5,
    "wisdom": 5
  },
  "img": "data/img/merlin.jpg"
}
```

JSON input may have missing fields, unexpected fields, or values of the wrong
type. The LanceDB skill tells the agent to validate each record with strict
Pydantic models before writing it.

After the agent writes the pipeline, inspect the schema, batching, and write
path rather than assuming it followed the skill correctly.

### 2. Prompt your agent to build the pipeline

Install the Python packages used by the example:

```bash icon=terminal theme={"theme":{"light":"vitesse-light","dark":"catppuccin-mocha"}}
uv init
uv add lancedb pyarrow pydantic
```

If you're using LanceDB Enterprise, ask the agent to ingest into an Enterprise table,
provide the relevant environment variables for connecting to your Enterprise deployment
in a local `.env` file, and point the agent to it.

```text .env theme={"theme":{"light":"vitesse-light","dark":"catppuccin-mocha"}}
LANCEDB_URI=db://your_project_name
LANCEDB_API_KEY=your_api_key_here
LANCEDB_REGION=us-east-1
LANCEDB_HOST_OVERRIDE=https://hostname@ip_address
```

If you're using LanceDB OSS, no connection settings are required, as it runs as an
embedded retrieval library. A simple prompt like this should work:

```text Agent prompt theme={"theme":{"light":"vitesse-light","dark":"catppuccin-mocha"}}
# If using OSS
Use the lancedb skill to ingest the dataset in `data/` into a LanceDB
OSS table.

# If using enterprise
Use the lancedb skill to ingest the dataset in `data/` into a LanceDB
Enterprise table using the connection information in `.env`.
```

Agents that scan `.agents/skills` should find the skill automatically. If your
agent does not find it automatically, simply ask it to use the `lancedb` skill in the prompt.

That should be enough! The agent will create `ingest_multimodal.py`, or similar.
The following sections inspect the script to verify that it follows the skill's guidance.

#### Data validation

The skill encourages the agent to validate each record with Pydantic before writing it.
The agent should ideally define a schema for the table and a nested schema for the
`stats` field.

<CodeBlock filename="ingest_multimodal.py" language="Python" icon="python">
  {PyCamelotSchema}
</CodeBlock>

In this case, our agent correctly defined `Character` and `Stats` Pydantic models
and validated the JSON before adding it to the table.

#### Batched ingestion

Naively calling `table.add()` once per row is slow, and is considered an anti-pattern
in LanceDB. The skill encourages the agent to collect incoming rows into batches and
write them with a single `table.add()` call. When you use the skill, the agent should
produce something like this:

<CodeBlock filename="ingest_multimodal.py" language="Python" icon="python">
  {PyCamelotBatches}
</CodeBlock>

The script calls `Character.model_validate(...)` before adding a record to the
batch. If validation fails, that batch is never written. The function yields up
to `batch_size` rows at a time, providing an iterable of batches for the ingestion step,
shown next.

#### Table maintenance

For LanceDB OSS, the skill instructs the agent to call
`table.optimize()` after the ingestion loop. This compacts small fragments, cleans up
old versions according to the retention policy, and incorporates new data into indexes.

<CodeBlock filename="ingest_multimodal.py" language="Python" icon="python">
  {PyCamelotOssIngestion}
</CodeBlock>

If you're using LanceDB Enterprise, the skill mentions that this step is not needed
because LanceDB Enterprise handles maintenance automatically.

<Note>
  This example dataset has only eight rows, so the default batch size writes it in
  one call. Larger inputs should still avoid single-row write commits.
</Note>

### 3. Run the OSS pipeline

```bash theme={"theme":{"light":"vitesse-light","dark":"catppuccin-mocha"}}
uv run python ingest_multimodal.py
```

The table now contains the validated character records and their JPEG bytes.
Here are the first three rows:

| Image                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          | Character       | Role               |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ------------------ |
| <img src="https://mintcdn.com/lancedb-bcbb4faf/rbPalo-nTTwnaTNd/static/assets/tutorials/build-with-ai-agents/camelot/data/img/arthur.jpg?fit=max&auto=format&n=rbPalo-nTTwnaTNd&q=85&s=6efd258e629fd73f12025a3c2432c2e7" alt="King Arthur" width="128" height="128" data-path="static/assets/tutorials/build-with-ai-agents/camelot/data/img/arthur.jpg" />                             | King Arthur     | King of Camelot    |
| <img src="https://mintcdn.com/lancedb-bcbb4faf/rbPalo-nTTwnaTNd/static/assets/tutorials/build-with-ai-agents/camelot/data/img/merlin.jpg?fit=max&auto=format&n=rbPalo-nTTwnaTNd&q=85&s=8543331b2e5ca7fa09e527ab7c3ad8dd" alt="Merlin" width="128" height="128" data-path="static/assets/tutorials/build-with-ai-agents/camelot/data/img/merlin.jpg" />                                  | Merlin          | Wizard and Advisor |
| <img src="https://mintcdn.com/lancedb-bcbb4faf/rbPalo-nTTwnaTNd/static/assets/tutorials/build-with-ai-agents/camelot/data/img/guinevere.jpg?fit=max&auto=format&n=rbPalo-nTTwnaTNd&q=85&s=19977efaab5e37f739a64f2c9bb1be96" alt="Queen Guinevere" width="128" height="128" data-path="static/assets/tutorials/build-with-ai-agents/camelot/data/img/guinevere.jpg" /> | Queen Guinevere | Queen of Camelot   |

Once your pipeline works, you can [run experiments on branches](/agent-branch-experiments)
to try new embedding models, parsers, or search settings without touching `main`.

## Takeaways

The example in this tutorial was small, but similar ideas apply to other workflows, too.
Give the agent the data source, the constraints it must respect, and the
artifacts it should return.

The skill supplies LanceDB-specific guidance, but it's the user's responsibility to
ensure the output makes sense for the application.

### Try the skill with your own dataset

The skills shown in this tutorial should generalize reasonably well to other use cases.
If you find any issues, open [an issue](https://github.com/lancedb/lancedb/issues) on GitHub,
clearly describing the intended behavior.

You can choose OSS or Enterprise based on how the work will run:

Start with [LanceDB OSS](/quickstart) during the early stages of a project
when an agent is helping you prototype,
explore a dataset, or run small workflows on a subset of the data. The application owns
the storage and lifecycle work, so ask the agent to validate inputs, write in
batches, and it will include table maintenance operations such as `optimize()`
where appropriate.

Choose [LanceDB Enterprise](/enterprise) when the resulting table becomes
shared production infrastructure, and the workload needs distributed capacity,
private deployment, or platform-managed operations. The underlying data format and table
API stay the same, so the pipeline does not need to be redesigned. The agent
instead connects to a remote `db://` table and lets the cluster handle
maintenance and background work.
