13 KiB
MiroFish — Guia d'instal·lació i desplegament
Aquesta guia cobreix les dues modalitats d'execució:
- Desenvolupament local — frontend + backend en mode dev
- Desplegament a Azure — producció amb Docker i Azure Container Apps
1. Desenvolupament local
Prerequisits
| Eina | Versió | Comprovació |
|---|---|---|
| Node.js | ≥ 18 | node -v |
| Python | ≥ 3.11, ≤ 3.12 | python --version |
| uv | última | uv --version |
Instal·lació
# 1. Clonar el repositori
git clone https://github.com/jaumemir/MiroFish.git
cd MiroFish
# 2. Configurar variables d'entorn
cp .env.example .env
# Edita .env i omple els valors (vegeu la secció de variables)
# 3. Instal·lar totes les dependències (Node + Python)
npm run setup:all
Variables d'entorn (.env)
# ── LLM principal (OpenAI-compatible) ─────────────────────────────
LLM_API_KEY=la-teva-clau
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
LLM_MODEL_NAME=qwen-plus
# ── Zep Cloud (graf de memòria) ───────────────────────────────────
ZEP_API_KEY=la-teva-clau-zep
# ── LLM accelerador (opcional) ────────────────────────────────────
LLM_BOOST_API_KEY=
LLM_BOOST_BASE_URL=
LLM_BOOST_MODEL_NAME=
# ── Autenticació ──────────────────────────────────────────────────
# Contrasenya de l'usuari "demo" per accedir a l'app
DEMO_PASSWORD=una-contrasenya-segura
# Clau per signar tokens JWT
# Genera-la amb: python -c "import secrets; print(secrets.token_hex(32))"
SECRET_KEY=una-clau-secreta-llarga
Execució
npm run dev
Obre el navegador a http://localhost:3000.
Fes login amb usuari demo i la DEMO_PASSWORD que has configurat.
El frontend (port 3000) i el backend (port 5001) s'inicien simultàniament.
Vite proxia automàticament les peticions/api/*al backend.
2. Desplegament a Azure Container Apps
Prerequisits
| Eina | Versió | Instal·lació |
|---|---|---|
| Azure CLI | ≥ 2.60 | docs.microsoft.com/cli/azure/install-azure-cli |
| Docker | ≥ 24 | docs.docker.com/get-docker |
| Python 3 | ≥ 3.8 | (per processar outputs JSON dels scripts) |
Estructura dels fitxers de desplegament
azure/
├── config.sh.example # plantilla de configuració (commited al repo)
├── config.sh # valors reals amb secrets (NO comitejar mai — gitignored)
├── infra.bicep # infraestructura base: ACR + Container Apps Env
├── container-app.bicep # Container App: es re-desplega a cada nova versió
├── 1-infra.sh # script pas 1: crea la infraestructura (una sola vegada)
└── 2-build-deploy.sh # script pas 2: build Docker + push + deploy (cada versió)
Pas 0 — Login a Azure
az login
Pas 1 — Configuració
cp azure/config.sh.example azure/config.sh
Edita azure/config.sh i omple tots els valors:
Variables obligatòries
| Variable | Descripció | On obtenir-la |
|---|---|---|
AZURE_SUBSCRIPTION_ID |
ID de la subscripció Azure | az account show --query id -o tsv |
AZURE_LOCATION |
Regió Azure (ex: westeurope) |
Llista de regions |
DEMO_PASSWORD |
Contrasenya de l'usuari demo |
Escull una contrasenya segura |
SECRET_KEY |
Clau Flask per signar JWT | python -c "import secrets; print(secrets.token_hex(32))" |
LLM_API_KEY |
Clau de l'API LLM | Alibaba Bailian o OpenAI |
LLM_BASE_URL |
URL base de l'API LLM | Default: Alibaba Qwen |
LLM_MODEL_NAME |
Nom del model | Default: qwen-plus |
ZEP_API_KEY |
Clau de Zep Cloud | app.getzep.com |
Variables opcionals
| Variable | Descripció | Default |
|---|---|---|
LLM_BOOST_API_KEY |
Clau LLM accelerador | (buit = desactivat) |
LLM_BOOST_BASE_URL |
URL LLM accelerador | (buit) |
LLM_BOOST_MODEL_NAME |
Model LLM accelerador | (buit) |
OASIS_DEFAULT_MAX_ROUNDS |
Rondes màximes simulació | 10 |
REPORT_AGENT_MAX_TOOL_CALLS |
Crides màximes a eines | 5 |
REPORT_AGENT_MAX_REFLECTION_ROUNDS |
Rondes de reflexió | 2 |
REPORT_AGENT_TEMPERATURE |
Temperatura del Report Agent | 0.5 |
Seguretat:
azure/config.shestà al.gitignore. Mai el comiteges al repositori.
Pas 2 — Crear infraestructura (una sola vegada)
bash azure/1-infra.sh
Aquest script crea al resource group rg_mirofish:
| Recurs | Nom | Descripció |
|---|---|---|
| Resource Group | rg_mirofish |
Contenidor de tots els recursos |
| Container Registry | mirofsihacr |
Registre privat Docker (SKU Basic) |
| Container Apps Environment | mirofish-env |
Plataforma d'execució de contenidors |
Al final imprimeix l'ACR Login Server i l'ID de l'entorn. Guarda'ls si els necessites.
Idempotent: pots executar-lo múltiples vegades sense errors.
Pas 3 — Build i deploy (a cada nova versió)
bash azure/2-build-deploy.sh
El script fa automàticament:
- Obté les dades de la infraestructura existent (ACR, Container Apps Env)
- Genera un tag de versió amb format
<git-sha>-<timestamp> docker buildde la imatge multi-stage (Vue build + Flask + gunicorn)docker pusha l'ACR privat- Desplega la Container App via Bicep amb tots els secrets configurats
Al final imprimeix la URL de l'aplicació:
URL de l'aplicació: https://mirofish.<hash>.westeurope.azurecontainerapps.io
Gestió de versions i re-deploys
Cada execució de 2-build-deploy.sh genera una nova revisió de la Container App amb tag únic. La versió latest sempre apunta a la darrera imatge.
Per veure l'historial de revisions:
az containerapp revision list \
--name mirofish \
--resource-group rg_mirofish \
--output table
Per consultar els logs en temps real:
az containerapp logs show \
--name mirofish \
--resource-group rg_mirofish \
--follow
Arquitectura de producció
Internet
│ HTTPS
▼
Container Apps Ingress (port 5001)
│
▼
Flask + gunicorn (1 worker, 4 threads)
├── GET / → serveix Vue SPA (frontend/dist/)
├── POST /api/auth/login → autenticació JWT (pública)
└── /api/* → protegit per JWT Bearer token
Escalat automàtic: de 1 a 10 rèpliques per nombre de peticions concurrents (llindar: 20).
Solució de problemes habituals
| Problema | Causa probable | Solució |
|---|---|---|
ERROR: No s'ha trobat azure/config.sh |
Fitxer no creat | cp azure/config.sh.example azure/config.sh |
Cannot login to ACR |
Docker no està en execució | docker info i arrenca Docker |
| Login retorna 401 sempre | DEMO_PASSWORD buida o incorrecta |
Verifica el valor a config.sh / secret Azure |
| Container App no arrenca | Imatge no trobada a l'ACR | Verifica que 2-build-deploy.sh hagi finalitzat sense errors |
| Token expirat al cap de 24h | Comportament esperat | Torna a fer login a /login |
3. Backend de graf pluggable (Graphiti + Neo4j)
La branca feat-pluggable-graph-backend introdueix un sistema de backends intercanviables per al graf de coneixement. El backend per defecte és Zep Cloud; l'alternatiu és Graphiti + Neo4j auto-allotjat.
Arquitectura
GraphBuilderService
│
│ self._graph = get_graph_backend()
▼
┌─────────────────────────────────┐
│ factory.get_graph_backend() │ ← llegeix GRAPH_BACKEND env var
│ (patró Singleton) │
└────────────┬────────────────────┘
│
┌────────┴────────┐
▼ ▼
ZepBackend GraphitiBackend
│ │
▼ ▼
Zep Cloud API Neo4j (bolt://)
+ graphiti-core
+ OpenAI embedder
Tots dos backends implementen la mateixa interfície abstracta GraphBackend (backend/app/graph/base.py):
| Mètode | Descripció |
|---|---|
create_graph(graph_id, name) |
Crea o registra el graf |
set_ontology(graph_ids, entities, edges) |
Defineix l'ontologia |
add_batch(graph_id, episodes) |
Afegeix episodis de text en lot |
get_episode(uuid_) |
Consulta l'estat de processament d'un episodi |
get_all_nodes(graph_id) |
Retorna tots els nodes del graf |
get_all_edges(graph_id) |
Retorna totes les arestes |
get_node(uuid_) |
Node per UUID |
get_node_edges(node_uuid) |
Arestes d'un node |
search(graph_id, query, limit) |
Cerca semàntica |
add_text(graph_id, data) |
Afegeix text directament |
delete_graph(graph_id) |
Elimina el graf complet |
Fitxers clau
backend/app/graph/
├── base.py — interfície abstracta GraphBackend
├── factory.py — factory + singleton (get_graph_backend)
├── zep_backend.py — implementació Zep Cloud
└── graphiti_backend.py — implementació Graphiti + Neo4j
Diferències de comportament entre backends
| Aspecte | ZepBackend | GraphitiBackend |
|---|---|---|
| Allotjament | Zep Cloud (SaaS) | Neo4j auto-allotjat |
| Ontologia | API nativa Zep | No-op (extracció LLM automàtica) |
| Polling d'episodis | episode.get(uuid_) real |
Retorna sempre processed=True |
| Consultes | SDK Zep | Queries Cypher directes |
| Paginació nodes/arestes | 100 items/pàgina, màx. 2000 | Sense límit explícit |
| Resiliència | Retry amb backoff exponencial (3 intents) | Sense retry |
| Cerca | reranker=cross_encoder |
graphiti_core.search() |
| Credencials | ZEP_API_KEY |
NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD |
| Threading async | No cal (SDK síncron) | Thread daemon + asyncio.run_coroutine_threadsafe |
Instal·lació de les dependències Graphiti
Graphiti és una dependència opcional. Per activar-la:
# Amb uv (recomanat)
uv pip install -e ".[graphiti]"
# Amb pip
pip install "mirofish-backend[graphiti]"
# o directament:
pip install "graphiti-core>=0.3.0" "neo4j>=5.23.0"
Les dependències base (Zep) segueixen instal·lant-se com sempre:
uv pip install -r requirements.txt
Variables d'entorn per a Graphiti + Neo4j
# Selecció de backend (per defecte: zep)
GRAPH_BACKEND=graphiti
# Connexió Neo4j (protocol bolt)
NEO4J_URI=bolt://<host>:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=la-teva-contrasenya
# LLM_API_KEY, LLM_BASE_URL i LLM_MODEL_NAME segueixen sent necessaris
# (graphiti-core els usa per a l'extracció d'entitats i els embeddings)
Nota: quan
GRAPH_BACKEND=graphiti,ZEP_API_KEYno és necessari.
Desplegament a Azure (aci-graphiti-neo4j)
Al resource group rg_mirofish existeix el container group aci-graphiti-neo4j amb tres contenidors al mateix pod:
| Contenidor | Imatge | Port intern | Funció |
|---|---|---|---|
neo4j |
mirofishgeneacr.azurecr.io/neo4j:5.26.0 |
7474 (HTTP), 7687 (bolt) | Base de dades de graf |
graphiti-mcp |
mirofishgeneacr.azurecr.io/knowledge-graph-mcp:standalone |
8000 | API graphiti-core via MCP |
caddy |
mirofishgeneacr.azurecr.io/caddy:2 |
443 | Proxy HTTPS per a graphiti-mcp |
Ports exposats públicament:
| Port | Protocol | Destí |
|---|---|---|
| 443 | TCP | caddy → graphiti-mcp (HTTPS, certificat Let's Encrypt) |
| 7687 | TCP | bolt → neo4j (autenticat) |
Endpoints:
- Graphiti MCP:
https://graphitigene-mcp.westeurope.azurecontainer.io - Neo4j bolt:
bolt://52.149.109.53:7687
Variables d'entorn del Container App mirofishgene (configuració activa):
GRAPH_BACKEND=graphiti
NEO4J_URI=bolt://52.149.109.53:7687
NEO4J_USER=neo4j
NEO4J_DATABASE=neo4j
NEO4J_PASSWORD=<secret: neo4j-password>
Tests
# Executar els tests del factory (no requereix Neo4j ni Zep actius)
cd .worktrees/feat-pluggable-graph-backend
pytest backend/tests/test_graph_factory.py -v
El fixture reset_graph_factory_singleton (a backend/tests/conftest.py) reseteja el singleton entre tests per evitar interferències quan es canvia GRAPH_BACKEND.