# Use Tencent VectorDB

> Switch storeBackend to tcvdb, required tcvdb.url / apiKey / database fields, BM25 language, server-side embedding model, and CA PEM path for HTTPS instances.

- Repository: TencentCloud/TencentDB-Agent-Memory
- GitHub: https://github.com/TencentCloud/TencentDB-Agent-Memory
- Human docs: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-5a33bbf5540a
- Complete Markdown: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-5a33bbf5540a/llms-full.txt

## Source Files

- `src/core/store/tcvdb.ts`
- `src/core/store/tcvdb-client.ts`
- `src/core/store/factory.ts`
- `src/config.ts`
- `openclaw.plugin.json`
- `scripts/export-tencent-vdb/export-tencent-vdb.ts`

---

---
title: "Use Tencent VectorDB"
description: "Switch storeBackend to tcvdb, required tcvdb.url / apiKey / database fields, BM25 language, server-side embedding model, and CA PEM path for HTTPS instances."
---

Set `storeBackend` to `tcvdb` so memory storage uses Tencent Cloud VectorDB (`TcvdbMemoryStore`) instead of local SQLite. Dense vectors are produced **on the VectorDB instance** from collection embedding config; sparse BM25 vectors are encoded **in-process** via `@tencentdb-agent-memory/tcvdb-text`; hybrid recall is a single `/document/hybridSearch` call with RRF.

<Info>
Default backend is `sqlite`. TCVDB is optional and requires a reachable VectorDB instance plus plugin (or Gateway) credentials. Client-side OpenAI-compatible `embedding.*` is **not** used for TCVDB dense vectors — the factory installs `NoopEmbeddingService` when `storeBackend` is `tcvdb`.
</Info>

## Prerequisites

- A Tencent Cloud VectorDB instance URL reachable from the OpenClaw gateway or TDAI Gateway host
- VectorDB account and API key (HTTP `Authorization: Bearer account=<username>&api_key=<apiKey>`)
- A **unique database name** you control (required at factory time; not auto-filled from instance id in runtime validation)
- For `https://` endpoints with a private CA: a readable CA PEM file path
- Plugin already installed and enabled (`memory-tencentdb` / OpenClaw `plugins.entries`)

## What changes when you switch

| Concern | `sqlite` (default) | `tcvdb` |
| --- | --- | --- |
| Dense vectors | Client embedding provider + local `vectors.db` / sqlite-vec | Server-side model on the collection (`tcvdb.embeddingModel`) |
| Sparse / keyword | Local FTS5 | Local BM25 sparse vectors + inverted index on `sparse_vector` |
| Hybrid recall | Parallel FTS + embed, client RRF | Native hybrid: dense `ann` + sparse `match` + `rerank.method: "rrf"` |
| Client embedding service | Remote provider when configured | `NoopEmbeddingService` (`dimensions` 0; skips local embed on capture) |
| L0/L1/profile store | SQLite tables | Collections `{database}_l0_conversations`, `{database}_l1_memories`, `{database}_profiles` |
| On-disk `vectors.db` | Used | Not used for vector storage |

Collection names are prefixed with the database name so multiple databases on one instance do not collide.

## Configure OpenClaw plugin

Edit `~/.openclaw/openclaw.json` under the plugin config object (plugin id `memory-tencentdb`):

```json
{
  "plugins": {
    "entries": {
      "memory-tencentdb": {
        "enabled": true,
        "config": {
          "storeBackend": "tcvdb",
          "tcvdb": {
            "url": "http://10.0.1.1:8100",
            "username": "root",
            "apiKey": "YOUR-VDB-API-KEY",
            "database": "agent_memory_prod",
            "alias": "primary",
            "embeddingModel": "bge-large-zh",
            "timeout": 10000,
            "caPemPath": "/etc/ssl/vdb-ca.pem"
          },
          "bm25": {
            "enabled": true,
            "language": "zh"
          },
          "recall": {
            "strategy": "hybrid"
          }
        }
      }
    }
  }
}
```

Restart the OpenClaw gateway after saving.

### Minimal required config

```json
{
  "storeBackend": "tcvdb",
  "tcvdb": {
    "url": "http://10.0.1.1:8100",
    "apiKey": "YOUR-VDB-API-KEY",
    "database": "agent_memory_prod"
  }
}
```

`createStoreBundle` **throws** if any of these are missing when `storeBackend === "tcvdb"`:

- `tcvdb.url`
- `tcvdb.apiKey`
- `tcvdb.database`

## Configure TDAI Gateway (Hermes / standalone)

For Gateway-hosted memory (`tdai-gateway.json` under `$TDAI_DATA_DIR`, default `~/.memory-tencentdb/memory-tdai`):

```bash
memory-tencentdb-ctl config vdb \
  --url "http://xxx-vdb.tencentclb.com:8100" \
  --username root \
  --api-key "YOUR-VDB-API-KEY" \
  --database "openclaw_memory" \
  --alias "primary" \
  --embedding-model "bge-large-zh" \
  --ca-pem "/etc/ssl/vdb-ca.pem" \
  --restart
```

Behavior:

- Writes `$.memory.tcvdb.{url, username, apiKey, database, alias?, caPemPath?, embeddingModel?}`
- By default also sets `$.memory.storeBackend` to `"tcvdb"` (skip with `--no-set-backend`)
- `--url` must start with `http://` or `https://`
- `--ca-pem` is validated as readable; only the path is stored (file is not copied)

Switch back to SQLite without deleting credentials:

```bash
memory-tencentdb-ctl config vdb-off --restart
# clear credentials as well:
memory-tencentdb-ctl config vdb-off --purge-creds --restart
```

## Field reference

### `storeBackend`

<ParamField body="storeBackend" type="string" default="sqlite">
Enum: `sqlite` | `tcvdb`. Parsed as `tcvdb` only when the value is exactly `"tcvdb"`; any other value falls back to `sqlite`.
</ParamField>

### `tcvdb` object

<ParamField body="url" type="string" required>
Instance base URL (e.g. `http://10.0.1.1:80` or external CLB host). Trailing slashes are stripped by the HTTP client.
</ParamField>

<ParamField body="apiKey" type="string" required>
VectorDB API key. Sent as `Authorization: Bearer account=<username>&api_key=<apiKey>`.
</ParamField>

<ParamField body="database" type="string" required>
Database name. Created idempotently on store init if missing. Must be unique for your deployment; used as collection name prefix.
</ParamField>

<ParamField body="username" type="string" default="root">
Account name for the Bearer auth header.
</ParamField>

<ParamField body="alias" type="string">
Optional human label stored in manifest / `database.json` snapshots for identification.
</ParamField>

<ParamField body="embeddingModel" type="string" default="bge-large-zh">
**Server-side** embedding model bound to L0/L1 collections at create time (`embedding.model` on the collection). Dense search passes query text as `embeddingItems` / ann `data`; the instance embeds them.
</ParamField>

<ParamField body="timeout" type="number" default="10000">
Per-request timeout in milliseconds (`AbortSignal.timeout`). Export CLI default is 30000; plugin/runtime default is 10000.
</ParamField>

<ParamField body="caPemPath" type="string">
Filesystem path to a CA certificate PEM file. Used only when `url` is `https://`. Loaded once at client construction into an undici `Agent` with `connect.ca`. Load failure is logged; HTTPS may then fail TLS verification.
</ParamField>

### `bm25` object (hybrid sparse path)

BM25 is primarily useful with `tcvdb` (native hybrid). Defaults still apply for both backends.

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `enabled` | boolean | `true` | When false, no encoder is created; TCVDB falls back to dense-only `/document/search` |
| `language` | `"zh"` \| `"en"` | `"zh"` | Pretrained BM25 params via `BM25Encoder.default(language)` (jieba-wasm tokenization in-package) |

```json
"bm25": { "enabled": true, "language": "en" }
```

Use `language: "en"` for English-dominant corpora (pair with an English-capable server embedding model such as `bge-large-en-v1.5` when your instance supports it).

## Runtime behavior

### Store factory

`createStoreBundle(config, { dataDir, logger })`:

1. Always builds optional BM25 encoder from `config.bm25`
2. On `storeBackend: "tcvdb"`, validates url / apiKey / database, constructs `TcvdbMemoryStore`, returns `embedding: NoopEmbeddingService` and store snapshot `{ type: "tcvdb", tcvdbUrl, tcvdbDatabase, tcvdbAlias? }`

### Init and collections

On `init()` the store:

1. `POST /database/list` then `/database/create` if needed  
2. Waits **5s** after a newly created database before creating collections  
3. Creates L1 and L0 collections with server embedding enabled on `text` / `message_text` respectively  
4. Creates profiles collection with embedding **disabled** (scalar + stub vector index)  
5. Prefers vector index type `DISK_FLAT` (dimension **1024**, metric **COSINE**); on API code `15113` or “DISK_FLAT not support” messages, falls back to `HNSW` (`M: 16`, `efConstruction: 200`)  
6. Always adds inverted index on `sparse_vector` (metric `IP`) for L0/L1  
7. Uses `shardNum: 1`, `replicaNum: 2`  
8. Sets `degraded = true` on init failure; subsequent ops return empty/false instead of throwing

### Upsert path

- L1/L0 documents store text fields; dense vectors are generated by the instance  
- If BM25 is enabled, `encodeTexts` fills `sparse_vector` before `/document/upsert` (`buildIndex: true`)  
- Capture skips local embed when embedding dimensions are 0 (noop / server-side path)

### Search path

- With BM25: `hybridSearch` with `ann` on field `text`/`message_text` (query string → server embed), `match` on `sparse_vector` (query sparse), `rerank: { method: "rrf", k: 60 }`, `readConsistency: "strongConsistency"`  
- Without BM25: dense-only `/document/search` with `embeddingItems`  
- Auto-recall short-circuits to `searchL1Hybrid` when `getCapabilities().nativeHybridSearch` is true (single HTTP call; no redundant local embed)

### HTTP client

- Retries up to **2** times on 5xx / timeout (not on 4xx API codes)  
- Logs one info line per successful path with latency (e.g. `/document/hybridSearch 85ms`)  
- Errors surface as `TcvdbApiError` with `apiCode` when the body `code !== 0`

## HTTPS and CA PEM

```text
https://instance-host
        │
        ▼
TcvdbClient constructor
  if url starts with https:// AND caPemPath set
    → fs.readFileSync(caPemPath)
    → undici Agent({ connect: { ca } })
    → request(..., { dispatcher })
```

- HTTP instances do not use `caPemPath`  
- If HTTPS is required by your network but `caPemPath` is omitted, TLS uses the process default trust store  
- Migration flag: `--tcvdb-ca-pem <path>`  
- ctl flag: `--ca-pem <path>`

## Embedding configuration interaction

| Config | Role with `tcvdb` |
| --- | --- |
| `tcvdb.embeddingModel` | **Authoritative** dense model on L0/L1 collections |
| `embedding.provider` / `baseUrl` / `apiKey` / `model` / `dimensions` | Not used for TCVDB dense vectors (noop service). Still relevant if you switch back to `sqlite` |
| `recall.strategy` | Prefer `"hybrid"` to use native hybrid; `"keyword"` uses sparse/FTS-style path; `"embedding"` uses dense path through store APIs |

Do not expect changing OpenAI-compatible `embedding.*` alone to change TCVDB dense vectors; recreate or migrate collections only when changing `embeddingModel` on a greenfield database.

## Verification

<Steps>
  <Step title="Confirm backend selection">
    After gateway restart, check plugin/Gateway logs for:

    ```text
    [memory-tdai][factory] Store created: backend=tcvdb, database=<name>, model=<embeddingModel>, bm25=enabled|disabled
    ```
  </Step>
  <Step title="Confirm init">
    Look for client debug/info around database/collection create, or degraded errors:

    ```text
    [memory-tdai][tcvdb] Initialized: db=<name>, model=<model>
    ```
  </Step>
  <Step title="Probe collections (optional)">
    ```bash
    npx export-tencent-vdb \
      --url "http://10.0.1.1:8100" \
      --username root \
      --api-key "YOUR-VDB-API-KEY" \
      --database "agent_memory_prod" \
      --probe
    ```

    Expect collections named `{database}_l1_memories`, `{database}_l0_conversations`, `{database}_profiles`.
  </Step>
  <Step title="Exercise hybrid recall">
    Run a session that should auto-recall, or call search tools. Logs may show:

    ```text
    [hybrid-native] Single-call hybrid: N results in Xms
    [memory-tdai][tcvdb-client] /document/hybridSearch Xms
    ```
  </Step>
  <Step title="Check manifest binding">
    Under the plugin data dir, `.metadata/manifest.json` store binding should report `type: "tcvdb"` with url/database (and optional alias). Mismatches vs current config are reported via store-binding diff helpers at startup.
  </Step>
</Steps>

## Export and inspect

Export collections to JSONL (skips dense `vector` by default; always includes `sparse_vector`):

```bash
npx export-tencent-vdb \
  --url "http://10.0.1.1:8100" \
  --username root \
  --api-key "YOUR-VDB-API-KEY" \
  --database "agent_memory_prod" \
  -o ./vdb-export-2026-08-04

# include dense vectors
npx export-tencent-vdb ... --include-vectors
```

Output layout:

```text
./vdb-export-YYYY-MM-DD/
├── <collection>.jsonl
├── schemas.json
└── export-meta.json
```

## Migrate existing SQLite data

To move local `vectors.db` into TCVDB and rewrite plugin config/manifest, use the offline migrator (see full workflow on the migrate page):

```bash
npx migrate-sqlite-to-tcvdb \
  --plugin-data-dir ~/.openclaw/memory-tdai \
  --openclaw-config-path ~/.openclaw/openclaw.json \
  --tcvdb-url http://127.0.0.1:80 \
  --tcvdb-username root \
  --tcvdb-api-key-env TCVDB_API_KEY \
  --tcvdb-database agent_memory_prod \
  --tcvdb-embedding-model bge-large-zh \
  --bm25-language zh \
  --yes
```

English corpus example: `--tcvdb-embedding-model bge-large-en-v1.5 --bm25-language en`. Dense-only: `--no-bm25-enabled`. HTTPS: `--tcvdb-ca-pem /path/to/ca.pem`.

## Failure modes

| Symptom | Likely cause | What to check |
| --- | --- | --- |
| Startup throw: requires `tcvdb.url` and `tcvdb.apiKey` | Missing required fields | Plugin config / `tdai-gateway.json` |
| Startup throw: requires `tcvdb.database` | Empty database name | Set a unique name before enable |
| Store degraded; empty recall | Init HTTP failure, wrong URL/auth, network | Client logs; probe with export `--probe` |
| Hybrid degrades to dense-only | `bm25.enabled: false` or encoder init failure | `bm25` config and package `@tencentdb-agent-memory/tcvdb-text` |
| HTTPS TLS errors | Missing/wrong CA | `caPemPath` / `--ca-pem` readability and PEM content |
| Collection create fails then HNSW | Instance lacks `DISK_FLAT` | Expected fallback; look for debug “DISK_FLAT not supported … falling back to HNSW” |
| Auth failures | Bad username/apiKey | Bearer format uses `account=` + `api_key=` |
| Client embedding 400s still appear | Unrelated `embedding.*` remote calls or leftover sqlite path | Confirm `storeBackend` and factory log line show `backend=tcvdb` |

## Related pages

<CardGroup>
  <Card title="Storage backends" href="/storage-backends">
    sqlite vs tcvdb factory selection, BM25, hybrid RRF, embedding service roles.
  </Card>
  <Card title="Configure embedding" href="/configure-embedding">
    OpenAI-compatible embedding fields used primarily by the sqlite backend.
  </Card>
  <Card title="Migrate SQLite to TCVDB" href="/migrate-to-tcvdb">
    Offline migrate-sqlite-to-tcvdb flags, layers, config rewrite, verification.
  </Card>
  <Card title="Plugin configuration reference" href="/plugin-config-reference">
    Full schema for storeBackend, tcvdb, bm25, and parseConfig defaults.
  </Card>
  <Card title="Gateway lifecycle" href="/gateway-ops">
    memory-tencentdb-ctl config vdb / vdb-off and tdai-gateway.json layout.
  </Card>
  <Card title="Inspect local memory" href="/inspect-local-memory">
    export-tencent-vdb and on-disk layout for diagnostics.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Broader failure checklist including store and recall issues.
  </Card>
</CardGroup>
