docs: сортировка History по темам (sonnet, opus, llm, sse, ux-frontend, upload, infra, plans, tests, base, code-fixes)

This commit is contained in:
“Naeel”
2026-08-24 15:23:31 +03:00
parent 25e4b46e76
commit db7cdbdd84
69 changed files with 0 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
# 2026-08-20 — Вопрос-ответ по LLM-чанкингу (Q&A)
Контекст: сервис обфускации, двухступенчатый детект ПДн (regex + LLM). Пользователь
хочет, чтобы LLM обрабатывал ВСЕ данные, а не урезку 8000 символов.
Обсуждение с Sonnet: основной вопрос + 6 уточнений.
Предыдущие файлы:
- History/2026-08-20-sonnet-query-llm-pattern.md — рекомендуемая схема
- History/2026-08-20-sonnet-query-llm-followup.md — уточнения перед внедрением
---
## Исходная проблема
`scan_llm_ner` (drhider/scanner.py) обрезал:
- каждый файл до первых 3000 символов (`t[:3000]`);
- всё вместе до 8000 символов (`combined[:8000]`);
- один вызов LLM на весь набор.
Итог: при 299 файлах LLM «видел» только ~8000 символов (~0.1–0.3% данных).
Пользователь: «всё затевалось чтобы ЛЛМ ВСЁ обрабатывал». → убрать урезку.
## Рекомендуемая схема (Sonnet, основной ответ)
- Отказаться от глобального батчинга → «один файл = один или несколько вызовов LLM», параллельно.
- Чанкинг per-file: чанк 6000 символов, overlap 400–500 символов.
- Дедупликация по файлу + верификация (найденная строка реально в тексте → отсекает галлюцинации).
- Батчинг мелких файлов — опционально, второй шаг.
## Уточнения (У.1–У.6) и ответы Sonnet
### У.1 — Алгоритм разбивки на чанки
Приоритет границ: `\n\n` → `\n` → `. ` → `? ` → `! ` → `; ` → `, ` → ` ` (пробел — крайний).
Ищем ближайшую границу с конца в диапазоне `[size//2 .. size]`. Жёсткий разрез — только если нет ни одного пробела.
Overlap: отступить назад на overlap, найти начало слова.
Псевдокод:
```python
BOUNDARIES = ['\n\n', '\n', '. ', '? ', '! ', '; ', ', ', ' ']
def split_into_chunks(text, size=6000, overlap=500):
chunks=[]; start=0
while start < len(text):
end=min(start+size, len(text))
if end==len(text):
chunks.append(text[start:]); break
cut=None
for b in BOUNDARIES:
pos=text.rfind(b, start+size//2, end)
if pos!=-1:
cut=pos+len(b); break
if cut is None: cut=end
chunks.append(text[start:cut])
ov=max(start, cut-overlap)
space=text.find(' ', ov)
start=(space+1) if (space!=-1 and space<cut) else ov
return chunks
```
### У.2 — Нормализация для дедупа
```python
def normalize_entity(s):
s=s.strip()
s=re.sub(r'\s+',' ',s)
s=s.lower()
s=re.sub(r'[«»“”‘’"\' ]','"',s) # кавычки → "
s=re.sub(r'[—–−-]','-',s) # тире → -
s=s.replace('\u00ad','') # мягкий перенос
s=s.replace('ё','е') # Ё→Е (OCR/PDF)
return s
```
Дедуп: `seen=set()` — добавлять, только если `normalize_entity(v) not in seen`.
### У.3 — Источник истины для верификации
Полный текст файла ДО обфускации (не чанк).
```python
def verify(entity, full_text):
if entity in full_text: return True
return normalize_entity(entity) in normalize_entity(full_text)
```
Если сущность из двух чанков с разным форматированием — нормализованный ключ одинаков → дедуп оставит один; хранить длиннее (или первый).
### У.4 — Батчинг мелких в первой итерации
НЕ нужен. 270 мелких: 1 файл=1 вызов ≈ 270 вызовов ≈ 101с при 4 потоках; батч по 5 → 54 вызова ≈ 20с. Разница ~80с несущественна. Батчинг — вторая итерация.
### У.5 — Промпт при чанкинге
Блок «Already captured by regex» ОСТАВИТЬ в каждом вызове (снижает дублирование с regex).
Блок правил — как есть в первую итерацию (если API с system/user — правила в system, текст чанка в user; иначе как сейчас).
Первый шаг: промпт не менять, только текстовый блок = чанк.
### У.6 — Общее время и rate-limit
Расчёт: 270 мелких (1 вызов) + 30 крупных (≈4 чанка) = 390 вызовов.
- 4 потока × 2с: 390/4×2 ≈ 195с ≈ 3.5 мин.
- 8 потоков: ~1.5–2 мин.
Rate-limit свой LLM: внешнего нет, ограничение GPU. Начать с 4, поднять до 8, если latency не растёт (>3× от базового — снижать).
---
## Итоговое решение (для внедрения, ждёт «делай»)
1. `scanner.py scan_llm_ner`: убрать `[:3000]`/`[:8000]`;
по каждому файлу из `all_texts` разбить на чанки (6000/500, split_into_chunks);
параллельные вызовы (ThreadPool, concurrency 4, крупные вперёд);
для каждого чанка — полный промпт + «regex-найденные»;
собрать сущности, normalize-дедуп, verify против полного текста файла, в mapping.
2. Добавить хелперы split_into_chunks / normalize_entity / verify в scanner.py.
3. Не дублировать regex-найденное; считать токены/время LLM корректно (llm_active/elapsed).
4. Прогнать тест на малом наборе (не прод): сколько сущностей добавит LLM, время.
Статус: НЕ внедрено (ждёт «делай»). Версия при внедрении — v0.0.57.