feat(prompt): PromptLibrary v3.1 — anti_patterns + output_priorities
Estende il compositor del SYSTEM con 2 sezioni opzionali iniettate
DOPO i VINCOLI core e PRIMA dell'EXAMPLE:
ANTI-PATTERN DA EVITARE: lista esplicita di cose da evitare (overfitting,
correlazione=causalita, > 4 AND, singolo evento estremo, ecc.)
PRIORITA' DI OUTPUT: trade-off come "robustezza > ottimalita su singolo
regime", "semplicita > complessita raffinata", "selettivita > attivita"
Razionale: ridurre la varianza non-utile nelle strategie generate
quando il LLM affronta trade-off, e prevenire overfitting nel design.
Entrambi i campi sono opzionali (skip se "") -> backward-compatible
con prompts.json v3.0.
PromptLibrary v3.1: +2 fields top-level (default "").
_build_system_prompt: 2 sezioni condizionali post-VINCOLI.
Test: +3 unit (compositor inject/skip + from_json parsing).
Tot: 235 test pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -197,7 +197,16 @@ def _build_system_prompt(lib: PromptLibrary, genome: HypothesisAgentGenome) -> s
|
||||
parts.append("")
|
||||
# 6. Vincoli (core scaffold)
|
||||
parts.append(_SYSTEM_CONSTRAINTS)
|
||||
# 7. Esempio (core scaffold)
|
||||
# 7. NEW v3.1: anti-pattern e output priorities (da prompts.json, opzionali)
|
||||
if lib.anti_patterns:
|
||||
parts.append("\nANTI-PATTERN DA EVITARE:\n")
|
||||
parts.append(lib.anti_patterns)
|
||||
parts.append("")
|
||||
if lib.output_priorities:
|
||||
parts.append("\nPRIORITA' DI OUTPUT (trade-off):\n")
|
||||
parts.append(lib.output_priorities)
|
||||
parts.append("")
|
||||
# 8. Esempio (core scaffold)
|
||||
parts.append(_SYSTEM_EXAMPLE)
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ class PromptLibrary:
|
||||
v3.0: aggiunge 4 campi top-level strategy-specific iniettabili nel prompt
|
||||
dal compositor ``_build_system_prompt``. Tutti opzionali con default sensati
|
||||
per backcompat.
|
||||
v3.1: aggiunge anti_patterns e output_priorities iniettati dopo i VINCOLI core.
|
||||
"""
|
||||
|
||||
styles: dict[str, str]
|
||||
@@ -98,6 +99,8 @@ class PromptLibrary:
|
||||
pattern_guidance: str = field(default="") # sezione PATTERN GUIDANCE del SYSTEM
|
||||
instruction: str = field(default="") # frase finale USER ("Genera una strategia...")
|
||||
domain_warnings: str = field(default="") # opzionale: warning di dominio (es. crypto 24/7)
|
||||
anti_patterns: str = field(default="") # NEW v3.1: lista esplicita di pattern da evitare
|
||||
output_priorities: str = field(default="") # NEW v3.1: trade-off espliciti di output
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if not self.styles:
|
||||
@@ -115,6 +118,8 @@ class PromptLibrary:
|
||||
("pattern_guidance", self.pattern_guidance),
|
||||
("instruction", self.instruction),
|
||||
("domain_warnings", self.domain_warnings),
|
||||
("anti_patterns", self.anti_patterns),
|
||||
("output_priorities", self.output_priorities),
|
||||
):
|
||||
if not isinstance(value, str):
|
||||
raise PromptLibraryError(
|
||||
@@ -135,6 +140,8 @@ class PromptLibrary:
|
||||
pattern_guidance=_DEFAULT_PATTERN_GUIDANCE,
|
||||
instruction=_DEFAULT_INSTRUCTION,
|
||||
domain_warnings="",
|
||||
anti_patterns="",
|
||||
output_priorities="",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@@ -190,6 +197,13 @@ class PromptLibrary:
|
||||
pattern_guidance = data.get("pattern_guidance", "")
|
||||
instruction = data.get("instruction", "")
|
||||
domain_warnings = data.get("domain_warnings", "")
|
||||
# Parse new optional top-level fields (v3.1)
|
||||
anti_patterns_raw = data.get("anti_patterns", "")
|
||||
output_priorities_raw = data.get("output_priorities", "")
|
||||
if not isinstance(anti_patterns_raw, str):
|
||||
raise PromptLibraryError(f"anti_patterns deve essere stringa, non {type(anti_patterns_raw)}")
|
||||
if not isinstance(output_priorities_raw, str):
|
||||
raise PromptLibraryError(f"output_priorities deve essere stringa, non {type(output_priorities_raw)}")
|
||||
|
||||
return cls(
|
||||
styles=styles,
|
||||
@@ -198,6 +212,8 @@ class PromptLibrary:
|
||||
pattern_guidance=pattern_guidance,
|
||||
instruction=instruction,
|
||||
domain_warnings=domain_warnings,
|
||||
anti_patterns=anti_patterns_raw,
|
||||
output_priorities=output_priorities_raw,
|
||||
)
|
||||
|
||||
@property
|
||||
|
||||
@@ -370,3 +370,53 @@ def test_user_template_uses_instruction_from_library(mocker): # type: ignore[no
|
||||
user_msg = call_kwargs["user"]
|
||||
assert "INSTR_X" in user_msg
|
||||
assert "Genera una strategia che cerchi anomalie sfruttabili in questo regime." not in user_msg
|
||||
|
||||
|
||||
def test_build_system_prompt_includes_anti_patterns_and_priorities(mocker): # type: ignore[no-untyped-def]
|
||||
"""anti_patterns e output_priorities da PromptLibrary appaiono nel SYSTEM prompt."""
|
||||
fake_llm = mocker.MagicMock()
|
||||
fake_llm.complete.return_value = CompletionResult(
|
||||
text=VALID_STRATEGY_JSON,
|
||||
input_tokens=200,
|
||||
output_tokens=80,
|
||||
tier=ModelTier.C,
|
||||
model="qwen",
|
||||
)
|
||||
lib = PromptLibrary(
|
||||
styles={"physicist": "Pensa come un fisico."},
|
||||
focus={},
|
||||
anti_patterns="EVITA_X",
|
||||
output_priorities="PRIORI_X",
|
||||
)
|
||||
agent = HypothesisAgent(llm=fake_llm, prompt_library=lib)
|
||||
agent.propose(make_genome(), make_summary())
|
||||
call_kwargs = fake_llm.complete.call_args.kwargs
|
||||
system_msg = call_kwargs["system"]
|
||||
assert "ANTI-PATTERN DA EVITARE" in system_msg
|
||||
assert "EVITA_X" in system_msg
|
||||
assert "PRIORITA' DI OUTPUT" in system_msg
|
||||
assert "PRIORI_X" in system_msg
|
||||
|
||||
|
||||
def test_build_system_prompt_skips_anti_patterns_and_priorities_when_empty(mocker): # type: ignore[no-untyped-def]
|
||||
"""anti_patterns='' e output_priorities='' -> sezioni opzionali assenti nel SYSTEM."""
|
||||
fake_llm = mocker.MagicMock()
|
||||
fake_llm.complete.return_value = CompletionResult(
|
||||
text=VALID_STRATEGY_JSON,
|
||||
input_tokens=200,
|
||||
output_tokens=80,
|
||||
tier=ModelTier.C,
|
||||
model="qwen",
|
||||
)
|
||||
lib = PromptLibrary(
|
||||
styles={"physicist": "Pensa come un fisico."},
|
||||
focus={},
|
||||
anti_patterns="",
|
||||
output_priorities="",
|
||||
)
|
||||
agent = HypothesisAgent(llm=fake_llm, prompt_library=lib)
|
||||
agent.propose(make_genome(), make_summary())
|
||||
call_kwargs = fake_llm.complete.call_args.kwargs
|
||||
system_msg = call_kwargs["system"]
|
||||
assert "ANTI-PATTERN" not in system_msg
|
||||
assert "PRIORITA' DI OUTPUT" not in system_msg
|
||||
|
||||
@@ -76,3 +76,15 @@ def test_prompt_library_accepts_empty_string_for_optional_fields() -> None:
|
||||
)
|
||||
assert lib.agent_role == ""
|
||||
assert lib.domain_warnings == ""
|
||||
|
||||
|
||||
def test_from_json_loads_anti_patterns_and_output_priorities(tmp_path: Path) -> None:
|
||||
"""from_json() legge anti_patterns e output_priorities (v3.1)."""
|
||||
data = {
|
||||
"styles": {"physicist": {"directive": "Cerca leggi conservative."}},
|
||||
"anti_patterns": "Evita overfitting.",
|
||||
"output_priorities": "Robustezza > ottimalita.",
|
||||
}
|
||||
lib = PromptLibrary.from_json(_write_json(data, tmp_path))
|
||||
assert lib.anti_patterns == "Evita overfitting."
|
||||
assert lib.output_priorities == "Robustezza > ottimalita."
|
||||
|
||||
Reference in New Issue
Block a user