Usa questa skill quando devi aggiungere o modificare la logica di classificazione del RulesEngine, aggiornare parsing_rules.json di un profilo, aggiungere combination_rules, modificare i pesi strong/weak, o debuggare una classificazione errata o confidence bassa.
Il RulesEngine è il layer dichiarativo di classificazione: legge parsing_rules.json, fa merge con il vocabolario condiviso, e produce un ClassificationResult (tipo messaggio + confidence + matched_markers). Non estrae entità — quella responsabilità appartiene al profile.py.
parsing_rules.jsoncombination_rules per casi ambiguistrong / weaktrader_profiles/shared/src/parser/rules_engine.py ← motore (non toccare salvo bug)
src/parser/trader_profiles/shared/
├── russian_trading.json ← vocabolario russo condiviso
└── english_trading.json ← vocabolario inglese condiviso
src/parser/trader_profiles/<trader>/parsing_rules.json ← profilo specifico
from src.parser.rules_engine import RulesEngine
engine = RulesEngine.load("src/parser/trader_profiles/trader_3/parsing_rules.json")
result = engine.classify(text)
# → ClassificationResult(
# message_type="NEW_SIGNAL",
# confidence=1.4, # non capped a 1.0 prima del merge in TraderParseResult
# matched_markers=["new_signal/лонг", "new_signal/sl:"],
# intents_hint=["U_MOVE_STOP"]
# )
intents = engine.detect_intents(text)
# → ["U_CLOSE_FULL"]
engine.is_blacklisted(text)
# → False
engine.number_format
# → {"decimal_separator": ".", "thousands_separator": " "}
Per i test, creare l'engine direttamente da dict senza file JSON:
engine = RulesEngine.from_dict({
"classification_markers": {
"new_signal": {"strong": ["лонг"], "weak": ["сетап"]}
}
})
{
"language": "ru",
"shared_vocabulary": "russian_trading",
"number_format": {
"decimal_separator": ".",
"thousands_separator": " "
},
"classification_markers": {
"new_signal": {
"strong": ["лонг", "long", "sl:", "tp1:"],
"weak": ["сигнал", "сетап"]
},
"update": {
"strong": ["стоп в бу", "close all", "закрываю все"],
"weak": ["по этим", "тут не актуально"]
},
"info_only": {
"strong": ["обзор", "VIP MARKET UPDATE"],
"weak": ["анализ", "мнение"]
}
},
"combination_rules": [
{
"if": ["weak_sl_ref", "strong_be_marker"],
"then": "update",
"confidence_boost": 0.3
}
],
"intent_markers": {
"U_MOVE_STOP": ["стоп в бу", "move stop to be"],
"U_CLOSE_FULL": ["закрываю все", "close all"],
"U_CLOSE_PARTIAL": ["частичная фиксация", "partial close"],
"U_CANCEL_PENDING": ["убираем лимитку", "cancel pending"],
"U_REENTER": ["повторный вход", "reenter"],
"U_ADD_ENTRY": ["добавляю вход", "add entry"],
"U_MODIFY_ENTRY": ["меняю вход", "modify entry"],
"U_UPDATE_TAKE_PROFITS": ["меняю тейки", "update tp"]
},
"target_ref_markers": {
"strong": {
"telegram_link": "t\\.me/",
"explicit_id": ["SIGNAL ID:\\s*#?\\d+", "#\\d{3,}"]
},
"weak": {
"pronouns": ["по этим", "по этому", "тут"]
}
},
"blacklist": ["#admin", "#stats", "weekly recap"],
"fallback_hook": {
"enabled": false,
"provider": null,
"model": null
}
}
new_signal, update, info_only):
strong × 1.0 + weak × 0.4combination_rules: se tutti i marker if corrispondono, aggiunge confidence_boost alla categoria thenUNCLASSIFIED, confidence=0.0intents_hint viene calcolato sempre, indipendentemente dalla classificazioneSe shared_vocabulary è dichiarato nel profilo, il motore fa il merge automatico:
classification_markers: unione per categoria e per strong/weakintent_markers, target_ref_markers: unione per chiaveblacklist: unione con deduplicazioneparsing_rules.json, non in rules_engine.pyrules_engine.py non va toccato salvo bug nel motore (logica di merge, pesi)strong vale 1.0, un weak vale 0.4 — calibrare di conseguenzacombination_rules servono per casi dove due weak insieme equivalgono a uno strongintents_hint nel ClassificationResult è un suggerimento — il profile.py è responsabile della classificazione finale degli intentsrules_engine.pyQuando un messaggio viene classificato male:
result.matched_markers per vedere quali marcatori hanno matchatopython parser_test/scripts/replay_parser.py --trader <trader>Quando usi questa skill, restituisci: