nanobot: 2026-09-10 12:33:37
This commit is contained in:
@@ -347,6 +347,16 @@ Pole `description` ve frontmatteru non-always skillu je **routing signál**, ne
|
||||
|
||||
Zdroj: `nanobot/agent/skills.py:111-159` (`build_skills_summary`, `_get_skill_description`), `skills.py:94-109` (`load_skills_for_context`, always skilly), `nanobot/agent/context.py:87-95`.
|
||||
|
||||
**Oficiální tvar `description`** ([Anthropic — Skill authoring best practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices), platí i pro nanobot, formát je identický). Nanobot wiki frontmatter skillů nedokumentuje — autoritou je tenhle dokument plus zjištění ze zdrojáku výše.
|
||||
|
||||
- Tvar: `<co skill dělá, slovesná fráze>. Use when <triggery/kontexty>.` Např. `Extract text and tables from PDF files, fill forms, merge documents. Use when working with PDF files or when the user mentions PDFs, forms, or document extraction.`
|
||||
- **Vždy třetí osoba** — `Processes Excel files…`, nikdy `I can help you…` ani `You can use this to…`; nekonzistentní osoba zhoršuje discovery.
|
||||
- Musí obsahovat **co dělá i kdy použít**, klíčový use case první, konkrétní klíčové termíny. Vágní (`Helps with documents`) je anti-pattern.
|
||||
- Limit **1 024 znaků** (Agent Skills spec); Claude Code listing ořezává na 1 536.
|
||||
- Nanobotí dodatek k tomu: „co dělá" = **schopnost**, ne postup. `Adds, deduplicates, and compacts entries in keep.md` je *jak* → do těla.
|
||||
|
||||
Aplikováno na `keep` (history 2026-09-04).
|
||||
|
||||
## Dream procesor — automatické self-improvement
|
||||
|
||||
Nanobot má vestavěný Dream procesor (`agent/memory.py:Dream`) který běží každé 2 hodiny. Jde o **dvou-fázový LLM pipeline** nad `history.jsonl`:
|
||||
@@ -1163,3 +1173,86 @@ Dream). Zbytek serverového workspace repa běžně stojí s necommitnutými zm
|
||||
(`keep.md`, `AGENTS.md`, `cron/jobs.json`, `reflect/*`) — to je normální stav, ne rozbité repo.
|
||||
Při ruční editaci `notes.md` proto commitni s prefixem `note:` a stage jen `notes/`.
|
||||
Zdroj: history 2026-09-04.
|
||||
|
||||
## Ollama Cloud embeddingy neexistují — cloud tier je completion-only (2026-09-09)
|
||||
|
||||
Žádný z 18 cloud modelů nemá capability `embedding`; `/api/embed` na cloud modelu vrací
|
||||
`unauthorized`, **zatímco `/api/generate` na tomtéž modelu projde** — takže to není problém
|
||||
autorizace, cloud tier ten endpoint prostě neobsluhuje a hláška je zavádějící. Katalog na
|
||||
ollama.com to potvrzuje: filtr `c=embedding` vrací 12 modelů, všechny jen ke stažení, žádný
|
||||
s cloud tagem. Embeddingy je tedy nutné hostovat lokálně. Zdroj: history 2026-09-09.
|
||||
|
||||
## Cena brute-force cosine v SQLite je z 96 % Python režie, ne matmul (2026-09-09)
|
||||
|
||||
Nad 10⁵×1024 float32: **594 ms = read 382 + pack 190 + dot 22**. Samotný numpy matmul je
|
||||
zanedbatelný; platí se za extrakci BLOBů a jejich složení do matice. Proto `sqlite-vec`
|
||||
(`vec0`) dá **19 ms @ 10k a 212 ms @ 100k** — skenuje v C. `.npy` + `mmap_mode='r'` je
|
||||
ještě rychlejší (35 ms), ale za cenu druhého souboru mimo DB. Pozor: `vec0` **není ANN
|
||||
index** — lineární škálování 19 → 212 ms to potvrzuje, výhoda je konstanta, ne asymptotika.
|
||||
Zdroj: history 2026-09-09.
|
||||
|
||||
## FTS5 a čeština: `remove_diacritics` + prefix wildcard stačí, trigram netřeba (2026-09-09)
|
||||
|
||||
`unicode61 remove_diacritics 1` a výš foldí diakritiku (dotaz `zaloha` najde `záloha`;
|
||||
hodnota `0` ne). Stemming `unicode61` neumí, ale **prefix wildcard to pokryje**: `záloh*`
|
||||
i `zaloh*` najdou *záloha, zálohování, zálohy*. Dotazová vrstva tedy lepí `*` na termy —
|
||||
trigram tokenizer není potřeba. Souvisí s varováním v `remind/scripts/store.py`
|
||||
(`find_active_by_exact_text()`), že SQLite `lower()` foldí jen ASCII. Zdroj: history 2026-09-09.
|
||||
|
||||
## `vec0` není cílem foreign key — kaskáda ho nevyčistí (2026-09-09)
|
||||
|
||||
`ON DELETE CASCADE` z nadřazené tabulky uklidí navázané řádky **i FTS5 external-content
|
||||
tabulku** (AFTER DELETE trigger se na kaskádě spustí), ale řádek ve `vec0` virtuální tabulce
|
||||
**osiří** — indexer ho musí mazat explicitně. Jinak index při mazání souborů tiše plní mrtvými
|
||||
vektory. Ověřeno smoke testem; `DELETE`/re-`INSERT`/`UPDATE` po `rowid` a `ROLLBACK` ve `vec0`
|
||||
jinak fungují normálně (sqlite-vec v0.1.6). Zdroj: history 2026-09-09.
|
||||
|
||||
## Ollama `keep_alive` musí být číslo, ne string (2026-09-09)
|
||||
|
||||
`{"keep_alive": -1}` i `{"keep_alive": "24h"}` → HTTP 200; **`{"keep_alive": "-1"}` → HTTP 400**.
|
||||
Cold load `qwen3-embedding:0.6b` (639 MB) je 1,81 s vs. warm 0,043 s, takže připíchnutí modelu
|
||||
se vyplatí, ale není kritické. Batching je naopak podstatný: 8,9 chunk/s po jednom vs.
|
||||
**108 chunk/s v batchi 32**. Zdroj: history 2026-09-09.
|
||||
|
||||
## Instruct prefix je u `qwen3-embedding` load-bearing, ne kosmetika (2026-09-09)
|
||||
|
||||
Na 12 parafrázových dotazech nad 123 reálnými chunky: **recall@10 8/12 s prefixem
|
||||
vs. 3/12 bez něj** (MRR 0,261 vs 0,204). Plán `final-wiki-hybrid-rag` ho označoval za
|
||||
„nekritickou vlastnost" na základě 5/5 vs 5/5 na jiném korpusu — na uživatelských datech
|
||||
to neplatí. Prefix musí být **bitově identický** při indexaci i dotazu, proto žije
|
||||
v `meta.query_prefix` a jeho změna vyžaduje `wiki_sync.py --full`. Zdroj: history 2026-09-09.
|
||||
|
||||
## FTS5 prefix wildcard NEfolduje českou flexi — jen prefixy (2026-09-09)
|
||||
|
||||
`záloh*` najde *záloha/zálohování/zálohy* jen proto, že `záloh` je **kmen**. Se skutečně
|
||||
skloněným dotazovým slovem to selže: naměřeno `cestu*` → **0** chunků v
|
||||
`travel/packaging-list.md`, `cesty*` → 3, `cest*` → 4. Wildcard je prefixový, takže pomůže
|
||||
jen když je dotazové slovo prefixem tvaru v dokumentu — a česká flexe mění koncovku, ne
|
||||
začátek. Důsledek: dotaz „co si vzít na cestu do zahraničí" nedostal doslovný seznam věcí
|
||||
na cestu ani do top 10. Tohle je polovičnost D6 v plánu, ne chyba implementace.
|
||||
Zdroj: history 2026-09-09.
|
||||
|
||||
## Hybrid RRF zlepšuje rank, ne pokrytí (2026-09-09)
|
||||
|
||||
Nad reálnými poznámkami: MRR **0,367 u RRF** vs 0,257 (BM25 sám) a 0,261 (vektory samy) —
|
||||
merge dvou ranků téže množiny opravdu vyhrává. Ale `recall@10` u RRF je **6/12**, zatímco
|
||||
vektory samotné 8/12: RRF řadí podle **shody** obou polovin, takže chunk, který našla jen
|
||||
vektorová polovina na ranku #9, vytlačí z top-10 chunky, na kterých se poloviny shodnou.
|
||||
Očekávaný kompromis, ne vada. Zdroj: history 2026-09-09.
|
||||
|
||||
## Bare `python3` neotevře `vec_chunks` — potřebuje `sqlite_vec.load()` (2026-09-09)
|
||||
|
||||
Dotaz na běžné tabulky (`chunks`, `files`) přes systémový `python3` projde, ale jakmile se
|
||||
sáhne na `vec0` virtuální tabulku, přijde `sqlite3.OperationalError: no such module: vec0`.
|
||||
Extension se musí načíst explicitně (`enable_load_extension(True)` + `sqlite_vec.load(conn)`),
|
||||
což skill dělá v `wiki_db.get_db()`. Při ruční inspekci indexu na serveru je proto nutné
|
||||
`uv run --with "sqlite-vec==0.1.6"`. Zdroj: history 2026-09-09.
|
||||
|
||||
## `ty.toml` `extra-paths` je plochý jmenný prostor — kolize modulů mezi skilly (2026-09-09)
|
||||
|
||||
Typechecker `ty` řeší `import store` proti seznamu `extra-paths` a **vyhrává první cesta**,
|
||||
takže dva skilly se stejným jménem modulu si navzájem rozbijí kontrolu (testy `wiki`
|
||||
dostávaly `store` z `remind`). Proto všechny skilly kromě `remind` prefixují moduly jménem
|
||||
skillu (`note_capture.py`, `wiki_sync.py`) — je to nutnost, ne estetika. U kolize, které se
|
||||
nelze vyhnout (`wiki_search.py` je i v retired `llm-wiki`), rozhoduje **pořadí** v
|
||||
`extra-paths`. Zdroj: history 2026-09-09.
|
||||
|
||||
Reference in New Issue
Block a user