Start Debugging

Flutter 3.x ganha um novo bloco de construção de "RAG offline": `mobile_rag_engine` (núcleo em Rust)

mobile_rag_engine traz RAG no dispositivo para Flutter com um núcleo em Rust, embeddings ONNX, busca vetorial HNSW e armazenamento SQLite. Um olhar prático sobre a API, o fluxo de integração e as restrições de distribuição.

RAG no dispositivo está aparecendo no mundo Flutter como algo que dá para realmente enviar, não só demonstrar. O mobile_rag_engine foi publicado no pub.dev há poucos dias e é opinativo do jeito certo: um núcleo em Rust para o trabalho pesado, uma API Flutter para integração e binários pré-compilados para que você não precise configurar Rust, Cargo ou o Android NDK só para experimentar.

Se você queria busca semântica dentro de um app sem enviar dados do usuário para um servidor, este é o formato que vale a pena estudar.

O que ele oferece (em termos práticos)

O pacote se posiciona como um motor RAG totalmente local:

Você ainda precisa enviar um modelo. A diferença é que, uma vez feito isso, o loop de recuperação é local e previsível.

Um fluxo minúsculo de ponta a ponta (adicionar docs, construir índice, buscar)

O quick start do README já está próximo do que você vai querer em um app real. Aqui está uma versão adaptada que torna o passo de “bytes do modelo” explícito para Flutter 3.x:

import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:mobile_rag_engine/mobile_rag_engine.dart';

Future<Uint8List> loadModelBytes(String assetPath) async {
  final data = await rootBundle.load(assetPath);
  return data.buffer.asUint8List();
}

Future<void> main() async {
  const dbPath = 'rag.sqlite';

  await RustLib.init(
    externalLibrary: ExternalLibrary.process(iKnowHowToUseIt: true),
  );

  await initTokenizer(tokenizerPath: 'assets/tokenizer.json');

  final modelBytes = await loadModelBytes('assets/model.onnx');
  await EmbeddingService.init(modelBytes);

  final docEmbedding = await EmbeddingService.embed('Flutter is a UI toolkit.');
  await addDocument(
    dbPath: dbPath,
    content: 'Flutter is a UI toolkit.',
    embedding: docEmbedding,
  );

  await rebuildHnswIndex(dbPath: dbPath);

  final queryEmbedding = await EmbeddingService.embed('What is Flutter?');
  final results = await searchSimilar(
    dbPath: dbPath,
    queryEmbedding: queryEmbedding,
    topK: 5,
  );

  print(results.first);
}

Esse é o loop central de que você precisa para recursos de “base de conhecimento offline”: busca em central de ajuda, notas pessoais, documentos corporativos sincronizados no dispositivo e qualquer app em que “mandar texto do usuário para um backend” não rola.

Restrições de distribuição para pensar com antecedência

O tamanho do modelo é design de produto

Mesmo modelos INT8 podem ser grandes. Decida se você envia o modelo no bundle do app, baixa na primeira execução ou usa entrega de assets específica da plataforma.

Custo de inicialização e caminho quente

A geração de embeddings é o passo caro. Sua UI deve ser honesta sobre isso: indexação em segundo plano, progresso e cache. O passo de recuperação (busca HNSW) costuma ser barato em comparação.

Se quiser as referências canônicas:

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Voltar