Pierwsze kroki z Lokalnym AI

Zbuduj własne, prywatne AI. Zobacz kompleksowe zestawienie poradników – od instalacji pierwszej aplikacji po zaawansowanych agentów. Sprawdź poradnik

Architektura i implementacja wtyczki Joplin AI Assistant: Prywatne modele językowe w ekosystemie notatek

implemetnacja  1
Streszczenie AI

Joplin AI Assistant to otwartoźródłowa wtyczka, która bezpiecznie rozszerza zbiór notatek o generatywną sztuczną inteligencję, łącząc lokalne silniki LLM (np. Ollama) z zdalnymi endpointami zgodnymi z OpenAI API w paradygmacie local‑first. Dzięki modułowej architekturze w TypeScript, deterministycznym sanitizatorom, oraz mechanizmom RAG i auto‑tagowania, użytkownik może w czasie rzeczywistym pobierać weryfikowane informacje, automatycznie klasyfikować dokumenty i generować strukturalne spisy treści, a wszystko to przy zachowaniu izolacji GUI oraz minimalizacji ryzyka halucynacji. Wtyczka dba o bezpieczeństwo danych poprzez „keep‑alive”‑free połączenia, tokenizację mediów, oraz CSP‑opracowane środowisko Webview, co gwarantuje stabilną, przyjazną dla użytkownika integrację AI z aplikacją Joplin.

Spis treści:
image

Projekt Joplin AI Assistant to otwartoźródłowa wtyczka rozszerzająca ekosystem aplikacji Joplin o zaawansowane możliwości generatywnej sztucznej inteligencji z zachowaniem paradygmatu local-first. Rozwiązanie integruje lokalne środowiska uruchomieniowe LLM (np. Ollama) oraz zdalne punkty końcowe zgodne ze standardem OpenAI API z wewnętrznym API danych notatnika. Architektura wtyczki kładzie szczególny nacisk na deterministyczne bezpieczeństwo danych, bezstratność operacji edycyjnych oraz izolację środowiska wykonawczego interfejsu graficznego.

Architektura modułowa i warstwa integracji z Joplin API

Wtyczka została zrealizowana w języku TypeScript i skompilowana do pojedynczego pakietu dystrybucyjnego za pomocą bundlera Webpack. Całość logiki biznesowej opiera się na oficjalnej bibliotece @joplin/api, która udostępnia interfejsy do manipulacji strukturą bazy SQLite, drzewem notatników, edytorem tekstu oraz panelami bocznymi w środowisku Electron. Architektura systemu została podzielona na ściśle odseparowane warstwy odpowiedzialności:

  • Warstwa kontrolera i punkt wejścia: Odpowiada za rejestrację poleceń w palecie komend, pozycji menu narzędziowego, przycisków paska edytora oraz subskrypcję zdarzeń cyklu życia aplikacji (m.in. zmiana zaznaczenia notatki, modyfikacja treści).
  • Warstwa usług pośredniczących (Services): Hermetyzuje komunikację zewnętrzną oraz operacje na danych. W jej skład wchodzą moduły odpowiedzialne za komunikację z modelami sztucznej inteligencji, silnik wyszukiwania sieciowego, zarządcę operacji na notatkach, serwis etykietowania oraz mechanizm blokad współbieżności.
  • Warstwa widoku (Views): Implementuje panel boczny w postaci odizolowanego komponentu Webview z własnym cyklem życia i komunikacją asynchroniczną opartą na kolejce wiadomości.
  • Warstwa bezpieczeństwa i zarządzania zadaniami: Nadzoruje atomowość modyfikacji tekstu, mechanizmy tworzenia migawek bezpieczeństwa oraz zapobieganie zjawiskom hazardu (race conditions) podczas długotrwałych operacji asynchronicznych.

Podwójny silnik wnioskowania LLM i optymalizacja protokołu HTTP

Podstawowym modułem komunikacyjnym wtyczki jest dedykowany serwis wykonawczy, który implementuje uniwersalny interfejs zapytań do modeli językowych. System obsługuje dwa tryby pracy: lokalny oparty na instancji Ollama oraz zdalny kompatybilny ze specyfikacją Chat Completions API. Adresy bazowe podawane przez użytkownika podlegają automatycznej normalizacji ścieżek URI, dzięki czemu aplikacja samodzielnie koryguje brakujące sufiksy punktów końcowych.

Podczas implementacji komunikacji z lokalnym demonem Ollama rozwiązano istotny problem wydajnościowy związany z mechanizmem Keep-Alive biblioteki HTTP w środowisku Node.js. Przy domyślnej konfiguracji gniazda sieciowe potrafiły pozostawać w stanie oczekiwania, powodując zawieszanie kolejnych zapytań po przetworzeniu odpowiedzi przez model. Problem wyeliminowano poprzez twarde wymuszenie nagłówka:

Connection: close

Dzięki temu gniazdo TCP jest zamykane niezwłocznie po odebraniu kompletnego strumienia JSON, co gwarantuje stabilność sesji i natychmiastowe zwalnianie zasobów po stronie lokalnego serwera LLM.

Przed przekazaniem treści notatki do modelu językowego moduł wykonuje rygorystyczną sanityzację wejścia. Wszelkie ciężkie elementy binarne, w tym osadzone obrazy w formacie Base64 oraz odnośniki do wewnętrznych zasobów multimedialnych Joplina, są wycinane i zastępowane zwięzłymi tokenami zastępczymi. Długość bufora tekstowego podlega obcięciu zgodnie z zależnością:

L_{\text{effective}} = \min(L_{\text{raw}} – L_{\text{media}}, L_{\text{max}})

gdzie L_{\text{max}} = 8000 znaków stanowi domyślny limit kontekstowy chroniący przed przepełnieniem pamięci operacyjnej modelu i gwałtowną degradacją czasu inferencji na maszynach lokalnych.

Zestawienie techniczne komponentów wtyczki

Kluczowe parametry techniczne poszczególnych modułów systemu przedstawia poniższa tabela:

Komponent
Protokół / API
Format danych wejście/wyjście
Główne zabezpieczenie
Komunikacja LLM HTTP/REST (Ollama / OpenAI spec) JSON (Chat Completion) Limit znaków, usuwanie multimediów, nagłówek Connection: close
Wyszukiwarka RAG HTTPS POST (Tavily, Serper.dev) JSON → Ustrukturyzowany Markdown z URL Maskowanie kluczy API, brak ekspozycji zapytań w logach
Panel boczny Webview Dwukierunkowe Electron IPC / RPC JSON Payload → DOM Sanityzacja encji HTML (ochrona przed Stored XSS)
Zarządca zadań Wewnętrzna maszyna stanów w TypeScript Flagi semafora (Boolean) Blokada współbieżności operacji modyfikujących notatki
Kopia bezpieczeństwa Joplin Data API (joplin.data) Wewnętrzne obiekty bazy danych SQLite Wymuszony synchroniczny zapis kopii przed mutacją tekstu

Architektura interfejsu Webview: Izolacja, RPC i dwa tryby pracy

Interfejs graficzny asystenta osadzony jest w bocznym panelu aplikacji, renderowanym wewnątrz ramki Electron Webview podlegającej restrykcyjnej polityce Content Security Policy (CSP). Z tego powodu skrypt widoku musi być kompilowany i rejestrowany jako osobny zasób, a cała komunikacja ze środowiskiem wtyczki odbywa się za pośrednictwem asynchronicznych komunikatów RPC.

Aby zapobiec niepożądanemu zjawisku migotania elementów interfejsu przy częstym odpytywaniu stanu (np. podczas pisania w edytorze notatki), w kodzie widoku wdrożono mechanizm porównywania skrótów stanu (dirty-checking). Drzewo DOM jest aktualizowane wyłącznie wtedy, gdy odebrana serializacja danych różni się od stanu zapisanego w pamięci podręcznej komponentu. Układ panelu wykorzystuje sztywne pozycjonowanie sekcji nagłówka i stopki z dynamicznym przeliczaniem wysokości kontenera wiadomości w zdarzeniu zmiany rozmiaru okna, co eliminuje problem obcinania pola tekstowego w ramce okna.

Panel asystenta oferuje dwa fundamentalne tryby operacyjne:

  • Tryb pytania (Ask Q&A Mode): Tryb całkowicie pasywny względem bazy danych. Model analizuje kontekst otwartej notatki oraz opcjonalne dane z wyszukiwarki sieciowej, generując odpowiedzi w dymkach czatu. Użytkownik zachowuje pełną kontrolę i może manualnie zdecydować o wklejeniu wygenerowanego fragmentu w miejscu kursora lub dołączeniu go na końcu dokumentu.
  • Tryb edycji (Edit Note Mode): Tryb bezpośredniej manipulacji treścią. Asystent dokonuje przepisania, korekty lub restrukturyzacji dokumentu i natychmiastowo nadpisuje bufor edytora poprzez API Joplina. Aby zapewnić bezpieczeństwo pracy, każda wygenerowana odpowiedź przechowuje w metadanych pierwotny stan notatki sprzed modyfikacji (originalBody), udostępniając pod dymkiem przycisk natychmiastowego wycofania zmian. Ponadto wszystkie modyfikacje są rejestrowane w natywnej historii wersji aplikacji Joplin.

Pobieranie wiedzy w czasie rzeczywistym (RAG)

Wtyczka implementuje lekki mechanizm generowania wspomaganego wyszukiwaniem (Retrieval-Augmented Generation). Gdy użytkownik zaznaczy fragment tekstu w edytorze lub w zapytaniu czatu użyje słów kluczowych wskazujących na potrzebę weryfikacji faktów, system aktywuje integrację z zewnętrznym silnikiem wyszukiwania.

Wspierani są dwaj dostawcy wyszukiwania: Tavily oraz Serper.dev. Usługa pobiera najbardziej trafne wyniki organiczne (nagłówek, fragment tekstu oraz adres źródłowy) i przekształca je w jednolity blok kontekstowy wstrzykiwany do promptu systemowego. W wytycznych dla modelu wymuszane jest stosowanie przypisów numerycznych [1], [2] oraz generowanie końcowej listy referencji z pełnymi odnośnikami URL. Pozwala to na eliminację halucynacji w przypadku notatek o tematyce bieżącej lub dynamicznie zmieniających się zagadnieniach technicznych.

Asynchroniczny auto-tagging i rekurencyjna agregacja bazy wiedzy

Organizacja dużych zbiorów notatek została zautomatyzowana za pomocą dwóch dedykowanych serwisów przetwarzania wsadowego:

  1. 01
    Inteligentne etykietowanie notatek: Moduł tagowania może pracować w trybie manualnym (uruchamianym z poziomu menu lub panelu ustawień z podglądem postępu) oraz w trybie autonomicznym. W trybie automatycznym procesor w tle wybudza się w interwale 15-minutowym i analizuje bazę dokumentów pod kątem spełnienia kryterium dojrzałości: t_{\text{current}} – t_{\text{created}} \ge 24\,\text{h}
    Opóźnienie wynoszące 24 godziny od utworzenia notatki zapobiega przedwczesnemu kategoryzowaniu dokumentów roboczych, które są jeszcze w trakcie redagowania przez użytkownika. Algorytm przed wysłaniem zapytania do LLM pobiera pełną mapę istniejących w bazie tagów i instruuje model, aby priorytetyzował już istniejące słowa kluczowe. Zapobiega to powstawaniu synonimów oraz rozrostowi niespójnych etykiet różniących się jedynie wielkością liter. Przetworzone identyfikatory notatek są periodycznie zapisywane w konfiguracji wtyczki (co 5 przetworzonych pozycji), co zapewnia odporność na nagłe zamknięcie aplikacji.
  2. 02
    Rekurencyjna generacja spisu zawartości: Serwis indeksowania analizuje pełne drzewo notatników, z wyłączeniem kosza systemowego oraz dedykowanego folderu spisu. System pobiera hierarchię za pomocą stronicowanych zapytań API, buduje strukturę drzewiastą węzłów, a następnie dla każdej niepustej notatki generuje skondensowane, jednozdaniowe streszczenie za pomocą dedykowanego promptu systemowego. Wynikiem jest zunifikowany dokument Markdown odzwierciedlający strukturę folderów, w którym opisy notatek prezentowane są w postaci ustrukturyzowanych cytatów. System gwarantuje idempotencję operacji: istniejący folder spisu oraz wcześniejsze notatki indeksowe są konsolidowane i aktualizowane bez tworzenia duplikatów.

Środki cyberbezpieczeństwa i ochrona integralności danych

Z punktu widzenia bezpieczeństwa aplikacji desktopowych integracja modeli LLM niesie ze sobą ryzyko wstrzyknięcia złośliwego kodu oraz przypadkowej utraty danych użytkownika. W projekcie zaimplementowano szereg rygorystycznych mechanizmów obronnych:

  • Ochrona przed atakami XSS w środowisku Electron: Ponieważ treść notatek może zawierać niesprawdzone dane pochodzące z zewnętrznych źródeł, wszystkie dynamiczne parametry wstrzykiwane do kodu HTML panelu bocznego (m.in. tytuły notatek, nazwa wybranego modelu, etykiety językowe) podlegają obowiązkowemu uciekaniu encji HTML (zamiana znaków &, <, >, ", '). Uniemożliwia to wykonanie wstrzykniętego skryptu JavaScript w kontekście uprzywilejowanego okna Webview.
  • Bezpieczeństwo danych uwierzytelniających: Wszelkie klucze API (dla zdalnych modeli, serwisów Tavily i Serper) są definiowane w ustawieniach z parametrem secure: true, co wymusza ich przechowywanie w bezpiecznym, szyfrowanym magazynie kluczy systemu operacyjnego (np. Keychain w macOS czy DPAPI w Windows). Dodatkowo wtyczka analizuje protokół zdalnego adresu i emituje ostrzeżenie w konsoli przy próbie przesyłania klucza Bearer przez nieszyfrowane połączenie HTTP.
  • Zasada gwarantowanej kopii zapasowej: Żadna funkcja modyfikująca tekst w edytorze (korekta gramatyczna, formatowanie Markdown, wstrzykiwanie wyników wyszukiwania) nie może zostać wykonana bez uprzedniego utworzenia fizycznej kopii dokumentu. Kopia jest zapisywana w dedykowanym folderze kopii zapasowych pod nazwą zawierającą znacznik [Oryginał]. W przypadku niepowodzenia operacji zapisu kopii, modyfikacja przez LLM jest natychmiastowo przerywana.
  • Blokada współbieżności zadań (TaskLockService): Aby wyeliminować ryzyko uszkodzenia danych przy jednoczesnym wywołaniu operacji z paska narzędzi i działaniu procesu w tle, zaimplementowano scentralizowany semafor blokujący. Jeśli zadanie o wysokim priorytecie (np. generowanie spisu notatników) jest aktywne, kolejne żądania są odrzucane z czytelnym komunikatem błędu, a procesy tła są bezpiecznie wstrzymywane.

Praktyczne zastosowania w inżynierii wiedzy

Zaimplementowane w projekcie mechanizmy techniczne rozwiązują kluczowe problemy związane z utrzymaniem dużych baz wiedzy typu Second Brain oraz dokumentacji inżynieryjnej:

  • Praca z danymi poufnymi w trybie offline: Dzięki pełnemu wsparciu dla lokalnego demona Ollama (np. modele z rodziny Llama 3, Qwen 2.5 czy DeepSeek), inżynierowie i badacze mogą przetwarzać dokumentację projektową, notatki ze spotkań czy kody źródłowe w środowisku całkowicie odciętym od Internetu (air-gapped), spełniając restrykcyjne wymogi zgodności RODO/GDPR i polityk korporacyjnych.
  • Eliminacja długu organizacyjnego w notatkach: Połączenie automatycznego generowania spisu treści z asynchronicznym etykietowaniem rozwiązuje powszechny problem fragmentacji informacji. Baza wiedzy jest nieustannie porządkowana w tle bez konieczności ręcznego przypisywania metadanych do każdego nowo utworzonego pliku.
  • Weryfikacja i synteza źródeł: Integracja z silnikami wyszukiwania bezpośrednio w oknie edytora skraca czas weryfikacji faktów technicznych. Zamiast przełączania kontekstu do przeglądarki, użytkownik otrzymuje zwięzłą syntezę danych z bezpośrednimi odnośnikami do specyfikacji i dokumentacji źródłowej.

Źródła

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Wymagane pola są oznaczone *

Powiązane posty

Powrót do góry