reflection: Hermes-style self-reflection (последняя открытая Hermes-фича)
Self-reflection: каждые N пользовательских ходов агент запускает one-shot
LLM-размышление о качестве своих ответов, сохраняет score+weakSpots в SQLite,
подмешивает top-K последних рефлексий в system prompt как "слабые места".
* sqldelight: новая таблица reflection (id, conversation_id?, created_at,
turns_analyzed, score, summary, weak_spots_json) + индексы по created_at и
conversation_id.
* persistence: Reflection data class + ReflectionStore interface +
SqliteReflectionStore (insert/get/listRecent/listForConversation/
deleteOlderThan/count + events Flow). weakSpots хранятся как JSON-массив,
парсятся ручным сканером (без kotlinx-serialization в этом модуле).
* agent: LlmReflector (one-shot LiteLlm через createConversation +
send, structured-output JSON). ReflectionParser (hand-rolled,
толерантный к ```json fences и лидирующему/завершающему тексту;
score принимает int или строку; weakSpots — массив).
* agent: ReflectionPrompts (Russian system+user prompts, аналогично
LlmMemoryReviewer/ReviewPrompts).
* agent: ChatAgent.buildSystemPrompt расширен параметром reflections —
добавляется секция `## Self-reflection: твои слабые места за последнее время`
после memory и перед soul-prepend.
* agent: ChatConversation.scheduleReflection — каждые reflectionInterval
пользовательских ходов (счётчик через workingMemory.list) запускает
reflector на Dispatchers.IO, результат сохраняет в reflectionStore
с conversationId. Не блокирует turn.
* AgentikConfig: новые поля reflectionInterval (env AGENTIK_REFLECTION_INTERVAL,
default 10, clamped 0..1000) и reflectionTopK (env AGENTIK_REFLECTION_TOP_K,
default 3, clamped 0..20).
* Main.kt: если reflectionInterval > 0 — создаём LlmReflector(llm); загружаем
top-K из SQLite в system prompt.
* Ids.reflection() — генератор id "refl-<uuid>".
* Tests: ReflectionParserTest (7: clean JSON, fences, лидирующий текст,
score-as-string, отсутствие score, невалидный JSON, escape-последовательности),
ReflectionStoreTest (7: round-trip, listRecent с лимитом, фильтр по
conversation_id, deleteOlderThan, count, encode/decode строк), и
ChatAgentReflectionTest (3: секция скрыта при пустых, присутствует с
score+spots, порядок soul→memory→reflection).
* README: новые env-переменные, раздел "Self-reflection", startup output.
Smoke test подтверждает: reflection секция появляется в system prompt когда
в SQLite есть записи (listRecent возвращает непустой список). При
reflectionInterval=0 reflector не создаётся, scheduleReflection — no-op.
Tests: 305 total green (+17: 7+7+3). Fatjar собирается, logback-вывод
работает (logging: см. предыдущий коммит f5a551b).
This commit is contained in:
@@ -53,6 +53,8 @@ java -jar standalone/build/libs/standalone-all.jar
|
||||
| `OPENAI_CONTEXT_WINDOW` | _выкл._ | Лимит контекстного окна в токенах (для compaction'а) |
|
||||
| `AGENTIK_GOOGLE_CONTEXT_WINDOW` | _выкл._ | То же для Google backend |
|
||||
| `AGENTIK_COMPRESSION_THRESHOLD` | `0.8` | Доля лимита, при которой запускается compaction |
|
||||
| `AGENTIK_REFLECTION_INTERVAL` | `10` | Self-reflection: каждый N-й пользовательский ход агент оценивает себя (LiteLlm) и сохраняет рефлексию. `0` = выключено. |
|
||||
| `AGENTIK_REFLECTION_TOP_K` | `3` | Сколько последних рефлексий подмешивать в system prompt как «слабые места». `0` = не подмешивать. |
|
||||
|
||||
### OpenAI backend
|
||||
|
||||
@@ -178,6 +180,26 @@ export AGENTIK_COMPRESSION_THRESHOLD=0.7 # сжимаем раньше
|
||||
нового compaction не запускается (защита от зацикливания). Решение —
|
||||
поднять `OPENAI_CONTEXT_WINDOW` или понизить threshold.
|
||||
|
||||
## Self-reflection (Hermes-style «слабые места»)
|
||||
|
||||
Каждые `AGENTIK_REFLECTION_INTERVAL` пользовательских ходов (default 10)
|
||||
запускается фоновая one-shot LLM-размышление: «оцени последние ходы,
|
||||
поставь score 1..5, выдели слабые места». Результат сохраняется в таблицу
|
||||
`reflection` SQLite и подмешивается в system prompt следующего хода как
|
||||
«Твои слабые места за последнее время».
|
||||
|
||||
Включено когда `AGENTIK_REFLECTION_INTERVAL > 0`. Требует LiteLlm
|
||||
(on-device или OpenAI — что указан в `AGENTIK_LLM_BACKEND`). На каждый
|
||||
reflection — один LiteLlm вызов (~1-3 сек для on-device, ~200-500мс для
|
||||
OpenAI). Это происходит в фоне (`Dispatchers.IO`), основной диалог не
|
||||
блокируется.
|
||||
|
||||
Топ-K последних рефлексий загружается в `buildSystemPrompt` и выводится
|
||||
как `## Self-reflection: твои слабые места за последнее время`. Агент
|
||||
видит их в каждом следующем ходе и (теоретически) должен избегать
|
||||
повторения. Используется как cheap "auto-improving prompt feedback"
|
||||
без ручного переписывания system prompt.
|
||||
|
||||
## Куратор памяти (Curator)
|
||||
|
||||
Фоновая корутина (запускается автоматически, если `AGENTIK_MEMORY_DIR != off`):
|
||||
@@ -356,6 +378,7 @@ agentik standalone listening on http://localhost:8080
|
||||
memory: /var/lib/agentik/memory (md-backend)
|
||||
compaction: enabled, threshold=0.8, window=128000 tokens
|
||||
curator: enabled (interval=1d, maxAge=90d)
|
||||
reflection: enabled (interval=10, topK=3)
|
||||
```
|
||||
|
||||
## Остановка
|
||||
|
||||
Reference in New Issue
Block a user