nessie

Nessie diegimas

Paleiskite Nessie savo pasirinktoje infrastruktūroje — nuo vieno kompiuterio iki valdomo debesies.

Ko reikia prieš pradedant

Nessie yra pnpm monorepo, sudarytas iš Node paslaugų ir dviejų statinių paketų. Kaip ją bepaleistumėte, pirmiausia turi būti tie patys keturi dalykai.

  • PostgreSQL su pgvector. Tai privaloma ir negali būti pakeičiama kitu variantu – migracijos vykdo CREATE EXTENSION vector ir sukuria vector(1024) stulpelius. Gamyboje naudojamas pgvector/pgvector:pg17.
  • Node 22 ir pnpm. Kiekvienas Dockerfile aplanke infrastructure/docker/ kuriamas remiantis node:22-slim, o repozitorijos šakninis package.json fiksuoja paketų tvarkyklę (pnpm@10.22.0).
  • Su OpenAI suderinamas modelio galinis taškas ir jo raktas. Per jį eina ir agentai, ir įterpimai (embeddings). Žr. „Modelio išvedimo konfigūravimas“ žemiau.
  • S3 suderinama objektų saugykla, reikalinga bet kuriam diegimui, kuris nėra vietinis kūrėjo diegimas. Įkėlimai į vietinį diską atmetami, kai veikia ne local režimas, ir tas atmetimas yra paleidimo klaida, o ne sumažintų galimybių paleidimas – žr. „Vienas kompiuteris ar valdomas debesis“.

Docker ir atvirkštinis tarpinis serveris reikalingi konteinerių keliui, aprašytam toliau, o domenas ir TLS – viskam, ką pasiekia internetas.

Techninės įrangos dydis – minimalus procesoriaus, atminties ir disko kiekis tam tikram žmonių skaičiui – repozitorijoje niekur nenurodytas, todėl ir šis puslapis jo nenurodo.

Komponentai ir tai, kaip jie susijungia

KomponentasKas tai yraĮeinantis srautas
api/HTTP/WebSocket API, pagrįstas Fastify. Visi klientai bendrauja tik su ja.Taip
worker/Agentų valdymas ir foninės užduotys. Skaito užduočių eilę; prievado neatidaro.Ne
admin/Produkto sąsaja – statinis paketas, sukurtas su Vite ir pateikiamas per nginx.Taip
web/Viešoji svetainė. Statinė, neprivaloma ir nesusijusi su produkto veikimu.Taip
PostgreSQLDuomenų bazė, užduočių eilė ir realaus laiko kanalas – visi trys vienu metu.Ne
Objektų saugyklaPriedai, avatarai ir žinių bazės failai. S3 suderinama; gamyboje naudojama MinIO.Ne
gateway/Pasirenkamas push pranešimų tarpininkas APNs ir FCM. Neveikia, kol jo sąmoningai neįjungiate.Taip

API ir darbuotojas yra vienas konteinerio vaizdas. Abu paketai glaudžiai susiję, todėl Dockerfile.app visus paketus sukuria vieną kartą, o darbuotojo konteineris perrašo komandą į node worker/dist/index.js. local režime atskiro darbuotojo konteinerio visai nėra: API savo procese paleidžia įterptą darbuotoją.

Redis nenaudojamas. Užduočių eilė ir realaus laiko perdavimas abu veikia per PostgreSQL – tai sąmoningas pasirinkimas, o ne praleidimas. Google Cloud medis dėl to paties ištrina savo Pub/Sub ir Redis modulius.

Prievadai

Vietinėje kūrimo aplinkoje pagal numatytuosius nustatymus API veikia prievade 5454, administravimo sąsaja – 5455. Kopija gali turėti savo porą, jei aplinkoje arba repozitorijos faile .env nustatysite NESSIE_API_PORT ir NESSIE_ADMIN_PORT; visi repozitorijos įrankiai, įskaitant naršyklės testų rinkinius, skaito tas pačias dvi reikšmes. Porą pasirinkite prieš paleisdami ir jos nekeiskite: perkėlus veikiančią paslaugą į kitą prievadą, administravimo sąsaja kalbasi ne su tuo API.

Gamyba yra kitokia ir nuo šios taisyklės nepriklauso. API konteineris klauso vidiniu prievadu 5554 (nustatytu per NESSIE_API_PORT), o push tarpininkas – prievadu 5556; abu veikia už atvirkštinio tarpinio serverio.

Paleidimas vienoje mašinoje kūrimui

Repozitorijoje yra Compose failas, kuriame yra tik duomenų bazė – to pakanka vietiniam darbo ciklui.

pnpm install
docker compose -f infrastructure/compose/docker-compose.yml up -d postgres

Šis konteineris publikuoja Postgres prievade 55432, o naudotojas, slaptažodis ir duomenų bazė visi pavadinti nessie. Prisijungimo eilutę įrašykite į .env failą repozitorijos šakniniame aplanke – API kūrimo skriptas jį nuskaito. Tada pritaikykite migracijas ir vieną kartą sukurkite darbuotoją, nes vietiniu režimu API darbuotoją įkelia iš jo sukurto dist katalogo:

DATABASE_URL=postgresql://nessie:nessie@localhost:55432/nessie

pnpm --filter @nessie/api prisma:migrate:deploy
pnpm --filter @nessie/worker build
pnpm dev

pnpm dev paleidžia API ir administravimo sąsają lygiagrečiai su automatiniu perkrovimu, prievaduose 5454 ir 5455. Patikrinkite, ar API atsako į GET /api/health.

Postgres ir pgvector reikalavimas

Trys plėtiniai sukuriami pačiomis migracijomis – vector, pg_trgm ir pgcrypto – todėl vaidmuo, kuris jas vykdo, turi turėti teisę kurti plėtinius. Valdomame Postgres tai pirmas dalykas, kurį verta patikrinti.

Vektoriaus plotis yra schemos dalis, o ne nustatymas. thoughts.embedding, thought_recalls.query_embedding ir knowledge_page_chunks.embedding yra vector(N) stulpeliai, o N vienu kartu nurodytas kaip EMBEDDING_DIMENSIONS faile packages/schemas/src/embedding.ts – šiuo metu 1024, t. y. gamyboje naudojamo įterpimų modelio natūralus plotis. Kiekviena įterpimo užklausa siunčia tą plotį, todėl tiekėjas, kuris atsakytų kitu, nutrūksta garsiai, o ne įrašo vektorių, kurių duomenų bazė nepriima. Pereiti prie kito pločio įterpimų modelio reiškia pakeisti šią konstantą, parašyti migraciją, kuri perkuria tris stulpelius, ir atlikti pakartotinį įterpimą: skirtingo pločio vektorių konvertuoti neįmanoma, todėl migracija juos anuliuoja, o ne apkarpo.

Jei Nessie veikia šalia kitų programų bendrame Docker tinkle, duomenų bazės konteineriui suteikite kitokį pavadinimą. Projekto Compose paslauga vadinasi nessie-postgres ir niekada nevadinasi postgres, nes paslaugos pavadinimas tampa DNS pseudonimu bendrame tinkle, o susidūrimas priverčia postgres:5432 ciklinai nukreipti užklausas į dvi duomenų bazes.

Konfigūracija

Veikimo konfigūracija yra sluoksniuota: nessie.config.json failas prijungiamas tik skaitymui prie API ir darbuotojo, o aplinkos kintamieji užrašomi viršuje. Jų atitikmenį nurodo ConfigEnvMap faile packages/config – tai autoritetingas sąrašas.

NESSIE_MODE parenka diegimo tipą: local (numatytasis ir kūrėjo kelias), hosted arba selfHosted – pastarąjį nustato savarankiškai diegiamas įdiegimas. Jis išjungia kūrėjo prisijungimą ir reikalauja CORS leidžiamųjų kilmių sąrašo.

Šie nustatymai yra tie, be kurių selfHosted diegimas nepasileis arba neveiks:

KintamasisKodėl
DATABASE_URL / NESSIE_DB_URLPostgres prisijungimo eilutė.
NESSIE_AUTH_SECRET32 baitai šešioliktainės formos (openssl rand -hex 32). Pasirašo sesijas ir pradinės sąrankos raktus. Už local režimo ribų be jo paleidimas nutrūksta; ši reikšmė turi būti ta pati kiekvienoje replikoje ir visuose diegimuose, nes kitaip kiekviename išleidime nutrūksta visos sesijos.
NESSIE_ENCRYPTION_KEY_RING, NESSIE_ENCRYPTION_ACTIVE_KEY_VERSIONJSON raktų žiedas ir etiketė, pasirenkanti aktyvų šakninį raktą; už local režimo ribų privalomi. Tai atskiras šakninis raktas nuo pasirašymo paslapties – raktų žiedas šifruoja kiekvieną ilgalaikę paslaptį, kurią Nessie saugo. Nenaudokite vieno kaip kito.
NESSIE_STORAGE_PROVIDERTuri būti s3. filesystem yra numatytoji reikšmė ir atmetama hosted bei selfHosted režimuose, todėl diegimas, kuriame nieko nenustatyta, nepasileidžia, o ne įrašo įkėlimų į diską, kurio nepasiekia joks kitas konteineris.
NESSIE_CORS_ORIGINSAdministratoriaus kilmė (origin). Administravimo sąsaja ir API yra atskiros kilmės, o API turi leisti tą, kurią aptarnauja.
NESSIE_API_PUBLIC_URL, NESSIE_ADMIN_PUBLIC_URLNaudojami OAuth peradresavimo URI, kai jie kuriami ne HTTP užklausos metu. Be pirmojo API užklausos metu meta klaidą.
NESSIE_MODEL_PROVIDER, _BASE_URL, _API_KEYKur nukreipiamas išvedimas. Žr. žemiau.

infrastructure/compose/.env.prod.example rodo visų jų tikslią formą, o pasirenkami blokai – objektų saugykla, paslapčių saugykla, SSO, susietas paštas – pažymėti komentarais vietoje. Pilnas katalogas, įskaitant visus pasirenkamus nustatymus, yra docs/deployment/configuration.md.

Diegimas su Docker Compose

Nukopijuokite .env.prod.example į .env šalia docker-compose.prod.yml ir užpildykite; tada paleiskite duomenų bazę, sukurkite, pritaikykite migracijas ir paleiskite paslaugas. Tvarka svarbi: migracijos ir pradiniai duomenys vykdomi prie jau veikiančios duomenų bazės, prieš bet kuriai paslaugai pradedant aptarnauti.

COMPOSE="docker compose -f infrastructure/compose/docker-compose.prod.yml"

bash infrastructure/compose/ensure-encryption-key-ring.sh infrastructure/compose/.env
$COMPOSE up -d nessie-postgres
$COMPOSE build nessie-api nessie-admin nessie-web
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api prisma:migrate:deploy
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api seed:connectors
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api seed:apps
$COMPOSE run --rm --no-deps nessie-api pnpm --filter @nessie/api reconcile
$COMPOSE up -d

Gamybiniai Dockerfile prieš kurdami kiekvieną paketą paleidžia jo lint patikrą, todėl lint klaida yra kūrimo klaida.

Suderinimo (reconcile) žingsnis yra privalomas

reconcile sėja kiekvienos organizacijos numatytąsias politikos taisykles ir papildo saugomų MCP ir Asmeninio asistento (Personal Assistant) įrankių leidimus. API tai anksčiau darydavo paleidimo metu kiekvienoje replikoje; dabar jis tik prisijungia, klauso ir nieko daugiau nedaro, todėl be šio žingsnio pirmoji organizacija neturi politikos taisyklių, o kiekvienas agento susiejimas atmetamas. Jis idempotentiškas, todėl paleisti jį kiekvieno diegimo metu nekainuoja nieko – o rankiniu būdu pritaikytas atnaujinimas taip pat turi jį paleisti.

Pirmoji savininko paskyra

Naujai įdiegtame selfHosted diegime naudotojų nėra, todėl API sukuria vienkartinį pradinės sąrankos raktą ir į žurnalą įrašo sąrankos nuorodą. Raktas saugomas Postgres, o ne procese, todėl visos replikos su juo sutaria.

docker compose -f infrastructure/compose/docker-compose.prod.yml logs nessie-api 2>&1 | grep bootstrap

Atidarykite https://<your-admin-host>/bootstrap?token=<token> ir sukurkite savininko paskyrą. Raktas galioja 15 minučių; norėdami gauti naują, paleiskite API paslaugą iš naujo.

Jei konfigūruojate SSO, pradinės sąrankos žingsnio visai nėra. Pradinės sąrankos režimas išjungiamas tą akimirką, kai įjungiamas išorinis autentifikavimo tiekėjas – priešingu atveju jis perimtų prisijungimo ekraną – o pirmasis žmogus, prisijungęs per SSO, sukuria numatytąją komandą ir tampa jos savininku.

Modelio išvedimo konfigūravimas

Pokalbiai veikia pagal OpenAI suderinamą protokolą. NESSIE_MODEL_BASE_URL yra galinis taškas, NESSIE_MODEL_API_KEY – nešiklio (bearer) raktas, o NESSIE_MODEL_PROVIDER nurodo adapterį. Nessie kompiliuoja adapterius openai, kimi ir deepseek, o viską kita pasiekia per bendrąjį OpenAI suderinamą jungtį. NESSIE_MODEL_NAME nustato diegimo numatytąjį modelį; atskiro agento pasirinktas modelis jam turi pirmenybę.

Įterpimai (embeddings) maršrutizuojami atskirai, nes pokalbių tiekėjas jų gali visai neteikti – pavyzdžiui, DeepSeek neturi įterpimų galinio taško. Kiekvienas nenustatytas NESSIE_EMBEDDING_* laukas paveldi pokalbių tiekėją, todėl diegimas, kuriame nenustatyta nė vieno, įterpimus generuoja per pokalbių galinį tašką. Kai pokalbių tiekėjas negali įterpti, nustatykite NESSIE_EMBEDDING_PROVIDER, NESSIE_EMBEDDING_MODEL ir, jei tarpinis serveris maršrutizuoja pagal paslaugą, paslaugos segmentą. Klaida čia nutrūksta tyliai, o ne garsiai: atsiminimų paieška ir žinių bazės paieška pereina į leksinį kanalą ir tęsia darbą, o žurnale nuolat rodoma kb_search: query embedding failed.

Nessie pati vykdoma išlaidų apskaita – kiekvienos organizacijos žetonų apskaitos žurnalas ir biudžeto vartai – nepriklauso nuo to, į kurį galinį tašką nukreipiate, ir veikia vienodai, nepriklausomai nuo to, ar nustatytas pasirašytas kiekvieno iškvietimo priskyrimas.

Prisijungimas

Nessie asmenis autentifikuoja per UnlikeOtherAI, kuris taip pat tvarko organizacijos ir komandų struktūrą. Administravimo prisijungimo puslapyje rodomas vienas mygtukas „Prisijungti / Registruotis“.

Integracija yra konfigūracijos JWT srautas, o ne standartinis OIDC: API adresu GET /api/auth/sso/config pateikia pasirašytą RS256 konfigūracijos dokumentą, o atitinkamą JWKS adresu GET /.well-known/jwks.json – abu API domene. Tai nustatoma vieną kartą: sugeneruokite RSA-2048 raktų porą ir nustatykite UOA_CONFIG_JWT_PRIVATE_KEY_B64, UOA_CONFIG_JWT_KID, UOA_DOMAIN, UOA_CONFIG_URL, UOA_JWKS_URL, UOA_REDIRECT_URL ir UOA_CONTACT_EMAIL; vieną kartą paspauskite mygtuką, kuris sukuria integracijos prašymą; patvirtinkite jį – tada į kontaktinį adresą atsiunčiama vienkartinė nuoroda su kliento paslaptimi; nustatykite UOA_CLIENT_SECRET ir paleiskite API iš naujo. kid turi būti unikalus kiekvienam domenui.

Veikimas už domeno, su TLS

Diegimas aptarnauja tris vardus: viešąją svetainę, administravimo sąsają ir API. Administravimo ir API kilmės nėra pakeičiamos viena kita. Dockerfile.admin įkūrimo metu įrašo VITE_API_BASE_URL į paketą, todėl kiekvienas sukurtas administravimo artefaktas – įskaitant darbalaukio versiją, kuri jį įtraukia – turi būti kuriamas pagal API kilmę. Jei kursite pagal paties administravimo kilmę, /api/auth/providers atsakys administravimo HTML apvalkalu, ir prisijungimas liks įstrigęs ties „Kraunami tiekėjai...“.

Gamyboje TLS baigiasi Caddy, kuris kiekvienam vardui gauna sertifikatus per HTTP-01 ir tam nereikia DNS tiekėjo papildinio. Nukreipkite tarpinį serverį į administravimo ir svetainės konteinerius 80 prievade, o į API – į jo vidinį prievadą.

Nustatykite NESSIE_API_TRUSTED_PROXY_HOPS į tarpinių serverių, esančių prieš API, skaičių – 1, jei už vieno atvirkštinio tarpinio serverio. Numatytoji reikšmė yra 0, kuri visiškai ignoruoja X-Forwarded-For. Tai vienas sprendimas su dviem pasekmėmis: ta pati reikšmė nustato ir autentifikacijos užklausų ribojimus, todėl per maža reikšmė leidžia visiems klientams dalytis tarpinio serverio kvota, o per didelė – klientas gali suklastoti savo adresą. Pradėkite nuo mažesnės reikšmės ir išmatuokite.

Kiekvieną organizaciją ir komandą aptarnauti jos poddomene galima, bet pagal numatytuosius nustatymus tai išjungta. Tai valdo NESSIE_TEAM_HOST_BASE_DOMAIN: jei nenustatyta, nuomininkai pagal serverio vardą nemaršrutizuojami iš viso, o sertifikatų išdavimo vartus NESSIE_TLS_CHECK_KEY atmeta visa, kol jis nenustatytas – tai teisingas numatytasis pasirinkimas diegimui, kuris šios galimybės nenaudoja.

Būklės patikros

Galinis taškasĮ kokį klausimą atsako
GET /api/healthAr šis procesas gyvas? Nutrūksta tik tada, kai pradeda baigti darbą.
GET /api/health/readyAr ši replika gali priimti naujas užklausas? Būtent į ją nukreipkite apkrovos balansuotoją.
GET /api/ops/healthKaip sekasi diegimui? Ataskaita žmogui – darbuotojų gyvybės signalai, eilės gylis, nepavykusios užduotys – o ne automatinė patikra.

Gavęs SIGTERM, API nemiršta ten, kur stovi, o baigia darbą. NESSIE_SHUTDOWN_TIMEOUT_MS riboja šį baigimą ir pagal numatytuosius nustatymus yra 25 sekundės; laikykite jį mažesnį už malonės laikotarpį, kurį orkestratorius suteikia konteineriui, nes kitaip vykdymo aplinka procesą nutraukia pirma ir baigimas neduoda jokios naudos.

Atnaujinimas

Atnaujinimas yra prisma migrate deploy prieš esamą duomenų bazę, tada pradiniai duomenys, tada reconcile. Tos pačios keturios komandos, kaip ir pirmą kartą diegiant.

Kelias išbandytas pagal tai, kuriuo maršrutu eina savarankiškai diegiantis naudotojas, o ne prieš naują duomenų bazę: CI atkuria momentinę kopiją, nufotografuotą dvidešimt migracijų anksčiau, ją migruoja iki dabartinės viršūnės, patikrina schemą ir atlieka dūmų patikrą pagrindinėse lentelėse. Bet koks išleidimas tame paskutiniame lange yra patvirtintas atnaujinimo šaltinis. Įsipareigojus migracijų aplankai nekeičiami, o lint žingsnis nutraukia kūrimą, jei kuris nors pervadinamas, perkeičiamas numeriu, ištrinamas ar pakeičiamas, nes visa tai sugadina migrate deploy duomenų bazei, kuri jau įrašė senąją eilutę.

Viena nepavykusi migracija sustabdo visus vėlesnius diegimus. migrate deploy sustoja ties pirmu gedimu ir visas vėlesnes migracijas atmeta klaida P3009, todėl diegimas lieka ant senos versijos, kol kas nors rankiniu būdu to neišvalys. Projekto paties gamyba vieną dieną visą dieną atmetė kiekvieną diegimą šiuo būdu. Išvalyti reikia patvirtinus, kad nepavykusi migracija tikrai atšaukta – nei vienas jos sukurtas objektas neturėtų egzistuoti, o tai, ką ji pakeitė, turi išlikti pradinėje formoje – ir tik tada pažymėti ją kaip atšauktą. Migracija, kuri pritaikyta tik iš dalies, nėra kandidatė.

Atsarginių kopijų kūrimas ir atkūrimas savarankiškai diegiamam Compose diegimui saugykloje neaprašytas, todėl šis puslapis nenurodo jai procedūros.

Vienas kompiuteris ar valdomas debesis

Aukščiau aprašytas vieno serverio Docker Compose kelias yra patikrintas: būtent juo veikia projekto paties gamyba – ant vieno serverio, kur duomenų bazė, objektų saugykla, API, darbuotojas, administravimo sąsaja ir svetainė veikia kaip konteineriai už bendro atvirkštinio tarpinio serverio.

Plėtimas už vieno kompiuterio ribų keičia tris dalykus, ir visi jie yra įgyvendinami, o ne rekomenduojami. Ne local režimu Nessie API ir darbuotoją paleidžia kaip atskirus procesus, kurių kiekvienas gali veikti keliais egzemplioriais, todėl atmetama bet kuri galimybė, kuri daro prielaidą, kad vienas procesas valdo mašinos diską: failų objektų saugykla (paleidimo klaida), vykdymo aplinkos šablonai su docker tiekėju (neveiksmingi, o paruošimas garsiai nutrūksta) ir įmontuoti įrankiai file_read, file_write ir file_glob (nesėkmingas įrankio rezultatas, kurį agentas gali perskaityti). Kiekvienas atmetimas nurodo nustatymą, režimą ir tai, ką naudoti vietoj jo.

Valdomam debesiui repozitorijoje yra Terraform medis infrastructure/terraform/, nukreiptas į Google Cloud: API kaip Cloud Run paslauga, kurios mažiausias egzempliorių skaičius – vienas, nes ji laiko nuolatinį Postgres LISTEN klientą ir vykdo priežiūros valymo užduotis, todėl sumažinus iki nulio sustoja realaus laiko pristatymas; darbuotojas kaip Cloud Run darbuotojų baseinas (worker pool), nes jis neatidaro prievado ir paslauga niekada netaptų pasiruošusi; migracijų užduotis, kuri kiekvieną išleidimą leidžia tik po sėkmingo migravimo; Cloud SQL for PostgreSQL 17; ir GCS saugykla, pasiekiama per S3 suderinamą sąsają.

Šis kelias parašytas, bet neišbandytas. Repozitorijoje tai pasakyta aiškiai, ir šis puslapis tai pakartoja: Google Cloud projekto nėra, medyje niekas nebuvo suplanuota ar pritaikyta realiame projekte, įkėlimo kelias į GCS neišbandytas su tikra saugykla (bucket), darbuotojų baseino išteklių tipas nepatvirtintas, o jame esantis patikimo tarpinio serverio šuolių skaičius yra vietos rezervas, kurį reikia išmatuoti, o ne jau išmatuota reikšmė. Administravimo sąsaja ir viešoji svetainė ten visai nemodeliuojamos. Traktuokite tai kaip pradžios tašką, kurį patys patikrinsite, o ne palaikomą diegimą.

Kur diegimo duomenys laikomi, ką programinė įranga saugo ir ką tyčia nesaugo, aprašyta atskirame puslapyje: Sukurta ES, ir kur laikomi jūsų duomenys.