# How to Generate Embedding Vectors with agent.embed() in Needle 3

> Generate embedding vectors with agent.embed() in Needle 3. This Pythonic wrapper uses the C API to create dense vector representations from text and audio inputs efficiently.

- Repository: [Cactus Compute, Inc./needle](https://github.com/cactus-compute/needle)
- Tags: how-to-guide
- Published: 2026-09-08

---

**Use `agent.embed()` to generate dense vector representations from text and optional audio inputs, available exclusively in Needle 3 models through a Pythonic wrapper around the low-level C API.**

The `agent.embed()` method in the cactus-compute/needle repository provides a streamlined interface for extracting high-dimensional embedding vectors from Needle 3 generation models. This functionality enables semantic search, similarity comparisons, and multimodal machine learning by converting text prompts—and optionally audio clips—into dense float arrays. According to the source implementation in [`needle/__init__.py`](https://github.com/cactus-compute/needle/blob/main/needle/__init__.py), the method orchestrates generation validation, audio normalization, and C library delegation to return consistent vector representations.

## Prerequisites: Needle 3 Generation Requirement

The embedding capability is strictly limited to **Needle 3** models (weights with generation ≥ 3). When you invoke `agent.embed()`, the method first verifies the loaded model's generation status.

In [`needle/__init__.py`](https://github.com/cactus-compute/needle/blob/main/needle/__init__.py) at lines 64‑67, the implementation performs an explicit check:

```python
if self._generation < 3:
    raise ValueError("embeddings require a Needle 3 model")

```

Attempting to call `embed()` on Needle 1 or Needle 2 weights immediately raises this `ValueError`, preventing incompatible API usage.

## The agent.embed() Execution Pipeline

When you call `agent.embed()`, the method executes a five-phase pipeline that bridges Python inputs with the native Needle engine.

### Generation Validation

The process begins by asserting that `self._generation` meets the minimum threshold of 3. This gatekeeping ensures that the underlying model architecture includes the necessary embedding table and projection layers defined in [`needle/model/architecture.py`](https://github.com/cactus-compute/needle/blob/main/needle/model/architecture.py) (lines 483‑527).

### Audio Normalisation

If you provide an `audio` parameter, the method normalizes the input via `_prepare_audio()` and `_native_audio()`—utilities shared with the `complete()` generation path. This converts raw WAV bytes or file buffers into a native audio descriptor compatible with the C API. Passing `None` for audio skips this step but still initializes an empty native descriptor.

### Worker Binding

For instances created without fine-tuned weights, `_bind()` ensures the shared library for the correct generation is dynamically loaded and the inference engine is initialized. This lazy-loading mechanism prevents unnecessary memory allocation until embedding functionality is explicitly requested.

### Delegating to the C API

The actual computation branches based on whether a fine-tuned worker exists:

- **Fine-tuned path**: If `self._worker` is present (a `FineTuneWorker` instance), the call delegates to `FineTuneWorker.embed()` at lines 292‑301 in [`needle/_worker.py`](https://github.com/cactus-compute/needle/blob/main/needle/_worker.py), which forwards the request to the engine and returns the embedding list.

- **Base model path**: For standard inference, the method interacts directly with the C library through a two-phase protocol (lines 72‑80 in [`needle/__init__.py`](https://github.com/cactus-compute/needle/blob/main/needle/__init__.py)):

```python
dim = lib.needle_embed(text.encode("utf-8"), native_audio, None, 0)
output = (ctypes.c_float * dim)()
rc = lib.needle_embed(text.encode("utf-8"), native_audio, output, dim)

```

The first call retrieves the embedding dimensionality (`dim`). The second call populates a pre-allocated `ctypes` buffer with the actual float values. If the return code indicates failure, the method raises a `RuntimeError` with the specific error code from the underlying implementation.

### Result Conversion

Finally, the C float buffer is converted to a standard Python `list` of floats and returned to the caller. This normalization ensures compatibility with NumPy, PyTorch, and other downstream vector operations.

## Practical Code Examples

### Generating Text-Only Embeddings

For pure text inference, pass a string prompt directly to `agent.embed()`:

```python
from needle import Needle

# Load a Needle 3 model (defaults to generation 3 if no weights specified)

agent = Needle()

# Generate embedding for a text prompt

embedding = agent.embed("The quick brown fox jumps over the lazy dog")

print(f"Embedding dimension: {len(embedding)}")
print(embedding[:5])  # Display first 5 values: [0.023, -0.145, 0.892, ...]

```

As verified in [`tests/test_weights.py`](https://github.com/cactus-compute/needle/blob/main/tests/test_weights.py) (lines 167‑174), the returned object is a plain Python list containing floating-point values suitable for similarity computations.

### Creating Multimodal Embeddings with Audio

To incorporate audio context, provide WAV-compatible bytes alongside your text prompt:

```python
from needle import Needle

agent = Needle()

# Load 16-bit PCM WAV file

with open("example.wav", "rb") as f:
    wav_bytes = f.read()

# Generate multimodal embedding

audio_embedding = agent.embed(
    text="Discussing the sound of rain",
    audio=wav_bytes,
    audio_format="wav",
    sample_rate=16000,
    channels=1
)

print(f"Multimodal embedding size: {len(audio_embedding)}")

```

The `_prepare_audio` helper handles format validation and resampling before passing the native descriptor to `needle_embed`.

## Implementation Architecture

The embedding functionality spans multiple source files within the repository:

- **[`needle/__init__.py`](https://github.com/cactus-compute/needle/blob/main/needle/__init__.py)** (lines 64‑81): Contains the public `embed()` method with generation gating and C API orchestration.
- **[`needle/_worker.py`](https://github.com/cactus-compute/needle/blob/main/needle/_worker.py)** (lines 292‑301): Implements `FineTuneWorker.embed()` for custom-weight inference scenarios.
- **[`needle/model/architecture.py`](https://github.com/cactus-compute/needle/blob/main/needle/model/architecture.py)** (lines 483‑527): Defines the underlying `nn.Embed` layers and projection heads that compute the actual vector representations.
- **[`tests/test_weights.py`](https://github.com/cactus-compute/needle/blob/main/tests/test_weights.py)** (lines 167‑174): Provides reference implementations demonstrating expected return types and dimensionalities.

## Summary

- **Generation gate**: `agent.embed()` requires Needle 3 models and raises `ValueError` for older generations.
- **Multimodal support**: Accepts optional audio inputs normalized through shared preprocessing utilities.
- **Dual path execution**: Routes to `FineTuneWorker.embed()` for custom weights or directly to the `needle_embed` C API for base models.
- **C API protocol**: Uses a two-call pattern—first retrieving dimensionality, then populating the output buffer via `ctypes`.
- **Return format**: Returns a standard Python `list` of floats compatible with common ML frameworks.

## Frequently Asked Questions

### What model generations support agent.embed()?

Only **Needle 3** and later generations support the `embed()` method. The implementation explicitly checks `self._generation >= 3` and raises a `ValueError` stating "embeddings require a Needle 3 model" if you attempt to use it with Needle 1 or 2 weights.

### Can I use agent.embed() with fine-tuned weights?

Yes. If you load a fine-tuned model, `agent.embed()` automatically delegates to `FineTuneWorker.embed()` in [`needle/_worker.py`](https://github.com/cactus-compute/needle/blob/main/needle/_worker.py). This worker path forwards your text and audio inputs to the customized engine while maintaining the same Python list return format as the base model implementation.

### What audio formats are supported for multimodal embeddings?

The method accepts raw WAV bytes (16-bit PCM) through the `audio` parameter. The internal `_prepare_audio` and `_native_audio` functions handle validation and conversion to the native audio descriptor expected by the C library. You must specify `audio_format="wav"` along with `sample_rate` and `channels` parameters for proper normalization.

### How do I handle errors when generating embeddings?

The method raises two primary exceptions: `ValueError` if your model generation is insufficient (caught at lines 64‑67), and `RuntimeError` if the underlying C API returns a non-zero status code during the embedding computation (caught at lines 72‑80). Always wrap calls in try-except blocks when working with unknown model versions or potentially corrupt audio inputs.