flutter_edge_ai_rag 1.0.0 copy "flutter_edge_ai_rag: ^1.0.0" to clipboard
flutter_edge_ai_rag: ^1.0.0 copied to clipboard

Pluggable on-device RAG for Flutter Edge AI, with independent vector-store providers and embedders.

flutter_edge_ai_rag #

Pluggable, instance-scoped retrieval-augmented generation for flutter_edge_ai. The package owns RAG orchestration and contracts; storage implementations are supplied by separate packages such as flutter_edge_ai_qdrant and flutter_edge_ai_sqlite.

Coming from flutter_edge_ai 1.x, where RAG lived in core? See the 1.x → 2.0 migration guide.

Add this package and at least one storage provider:

dependencies:
  flutter_edge_ai_rag: ^1.0.0
  flutter_edge_ai_sqlite: ^2.0.0   # all six platforms
  # or flutter_edge_ai_qdrant: ^2.0.0 (native only)
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter_edge_ai_rag/flutter_edge_ai_rag.dart';
import 'package:flutter_edge_ai_sqlite/flutter_edge_ai_sqlite.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';

final rag = FlutterEdgeAiRag(
  providers: [const SqliteVectorStoreProvider()],
);

// An absolute path on native, a plain name on Web. path_provider has no Web
// implementation, so it is only called on native.
Future<String> ragLocation(String name) async => kIsWeb
    ? name
    : p.join((await getApplicationDocumentsDirectory()).path, name);

final location = await ragLocation('knowledge.db');

if (!rag.canOpen(
  VectorStoreSpec(providerId: 'sqlite', location: location),
)) {
  throw UnsupportedError('SQLite RAG is unavailable on this platform');
}

final index = await rag.open(
  spec: VectorStoreSpec(
    providerId: 'sqlite',
    location: location,
    filterSchema: FilterSchema(fields: [
      FilterField(name: 'topic', type: FilterFieldType.string),
    ]),
  ),
  activeEmbedderProfileId:
      'embeddinggemma-300m-seq256-mp-rev-29888fcee321-'
      'retrieval-prefix-meanpool-l2-v1',
);

await index.addText(
  id: 'intro',
  content: 'Flutter runs on six platforms.',
  metadata: '{"topic":"flutter"}',
);
final hits = await index.searchText(
  query: 'Where does Flutter run?',
  filter: Filter(
    must: [FieldEquals(key: 'topic', value: 'flutter')],
  ),
);
await index.flush();
await index.dispose();

location is an absolute path on native — a database file for SQLite, a directory for Qdrant; build it from getApplicationDocumentsDirectory() — and a plain name on Web.

open() pins the embedder that is active at that moment: install the embedder before opening the index, and after switching embedders open a new index at a new location. The default embedder is borrowed from FlutterEdgeAi.getActiveEmbedder(). This package never closes that core-owned model. Its activeEmbedderProfileId is explicit because a mutable file path or download URL is not a content identity. Use a stable, versioned ID that covers the weights and the tokenizer, pooling, normalization, and document/query prefix contract that define the embedding space. Without that ID, vector-only use of an already-bound store remains available, but the first text operation fails instead of inventing an identity.

Pass a custom RagEmbedder to open() when RAG must be initialized independently from the main Flutter Edge AI runtime. Pure addVector and searchVector workflows do not resolve an embedder at all, but they require an explicit profile when a new location is opened:

final vectors = await rag.open(
  spec: VectorStoreSpec(
    providerId: 'sqlite',
    location: await ragLocation('vectors.db'),
  ),
  embeddingProfile: EmbeddingProfile(
    id: 'embeddinggemma-300m-v1',
    dimension: 768,
  ),
);

An independent text pipeline supplies its own borrowed embedder:

class AppEmbedder implements RagEmbedder {
  AppEmbedder(this.model);

  final MyEmbeddingModel model;

  @override
  Future<EmbeddingProfile> get profile async => EmbeddingProfile(
    id: 'my-embedder-weights-tokenizer-pooling-prefix-v1',
    dimension: 384,
  );

  @override
  Future<List<double>> embedDocument(String text) =>
      model.embed(text, prefix: 'document: ');

  @override
  Future<List<double>> embedQuery(String text) =>
      model.embed(text, prefix: 'query: ');
}

final customIndex = await rag.open(
  spec: VectorStoreSpec(
    providerId: 'sqlite',
    location: await ragLocation('custom-v1.db'),
  ),
  embedder: AppEmbedder(myEmbeddingModel),
);

One RagIndex pins one EmbeddingProfile. Use a different persistent location for each embedding profile; mixing vectors from different models is invalid even when their dimensions happen to match. Providers persist this binding beside the vectors and refuse to overwrite it, so the same safety rule survives app restarts. A vector operation on an unbound index fails until a text operation binds its embedder or embeddingProfile is passed to open().

An existing nonempty database without profile metadata is treated as legacy and is never adopted silently. Migration requires the caller to attest the model identity explicitly; the package also verifies its dimension:

final migrated = await rag.open(
  spec: VectorStoreSpec(
    providerId: 'sqlite',
    location: await ragLocation('legacy.db'),
    allowLegacyProfileAdoption: true,
  ),
  embeddingProfile: knownLegacyProfile,
);

RagIndex owns and closes its vector store. The embedder is always borrowed. Normal reads and writes may overlap; flush, clear, and dispose are exclusive barriers. Dispose rejects new work immediately and waits for work already accepted by the index. clear() removes documents but intentionally keeps the persistent profile binding: one location remains one embedding space for its lifetime.

Keep one app-owned index per location. On Web, SQLite enforces that rule with an exclusive Web Lock, so make open() single-flight and share the returned future rather than opening from multiple widgets. At shutdown, dispose every RagIndex first, then call FlutterEdgeAi.dispose() or dispose a custom embedder that the indexes borrowed.

0
likes
150
points
--
downloads

Documentation

API reference

Publisher

verified publishersashadenisov.dev

Weekly Downloads

Pluggable on-device RAG for Flutter Edge AI, with independent vector-store providers and embedders.

Homepage
Repository (GitHub)
View/report issues

Topics

#rag #vector-search #embeddings #on-device #ai

License

MIT (license)

Dependencies

flutter_edge_ai

More

Packages that depend on flutter_edge_ai_rag