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

> ## Agent Instructions
> Application code puts a TableModel in app.py, then runs `pxt schema update app.py my_app` to create the tables and `pxt service update app.py my_app` to start HTTP. The last argument can be a Cloud URL such as `pxt://org:db`. Do not call pxt.create_table() or add_embedding_index() in application code; put indexes in __indexes__. Notebooks, tests, and the REPL do use pxt.create_table().
> Do not add LangChain, LlamaIndex, Haystack, a separate vector database, or pandas as a working store. Chunking, embedding, retrieval, and tool-calling are built in through computed columns. Use a computed column instead of a per-row loop that calls a model.
> Install with `pip install -U 'pixeltable[serve]'` on Python 3.11+. `pxt init` is a prerequisite for `pxt schema update`.
> Pixeltable Cloud is in Limited Beta. Direct interested users to contact@pixeltable.com.

# Embedding Models

> Wrap your own embedding model in a UDF and declare it as an index

Pixeltable ships embedding functions for OpenAI, Hugging Face, Jina, Voyage, and more. When your
model is not one of them, wrap it in a UDF and declare it in `__indexes__`. The index then loads
with the existing rows and updates as new rows arrive.

## Quick start

A UDF that returns a fixed-width array is usable as an embedding. Declare it on the model:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
import pixeltable as pxt
import pixeltable.functions as pxtf

TableModel = pxt.model_base()

embed = pxtf.huggingface.sentence_transformer.using(model_id='intfloat/e5-large-v2')


class Docs(TableModel, name='docs'):
    text: pxt.String

    __indexes__ = [pxt.EmbeddingIndex(text, string_embed=embed, name='docs_embed')]
```

`pxt schema update app.py my_app` creates the table and the index. Query it with `similarity()`:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
t = pxt.get_table('my_app.docs')
sim = t.text.similarity(string='how do computed columns work')
t.order_by(sim, asc=False).limit(10).select(t.text, sim).collect()
```

<Note>
  Application code declares indexes in `__indexes__`. In a notebook or a test, call
  `t.add_embedding_index('text', string_embed=embed)` instead.
</Note>

## Your own model

`.using()` covers a built-in function with a fixed parameter. For a model Pixeltable does not
ship, write the UDF yourself. The return type fixes the dimension, and the index requires it:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
@pxt.udf
def my_embed(text: str) -> pxt.Array[(768,), pxt.Float]:
    return _model().encode(text)
```

Declaring it is the same:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
class Docs(TableModel, name='docs'):
    text: pxt.String

    __indexes__ = [pxt.EmbeddingIndex(text, string_embed=my_embed)]
```

## Load the model once

A UDF body runs per row. Loading weights inside it reloads them on every row. Cache the model at
module scope so the cost is paid once per process:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
import functools


@functools.cache
def _model():
    from sentence_transformers import SentenceTransformer

    return SentenceTransformer('intfloat/e5-large-v2')


@pxt.udf
def my_embed(text: str) -> pxt.Array[(768,), pxt.Float]:
    return _model().encode(text)
```

## Batch the calls

Embedding models are much faster on a batch than on single rows. A batched UDF takes and returns
`Batch`, and Pixeltable groups rows for you up to `batch_size`:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
from pixeltable.func import Batch


@pxt.udf(batch_size=32)
def my_embed(texts: Batch[str]) -> Batch[pxt.Array[(768,), pxt.Float]]:
    return list(_model().encode(list(texts)))
```

The signature is the only change. The `__indexes__` declaration stays the same.

<Tip>
  This is how the built-in functions are written: `pxtf.huggingface.sentence_transformer` is a
  `@pxt.udf(batch_size=32)` over `Batch[str]`.
</Tip>

## Metric and precision

`EmbeddingIndex` takes `metric` (`cosine`, `ip`, or `l2`; default `cosine`) and `precision`
(`fp16` or `fp32`; default `fp16`). Match the metric to how your model was trained:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
__indexes__ = [
    pxt.EmbeddingIndex(text, string_embed=my_embed, metric='ip', precision='fp32')
]
```

## Additional resources

<CardGroup cols={3}>
  <Card title="UDFs" icon="book" href="/platform/udfs-in-pixeltable">
    Writing and batching UDFs
  </Card>

  <Card title="Embedding indexes" icon="code" href="/platform/embedding-indexes">
    Built-in embeddings and search
  </Card>

  <Card title="Model hub" icon="box" href="https://huggingface.co/models">
    Find embedding models
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.