<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Praise James</title>
    <description>The latest articles on DEV Community by Praise James (@techwithpraisejames).</description>
    <link>https://dev.to/techwithpraisejames</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3532165%2Fd48ea0d6-d6fa-45f5-bc67-f4b5517e4eb9.jpg</url>
      <title>DEV Community: Praise James</title>
      <link>https://dev.to/techwithpraisejames</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/techwithpraisejames"/>
    <language>en</language>
    <item>
      <title>Build an OpenClaw Memory Plugin with Actian VectorAI DB</title>
      <dc:creator>Praise James</dc:creator>
      <pubDate>Thu, 09 Jul 2026 18:07:12 +0000</pubDate>
      <link>https://dev.to/actiandev/build-an-openclaw-memory-plugin-with-actian-vectorai-db-3gh2</link>
      <guid>https://dev.to/actiandev/build-an-openclaw-memory-plugin-with-actian-vectorai-db-3gh2</guid>
      <description>&lt;p&gt;Context compaction is a common failure point for most OpenClaw memory systems. When the context window fills, OpenClaw compacts the session to make room for new messages. Any memory operations that were not flushed to durable storage can be lost during this transition.&lt;/p&gt;

&lt;p&gt;The default memory-core backend uses a &lt;a href="https://docs.openclaw.ai/concepts/memory-builtin" rel="noopener noreferrer"&gt;per-agent SQLite database&lt;/a&gt; powered by sqlite-vec. This architecture is lightweight, easy to set up, and works well for individual developers running a single agent on a local machine. It becomes fragile when you run multiple agents or when a file-based state needs to be shared or managed outside the runtime.&lt;/p&gt;

&lt;p&gt;To address these limitations, this tutorial demonstrates how to build a production-ready OpenClaw memory plugin powered by &lt;a href="https://www.actian.com/databases/vectorai-db/" rel="noopener noreferrer"&gt;Actian VectorAI DB&lt;/a&gt;. Rather than storing embeddings and memory records inside local SQLite files, the plugin externalizes memory into a dedicated vector database designed for high availability, durability, and independent scaling.&lt;/p&gt;

&lt;p&gt;By moving memory management outside the runtime, agents gain access to a centralized knowledge layer that teams can share across processes, hosts, and deployment environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  How OpenClaw Memory Works by Default
&lt;/h2&gt;

&lt;p&gt;OpenClaw uses a &lt;a href="https://docs.openclaw.ai/concepts/memory" rel="noopener noreferrer"&gt;default memory plugin&lt;/a&gt; called &lt;code&gt;memory-core&lt;/code&gt;. It indexes &lt;code&gt;MEMORY.md&lt;/code&gt; into chunks and stores them in a per-agent SQLite database located at &lt;code&gt;~/.openclaw/memory/&amp;lt;agentId&amp;gt;.sqlite&lt;/code&gt;. Inside this file are two key components: an FTS5 (Full-Text Search version 5) index for keyword search and a &lt;code&gt;vec0&lt;/code&gt; vector index powered by the &lt;code&gt;sqlite-vec&lt;/code&gt; extension for semantic search.&lt;/p&gt;

&lt;p&gt;The important design point is that the Markdown files in the agent workspace are the source of truth. Files like &lt;code&gt;MEMORY.md&lt;/code&gt; and &lt;code&gt;memory/YYYY-MM-DD.md&lt;/code&gt; hold the actual durable content. The SQLite database does not store primary memory. It only &lt;a href="https://mem0.ai/blog/openclaw-memory-system-how-it-works-and-how-to-set-it-up" rel="noopener noreferrer"&gt;builds a derived, regenerable index&lt;/a&gt; over those files. This distinction matters because this tutorial replaces the indexing layer, not the underlying memory files.&lt;/p&gt;

&lt;p&gt;In practice, this design introduces some failure modes that push teams toward external memory backends. &lt;/p&gt;

&lt;h3&gt;
  
  
  Failure modes in the default memory-core backend
&lt;/h3&gt;

&lt;p&gt;Context compaction events can &lt;a href="https://github.com/openclaw/openclaw/issues/39609" rel="noopener noreferrer"&gt;orphan in-flight memory operations&lt;/a&gt;. Even though recent fixes in the May 2026 release improve how OpenClaw closes local embedding providers when active-memory searches time out, the underlying issue remains tied to lifecycle boundaries during compaction.&lt;/p&gt;

&lt;p&gt;One of the failure modes is that multiple agent instances cannot reliably share a single &lt;code&gt;&amp;lt;agentId&amp;gt;.sqlite&lt;/code&gt; file. This creates contention in distributed setups where agents need shared knowledge, leading to inconsistent memory state across instances.&lt;/p&gt;

&lt;p&gt;Another failure mode is that &lt;code&gt;sqlite-vec&lt;/code&gt; extension must exist in the runtime environment. When it is missing, OpenClaw falls back to &lt;a href="https://www.pingcap.com/blog/local-first-rag-using-sqlite-ai-agent-memory-openclaw/[](url)" rel="noopener noreferrer"&gt;in-process JavaScript cosine similarity&lt;/a&gt;, which does not scale for production workloads or high-throughput memory search.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context compaction lifecycle
&lt;/h3&gt;

&lt;p&gt;Context compaction runs when the context window fills and OpenClaw removes older messages to free space. Before compaction begins, &lt;a href="https://mem0.ai/blog/openclaw-memory-management-live-data-compaction-and-best-practices#:~:text=Pre%2Dcompaction%20memory%20flush" rel="noopener noreferrer"&gt;OpenClaw triggers an automatic memory flush&lt;/a&gt;, but this only captures memories the agent has explicitly written. Any in-flight operations or pending writes that have not reached the memory files are not persisted.&lt;/p&gt;

&lt;p&gt;After compaction, the agent resumes with a compressed version of its previous conversation. At that point, memory recall depends on what has already been written to the memory files and indexed for retrieval. Any information that was still in-flight and had not been persisted before compaction cannot be recalled during that session. The issue is not that durable memory disappears, but that memory that was never successfully persisted cannot be recovered.&lt;/p&gt;

&lt;p&gt;Because the SQLite database lives inside the agent process, the vector index is tightly coupled to the runtime. When the process restarts or compaction resets the context, the index does not exist independently. Moving the memory layer to VectorAI DB decouples storage from the agent lifecycle, so the memory system survives compaction and continues to serve queries across sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Plugin Slot System
&lt;/h2&gt;

&lt;p&gt;OpenClaw uses a named slot system to control extensibility points inside the agent runtime. The &lt;a href="https://docs.openclaw.ai/tools/plugin" rel="noopener noreferrer"&gt;memory system is one of these slots&lt;/a&gt;, exposed as &lt;code&gt;plugins.slots.memory&lt;/code&gt;. This slot determines which backend handles all memory-related tool calls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.openclaw.ai/concepts/context-engine" rel="noopener noreferrer"&gt;The slot system separates memory behavior from memory storage&lt;/a&gt;. That separation allows you to move from a local SQLite-based index to an external vector database without modifying agent logic or tool definitions. In practice, this means one config change followed by a restart is enough to replace the entire memory backend.&lt;/p&gt;

&lt;p&gt;OpenClaw enforces a single active memory plugin at a time. The architecture does not support multiple concurrent memory backends in the same slot. &lt;a href="https://github.com/openclaw/openclaw/issues/60572[](url)" rel="noopener noreferrer"&gt;Issue #60572 on GitHub&lt;/a&gt; proposes splitting memory into sub-slots such as &lt;code&gt;memory.recall&lt;/code&gt;, &lt;code&gt;memory.store&lt;/code&gt;, and &lt;code&gt;memory.compaction&lt;/code&gt;, but this has not merged as of May 2026. As a result, every implementation must fully replace the existing memory provider rather than extend it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhtgpn4x0pr9vsz3i2b65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhtgpn4x0pr9vsz3i2b65.png" alt="Figure 1: Plugin slot architecture&lt;br&gt;
" width="412" height="512"&gt;&lt;/a&gt;&lt;br&gt;
Figure 1: Plugin slot architecture&lt;/p&gt;

&lt;p&gt;Before writing the VectorAI DB plugin, it helps to study existing implementations of this pattern. The noncelogic/openclaw-memory-lancedb and lancedb/openclaw-lancedb-demo repositories show how external vector stores integrate into the slot system. The serenichron/openclaw-memory-mem0 plugin is the cleanest reference. It demonstrates the minimal structure required to implement a working memory backend and serves as the template for the VectorAI DB integration in this tutorial.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting Up VectorAI DB
&lt;/h2&gt;

&lt;p&gt;Before writing the plugin, get VectorAI DB running locally and verify vector search works end-to-end. To execute the commands in this section, install the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;NPM&lt;/li&gt;
&lt;li&gt;- Docker&lt;/li&gt;
&lt;li&gt;- Ollama&lt;/li&gt;
&lt;li&gt;- OpenClaw CLI&lt;/li&gt;
&lt;li&gt;- &lt;a href="https://api.together.ai/" rel="noopener noreferrer"&gt;Together AI API key&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In your project directory, create a &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;vectorai&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actian/vectorai:latest&lt;/span&gt;
   &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux/amd64&lt;/span&gt; &lt;span class="c1"&gt;# If you are using a macOs device, else comment this line.&lt;/span&gt;
   &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vectorai_db&lt;/span&gt;
   &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;6573:6573"&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;6574:6574"&lt;/span&gt;
   &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/var/lib/actian-vectorai&lt;/span&gt;
   &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;VECTORAI_LOG_LEVEL=info&lt;/span&gt;
   &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the VectorAI DB server by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure Ollama is running and the model is ready:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull nomic-embed-text
ollama pull llama3.2:3b
ollama serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vectorai-memory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"openclaw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="s2"&gt;"./dist/index.js"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esbuild index.ts --bundle --platform=node --format=esm --external:openclaw --external:@actian/vectorai-client --external:@grpc/grpc-js --external:typebox --outfile=dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"build:check"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsc --noEmit"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"@actian/vectorai-client"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.0.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"@sinclair/typebox"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.34.49"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"openclaw"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2026.5.28"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"typebox"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.1.39"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"@types/node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^22.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"esbuild"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.28.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^5.0.0"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;tsconfig.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ES2022"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ESNext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"moduleResolution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundler"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"esModuleInterop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"skipLibCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="s2"&gt;"index.ts"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This installs all the dependencies.&lt;/p&gt;

&lt;p&gt;Create a collection the plugin will use. In your project directory, create a file &lt;code&gt;create-collection.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;VectorAIClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@actian/vectorai-client&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost:6574&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;restUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:6573&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;768&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="n"&gt;nomic&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;embed&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="n"&gt;dimensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openclaw-memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;dimension&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;distanceMetric&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;COSINE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Smoke&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;insert&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openclaw-memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;smoke test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MEMORY.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;


&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openclaw-memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;


&lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Collection ready. Top result:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the connection by running the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx tsx create-collection.ts 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see an output as shown:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6urftlzm389w55wx3743.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6urftlzm389w55wx3743.png" alt="Figure 2: Verify connection&lt;br&gt;
" width="512" height="62"&gt;&lt;/a&gt;&lt;br&gt;
Figure 2: Verify connection&lt;/p&gt;
&lt;h2&gt;
  
  
  Building the Plugin
&lt;/h2&gt;

&lt;p&gt;The OpenClaw memory slot expects a plugin that implements the memory tools and lifecycle hooks used by the agent runtime. The plugin below replaces the default &lt;code&gt;SQLite/sqlite-vec&lt;/code&gt; backend with VectorAI DB.&lt;/p&gt;

&lt;p&gt;Create a file &lt;code&gt;index.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;defineToolPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openclaw/plugin-sdk/tool-plugin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;typebox&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hasId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@actian/vectorai-client&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_GRPC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost:6574&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_REST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:6573&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_OLLAMA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:11434&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_COLLECTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;openclaw-memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EMBED_MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nomic-embed-text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_LIMIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EMBED_DIM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hashId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;imul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ollamaHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`${ollamaHost}/api/embeddings`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;EMBED_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`Ollama embed failed: ${res.status} ${res.statusText}`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineToolPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vectorai-memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VectorAI Memory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Routes OpenClaw memory tools to Actian VectorAI DB via Ollama embeddings.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;


   &lt;span class="n"&gt;configSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
       &lt;span class="n"&gt;grpcAddr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VectorAI gRPC address (default: localhost:6574)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
       &lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="n"&gt;restUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VectorAI REST URL (default: http://localhost:6573)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
       &lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="n"&gt;ollamaHost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ollama host for embeddings (default: http://localhost:11434)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
       &lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;VectorAI collection name (default: openclaw-memory)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
       &lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;}),&lt;/span&gt;


   &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;


       &lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
           &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vectorai_store&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Store in VectorAI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Embed and store a text chunk in VectorAI DB. Returns the assigned numeric ID.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
               &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The text content to embed and store.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
               &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The source file or identifier this text came from.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
               &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Line number within the source file.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})),&lt;/span&gt;
           &lt;span class="p"&gt;}),&lt;/span&gt;
           &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;throwIfAborted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;grpcAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grpcAddr&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_GRPC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_REST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ollamaHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ollamaHost&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_OLLAMA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_COLLECTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grpcAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ollamaHost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hashId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`${source}:${line ?? 0}:${text.slice(0, 40)}`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


               &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
               &lt;span class="p"&gt;]);&lt;/span&gt;


               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;stored&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
           &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;}),&lt;/span&gt;


       &lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
           &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vectorai_search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Search VectorAI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Semantic search over stored memories. Returns ranked results with scores.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
               &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Natural language query to find semantically similar stored entries.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
               &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                   &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                       &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sb"&gt;`Max results to return (default: ${DEFAULT_LIMIT}, max: 20).`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;minimum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="p"&gt;})&lt;/span&gt;
               &lt;span class="p"&gt;),&lt;/span&gt;
           &lt;span class="p"&gt;}),&lt;/span&gt;
           &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;throwIfAborted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;grpcAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grpcAddr&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_GRPC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_REST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;ollamaHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ollamaHost&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_OLLAMA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_COLLECTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grpcAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ollamaHost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_LIMIT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="p"&gt;});&lt;/span&gt;


               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                   &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
                       &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="p"&gt;}))&lt;/span&gt;
               &lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;}),&lt;/span&gt;


       &lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
           &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vectorai_recall&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Recall from VectorAI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieve a specific memory by its numeric ID.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
               &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The numeric ID of the memory point to retrieve.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
           &lt;span class="p"&gt;}),&lt;/span&gt;
           &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;throwIfAborted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;grpcAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grpcAddr&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_GRPC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_REST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_COLLECTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grpcAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                   &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EMBED_DIM&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;hasId&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
               &lt;span class="p"&gt;);&lt;/span&gt;


               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                   &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;
                       &lt;span class="err"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                       &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;
               &lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;}),&lt;/span&gt;


       &lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
           &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vectorai_forget&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Forget from VectorAI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Permanently delete a stored memory by its numeric ID.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
               &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The numeric ID of the memory point to delete.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
           &lt;span class="p"&gt;}),&lt;/span&gt;
           &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;throwIfAborted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;


               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;grpcAddr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grpcAddr&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_GRPC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_REST&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="err"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_COLLECTION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


               &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grpcAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;restUrl&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
               &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;


               &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
           &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="p"&gt;}),&lt;/span&gt;


   &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the file &lt;code&gt;dist/index.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The plugin uses OpenClaw's plugin SDK and exports a standard plugin entry.&lt;br&gt;
The &lt;code&gt;defineToolPlugin()&lt;/code&gt; function is the plugin entry point. OpenClaw calls it during startup and exposes the runtime API used to register tools and lifecycle hooks.&lt;/p&gt;

&lt;p&gt;The plugin creates a VectorAI DB client and an embedding helper that generates vectors using Ollama's &lt;code&gt;nomic-embed-text model&lt;/code&gt;. Every memory operation uses the same embedding pipeline, which keeps retrieval and storage consistent.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tool implementations
&lt;/h3&gt;

&lt;p&gt;The plugin registers four tools that mirror OpenClaw's memory operations.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vectorai_store&lt;/code&gt; embeds a text chunk and stores it together with metadata such as the source file path and line number.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vectorai_search&lt;/code&gt; embeds the query, performs a vector search against the &lt;code&gt;openclaw-memory&lt;/code&gt; collection, and returns the most relevant memories ranked by semantic similarity.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vectorai_recall&lt;/code&gt; retrieves a specific memory by ID.&lt;/p&gt;

&lt;p&gt;Each stored record contains metadata. This metadata makes it possible to trace search results back to the original memory file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vectorai_forget&lt;/code&gt; removes a stored memory from the VectorAI DB collection.&lt;/p&gt;

&lt;p&gt;At this point, OpenClaw can already store, search, recall, and delete memories through VectorAI DB instead of &lt;code&gt;SQLite/sqlite-vec&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configure OpenClaw
&lt;/h3&gt;

&lt;p&gt;Create an &lt;code&gt;openclaw.plugin.json&lt;/code&gt; file that registers the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vectorai-memory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VectorAI memory"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Store and retrieve data in Actian VectorAI DB using semantic vector search."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"activation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"onStartup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"contracts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="s2"&gt;"vectorai_store"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="s2"&gt;"vectorai_search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="s2"&gt;"vectorai_recall"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="s2"&gt;"vectorai_forget"&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"configSchema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"grpcAddr"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"restUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"ollamaHost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="nl"&gt;"collection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
           &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This single configuration change swaps the memory backend from &lt;code&gt;SQLite/sqlite-vec&lt;/code&gt; to VectorAI DB. The agent behavior and prompts stay the same but the memory layer changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing and activating the plugin
&lt;/h3&gt;

&lt;p&gt;At this point, the plugin is complete. The final step is swapping OpenClaw from the default &lt;code&gt;memory-core&lt;/code&gt; backend to the new VectorAI DB backend.&lt;br&gt;
So far, your directory structure should look like this:&lt;br&gt;
.&lt;/p&gt;

&lt;p&gt;├── create-collection.ts&lt;br&gt;
├── data&lt;br&gt;
├── dist&lt;br&gt;
│   └── index.js&lt;br&gt;
├── docker-compose.yml&lt;br&gt;
├── index.ts&lt;br&gt;
├── openclaw.plugin.json&lt;br&gt;
├── tsconfig.json&lt;br&gt;
├── package-lock.json&lt;br&gt;
├── package.json&lt;/p&gt;

&lt;p&gt;Install the plugin from your local directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw plugins &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You see an output shown:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg9323p7cs9r3k1q297kb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg9323p7cs9r3k1q297kb.png" alt="Figure 3: OpenClaw plugin installation" width="512" height="110"&gt;&lt;/a&gt;&lt;br&gt;
Figure 3: OpenClaw plugin installation&lt;/p&gt;

&lt;p&gt;Configure your OpenClaw agent to use the Together AI API Llama-3.3-70B-Instruct-Turbo chat model by default. Replace the placeholder with your API key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw onboard &lt;span class="nt"&gt;--non-interactive&lt;/span&gt; &lt;span class="nt"&gt;--accept-risk&lt;/span&gt; &lt;span class="nt"&gt;--mode&lt;/span&gt; &lt;span class="nb"&gt;local&lt;/span&gt; &lt;span class="nt"&gt;--auth-choice&lt;/span&gt; together-api-key &lt;span class="nt"&gt;--together-api-key&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOGETHER_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
openclaw config &lt;span class="nb"&gt;set &lt;/span&gt;agents.defaults.model.primary &lt;span class="s2"&gt;"together/meta-llama/Llama-3.3-70B-Instruct-Turbo"&lt;/span&gt;
openclaw config &lt;span class="nb"&gt;set &lt;/span&gt;plugins.allow &lt;span class="s1"&gt;'["vectorai-memory", "together"]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart the OpenClaw gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw gateway restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test connection
&lt;/h3&gt;

&lt;p&gt;Check the agent your OpenClaw is using by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw agents list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see an output shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1rlnuf65qbtzq9vn9ib.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1rlnuf65qbtzq9vn9ib.png" alt="Figure 4: Getting the agent&lt;br&gt;
" width="512" height="93"&gt;&lt;/a&gt;&lt;br&gt;
Figure 4: Getting the agent&lt;/p&gt;

&lt;p&gt;In this case, OpenClaw uses the default agent &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To verify the plugin works, store a test memory in VectorAI DB using the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw agent &lt;span class="nt"&gt;--agent&lt;/span&gt; main &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s1"&gt;'/tool vectorai_store {"text":"Rome is the capital of Italy","source":"test","line":1}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq1e20io0s9vdjb9bojrz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq1e20io0s9vdjb9bojrz.png" alt="Figure 5: Storing to VectorAI DB&lt;br&gt;
" width="512" height="77"&gt;&lt;/a&gt;&lt;br&gt;
Figure 5: Storing to VectorAI DB&lt;/p&gt;

&lt;p&gt;To retrieve it, ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openclaw agent &lt;span class="nt"&gt;--agent&lt;/span&gt; main &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s1"&gt;'/tool vectorai_search {"query":"what is the capital of Italy?"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get the following results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9zby4a4jng51ubj8mlcf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9zby4a4jng51ubj8mlcf.png" alt="Figure 6: Agent retrieving from VectorAI DB&lt;br&gt;
" width="512" height="110"&gt;&lt;/a&gt;&lt;br&gt;
Figure 6: Agent retrieving from VectorAI DB&lt;/p&gt;

&lt;h2&gt;
  
  
  Why On-Premises Memory Matters for Production Agents
&lt;/h2&gt;

&lt;p&gt;For many teams, cloud-hosted memory services are a practical choice. They simplify deployment and reduce operational overhead. However, they are not always an option.&lt;/p&gt;

&lt;p&gt;Production agents often run in environments where data cannot leave the network boundary. Financial institutions, healthcare organizations, government agencies, and industrial environments frequently restrict cloud egress or require local data residency. In these cases, the memory layer must run alongside the application infrastructure.&lt;/p&gt;

&lt;p&gt;VectorAI DB allows teams to keep semantic search and durable memory inside their own environment. Memory remains available across agent restarts, context compaction events, and multiple agent instances without depending on an external service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;OpenClaw's default SQLite/sqlite-vec memory backend works well for a single agent running on a single machine. As soon as you need shared memory, durable storage across context compaction events, or independent management of the vector store, an external backend becomes a better fit.&lt;/p&gt;

&lt;p&gt;In this tutorial, you built a custom OpenClaw plugin that routes memory operations to VectorAI DB. The swap required only a plugin installation, a configuration change, and a gateway restart. The agent behavior stayed the same, but the memory layer became persistent, shareable, and independent of the agent runtime.&lt;/p&gt;

&lt;p&gt;Get started with &lt;a href="https://www.actian.com/databases/vectorai-db/community-edition/" rel="noopener noreferrer"&gt;Actian VectorAI DB Community Edition&lt;/a&gt; by signing up today. Check the &lt;a href="https://docs.vectoraidb.actian.com/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for deployment and usage instructions, and participate in the &lt;a href="https://discord.com/invite/432A2M63Py[](url)" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; community for support and discussions.&lt;/p&gt;

</description>
      <category>vectoraidb</category>
      <category>openclaw</category>
    </item>
    <item>
      <title>Running Gemma 2B on Edge Hardware with Actian VectorAI DB</title>
      <dc:creator>Praise James</dc:creator>
      <pubDate>Thu, 09 Jul 2026 17:49:35 +0000</pubDate>
      <link>https://dev.to/actiandev/running-gemma-2b-on-edge-hardware-with-actian-vectorai-db-29ed</link>
      <guid>https://dev.to/actiandev/running-gemma-2b-on-edge-hardware-with-actian-vectorai-db-29ed</guid>
      <description>&lt;p&gt;Today, running a powerful language model entirely on edge hardware is no longer the hard part. The problem is making it useful once it is there. A developer can deploy &lt;a href="https://huggingface.co/google/gemma-2b" rel="noopener noreferrer"&gt;Gemma 2B&lt;/a&gt; on &lt;a href="https://www.nvidia.com/en-us/autonomous-machines/embedded-systems/jetson-orin/nano-super-developer-kit/" rel="noopener noreferrer"&gt;NVIDIA Jetson Orin Nano&lt;/a&gt; or a custom hardware device, run inference locally, and generate responses without sending a single token to the cloud. &lt;/p&gt;

&lt;p&gt;The model performs well, supports an 8K token context window, and delivers enough throughput for many production edge applications. The real challenge appears when the agent needs to answer questions from a 50,000-document maintenance corpus that is far larger than anything that fits inside its context window.&lt;/p&gt;

&lt;p&gt;A local model without a local vector store faces two choices. Either overload the context window with documents that do not fit or call a remote retrieval service that may not exist in an offline environment. Neither option works for industrial systems, robotics platforms, field service devices, or other regulated industries where connectivity is unreliable or unavailable.&lt;/p&gt;

&lt;p&gt;This article builds a complete local inference stack using the Gemma 2B model. Gemma 2B handles text generation through Ollama. Actian VectorAI DB handles semantic retrieval from a large document corpus. The entire stack runs on the device, requires no cloud services during operation, and provides a practical foundation for retrieval-augmented agents deployed at the edge.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Gemma 2B Brings to Edge Hardware
&lt;/h2&gt;

&lt;p&gt;Most edge AI developers no longer struggle to run a language model locally. The challenge is finding one that delivers useful reasoning and text generation while fitting within the memory and power constraints of edge devices. &lt;/p&gt;

&lt;p&gt;Gemma 2B is a lightweight open model designed for local inference. It can run on devices such as the NVIDIA Jetson Orin Nano, Raspberry Pi 5, and industrial gateways. In this setup, the model runs on-device, so data stays local instead of flowing through cloud infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Model&lt;/strong&gt;: Gemma 2B&lt;br&gt;
&lt;strong&gt;Parameters&lt;/strong&gt;: 2 billion&lt;br&gt;
&lt;strong&gt;Disk size&lt;/strong&gt;: ~1.6GB&lt;br&gt;
&lt;strong&gt;Target hardware&lt;/strong&gt;: Raspberry Pi 5, Jetson Orin Nano, edge gateways, embedded Linux devices&lt;br&gt;
&lt;strong&gt;RAM required&lt;/strong&gt;: &lt;a href="https://huggingface.co/google/gemma-2b/discussions/61#:~:text=We%20recommend%20a%208GB%2B%20RAM%20on%20GPU%20for%20the%202B%20checkpoint%20and%2024GB%2B%20RAM%20on%20GPU%20for%20the%207B%20checkpoint.%20Please%20refer%20to%20this%20Gemma%20official%20document%20for%20more%20details%20in%20this.%20Thank%20you." rel="noopener noreferrer"&gt;8GB+&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For many edge workloads, these hardware requirements are modest enough to leave room for additional services on the same device. &lt;/p&gt;

&lt;p&gt;Gemma 2B also supports an &lt;a href="https://ollama.com/library/gemma2#:~:text=ollama%20run%20gemma2-,Models,-View%20all%20%E2%86%92" rel="noopener noreferrer"&gt;8K token context window&lt;/a&gt;. While that is sufficient for conversations, instructions, and small document sets, it quickly becomes a limitation when an agent must search across thousands of maintenance manuals, support articles, operational procedures, or historical records. A single industrial knowledge base can contain millions of words, far exceeding what the model can hold in context at once. The model is &lt;a href="https://blog.google/innovation-and-ai/technology/developers-tools/google-gemma-2/" rel="noopener noreferrer"&gt;released under a commercially friendly license&lt;/a&gt;, which matters if you need to deploy it on-premises or at the edge.&lt;/p&gt;

&lt;p&gt;The problem is that local inference only solves half of the architecture. Once the corpus grows beyond what fits in the context window, the agent needs a retrieval layer that can find the right information before generation begins.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Retrieval Gap
&lt;/h2&gt;

&lt;p&gt;Getting Gemma 2B running locally solves the generation problem. It does not solve the retrieval problem. An edge agent can only answer questions using information that exists in its prompt or context window. As soon as the knowledge base grows beyond what fits in memory, the agent needs a way to locate the right information before generating a response. &lt;/p&gt;

&lt;p&gt;This approach has some failure modes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Context window overflow
&lt;/h3&gt;

&lt;p&gt;An 8K token context window sounds large until the agent must work with a real-world document collection. A library of regulatory documentation can contain hundreds of thousands or even millions of words.&lt;/p&gt;

&lt;p&gt;Without retrieval, developers often attempt to load as many documents as possible into the prompt. That approach quickly reaches the context limit. The model then truncates documents, loses important details, or generates answers from incomplete information. The result is lower accuracy and less reliable responses.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cloud dependency
&lt;/h3&gt;

&lt;p&gt;Many Retrieval-Augmented Generation (RAG) tutorials solve the context problem by connecting the model to a cloud-hosted vector database. That works in environments where internet connectivity is not a core requirement. It becomes a problem when the application runs in a highly regulated or an air-gapped environment, with no internet access.&lt;/p&gt;

&lt;p&gt;When the retrieval layer depends on a cloud service, the agent depends on the network. If the connection fails, the retrieval fails. In many cases, the agent cannot answer questions because the information it needs never reaches the model.&lt;/p&gt;
&lt;h3&gt;
  
  
  Scale degradation with basic embedding search
&lt;/h3&gt;

&lt;p&gt;Simple embedding search implementations work well with a few hundred documents. Many developers start with an in-memory vector index or a basic search capability bundled with a local inference framework. Performance is acceptable during testing because the dataset is small.&lt;/p&gt;

&lt;p&gt;The situation changes when the corpus grows to tens of thousands of document chunks and the application begins serving multiple queries per second. Search latency increases, memory usage rises, and retrieval becomes the bottleneck in the system.&lt;/p&gt;

&lt;p&gt;An edge-compliant vector store deployed on the device resolves all three challenges without adding cloud dependency.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Full Stack
&lt;/h2&gt;

&lt;p&gt;The goal is to keep both inference and retrieval on the same device. Gemma 2B handles generation while VectorAI DB handles retrieval. Together, they form a complete RAG stack that operates without cloud dependency.&lt;/p&gt;

&lt;p&gt;In this architecture, the user never interacts with the language model directly. Every query first passes through the retrieval layer, which searches the local document corpus and returns the most relevant information. The application injects those retrieved documents into the prompt before sending it to Gemma 2B. The model then generates a response grounded in the retrieved context rather than relying solely on its training data.&lt;/p&gt;

&lt;p&gt;The stack consists of two core components:&lt;/p&gt;
&lt;h3&gt;
  
  
  Gemma 2B
&lt;/h3&gt;

&lt;p&gt;Gemma 2B serves as the generation layer. It receives the user query along with the retrieved context and produces the final response. Running through Ollama simplifies deployment on edge hardware by providing a lightweight local API for inference. &lt;/p&gt;

&lt;p&gt;Responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accept user prompts&lt;/li&gt;
&lt;li&gt;Process retrieved context&lt;/li&gt;
&lt;li&gt;Generate grounded responses&lt;/li&gt;
&lt;li&gt;Run entirely on-device&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  VectorAI DB
&lt;/h3&gt;

&lt;p&gt;VectorAI DB serves as the retrieval layer. It stores document chunks and their metadata, then performs semantic search against the local corpus. When a user submits a query, the application converts that query into an embedding and sends it to VectorAI DB. The database returns the most semantically relevant document chunks, which become context for the language model.&lt;/p&gt;

&lt;p&gt;Responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store document embeddings&lt;/li&gt;
&lt;li&gt;Perform a semantic similarity search&lt;/li&gt;
&lt;li&gt;Retrieve relevant context&lt;/li&gt;
&lt;li&gt;Operate without network connectivity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This architecture keeps every component inside the device boundary. Once the model, embeddings, and database are installed, the system can answer questions without relying on external APIs, cloud-hosted vector databases, or internet connectivity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsmkbbd7qdehupvs6seua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsmkbbd7qdehupvs6seua.png" alt="Figure 1: Local inference and retrieval stack architecture" width="408" height="512"&gt;&lt;/a&gt;&lt;br&gt;
Figure 1: Local inference and retrieval stack architecture&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting Up the Stack
&lt;/h2&gt;

&lt;p&gt;This section builds a complete local retrieval and inference stack on an edge device using Gemma 2B for inference and VectorAI DB for retrieval.&lt;/p&gt;
&lt;h3&gt;
  
  
  Stage 1: Install Ollama and pull Gemma 2B
&lt;/h3&gt;

&lt;p&gt;Install Ollama on your custom hardware device by following the &lt;a href="https://ollama.com/download" rel="noopener noreferrer"&gt;installation instructions for your operating system&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After installation, pull the Gemma 2B model. Use the latest available tag for Gemma 2B in Ollama. Confirm the exact tag in the &lt;a href="https://ollama.com/library/gemma2" rel="noopener noreferrer"&gt;Ollama model registry&lt;/a&gt; before production use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull gemma2:2b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see an output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fab399mne9e1mloaadxpm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fab399mne9e1mloaadxpm.png" alt="Figure 2: Ollama pull for Gemma 2B&lt;br&gt;
" width="512" height="76"&gt;&lt;/a&gt;&lt;br&gt;
Figure 2: Ollama pull for Gemma 2B&lt;/p&gt;

&lt;p&gt;Verify the installation by running the test prompt&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run gemma2:2b &lt;span class="s2"&gt;"Explain what a vector database does in one sentence."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4neb6aa95kd0oj5uf6dz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4neb6aa95kd0oj5uf6dz.png" alt="Figure 3: Verify Ollama Gemma 2B installation" width="512" height="34"&gt;&lt;/a&gt;&lt;br&gt;
Figure 3: Verify Ollama Gemma 2B installation&lt;/p&gt;
&lt;h3&gt;
  
  
  Stage 2: Install Docker and run VectorAI DB
&lt;/h3&gt;

&lt;p&gt;Install Docker by &lt;a href="https://docs.docker.com/engine/install/" rel="noopener noreferrer"&gt;following the guide&lt;/a&gt; and confirm that the Docker service is running. Then, create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file with the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:
 vectorai:
   image: actian/vectorai:latest
   container_name: vectorai_db
   ports:
    - "6573:6573" #rest
    - "6574:6574" #grpc
   volumes:
     # vector data persists across restarts
    - ./data:/var/lib/actian-vectorai
   environment:
    - VECTORAI_LOG_LEVEL=info
    - ACTIAN_VECTORAI_ACCEPT_EULA=YES
   restart: unless-stopped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the VectorAI DB server by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stage 3: Connect with VectorAIClient and create a collection
&lt;/h3&gt;

&lt;p&gt;Install &lt;a href="https://docs.astral.sh/uv/getting-started/installation/" rel="noopener noreferrer"&gt;UV&lt;/a&gt; and run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv init &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the dependencies by running the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv add actian-vectorai-client requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a file &lt;code&gt;create_collection.py&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;actian_vectorai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VectorParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Distance&lt;/span&gt;
&lt;span class="c1"&gt;# ── Config ─────────────────────────────────────────────────────────────────────
&lt;/span&gt;&lt;span class="n"&gt;VECTORAI_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost:6574&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;COLLECTION&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;OLLAMA_URL&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:11434/api/embeddings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;OLLAMA_MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemma2:2b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="c1"&gt;# ──────────────────────────────────────────────────────────────────────────────
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_embedding_dim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Probe Ollama once to get the embedding dimension for this model.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;OLLAMA_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OLLAMA_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;probe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embedding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Probing embedding dimension from Ollama (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;OLLAMA_MODEL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;dim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_embedding_dim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Embedding dimension: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VECTORAI_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;health_check&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Connected to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; v&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


       &lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;COLLECTION&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Collection &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;COLLECTION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; already exists — nothing to do.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt;
       &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="n"&gt;COLLECTION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;vectors_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;VectorParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Distance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cosine&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="c1"&gt;# 5. Confirm using get_info()
&lt;/span&gt;       &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COLLECTION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Collection created: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;COLLECTION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Vector size : &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Distance    : Cosine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Status      : &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  Points      : &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points_count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Payload fields written at ingest time:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  content     — chunk text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  source      — source filename&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  chunk_index — position of this chunk within the document&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  metadata    — dict with char_start and total_chunks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;create_collection.py&lt;/code&gt; does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detects embedding size automatically by sending a sample text to Ollama, avoiding hardcoded vector dimensions&lt;/li&gt;
&lt;li&gt;Connects to VectorAI DB via gRPC and checks that the database server is running&lt;/li&gt;
&lt;li&gt;Checks for an existing &lt;code&gt;docs&lt;/code&gt; collection and exits if it already exists, making the script safe to rerun&lt;/li&gt;
&lt;li&gt;Creates the &lt;code&gt;docs&lt;/code&gt; collection only when it does not exist.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run this file by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run create_collection.py    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk9u4tjgk0nbcukcaqpfq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk9u4tjgk0nbcukcaqpfq.png" alt="Figure 4: Run create_collection.py" width="512" height="216"&gt;&lt;/a&gt;&lt;br&gt;
Figure 4: Run create_collection.py&lt;/p&gt;
&lt;h3&gt;
  
  
  Stage 4: Ingest a document corpus
&lt;/h3&gt;

&lt;p&gt;With the collection created, the next step is to fill it. The ingestion script reads every &lt;code&gt;.txt&lt;/code&gt; file in a local &lt;code&gt;docs/&lt;/code&gt;directory, splits each file into chunks, generates an embedding for each chunk using Ollama, and writes the result to VectorAI DB. No external API is called at any point in this process.&lt;br&gt;
Create a &lt;code&gt;docs/&lt;/code&gt; directory and add a file named &lt;code&gt;corpus.txt&lt;/code&gt; inside it with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Hydraulic Press Unit 7 — Maintenance Reference


Unit 7 is a 50-ton hydraulic press manufactured by Duratek in 2019.
Serial number: DT-7740-B. Located in Bay 3, Building 2.


Scheduled maintenance is every 90 days. Last service was completed on March 14, 2026 by technician R. Okafor.


Hydraulic fluid: ISO 46 mineral oil. Tank capacity is 12 liters.
Replace fluid every 180 days or if colour turns dark brown.


The main pump runs at 210 bar operating pressure. Maximum rated pressure is 250 bar.
If pressure drops below 180 bar during operation, inspect the pump seals.


Hydraulic coupling torque spec: 42 Nm ± 2 Nm. Use thread-lock grade 243 after torquing.


Known issue: the pressure relief valve on Unit 7 sticks occasionally at cold start.
Workaround is to run the press unloaded for 2 minutes before applying load.
Replacement valve part number: DT-PRV-114.


Emergency stop is the red panel on the left side of the frame.
Do not operate the press without the safety guard in place.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a file &lt;code&gt;ingest.py&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;


&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;actian_vectorai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PointStruct&lt;/span&gt;
&lt;span class="c1"&gt;# ── Config ─────────────────────────────────────────────────────────────────────
&lt;/span&gt;&lt;span class="n"&gt;VECTORAI_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost:6574&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;COLLECTION&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;OLLAMA_URL&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:11434/api/embeddings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;OLLAMA_MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemma2:2b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;DOCS_DIR&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;CHUNK_SIZE&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;    &lt;span class="c1"&gt;# characters per chunk
# ──────────────────────────────────────────────────────────────────────────────
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;OLLAMA_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OLLAMA_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embedding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;chunk_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;CHUNK_SIZE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;CHUNK_SIZE&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DOCS_DIR&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No .txt files found in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DOCS_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Create the folder and drop some .txt files in it, then re-run.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; file(s) in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DOCS_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VECTORAI_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="c1"&gt;# Confirm the collection is there before doing any work
&lt;/span&gt;       &lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;COLLECTION&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Collection &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;COLLECTION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; not found.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Run &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;python create_collection.py&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; first.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt;
       &lt;span class="n"&gt;total_chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
       &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;chunk_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
           &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ingesting &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; chunks)...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
               &lt;span class="n"&gt;vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                   &lt;span class="nc"&gt;PointStruct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                       &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
                       &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                       &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                           &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chunk_index&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metadata&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;char_start&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;CHUNK_SIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_chunks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                           &lt;span class="p"&gt;},&lt;/span&gt;
                       &lt;span class="p"&gt;},&lt;/span&gt;
                   &lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upsert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COLLECTION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="n"&gt;total_chunks&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  ✓ &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; chunks written&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="c1"&gt;# Final count from the DB
&lt;/span&gt;       &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COLLECTION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Done. &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total_chunks&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; chunks ingested this run.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Total points in &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;COLLECTION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ingest.py&lt;/code&gt; script is responsible for preparing documents for retrieval. It performs the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Loads documents from the configured source directory&lt;/li&gt;
&lt;li&gt;Splits each document into 400-character chunks to create focused passages that can be retrieved accurately&lt;/li&gt;
&lt;li&gt;Generates embeddings for each chunk by sending the text to Ollama's &lt;code&gt;/api/embeddings&lt;/code&gt; endpoint&lt;/li&gt;
&lt;li&gt;Builds a payload containing the chunk text and associated metadata, such as the document ID, chunk ID, and source information&lt;/li&gt;
&lt;li&gt;Stores the vector and payload in the vector database, allowing the chunks to be searched later using semantic similarity&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After ingestion is complete, every chunk is represented by both its embedding vector and its metadata. This enables the retrieval system to find the most relevant passages for a query and return the original text along with information about where it came from.&lt;/p&gt;

&lt;p&gt;Run the &lt;code&gt;ingest.py&lt;/code&gt; by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run ingest.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns the following results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftw6kbt6p10nrec8ha0i0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftw6kbt6p10nrec8ha0i0.png" alt="Figure 5: Run ingest.py" width="512" height="147"&gt;&lt;/a&gt;&lt;br&gt;
Figure 5: Run ingest.py&lt;/p&gt;
&lt;h2&gt;
  
  
  Building the Retrieval Loop
&lt;/h2&gt;

&lt;p&gt;The retrieval loop is the core of the system. It connects three local components into one flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user query input&lt;/li&gt;
&lt;li&gt;VectorAI DB for semantic retrieval&lt;/li&gt;
&lt;li&gt;Gemma 2B via Ollama for response generation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full pipeline runs entirely on-device and turns a raw question into a grounded answer using retrieved context.&lt;/p&gt;

&lt;p&gt;Create a file &lt;code&gt;query.py&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;actian_vectorai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VectorAIClient&lt;/span&gt;


&lt;span class="c1"&gt;# ── Config ─────────────────────────────────────────────────────────────────────
&lt;/span&gt;&lt;span class="n"&gt;VECTORAI_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost:6574&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;COLLECTION&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;OLLAMA_URL&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:11434&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;OLLAMA_MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemma2:2b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;TOP_K&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="c1"&gt;# ──────────────────────────────────────────────────────────────────────────────
&lt;/span&gt;



&lt;span class="c1"&gt;# Step 1: Accepts a user query
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Query: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


   &lt;span class="c1"&gt;# Step 2: Embed the query using the same model used at ingest time.
&lt;/span&gt;   &lt;span class="c1"&gt;# Using the same model is critical — the query vector must exist in the
&lt;/span&gt;   &lt;span class="c1"&gt;# same vector space as the stored chunk vectors for similarity to be meaningful.
&lt;/span&gt;   &lt;span class="n"&gt;query_vector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


   &lt;span class="c1"&gt;# Step 3: Search VectorAI DB for the top-k most similar chunks
&lt;/span&gt;   &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;VectorAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VECTORAI_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="n"&gt;COLLECTION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query_vector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TOP_K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="p"&gt;)&lt;/span&gt;


   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No results returned. Make sure you have run ingest.py first.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt;


   &lt;span class="c1"&gt;# Print retrieved chunks so retrieval is visible, not just implied
&lt;/span&gt;   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;── Retrieved &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; chunk(s) ───────────────────────────&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;context_parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
       &lt;span class="n"&gt;source&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;chunk&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chunk_index&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;] &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; / chunk &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  (score: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;context_parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;────────────────────────────────────────────────────&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


   &lt;span class="c1"&gt;# Step 4: Inject retrieved chunks into the prompt as context.
&lt;/span&gt;   &lt;span class="c1"&gt;# The model is explicitly told to use only the provided context.
&lt;/span&gt;   &lt;span class="c1"&gt;# This keeps the response grounded in the indexed documents and prevents
&lt;/span&gt;   &lt;span class="c1"&gt;# the model from drawing on its general training knowledge.
&lt;/span&gt;   &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context_parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a maintenance assistant. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use only the context below to answer the question. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;If the answer is not in the context, say so.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Context:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Question: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Answer:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;


   &lt;span class="c1"&gt;# Step 5: Call Gemma 2B via the Ollama API and return the response
&lt;/span&gt;   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Generating answer with Gemma 2B...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;OLLAMA_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/api/generate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OLLAMA_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Answer:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;




&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;OLLAMA_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/api/embeddings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OLLAMA_MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;embedding&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;




&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Usage: python query.py &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;your question here&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Accepts a user query&lt;/strong&gt;: The script starts by taking a question from the command line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Converts the query into an embedding&lt;/strong&gt;: The &lt;code&gt;embed()&lt;/code&gt; function sends the query to Ollama’s embeddings endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Searches VectorAI DB for relevant context&lt;/strong&gt;: The embedding is used to query the local vector database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prints retrieved chunks&lt;/strong&gt;: Before generating a response, the script prints the retrieved results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Builds a grounded prompt for Gemma 2B&lt;/strong&gt;: All retrieved chunks are merged into a single context block.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sends the prompt to Gemma 2B via Ollama&lt;/strong&gt;: The final step sends the structured prompt to the local model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Returns the final answer&lt;/strong&gt;: The response is extracted and printed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Test the end-to-end flow by running the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run query.py &lt;span class="s2"&gt;"what is the torque spec for the hydraulic coupling?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F91fh7rn2mfqgquvit0em.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F91fh7rn2mfqgquvit0em.png" alt="Figure 6: Building the retrieval loop&lt;br&gt;
" width="512" height="295"&gt;&lt;/a&gt;&lt;br&gt;
Figure 6: Building the retrieval loop&lt;/p&gt;

&lt;p&gt;From the output, you see that the model is no longer answering from its internal training data alone. Instead, it is explicitly grounded in the retrieved chunks printed from VectorAI DB before generation. Each response is tied to specific documents, which means you can trace every answer back to the source material.&lt;/p&gt;
&lt;h2&gt;
  
  
  Running Offline
&lt;/h2&gt;

&lt;p&gt;This is the final validation of the entire stack. At this point, both Gemma 2B and VectorAI DB are already installed, the corpus has been indexed, and the retrieval loop is working on a live connection. The next step is to prove that nothing in the runtime path depends on the internet.&lt;/p&gt;

&lt;p&gt;Disable your network interface by running the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;networksetup &lt;span class="nt"&gt;-setairportpower&lt;/span&gt; en0 off  &lt;span class="c"&gt;# for MacOs&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ip &lt;span class="nb"&gt;link set &lt;/span&gt;eth0 down  &lt;span class="c"&gt;# for Linux&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv run query.py &lt;span class="s2"&gt;"what is the serial number"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get the following results:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdzt225isyrfryh3w1a1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdzt225isyrfryh3w1a1o.png" alt="Figure 7: Verify offline execution" width="512" height="309"&gt;&lt;/a&gt;&lt;br&gt;
Figure 7: Verify offline execution&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;This system demonstrates that edge AI is no longer limited to isolated model inference. Gemma 2B handles local text generation efficiently on devices like the Jetson Orin Nano, while VectorAI DB provides a persistent semantic memory layer that runs on the same hardware. Together, they form a complete retrieval-augmented generation stack that operates without cloud services during runtime.&lt;/p&gt;

&lt;p&gt;After initial setup, the stack continues to function without network access. The model does not require external APIs, and the vector database does not depend on cloud infrastructure. This makes the architecture suitable for industrial environments, robotics systems, and field devices where connectivity is unreliable or restricted.&lt;/p&gt;

&lt;p&gt;Get started with &lt;a href="https://www.actian.com/databases/vectorai-db/community-edition/" rel="noopener noreferrer"&gt;Actian VectorAI DB Community Edition&lt;/a&gt; by signing up today. Check the &lt;a href="https://docs.vectoraidb.actian.com/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for deployment and usage instructions, and participate in the &lt;a href="https://discord.com/invite/432A2M63Py" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; community for support and discussions.&lt;/p&gt;

</description>
      <category>gemma</category>
      <category>vectoraidb</category>
    </item>
    <item>
      <title>Best Vector Databases for AI Agents in 2026</title>
      <dc:creator>Praise James</dc:creator>
      <pubDate>Thu, 09 Jul 2026 15:51:54 +0000</pubDate>
      <link>https://dev.to/actiandev/best-vector-databases-for-ai-agents-in-2026-1kfj</link>
      <guid>https://dev.to/actiandev/best-vector-databases-for-ai-agents-in-2026-1kfj</guid>
      <description>&lt;p&gt;Evaluating the best vector databases for AI agents in 2026 presents a different problem than it did a few years ago. Most vector databases are adequate in a Retrieval-Augmented Generation (RAG) demo. The decision comes down to fit: where the agent runs, what it needs to do, and how much write load the architecture generates.&lt;/p&gt;

&lt;p&gt;Two distinctions matter more than most comparison articles acknowledge. First, RAG retrieval and agent memory are different workloads. RAG systems primarily read from a vector store, while agent memory systems continuously write new observations back into it. Second, deployment constraints often eliminate options before performance becomes relevant. A cloud-managed database may perform well in benchmarks but fail a compliance review or data residency requirement.&lt;/p&gt;

&lt;p&gt;This article covers eight databases: &lt;a href="https://www.actian.com/blog/developer/is-actian-vectorai-db-the-best-on-premises-pinecone-alternative/" rel="noopener noreferrer"&gt;Pinecone&lt;/a&gt;, &lt;a href="https://www.actian.com/blog/developer/is-actian-vectorai-db-the-best-lightweight-milvus-alternative/" rel="noopener noreferrer"&gt;Milvus&lt;/a&gt;, Qdrant, Weaviate, &lt;a href="https://www.actian.com/blog/developer/is-actian-vectorai-db-the-best-production-chromadb-alternative/" rel="noopener noreferrer"&gt;Chroma&lt;/a&gt;, &lt;a href="https://www.actian.com/blog/developer/is-actian-vectorai-db-the-best-embedded-pgvector-alternative/" rel="noopener noreferrer"&gt;pgvector&lt;/a&gt;, &lt;a href="https://www.lancedb.com/" rel="noopener noreferrer"&gt;LanceDB&lt;/a&gt;, and &lt;a href="https://docs.vectoraidb.actian.com/home/quickstart/quickstart" rel="noopener noreferrer"&gt;Actian VectorAI DB&lt;/a&gt;. It opens with five evaluation criteria, works through the strengths and limitations of each database, maps each to either RAG retrieval or agent memory, and closes with a decision table.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Vector Database for AI Agents?
&lt;/h2&gt;

&lt;p&gt;A vector database stores embeddings, high-dimensional numerical representations of text, images, audio, and other unstructured data, and retrieves them through semantic similarity rather than exact keyword matching. To perform vector similarity search efficiently, vector databases use Approximate Nearest Neighbor (&lt;a href="https://www.geeksforgeeks.org/machine-learning/approximate-nearest-neighbor-ann-search/" rel="noopener noreferrer"&gt;ANN&lt;/a&gt;) algorithms such as Hierarchical Navigable Small World (&lt;a href="https://www.mongodb.com/resources/basics/hierarchical-navigable-small-world" rel="noopener noreferrer"&gt;HNSW&lt;/a&gt;) and Inverted File Index (IVF).&lt;/p&gt;

&lt;p&gt;Traditional relational databases match records by exact value. An AI agent searching for documents related to "equipment failure in cold conditions" will not retrieve a record titled "low-temperature motor fault" unless those exact words appear. A vector database returns semantically similar results regardless of surface wording. That retrieval quality gap is why agents need a dedicated vector store.&lt;/p&gt;

&lt;p&gt;AI agents use vector databases for two distinct purposes. The first is RAG, where the agent retrieves relevant documents before generating a response. The second is agent memory, where the agent continuously reads and writes information about previous interactions, observations, and task outcomes.&lt;/p&gt;

&lt;p&gt;A vector database does not replace Postgres or another transactional database. Most production distributed architectures store structured records, user metadata, and transactional data in a relational database, while using an AI-native vector database for semantic search, retrieval, and long-term memory operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Evaluate a Vector Database for AI Agents in 2026
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Query speed under load
&lt;/h3&gt;

&lt;p&gt;The fastest vector database benchmark is often the least useful metric for production agents. Static Queries Per Second (QPS) measurements assume a fixed index with no concurrent writes. Real agents continuously ingest documents, update memories, and create embeddings. Streaming ingestion performance at your target recall threshold is often a better production signal than peak benchmark numbers. The VectorDBBench leaderboard, maintained by Zilliz, updates the benchmark suite over time. Because Zilliz also develops Milvus, treat the leaderboard as directional guidance rather than a neutral ranking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write pattern support
&lt;/h3&gt;

&lt;p&gt;RAG retrieval is read-heavy. Agent memory is read-write, so every task completion can add write load. &lt;a href="https://zilliz.com/vdbbench-leaderboard?dataset=vectorSearch" rel="noopener noreferrer"&gt;VectorDBBench&lt;/a&gt; data shows how large this gap can be: Zilliz Cloud drops from 7,385 QPS static to 1,860 QPS with 1,000 rows per second of ingestion, a 75% reduction. Self-hosted Milvus 16c64g drops from 2,747 to 156 QPS under the same ingestion rate. Pinecone p2.x8 drops from 1,131 to 369 QPS under 500 rows-per-second ingestion. Static QPS and streaming ingestion QPS are not the same ranking. A database can look fast in one and fall behind in the other.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment model
&lt;/h3&gt;

&lt;p&gt;A cloud-managed vector database is not always an option for every team. Regulated industries (healthcare under HIPAA, finance under PCI DSS or SOC 2), government systems, and industrial edge deployments have structured data residency requirements that eliminate cloud-managed options entirely. Use three separate categories: cloud-only, self-hosted, and edge or air-gapped. Those deployment constraints determine which databases are relevant for a given team.&lt;/p&gt;

&lt;h3&gt;
  
  
  Operational overhead
&lt;/h3&gt;

&lt;p&gt;Infrastructure complexity influences long-term costs as much as software pricing. Running pgvector on an existing Postgres instance introduces little additional operational burden. Operating Milvus at scale often requires Kubernetes expertise and dedicated infrastructure support. Managed services reduce operational work but transfer that cost into subscription pricing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 8 Best Vector Databases for AI Agents in 2026
&lt;/h2&gt;

&lt;p&gt;The decision depends on three factors: where the agent runs, what it needs to do (retrieval, memory, or both), and how much operational complexity the team can support. Different modern vector databases optimize for different combinations of those requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. VectorAI DB
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.actian.com/blog/databases/how-to-evaluate-vector-databases-in-2026/" rel="noopener noreferrer"&gt;VectorAI DB&lt;/a&gt; targets environments where deployment constraints matter as much as retrieval performance. Rather than focusing solely on cloud-native workloads, it is designed to run across cloud, on-premises, edge, and air-gapped environments using the same deployment model.&lt;br&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Cloud, self-hosted, on-premises, edge, air-gapped environments&lt;br&gt;
&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regulated industries with strict data residency requirements&lt;/li&gt;
&lt;li&gt;Industrial and manufacturing edge AI deployments&lt;/li&gt;
&lt;li&gt;Teams that need a consistent deployment model across cloud and disconnected environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Closed-source engine&lt;/li&gt;
&lt;li&gt;Smaller ecosystem than more established vector databases&lt;/li&gt;
&lt;li&gt;SDK support is limited to Python and JavaScript at launch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a newer entrant, &lt;a href="https://docs.vectoraidb.actian.com/home/quickstart/quickstart" rel="noopener noreferrer"&gt;VectorAI DB&lt;/a&gt; is still expanding its ecosystem, integrations, and platform capabilities. The product roadmap is developing rapidly, with new features and improvements released regularly.&lt;/p&gt;

&lt;p&gt;The primary differentiator is deployment flexibility. The same Docker image can run in cloud environments, on-premises infrastructure, NVIDIA Jetson devices, and fully air-gapped networks without requiring different operational models for each environment.&lt;/p&gt;

&lt;p&gt;For teams building AI agents in regulated environments, industrial settings, or locations where cloud connectivity is unavailable or restricted, deployment requirements may eliminate many alternatives before benchmark comparisons begin.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. pgvector
&lt;/h3&gt;

&lt;p&gt;pgvector extends Postgres with vector search capabilities and remains the default choice for teams already invested in the Postgres ecosystem.&lt;br&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Self-hosted Postgres&lt;br&gt;
&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent memory workloads are tightly coupled with relational data&lt;/li&gt;
&lt;li&gt;Teams operating below 10 million vectors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large vector workloads increase storage overhead and memory pressure&lt;/li&gt;
&lt;li&gt;Scaling requires Postgres expertise rather than dedicated vector infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The strongest argument for pgvector is architectural simplicity. Instead of introducing another database, teams can keep vector search alongside transactional relational data. This approach works particularly well for agents that need frequent joins between memories, user records, and application state.&lt;/p&gt;

&lt;p&gt;An independent benchmark from &lt;a href="https://www.steezr.com/en/blog/pgvector-08-vs-dedicated-vector-db-when-postgres-is-enough" rel="noopener noreferrer"&gt;Steezr&lt;/a&gt; found pgvector 0.8.0 HNSW performance comparable to Qdrant 1.13 at a 1M vector scale on AWS c6i.2xlarge hardware. That result suggests some teams can stay on pgvector longer before moving to a dedicated vector database.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Qdrant
&lt;/h3&gt;

&lt;p&gt;Qdrant balances retrieval performance, deployment flexibility, and support for memory-heavy workloads.&lt;br&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Cloud, self-hosted, Kubernetes&lt;br&gt;
&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent memory systems with frequent updates&lt;/li&gt;
&lt;li&gt;Hybrid search workloads that combine semantic and keyword retrieval&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vector dimensions remain fixed after collection creation&lt;/li&gt;
&lt;li&gt;Payload indexes require deliberate planning and configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Qdrant's strength lies in versatility. Teams can begin with self-hosted deployments and later adopt managed offerings without changing databases. Its support for metadata filtering, hybrid search capabilities, and memory-oriented workloads has made it a common choice for production AI systems.&lt;/p&gt;

&lt;p&gt;A vendor-funded three-week production evaluation by &lt;a href="https://particula.tech/blog/pinecone-vs-qdrant-comparison" rel="noopener noreferrer"&gt;Particula&lt;/a&gt; measured Qdrant at 22ms p95 latency on a 10-million-vector workload, compared with 45ms for Pinecone. Engineers should treat the result as directional rather than definitive, as the comparison was not conducted independently.&lt;/p&gt;

&lt;p&gt;For teams that need both operational flexibility and solid performance, Qdrant is a good fit.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Pinecone
&lt;/h3&gt;

&lt;p&gt;Pinecone targets teams that prefer managed infrastructure and are willing to pay for operational simplicity.&lt;br&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Cloud-managed&lt;br&gt;
&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Organizations with limited DevOps capacity&lt;/li&gt;
&lt;li&gt;Teams that prioritize managed operations over infrastructure control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No self-hosting option&lt;/li&gt;
&lt;li&gt;Costs can increase significantly under large-scale ingestion and retrieval workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.g2.com/products/pinecone/reviews" rel="noopener noreferrer"&gt;Pinecone&lt;/a&gt; offloads infrastructure management, scaling, and maintenance to the provider. It fits teams that want managed operations and are comfortable trading off self-hosting control.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Weaviate
&lt;/h3&gt;

&lt;p&gt;Weaviate is positioned for agentic retrieval workflows and coding-agent integrations.&lt;br&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Cloud and self-hosted&lt;br&gt;
&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agentic retrieval workflows&lt;/li&gt;
&lt;li&gt;Coding agents and multi-step reasoning systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More operational complexity than managed platforms&lt;/li&gt;
&lt;li&gt;Kubernetes expertise is often required for larger deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Weaviate differentiates itself through &lt;a href="https://www.globenewswire.com/news-release/2026/02/21/3242244/0/en/Weaviate-Launches-Agent-Skills-to-Empower-AI-Coding-Agents.html" rel="noopener noreferrer"&gt;agent-native capabilities&lt;/a&gt; rather than raw vector search performance. Its Query Agent reached general availability in 2025, and Agent Skills launched in 2026 with integrations targeting Claude Code, Cursor, GitHub Copilot, VS Code, and Gemini CLI.&lt;/p&gt;

&lt;p&gt;These key features position Weaviate as more than a storage layer. It increasingly functions as infrastructure for agent orchestration and retrieval workflows.&lt;/p&gt;

&lt;p&gt;Teams building sophisticated agent ecosystems may find Weaviate's agent tooling more compelling than benchmark advantages measured in milliseconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Milvus
&lt;/h3&gt;

&lt;p&gt;Milvus targets teams that need to search billions of vectors across distributed infrastructure. It is a strong fit when scale matters more than operational simplicity.&lt;br&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Self-hosted Kubernetes, managed through Zilliz Cloud.&lt;br&gt;
&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-billion vector workloads&lt;/li&gt;
&lt;li&gt;Multimodal agents that combine text, image, audio, and video embeddings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Significant operational complexity&lt;/li&gt;
&lt;li&gt;Requires immediate patching of critical vulnerabilities such as CVE-2026-26190 on affected versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Milvus 2.6 also introduced &lt;a href="https://zilliz.com/vdbbench-leaderboard?dataset=vectorSearch" rel="noopener noreferrer"&gt;RaBitQ quantization&lt;/a&gt;, which claims a 72% memory reduction and 4× faster queries at approximately 95% recall. These figures come from Milvus and should be treated as vendor-published benchmarks.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Chroma
&lt;/h3&gt;

&lt;p&gt;Chroma is a local-first option for quickly getting a prototype agent running. Most developers can move from installation to retrieval in minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment&lt;/strong&gt;: Local-first, single-node&lt;br&gt;
&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prototyping&lt;/li&gt;
&lt;li&gt;Personal AI assistants&lt;/li&gt;
&lt;li&gt;Local development environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited production scalability&lt;/li&gt;
&lt;li&gt;Weak concurrency handling at larger vector counts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The challenge appears when prototypes become products. A commonly cited practitioner report described Chroma performing well during development but becoming unusable at roughly &lt;a href="https://www.jahanzaib.ai/blog/vector-database-ai-agents-pinecone-weaviate-chroma-qdrant" rel="noopener noreferrer"&gt;two million vectors&lt;/a&gt; with 12 concurrent users. In that practitioner report, the team said latency dropped from about 800 ms to 28 ms after migrating to Qdrant under the same workload.&lt;/p&gt;

&lt;p&gt;For developers looking to validate an idea before committing to infrastructure, Chroma is a practical starting point. For production systems with sustained concurrency or larger vector counts, it is usually a poor fit.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. LanceDB
&lt;/h3&gt;

&lt;p&gt;LanceDB focuses on embedded AI applications. Rather than running a separate database service, developers can package retrieval directly into local applications.&lt;br&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Embedded database, local-first&lt;br&gt;
&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Desktop AI applications&lt;/li&gt;
&lt;li&gt;IDE extensions&lt;/li&gt;
&lt;li&gt;Offline assistants&lt;/li&gt;
&lt;li&gt;Multimodal agent workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No built-in multi-tenant access controls&lt;/li&gt;
&lt;li&gt;Shorter production history than established alternatives&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One notable adoption example comes from &lt;a href="https://www.lancedb.com/blog/ai-native-development-local-continue-lancedb" rel="noopener noreferrer"&gt;Continue&lt;/a&gt;, the open-source coding assistant. Continue selected LanceDB because it offered an embedded TypeScript library with fast on-disk retrieval and SQL-style filtering.&lt;/p&gt;

&lt;p&gt;That design makes LanceDB particularly attractive when the agent runs on the user's machine rather than inside a centralized cloud platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  RAG Retrieval vs. Agent Memory: Which Database Fits Which Use Case?
&lt;/h2&gt;

&lt;p&gt;The distinction matters because most evaluation articles treat RAG and agent memory as the same workload, and they are not.&lt;/p&gt;

&lt;p&gt;RAG retrieval is read-heavy. Documents are ingested once and queried repeatedly. Freshness matters, but writes happen relatively infrequently.&lt;br&gt;
Agent memory is read-write at runtime. Agents retrieve previous memories, generate new observations, and immediately write those observations back into storage. Freshness becomes a core requirement.&lt;/p&gt;

&lt;h3&gt;
  
  
  RAG-optimized databases
&lt;/h3&gt;

&lt;p&gt;These databases excel when retrieval dominates writes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pinecone&lt;/li&gt;
&lt;li&gt;Milvus&lt;/li&gt;
&lt;li&gt;pgvector (especially under 10M vectors)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They perform best when agents search document collections rather than constantly updating memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory-optimized databases
&lt;/h3&gt;

&lt;p&gt;These databases handle continuous writes more effectively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qdrant&lt;/li&gt;
&lt;li&gt;Weaviate&lt;/li&gt;
&lt;li&gt;LanceDB&lt;/li&gt;
&lt;li&gt;Actian VectorAI DB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They fit agents that update memory after every interaction, workflow, or task completion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Both (with caveats)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;pgvector works well below about five million vectors when transactional consistency matters.&lt;/li&gt;
&lt;li&gt;Chroma works well during development and prototyping, but is not a long-term production memory layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One additional consideration is memory freshness. &lt;a href="https://github.blog/ai-and-ml/github-copilot/building-an-agentic-memory-system-for-github-copilot/[](url)" rel="noopener noreferrer"&gt;GitHub's engineering&lt;/a&gt; team reported using a 28-day auto-expiry policy and repository-scoped memories in GitHub Copilot. That example shows why retention rules matter: stale memories create more risk than missing memories. Any production memory architecture should define retention and expiration policies before optimizing retrieval performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision Table
&lt;/h2&gt;

&lt;p&gt;This table summarizes the fastest way to narrow your shortlist by workload, deployment, and write pattern.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Database&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Deployment&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Hybrid search&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Open source / Free&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Skip if&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pgvector&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Self-hosted (Postgres)&lt;/td&gt;
&lt;td&gt;Agent memory with relational data&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;You need sustained billion-scale growth, or can't tolerate Postgres operational overhead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Qdrant&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloud, Self-hosted&lt;/td&gt;
&lt;td&gt;Balanced retrieval and memory workloads&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;You need a fully air-gapped managed experience&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pinecone&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloud&lt;/td&gt;
&lt;td&gt;Zero-ops vector search&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Data residency or write-heavy workloads matter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Weaviate&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloud, Self-hosted&lt;/td&gt;
&lt;td&gt;Agent-native retrieval pipelines&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Your team lacks Kubernetes expertise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Milvus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Self-hosted, Managed&lt;/td&gt;
&lt;td&gt;Billion-scale search&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Your team cannot operate a distributed infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Chroma&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Local&lt;/td&gt;
&lt;td&gt;Rapid prototyping&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;You expect production concurrency at scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LanceDB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Embedded&lt;/td&gt;
&lt;td&gt;Local and on-device agents&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;You need multi-tenant enterprise controls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VectorAI DB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cloud, on-premises, edge, air-gapped&lt;/td&gt;
&lt;td&gt;Regulated and disconnected deployments&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Your deployment is cloud-native, and air-gap support is irrelevant&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;The best vector database for AI agents in 2026 depends more on workload characteristics than features.&lt;/p&gt;

&lt;p&gt;If your team already runs Postgres and expects fewer than 10 million vectors, start with pgvector. If you want managed infrastructure, evaluate Pinecone first and compare it with self-hosted Qdrant before committing to the cost-efficiency model.&lt;/p&gt;

&lt;p&gt;If your agent runs in a regulated environment, on industrial hardware, or without guaranteed cloud connectivity, &lt;a href="https://www.actian.com/blog/databases/how-to-evaluate-vector-databases-in-2026/" rel="noopener noreferrer"&gt;VectorAI DB&lt;/a&gt; is the only mainstream 2026 database built specifically for that constraint.&lt;/p&gt;

</description>
      <category>vectordatabase</category>
      <category>aiagents</category>
    </item>
    <item>
      <title>5 Edge AI Architecture Patterns for Disconnected Environments</title>
      <dc:creator>Praise James</dc:creator>
      <pubDate>Mon, 18 May 2026 11:05:16 +0000</pubDate>
      <link>https://dev.to/actiandev/5-edge-ai-architecture-patterns-for-disconnected-environments-27of</link>
      <guid>https://dev.to/actiandev/5-edge-ai-architecture-patterns-for-disconnected-environments-27of</guid>
      <description>&lt;p&gt;A haul truck operating 200 miles from the nearest cellular tower does not pause when connectivity drops. An offshore wind turbine does not suspend fault detection because a satellite link fails in a storm. In these environments, inference, control loops, and safety systems must continue operating regardless of network status. Yet the dominant edge AI architecture still revolves around connectivity and cloud AI.&lt;/p&gt;

&lt;p&gt;Disconnected environments demand edge-native, offline-first architectures designed for operational autonomy. Market signals reinforce this reality.&lt;/p&gt;

&lt;p&gt;ABI Research projects &lt;a href="https://www.abiresearch.com/press/edge-server-spending-to-reach-us19-billion-by-2027-enabling-integration-of-edge-based-solutions-as-part-of-edge-to-cloud-orchestration-strategy" rel="noopener noreferrer"&gt;edge server spending&lt;/a&gt; to reach $19B by 2027, with on-premises deployments accounting for nearly $10.5B. In 2025, organizations deployed &lt;a href="https://www.vpnranks.com/resources/edge-computing-statistics/" rel="noopener noreferrer"&gt;approximately 815 million&lt;/a&gt; edge-enabled IoT devices globally.&lt;/p&gt;

&lt;p&gt;Most operational environments are inherently distributed, generating data far from centralized cloud systems. Edge deployment strategies that depend on sending that data back and forth for processing cause IoT systems to miss critical insights, increase latency, and introduce data loss. Yet proposed edge architectures still treat offline readiness as an add-on rather than the default.&lt;/p&gt;

&lt;p&gt;We present five edge AI deployment patterns that operate without assumed connectivity, covering their implementation tactics, real-world scenarios, trade-offs, and a decision framework for selecting the right pattern for your operational priorities.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Suitable use cases for each documented deployment pattern at a glance.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The drone (self-contained single-node edge AI)&lt;/td&gt;
&lt;td&gt;Autonomous mobile systems with strict energy budgets and zero cloud connection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The factory (multi-node edge AI with optional cloud)&lt;/td&gt;
&lt;td&gt;Facilities with local infrastructure in intermittent environments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hierarchical federated learning (client-edge-cloud)&lt;/td&gt;
&lt;td&gt;Privacy-sensitive distributed operations where data leakage risks are unacceptable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Store-and-forward disconnected inference&lt;/td&gt;
&lt;td&gt;Operations with scheduled connectivity windows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The network (distributed edge-to-edge fabric)&lt;/td&gt;
&lt;td&gt;Distributed coordination without cloud dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why Disconnected Environments are an Edge AI Problem
&lt;/h2&gt;

&lt;p&gt;There is a structural blind spot for disconnected environments, driven by the assumption that industries using edge AI models are cloud-centric and operate under persistent connectivity. Where edge AI applications matter most, constant network access does not exist.&lt;/p&gt;

&lt;h3&gt;
  
  
  What disconnected actually means
&lt;/h3&gt;

&lt;p&gt;Disconnected environments are settings with unreliable or nonexistent connectivity, ranging from airgapped scenarios with complete network isolation to intermittent setups with frequent connectivity degradation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n9z1nrhyfrupmvoogjq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4n9z1nrhyfrupmvoogjq.png" alt="Figure 1: Connectivity spectrum" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In these operational settings, edge AI capabilities truly shine because they support the real-time data processing, low latency, bandwidth optimization, and data governance that disconnected environments require.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.precedenceresearch.com/edge-ai-market" rel="noopener noreferrer"&gt;Precedence Research&lt;/a&gt; estimates the global edge AI market will reach $143B by 2034, a potential 472% increase from $25B in 2025. For a significant portion of this market, constant cloud connectivity is not feasible. Yet inference, local data storage, and real-time decision-making must continue regardless of network status or location.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disconnection is where edge AI earns its value
&lt;/h3&gt;

&lt;p&gt;Disconnected environments such as mining sites, manufacturing plants, military operations, offshore wind farms, and smart cities expose the limitations of current edge AI deployment solutions.&lt;/p&gt;

&lt;p&gt;Rio Tinto operates on mining sites up to &lt;a href="https://www.bbc.com/news/articles/cgej7gzg8l0o[](url)" rel="noopener noreferrer"&gt;930 miles&lt;/a&gt; from cellular coverage, where operators cannot rely on a centralized infrastructure. They need autonomous inspection robots that use edge AI to track personnel and vehicles, interpreting data from 3D LiDAR, thermal imaging, and gas sensors in real-time.&lt;/p&gt;

&lt;p&gt;At least &lt;a href="https://www.alcircle.com/news/rio-tinto-welcomes-300th-komatsu-autonomous-haulage-truck-at-pilbara-operations-wa-111740#:~:text=%E2%80%9CThe%20AHS%20fleet%20at%20Rio,Tinto%20takes%20with%20its%20suppliers.%22" rel="noopener noreferrer"&gt;300 autonomous haul trucks&lt;/a&gt; operate in Rio Tinto’s Pilbara region. Each truck processes roughly 5TB of data daily through subterranean tunnels with limited connectivity, requiring &lt;a href="https://www.rcrwireless.com/20180710/network-infrastructure/four-private-lte-use-cases#:~:text=According%20to%20a%20Qualcomm%20white%20paper%20on,and%20related%20facilities%20including%20transportation%20hubs%20and" rel="noopener noreferrer"&gt;private LTE networks&lt;/a&gt; for on-device IoT processing.&lt;/p&gt;

&lt;p&gt;Offshore wind farms face a similar constraint. Turbines and inspection vessels go offline when satellite connections fail due to harsh weather or line-of-sight blockage, and each turbine averages &lt;a href="https://www.groundcontrol.com/blog/wireless-connectivity-for-offshore-wind-farms/" rel="noopener noreferrer"&gt;approximately 8.3 failures per year&lt;/a&gt;. These farms need edge AI systems that detect issues early, monitor real-time maritime traffic, analyze local SCADA data, and trigger inspections based on immediate wind conditions.&lt;/p&gt;

&lt;p&gt;In remote manufacturing environments, plant managers also need edge AI to automate quality inspections, predict machine failures, and protect workforce health.&lt;/p&gt;

&lt;p&gt;A similar demand for local, secure processing drives military operations, where systems operate within airgapped networks in denied, disrupted, intermittent, and limited (DDIL) environments to maintain data confidentiality and integrity. Soldiers must communicate with command units and analyze real-time warfare data without relying on cloud data centers or large computing resources.&lt;/p&gt;

&lt;p&gt;These are the environments where edge AI deployment delivers the most impact. According to Dell, enterprise data processing will shift to &lt;a href="https://www.dell.com/en-us/blog/the-power-of-small-edge-ai-predictions-for-2026/" rel="noopener noreferrer"&gt;distributed data centers&lt;/a&gt; in 2026, but most documented architectures still emphasize transmitting data back to cloud data centers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Constrained hardware shapes model deployment
&lt;/h3&gt;

&lt;p&gt;The demands of AI compute and workload scaling at the edge also fuel the cloud-edge deployment recommendations.&lt;/p&gt;

&lt;p&gt;A deep learning model with &lt;a href="https://localaimaster.com/blog/ram-requirements-local-ai" rel="noopener noreferrer"&gt;3B parameters can require up to 4GB of RAM&lt;/a&gt;, but edge devices like microcontrollers and IoT sensors typically have &lt;a href="https://promwad.com/news/best-microcontrollers-low-power-iot-2025" rel="noopener noreferrer"&gt;less than 1GB&lt;/a&gt; for OS, workloads, and storage combined. Connected environment architectures assume large compute availability that doesn’t exist at the edge.&lt;/p&gt;

&lt;p&gt;Edge AI architectures must start with offline-first assumptions and hardware ceilings from day one. Retrofitting offline capability into cloud systems will not compensate for connectivity gaps and limited hardware resources. Below, we detail five architectural patterns tailored for disconnected environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 1: The Drone (Self-Contained Single-Node Edge AI)
&lt;/h2&gt;

&lt;p&gt;In environments where connectivity is unavailable, and operational latency cannot tolerate network round-trips, the deployment boundary collapses to a single device. Inference cannot be delegated, synchronized, or deferred. Edge devices like drones, underwater vehicles, and remote inspection robots must make decisions using only locally available compute, memory, and sensor input.&lt;/p&gt;

&lt;p&gt;This constraint defines the drone architecture. All AI logic runs on a single device, without external orchestration or cloud offloading.&lt;/p&gt;

&lt;h3&gt;
  
  
  When the device is the entire stack
&lt;/h3&gt;

&lt;p&gt;Mobile systems that must function autonomously in disconnected environments benefit most from this pattern.&lt;/p&gt;

&lt;p&gt;With no external orchestration layer, data capturing, preprocessing, inference, storage, and control logic operate within a self-contained package. This package runs on a single node without networking with other nodes or distributing model training.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvk0484awih8oozg6fmxf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvk0484awih8oozg6fmxf.png" alt="Figure 2: Single-node drone architecture" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Onboard decision logic means edge devices can execute predefined operations even when disconnected. Once a device captures data, it filters out redundant information, retaining only relevant data for eventual manual retrieval.&lt;/p&gt;

&lt;p&gt;Autonomous drones that perform object detection and terrain classification in mining zones cannot pause execution while awaiting external inference. The drone architecture removes network dependency by focusing on on-device inference.&lt;/p&gt;

&lt;p&gt;This makes it the most viable pattern for DDIL environments where connectivity is actively denied or degraded. Defense drones cannot assume that the network will recover or that a command signal will arrive at all. Every battlefield coordination must be executable from the device alone.&lt;/p&gt;

&lt;p&gt;GE Aerospace, which runs &lt;a href="https://www.geaerospace.com/news/press-releases/ge-aerospace-deploys-ai-driven-inspection-tool-maximize-narrowbody-engine-time-wing?utm_source=perplexity" rel="noopener noreferrer"&gt;45,000+ commercial aircraft engines&lt;/a&gt; and captures over &lt;a href="https://www.genpact.com/case-studies/soaring-toward-safer-skies-with-remote-engine-monitoring?utm_source=perplexity" rel="noopener noreferrer"&gt;480,000 data snapshots daily per aircraft&lt;/a&gt;, implements this architecture at scale. Onboard AI models handle predictive maintenance in strict accordance with DO-178C, which requires GE Aerospace to verify every airborne system against all possible failure conditions before it ever leaves the ground. This quality assurance aligns with the drone’s architectural requirement of no external support after model deployment.&lt;/p&gt;

&lt;p&gt;Single-node local processing requires machine learning models with small footprints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimizing intelligence for the edge
&lt;/h3&gt;

&lt;p&gt;Edge devices operate within strict memory and power ceilings measured in megabytes and milliwatts. When full-precision networks exceed available RAM or energy budgets, model capacity must be optimized before inference becomes feasible.&lt;/p&gt;

&lt;p&gt;Not every edge workload needs a neural network. In constrained environments like offshore wind farms, classical statistical methods, such as &lt;a href="https://medium.com/@aausafq/draft-rethinking-ai-for-the-edge-63c073dee59a" rel="noopener noreferrer"&gt;Welford’s algorithm and linear regression often outperform neural networks&lt;/a&gt; on streaming data processing.&lt;/p&gt;

&lt;p&gt;A microcontroller computing sensor data with Welford’s algorithm updates statistics sequentially, without retaining past data points, which keeps memory and power consumption low. Before pushing a neural network to its hardware limit, consider whether the model class itself is suitable for the use case.&lt;/p&gt;

&lt;p&gt;When neural networks are the right fit for the workload, quantization addresses their hardware limitations by reducing the numerical precision of their weights, biases, and activations. Downsizing from 32-bit to 8-bit shrinks model size &lt;a href="https://www.edge-ai-vision.com/2024/02/quantization-of-convolutional-neural-networks-model-quantization/" rel="noopener noreferrer"&gt;by approximately 75%&lt;/a&gt; with less than 1% accuracy loss.&lt;/p&gt;

&lt;p&gt;Another model compression technique, pruning, eliminates redundant parameters that contribute minimally to output accuracy. Pruning an object detection model like YOLOv5 can reduce its parameter count and &lt;a href="https://dl.acm.org/doi/10.1145/3762329.3762371" rel="noopener noreferrer"&gt;computational cost by 40%&lt;/a&gt; before deployment.&lt;/p&gt;

&lt;p&gt;TinyML frameworks such as TensorFlow Lite for Microcontrollers, ONNX Runtime, and PyTorch Mobile support compact model deployment. The following code shows an example quantization scenario with TensorFlow Lite.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tensorflow&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="c1"&gt;# Post-training quantization using TFLite converter
# Converts 32-bit floats to 8-bit integers
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;representative_dataset&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;

&lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TFLiteConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_saved_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saved_model_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optimizations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Optimize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEFAULT&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;representative_dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;representative_dataset&lt;/span&gt;

&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;target_spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;supported_ops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OpsSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TFLITE_BUILTINS_INT8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inference_input_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int8&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inference_output_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int8&lt;/span&gt;

&lt;span class="n"&gt;tflite_quant_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start with quantization for higher speedup rates without significant accuracy loss, followed by pruning to compress the model’s size further. For the drone architecture, the target size on a single microcontroller is &amp;lt;1MB. Plumerai’s person detection model demonstrates how compression techniques can achieve this goal. The model achieved &lt;a href="https://blog.plumerai.com/2021/12/datacenter-ai-on-mcu/" rel="noopener noreferrer"&gt;737KB on an ARM Cortex-M7&lt;/a&gt; microcontroller with less than 256KB of on-chip RAM using binarized neural networks.&lt;/p&gt;

&lt;p&gt;At the hardware level, energy-efficient processors such as the NVIDIA Jetson Nano, Google Edge TPU, and ARM Cortex-M execute AI models directly on edge devices, purpose-built for computer vision and sensor fusion workloads. ARM Cortex-M variants deliver up to &lt;a href="https://www.digikey.com/en/articles/how-and-why-microcontrollers-can-help-democratize-access-to-edge-ai#:~:text=Machine%20learning%20applications%20running%20on,and%20hardware%20components%20for%20inferencing" rel="noopener noreferrer"&gt;600 giga-operations per second (GOPS) with an energy efficiency averaging 3 tera-operations per second per watt (TOPS/W)&lt;/a&gt;, depending on configuration.&lt;/p&gt;

&lt;p&gt;Drone deployment introduces an architectural rigidity. With limited runtime intervention, the architecture must anticipate every failure state during design. The DO-178C reinforces this constraint by requiring full system validation before deployment. Teams must engineer every model update and behavioral correction with no orchestration window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 2: The Factory (Multi-Node Edge AI With Optional Cloud)
&lt;/h2&gt;

&lt;p&gt;During network outages in manufacturing and large retail facilities, inference must continue in-house across multiple machines. The factory architecture meets this requirement by distributing AI workloads across on-premises edge clusters, keeping operational control within the facility boundary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.actian.com/blog/data-management/sync-your-data-from-edge-to-cloud-with-actian-zen-easysync/" rel="noopener noreferrer"&gt;Cloud synchronization&lt;/a&gt; remains optional, used only for model retraining or batch analytics rather than as a runtime dependency. The priority is maintaining resilience and operational independence across all nodes, regardless of network availability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inference stays on the factory floor
&lt;/h3&gt;

&lt;p&gt;The factory architecture centers on three components: edge gateways, compute nodes, and local storage.&lt;/p&gt;

&lt;p&gt;An edge gateway routes sensor requests to edge nodes, which pull context from local edge databases like &lt;a href="https://www.actian.com/databases/zen/" rel="noopener noreferrer"&gt;Actian Zen&lt;/a&gt;, act on model inference, and write the results back to the database. Decision-making and local computing stays on-premises. Cloud systems only handle model updates periodically or on trigger.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgux0vgy4ep4eqgc4k8tq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgux0vgy4ep4eqgc4k8tq.png" alt="Figure 3: The factory architecture" width="800" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Industrial environments generate continuous, high-volume telemetry data from sensors, controllers, and inspection systems. Distributing inference across multiple edge nodes maintains high inference throughput. But without a local orchestration layer managing distribution and managing model lifecycle, edge nodes operate as isolated processors rather than a coordinated system.&lt;/p&gt;

&lt;p&gt;K3s, AWS IoT Greengrass, Azure IoT Edge, and Siemens Industrial Edge are popular orchestration tools for managing edge clusters. Each differs in how they handle model deployment and node management.&lt;/p&gt;

&lt;p&gt;K3s deploys containerized models as clusters of worker nodes with a control plane for health visibility. Configuring its datastore endpoint parameter enables teams to store local data in on-premises databases like PostgreSQL and Actian Zen, replacing the default SQLite. &lt;a href="https://dok.community/blog/persistence-at-the-edge/" rel="noopener noreferrer"&gt;Chick-fil-A&lt;/a&gt; uses K3s at the edge to process point-of-sale transactions across 3,000+ restaurants.&lt;/p&gt;

&lt;p&gt;AWS IoT Greengrass deploys cloud-compiled AI models as components with predefined inference functions to &lt;a href="https://aws.amazon.com/blogs/aws/new-machine-learning-inference-at-the-edge-using-aws-greengrass/#:~:text=Industrial%20Maintenance%20%E2%80%93%20Smart%2C%20local%20monitoring,predict%20failures%2C%20detect%20faulty%20equipment.&amp;amp;text=There%20are%20several%20different%20aspects,with%20a%20couple%20of%20clicks:" rel="noopener noreferrer"&gt;NVIDIA Jetson TX2, Intel Atom boards, and Raspberry Pi-powered devices&lt;/a&gt;. Inference remains on-premises, with data exported optionally to AWS IoT Core for model optimization. Pfizer manufacturing sites use &lt;a href="https://aws.amazon.com/blogs/industries/pfizer-boosts-bioreactor-efficiency-with-aws-industrial-edge-services/" rel="noopener noreferrer"&gt;AWS IoT Greengrass&lt;/a&gt; for near-real-time bioreactor monitoring to minimize contamination risk.&lt;/p&gt;

&lt;p&gt;Siemens Industrial Edge deploys Docker-containerized models directly on the shop floor, delivering &lt;a href="https://blog.siemens.com/2024/05/enhancing-productivity-with-siemens-industrial-edge/" rel="noopener noreferrer"&gt;real-time machine status&lt;/a&gt;. Siemens Electronics Factory Erlangen &lt;a href="https://aws.amazon.com/partners/success/siemens-electronics-factory-erlangen-siemens/" rel="noopener noreferrer"&gt;reduced model deployment time by 80% and false anomaly detection on printed circuit boards (PCBs) by 50%&lt;/a&gt; using this orchestrator. By running inference on PCB images locally and outsourcing only model retraining to the cloud, the factory has saved data storage costs by 90%.&lt;/p&gt;

&lt;p&gt;Azure IoT Edge uses a JSON deployment manifest to specify which containerized models to download to edge devices. Data processing happens at the edge with Azure IoT Hub providing centralized oversight while the devices maintain autonomy. &lt;a href="https://www.microsoft.com/en/customers/story/1601901070675086388-thomas-concrete-group-discrete-manufacturing-azure-en-united-states" rel="noopener noreferrer"&gt;Thomas Concrete Group&lt;/a&gt; uses Azure IoT Edge to collect data from sensors embedded in wet concrete, estimate the concrete’s hardening timeline, and send predictions to Azure IoT Hub.&lt;/p&gt;

&lt;p&gt;The table below highlights the differences between each orchestrator.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criteria&lt;/th&gt;
&lt;th&gt;K3s&lt;/th&gt;
&lt;th&gt;Azure IoT Edge&lt;/th&gt;
&lt;th&gt;AWS IoT Greengrass&lt;/th&gt;
&lt;th&gt;Siemens Industrial Edge&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Node management&lt;/td&gt;
&lt;td&gt;Manages nodes via a lightweight control plane&lt;/td&gt;
&lt;td&gt;Manages nodes remotely through Azure IoT Hub&lt;/td&gt;
&lt;td&gt;Manages nodes via AWS IoT Core&lt;/td&gt;
&lt;td&gt;Manages nodes via the Siemens Industrial Edge Management platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model deployment&lt;/td&gt;
&lt;td&gt;Deploys models as Kubernetes pods using standard container images&lt;/td&gt;
&lt;td&gt;Configures deployments via a JSON manifest that defines which modules, containing the trained models, run on which nodes&lt;/td&gt;
&lt;td&gt;Deploys models as components with predefined inference functions&lt;/td&gt;
&lt;td&gt;Deploys models directly on shop floors as Docker containers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud integration&lt;/td&gt;
&lt;td&gt;Can be integrated with a central infrastructure&lt;/td&gt;
&lt;td&gt;Supported via Azure IoT Hub&lt;/td&gt;
&lt;td&gt;Integrates with AWS IoT Core&lt;/td&gt;
&lt;td&gt;Supports integration with AWS services&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  When the OT network is the security boundary
&lt;/h3&gt;

&lt;p&gt;Industrial companies converge their IT and operational technology (OT) networks to support on-premises AI and IoT integrations. But this convergence expands their attack surface area. &lt;a href="https://zeronetworks.com/blog/ot-security-trends-2025-escalating-threats-evolving-tactics" rel="noopener noreferrer"&gt;75% of OT attacks&lt;/a&gt; originate in IT environments, and &lt;a href="https://techinformed.com/manufacturers-face-losses-up-to-2m-cyberattack/" rel="noopener noreferrer"&gt;80% of manufacturers&lt;/a&gt; report increasing security threats across their IT/OT networks.&lt;/p&gt;

&lt;p&gt;For teams considering factory deployment for industrial systems, network segmentation must become a top priority. Edge AI solutions should operate solely within the OT network in compliance with the Purdue model. Sensitive data and inference stay close to the machines, sensors, and Programmable Logic Controllers (PLCs) that need them. This security boundary minimizes lateral movement of threats from the IT network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 3: Hierarchical Federated Learning (Client-Edge-Cloud)
&lt;/h2&gt;

&lt;p&gt;Hierarchical federated learning (HFL) builds on a three-layer infrastructure for teams navigating data mobility restrictions at the edge.&lt;/p&gt;

&lt;p&gt;At the lowest layer, client devices perform local training, optimizing model parameters through local gradient descent. Edge servers at the intermediate layer aggregate updated model weights from all client devices for statistical coherence. A final aggregation round by a cloud server marks the top layer, producing a global model that the edge servers distribute back to the client devices. Since only parameter updates traverse this hierarchy, intermittent connectivity does not halt training progress.&lt;/p&gt;

&lt;p&gt;The image below captures this iteration, which continues until the global model reaches the desired accuracy or converges.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyz5qtq1yo1a1gu8yxgbb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyz5qtq1yo1a1gu8yxgbb.png" alt="Figure 4: Hierarchical federated learning architecture" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Domains such as healthcare and financial services, where raw data is bound to its origin by privacy constraints, regulatory requirements, and bandwidth limitations, are ideal HFL use cases. Data sovereignty mandates and &lt;a href="https://www.foreignaffairs.com/united-states/ai-divide" rel="noopener noreferrer"&gt;geopolitical tensions&lt;/a&gt; add another layer to this constraint, restricting where and how data flows at the infrastructure level.&lt;/p&gt;

&lt;p&gt;A study by BARC found that &lt;a href="https://barc.com/the-great-cloud-reversal/" rel="noopener noreferrer"&gt;19% of companies&lt;/a&gt; plan to increase their on-premises investments, driven by this need for data sovereignty. HFL allows a shared model to improve across distributed nodes without the underlying data ever crossing a jurisdictional boundary.&lt;/p&gt;

&lt;p&gt;A recent experimental HFL training in healthcare achieved &lt;a href="https://www.accscience.com/journal/AIH/articles/online_first/5141" rel="noopener noreferrer"&gt;94.23% accuracy&lt;/a&gt; on a modified National Institute of Standards and Technology dataset, while keeping data on client devices. Only relevant aggregated information ever reaches the cloud to preserve privacy and curtail data leakage risks.&lt;/p&gt;

&lt;p&gt;In healthcare deployment, wearable devices (lowest layer) transmit raw data to a hospital’s local edge server (intermediate layer), which aggregates data from multiple wearables and sends it to a regional research institution (top layer) for final aggregation without exposing patient data.&lt;/p&gt;

&lt;p&gt;HFL is the most complex pattern to implement. Tooling support remains fragmented, and unlike other patterns discussed, it currently lacks native support within the Actian ecosystem. Teams should weigh this implementation overhead before committing to this architecture.&lt;/p&gt;

&lt;p&gt;The HFL architecture has three variants depending on which layer orchestrates data decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Cloud-orchestrated hierarchical federated learning
&lt;/h3&gt;

&lt;p&gt;The central cloud server coordinates the training process, client-edge communications, synchronization schedules, and the overall topology, with no additional aggregation rounds from the edge servers.&lt;/p&gt;

&lt;p&gt;Cloud-orchestrated HFL fits financial institutions, where occasional reliable connectivity can sustain the coordination loop. In a fraud detection deployment, multiple banking institutions might train models using transaction data, sending updates to the cloud, which aggregates, validates, and redistributes the improved model back to the banks.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Edge-orchestrated hierarchical federated learning
&lt;/h3&gt;

&lt;p&gt;Edge servers autonomously manage local client assignments, aggregating client updates to produce a locally improved model without cloud round-trips. Cloud systems only support at interval for bulk model retraining. Environments like offshore wind farms, where unstable connectivity is the baseline, benefit most from this variant. Turbines send model updates to a local edge server, which handles aggregation and independent model improvement.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Peer-to-peer aggregation
&lt;/h3&gt;

&lt;p&gt;This variant focuses on a gossip-like model with no central orchestrator. Clients exchange their model weights with other nodes, reducing gradient conflicts under heterogeneous data.&lt;/p&gt;

&lt;p&gt;Where the core HFL pattern reduces cloud ingress fees through aggregated updates, peer-to-peer aggregation keeps both training and aggregation within participating nodes. In distributed environments like smart cities, traffic sensors exchange anomaly-detection updates directly with neighboring devices until they converge on an improved model across the network organically.&lt;/p&gt;

&lt;p&gt;All three variants differ in their functional requirements, highlighted in the table below.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Cloud-orchestrated&lt;/th&gt;
&lt;th&gt;Edge-orchestrated&lt;/th&gt;
&lt;th&gt;Peer-to-peer aggregation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Orchestration model&lt;/td&gt;
&lt;td&gt;Cloud coordinates all aggregation and model distribution&lt;/td&gt;
&lt;td&gt;Edge server aggregates locally, syncs with cloud periodically&lt;/td&gt;
&lt;td&gt;No orchestrator; updates propagate between clients until convergence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privacy level&lt;/td&gt;
&lt;td&gt;Medium; the cloud controls model updates&lt;/td&gt;
&lt;td&gt;High; raw data remains on local edge servers&lt;/td&gt;
&lt;td&gt;High; no central point oversees aggregated updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bandwidth requirements&lt;/td&gt;
&lt;td&gt;High; all updates are sent to the cloud&lt;/td&gt;
&lt;td&gt;Medium; only aggregated updates reach cloud&lt;/td&gt;
&lt;td&gt;Low; updates only travel between neighboring peers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disconnection tolerance&lt;/td&gt;
&lt;td&gt;Low; cloud disconnection breaks coordination&lt;/td&gt;
&lt;td&gt;High; edge server operates independently during outages&lt;/td&gt;
&lt;td&gt;Medium; network partitions slow convergence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;HFL’s layered infrastructure supports large-scale model training by distributing computation and communication across multiple nodes in the hierarchy. The challenge with this multi-tier design lies in navigating communication overhead, stale global models, and node reconfigurations.&lt;/p&gt;

&lt;p&gt;In HFL, communication cost is directly proportional to the model update size. Gradient compression techniques such as random sparsification and stochastic rounding shrink update payloads by &lt;a href="https://www.scirp.org/journal/paperinformation?paperid=133610" rel="noopener noreferrer"&gt;up to 98%&lt;/a&gt; before transmission.&lt;/p&gt;

&lt;p&gt;The asynchronous update cycle of HFL, where the global model incorporates client updates as they arrive, also amplifies the likelihood of stale model parameters. Weighted aggregation limits the influence of stale updates, preventing slower devices from degrading the global model.&lt;/p&gt;

&lt;p&gt;Topology shifts add another challenge. Clients get reassigned to different edge servers, roles shift between client and aggregator nodes, and new devices join mid-training. Each reconfiguration stalls convergence and degrades accuracy if new edge servers lack prior training history.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 4: Store-and-Forward Disconnected Inference
&lt;/h2&gt;

&lt;p&gt;In disconnected environments, intermittent connectivity can stretch for hours or days. Store-and-forward architecture accounts for this reality, sustaining large-scale data processing and storage during downtime, and forwarding summaries to the cloud once the system reconnects.&lt;/p&gt;

&lt;p&gt;For industrial automation environments, such as remote oil and gas operations and maritime vessels operating miles from cellular towers, this architecture solves the core problem of maintaining data continuity despite network disruption.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inference doesn’t wait for the cloud
&lt;/h3&gt;

&lt;p&gt;Store-and-forward deployment follows a hybrid approach. Training begins in the cloud, but execution shifts to the edge after model deployment. When connectivity drops, decision-making, control loops, and alarm triggers continue locally without interruption, and the system buffers timestamped results to a local edge database until synchronization resumes.&lt;/p&gt;

&lt;p&gt;Upon network restoration, the edge gateway offloads all buffered events to a central cloud infrastructure, providing the data required to push updated models and optimize AI pipelines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7c1nm6j4mhgz26rj5mt4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7c1nm6j4mhgz26rj5mt4.png" alt="Figure 5: Store-and-forward architecture" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Store-and-forward architecture creates a feedback loop that prevents data loss during disconnection. In manufacturing plants, SCADA systems continue collecting data from PLCs, Remote Terminal Units (RTUs), and edge gateways until connection resumes.&lt;/p&gt;

&lt;h3&gt;
  
  
  When the data finally moves
&lt;/h3&gt;

&lt;p&gt;The “forward” part of this architecture relies on lightweight communication protocols like Message Queuing Telemetry Transport (MQTT), designed for unstable networks and bandwidth-limited environments.&lt;/p&gt;

&lt;p&gt;MQTT’s publish-subscribe model routes queued updates from edge gateways to the cloud through brokers like Mosquitto. Publishers (sensors) send messages to a topic (temperature), and subscribers (cloud servers) receive messages from their registered topics. Messages replay in the exact chronological order they were received.&lt;/p&gt;

&lt;p&gt;The Python code snippet below illustrates a starting-point implementation using the Paho MQTT library. It uses Quality of Service (QoS) 1, a persistent session that enables Mosquitto to queue messages while the subscriber is offline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pip install paho-mqtt
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;paho.mqtt.publish&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;publish&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Usage: publisher.py &amp;lt;topic&amp;gt; &amp;lt;message&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Production code will add retry logic, local queue persistence, and message deduplication
&lt;/span&gt;
&lt;span class="n"&gt;topic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To initiate data transfer after reconnection, the script below creates a persistent session using &lt;code&gt;clean_session=False&lt;/code&gt; and &lt;code&gt;loop_forever()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;paho.mqtt.client&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;mqtt&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Usage: subscriber.py &amp;lt;topic&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;topic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;client_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test-client&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userdata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Connected with result code &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userdata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mqtt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clean_session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on_connect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;on_connect&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;on_message&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1883&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loop_forever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store-and-forward architecture can introduce data replication inconsistencies during gateway synchronization. The system requires an arbitration policy, such as last-write-wins, which applies changes based on each update’s timestamp. When timestamps are identical, data structures like Conflict-free Replicated Data Types (CRDTs) merge copies to achieve a consistent final state across all edge gateways.&lt;/p&gt;

&lt;p&gt;Delta sync further improves CRDTs’ results. Where full dataset replication triggers on every record change, delta sync resolves conflicts at the property level, addressing only the modified fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pattern 5: The Network (Distributed Edge-to-Edge Fabric)
&lt;/h2&gt;

&lt;p&gt;The network deployment pattern addresses the lack of fault tolerance and distributed processing prevalent in disconnected multi-site operations such as logistics networks and smart grids.&lt;/p&gt;

&lt;p&gt;The network deployment pattern addresses the lack of fault tolerance and distributed processing prevalent in disconnected multi-site operations such as logistics networks and smart grids.&lt;/p&gt;

&lt;p&gt;Coordinating edge devices across multiple locations through a cloud system quickly breaks outside network coverage. This is why the network architecture follows an east-west communication pattern, enabling edge nodes to exchange data directly with peers without central coordination.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mesh communication handles distributed intelligence
&lt;/h3&gt;

&lt;p&gt;The network deployment pattern adopts a non-hierarchical design, connecting multiple IoT devices through a mesh network to improve system uptime during outages. Each node dynamically communicates with its neighbors, forming a bidirectional network that relays data to remote environments via multi-hop paths.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe8nqyrfz1bs8ocxvi5kx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe8nqyrfz1bs8ocxvi5kx.png" alt="Figure 6: Network architecture" width="800" height="597"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The cloud only joins as a peer for optional sync, but core computing remains on the network, working without centralized control.&lt;/p&gt;

&lt;p&gt;Smart grids are well-suited for this architecture, where &lt;a href="https://www.ericsson.com/en/blog/2021/10/wireless-for-power-grids" rel="noopener noreferrer"&gt;teleprotection demands 10–20ms latency&lt;/a&gt;. A network of transmission substations continuously tracks electricity flow and consumption patterns in real-time to detect imbalances before they escalate. That real-time visibility supports dynamic load redistribution and &lt;a href="https://www.sciencedirect.com/topics/engineering/autonomous-microgrid" rel="noopener noreferrer"&gt;autonomous microgrid management&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Military uncrewed aerial vehicles (UAVs) are another use case. When GPS fails in DDIL environments, &lt;a href="https://www.bluwireless.com/insight/gps-denied-drone-communications/" rel="noopener noreferrer"&gt;UAVs relay ISR data&lt;/a&gt; between each other through mesh networks. Adaptive interference routing ensures reliable data flow, while line-of-sight transmission reduces latency.&lt;/p&gt;

&lt;p&gt;This deployment pattern optimizes for network redundancy. Gossip protocol and distributed consensus algorithms like Raft eliminate single points of failure. When a node loses connection, the network remains operational, rerouting its data through other nodes.&lt;/p&gt;

&lt;p&gt;Gossip protocol enables live peer discovery through continuous, lightweight information exchanges. Each node always has a current view of its local network. Raft follows a leader-based approach where an elected leader node handles all writes, and log replication ensures follower nodes maintain a shared state. Edge databases replicate data across multiple nodes to improve consistency.&lt;/p&gt;

&lt;p&gt;Treating Gossip and Raft as competing options overlooks what actually matters. The focus should be on understanding where each sits in the CAP theorem and the trade-offs they introduce to a distributed network.&lt;/p&gt;

&lt;h3&gt;
  
  
  The consistency vs. availability trade-off
&lt;/h3&gt;

&lt;p&gt;When network partitions split the mesh, Raft ensures strong data consistency, while Gossip provides availability fallback and eventual consistency when paired with approaches like CRDTs.&lt;/p&gt;

&lt;p&gt;In edge computing, where connection is limited and nodes are numerous, partition tolerance is non-negotiable. Edge AI systems must choose whether to prioritize consistency or availability when implementing the network architecture.&lt;/p&gt;

&lt;p&gt;Availability is often optimal, as edge nodes continue to function independently after disconnection. Consistency-focused designs like Raft risk write suspensions and stale reads during network partitions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Raft&lt;/th&gt;
&lt;th&gt;Gossip&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Architecture&lt;/td&gt;
&lt;td&gt;Leader election and log replication&lt;/td&gt;
&lt;td&gt;Peer-to-peer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Moderate; requires at least a quorum of nodes in a network to become available&lt;/td&gt;
&lt;td&gt;Low; messages travel quickly but propagation rounds can slow down speed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Consistency guarantees&lt;/td&gt;
&lt;td&gt;Strong consistency&lt;/td&gt;
&lt;td&gt;Eventual consistency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partition tolerance&lt;/td&gt;
&lt;td&gt;Moderate; might not survive a partition&lt;/td&gt;
&lt;td&gt;High; heals partitions faster&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Speed and data delivery trade-offs are another critical constraint of the network architecture. Mesh networking adds latency with each hop as the node count increases. If your system needs data back in &amp;lt;50ms or your latency requirements can tolerate &amp;gt;100ms, this trade-off should shape your design decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Edge AI Deployment Pattern
&lt;/h2&gt;

&lt;p&gt;There’s no specific “right” edge AI deployment pattern for disconnected environments. A solid architecture implementation begins with a clear grasp of the specific constraints, goals, and characteristics of your target application. This means envisioning the full workload lifecycle, including connectivity profile, available compute resources, and latency requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Evaluate network stability
&lt;/h3&gt;

&lt;p&gt;Network stability is the primary driver of any edge AI deployment strategy. Determine how much resilience must be engineered into the edge nodes based on the expected duration of disconnection.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If the system is always disconnected&lt;/strong&gt;: Use drone or network architectures as they are designed to operate completely offline regardless of connectivity status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If the interruption persists for only minutes or hours&lt;/strong&gt;: Use factory or HFL architecture to continue data aggregation and inference without interruption. The system remains functional during the outage because all required dependencies already exist within the operational perimeter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If intermittent connectivity lasts for days or weeks&lt;/strong&gt;: Use the store-and-forward architecture to buffer inference results and operational data locally until the scheduled connectivity window becomes available again.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Assess latency requirements
&lt;/h3&gt;

&lt;p&gt;Define the maximum acceptable latency for your specific application by considering network hops, node availability, and geographical proximity of the edge nodes. The thresholds below reflect typical deployment patterns. Validate them against your specific hardware and network conditions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If the system requires &amp;lt;50ms latency&lt;/strong&gt;: Use the drone deployment pattern. Its single-node architecture keeps inference directly on sensors, cameras, or gateways, enabling near-real-time responses. Factory architecture also minimizes latency by running on edge servers within the same facility or on the factory floor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If the system requires &amp;lt;100ms latency&lt;/strong&gt;: Use the network or HFL architecture to distribute model improvement workloads across multiple nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If &amp;lt;500ms latency is acceptable&lt;/strong&gt;: Use store-and-forward architecture for non-critical IoT data that requires batch processing or long-term analytics. It batch-offloads data-intensive tasks to the cloud.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Evaluate resource constraints
&lt;/h3&gt;

&lt;p&gt;Edge AI applications differ in processing power, storage, and bandwidth consumption, which impacts inference speed, data aggregation, and real-time analytics. Evaluate each resource limit independently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Power constraint&lt;/strong&gt;: For compute power &amp;lt;1 GFLOPS, common in microcontrollers used for sensor inference, the drone architecture is most suitable. It runs on constrained IoT devices using lightweight, inference-only models. At 10–100 GFLOPS, common in edge gateways, HFL and network architectures become more effective as they handle data aggregation needs well at this level. For edge GPU clusters that scale to &amp;gt;10 TFLOPS, factory and store-and-forward architecture support clustered inference pipelines, since they run on-premises.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bandwidth constraint&lt;/strong&gt;: Use store-and-forward architecture or HFL to store and process raw, high-volume data at the edge, forwarding only summarized updates to the cloud if required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data storage constraint&lt;/strong&gt;: Use factory or store-and-forward architectures paired with &lt;a href="https://www.actian.com/blog/data-warehouse/embedded-databases-iot-use-cases/" rel="noopener noreferrer"&gt;embedded databases&lt;/a&gt; to store time-series data locally and scale vertically within the facility. Databases like Actian Zen are optimized for edge AI use cases and can also sync with the cloud once connectivity is restored.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Consider a hybrid approach
&lt;/h3&gt;

&lt;p&gt;Industrial systems often combine the strengths of multiple architectures into a coordinated system that delivers resilience and flexibility. Rio Tinto’s mining operations illustrate what hybrid deployment looks like at scale.&lt;/p&gt;

&lt;p&gt;At the Greater Nammuldi iron ore mine, more than &lt;a href="https://www.bbc.com/news/articles/cgej7gzg8l0o" rel="noopener noreferrer"&gt;50 autonomous trucks&lt;/a&gt; operate on predefined routes, using onboard sensors to detect obstacles, an example of the &lt;strong&gt;drone architecture&lt;/strong&gt;. Across 17 sites in Western Australia, these trucks transmit operational data to Rio Tinto’s Operations Centre in Perth, reflecting the &lt;strong&gt;network architecture&lt;/strong&gt;. Finally, an autonomous rail system transports mined ore, synchronizing with the Operations Centre upon reaching port facilities. This fits the &lt;strong&gt;store-and-forward architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rio Tinto demonstrates that deployment patterns are not mutually exclusive. If your use case requires multiple architectures, consider running them on the layer of the system where they’re best suited, rather than forcing a single architecture across the entire operation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznn34a2gfwqdha3e5zmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fznn34a2gfwqdha3e5zmg.png" alt="Figure 7: Decision framework for choosing an edge AI architecture" width="800" height="1688"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The following table maps specific deployment scenarios to their optimal disconnected edge AI deployment pattern to inform your decision.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Deployment scenarios&lt;/th&gt;
&lt;th&gt;Recommended pattern&lt;/th&gt;
&lt;th&gt;Rationale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Autonomous inspection drones over oil fields or offshore wind farms&lt;/td&gt;
&lt;td&gt;Drone (single-node self-contained)&lt;/td&gt;
&lt;td&gt;A self-contained inference runtime with embedded local storage eliminates distributed computation to meet hardware limitations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automotive assembly lines running defect detection models&lt;/td&gt;
&lt;td&gt;Factory (multi-node edge AI)&lt;/td&gt;
&lt;td&gt;Cloud dependency is too risky for uptime requirements, so edge clusters run within the facility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hospital networks where patient data cannot leave individual facilities under HIPAA&lt;/td&gt;
&lt;td&gt;Hierarchical federated learning&lt;/td&gt;
&lt;td&gt;Models train locally, sharing only weight updates to the cloud, so raw data remains on the local site in compliance with data sovereignty and privacy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cargo vessels at sea syncing operational data at port&lt;/td&gt;
&lt;td&gt;Store-and-forward&lt;/td&gt;
&lt;td&gt;A local buffer ensures no inference result or operational event is lost across connectivity gaps that can last days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Smart city traffic management across distributed intersections with no central server dependency&lt;/td&gt;
&lt;td&gt;Network (distributed edge-to-edge fabric)&lt;/td&gt;
&lt;td&gt;Nodes communicate peer-to-peer via consensus, so node loss reduces capacity without disrupting overall network operation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Industries operating across remote, underground, maritime, and geographically dispersed terrain need edge-native architectures that capture real-time insights and keep critical assets running without cloud dependency.&lt;/p&gt;

&lt;p&gt;The deployment patterns discussed prioritize what matters most for disconnected environments: local inference, no centralization latency, lower communication costs, and system autonomy.&lt;/p&gt;

&lt;p&gt;Before committing to a pattern, validate three things in your own environment: how long your system can tolerate network outage before data loss becomes operationally significant, whether your edge hardware can sustain the compute demands of your chosen architecture without degrading inference quality, and whether your team has the tooling maturity to manage model lifecycle at the edge without cloud dependency. Map your constraints against the decision framework above.&lt;/p&gt;

&lt;p&gt;The right answer might not be a single pattern. Layer in hybrid approaches only when the resilience gains justify the operational complexity.&lt;/p&gt;

&lt;p&gt;Each pattern depends on a data infrastructure that can operate, store, and sync entirely at the edge. For teams that need to go beyond structured storage and perform semantic search on their local data without exporting vector embeddings to a cloud server, &lt;a href="https://www.actian.com/databases/vectorai-db/" rel="noopener noreferrer"&gt;Actian VectorAI DB&lt;/a&gt; is optimized for this use case. &lt;a href="https://www.actian.com/databases/vectorai-db/" rel="noopener noreferrer"&gt;Start for free&lt;/a&gt; today.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Join the &lt;a href="https://discord.gg/432A2M63Py" rel="noopener noreferrer"&gt;Actian community on Discord&lt;/a&gt; to discuss edge AI architecture patterns with engineers deploying in disconnected environments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>iot</category>
    </item>
    <item>
      <title>What's Changing in Vector Databases in 2026</title>
      <dc:creator>Praise James</dc:creator>
      <pubDate>Tue, 17 Feb 2026 14:25:14 +0000</pubDate>
      <link>https://dev.to/actiandev/whats-changing-in-vector-databases-in-2026-3pbo</link>
      <guid>https://dev.to/actiandev/whats-changing-in-vector-databases-in-2026-3pbo</guid>
      <description>&lt;p&gt;The vector database market has shifted. Engineering conversations have matured from “use Pinecone” to “we can build this on PostgreSQL." What the market is witnessing is a growing movement from cloud-native vector databases back to traditional infrastructure, where embedding vector search directly into a relational database has become standard practice.&lt;/p&gt;

&lt;p&gt;Every major cloud provider and traditional database, from AWS and Azure to MongoDB and PostgreSQL, now handles vector data. This consolidation raises two key questions: “Are standalone vector solutions still necessary?” or “Should teams continue with familiar multi-model systems like PostgreSQL?”&lt;/p&gt;

&lt;p&gt;Deployment limitations add another critical dimension. For many data-heavy industries like IoT, manufacturing, and retail, there are rarely practical ways to run these databases where data actually lives. This constraint exposes a gap in edge and on-premises deployment support. &lt;/p&gt;

&lt;p&gt;Additionally, AI agents are generating 10x &lt;a href="https://tomtunguz.com/2026-predictions/" rel="noopener noreferrer"&gt;more queries&lt;/a&gt; than human-driven applications, forcing a fundamental rethink of database throughput architecture. Despite the significance of these shifts, there is no thorough analysis of their implications for architectural decisions.&lt;/p&gt;

&lt;p&gt;We examine the core forces that have transformed the vector database market, argue why specialized solution usage is declining, assess where edge deployment support stands in 2026, and present an actionable database decision framework that accounts for data you can't migrate to the cloud. &lt;/p&gt;

&lt;h2&gt;
  
  
  What Shifted in 2025
&lt;/h2&gt;

&lt;p&gt;Pre-2025, purpose-built vector databases were presented as the standard infrastructure, but by 2026, a different reality emerges. Vectors have moved from being a database category to a data type. &lt;/p&gt;

&lt;p&gt;Major traditional database providers, from PostgreSQL to Oracle and MongoDB, now add native vector support. MongoDB integrated &lt;a href="https://www.infoworld.com/article/2338676/mongodb-adds-vector-search-to-atlas-database-to-help-build-ai-apps.html" rel="noopener noreferrer"&gt;Atlas Vector Search&lt;/a&gt;, PostgreSQL added &lt;a href="https://venturebeat.com/data-infrastructure/timescale-expands-open-source-vector-database-capabilities-for-postgresql" rel="noopener noreferrer"&gt;pgvector and pgvectorscale&lt;/a&gt; extensions, and Oracle introduced &lt;a href="https://blogs.oracle.com/database/oracle-announces-general-availability-of-ai-vector-search-in-oracle-database-23ai" rel="noopener noreferrer"&gt;Oracle Database 23ai&lt;/a&gt;. Top cloud providers, like AWS, Google, and Azure, also joined this trend. &lt;/p&gt;

&lt;p&gt;Integrated vector support eliminates the need to introduce a separate database alongside your primary relational system to implement vector search for AI applications. While purpose-built vector databases still dominate vendor lists, the market has already moved on, and the PostgreSQL acquisitions make that clear. &lt;/p&gt;

&lt;p&gt;In 2025 alone, Snowflake and Databricks &lt;a href="https://www.theregister.com/2025/06/10/snowflake_and_databricks_bank_postgresql/" rel="noopener noreferrer"&gt;spent approximately $1.25B&lt;/a&gt; acquiring PostgreSQL-first companies. At the same time, &lt;a href="https://survey.stackoverflow.co/2025/technology#1-dev-id-es" rel="noopener noreferrer"&gt;Stack Overflow &lt;/a&gt;reported PostgreSQL as the most used (46.5%) database among developers in 2025. These numbers signal that relational databases are now fit for AI workloads. But &lt;a href="https://venturebeat.com/data/six-data-shifts-that-will-shape-enterprise-ai-in-2026" rel="noopener noreferrer"&gt;VentureBeat&lt;/a&gt; predicts that this shift will narrow down purpose-built platforms to specialized use cases.&lt;/p&gt;

&lt;p&gt;By integrating vector search directly into production systems, traditional databases are compressing the role of dedicated vector infrastructure to billion-scale workloads with sub-50ms latency requirements, consistent with VentureBeat’s analysis and confirmed by PostgreSQL acquisitions. &lt;/p&gt;

&lt;p&gt;To understand what this 2025 shift means for your architectural decisions in 2026, let’s first look at how we got here. &lt;/p&gt;

&lt;h2&gt;
  
  
  A Refresher on Vector Databases
&lt;/h2&gt;

&lt;p&gt;Vector databases store, index, and query high-dimensional vector embeddings that represent multimodal data as numerical arrays to capture their semantic and contextual relationships. As unstructured data accounts for 90% of the &lt;a href="https://www.box.com/resources/unstructured-data-paper" rel="noopener noreferrer"&gt;global information&lt;/a&gt; footprint, encoding meaning for machine learning models requires embedding storage, vector search, and context retrieval, which vector databases handle. This infrastructure underpins many AI applications, including retrieval-augmented generation (RAG), recommendation systems, and natural language processing (NLP).&lt;/p&gt;

&lt;h2&gt;
  
  
  How Similarity Search Actually Works
&lt;/h2&gt;

&lt;p&gt;The core retrieval technology for similarity search is approximate nearest neighbor search. Most databases use hierarchical navigable small world graphs (HNSW), inverted file (IVF), locality-sensitive hashing (LSH), or product quantization (PQ) ANN indexing algorithms.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0bix972srilxaxedtao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm0bix972srilxaxedtao.png" alt="Figure 1: How vector similarity search works" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a query vector arrives, the database follows a graph, hash, or quantization-based approach to find approximate nearest neighbor candidates within the vector space. The database then computes the distance between these vectors, typically using cosine similarity or Euclidean distance functions to rank the top-K results, as illustrated in the image above. These ranked results either improve the context that becomes the final output or serve as a candidate set for re-ranking to identify more true nearest neighbors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Retrieval-Augmented Generation (RAG) Made Vector Databases Essential
&lt;/h2&gt;

&lt;p&gt;The persistent interest in vector databases is a direct response to large language models' hallucinations, lack of domain knowledge, and inability to incorporate up-to-date information into their responses, making them insufficient for accuracy-sensitive tasks. RAG methods augment LLM outputs, leveraging vector databases as external knowledge bases and vector search as the computational backbone for retrieving relevant context. &lt;/p&gt;

&lt;p&gt;Conventional RAG systems build on a four-tier architecture: converting incoming queries into vector representations using an embedding model, executing a similarity search on stored vectors, integrating the retrieved relevant chunks and the query into an extended context that a language model processes, and finally transmitting the generated response back to the user. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feeodgu34g8wbv2zliq4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feeodgu34g8wbv2zliq4a.png" alt="Figure 2: Typical cloud retrieval-augmented generation workflow" width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Purpose-built vector databases simplified RAG implementation and efficient similarity search for early AI adopters. But three things changed between 2022 and 2025.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Market Forces Reshaping Vector Databases in 2026
&lt;/h2&gt;

&lt;p&gt;If 2022–2025 was about adding vector-native databases to AI applications, 2026 is leaning towards moving back to extended relational databases, rethinking architectural designs, and addressing an overlooked edge deployment gap. These three distinct trends stand out the most. &lt;/p&gt;

&lt;h3&gt;
  
  
  Force 1: Database Consolidation (Multimodal Platforms Win)
&lt;/h3&gt;

&lt;p&gt;In 2026, major traditional relational databases have integrated vector capabilities into their data layer, and their extensions are already showing success with AI workloads. PostgreSQL’s pgvectorscale, for instance, &lt;a href="https://www.tigerdata.com/blog/how-we-made-postgresql-as-fast-as-pinecone-for-vector-data" rel="noopener noreferrer"&gt;benchmarked&lt;/a&gt; 471 QPS, against Qdrant's 41 QPS at 99% recall on 50M vectors. This consolidation means developers can now build moderate-scale production AI applications on general-purpose databases. &lt;/p&gt;

&lt;p&gt;While purpose-built vector databases excel at vector search, infrastructure consolidation outweighs specialization when the workload doesn't demand it. Consider a product documentation knowledge base with 10M embedded documents, processing 500QPS, and requiring hybrid search. Traditional databases handle this workload effectively while also managing log collection, full-text search, and query analytics.&lt;/p&gt;

&lt;p&gt;One relational database that stands out in 2026 is PostgreSQL. An optimized PostgreSQL database currently supports &lt;a href="https://openai.com/index/scaling-postgresql/" rel="noopener noreferrer"&gt;OpenAI's&lt;/a&gt; ChatGPT and API, and the reason is simple: PostgreSQL gives engineers the flexibility, stability, and cost control needed for GenAI development. There are fewer moving parts, the system combines transactional safety with analytical capability, and a familiar ecosystem anchors your stack. &lt;/p&gt;

&lt;p&gt;Meanwhile, there's also the hybrid search advantage of PostgreSQL + pgvector that enables production systems to model nuanced relationships between data to match real user queries. Engineers prioritize databases that support personalization and enforce business rules such as price thresholds, categories, permissions, and date ranges. PostgreSQL achieves this richer data retrieval by merging dense and sparse vector embeddings. The database and its vector data extensions obtain query results from vector search, keyword matching, and metadata filters. &lt;/p&gt;

&lt;p&gt;Below is a Python example that demonstrates vector similarity search with metadata filtering using PostgreSQL + pgvector. The code takes a pre-filtering approach, filtering rows first by price and category before measuring vector distance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;psycopg2&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pgvector.psycopg2&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;register_vector&lt;/span&gt;

&lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psycopg2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dbname=mydb user=postgres&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;register_vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;query_embedding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;min_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;electronics&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    SELECT product_name, price, category, embedding &amp;lt;-&amp;gt; %s AS distance
    FROM products
    WHERE price &amp;gt;= %s AND category = %s
    ORDER BY embedding &amp;lt;-&amp;gt; %s
    LIMIT 5
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query_embedding&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchall&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (similarity: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pure vector search focuses on only similarity search operations. In contrast, hybrid search provides a better basis for reasoning about interconnected information on diverse data types by capturing both semantic matches and contextually appropriate responses.&lt;/p&gt;

&lt;p&gt;Vector-native solutions still matter, but for billion-scale use cases where performance, tuned indexes, and vector quantization are a priority. If you're building RAG applications or knowledge management systems, with a stable load of 50-100M vectors, traditional databases provide a unified platform where vectors and application data can reside in the same place. &lt;/p&gt;

&lt;h3&gt;
  
  
  Force 2: AI Agents Breaking the Query Model
&lt;/h3&gt;

&lt;p&gt;AI agents are issuing &lt;a href="https://tomtunguz.com/2026-predictions/" rel="noopener noreferrer"&gt;10x more queries&lt;/a&gt; than humans in 2026. This means the vector database infrastructure designed for human query patterns won't work for agents.  Autonomous systems spin up an &lt;a href="https://www.databricks.com/company/newsroom/press-releases/databricks-agrees-acquire-neon-help-developers-deliver-ai-systems" rel="noopener noreferrer"&gt;isolated PostgreSQL instance&lt;/a&gt; in &amp;lt;500ms, rely on heavy parallelism, and ingest large datasets continuously. Low-latency databases alone won’t serve this behavior. Throughput must also scale to match the surge in concurrency that agents will introduce in 2026.&lt;/p&gt;

&lt;p&gt;However, not all vector databases are agent-ready, and optimizing for throughput often compromises latency. In production systems, these trade-offs become more pronounced. &lt;/p&gt;

&lt;p&gt;Database providers must rethink their architectural designs to align with agentic workloads. Traditional caching strategies that focused solely on storing frequently accessed embeddings must evolve to leverage semantic cache, which reuses previously retrieved query-answer pairs under similar computing conditions. This setup can reduce latency and inference costs, while maintaining high throughput during high traffic.&lt;/p&gt;

&lt;p&gt;At the indexing layer, databases must be configurable, exposing vector index parameters so engineers can tune trade-offs between speed, recall, and memory usage. To prevent server overload, databases must also move from static, reusable maximum connections to dynamic pool sizing that adjusts connection pools based on real-time demand. This minimizes running out of available connections under load or accumulating many idle ones. &lt;/p&gt;

&lt;p&gt;In 2026, vector databases must rewire infrastructure design for an agentic era rather than waiting to be shaped by it.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Force 3: The Deployment Gap Nobody's Filling
&lt;/h3&gt;

&lt;p&gt;While cloud databases have scaled to handle billions of vectors, developers building privacy-first, latency-sensitive applications at the edge are still being ignored in 2026. &lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.marketsandmarkets.com/Market-Reports/edge-computing-market-133384090.html" rel="noopener noreferrer"&gt;edge computing market&lt;/a&gt; was worth $168B in 2025, and &lt;a href="https://iot-analytics.com/number-connected-iot-devices/" rel="noopener noreferrer"&gt;IoT Analytics&lt;/a&gt; estimates the number of connected IoT devices will hit 39 billion by 2030. There's an active market, yet no one has filled the deployment gap. &lt;/p&gt;

&lt;p&gt;What the market is ignoring is that cloud-only databases are not equipped for offline scenarios, with limited bandwidth and intermittent connectivity. Critical applications, such as in healthcare, demand real-time responses (&amp;lt;10ms) and continuous system availability. Inability to operate during outages can cost between $700 and $450,000 per hour, depending on the industry. Edge setup can provide that always-on infrastructure while cutting transit costs. &lt;/p&gt;

&lt;p&gt;There are also the data security, compliance, and sovereignty requirements that regulated applications must meet by keeping data on-premises. Fulfilling these constraints means adapting infrastructure to support a secure, decentralized computing model that cloud systems cannot deliver. Edge deployment minimizes data movement and isolates sensitive workloads to reduce compliance scope. &lt;/p&gt;

&lt;p&gt;For air-gapped environments, localized decision-making is non-negotiable. Public cloud deployments rely on persistent connections, but applications operating within a controlled perimeter must avoid outbound connections. Adopting a private cloud approach is costly and resource-intensive, whereas edge infrastructure succeeds by processing data locally at the source.&lt;/p&gt;

&lt;p&gt;Yet in 2026, moving the edge beyond do-it-yourself setups is still in its early stages, despite a thriving market. Most hyperscalers currently treat edge computing as an extension of their existing cloud business. What the market needs is an edge-native solution that scales vertically to improve the network capacity, storage power, and processing ability of existing machines. But everyone still builds for the cloud. &lt;/p&gt;

&lt;p&gt;These three forces reveal a market that needs careful architectural reevaluation. One might be taking a hybrid approach, combining cloud and on-premises deployment for edge use cases. Another option is returning to the Postgres environment we are already familiar with. &lt;/p&gt;

&lt;h2&gt;
  
  
  The PostgreSQL Renaissance (and What It Means)
&lt;/h2&gt;

&lt;p&gt;Hyperscalers have been doubling down on PostgreSQL, and more engineers are choosing the database for enterprise-grade AI applications. This resurgence in interest and usage signals a change in infrastructure requirements for GenAI development. &lt;/p&gt;

&lt;h3&gt;
  
  
  Why the Hyperscalers Bet Big on PostgreSQL
&lt;/h3&gt;

&lt;p&gt;Every hyperscaler has integrated PostgreSQL technology into its database services. Google offers Cloud SQL for PostgreSQL and AlloyDB, AWS has Amazon Aurora and Amazon RDS for PostgreSQL, and Microsoft provides Azure Database for PostgreSQL. Top data warehouse providers are not left out of this PostgreSQL adoption either. &lt;/p&gt;

&lt;p&gt;In May 2025, Databricks acquired Neon for $1B. Snowflake followed the same trend in June 2025, acquiring Crunchy Data for an estimated $250M. In October 2025, Supabase also raised $100M in Series E funding. &lt;/p&gt;

&lt;p&gt;Hyperscalers recognize PostgreSQL's familiar, versatile, and extensible infrastructure, which already powers many enterprise databases, and leverage it to support engineers building agentic AI applications with PostgreSQL compatibility. With a 40-year market run, the open-source vector database has developed a mature tooling, flexible enough for both online transaction processing (OLTP) and AI application development. Plus, its dual JSON and vector support enables teams to build on the foundation they already know and scale from it.  &lt;/p&gt;

&lt;p&gt;At the same time, PostgreSQL’s pgvector and pgvectorscale extensions, with HNSW and StreamingDiskANN indexes, mean vector storage and similarity search happen directly within the database. &lt;/p&gt;

&lt;p&gt;Another factor fueling the PostgreSQL comeback is its ACID-compliant engine. Hyperscalers work with enterprise teams seeking data integrity and application stability for critical systems such as financial applications. PostgreSQL's transactional guarantees offer predictable and consistent behavior for production workloads. &lt;/p&gt;

&lt;p&gt;Despite hyperscalers’ convergence on PostgreSQL, AWS has presented a counter-trend to its PostgreSQL-based offerings with S3 Vectors. Instead of indexing vectors inside a database, embeddings live in object storage, querying 2 billion vectors per index. &lt;a href="https://aws.amazon.com/blogs/aws/amazon-s3-vectors-now-generally-available-with-increased-scale-and-performance/" rel="noopener noreferrer"&gt;AWS&lt;/a&gt; positions this storage-first model as a 90% TCO reduction for AI workloads, trading low latency (&amp;gt;100ms) for cost efficiency. This S3 Vectors’ deviation highlights PostgreSQL's scale limits. &lt;/p&gt;

&lt;p&gt;PostgreSQL is fast enough for many vector data workloads, but specialized architectures still win at scale. For instance, PostgreSQL’s multiversion concurrency control (MVCC) implementation is inefficient for write-heavy workloads, like real-time chat systems. During high write traffic, tables bloat and indexes require more maintenance, which in turn degrades application performance. &lt;/p&gt;

&lt;h3&gt;
  
  
  When PostgreSQL with pgvector Is Enough
&lt;/h3&gt;

&lt;p&gt;If your application already relies on PostgreSQL, introducing pgvector is a natural extension rather than adopting a new infrastructure or performing costly data migrations. Your vectors live next to your relational data, and you can query them in the same transaction using both similarity search and SQL JOINs. This hybrid search capability improves your application's retrieval layer and data management beyond pure vector search, with metadata constraints. &lt;/p&gt;

&lt;p&gt;PostgreSQL + pgvector also performs well for moderate-scale vector operations such as enterprise knowledge bases or internal RAG applications, where you're handling &amp;lt;100M vectors, with sub-100ms latency requirements. &lt;/p&gt;

&lt;h3&gt;
  
  
  When You Still Need Purpose-built
&lt;/h3&gt;

&lt;p&gt;If vector search is your primary workload, purpose-built platforms offer indexing structures, high-precision similarity search, and low-latency execution paths tuned for billion-scale vectors and high-throughput applications like recommendation or search engines. Dedicated databases are also effective if your search requirements demand specific capabilities like an HNSW index with dynamic edge pruning or sub-vector product quantization.&lt;/p&gt;

&lt;p&gt;This table summarizes the key differentiators between purpose-built databases and PostgreSQL + pgvector extension.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Features&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Purpose-built&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;PostgreSQL + pgvector&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Performance (QPS)&lt;/td&gt;
&lt;td&gt;&amp;gt;5k QPS&lt;/td&gt;
&lt;td&gt;500–1500 QPS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale (max vectors)&lt;/td&gt;
&lt;td&gt;Billions of vectors&lt;/td&gt;
&lt;td&gt;&amp;lt;100M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;&amp;lt;50 ms&lt;/td&gt;
&lt;td&gt;&amp;lt;100 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost model&lt;/td&gt;
&lt;td&gt;Usage-based for cloud-native databases; infrastructure-driven for self-hosted&lt;/td&gt;
&lt;td&gt;Infrastructure-driven&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Operational complexity&lt;/td&gt;
&lt;td&gt;Fully managed for cloud-based databases; self-hosted options require infrastructure ownership&lt;/td&gt;
&lt;td&gt;Requires proficiency in SQL and PostgreSQL-specific features&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer experience&lt;/td&gt;
&lt;td&gt;Designed for speed and abstraction; provides APIs and SDKs&lt;/td&gt;
&lt;td&gt;Broad tooling support with many connectors and libraries for different development use cases&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One key factor driving teams to rethink database choices in 2026 is cost. Cloud-based vector databases like Pinecone reveal something uncomfortable about cloud bills. &lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Economics Are Breaking (Usage-Based Pricing at Scale)
&lt;/h2&gt;

&lt;p&gt;Usage-based pricing seems cost-effective for modest workloads until a system succeeds. Consider a RAG application handling 10M queries per month. At first, the base storage and computational cost feel predictable. But as traffic grows to 150M, the cumulative costs of storage, database lookups, indexing recomputation, and egress fees reveal how volatile usage-based billing becomes at scale. &lt;/p&gt;

&lt;p&gt;For instance, with 100M (1024-dim) vectors, 150M queries, and 10M writes per month, your estimated Pinecone bill for the RAG application will total around $5,000-$6,000, accounting only for storage, query cost, and write cost. If you factor in egress fees of about $0.08 per GB, the bill escalates further when data transfer is involved.&lt;/p&gt;

&lt;p&gt;Teams using cloud-based vector databases have reported surprise bills up to $5,000 on Reddit. Market pricing trends also echo this cloud bill volatility. In 2025, cloud vendors introduced &lt;a href="https://www.saastr.com/the-great-price-surge-of-2025-a-comprehensive-breakdown-of-pricing-increases-and-the-issues-they-have-created-for-all-of-us/" rel="noopener noreferrer"&gt;price hikes&lt;/a&gt; estimated at 9-25%, and between 2010 and 2024, cloud database costs increased by 30%, with usage-based pricing becoming the dominant model. &lt;/p&gt;

&lt;p&gt;In cloud environments, &lt;a href="https://www.actian.com/blog/databases/the-hidden-cost-of-vector-database-pricing-models/" rel="noopener noreferrer"&gt;costs scale unpredictably&lt;/a&gt; with growing data volume and query frequency. Pay-as-you-go pricing is the accelerant here, amplifying unreliable cost forecasting. Meanwhile, cloud vendors’ incentives scale with your consumption. More queries, storage, and processing result in higher, unpredictable bills for teams, while vendor revenue grows. &lt;a href="https://www.deloitte.com/us/en/what-we-do/capabilities/cloud-transformation/articles/cloud-consumption-model.html" rel="noopener noreferrer"&gt;Deloitte&lt;/a&gt; reported that companies adopting usage-based models grow revenue 38% faster year-over-year. &lt;/p&gt;

&lt;p&gt;Consumption-driven billing promises automatic scaling with workload demand. But teams often lack visibility into exactly what drives the spend and receive bills for both active queries, idle replicas, redundant embedding recomputation, and cloud add-ons. With the variability of the usage-based pricing model, it makes sense to reassess deployment strategy.&lt;/p&gt;

&lt;p&gt;For workloads with predictable traffic, teams can trade the flexibility of a usage-based model for the cost stability of reserved capacity. For instance, committing to a one-year reserved capacity plan can reduce the cost of handling 150M queries per month to $40,000-$42,000 annually, about 32% less than the usage-based pricing cost. &lt;/p&gt;

&lt;p&gt;Migrating to on-premises infrastructure is another alternative for teams with existing DevOps maturity. There's the upfront hardware and security investments. But when optimized, on-premises deployment can significantly control cost. For instance, a self-hosted Milvus deployment handling 150M vectors might require three &lt;code&gt;m5.2xlarge&lt;/code&gt; instances plus distributed storage, totaling around $900-$1,000 per month. &lt;/p&gt;

&lt;p&gt;For latency-critical workloads, edge processing provides another path. Processing 5TB of data at the edge, for example, can save approximately $400-$600 in egress fees. But there's still a huge gap in edge deployment. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Edge Deployment Gap (Where the Market Isn't Looking)
&lt;/h2&gt;

&lt;p&gt;Market attention has focused on cloud vector databases, but they don’t tell the full story of what is happening in offline and air-gapped environments where security, ultra-low latency, decentralization, and compliance are non-negotiables. &lt;/p&gt;

&lt;p&gt;In 2026, &lt;a href="https://services.global.ntt/en-us/newsroom/new-report-finds-enterprises-are-accelerating-edge-adoption#:~:text=your%20business%20transformation-,2026%20Global%20AI%20Report:%20A%20Playbook%20for%20AI%20Leaders,San%20Jose%2C%20Calif" rel="noopener noreferrer"&gt;more enterprises&lt;/a&gt; are leaning towards edge deployment, indicating a rethink of how teams want to handle data processing. Regulated industries need infrastructure that runs where most data decisions are already made, on devices at the network’s edge. Edge deployment meets this demand by keeping computation closer to the source.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.gartner.com/en/newsroom/press-releases/2023-08-01-gartner-identifies-top-trends-shaping-future-of-data-science-and-machine-learning" rel="noopener noreferrer"&gt;Gartner&lt;/a&gt; projects that 55% of deep neural network data analysis will occur at the edge. Yet the edge AI ecosystem remains immature. Cloud is not dead, but there are mission-critical workloads today that cloud deployment cannot support efficiently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Cases Cloud Vendors Can't Address
&lt;/h3&gt;

&lt;p&gt;While cloud vendors offer mature features for integrating vector search into enterprise workflows, there are still use cases they aren't equipped to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Healthcare&lt;/strong&gt;: Medical data and patient records often reside on-premises, governed by HIPAA, GDPR, and other privacy regulations. Hospitals need real-time health analysis happening on-premises, as migrating private data to the cloud expands their attack surface, requires a strong security posture, and increases compliance overhead. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autonomous systems&lt;/strong&gt;: Autonomous vehicles need split-second local decision-making on camera and LiDAR data to maintain situational awareness, with or without external connectivity. Network round-trips to cloud servers limit the delivery of this time-sensitive data. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Military&lt;/strong&gt;: Military services manage sensitive assets through classified networks in an air-gapped and high-risk environment. They expect to push an update to an edge node and have it go live across the fleet in real time for tactical operations. Military services cannot tolerate the network latency and bandwidth constraints of the public cloud. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manufacturing&lt;/strong&gt;: Manufacturing sites’ network carries real-time sensor streams, safety systems, and production telemetry that require immediate analysis for predictive maintenance and operational efficiency. Some manufacturing facilities operate in remote locations with no connectivity, so going "cloud-first” is impractical, as they need solutions designed for interference-heavy factory floors.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retail&lt;/strong&gt;: Retail businesses need consistent local retrieval and immediate analysis of point-of-sale data, regardless of intermittent connectivity, as downtime costs approximately $700 per hour. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These use cases show where cloud vector databases still struggle to meet the latency and security requirements of on-device data. What features enable edge vector databases to satisfy these requirements, and why are comprehensive solutions still scarce? &lt;/p&gt;

&lt;h3&gt;
  
  
  What an Edge Vector Database Needs
&lt;/h3&gt;

&lt;p&gt;Edge vector databases run on edge servers, enabling AI applications to process data stored locally and receive responses in real time without waiting for back-and-forth communication with the cloud. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjscamxrlhi4pjo7ef3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjscamxrlhi4pjo7ef3z.png" alt="Figure 3: Cloud vs. edge vector database architecture" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unlike cloud environments, which assume steady connectivity and large compute power, edge solutions are engineered to manage unstable networks and process local data under resource constraints. With edge vector databases, data stays at its point of generation, ingestion and analysis happen in real time, and the system adapts to unpredictable conditions at the edge.&lt;/p&gt;

&lt;p&gt;There are three core design requirements an &lt;a href="https://www.actian.com/glossary/edge-databases/#:~:text=Reduced%20Latency:%20Traditional%20data%20storage,store%20frequently%20accessed%20data%20locally." rel="noopener noreferrer"&gt;edge database&lt;/a&gt; needs to deliver on this promise of speed and reliability: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight infrastructure&lt;/strong&gt;: Distributed operations require infrastructure that is lightweight and deployable by design for resource-constrained edge servers. Having a compact in-memory data structure also helps to minimize the database memory footprint. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline capability&lt;/strong&gt;: Edge databases must execute local data analytics without relying on connected servers. Even with intermittent connectivity and limited bandwidth, AI applications should remain functional and operate independently.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sync-when-connected architecture&lt;/strong&gt;: Edge databases must automatically sync offline data, resolve conflicts, and reflect data changes when connectivity is restored. This mechanism helps to track performance metrics locally and maintain operational visibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite growing demand, the database market has few edge-native solutions because designing one that ticks the lightweight, offline-capable, and synchronization boxes is complex.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Nobody's Building This
&lt;/h3&gt;

&lt;p&gt;The edge deployment model remains an underdeveloped market with fragmented tooling for several reasons. &lt;/p&gt;

&lt;p&gt;One, edge infrastructure is complex, emphasizing fault tolerance and near-instant latency. Teams also need immediate visibility into device status, synchronization health, and data integrity across potentially thousands of endpoints. But edge devices, such as sensors and cameras, have limited compute and memory resources. &lt;/p&gt;

&lt;p&gt;Even enterprise-level control hosts often cap at 2-16GB of memory, significantly smaller than the memory centralized servers provide. Running inference on these devices will waste resources at their edge nodes and increase latency. Optimizing for real-time results becomes harder. &lt;/p&gt;

&lt;p&gt;However, that hardware baseline is improving. Advancements in edge computing, including the adoption of Ampere architecture, and the increasing prevalence of devices like the Jetson Nano, are expanding the amount of usable compute available at the edge. &lt;/p&gt;

&lt;p&gt;Another challenge is that edge computing is inherently distributed, with configurations varying across several hardware that operate independently. This hardware heterogeneity complicates data synchronization between diverse edge devices, especially as workloads shift across an unpredictable network. &lt;/p&gt;

&lt;p&gt;Nobody is building edge deployment models because of the operational complexity and specialization they require. Purpose-built databases like Qdrant add edge computing support, but still primarily operate under a centralized model. Edge-specific databases barely exist, with ObjectBox being a rare exception. The vendors who get it right must find a balance between strict latency requirements, hardware orchestration, consistent operational performance, and computational power.&lt;/p&gt;

&lt;p&gt;This table highlights where each available database deployment strategy thrives and where it falls short. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Deployment model&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Best for&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cloud-native&lt;/td&gt;
&lt;td&gt;Ready-to-use solution, faster time-to-success, auto-scaling&lt;/td&gt;
&lt;td&gt;High TCO at scale, cyberattack vulnerability, and increased latency with each network hop&lt;/td&gt;
&lt;td&gt;Teams seeking managed infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On-premises&lt;/td&gt;
&lt;td&gt;Development flexibility, full control and customization, data privacy&lt;/td&gt;
&lt;td&gt;High upfront fees, maintenance burden&lt;/td&gt;
&lt;td&gt;Organizations in regulated sectors with stringent data privacy requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edge/offline&lt;/td&gt;
&lt;td&gt;Near-instant latency, local data processing&lt;/td&gt;
&lt;td&gt;Emerging market, lacks infrastructure software&lt;/td&gt;
&lt;td&gt;Engineers building latency-critical AI applications or seeking decentralized data processing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hybrid&lt;/td&gt;
&lt;td&gt;Keeps control systems local while leveraging cloud analytics&lt;/td&gt;
&lt;td&gt;Management complexity, high latency&lt;/td&gt;
&lt;td&gt;Organizations seeking both cloud scalability and on-prem flexibility and security&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Engineers can explore a hybrid approach that combines cloud for elasticity, on-premises for flexibility, and edge for speed. &lt;/p&gt;

&lt;h2&gt;
  
  
  What To Do in 2026 (Decision Framework)
&lt;/h2&gt;

&lt;p&gt;The decision you make in 2026 can mean the difference between an AI application that thrives and one that struggles. Your architecture evaluation should prioritize your performance goals, scale, preferred cost model, existing stack, regulatory requirements, and data sovereignty needs. &lt;/p&gt;

&lt;h3&gt;
  
  
  If You're Starting Fresh
&lt;/h3&gt;

&lt;p&gt;Workload patterns should be your decision driver, not industry trends or scale panic. Is your AI application handling: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&amp;lt;10M vectors&lt;/strong&gt;: Start with PostgreSQL + pgvector, especially if your core data already lives in PostgreSQL. pgvector thrives with moderate data scale, and its hybrid search architecture improves retrieval quality for RAG applications. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;10M-100M vectors&lt;/strong&gt;: Both purpose-built databases and PostgreSQL's pgvectorscale can serve your workload, but with trade-offs. PostgreSQL + pgvectorscale works effectively at this scale, but performance might degrade with dynamic workloads or concurrent queries. Purpose-built outperforms in auto-scaling with increased data volume, and in maintaining persistent latency during traffic spikes. The trade-off is unpredictable cloud costs or operational overhead for self-hosted solutions. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;100M+ vectors&lt;/strong&gt;: Use specialized vector databases like Pinecone, Qdrant, and Milvus. They are designed for billion-scale vector operations, especially for high-throughput vector search (&amp;gt; 1,000 QPS) and high concurrent writes. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, if your application must run offline, the options on the market are still limited.&lt;/p&gt;

&lt;h3&gt;
  
  
  If You're Already Using a Vector Database
&lt;/h3&gt;

&lt;p&gt;Architect for expansion, but analyze your present situation. You should: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate cost trajectory&lt;/strong&gt;: Track your actual monthly spend, considering factors like data volume, QPS requirements, storage, and computation. At your projected growth, deduce what your current bill will look like in 12 months. If the numbers demand a more predictable cost model, consider reserved capacity or on-premises deployment. But if usage-based pricing better aligns with your budget and scale, continue with it. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmark query patterns&lt;/strong&gt;: Determine the dataset size your application processes monthly, and its average query latency. If you're hitting agent-scale queries, consider implementing optimization methods like semantic caching and quantization, or horizontal scaling techniques like sharding, which partitions agent memory, embeddings, and tool state, enabling parallel writes. For fluctuating workloads, future-proofing your vector database means designing for elastic scaling, which cloud solutions can provide.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider PostgreSQL migration if scale permits&lt;/strong&gt;: If growth is slow (for instance, 10M vectors, 200 QPS average, doubling every 6-12 months), migrating to PostgreSQL fits this scenario.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assess deployment model constraints&lt;/strong&gt;: Understand the strengths and limitations of your current runtime environment. Cloud vendors introduce non-linear costs and compliance overhead. On-premises setup presents high upfront expenses and limited elasticity. Edge deployment means limited resources and synchronization complexity. Being realistic about these constraints helps you validate that switching vector databases solves a real problem rather than creating new ones. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  If You Need Edge/On-premises
&lt;/h3&gt;

&lt;p&gt;Understand that while cloud vendors compete for hyperscale workloads, edge deployment remains largely unaddressed. As a result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate rare options&lt;/strong&gt;: Native edge deployment solutions are scarce, but some existing options include ObjectBox, an on-device NoSQL object database, and pgEdge, an extension of standard PostgreSQL, but for distributed setups. There are also industry-specific custom edge solutions, but each comes with trade-offs in maturity, scalability, or ecosystem support.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider using PostgreSQL on-premises with pgvector&lt;/strong&gt;: If you already have operational capacity, deploying PostgreSQL on-premises gives you total control over your database environment. The trade-off is manually optimizing for performance, monitoring, and security. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anticipate new market entrants&lt;/strong&gt;: The native edge deployment gap discussed earlier remains largely overlooked by major vendors, but emerging solutions, such as &lt;a href="https://www.actian.com/databases/vectorai-db/" rel="noopener noreferrer"&gt;Actian VectorAI DB&lt;/a&gt;, are addressing this gap with a database that accounts for the physical and network realities of offline scenarios. Specifically, Actian supports local data analytics in environments with unstable connectivity, such as store checkout hardware and factory-floor machinery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The flowchart below captures this decision framework at a glance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F96kenw5s53ovqgw67d4n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F96kenw5s53ovqgw67d4n.png" alt="Figure 4: Choosing a vector database in 2026" width="800" height="1375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;This analysis has spotlighted fundamental shifts in a market that focused squarely on purpose-built vector databases before 2025. &lt;/p&gt;

&lt;p&gt;In 2026, vectors are now a data type, and we are seeing more teams returning to the relational databases where their data already lives and leveraging their vector extensions. PostgreSQL is at the forefront of this renewed interest, providing the ACID-compliance, operational expertise, and flexibility that GenAI applications need. What this means for purpose-built solutions is that they now matter only for high-throughput, recall-sensitive systems. &lt;/p&gt;

&lt;p&gt;Meanwhile, even for high-throughput vector databases, AI agents’ query pressure is forcing a rethink of architectural design to support parallel writes and concurrent requests at a new scale. On top of this, fragmentation defines edge and on-premises deployments, with few straightforward approaches for processing data closer to the point of production.&lt;/p&gt;

&lt;p&gt;Looking ahead, the next shift will come from vendors that move beyond 2024's cloud-first database promotions to cater to the growing demand for offline-capable architecture. If you need to run AI workloads on-premises or at the edge, the options in 2026 are still limited, but that gap is starting to close with databases like Actian VectorAI DB. &lt;a href="https://www.actian.com/databases/vectorai-db/#waitlist" rel="noopener noreferrer"&gt;Join the waitlist&lt;/a&gt; for early access. &lt;/p&gt;

</description>
      <category>vectordatabase</category>
      <category>database</category>
      <category>vectoraidb</category>
    </item>
    <item>
      <title>Capalyze Complete Review: Features, Pros, and Cons</title>
      <dc:creator>Praise James</dc:creator>
      <pubDate>Fri, 26 Sep 2025 17:44:57 +0000</pubDate>
      <link>https://dev.to/techwithpraisejames/capalyze-complete-review-features-pros-and-cons-4oi9</link>
      <guid>https://dev.to/techwithpraisejames/capalyze-complete-review-features-pros-and-cons-4oi9</guid>
      <description>&lt;p&gt;Every company, business professional, data analyst, or researcher who wants to deliver tangible results needs data. According to NewVantage Partners, &lt;a href="https://www.businesswire.com/news/home/20220103005036/en/NewVantage-Partners-Releases-2022-Data-And-AI-Executive-Survey" rel="noopener noreferrer"&gt;3 in 5&lt;/a&gt; organizations are using data analytics to drive business innovation. &lt;/p&gt;

&lt;p&gt;Often, the data used for this analysis is obtained from the web using web scraping platforms. However, most available platforms focus on scraping raw data that requires further analysis to get useful business insights. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://capalyze.ai/home" rel="noopener noreferrer"&gt;Capalyze&lt;/a&gt; aims to address this issue by offering an Artificial Intelligence (AI) agent that takes natural language prompts and turns web data into business-ready spreadsheets. It also includes detailed reports and downloadable charts that can be shared with stakeholders. &lt;/p&gt;

&lt;p&gt;In this review, we examine Capalyze's features, strengths, limitations, and competitors. By the end, you'll know if Capalyze can support your team in improving efficiency, enabling faster data-driven decision-making, and boosting financial performance. &lt;/p&gt;

&lt;h2&gt;
  
  
  How Capalyze Supports Data Collection using AI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgmp795ok56x68yxzcy8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgmp795ok56x68yxzcy8.png" alt="Capalyze home page" width="800" height="355"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Caption: Capalyze home page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Capalyze builds upon &lt;a href="https://univer.ai/" rel="noopener noreferrer"&gt;Univer&lt;/a&gt;, an open-source SDK for creating spreadsheets, and uses AI to enable real-time public data collection and analysis. It does so in three key steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: The user provides the target URL or enters just their data request in plain English, depending on the mode they choose. &lt;/p&gt;

&lt;p&gt;Beginner Mode only accepts the target URL, while Expert Mode accepts detailed prompts, and Capalyze decides where to extract relevant data from. In the sample below, I used Beginner Mode to scrape content from the YouTube search results for iPhone 17.&lt;/p&gt;

&lt;p&gt;Note that you will need to install the Capalyze Chrome extension before you can perform a scraping task.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7p1y0eseg075vw6bo8b6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7p1y0eseg075vw6bo8b6.png" alt="Capalyze Beginner Mode" width="800" height="355"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Caption: Capalyze Beginner Mode&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckx80a82jb7uh4fgj5gl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fckx80a82jb7uh4fgj5gl.png" alt="Capalyze web scraping agent" width="800" height="439"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Caption: Capalyze web scraping agent&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Choose whether the result should include analysis. For this sample, I focused on the scraping component of Capalyze.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt;: Capalyze crawls the web page that contains the requested data and suggests fields for the table. The user can confirm or adjust the fields based on their preferences, as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgs9m5e1u4wtk7tmi79z9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgs9m5e1u4wtk7tmi79z9.png" alt="Using Capalyze to extract Youtube data" width="800" height="393"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Caption: Suggested fields from Capalyze&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I accepted the suggested fields and began extraction. As Capalyze goes to work, it provides a live preview of the data collection process, which you can stop and save at any time if you’ve gotten the amount of data you want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5hokh70pirftpf10hlj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc5hokh70pirftpf10hlj.png" alt="Youtube data on iPhone 17 from Capalyze" width="800" height="365"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Caption: Extracting data from Youtube search results&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I stopped the extraction after 193 items.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt;: Capalyze returns precise data that matches the user's query and turns it into spreadsheets or charts for organization and visualization, respectively. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flu6mryv2iaarp5cxmh8v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flu6mryv2iaarp5cxmh8v.png" alt="Capalyze spreadsheet powered by Univer" width="800" height="378"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Caption: Structured dataset from Capalyze AI agent&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Capalyze successfully provided a table containing 193 videos with 12 columns of information, including video titles, channels, view counts, upload dates, and other metadata, in approximately seven minutes. I asked the agent to create a chart on the verified channels and features using a bar chart.&lt;/p&gt;

&lt;p&gt;The result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0m2fvc1hjxulj763sfpu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0m2fvc1hjxulj763sfpu.png" alt="Capalyze bar chart" width="800" height="420"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Caption: Bar chart visualizing verified channels&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I loved being able to switch between different chart types. This is the same data as a Sankey chart:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tcxgvdpeg613oulkt04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tcxgvdpeg613oulkt04.png" alt="Sankey chart for data on verified channels" width="800" height="420"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Caption: Sankey chart vizualizing verified channels&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Capalyze also proactively generated a report on its key findings and business implications, without any specific request for this analysis. Here’s a snippet of the report:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ygh9kd9c8vn0e6fnaqy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ygh9kd9c8vn0e6fnaqy.png" alt="Capalyze visual report" width="659" height="669"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Caption: Capalyze report snippet&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To view the report and my full conversation with Capalyze's AI agent, use this &lt;a href="https://capalyze.ai/share/1971450539718025216" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Other features of Capalyze include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Basic and premium AI models&lt;/strong&gt;: Capalyze can automatically select the best model for a specific use case (basic), or users can choose advanced AI models (premium). The sample above used a Premium Model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local file analysis&lt;/strong&gt;: The agent allows teams to upload and analyze their local Excel and CSV files using AI models. If you need to, for example, understand the relationship between two columns in a file, you can use the Data Chat feature to converse with the agent.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F043hnvkp2e4bncf73ih5.png" alt="Capalyze Data Chat feature" width="800" height="389"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Caption: Capalyze Data Chat feature&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Text analysis&lt;/strong&gt;: Businesses can prompt Capalyze to perform sentiment analysis or provide suggestions on a dataset.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data enrichment&lt;/strong&gt;: Capalyze can enhance datasets (for example, adding a new column) of up to 30.000 rows, depending on your subscription plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Editable Excel files&lt;/strong&gt;: Teams can edit their extracted datasets within the Capalyze platform before downloading them to their local storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Businesses can use Capalyze to extract competitor information, product reviews, market trends, and social media analytics to understand customer behavior, refine marketing strategies, and anticipate market changes. &lt;/p&gt;

&lt;h2&gt;
  
  
  Strengths and Limitations of Capalyze
&lt;/h2&gt;

&lt;p&gt;Below are some areas where Capalyze  shines and where it might fall short:&lt;br&gt;
&lt;strong&gt;Strengths&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abstracts extensive coding and manual data processing by outsourcing the work to its AI engine&lt;/li&gt;
&lt;li&gt;Accepts natural language prompts, so teams don’t need to write complex Excel formulas or fragile scripts that break frequently when used on dynamic sites&lt;/li&gt;
&lt;li&gt;Extracts data from high-traffic sites like Amazon, social platforms like LinkedIn and TikTok, and Google products like Google Maps and Play Store&lt;/li&gt;
&lt;li&gt;Turns data into spreadsheets so businesses and researchers can quickly inspect the records or export them for further analysis&lt;/li&gt;
&lt;li&gt;Visualizes data as charts to identify trends and communicate insights to stakeholders, with support for 19 chart types &lt;/li&gt;
&lt;li&gt;Can generate a detailed report to accompany the chart &lt;/li&gt;
&lt;li&gt;Supports batch scraping from multiple URLs&lt;/li&gt;
&lt;li&gt;Provides a Chrome extension for easy plug-in to your desktop and browser fingerprinting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Capalyze does not provide detailed documentation on its product, so users who have questions may need to reach out via email or Discord. &lt;/li&gt;
&lt;li&gt;Users can only use the batch scraping feature for tables that include columns with links. &lt;/li&gt;
&lt;li&gt;The download and full-screen feature while viewing reports is still in development.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Despite these limitations, Capalyze simplifies data collection for businesses and enterprises through a no-code conversational workflow that returns visual and organized table summaries of web data. Let’s take a look at some competing tools and how they differ from Capalyze. &lt;/p&gt;

&lt;h2&gt;
  
  
  How Capalyze Compares to Other No-code Data Collection Platforms
&lt;/h2&gt;

&lt;p&gt;ParseHub, Octoparse, Webscraper.io, and Browse AI are some popular no-code/low-code parsing and scraping options available in the market. The following table compares the strengths and challenges of each tool, along with the data needs they best serve.  &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool/Platform&lt;/th&gt;
&lt;th&gt;Strengths&lt;/th&gt;
&lt;th&gt;Weaknesses&lt;/th&gt;
&lt;th&gt;Most Suitable For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ParseHub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;- Provides cloud-based data collection and storage  &lt;br&gt; - Includes features like IP rotation, scheduled collection, and API integration&lt;/td&gt;
&lt;td&gt;First-time users might experience an initial learning curve before becoming proficient&lt;/td&gt;
&lt;td&gt;Extracting data directly into cloud storage like Amazon S3 or Dropbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Octoparse&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;- Auto-generates selectors and builds workflow for scraping web pages in a point-and-click interface  &lt;br&gt; - Provides pre-built templates for popular sites like Amazon and eBay&lt;/td&gt;
&lt;td&gt;More complex scraping jobs like pagination and infinite scrolling will require the user to manually adjust the workflow&lt;/td&gt;
&lt;td&gt;Overcoming web scraping challenges like CAPTCHA solving, JavaScript rendering, and infinite scrolling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Webscraper.io&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free and configurable Chrome extension for scraping websites&lt;/td&gt;
&lt;td&gt;Since users need to create a sitemap to extract data, it requires understanding of page structure and parent/child relationships&lt;/td&gt;
&lt;td&gt;Simple web scraping tasks as it might break when extracting data from high-traffic or dynamic sites&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Browse AI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;- Enables bulk data extraction using “robots” that learn defined actions  &lt;br&gt; - Provides built-in scheduling feature for periodic scraping jobs&lt;/td&gt;
&lt;td&gt;The robots might break when site layout changes or while performing more complex extraction like crawling each subpage of a domain&lt;/td&gt;
&lt;td&gt;Real-time monitoring of web page changes and scraping data for large language models (LLMs)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Capalyze stands out by going beyond providing singular solutions for generating parsing scripts or training personalized scrapers. Rather, it abstracts the entire technicalities of the web data collection process and transforms raw data into actionable information, allowing businesses and analysts to understand the data at a glance. It also reduces the need for extensive downstream analysis by providing structured datasets and generating reports upfront. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you need a no-code data analytics tool to reduce time-to-insight, Capalyze provides an AI agent that crawls web pages and returns structured data, detailed reports, and informative charts. For businesses seeking to improve operational efficiency, customer engagement, and market strategy, begin with Capalyze's free trial and experiment with its features to determine if they align with your team's needs. &lt;/p&gt;

&lt;p&gt;Sign up to start using &lt;a href="https://capalyze.ai/home" rel="noopener noreferrer"&gt;Capalyze&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>nocode</category>
      <category>webscraping</category>
      <category>aiagents</category>
      <category>capalyze</category>
    </item>
  </channel>
</rss>
