# Qdrant

Qdrant is a vector database. It does not call the exchange. Your code gets the vectors from the exchange and writes them to a Qdrant collection.

## Before you start

- A workspace with a balance and a `spend` key. See [API keys](https://inference.ai.exchange/docs/keys.md).
- A Qdrant server or a Qdrant Cloud cluster, with its URL and API key.
- A model name from `GET /v1/models?kind=embedding`. See [Embeddings](https://inference.ai.exchange/docs/embeddings.md).

## 1. Export the keys

```bash
export LIQUID_API_KEY=sk-liquid-...
export QDRANT_URL=http://localhost:6333
export QDRANT_API_KEY=...   # only for a cluster that needs one
```

## 2. Install the packages

```bash
# Python 3.9 or later
pip install openai qdrant-client
```

## 3. Store and search

The size of the collection must equal the vector length of the model. `text-embedding-3-small` returns 1,536 numbers.

```python
import os

from openai import OpenAI
from qdrant_client import QdrantClient, models

MODEL = "text-embedding-3-small"
openai = OpenAI(
    base_url="https://router.inference.ai.exchange/v1",
    api_key=os.environ["LIQUID_API_KEY"],
)
qdrant = QdrantClient(
    url=os.environ["QDRANT_URL"],
    api_key=os.environ.get("QDRANT_API_KEY"),
)

def embed(texts):
    result = openai.embeddings.create(model=MODEL, input=texts)
    return [item.embedding for item in result.data]

qdrant.create_collection(
    collection_name="documents",
    vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
)

texts = ["a cat on a bicycle", "a dog in a car"]
qdrant.upsert(
    collection_name="documents",
    points=[
        models.PointStruct(id=i, vector=vector, payload={"body": text})
        for i, (text, vector) in enumerate(zip(texts, embed(texts)))
    ],
)

hits = qdrant.query_points(
    collection_name="documents",
    query=embed(["an animal on two wheels"])[0],
    limit=3,
).points
for hit in hits:
    print(f"{hit.score:.3f}  {hit.payload['body']}")
```

Use the same model for the stored texts and for the query.

## Notes

- Send the texts in batches of up to 2,048. One request is one auction and has one cap.
- Keep one model for one collection. A change of model needs a new collection and a new embed of every point. See [Embeddings](https://inference.ai.exchange/docs/embeddings.md).
- `create_collection` fails if the collection exists. Create it one time, or check with `collection_exists`.
- The exchange sets a cap on each request. It is in the `x-liquid-cap-usd` response header. To limit total spend, set a spending limit on the key. See [API keys](https://inference.ai.exchange/docs/keys.md).

## Troubleshooting

| Symptom                                 | Cause and fix                                                                              |
| --------------------------------------- | ------------------------------------------------------------------------------------------ |
| `Vector dimension error`                | The collection size differs from the model. Create the collection with the model's length. |
| `401` from the exchange                 | The key is wrong, revoked or expired. Export it again.                                     |
| `model_not_found`                       | The model is not on the book. Use an exact name from `GET /v1/models`.                     |
| A request is refused for lack of funds. | The workspace balance cannot cover the cap. Add funds on the **Credits** page.             |

See [Errors](https://inference.ai.exchange/docs/errors.md) for the error codes.

## Next steps

- [Embeddings](https://inference.ai.exchange/docs/embeddings.md): the request, the price and the limits.
- [LlamaIndex](https://inference.ai.exchange/docs/connect-llamaindex.md): build an index over your documents.
- [pgvector](https://inference.ai.exchange/docs/connect-pgvector.md): keep the vectors in Postgres instead.
