Skip to content

Commit 2bc6b39

Browse files
committed
Refactor optimization notebook and enhance actions module
- Updated the optimization notebook to improve prompt instructions and evaluation process. - Changed the manual prompt variable name for clarity and adjusted the evaluation metrics. - Enhanced the `run_optimization` function to accept custom instructions for better prompt optimization. - Added a new function to format optimized prompts for improved readability. - Introduced a new CSV analysis script to summarize categories, priorities, and assigned groups from the dataset.
1 parent f8f0fa1 commit 2bc6b39

3 files changed

Lines changed: 178 additions & 93 deletions

File tree

notebooks/02_optimization.ipynb

Lines changed: 103 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,15 @@
115115
"from dspy_tasks.actions import run_with_prompt\n",
116116
"from dspy_tasks.visualize import display_score, display_results_table\n",
117117
"\n",
118-
"# Dein manueller Versuch — ändere den Prompt und führe die Zelle erneut aus!\n",
119-
"MEIN_PROMPT = \"\"\"Classify this IT support ticket.\n",
120-
"Category MUST be one of: Event NO Customer Impact, Failure, Service Request\n",
121-
"Priority MUST be one of: High, Medium, Standard\n",
122-
"Assigned group MUST be one of: SDE - Service Desk, OFC - Office & Collaboration, PRM - Premium Support, CDC - Client Design & Standard SW Integration, OUM - Incident, Helpdesk, Service-Center IKT, Service-Center IKT Bestellungen, Smartcard Office, CBCD - Container Basierte Cloud Dienste, OPC - Applikationen, DevOps - Rein, BVX - ePortal Service Line, IOM - Input / Output Mgmt., OPM - DLC Dispatching, O-SDK, ESTV-RSS-Stammdaten, FIB - BIT Store Bollwerk, Immobilien BAZG, Bedarfsmanagement, Güter und Ausrüstung\"\"\"\n",
123-
"\n",
124-
"result = run_with_prompt(\"ticket_routing\", MEIN_PROMPT, max_eval=3)\n",
125-
"display_score(\"Dein manueller Prompt\", result.score)\n",
126-
"display_results_table(result.individual_scores)"
118+
"# Dein manueller Prompt — ändere ihn und führe die Zelle erneut aus!\n",
119+
"MEIN_PROMPT = \"\"\"Klassifiziere dieses IT-Support-Ticket.\n",
120+
"Kategorie MUSS eine von diesen sein: Event NO Customer Impact, Failure, Service Request\n",
121+
"Priorität MUSS eine von diesen sein: High, Medium, Standard\n",
122+
"Zuständige Gruppe MUSS eine von diesen sein: SDE - Service Desk, OFC - Office & Collaboration, PRM - Premium Support, CDC - Client Design & Standard SW Integration, OUM - Incident, Helpdesk, Service-Center IKT, Service-Center IKT Bestellungen, Smartcard Office, CBCD - Container Basierte Cloud Dienste, OPC - Applikationen, DevOps - Rein, BVX - ePortal Service Line, IOM - Input / Output Mgmt., OPM - DLC Dispatching, O-SDK, ESTV-RSS-Stammdaten, FIB - BIT Store Bollwerk, Immobilien BAZG, Bedarfsmanagement, Güter und Ausrüstung\"\"\"\n",
123+
"\n",
124+
"manual_result = run_with_prompt(\"ticket_routing\", MEIN_PROMPT, max_eval=8)\n",
125+
"display_score(\"Dein manueller Prompt\", manual_result.score)\n",
126+
"display_results_table(manual_result.individual_scores)"
127127
]
128128
},
129129
{
@@ -169,39 +169,30 @@
169169
"metadata": {},
170170
"outputs": [],
171171
"source": [
172-
"from dspy_tasks.actions import run_optimization, run_with_prompt\n",
172+
"from dspy_tasks.actions import run_optimization\n",
173173
"from dspy_tasks.tasks import get_task\n",
174174
"from dspy_tasks.visualize import display_improvement, display_insight, display_prompt_diff, display_score, display_results_table\n",
175175
"\n",
176176
"task = get_task(\"ticket_routing\")\n",
177177
"print(f\"⏳ Optimiere {task.name} mit BootstrapFewShot...\")\n",
178+
"print(f\" Basis: dein manueller Prompt\")\n",
178179
"print(f\" Das kann 10-60 Sekunden dauern...\\n\")\n",
179180
"\n",
180-
"result = run_optimization(\"ticket_routing\", \"BootstrapFewShot\", max_eval=8)\n",
181+
"bs_result = run_optimization(\"ticket_routing\", \"BootstrapFewShot\", max_eval=8, instructions=MEIN_PROMPT)\n",
181182
"\n",
182-
"# Zeige Baseline (zero-shot, OHNE Prompt) vs. Optimiert\n",
183183
"print(\"\" * 60)\n",
184-
"print(\"📊 VORHER: Zero-Shot Baseline (kein Prompt, kein Beispiel)\")\n",
185-
"display_score(\"Zero-Shot Baseline\", result.baseline_score)\n",
186-
"if result.baseline_individual_scores:\n",
187-
" display_results_table(result.baseline_individual_scores)\n",
184+
"print(\"📊 NACHHER: Optimierter Prompt (dein Prompt + Few-Shot Beispiele)\")\n",
185+
"display_score(\"Nach BootstrapFewShot\", bs_result.optimized_score)\n",
186+
"if bs_result.optimized_individual_scores:\n",
187+
" display_results_table(bs_result.optimized_individual_scores)\n",
188188
"\n",
189-
"print(\"\\n\" + \"\" * 60)\n",
190-
"print(\"📊 NACHHER: Optimierter Prompt (mit Few-Shot Beispielen)\")\n",
191-
"display_score(\"Nach BootstrapFewShot\", result.optimized_score)\n",
192-
"if result.optimized_individual_scores:\n",
193-
" display_results_table(result.optimized_individual_scores)\n",
189+
"display_improvement(manual_result.score, bs_result.optimized_score)\n",
194190
"\n",
195-
"display_improvement(result.baseline_score, result.optimized_score)\n",
196-
"print(f\"⏱️ Optimierung dauerte {result.elapsed_seconds}s | {result.llm_calls} LLM-Aufrufe\")\n",
197-
"\n",
198-
"display_prompt_diff(result.prompt_before, result.prompt_after)\n",
191+
"display_prompt_diff(MEIN_PROMPT, bs_result.prompt_after)\n",
199192
"\n",
200193
"display_insight(\"Was gerade passiert ist\",\n",
201-
" f\"Zero-Shot (ohne Prompt): {result.baseline_score:.0%}. \"\n",
202-
" f\"Nach Optimierung: {result.optimized_score:.0%}. \"\n",
203-
" \"Der Optimizer hat aus den Trainingsdaten die besten Beispiel-Tickets ausgewählt und in den Prompt eingefügt. \"\n",
204-
" \"Vergleich das mit deinem manuellen Prompt oben — ist der Optimizer besser?\")"
194+
" f\"Dein Prompt: {manual_result.score:.0%} → BootstrapFewShot: {bs_result.optimized_score:.0%}. \"\n",
195+
" \"Der Optimizer hat deinen Prompt als Basis genommen und die besten Beispiel-Tickets hinzugefügt.\")"
205196
]
206197
},
207198
{
@@ -241,15 +232,12 @@
241232
"\n",
242233
"task = get_task(\"ticket_routing\")\n",
243234
"\n",
244-
"# --- BootstrapFewShot ---\n",
235+
"# --- BootstrapFewShot (basierend auf manuellem Prompt) ---\n",
245236
"print(f\"⏳ BootstrapFewShot auf {task.name}...\\n\")\n",
246-
"r_bs = run_optimization(\"ticket_routing\", \"BootstrapFewShot\", max_eval=8)\n",
247-
"print(f\"\\n✅ BootstrapFewShot: {r_bs.baseline_score:.0%} → {r_bs.optimized_score:.0%}\")\n",
248-
"display_improvement(r_bs.baseline_score, r_bs.optimized_score)\n",
237+
"r_bs = run_optimization(\"ticket_routing\", \"BootstrapFewShot\", max_eval=8, instructions=MEIN_PROMPT)\n",
238+
"print(f\"✅ BootstrapFewShot: {r_bs.optimized_score:.0%}\")\n",
249239
"\n",
250-
"print(\"\\n📝 BootstrapFewShot — Prompt VORHER:\")\n",
251-
"print(r_bs.prompt_before)\n",
252-
"print(\"\\n📝 BootstrapFewShot — Prompt NACHHER:\")\n",
240+
"print(\"\\n📝 BootstrapFewShot — Prompt:\")\n",
253241
"print(r_bs.prompt_after[:2000])\n",
254242
"if len(r_bs.prompt_after) > 2000:\n",
255243
" print(f\"... ({len(r_bs.prompt_after)} Zeichen)\")\n",
@@ -258,16 +246,18 @@
258246
"if r_bs.optimized_individual_scores:\n",
259247
" display_results_table(r_bs.optimized_individual_scores)\n",
260248
"\n",
261-
"# --- MIPROv2 ---\n",
249+
"# --- MIPROv2 (basierend auf dem BESSEREN der beiden bisherigen Ergebnisse) ---\n",
262250
"print(f\"\\n{'━'*60}\")\n",
263-
"print(f\"⏳ MIPROv2 auf {task.name}...\\n\")\n",
264-
"r_mipro = run_optimization(\"ticket_routing\", \"MIPROv2\", max_eval=8)\n",
265-
"print(f\"\\n✅ MIPROv2: {r_mipro.baseline_score:.0%} → {r_mipro.optimized_score:.0%}\")\n",
266-
"display_improvement(r_mipro.baseline_score, r_mipro.optimized_score)\n",
267-
"\n",
268-
"print(\"\\n📝 MIPROv2 — Prompt VORHER:\")\n",
269-
"print(r_mipro.prompt_before)\n",
270-
"print(\"\\n📝 MIPROv2 — Prompt NACHHER:\")\n",
251+
"best_score = max(manual_result.score, r_bs.optimized_score)\n",
252+
"best_prompt = MEIN_PROMPT if manual_result.score >= r_bs.optimized_score else r_bs.prompt_after\n",
253+
"best_label = \"Manuell\" if manual_result.score >= r_bs.optimized_score else \"BootstrapFewShot\"\n",
254+
"print(f\"⏳ MIPROv2 auf {task.name}...\")\n",
255+
"print(f\" Basis: {best_label} ({best_score:.0%}) — das bisherige beste Ergebnis\\n\")\n",
256+
"\n",
257+
"r_mipro = run_optimization(\"ticket_routing\", \"MIPROv2\", max_eval=8, instructions=best_prompt)\n",
258+
"print(f\"✅ MIPROv2: {r_mipro.optimized_score:.0%}\")\n",
259+
"\n",
260+
"print(\"\\n📝 MIPROv2 — Prompt:\")\n",
271261
"print(r_mipro.prompt_after[:2000])\n",
272262
"if len(r_mipro.prompt_after) > 2000:\n",
273263
" print(f\"... ({len(r_mipro.prompt_after)} Zeichen)\")\n",
@@ -276,29 +266,22 @@
276266
"if r_mipro.optimized_individual_scores:\n",
277267
" display_results_table(r_mipro.optimized_individual_scores)\n",
278268
"\n",
279-
"# --- Vergleich ---\n",
269+
"# --- Vergleich aller 3 ---\n",
280270
"print(f\"\\n{'━'*60}\")\n",
281-
"print(\"📊 Zusammenfassung:\")\n",
282-
"print(f\" Dein manueller Prompt: scroll hoch und vergleich!\")\n",
283-
"print(f\" Zero-Shot Baseline: {r_bs.baseline_score:.0%}\")\n",
284-
"print(f\" BootstrapFewShot: {r_bs.optimized_score:.0%}\")\n",
285-
"print(f\" MIPROv2: {r_mipro.optimized_score:.0%}\")\n",
271+
"print(\"📊 Alle 3 Prompts im Vergleich:\")\n",
272+
"print(f\" 1. Manueller Prompt: {manual_result.score:.0%} (deine Anweisung)\")\n",
273+
"print(f\" 2. BootstrapFewShot: {r_bs.optimized_score:.0%} (dein Prompt + Beispiele)\")\n",
274+
"print(f\" 3. MIPROv2: {r_mipro.optimized_score:.0%} (bester Prompt + Beispiele + umgeschrieben)\")\n",
286275
"\n",
287276
"scores = {\n",
288-
" \"BootstrapFewShot\": {\"baseline\": r_bs.baseline_score, \"optimized\": r_bs.optimized_score},\n",
289-
" \"MIPROv2\": {\"baseline\": r_mipro.baseline_score, \"optimized\": r_mipro.optimized_score},\n",
277+
" \"Manuell\": {\"baseline\": manual_result.score, \"optimized\": manual_result.score},\n",
278+
" \"BootstrapFewShot\": {\"baseline\": manual_result.score, \"optimized\": r_bs.optimized_score},\n",
279+
" \"MIPROv2\": {\"baseline\": manual_result.score, \"optimized\": r_mipro.optimized_score},\n",
290280
"}\n",
291-
"fig = bar_comparison(\"Ticket Routing: Optimizer-Vergleich\", scores)\n",
281+
"fig = bar_comparison(\"Ticket Routing: Manuell vs. Optimizer\", scores)\n",
292282
"fig.show()"
293283
]
294284
},
295-
{
296-
"cell_type": "code",
297-
"execution_count": null,
298-
"metadata": {},
299-
"outputs": [],
300-
"source": []
301-
},
302285
{
303286
"cell_type": "markdown",
304287
"metadata": {},
@@ -470,32 +453,67 @@
470453
"metadata": {},
471454
"outputs": [],
472455
"source": [
473-
"# Verfügbare Aufgaben zum Optimieren:\n",
474-
"available = [\"multihop_qa\", \"report_generation\"]\n",
475-
"print(\"Verfügbare Aufgaben:\")\n",
476-
"for tid in available:\n",
477-
" t = get_task(tid)\n",
478-
" examples = t.load_examples()[:2]\n",
479-
" print(f\"\\n 📋 {tid}: {t.name}\")\n",
480-
" print(f\" {t.description}\")\n",
481-
" if examples:\n",
482-
" sample = examples[0]\n",
483-
" input_preview = \" | \".join(f\"{k}={str(v)[:60]}\" for k, v in sample.inputs().items())\n",
484-
" print(f\" Beispiel-Input: {input_preview[:120]}...\")\n",
485-
"\n",
486-
"# ═══ Wähle eine Aufgabe (ändere den String): ═══\n",
487-
"TASK = \"multihop_qa\"\n",
456+
"# ━━━ Verfügbare Aufgaben ━━━\n",
457+
"from dspy_tasks.tasks import list_tasks\n",
458+
"from dspy_tasks.actions import run_with_prompt\n",
459+
"\n",
460+
"print(\"Alle verfügbaren Aufgaben:\\n\")\n",
461+
"for tier in [1, 2, 3, 4]:\n",
462+
" tasks_in_tier = [t for t in list_tasks() if t.tier == tier]\n",
463+
" tier_labels = {1: \"Basics\", 2: \"Reasoning\", 3: \"Composition\", 4: \"Agentic\"}\n",
464+
" print(f\" Tier {tier} — {tier_labels[tier]}:\")\n",
465+
" for t in tasks_in_tier:\n",
466+
" examples = t.load_examples()[:1]\n",
467+
" sample_input = \"\"\n",
468+
" if examples:\n",
469+
" sample_input = \" | \".join(f\"{k}={str(v)[:40]}\" for k, v in examples[0].inputs().items())\n",
470+
" print(f\" • {t.id:25s} {t.name}\")\n",
471+
" print(f\" {t.description[:80]}\")\n",
472+
" if sample_input:\n",
473+
" print(f\" Beispiel: {sample_input[:100]}\")\n",
474+
" print()\n",
475+
"\n",
476+
"# ━━━ Aufgabe 1: Sentiment (BootstrapFewShot) ━━━\n",
477+
"SENT_PROMPT = \"Bestimme ob diese Bewertung positiv, negativ oder neutral ist.\"\n",
478+
"print(\"\" * 60)\n",
479+
"print(\"📋 Sentiment Classification — BootstrapFewShot\\n\")\n",
480+
"\n",
481+
"manual_sent = run_with_prompt(\"sentiment\", SENT_PROMPT, max_eval=8)\n",
482+
"display_score(\"Sentiment: Manueller Prompt\", manual_sent.score)\n",
483+
"display_results_table(manual_sent.individual_scores)\n",
484+
"\n",
485+
"print(\"\\n⏳ Optimiere mit BootstrapFewShot (basierend auf manuellem Prompt)...\")\n",
486+
"r_sent = run_optimization(\"sentiment\", \"BootstrapFewShot\", max_eval=8, instructions=SENT_PROMPT)\n",
487+
"display_score(\"Sentiment: Nach BootstrapFewShot\", r_sent.optimized_score)\n",
488+
"if r_sent.optimized_individual_scores:\n",
489+
" display_results_table(r_sent.optimized_individual_scores)\n",
490+
"display_improvement(manual_sent.score, r_sent.optimized_score)\n",
488491
"\n",
492+
"# ━━━ Aufgabe 2: Multi-Hop QA (BootstrapFewShot → MIPROv2) ━━━\n",
493+
"MHQA_PROMPT = \"Beantworte die Frage basierend auf dem Kontext. Denke Schritt für Schritt.\"\n",
489494
"print(f\"\\n{'━'*60}\")\n",
490-
"print(f\"⏳ Optimiere {TASK}...\")\n",
491-
"result = run_optimization(TASK, \"BootstrapFewShot\", max_eval=8)\n",
492-
"display_improvement(result.baseline_score, result.optimized_score)\n",
493-
"display_prompt_diff(result.prompt_before, result.prompt_after)\n",
494-
"\n",
495-
"# Zeige Ergebnisse pro Beispiel\n",
496-
"print(\"\\n📊 Ergebnisse nach Optimierung:\")\n",
497-
"if result.optimized_individual_scores:\n",
498-
" display_results_table(result.optimized_individual_scores)"
495+
"print(\"📋 Multi-Hop QA — BootstrapFewShot → MIPROv2\\n\")\n",
496+
"\n",
497+
"manual_mhqa = run_with_prompt(\"multihop_qa\", MHQA_PROMPT, max_eval=8)\n",
498+
"display_score(\"Multi-Hop QA: Manueller Prompt\", manual_mhqa.score)\n",
499+
"display_results_table(manual_mhqa.individual_scores)\n",
500+
"\n",
501+
"# Erst BootstrapFewShot\n",
502+
"print(\"\\n⏳ Schritt 1: BootstrapFewShot...\")\n",
503+
"r_mhqa_bs = run_optimization(\"multihop_qa\", \"BootstrapFewShot\", max_eval=8, instructions=MHQA_PROMPT)\n",
504+
"display_score(\"Multi-Hop QA: Nach BootstrapFewShot\", r_mhqa_bs.optimized_score)\n",
505+
"\n",
506+
"# Dann MIPROv2 auf dem besseren Ergebnis\n",
507+
"best_mhqa_score = max(manual_mhqa.score, r_mhqa_bs.optimized_score)\n",
508+
"best_mhqa_prompt = MHQA_PROMPT if manual_mhqa.score >= r_mhqa_bs.optimized_score else r_mhqa_bs.prompt_after\n",
509+
"best_mhqa_label = \"Manuell\" if manual_mhqa.score >= r_mhqa_bs.optimized_score else \"BootstrapFewShot\"\n",
510+
"print(f\"\\n⏳ Schritt 2: MIPROv2 (basierend auf {best_mhqa_label}: {best_mhqa_score:.0%})...\")\n",
511+
"r_mhqa = run_optimization(\"multihop_qa\", \"MIPROv2\", max_eval=8, instructions=best_mhqa_prompt)\n",
512+
"display_score(\"Multi-Hop QA: Nach MIPROv2\", r_mhqa.optimized_score)\n",
513+
"if r_mhqa.optimized_individual_scores:\n",
514+
" display_results_table(r_mhqa.optimized_individual_scores)\n",
515+
"\n",
516+
"print(f\"\\n📊 Manuell {manual_mhqa.score:.0%} → BootstrapFewShot {r_mhqa_bs.optimized_score:.0%} → MIPROv2 {r_mhqa.optimized_score:.0%}\")"
499517
]
500518
},
501519
{

notebooks/_analyze_csv.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import csv
2+
from collections import Counter
3+
4+
with open('/Users/abossard/Desktop/projects/python-quart-vite-react/csv/data.csv', encoding='utf-8', errors='replace') as f:
5+
reader = csv.DictReader(f)
6+
rows = list(reader)
7+
8+
print(f'Total rows: {len(rows)}')
9+
sample = rows[0]
10+
for col in ['Summary*', 'Category', 'Priority*', 'Assigned Group*+', 'Incident Type*']:
11+
val = sample.get(col, 'NOT FOUND')
12+
print(f' {col}: {str(val)[:60]}')
13+
14+
cats = Counter(r.get('Category', '') for r in rows)
15+
prios = Counter(r.get('Priority*', '') for r in rows)
16+
groups = Counter(r.get('Assigned Group*+', '') for r in rows)
17+
18+
print(f'\nCategories: {dict(cats.most_common(5))}')
19+
print(f'Priorities: {dict(prios.most_common(5))}')
20+
print(f'\nGroups ({len(groups)}):')
21+
for g, c in groups.most_common(25):
22+
print(f' {c:4d} {g}')

notebooks/dspy_tasks/actions.py

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,20 +84,32 @@ def run_on_examples(examples, instructions: str, signature_class, metric_fn) ->
8484
)
8585

8686

87-
def run_optimization(task_id: str, optimizer: str = "BootstrapFewShot", *, max_eval: Optional[int] = None) -> OptimizationResult:
88-
"""Optimize a task's prompt, then evaluate. Takes 10-60 seconds."""
87+
def run_optimization(task_id: str, optimizer: str = "BootstrapFewShot", *, max_eval: Optional[int] = None, instructions: Optional[str] = None) -> OptimizationResult:
88+
"""Optimize a task's prompt, then evaluate. Takes 10-60 seconds.
89+
90+
If instructions is provided, it's used as the starting prompt (instead of zero-shot).
91+
"""
8992
task = get_task(task_id)
9093
trainset, devset = task.split_examples()
9194
if max_eval:
9295
devset = devset[:max_eval]
9396

94-
# Baseline
95-
module = task.make_module()
97+
# Build module — with custom instructions if provided
98+
def _make_module_with_instructions():
99+
if instructions:
100+
CustomSig = _make_signature(task.signature_class, instructions)
101+
if task.module_type == "ChainOfThought":
102+
return dspy.ChainOfThought(CustomSig)
103+
return dspy.Predict(CustomSig)
104+
return task.make_module()
105+
106+
# Baseline (with the given instructions, not zero-shot)
107+
module = _make_module_with_instructions()
96108
baseline_results = _evaluate_examples(module, devset, task.metric_fn)
97109
baseline_score = _mean([r["score"] for r in baseline_results])
98110

99-
# Optimize
100-
module_fresh = task.make_module()
111+
# Optimize (starting from the same instructions)
112+
module_fresh = _make_module_with_instructions()
101113
start = time.time()
102114
if optimizer == "MIPROv2":
103115
opt = dspy.MIPROv2(metric=task.metric_fn, auto="light")
@@ -119,8 +131,8 @@ def run_optimization(task_id: str, optimizer: str = "BootstrapFewShot", *, max_e
119131
optimized_score=opt_score,
120132
improvement=improvement,
121133
improvement_pct=(improvement / max(baseline_score, 0.01)) * 100,
122-
prompt_before="(zero-shot)",
123-
prompt_after=str(optimized_module.dump_state()) if hasattr(optimized_module, 'dump_state') else "(optimized)",
134+
prompt_before=instructions or "(zero-shot)",
135+
prompt_after=_format_optimized_prompt(optimized_module),
124136
trial_scores=[baseline_score, opt_score],
125137
elapsed_seconds=round(opt_elapsed, 2),
126138
llm_calls=len(baseline_results) + len(opt_results),
@@ -138,6 +150,39 @@ def _current_model() -> str:
138150
return str(getattr(lm, 'model', '?')) if lm else '?'
139151

140152

153+
def _format_optimized_prompt(module) -> str:
154+
"""Format an optimized DSPy module's state into a human-readable string."""
155+
if not hasattr(module, 'dump_state'):
156+
return "(optimized)"
157+
158+
state = module.dump_state()
159+
parts = []
160+
161+
for predictor_name, predictor_state in state.items():
162+
# Extract instructions
163+
sig = predictor_state.get('signature', {})
164+
instructions = sig.get('instructions', '')
165+
if instructions:
166+
parts.append("━━━ INSTRUCTIONS ━━━")
167+
parts.append(instructions)
168+
169+
# Extract demos (few-shot examples)
170+
demos = predictor_state.get('demos', [])
171+
if demos:
172+
parts.append(f"\n━━━ FEW-SHOT EXAMPLES ({len(demos)}) ━━━")
173+
for i, demo in enumerate(demos):
174+
parts.append(f"\n Example {i+1}:")
175+
for key, value in demo.items():
176+
if key == 'augmented':
177+
continue
178+
val_str = str(value)
179+
if len(val_str) > 200:
180+
val_str = val_str[:200] + "..."
181+
parts.append(f" {key}: {val_str}")
182+
183+
return "\n".join(parts) if parts else str(state)
184+
185+
141186
def _make_signature(base_sig, instructions: str):
142187
fields = {}
143188
for name, field_info in base_sig.model_fields.items():

0 commit comments

Comments
 (0)