315 lines
16 KiB
Markdown
315 lines
16 KiB
Markdown
# Repo Agent & QA — LLM Proxy • OpenWebUI Tools • Agent Repo/QA
|
||
|
||
Een compacte, productierijpe stack om (1) chat/LLM-verzoeken af te handelen, (2) OpenWebUI-compatibele tools (STT/TTS/Retrieval) aan te bieden, en (3) een **Repo Agent** te draaien die **kandidaten zoekt, diffs genereert** (dry-run) en — na akkoord — **schrijft & pusht** op een nieuwe branch. Inclusief **Repo-QA** (vraag-antwoord over je codebase met padverwijzingen), **Laravel-bewuste heuristiek**, **hybride retrieval** (Meili/BM25 + embeddings/Chroma), **slim chunking**, **niet-destructieve guards** en een **lichte graaf-boost** (route ⇄ controller ⇄ view ⇄ lang).
|
||
|
||
> Dockerfile inbegrepen (Python 3.11-slim), met o.a. `faster-whisper`, `piper` TTS, Meili/Chroma-clients, `gitpython`, `sentence-transformers`, `rank-bm25`.
|
||
|
||
---
|
||
|
||
## Inhoudsopgave
|
||
|
||
* [Architectuur in 3 onderdelen](#architectuur-in-3-onderdelen)
|
||
* [Belangrijkste features](#belangrijkste-features)
|
||
* [Snel starten](#snel-starten)
|
||
|
||
* [Docker (aanbevolen)](#docker-aanbevolen)
|
||
* [Zonder Docker (dev)](#zonder-docker-dev)
|
||
* [Configuratie (ENV)](#configuratie-env)
|
||
* [Endpoints](#endpoints)
|
||
* [Hoe het werkt (flow prompt → diffs/qa)](#hoe-het-werkt-flow-prompt--diffsqa)
|
||
* [Retrieval & indexing](#retrieval--indexing)
|
||
* [Chunking & contextbudget](#chunking--contextbudget)
|
||
* [Laravel-bewust + lichte graaf-boost](#laravel-bewust--lichte-graaf-boost)
|
||
* [Veiligheid: diff-guard & apply](#veiligheid-diff-guard--apply)
|
||
* [Troubleshooting](#troubleshooting)
|
||
* [Roadmap (suggesties)](#roadmap-suggesties)
|
||
* [Licentie](#licentie)
|
||
|
||
---
|
||
|
||
## Architectuur in 3 onderdelen
|
||
|
||
| Onderdeel | Doel | Taken | Bestanden in deze repo |
|
||
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||
| **LLM Proxy** | Dunne HTTP-laag voor chat/LLM + (optioneel) tool-calls; OpenWebUI-vriendelijk. | `/chat` endpoint, promptverrijking, streaming; kan tools/agent aanroepen. | `app.py` (routes) |
|
||
| **OpenWebUI-compatible Tools** | Kleine helper-endpoints die je rechtstreeks vanuit OpenWebUI of de proxy kunt aanroepen. | STT (faster-whisper), TTS (piper), retrieval (Meili/BM25/Chroma), PDF/afbeelding utils. | `app.py` (tool-routes), helpers in `queue_helper.py` |
|
||
| **Agent Repo & Repo QA** | “De smid”: zoekt relevante files, bouwt context, **maakt diffs** (dry-run), en kan **apply & push** doen op nieuwe branch. QA over repo. | Kandidaten zoeken, slim chunken, LLM-editplannen, diff-guards, branch & push. Repo-QA antwoord met padbronnen. | **`agent_repo.py`**, `smart_rag.py`, `windowing_utils.py`, `queue_helper.py` |
|
||
|
||
**Mijn advies (prod vs dev):**
|
||
|
||
* **Prod:** scheid *LLM Proxy + Tools* (publiek) van *Agent Repo/QA* (afschermen; heeft Gitea-rechten).
|
||
* **Dev:** alles in één Uvicorn-app (zoals in deze Dockerfile) is prima.
|
||
|
||
---
|
||
|
||
## Belangrijkste features
|
||
|
||
* **Hybride retrieval**: Meili/BM25 (file-niveau **harde signalen**) + Chroma/embeddings (chunk-niveau **semantiek**).
|
||
* **Laravel-bewuste heuristiek**: routes scannen, controller ↔ view ↔ lang keys, FormRequests/Policies.
|
||
* **Slim chunken**: taalspecifiek (PHP/Blade/JS/MD), functie/section-grenzen; overlap; contextbudget.
|
||
* **Lichte graaf-boost**: route ⇄ controller ⇄ view ⇄ lang relaties wegen mee in ranking.
|
||
* **Niet-destructieve patches**: diff-guard op deletieratio; kleine, anker-gebaseerde edits; sanity-checks.
|
||
* **Repo-QA**: compacte, bronverwijzende antwoorden (“Bronnen: padnamen”).
|
||
* **OpenWebUI-tools**: STT (faster-whisper), TTS (piper), retrieval als losse endpoints.
|
||
* **Dry-run → Apply**: eerst diffs tonen; na *“Akkoord apply”* nieuwe branch + push.
|
||
|
||
---
|
||
|
||
## Snel starten
|
||
|
||
### Docker (aanbevolen)
|
||
|
||
**Dockerfile (samenvatting)**
|
||
|
||
```dockerfile
|
||
FROM python:3.11-slim
|
||
WORKDIR /app
|
||
COPY requirements.txt .
|
||
RUN apt-get update && apt-get -y install git curl ffmpeg libcairo2 libpango-1.0-0 libgdk-pixbuf2.0-0 apt-utils
|
||
RUN pip install --upgrade pip
|
||
RUN pip install --no-cache-dir -r requirements.txt
|
||
RUN pip install PyPDF2 python-multipart gitpython chromadb httpx meilisearch pandas openpyxl python-pptx faster-whisper==1.0.0 cairosvg sentence-transformers rank-bm25
|
||
# piper TTS
|
||
RUN apt-get update && apt-get install -y --no-install-recommends wget ca-certificates libstdc++6 libatomic1 \
|
||
&& rm -rf /var/lib/apt/lists/* \
|
||
&& mkdir -p /opt/piper \
|
||
&& set -eux; URL="https://github.com/rhasspy/piper/releases/download/2023.11.14-2/piper_linux_x86_64.tar.gz"; \
|
||
wget -O /tmp/piper.tgz "$URL"; tar -xzf /tmp/piper.tgz -C /opt/piper --strip-components=1; \
|
||
ln -sf /opt/piper/piper /usr/local/bin/piper; rm -f /tmp/piper.tgz
|
||
COPY app.py .
|
||
COPY queue_helper.py .
|
||
COPY agent_repo.py .
|
||
COPY windowing_utils.py .
|
||
COPY smart_rag.py .
|
||
EXPOSE 8080
|
||
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]
|
||
```
|
||
|
||
**Build & run**
|
||
|
||
```bash
|
||
# 1) Build
|
||
docker build -t repo-agent:latest .
|
||
|
||
# 2) Run (met voorbeeld-ENV; pas aan op jouw omgeving)
|
||
docker run --rm -p 8080:8080 \
|
||
-e MEILI_URL=http://host.docker.internal:7700 \
|
||
-e MEILI_MASTER_KEY=your_meili_key \
|
||
-e GITEA_URL=http://host.docker.internal:3000 \
|
||
-e GITEA_TOKEN=your_gitea_token \
|
||
-e REPO_AGENT_SMART=1 \
|
||
-e AGENT_DESTRUCTIVE_RATIO=0.25 \
|
||
-e RAG_GRAPH_ENABLE=1 \
|
||
repo-agent:latest
|
||
```
|
||
|
||
> **Tip:** start MeiliSearch naast deze container (of gebruik bestaande). Chroma is optioneel; zonder Chroma valt retrieval semantisch terug op BM25/Meili.
|
||
|
||
### Zonder Docker (dev)
|
||
|
||
```bash
|
||
python -m venv .venv && source .venv/bin/activate
|
||
pip install -r requirements.txt
|
||
pip install PyPDF2 python-multipart gitpython chromadb httpx meilisearch pandas openpyxl python-pptx faster-whisper==1.0.0 cairosvg sentence-transformers rank-bm25
|
||
uvicorn app:app --host 0.0.0.0 --port 8080 --reload
|
||
```
|
||
|
||
---
|
||
|
||
## Configuratie (ENV)
|
||
|
||
| Variabele | Betekenis | Default / Opmerking |
|
||
| ---------------------------------------------- | --------------------------------------------------------- | ---------------------------- |
|
||
| `MEILI_URL`, `MEILI_MASTER_KEY` | MeiliSearch voor file-retrieval & (optioneel) indexing. | Aanbevolen. |
|
||
| `REPO_AGENT_SMART` | Schakel intent-/expansie + hybride retrieval in de agent. | `1` (aan) |
|
||
| `GITEA_URL`, `GITEA_TOKEN` | Nodig voor private repos en **apply/push**. | Sterk aanbevolen voor Agent. |
|
||
| `AGENT_DEFAULT_BRANCH` | Basisbranch om op te clonen/indexeren. | `main` (fallback `master`) |
|
||
| `AGENT_DESTRUCTIVE_RATIO` | Max. deletieratio vóór blokkeren (0–1). | `0.25` (voorbeeld) |
|
||
| `RAG_GRAPH_ENABLE` | **Lichte graaf-boost** op ranking inschakelen. | **`1` (aan)** |
|
||
| `RAG_EMB_WEIGHT` | Gewicht embeddings t.o.v. lexicaal signaal. | `0.6` typisch |
|
||
| `RAG_PER_QUERY_K`, `RAG_N_RESULTS` | Recall parameters hybrid retrieval. | 30 / 18 (voorbeeld) |
|
||
| `RAG_NEIGHBORS` | Laravel “buren” (routes→controllers→views). | `1` (aan) |
|
||
| `LLM_PRIORS_ENABLE`, `LLM_PRIORS_K` | LLM-gebaseerde pad-prior suggesties. | `1` / `12` |
|
||
| `LARAVEL_PRIORS_K` | Max #Laravel priors vóór RAG. | `8` |
|
||
| `CHUNK_CHARS_LARAVEL`, `CHUNK_OVERLAP_LARAVEL` | Chunkgrootte/overlap voor Laravel-stacks. | 1800 / 300 |
|
||
| `CHUNK_CHARS_DEFAULT`, `CHUNK_OVERLAP_DEFAULT` | Idem voor generieke stacks. | 2600 / 350 |
|
||
| `AGENT_QA_CTX_BUDGET_TOKENS` | Tokenbudget voor Repo-QA context. | 6000 |
|
||
| `QA_MIN_PER_SNIPPET`, `QA_MAX_PER_SNIPPET` | Contextdistributie per snippet. | 180 / 900 |
|
||
| `QA_KEEP_TOP_K` | Max snippets na trimming. | 8 |
|
||
|
||
> **NB**: Veel van bovenstaande komen rechtstreeks terug in `agent_repo.py` (zie env-reads aldaar). Waarden hierboven zijn “goede defaults”.
|
||
|
||
---
|
||
|
||
## Endpoints
|
||
|
||
> Endpoints staan in `app.py`. Onderstaande is het **standaardpatroon** in deze setup.
|
||
|
||
### 1) LLM Proxy
|
||
|
||
* `POST /chat` — voer een chat uit (optioneel met tool-calls)
|
||
|
||
Voorbeeld:
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8080/chat \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"messages":[{"role":"user","content":"Geef een korte samenvatting van de meldingenmodule."}]}'
|
||
```
|
||
|
||
### 2) OpenWebUI-compatible Tools
|
||
|
||
* `POST /tools/stt` — audio → tekst (faster-whisper)
|
||
* `POST /tools/tts` — tekst → audio (piper)
|
||
* `POST /tools/retrieve` — retrieval (Meili/BM25 + embeddings)
|
||
|
||
Voorbeeld:
|
||
|
||
```bash
|
||
curl -X POST http://localhost:8080/tools/retrieve \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"query":"waar staat het wachtwoordbeleid?", "k": 12}'
|
||
```
|
||
|
||
### 3) Agent Repo & Repo QA
|
||
|
||
* `POST /agent/dryrun` — **genereer diffs**, geen writes
|
||
* `POST /agent/apply` — **schrijf & push** (na akkoord)
|
||
* `POST /qa/ask` — Repo-QA met paden als bronnen
|
||
|
||
Voorbeelden:
|
||
|
||
```bash
|
||
# Dry-run diffs
|
||
curl -X POST http://localhost:8080/agent/dryrun \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"repo":"owner/project","user_goal":"Vervang \"Versturen\" → \"Verzenden\" in meldingen-create"}'
|
||
|
||
# Apply (na akkoord)
|
||
curl -X POST http://localhost:8080/agent/apply \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"repo":"owner/project","confirm":"Akkoord apply"}'
|
||
|
||
# Repo-QA
|
||
curl -X POST http://localhost:8080/qa/ask \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"repo":"owner/project","question":"Waar wordt de storing-aanmaak afgehandeld?"}'
|
||
```
|
||
|
||
---
|
||
|
||
## Hoe het werkt (flow prompt → diffs/qa)
|
||
|
||
**Samengevatte pipeline (Agent Repo):**
|
||
|
||
1. **Prompt binnen** → intent & scope (optioneel refine; NL/EN synonyms).
|
||
2. **Repo selecteren** → clone/update op basisbranch; meelifall-cache.
|
||
3. **Candidate discovery (hybride)**
|
||
|
||
* **Meili/BM25 (file-niveau, hard signal)**: top-N files.
|
||
* **LLM-priors + Laravel-heuristiek**: routes, controllers, views, lang-keys.
|
||
* **Chroma/embeddings (chunk-niveau, zacht signaal)**.
|
||
* **Lichte graaf-boost**: route ⇄ controller ⇄ view ⇄ lang.
|
||
4. **Slim chunken**: functie/section-grenzen; overlap; metadata (path, class/method, blade-section, start/end).
|
||
5. **Contextbouw (RAG)**: top-chunks + korte file/dir-summaries → compact context.
|
||
6. **Patchvoorstel per bestand**
|
||
|
||
* **Veilige literal-replaces** (UI-labels) → minimaal.
|
||
* **LLM edit-plan** met regex/insert/replace-operaties (max 4 stappen).
|
||
* **Volledige rewrite (guarded)** als laatste redmiddel.
|
||
7. **Diff-guard & checks**: deletieratio drempel; syntaxis/parse waar mogelijk.
|
||
8. **Resultaat**: toon diffs + “waarom geselecteerd”; **Akkoord apply** → branch + push.
|
||
|
||
**Repo-QA:**
|
||
|
||
* Zelfde discovery/ctx, maar i.p.v. diffs levert QA een **kort antwoord + bronpaden**.
|
||
|
||
---
|
||
|
||
## Retrieval & indexing
|
||
|
||
* **MeiliSearch**: snelle file-retriever. Gebruik `name/path/summary/content` als searchable; boost bekende paden (`routes/**`, `resources/views/**`, `app/Http/Controllers/**`) bij route/view/vertaling-taken.
|
||
* **BM25 fallback**: aanwezig als Meili niet beschikbaar is.
|
||
* **Chroma (optioneel)**: embeddings per **chunk** met metadata (`path`, `lang`, `class`, `function`, `route`, `blade_section`, `start/end`). Wordt gebruikt als **zachte** rankingbron naast Meili.
|
||
|
||
**Reranking (vuistregel)**
|
||
`FinalScore(file) = 0.55 * Meili + 0.35 * Embeddings + 0.10 * Heuristiek + PathBoost + Recency`
|
||
|
||
---
|
||
|
||
## Chunking & contextbudget
|
||
|
||
* **Taalspecifiek**:
|
||
|
||
* PHP → class/method/closure; docblocks mee.
|
||
* Blade → `@section`, componenten, top-level HTML-blokken.
|
||
* JS/TS → function/module-grenzen.
|
||
* MD/Tekst → alinea’s; headers intact.
|
||
* **Budget**: context trimmer verdeelt tokens over snippets (`QA_MIN/MAX_PER_SNIPPET`, `QA_KEEP_TOP_K`), deduplication, novelty-score en overlap.
|
||
|
||
---
|
||
|
||
## Laravel-bewust & lichte graaf-boost
|
||
|
||
* **Route-mapping**: scan `routes/web.php`/`api.php` → `Controller@method`.
|
||
* **View & lang-koppeling**: `return view('foo.bar')` → `resources/views/foo/bar.blade.php`; `__('key')`, `@lang('key')` → `resources/lang/**`.
|
||
* **Neighbors**: controller → view(s), route → controller, view → partials/layouts (dichtbij).
|
||
* **Graph-boost (aan)**: deze relaties wegen mee in ranking (standaard **aan** via `RAG_GRAPH_ENABLE=1`).
|
||
|
||
**Tree + samenvattingen**
|
||
|
||
* Projecttree krijgt **korte omschrijvingen per dir/file** (README’s, docblocks, eerste regels) zodat de LLM **snapt welke lagen** er zijn. Deze summaries worden hergebruikt in retrieval en prompt-context.
|
||
|
||
---
|
||
|
||
## Veiligheid: diff-guard & apply
|
||
|
||
* **Destructiviteits-guard**: schat deletieratio met `difflib.ndiff`; blokkeer als `> AGENT_DESTRUCTIVE_RATIO` (files < ~6 regels worden soepeler behandeld).
|
||
* **Editstrategie (minimaal eerst)**:
|
||
|
||
1. gerichte literal-replaces (quotes, fallbacks),
|
||
2. scoped HTML/Blade vervanging,
|
||
3. LLM edit-plan (max 4 bewerkingen),
|
||
4. guarded rewrite.
|
||
* **Apply**: alleen na “Akkoord apply” → nieuwe branch `task/<slug>-YYYYMMDD-HHMMSS` → **push** (Gitea token vereist).
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
* **Geen kandidaten gevonden** → specificeer een route, bestand of label-tekst; controleer Meili/Chroma beschikbaarheid.
|
||
* **Apply faalt** → check `GITEA_URL`/`GITEA_TOKEN` en repo-rechten; branch bestaat al?
|
||
* **STT/TTS werkt niet** → controleer `ffmpeg` in container en piper/faster-whisper install (zitten in Dockerfile).
|
||
* **Lage precisie** → verhoog `RAG_PER_QUERY_K` en `RAG_N_RESULTS`, zet `RAG_GRAPH_ENABLE=1`, gebruik `LLM_PRIORS_ENABLE=1`.
|
||
|
||
---
|
||
|
||
## Roadmap (suggesties)
|
||
|
||
* **AST-chunking voor PHP** (nikic/php-parser) voor nog scherpere grenzen.
|
||
* **Cross-encoder reranker** (klein model) bovenop cosine.
|
||
* **Blade compile-check** (sanity) en `php -l` op changed files.
|
||
* **Auto test-suggesties** bij diffs.
|
||
* **Meer tools** (PDF tabel-extractie, image-OCR) als OpenWebUI-endpoints.
|
||
|
||
---
|
||
|
||
## Licentie
|
||
|
||
Kies een licentie (MIT/Apache-2.0/GPL-3.0). Voeg `LICENSE` toe aan de repo.
|
||
|
||
---
|
||
|
||
### Bestandsoverzicht
|
||
|
||
```
|
||
app.py # Uvicorn/FastAPI app; /chat, tools, agent/qa routes
|
||
agent_repo.py # Repo Agent & Repo QA: retrieval, chunking, diffs, apply
|
||
smart_rag.py # Intent/expansie, hybride retrieval helpers
|
||
windowing_utils.py # Chunking & contextbudget utils
|
||
queue_helper.py # Hulpfuncties voor taken/IO
|
||
Dockerfile # Container build (Python 3.11-slim, piper, faster-whisper, Meili/Chroma clients)
|
||
requirements.txt # Basis Python dependencies
|
||
```
|
||
|