Curriculum design for ConvFinQA, paving the way to program optimization
programming
dspy
curriculum-learning
Author
Shubham Gupta
Published
September 1, 2025
In our previous exploration, we analyzed 3,458 ConvFinQA records and established a curriculum learning framework with three difficulty stages: Easy (β€2 ops, simple context), Medium (2-3 ops, moderate complexity), and Hard (β₯4 ops, complex multi-turn reasoning).
Now itβs time to put this curriculum to work by implementing and evaluating our models.
From Prompting to Programming
Traditionally, LLM applications rely on hand-rolled promptsβcarefully crafted text instructions that are often brittle and difficult to optimize, especially for complex multi-step reasoning tasks like financial QA.
Our curriculum learning approach demands systematic experimentation across models, difficulty levels, and optimization strategies. This makes DSPy the ideal framework, as it transforms prompting from an art into systematic, testable code.
Why DSPy for curriculum learning?
Reproducible experiments: Prompts become Python objects β diffable, unit-testable, version-controlled
Optimization: Built-in optimizers (LabeledFewShot, BootstrapFewShot) auto-search the prompt space across our curriculum stages
Clean evaluation pipeline: First-class metrics supportβplug in exact match, hit .compile(), get train/val loops with curriculum-aware sampling
Model flexibility: Test curriculum effects across GPT-4, o4-mini, Gemini, and open-source models with one-line swaps
Efficient iteration: Caching and threading speed up development cycles crucial for curriculum experiments
This approach lets us test whether our EasyβMediumβHard curriculum improves financial reasoning compared to random sampling.
Evaluation Metrics
For this exploratory analysis, we need a clear metric to measure model performance across our curriculum learning experiments. Following the original ConvFinQA paper, we adopt Exact Match (EM) as our primary evaluation metric.
Primary Metric: Turn-level EM
Turn-level EM measures whether the generated answer for a specific dialogue turn exactly matches the gold standard answer. This binary metric (1 for exact match, 0 otherwise) provides a strict but interpretable measure of performance that directly aligns with the task requirements.
We choose this as our primary metric for several reasons: - Simplicity: Easy to implement and interpret for initial experimentation - Strictness: Financial reasoning requires precisionβapproximate answers can be misleading - Comparability: Direct comparison with baseline results from the original paper - Curriculum sensitivity: Clear signal for measuring improvement across difficulty levels
Additional Metrics (Future Work)
There are several other metrics could be useful:
Conversation-level metrics like Dialogue Mean EM and Joint EM would better capture multi-turn reasoning dependencies, but add complexity to curriculum design. Since our curriculum is based on individual example difficulty rather than conversation-level complexity, turn-level metrics are more appropriate for this phase.
Diagnostic metrics such as Exec-agree % and numeric error analysis would help distinguish between reasoning failures and execution errors. However, for establishing whether curriculum learning improves over random sampling, the binary success signal from exact match provides sufficient discriminative power.
Efficiency metrics like program length and evidence tokens could reveal interesting patterns about how curriculum learning affects model behavior, but are secondary to establishing basic performance improvements.
Weβve skipped the other metrics for now for the sake of brevity.
Model List
We will consider the following families of models:
Family
Rationale
Benchmarked Checkpoints
Non-Reasoning
Classic next-token predictors. Useful as baselines for curriculum-learning because they expose the value of explicit reasoning.
import dspyllms = [ lm_oai_gpt_4_1, lm_oai_gpt_4_1_mini, lm_oai_o4_mini, lm_anthropic_sonnet_4_0, lm_gemini_flash_2_5, lm_gemini_flash_2_5_lite, lm_oai_o3, lm_anthropic_opus_4_0, lm_gemini_pro_2_5, lm_qwen3_32b,]class Echo(dspy.Signature):"""Echoes the input prompt.""" prompt = dspy.InputField() output = dspy.OutputField()with mlflow.start_run(run_name="Setup") as run:for lm in llms:try:with dspy.context(lm=lm, track_usage=True, cache=True):if lm in [lm_oai_gpt_4_1, lm_oai_gpt_4_1_mini]: program = dspy.Predict("instruction -> answer")else: program = dspy.ChainOfThought("instruction -> answer") response = program(instruction="What is the date?")ifgetattr(response, "reasoning", None):print(f"{lm.model} Reasoning: {response.reasoning}")print(f"{lm.model}: {response.answer}")exceptExceptionas e:print(f"{getattr(lm, 'model', lm)}: ERROR - {e}")
openai/gpt-4.1-2025-04-14: Today's date is June 13, 2024.
openai/gpt-4.1-mini-2025-04-14: The current date is June 15, 2024.
openai/o4-mini-2025-04-16 Reasoning: The user asked for the current date. I will provide today's date in a clear, human-readable format.
openai/o4-mini-2025-04-16: The current date is May 30, 2024.
anthropic/claude-sonnet-4-20250514 Reasoning: The user is asking for the current date. However, I don't have access to real-time information or the ability to know what the current date is. I should explain that I cannot provide the current date and suggest how they can find this information.
anthropic/claude-sonnet-4-20250514: I don't have access to real-time information, so I cannot tell you the current date. To find today's date, you can:
- Check your computer, phone, or other device
- Search "what is today's date" in a search engine
- Ask a voice assistant like Siri, Alexa, or Google Assistant
gemini/gemini-2.5-flash Reasoning: The user is asking for the current date. I will provide today's date.
gemini/gemini-2.5-flash: June 10, 2024
gemini/gemini-2.5-flash-lite Reasoning: The user is asking for the current date. I need to access the current date and format it as requested.
gemini/gemini-2.5-flash-lite: The current date is October 26, 2023.
openai/o3-2025-04-16 Reasoning: I donβt have real-time access to the system clock, so Iβm unable to determine the exact current date at the moment of this response.
openai/o3-2025-04-16: Iβm sorry, I donβt have access to real-time information to tell todayβs date.
anthropic/claude-opus-4-20250514 Reasoning: The user is asking for the current date. However, as an AI assistant, I don't have access to real-time information and cannot provide the current date. I should explain this limitation clearly to the user.
anthropic/claude-opus-4-20250514: I don't have access to real-time information, so I cannot tell you today's date. To get the current date, you can check your device's calendar, search "what's today's date" in a search engine, or ask a voice assistant with real-time capabilities.
gemini/gemini-2.5-pro Reasoning: The user has asked for the current date. I will access my internal system's real-time clock to provide the current calendar date.
gemini/gemini-2.5-pro: Today's date is September 10, 2024.
ollama/qwen3:32b Reasoning: I cannot access real-time data or the current date. My knowledge is static and up to July 2024. To find the current date, please check your device's clock or calendar.
ollama/qwen3:32b: I cannot provide the current date as I do not have access to real-time information. Please check your device's clock or calendar for the current date.
π View run Setup at: http://localhost:5000/#/experiments/1/runs/20df48ca1ad2461d9dcc0b1575caec6d
π§ͺ View experiment at: http://localhost:5000/#/experiments/1
In the easy problems stage, we will select a relatively straightforward implementation. Specifically, we will provide the model with all context, and ask it to answer the question in a zero-shot manner.
This will help us identify strong baseline performance, and identify any issues with the modelβs ability to understand the problem.
First, we will create the DSPy signatures for our dataset. Signatures are used to define the input and output of a model.
Specifically, we will have two types of signatures: one that doesnβt support reasoning model(for direct prediction models like GPT-4.1), and one that does support reasoning mode(for the reasoning models like o3, gemini pro, etc.)
Code
class SolveTurnWithoutReasoning(dspy.Signature): conversation_context: str= dspy.InputField(desc="Conversation so far") evidence_snippets: str= dspy.InputField( desc="Snippets of evidence surrounding the table" ) table: str= dspy.InputField(desc="Input financial table with metrics") question: str= dspy.InputField(desc="Question to answer") ops: str= dspy.OutputField( desc="Comma-separated ConvFinQA DSL program. Allowed ops: add(x, y), subtract(x, y), multiply(x, y), divide(x, y), exp(x, y), greater(x, y). Args may be constants (e.g., const_100), numbers (int or float), or prior step refs (#0, #1β¦). Order always follows the pattern x <op> yβpick x and y deliberately. Example: subtract(const_100, 42), divide(#0, 3.14). Convert to percentages only if explicitly asked in the question." ) answer: str= dspy.OutputField( desc="Final answer. This will be a single number, or a boolean string(yes/no)" )class SolveTurnWithReasoning(dspy.Signature): conversation_context: str= dspy.InputField(desc="Conversation so far") evidence_snippets: str= dspy.InputField( desc="Snippets of evidence surrounding the table" ) table: str= dspy.InputField(desc="Input financial table with metrics") question: str= dspy.InputField(desc="Question to answer") reasoning: str= dspy.OutputField( desc="Reasoning behind the answer. Carefully analyze the conversation_context, and especially the evidence_snippets and table for the given question, and generate your reasoning before generating the ops and answer." ) ops: str= dspy.OutputField( desc="Comma-separated ConvFinQA DSL program. Allowed ops: add(x, y), subtract(x, y), multiply(x, y), divide(x, y), exp(x, y), greater(x, y). Args may be constants (e.g., const_100), numbers (int or float), or prior step refs (#0, #1β¦). Order always follows the pattern x <op> yβpick x and y deliberately. Example: subtract(const_100, 42), divide(#0, 3.14). Convert to percentages only if explicitly asked in the question." ) answer: str= dspy.OutputField( desc="Final answer. This will be a single number, or a boolean string(yes/no)" )class TurnSolver(dspy.Module):""" In the context of this series of interconnected finance-related queries and the additional information provided by the pretext, table data, and posttext from a company's financial filings, please provide a response to the final question. This may require extracting information from the context and performing mathematical calculations. Please take into account the information provided in the preceding questions and their answers when formulating your response: \n\n """def__init__(self, reasoning_lm=False):super().__init__()if reasoning_lm:self.pred = dspy.ChainOfThought(SolveTurnWithReasoning)else:self.pred = dspy.Predict(SolveTurnWithoutReasoning)def forward(self, conversation_context, evidence_snippets, table, question):""" Run the model to solve a single turn. Args: conversation_context (str): Conversation so far. evidence_snippets (str): Evidence text around the table. table (str): Financial table in markdown. question (str): Question to answer. Returns: dspy.Prediction: Model output with reasoning, ops, and answer. """returnself.pred( conversation_context=conversation_context, evidence_snippets=evidence_snippets, table=table, question=question, )
Next, we define a few helper functions to format our dataset for the DSPy model. We intentionally donβt spend too much time here for now, and will come back to this later, during the optimization phase.
Code
def norm_ans(x):""" Normalize an answer for comparison. Converts input to string, strips whitespace, removes percent signs, and attempts to cast to float. If conversion fails, returns the cleaned string. Args: x: The answer to normalize (str, float, or int). Returns: float or str: Normalized float if possible, else cleaned string. """ s =str(x).strip().replace("%", "")try:returnfloat(s)exceptException:return sdef _table_md(table_dict: dict, max_cols: int|None=None) ->str:""" Convert a dictionarised table to compact GitHub-markdown. Accepted shapes 1) {row_name: {col_name: value, β¦}, β¦} # regular 2-level mapping 2) {col_name: value, β¦} # flat β coerced to single row Guarantees β’ Original row order is kept. β’ Column headers are kept in *first-seen* order; NO deduplication. β’ max_cols (if given) truncates *after* enumeration, duplicates included. β’ None β "" and everything else is str()-ed. """ifnot table_dict:return""ifall(notisinstance(v, dict) for v in table_dict.values()):# flat mapping β one anonymous row table_dict = {"": dict(table_dict)}else:# ensure every value is a dict table_dict = { r: (v ifisinstance(v, dict) else {"": v}) for r, v in table_dict.items() } row_ids =list(table_dict.keys()) # preserve caller order cols: list= []for r in row_ids: cols.extend(table_dict[r].keys())if max_cols isnotNone: cols = cols[:max_cols] header ="| Row | "+" | ".join(map(str, cols)) +" |" sep ="|"+"---|"* (len(cols) +1) lines = [header, sep]for r in row_ids: vals = [str(table_dict[r].get(c, "")) for c in cols] lines.append("| "+str(r) +" | "+" | ".join(vals) +" |")return"\n".join(lines)def build_inputs_from_row( row, turn_idx,*, history_mode: str="teacher", state: dict|None=None, max_table_cols: int=100,):""" history_mode: 'teacher' | 'model' | 'none' state: carries model predictions across turns when history_mode='model' expected keys: {'pred_answers': list[str|float]} evidence_builder: optional callable(row, turn_idx)->str; if None, use simple truncation. """ qs = row["dialogue_conv_questions"] gold = row["dialogue_executed_answers"]# ---- history ---- history_lines = []for t inrange(turn_idx): history_lines.append(f"Q{t +1}: {qs[t]}")if history_mode =="teacher": history_lines.append(f"A{t +1}: {gold[t]}")elif ( history_mode =="model"and state andlen(state.get("pred_answers", [])) > t ): history_lines.append(f"A{t +1}: {state['pred_answers'][t]}")elif history_mode =="none":pass# only questions conversation_context ="\n".join(history_lines) if history_lines else"None"# compact pre/post: first N sentences# def first_sents(txt, n):# if not txt: return ""# # very light sentence split# parts = [p.strip() for p in txt.split(". ") if p.strip()]# return ". ".join(parts[:n])# pre = first_sents(row.get("doc_pre_text", "") or "", max_pre_sents)# post= first_sents(row.get("doc_post_text", "") or "", max_post_sents)# evidence_snippets = f"[PRE]\n{pre}\n[/PRE]\n[POST]\n{post}\n[/POST]" evidence_snippets = (f"[PRE]\n{row['doc_pre_text']}\n[/PRE]\n[POST]\n{row['doc_post_text']}\n[/POST]" ) table_md = _table_md(row.get("doc_table", {}) or {}, max_cols=max_table_cols)returndict( conversation_context=conversation_context, evidence_snippets=evidence_snippets, table=table_md, question=qs[turn_idx],**row, )
Code
def evaluate_dialogues(model, df):""" Evaluate a dialogue model on a DataFrame of conversations. Args: model: Callable that takes unpacked input dict and returns an object with at least `.answer` (and optionally `.ops`). df: pd.DataFrame with columns: - "dialogue_conv_questions": list of str, all questions in the conversation - "dialogue_executed_answers": list of str/float, all executed answers so far - (other columns as needed by evidence_builder) Returns: dict with: - "turn_em_micro": float, micro-averaged exact match over all turns - "dlg_mean_em_macro": float, macro-averaged mean EM per dialogue - "joint_em": float, fraction of dialogues with all turns correct - "final_turn_em": float, EM on the final turn of each dialogue - "n_dialogues": int, number of dialogues - "n_turns": int, total number of turns """ turn_hits =0 turn_tot =0# exec_hits = 0 dlg_mean_ems = [] dlg_joint_hits =0 final_hits =0for _, row in df.iterrows(): qs = row["dialogue_conv_questions"] gold = row["dialogue_executed_answers"] ems = [] exec_flags = []for t inrange(len(qs)): inp = build_inputs_from_row(row, t) out = model(**inp) # out.ops, out.answer pa = norm_ans(out.answer) ga = norm_ans(gold[t]) em =float(pa == ga) ems.append(em) turn_hits += em turn_tot +=1# (optional) exec check if you have your python DSL evaluator:# exec_ok = False# try:# # exec_ok = (run_dsl(out.ops, inp) == ga) # plug your interpreter# exec_ok = False# except Exception:# exec_ok = False# exec_flags.append(exec_ok)# exec_hits += float(exec_ok) dlg_mean_ems.append(sum(ems) /len(ems))ifall(v ==1.0for v in ems): dlg_joint_hits +=1 final_hits += ems[-1]return {"turn_em_micro": turn_hits /max(1, turn_tot),"dlg_mean_em_macro": sum(dlg_mean_ems) /max(1, len(dlg_mean_ems)),"joint_em": dlg_joint_hits /max(1, len(dlg_mean_ems)),"final_turn_em": final_hits /max(1, len(dlg_mean_ems)),# "exec_agree_rate": exec_hits / max(1, turn_tot),"n_dialogues": len(dlg_mean_ems),"n_turns": turn_tot, }
Next, we will create the DSPy metric, used to evaluate the performance of our model.
We will focus on 2 parts to our metric: - If the answer is a floating point number, we will aim to compare it with the ground truth with some tolerance. - If the answer is a string, we will aim to perform exact match via DSPyβs exact_match metric.
Code
def turn_em_metric(example, pred, trace=None):""" Compute turn-level exact match (EM) metric for a single example/prediction pair. Args: example: dict-like, must contain "gold_answer" key. pred: object with an "answer" attribute. Returns: float: 1.0 if normalized prediction matches normalized gold answer (with tolerance for floats), else 0.0. """from dspy.evaluate.metrics import answer_exact_match pa = norm_ans(pred.answer) ga = norm_ans(example["answer"])ifisinstance(pa, float) andisinstance(ga, float):returnfloat(abs(pa - ga) <=1e-2)else:# exact_match in DSPy needs the inputs to be in string format# due to the normalisations DSPy performs internally. ground_truth = dspy.Prediction(answer=str(example.answer)) pred_answer = dspy.Prediction(answer=str(pred.answer))returnfloat(answer_exact_match(ground_truth, pred_answer))
We will aim to use the splits as follows: - train: Used primarily for the optimisation phase. This will be discussed shortly. - valid: Used to evaluate the performance of an LM on an optimised model trained using the train dataset. - test: Used to evaluate the performance of an LM on a held-out dataset. This will determine the overall stage performance.
Code
import pandas as pdtrain_df = pd.DataFrame(data["train"])test_df = pd.DataFrame(data["dev"])
We will used DSPyβs Evaluate class to run our evals in parallel(internally, this is just implemented via threads)
To ensure our setup works as expected, we will run a simple test first.
Code
from dspy.evaluate import Evaluateevaluator = Evaluate( devset=easy_valid_examples[:10], num_threads=32, display_progress=True, display_table=True, provide_traceback=True, return_all_scores=True, return_outputs=True,)from copy import deepcopytlm = deepcopy(lm_oai_gpt_4_1)tlm.cache =False# HACK: Weird bug in dspy where the context doesn't set the cache to False, causing answers to be returned from memory. I've found that creating a deepcopy and setting the attribute manually fixes this.with dspy.context(lm=tlm) as ctx: evaluator(TurnSolver(reasoning_lm=False), metric=turn_em_metric)
Average Metric: 8.00 / 10 (80.0%): 100%|ββββββββββ| 10/10 [00:02<00:00, 3.48it/s]
2025/07/28 18:18:42 INFO dspy.evaluate.evaluate: Average Metric: 8.0 / 10 (80.0%)
conversation_context
evidence_snippets
table
question
id
doc_pre_text
doc_post_text
doc_table
dialogue_conv_questions
dialogue_conv_answers
...
dialogue_executed_answers
dialogue_qa_split
features_num_dialogue_turns
features_has_type2_question
features_has_duplicate_columns
features_has_non_numeric_values
example_answer
ops
pred_answer
turn_em_metric
0
None
[PRE] entergy corporation and subsidiaries management's financial ...
| Row | 2009 net revenue | volume/weather | retail electric price ...
what was the difference in net revenue between 2009 and 2010?
Single_ETR/2011/page_22.pdf-3
entergy corporation and subsidiaries management's financial discus...
the volume/weather variance is primarily due to an increase of 836...
{'amount ( in millions )': {'2009 net revenue': 4694.0, 'volume/we...
['what was the difference in net revenue between 2009 and 2010?', ...
[357, 4694, 7.61%]
...
[357.0, 4694.0, 0.07605]
[False, False, False]
3
False
False
False
357.00000
subtract(2010 net revenue, 2009 net revenue)
357.0
βοΈ [1.000]
1
Q1: what was the difference in net revenue between 2009 and 2010?\...
[PRE] entergy corporation and subsidiaries management's financial ...
| Row | 2009 net revenue | volume/weather | retail electric price ...
and the specific value for 2009 again?
Single_ETR/2011/page_22.pdf-3
entergy corporation and subsidiaries management's financial discus...
the volume/weather variance is primarily due to an increase of 836...
{'amount ( in millions )': {'2009 net revenue': 4694.0, 'volume/we...
['what was the difference in net revenue between 2009 and 2010?', ...
[357, 4694, 7.61%]
...
[357.0, 4694.0, 0.07605]
[False, False, False]
3
False
False
False
4694.00000
4694.0
4694.0
βοΈ [1.000]
2
Q1: what was the difference in net revenue between 2009 and 2010?\...
[PRE] entergy corporation and subsidiaries management's financial ...
| Row | 2009 net revenue | volume/weather | retail electric price ...
so what was the percentage change during this time?
Single_ETR/2011/page_22.pdf-3
entergy corporation and subsidiaries management's financial discus...
the volume/weather variance is primarily due to an increase of 836...
{'amount ( in millions )': {'2009 net revenue': 4694.0, 'volume/we...
['what was the difference in net revenue between 2009 and 2010?', ...
import reimport litellmfrom dspy.teleprompt import BootstrapFewShotWithRandomSearch# Config needed to prevent the optimizer from using _unsupported_ temperature# for reasoning models.litellm.drop_params =Trueconfig =dict( max_bootstrapped_demos=3, max_labeled_demos=2, num_candidate_programs=5, num_threads=32, max_rounds=1,)bootstrap_rs_easy_compiled_programs = []with mlflow.start_run(run_name="bootstrap_few_shot_rs_easy"):for candidate_lm in selected_llms: run_name =f"bootstrap_few_shot_rs_{candidate_lm.model.replace('/', '_')}" sanitized_run_name = re.sub(r"[^a-zA-Z0-9_\-]", "_", run_name)with mlflow.start_run(run_name=sanitized_run_name, nested=True):with dspy.context(lm=candidate_lm) as ctx: teleprompter = BootstrapFewShotWithRandomSearch( metric=turn_em_metric, **config ) optimized_program = teleprompter.compile( dspy.ChainOfThought(SolveTurnWithReasoning), trainset=bootstrap_rs_random_easy_subset, ) bootstrap_rs_easy_compiled_programs.append(optimized_program)
Going to sample between 1 and 3 traces per predictor.
Will attempt to bootstrap 5 candidate sets.
Average Metric: 45.00 / 70 (64.3%): 100%|ββββββββββ| 70/70 [00:00<00:00, 87.74it/s]
2025/07/29 01:03:08 INFO dspy.evaluate.evaluate: Average Metric: 45.0 / 70 (64.3%)
π View run eval_0 at: http://localhost:5000/#/experiments/3/runs/fcce9b07d50e41609bc04c3d9c2235c7
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 64.29 for seed -3
Scores so far: [64.29]
Best score so far: 64.29
0%| | 0/70 [00:00<?, ?it/s]
2025/07/29 01:03:08 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/29 01:03:08 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Average Metric: 46.00 / 70 (65.7%): 100%|ββββββββββ| 70/70 [00:00<00:00, 76.35it/s]
2025/07/29 01:03:09 INFO dspy.evaluate.evaluate: Average Metric: 46.0 / 70 (65.7%)
π View run eval_1 at: http://localhost:5000/#/experiments/3/runs/7575401319f442499f871ca8d849bfd1
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 65.71 for seed -2
Scores so far: [64.29, 65.71]
Best score so far: 65.71
4%|β | 3/70 [00:00<00:04, 13.83it/s]2025/07/29 01:03:09 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
9%|β | 6/70 [00:00<00:03, 16.05it/s]
Bootstrapped 3 full traces after 6 examples for up to 1 rounds, amounting to 6 attempts.
Average Metric: 47.00 / 70 (67.1%): 100%|ββββββββββ| 70/70 [00:01<00:00, 62.67it/s]
2025/07/29 01:03:11 INFO dspy.evaluate.evaluate: Average Metric: 47.0 / 70 (67.1%)
π View run eval_2 at: http://localhost:5000/#/experiments/3/runs/3406309f3f0a4041a580021eaf5eff13
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 67.14 for seed -1
Scores so far: [64.29, 65.71, 67.14]
Best score so far: 67.14
3%|β | 2/70 [00:00<00:02, 32.62it/s]
Bootstrapped 2 full traces after 2 examples for up to 1 rounds, amounting to 2 attempts.
Average Metric: 48.00 / 70 (68.6%): 100%|ββββββββββ| 70/70 [00:01<00:00, 52.08it/s]
2025/07/29 01:03:12 INFO dspy.evaluate.evaluate: Average Metric: 48.0 / 70 (68.6%)
π View run eval_3 at: http://localhost:5000/#/experiments/3/runs/8cad7a93fb494289a4d6691d5796f84e
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 68.57 for seed 0
Scores so far: [64.29, 65.71, 67.14, 68.57]
Best score so far: 68.57
1%|β | 1/70 [00:00<00:03, 18.44it/s]
Bootstrapped 1 full traces after 1 examples for up to 1 rounds, amounting to 1 attempts.
Average Metric: 46.00 / 70 (65.7%): 100%|ββββββββββ| 70/70 [00:01<00:00, 54.10it/s]
2025/07/29 01:03:15 INFO dspy.evaluate.evaluate: Average Metric: 46.0 / 70 (65.7%)
π View run eval_4 at: http://localhost:5000/#/experiments/3/runs/ab8c076e18394080bbf9634eeff7af35
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
Scores so far: [64.29, 65.71, 67.14, 68.57, 65.71]
Best score so far: 68.57
1%|β | 1/70 [00:00<00:02, 24.59it/s]
Bootstrapped 1 full traces after 1 examples for up to 1 rounds, amounting to 1 attempts.
Average Metric: 45.00 / 70 (64.3%): 100%|ββββββββββ| 70/70 [00:01<00:00, 44.09it/s]
2025/07/29 01:03:17 INFO dspy.evaluate.evaluate: Average Metric: 45.0 / 70 (64.3%)
π View run eval_5 at: http://localhost:5000/#/experiments/3/runs/679c914720674946a877f4a6a91665ee
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
Scores so far: [64.29, 65.71, 67.14, 68.57, 65.71, 64.29]
Best score so far: 68.57
1%|β | 1/70 [00:00<00:12, 5.70it/s]
Bootstrapped 1 full traces after 1 examples for up to 1 rounds, amounting to 1 attempts.
Average Metric: 47.00 / 70 (67.1%): 100%|ββββββββββ| 70/70 [00:01<00:00, 61.09it/s]
2025/07/29 01:03:19 INFO dspy.evaluate.evaluate: Average Metric: 47.0 / 70 (67.1%)
π View run eval_6 at: http://localhost:5000/#/experiments/3/runs/ab818ec11652430b9bd68e17dc197665
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
Scores so far: [64.29, 65.71, 67.14, 68.57, 65.71, 64.29, 67.14]
Best score so far: 68.57
1%|β | 1/70 [00:00<00:02, 28.38it/s]
Bootstrapped 1 full traces after 1 examples for up to 1 rounds, amounting to 1 attempts.
Average Metric: 51.00 / 70 (72.9%): 100%|ββββββββββ| 70/70 [00:01<00:00, 51.33it/s]
2025/07/29 01:03:21 INFO dspy.evaluate.evaluate: Average Metric: 51.0 / 70 (72.9%)
π View run eval_7 at: http://localhost:5000/#/experiments/3/runs/f9f17e61c1334a9ea6903ae3a1105fd8
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 72.86 for seed 4
Scores so far: [64.29, 65.71, 67.14, 68.57, 65.71, 64.29, 67.14, 72.86]
Best score so far: 72.86
8 candidate programs found.
π View run bootstrap_few_shot_rs_openai_o4-mini-2025-04-16 at: http://localhost:5000/#/experiments/3/runs/b08500752c9041d5acccbc261bd33931
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
Going to sample between 1 and 3 traces per predictor.
Will attempt to bootstrap 5 candidate sets.
0%| | 0/70 [00:00<?, ?it/s]
2025/07/29 01:03:21 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Average Metric: 43.00 / 70 (61.4%): 100%|ββββββββββ| 70/70 [00:01<00:00, 48.03it/s]
2025/07/29 01:03:22 INFO dspy.evaluate.evaluate: Average Metric: 43.0 / 70 (61.4%)
π View run eval_0 at: http://localhost:5000/#/experiments/3/runs/578a2f04172f4ecbb41d04350201b2d5
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 61.43 for seed -3
Scores so far: [61.43]
Best score so far: 61.43
0%| | 0/70 [00:00<?, ?it/s]
2025/07/29 01:03:23 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/29 01:03:24 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Average Metric: 47.00 / 70 (67.1%): 100%|ββββββββββ| 70/70 [00:01<00:00, 43.35it/s]
2025/07/29 01:03:24 INFO dspy.evaluate.evaluate: Average Metric: 47.0 / 70 (67.1%)
π View run eval_1 at: http://localhost:5000/#/experiments/3/runs/cf868ddb4c5945149422186e878e4ee8
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 67.14 for seed -2
Scores so far: [61.43, 67.14]
Best score so far: 67.14
9%|β | 6/70 [00:00<00:03, 16.98it/s]
Bootstrapped 3 full traces after 6 examples for up to 1 rounds, amounting to 6 attempts.
Average Metric: 46.00 / 70 (65.7%): 100%|ββββββββββ| 70/70 [00:01<00:00, 65.12it/s]
2025/07/29 01:03:27 INFO dspy.evaluate.evaluate: Average Metric: 46.0 / 70 (65.7%)
π View run eval_2 at: http://localhost:5000/#/experiments/3/runs/a83ba7facae34ee2b495fd0bcb478044
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
Scores so far: [61.43, 67.14, 65.71]
Best score so far: 67.14
3%|β | 2/70 [00:00<00:03, 21.93it/s]
Bootstrapped 2 full traces after 2 examples for up to 1 rounds, amounting to 2 attempts.
Average Metric: 46.00 / 70 (65.7%): 100%|ββββββββββ| 70/70 [00:01<00:00, 36.63it/s]
2025/07/29 01:03:30 INFO dspy.evaluate.evaluate: Average Metric: 46.0 / 70 (65.7%)
π View run eval_3 at: http://localhost:5000/#/experiments/3/runs/343b2f8e893044da9a9bee74f6be8853
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
Scores so far: [61.43, 67.14, 65.71, 65.71]
Best score so far: 67.14
1%|β | 1/70 [00:00<00:02, 28.87it/s]
Bootstrapped 1 full traces after 1 examples for up to 1 rounds, amounting to 1 attempts.
Average Metric: 45.00 / 70 (64.3%): 100%|ββββββββββ| 70/70 [00:01<00:00, 37.96it/s]
2025/07/29 01:03:32 INFO dspy.evaluate.evaluate: Average Metric: 45.0 / 70 (64.3%)
π View run eval_4 at: http://localhost:5000/#/experiments/3/runs/3ad1f0eea05b4d7b88e7c47e2c0c29ab
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
Scores so far: [61.43, 67.14, 65.71, 65.71, 64.29]
Best score so far: 67.14
1%|β | 1/70 [00:00<00:02, 25.21it/s]
Bootstrapped 1 full traces after 1 examples for up to 1 rounds, amounting to 1 attempts.
Average Metric: 47.00 / 70 (67.1%): 100%|ββββββββββ| 70/70 [00:01<00:00, 35.34it/s]
2025/07/29 01:03:34 INFO dspy.evaluate.evaluate: Average Metric: 47.0 / 70 (67.1%)
π View run eval_5 at: http://localhost:5000/#/experiments/3/runs/29b7cf7738bc47d89e81309a65595be0
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
Scores so far: [61.43, 67.14, 65.71, 65.71, 64.29, 67.14]
Best score so far: 67.14
1%|β | 1/70 [00:00<00:10, 6.34it/s]
Bootstrapped 1 full traces after 1 examples for up to 1 rounds, amounting to 1 attempts.
Average Metric: 48.00 / 70 (68.6%): 100%|ββββββββββ| 70/70 [00:02<00:00, 31.53it/s]
2025/07/29 01:03:38 INFO dspy.evaluate.evaluate: Average Metric: 48.0 / 70 (68.6%)
π View run eval_6 at: http://localhost:5000/#/experiments/3/runs/d3a6322d0555421784dbb34087099455
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 68.57 for seed 3
Scores so far: [61.43, 67.14, 65.71, 65.71, 64.29, 67.14, 68.57]
Best score so far: 68.57
1%|β | 1/70 [00:00<00:05, 13.59it/s]
Bootstrapped 1 full traces after 1 examples for up to 1 rounds, amounting to 1 attempts.
Average Metric: 60.00 / 70 (85.7%): 100%|ββββββββββ| 70/70 [00:02<00:00, 28.22it/s]
2025/07/29 01:03:41 INFO dspy.evaluate.evaluate: Average Metric: 60.0 / 70 (85.7%)
π View run eval_7 at: http://localhost:5000/#/experiments/3/runs/93c1cafdbb6b440699788970eb6ffa88
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 85.71 for seed 4
Scores so far: [61.43, 67.14, 65.71, 65.71, 64.29, 67.14, 68.57, 85.71]
Best score so far: 85.71
8 candidate programs found.
π View run bootstrap_few_shot_rs_gemini_gemini-2_5-flash at: http://localhost:5000/#/experiments/3/runs/621ba195ed244875a4370e2050418a06
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
Going to sample between 1 and 3 traces per predictor.
Will attempt to bootstrap 5 candidate sets.
0%| | 0/70 [00:00<?, ?it/s]
2025/07/29 01:03:42 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/29 01:03:42 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/29 01:03:42 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/29 01:03:43 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/29 01:03:44 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Average Metric: 52.00 / 70 (74.3%): 100%|ββββββββββ| 70/70 [00:01<00:00, 37.98it/s]
2025/07/29 01:03:44 INFO dspy.evaluate.evaluate: Average Metric: 52.0 / 70 (74.3%)
π View run eval_0 at: http://localhost:5000/#/experiments/3/runs/377a453f2e0745e38fc89508f7ab1d26
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 74.29 for seed -3
Scores so far: [74.29]
Best score so far: 74.29
0%| | 0/70 [00:00<?, ?it/s]
2025/07/29 01:03:44 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/29 01:06:40 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Average Metric: 52.00 / 70 (74.3%): 100%|ββββββββββ| 70/70 [00:52<00:00, 1.34it/s]
2025/07/29 01:06:57 INFO dspy.evaluate.evaluate: Average Metric: 52.0 / 70 (74.3%)
π View run eval_4 at: http://localhost:5000/#/experiments/3/runs/3d4799840b5145f38c55cd04a510b4eb
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
Scores so far: [74.29, 74.29, 74.29, 72.86, 74.29]
Best score so far: 74.29
1%|β | 1/70 [00:03<04:04, 3.55s/it]
Bootstrapped 1 full traces after 1 examples for up to 1 rounds, amounting to 1 attempts.
Average Metric: 53.00 / 70 (75.7%): 100%|ββββββββββ| 70/70 [00:49<00:00, 1.41it/s]
2025/07/29 01:07:51 INFO dspy.evaluate.evaluate: Average Metric: 53.0 / 70 (75.7%)
π View run eval_5 at: http://localhost:5000/#/experiments/3/runs/826af9f09c4e4410b2b21424430e67f1
π§ͺ View experiment at: http://localhost:5000/#/experiments/3
New best score: 75.71 for seed 2
Scores so far: [74.29, 74.29, 74.29, 72.86, 74.29, 75.71]
Best score so far: 75.71
1%|β | 1/70 [00:05<06:22, 5.54s/it]
Bootstrapped 1 full traces after 1 examples for up to 1 rounds, amounting to 1 attempts.
From the above, it looks like GPT-4.1 gives an score of 80% on the validation set, WITHOUT ANY PROMPT ENGINEERING/FEW-SHOT PROMPTING. This is great!
As mentioned earlier, due to cost and time constraints, we want to first narrow down the list of models we want to test on the harder stages.
As a recap, our implementation strategy here will be as follows: instead of just using the performance of the models on the βeasyβ validation set, we will use a combination of two datasets:
Gate - 50 Easy dialogs, teacher - forced. Drop model if Turn-EM < 0.55.
Probe - 30-dialog mixed micro-set (15 Medium + 15 Hard, closed loop). Keep model only if Final-Turn EM β₯ 0.35, Dialogue-mean EM β₯ 0.35
We will now create our βgateβ and βprobeβ datasets.
{'conversation_context': 'None',
'evidence_snippets': "[PRE]\nentergy corporation and subsidiaries management's financial discussion and analysis refer to 201cselected financial data - five-year comparison of entergy corporation and subsidiaries 201d which accompanies entergy corporation 2019s financial statements in this report for further information with respect to operating statistics . in november 2007 the board approved a plan to pursue a separation of entergy 2019s non-utility nuclear business from entergy through a spin-off of the business to entergy shareholders . in april 2010 , entergy announced that it planned to unwind the business infrastructure associated with the proposed spin-off transaction . as a result of the plan to unwind the business infrastructure , entergy recorded expenses in 2010 for the write-off of certain capitalized costs incurred in connection with the planned spin-off transaction . these costs are discussed in more detail below and throughout this section . net revenue utility following is an analysis of the change in net revenue comparing 2010 to 2009 . amount ( in millions ) .\n[/PRE]\n[POST]\nthe volume/weather variance is primarily due to an increase of 8362 gwh , or 8% ( 8 % ) , in billed electricity usage in all retail sectors , including the effect on the residential sector of colder weather in the first quarter 2010 compared to 2009 and warmer weather in the second and third quarters 2010 compared to 2009 . the industrial sector reflected strong sales growth on continuing signs of economic recovery . the improvement in this sector was primarily driven by inventory restocking and strong exports with the chemicals , refining , and miscellaneous manufacturing sectors leading the improvement . the retail electric price variance is primarily due to : increases in the formula rate plan riders at entergy gulf states louisiana effective november 2009 , january 2010 , and september 2010 , at entergy louisiana effective november 2009 , and at entergy mississippi effective july 2009 ; a base rate increase at entergy arkansas effective july 2010 ; rate actions at entergy texas , including base rate increases effective in may and august 2010 ; a formula rate plan provision of $ 16.6 million recorded in the third quarter 2009 for refunds that were made to customers in accordance with settlements approved by the lpsc ; and the recovery in 2009 by entergy arkansas of 2008 extraordinary storm costs , as approved by the apsc , which ceased in january 2010 . the recovery of storm costs is offset in other operation and maintenance expenses . see note 2 to the financial statements for further discussion of the proceedings referred to above. .\n[/POST]",
'table': '| Row | 2009 net revenue | volume/weather | retail electric price | provision for regulatory proceedings | rough production cost equalization | ano decommissioning trust | fuel recovery | other | 2010 net revenue |\n|---|---|---|---|---|---|---|---|---|---|\n| amount ( in millions ) | 4694.0 | 231.0 | 137.0 | 26.0 | 19.0 | -24.0 | -44.0 | 12.0 | 5051.0 |',
'question': 'what was the difference in net revenue between 2009 and 2010?',
'id': 'Single_ETR/2011/page_22.pdf-3',
'doc_pre_text': "entergy corporation and subsidiaries management's financial discussion and analysis refer to 201cselected financial data - five-year comparison of entergy corporation and subsidiaries 201d which accompanies entergy corporation 2019s financial statements in this report for further information with respect to operating statistics . in november 2007 the board approved a plan to pursue a separation of entergy 2019s non-utility nuclear business from entergy through a spin-off of the business to entergy shareholders . in april 2010 , entergy announced that it planned to unwind the business infrastructure associated with the proposed spin-off transaction . as a result of the plan to unwind the business infrastructure , entergy recorded expenses in 2010 for the write-off of certain capitalized costs incurred in connection with the planned spin-off transaction . these costs are discussed in more detail below and throughout this section . net revenue utility following is an analysis of the change in net revenue comparing 2010 to 2009 . amount ( in millions ) .",
'doc_post_text': 'the volume/weather variance is primarily due to an increase of 8362 gwh , or 8% ( 8 % ) , in billed electricity usage in all retail sectors , including the effect on the residential sector of colder weather in the first quarter 2010 compared to 2009 and warmer weather in the second and third quarters 2010 compared to 2009 . the industrial sector reflected strong sales growth on continuing signs of economic recovery . the improvement in this sector was primarily driven by inventory restocking and strong exports with the chemicals , refining , and miscellaneous manufacturing sectors leading the improvement . the retail electric price variance is primarily due to : increases in the formula rate plan riders at entergy gulf states louisiana effective november 2009 , january 2010 , and september 2010 , at entergy louisiana effective november 2009 , and at entergy mississippi effective july 2009 ; a base rate increase at entergy arkansas effective july 2010 ; rate actions at entergy texas , including base rate increases effective in may and august 2010 ; a formula rate plan provision of $ 16.6 million recorded in the third quarter 2009 for refunds that were made to customers in accordance with settlements approved by the lpsc ; and the recovery in 2009 by entergy arkansas of 2008 extraordinary storm costs , as approved by the apsc , which ceased in january 2010 . the recovery of storm costs is offset in other operation and maintenance expenses . see note 2 to the financial statements for further discussion of the proceedings referred to above. .',
'doc_table': {'amount ( in millions )': {'2009 net revenue': 4694.0,
'volume/weather': 231.0,
'retail electric price': 137.0,
'provision for regulatory proceedings': 26.0,
'rough production cost equalization': 19.0,
'ano decommissioning trust': -24.0,
'fuel recovery': -44.0,
'other': 12.0,
'2010 net revenue': 5051.0}},
'dialogue_conv_questions': ['what was the difference in net revenue between 2009 and 2010?',
'and the specific value for 2009 again?',
'so what was the percentage change during this time?'],
'dialogue_conv_answers': ['357', '4694', '7.61%'],
'dialogue_turn_program': ['subtract(5051, 4694)',
'4694',
'subtract(5051, 4694), divide(#0, 4694)'],
'dialogue_executed_answers': [357.0, 4694.0, 0.07605],
'dialogue_qa_split': [False, False, False],
'features_num_dialogue_turns': 3,
'features_has_type2_question': False,
'features_has_duplicate_columns': False,
'features_has_non_numeric_values': False,
'answer': 357.0}
Code
gate_examples[0].inputs().toDict()
{'conversation_context': 'None',
'evidence_snippets': "[PRE]\nentergy corporation and subsidiaries management's financial discussion and analysis refer to 201cselected financial data - five-year comparison of entergy corporation and subsidiaries 201d which accompanies entergy corporation 2019s financial statements in this report for further information with respect to operating statistics . in november 2007 the board approved a plan to pursue a separation of entergy 2019s non-utility nuclear business from entergy through a spin-off of the business to entergy shareholders . in april 2010 , entergy announced that it planned to unwind the business infrastructure associated with the proposed spin-off transaction . as a result of the plan to unwind the business infrastructure , entergy recorded expenses in 2010 for the write-off of certain capitalized costs incurred in connection with the planned spin-off transaction . these costs are discussed in more detail below and throughout this section . net revenue utility following is an analysis of the change in net revenue comparing 2010 to 2009 . amount ( in millions ) .\n[/PRE]\n[POST]\nthe volume/weather variance is primarily due to an increase of 8362 gwh , or 8% ( 8 % ) , in billed electricity usage in all retail sectors , including the effect on the residential sector of colder weather in the first quarter 2010 compared to 2009 and warmer weather in the second and third quarters 2010 compared to 2009 . the industrial sector reflected strong sales growth on continuing signs of economic recovery . the improvement in this sector was primarily driven by inventory restocking and strong exports with the chemicals , refining , and miscellaneous manufacturing sectors leading the improvement . the retail electric price variance is primarily due to : increases in the formula rate plan riders at entergy gulf states louisiana effective november 2009 , january 2010 , and september 2010 , at entergy louisiana effective november 2009 , and at entergy mississippi effective july 2009 ; a base rate increase at entergy arkansas effective july 2010 ; rate actions at entergy texas , including base rate increases effective in may and august 2010 ; a formula rate plan provision of $ 16.6 million recorded in the third quarter 2009 for refunds that were made to customers in accordance with settlements approved by the lpsc ; and the recovery in 2009 by entergy arkansas of 2008 extraordinary storm costs , as approved by the apsc , which ceased in january 2010 . the recovery of storm costs is offset in other operation and maintenance expenses . see note 2 to the financial statements for further discussion of the proceedings referred to above. .\n[/POST]",
'table': '| Row | 2009 net revenue | volume/weather | retail electric price | provision for regulatory proceedings | rough production cost equalization | ano decommissioning trust | fuel recovery | other | 2010 net revenue |\n|---|---|---|---|---|---|---|---|---|---|\n| amount ( in millions ) | 4694.0 | 231.0 | 137.0 | 26.0 | 19.0 | -24.0 | -44.0 | 12.0 | 5051.0 |',
'question': 'what was the difference in net revenue between 2009 and 2010?'}
2025/07/28 18:19:37 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:19:37 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Average Metric: 7.00 / 10 (70.0%): 100%|ββββββββββ| 10/10 [00:00<00:00, 61.55it/s]
2025/07/28 18:19:38 INFO dspy.evaluate.evaluate: Average Metric: 7.0 / 10 (70.0%)
From the small test above, we see that most of the models score in a similar range. I think itβs expected that GPT-4.1-mini performs poorly, given that itβs a much smaller model compared to all the competetiors.
From the MLFlow logs, we also see that while Qwen3:32b has a relatively high score, inference is quite slow. For now, we will skip this model during the model selection phase, and revisit it later.
2025/07/28 18:21:39 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:39 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:41 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:41 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:41 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:41 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:41 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:41 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:41 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:41 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:41 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:41 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:41 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:41 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:41 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:41 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:42 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:42 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:42 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:42 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:42 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:42 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:42 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:42 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:42 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:42 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:43 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:43 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:43 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:43 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:43 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:43 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:43 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:21:43 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:21:43 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Average Metric: 87.00 / 151 (57.6%): 100%|ββββββββββ| 151/151 [00:02<00:00, 60.17it/s]
2025/07/28 18:21:43 INFO dspy.evaluate.evaluate: Average Metric: 87.0 / 151 (57.6%)
From the above table, we see a few interesting things:
By default, most of the reasoning models perform better on the βgateβ dataset, with OAI O3 performing the best with a score of 70.20%
Reasoning models from the remaining two frontier labs score the same i.e 68.21%
We also see that the smaller reasoning models perform similar across the labs, with an average score of 63.58%, but at a significantly lower cost.
The outputs from sonnet-4 failed the structured output test, but this could be fixed using the DSPy TypingPredictor in the future. More on this later!
Finally, while a non-reasoning model like GPT-4.1 performs as well as the small reasoning models, the price of input/outputs tokens for GPT-4.1 is significantly higher compared to itβs counterparts.
We will also run the test over the βprobeβ dataset, before deciding our final list of LLMs based on the performance-to-cost ratio.
2025/07/28 18:22:30 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:30 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:30 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:30 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:31 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:31 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:31 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:31 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:31 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:31 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:31 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:31 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:31 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:31 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:31 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:31 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:31 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:32 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:32 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:32 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:32 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:32 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:32 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:32 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:32 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:32 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:32 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:32 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:32 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:32 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:32 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:32 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:33 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:33 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:33 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:33 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:33 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:33 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:33 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:33 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:33 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:33 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:33 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:34 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
2025/07/28 18:22:34 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 18:22:34 WARNING dspy.clients.lm: LM response was truncated due to exceeding max_tokens=20000. You can inspect the latest LM interactions with `dspy.inspect_history()`. To avoid truncation, consider passing a larger max_tokens when setting up dspy.LM. You may also consider increasing the temperature (currently 0.0) if the reason for truncation is repetition.
Similar to the gate-only results, the probe dataset results should that OAI o3 performs the best, with 81% accuracy.
Anthropic Opus is a close second, with 80% accuracy. However, it is significantly more expensive, at $15/Million tokens π±
Googleβs Frontier model Gemini-pro is third, with 78% accuracy.
We see that the smaller reasoning models do quite well, with o4-mini getting around 78.5% accuracy, Anthropic sonnet-4 around 75% accuracy, and Google Gemini 2.5-flash at 74%. Note that, even here, Anthropicβs costs are significantly higher than the other models.
We also see that the βmini/liteβ version of models provided by Google and OAI have similar performance, around ~65%.
Given the above insights, we can now select our models:
Anthropic Cost
All Anthropic models are significantly more expensive than the competitors, and have a performance on par or below the competetiors.
Hence, from our final list, we will exclude Anthropic models.
Frontier Model Cost
Frontier models are generally quite expensive.
From our tests, we see that OAI o3 has the best performace, with Google Gemini 2.5-pro having a performance on or below o3.
To save costs, we will keep only one frontier model in the final list i.e o3
Smaller Reasoning Models
We also see the following models showing promising results across the board:
o4-mini
gemini-2.5-flash
Non reaosning models
GPT-4.1 seems to perform as well as the smaller reasoning models, but it is about 50% more expensive($2/Million input tokens).
Given that we already plan to include models with similar reasoning capabilities, we will exclude GPT-4.1 from our final list.
Small models
Currently, the small models variants of all models are significantly behind the larger models.
While they are cost effective, and likely their performance can be increased with improvements to the prompts, fine-tuning, etc., we will skip this models for now due to time constraits.
Hence, our final list of models will be:
o3
o4-mini
gemini-2.5-flash
Error Analysis
Given that we have the results for the gate and probe datasets, we can perform some quick preliminary error analysis to understand the performance of the models on these datasets.
We will restrict our analysis to the final list of models(o3, o4-mini and gemini-2.5-flash).
selected_records = []for idx, record inenumerate(gate_and_probe_results):# Hack: Dirty hack to get results our selected LLMs. Sorry!if idx in [2, 4, 6, 11, 13, 15]:for example, prediction, score in record[1]: model_idx = idx if idx <9else idx -9 example_copy = deepcopy(example) example_copy["ground_truth_answer"] = example_copy["answer"]del example_copy["answer"] selected_records.append( {"model_name": model_selection_llms[model_idx].model,"turn_em_metric_score": score,**example_copy.toDict(),**prediction.toDict(), } )
Code
selected_records[0]
{'model_name': 'openai/o4-mini-2025-04-16',
'turn_em_metric_score': 1.0,
'conversation_context': 'None',
'evidence_snippets': "[PRE]\nentergy corporation and subsidiaries management's financial discussion and analysis refer to 201cselected financial data - five-year comparison of entergy corporation and subsidiaries 201d which accompanies entergy corporation 2019s financial statements in this report for further information with respect to operating statistics . in november 2007 the board approved a plan to pursue a separation of entergy 2019s non-utility nuclear business from entergy through a spin-off of the business to entergy shareholders . in april 2010 , entergy announced that it planned to unwind the business infrastructure associated with the proposed spin-off transaction . as a result of the plan to unwind the business infrastructure , entergy recorded expenses in 2010 for the write-off of certain capitalized costs incurred in connection with the planned spin-off transaction . these costs are discussed in more detail below and throughout this section . net revenue utility following is an analysis of the change in net revenue comparing 2010 to 2009 . amount ( in millions ) .\n[/PRE]\n[POST]\nthe volume/weather variance is primarily due to an increase of 8362 gwh , or 8% ( 8 % ) , in billed electricity usage in all retail sectors , including the effect on the residential sector of colder weather in the first quarter 2010 compared to 2009 and warmer weather in the second and third quarters 2010 compared to 2009 . the industrial sector reflected strong sales growth on continuing signs of economic recovery . the improvement in this sector was primarily driven by inventory restocking and strong exports with the chemicals , refining , and miscellaneous manufacturing sectors leading the improvement . the retail electric price variance is primarily due to : increases in the formula rate plan riders at entergy gulf states louisiana effective november 2009 , january 2010 , and september 2010 , at entergy louisiana effective november 2009 , and at entergy mississippi effective july 2009 ; a base rate increase at entergy arkansas effective july 2010 ; rate actions at entergy texas , including base rate increases effective in may and august 2010 ; a formula rate plan provision of $ 16.6 million recorded in the third quarter 2009 for refunds that were made to customers in accordance with settlements approved by the lpsc ; and the recovery in 2009 by entergy arkansas of 2008 extraordinary storm costs , as approved by the apsc , which ceased in january 2010 . the recovery of storm costs is offset in other operation and maintenance expenses . see note 2 to the financial statements for further discussion of the proceedings referred to above. .\n[/POST]",
'table': '| Row | 2009 net revenue | volume/weather | retail electric price | provision for regulatory proceedings | rough production cost equalization | ano decommissioning trust | fuel recovery | other | 2010 net revenue |\n|---|---|---|---|---|---|---|---|---|---|\n| amount ( in millions ) | 4694.0 | 231.0 | 137.0 | 26.0 | 19.0 | -24.0 | -44.0 | 12.0 | 5051.0 |',
'question': 'what was the difference in net revenue between 2009 and 2010?',
'id': 'Single_ETR/2011/page_22.pdf-3',
'doc_pre_text': "entergy corporation and subsidiaries management's financial discussion and analysis refer to 201cselected financial data - five-year comparison of entergy corporation and subsidiaries 201d which accompanies entergy corporation 2019s financial statements in this report for further information with respect to operating statistics . in november 2007 the board approved a plan to pursue a separation of entergy 2019s non-utility nuclear business from entergy through a spin-off of the business to entergy shareholders . in april 2010 , entergy announced that it planned to unwind the business infrastructure associated with the proposed spin-off transaction . as a result of the plan to unwind the business infrastructure , entergy recorded expenses in 2010 for the write-off of certain capitalized costs incurred in connection with the planned spin-off transaction . these costs are discussed in more detail below and throughout this section . net revenue utility following is an analysis of the change in net revenue comparing 2010 to 2009 . amount ( in millions ) .",
'doc_post_text': 'the volume/weather variance is primarily due to an increase of 8362 gwh , or 8% ( 8 % ) , in billed electricity usage in all retail sectors , including the effect on the residential sector of colder weather in the first quarter 2010 compared to 2009 and warmer weather in the second and third quarters 2010 compared to 2009 . the industrial sector reflected strong sales growth on continuing signs of economic recovery . the improvement in this sector was primarily driven by inventory restocking and strong exports with the chemicals , refining , and miscellaneous manufacturing sectors leading the improvement . the retail electric price variance is primarily due to : increases in the formula rate plan riders at entergy gulf states louisiana effective november 2009 , january 2010 , and september 2010 , at entergy louisiana effective november 2009 , and at entergy mississippi effective july 2009 ; a base rate increase at entergy arkansas effective july 2010 ; rate actions at entergy texas , including base rate increases effective in may and august 2010 ; a formula rate plan provision of $ 16.6 million recorded in the third quarter 2009 for refunds that were made to customers in accordance with settlements approved by the lpsc ; and the recovery in 2009 by entergy arkansas of 2008 extraordinary storm costs , as approved by the apsc , which ceased in january 2010 . the recovery of storm costs is offset in other operation and maintenance expenses . see note 2 to the financial statements for further discussion of the proceedings referred to above. .',
'doc_table': {'amount ( in millions )': {'2009 net revenue': 4694.0,
'volume/weather': 231.0,
'retail electric price': 137.0,
'provision for regulatory proceedings': 26.0,
'rough production cost equalization': 19.0,
'ano decommissioning trust': -24.0,
'fuel recovery': -44.0,
'other': 12.0,
'2010 net revenue': 5051.0}},
'dialogue_conv_questions': ['what was the difference in net revenue between 2009 and 2010?',
'and the specific value for 2009 again?',
'so what was the percentage change during this time?'],
'dialogue_conv_answers': ['357', '4694', '7.61%'],
'dialogue_turn_program': ['subtract(5051, 4694)',
'4694',
'subtract(5051, 4694), divide(#0, 4694)'],
'dialogue_executed_answers': [357.0, 4694.0, 0.07605],
'dialogue_qa_split': [False, False, False],
'features_num_dialogue_turns': 3,
'features_has_type2_question': False,
'features_has_duplicate_columns': False,
'features_has_non_numeric_values': False,
'ground_truth_answer': 357.0,
'reasoning': 'The table shows 2009 net revenue of 4,694.0 million and 2010 net revenue of 5,051.0 million. The difference is 5,051.0 minus 4,694.0, which equals 357.0 million.',
'ops': 'subtract(const_5051.0, const_4694.0)',
'answer': '357.0'}
Code
from typing import Literalimport dspyclass AssessmentSignature(dspy.Signature):""" Categorize model predictions by comparing them to ground truth, context, and evidence. Assign a specific error type or OK label, with concise justification, based on rubric. When comparing numerical answers, always allow a tolerance of 1e-2. For eg: If the question asks for a percentage, but the ground_truth_answer is given as a decimal, the assessment_answer label will be GROUND_TRUTH_INCORRECT """ ground_truth_answer: str= dspy.InputField( desc="The correct answer as per the ground truth data." ) table: str= dspy.InputField( desc="Tabular data (as string) relevant to the question and answer." ) conversation_context: str= dspy.InputField( desc="Previous dialogue turns or context for the current question." ) evidence_snippets: str= dspy.InputField( desc="Text snippets from the source document supporting the answer." ) question: str= dspy.InputField(desc="The question being answered by the model.") predicted_reasoning: str= dspy.InputField( desc="Model's step-by-step explanation or justification for its answer." ) predicted_ops: str= dspy.InputField( desc="Operations or programmatic steps the model used to derive its answer." ) predicted_answer: str= dspy.InputField( desc="The answer predicted by the model for the given question." ) assessment_answer: Literal["OK","NUMERICAL_ANSWER_WRONG","TEXTUAL_SELECTION_ANSWER_WRONG","FORMAT_ERROR","EVIDENCE_MISMATCH","GROUND_TRUTH_INCORRECT", ] = dspy.OutputField(desc="Single categorical label.")
Code
selected_records[0]
{'model_name': 'openai/o4-mini-2025-04-16',
'turn_em_metric_score': 1.0,
'conversation_context': 'None',
'evidence_snippets': "[PRE]\nentergy corporation and subsidiaries management's financial discussion and analysis refer to 201cselected financial data - five-year comparison of entergy corporation and subsidiaries 201d which accompanies entergy corporation 2019s financial statements in this report for further information with respect to operating statistics . in november 2007 the board approved a plan to pursue a separation of entergy 2019s non-utility nuclear business from entergy through a spin-off of the business to entergy shareholders . in april 2010 , entergy announced that it planned to unwind the business infrastructure associated with the proposed spin-off transaction . as a result of the plan to unwind the business infrastructure , entergy recorded expenses in 2010 for the write-off of certain capitalized costs incurred in connection with the planned spin-off transaction . these costs are discussed in more detail below and throughout this section . net revenue utility following is an analysis of the change in net revenue comparing 2010 to 2009 . amount ( in millions ) .\n[/PRE]\n[POST]\nthe volume/weather variance is primarily due to an increase of 8362 gwh , or 8% ( 8 % ) , in billed electricity usage in all retail sectors , including the effect on the residential sector of colder weather in the first quarter 2010 compared to 2009 and warmer weather in the second and third quarters 2010 compared to 2009 . the industrial sector reflected strong sales growth on continuing signs of economic recovery . the improvement in this sector was primarily driven by inventory restocking and strong exports with the chemicals , refining , and miscellaneous manufacturing sectors leading the improvement . the retail electric price variance is primarily due to : increases in the formula rate plan riders at entergy gulf states louisiana effective november 2009 , january 2010 , and september 2010 , at entergy louisiana effective november 2009 , and at entergy mississippi effective july 2009 ; a base rate increase at entergy arkansas effective july 2010 ; rate actions at entergy texas , including base rate increases effective in may and august 2010 ; a formula rate plan provision of $ 16.6 million recorded in the third quarter 2009 for refunds that were made to customers in accordance with settlements approved by the lpsc ; and the recovery in 2009 by entergy arkansas of 2008 extraordinary storm costs , as approved by the apsc , which ceased in january 2010 . the recovery of storm costs is offset in other operation and maintenance expenses . see note 2 to the financial statements for further discussion of the proceedings referred to above. .\n[/POST]",
'table': '| Row | 2009 net revenue | volume/weather | retail electric price | provision for regulatory proceedings | rough production cost equalization | ano decommissioning trust | fuel recovery | other | 2010 net revenue |\n|---|---|---|---|---|---|---|---|---|---|\n| amount ( in millions ) | 4694.0 | 231.0 | 137.0 | 26.0 | 19.0 | -24.0 | -44.0 | 12.0 | 5051.0 |',
'question': 'what was the difference in net revenue between 2009 and 2010?',
'id': 'Single_ETR/2011/page_22.pdf-3',
'doc_pre_text': "entergy corporation and subsidiaries management's financial discussion and analysis refer to 201cselected financial data - five-year comparison of entergy corporation and subsidiaries 201d which accompanies entergy corporation 2019s financial statements in this report for further information with respect to operating statistics . in november 2007 the board approved a plan to pursue a separation of entergy 2019s non-utility nuclear business from entergy through a spin-off of the business to entergy shareholders . in april 2010 , entergy announced that it planned to unwind the business infrastructure associated with the proposed spin-off transaction . as a result of the plan to unwind the business infrastructure , entergy recorded expenses in 2010 for the write-off of certain capitalized costs incurred in connection with the planned spin-off transaction . these costs are discussed in more detail below and throughout this section . net revenue utility following is an analysis of the change in net revenue comparing 2010 to 2009 . amount ( in millions ) .",
'doc_post_text': 'the volume/weather variance is primarily due to an increase of 8362 gwh , or 8% ( 8 % ) , in billed electricity usage in all retail sectors , including the effect on the residential sector of colder weather in the first quarter 2010 compared to 2009 and warmer weather in the second and third quarters 2010 compared to 2009 . the industrial sector reflected strong sales growth on continuing signs of economic recovery . the improvement in this sector was primarily driven by inventory restocking and strong exports with the chemicals , refining , and miscellaneous manufacturing sectors leading the improvement . the retail electric price variance is primarily due to : increases in the formula rate plan riders at entergy gulf states louisiana effective november 2009 , january 2010 , and september 2010 , at entergy louisiana effective november 2009 , and at entergy mississippi effective july 2009 ; a base rate increase at entergy arkansas effective july 2010 ; rate actions at entergy texas , including base rate increases effective in may and august 2010 ; a formula rate plan provision of $ 16.6 million recorded in the third quarter 2009 for refunds that were made to customers in accordance with settlements approved by the lpsc ; and the recovery in 2009 by entergy arkansas of 2008 extraordinary storm costs , as approved by the apsc , which ceased in january 2010 . the recovery of storm costs is offset in other operation and maintenance expenses . see note 2 to the financial statements for further discussion of the proceedings referred to above. .',
'doc_table': {'amount ( in millions )': {'2009 net revenue': 4694.0,
'volume/weather': 231.0,
'retail electric price': 137.0,
'provision for regulatory proceedings': 26.0,
'rough production cost equalization': 19.0,
'ano decommissioning trust': -24.0,
'fuel recovery': -44.0,
'other': 12.0,
'2010 net revenue': 5051.0}},
'dialogue_conv_questions': ['what was the difference in net revenue between 2009 and 2010?',
'and the specific value for 2009 again?',
'so what was the percentage change during this time?'],
'dialogue_conv_answers': ['357', '4694', '7.61%'],
'dialogue_turn_program': ['subtract(5051, 4694)',
'4694',
'subtract(5051, 4694), divide(#0, 4694)'],
'dialogue_executed_answers': [357.0, 4694.0, 0.07605],
'dialogue_qa_split': [False, False, False],
'features_num_dialogue_turns': 3,
'features_has_type2_question': False,
'features_has_duplicate_columns': False,
'features_has_non_numeric_values': False,
'ground_truth_answer': 357.0,
'reasoning': 'The table shows 2009 net revenue of 4,694.0 million and 2010 net revenue of 5,051.0 million. The difference is 5,051.0 minus 4,694.0, which equals 357.0 million.',
'ops': 'subtract(const_5051.0, const_4694.0)',
'answer': '357.0'}
Weβll use Gemini Flash 2.5 as our judge model, for classifying the generated predictions for error analysis
Code
from tqdm import tqdmjudge_lm = deepcopy(lm_gemini_flash_2_5)judge_results = []with mlflow.start_run(run_name="error_analysis_gemini_2.5_flash") as run:with dspy.context(lm=judge_lm, cache=True, track_cost=True):for example in tqdm(judge_examples, desc="Judging examples"): module = dspy.ChainOfThought(AssessmentSignature) jr = module(**example) jr["assessment_reasoning"] = jr["reasoning"]del jr["reasoning"] judge_results.append( {"id": example["id"],"model_name": example["model_name"],"question": example["question"],"ground_truth_answer": example["ground_truth_answer"],"predicted_answer": example["predicted_answer"],"assessment_answer": jr["assessment_answer"],"assessment_reasoning": jr["assessment_reasoning"], } )
Judging examples: 1%| | 2/289 [00:00<00:17, 16.77it/s]2025/07/28 20:07:50 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 1%|β | 4/289 [00:00<00:19, 14.79it/s]2025/07/28 20:07:50 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 2%|β | 6/289 [00:00<00:19, 14.85it/s]2025/07/28 20:07:50 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:50 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 4%|β | 11/289 [00:00<00:22, 12.42it/s]2025/07/28 20:07:51 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 5%|β | 14/289 [00:00<00:18, 15.05it/s]2025/07/28 20:07:51 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:51 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 6%|β | 17/289 [00:01<00:15, 18.13it/s]2025/07/28 20:07:51 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:51 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 7%|β | 20/289 [00:01<00:13, 19.77it/s]2025/07/28 20:07:51 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 8%|β | 24/289 [00:01<00:11, 23.48it/s]2025/07/28 20:07:51 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 10%|β | 28/289 [00:01<00:09, 26.52it/s]2025/07/28 20:07:51 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 11%|β | 32/289 [00:01<00:09, 27.24it/s]2025/07/28 20:07:51 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 12%|ββ | 35/289 [00:01<00:10, 23.43it/s]2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 13%|ββ | 38/289 [00:01<00:10, 23.92it/s]2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 14%|ββ | 41/289 [00:01<00:10, 23.64it/s]2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 15%|ββ | 44/289 [00:02<00:10, 24.06it/s]2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 16%|ββ | 47/289 [00:02<00:09, 24.36it/s]2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 17%|ββ | 50/289 [00:02<00:09, 24.44it/s]2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 18%|ββ | 53/289 [00:02<00:10, 23.14it/s]2025/07/28 20:07:52 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 20%|ββ | 59/289 [00:02<00:11, 20.29it/s]2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 21%|βββ | 62/289 [00:03<00:13, 16.86it/s]2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 22%|βββ | 65/289 [00:03<00:11, 19.32it/s]2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 24%|βββ | 68/289 [00:03<00:10, 20.77it/s]2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 25%|βββ | 71/289 [00:03<00:09, 22.32it/s]2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 26%|βββ | 74/289 [00:03<00:09, 22.84it/s]2025/07/28 20:07:53 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 27%|βββ | 77/289 [00:03<00:09, 22.32it/s]2025/07/28 20:07:54 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 28%|βββ | 80/289 [00:03<00:10, 20.68it/s]2025/07/28 20:07:54 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 30%|βββ | 86/289 [00:04<00:09, 21.69it/s]2025/07/28 20:07:54 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:54 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:54 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 31%|βββ | 89/289 [00:04<00:09, 21.10it/s]2025/07/28 20:07:54 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 32%|ββββ | 92/289 [00:04<00:09, 21.50it/s]2025/07/28 20:07:54 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:54 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 33%|ββββ | 95/289 [00:04<00:08, 22.81it/s]2025/07/28 20:07:54 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 34%|ββββ | 98/289 [00:04<00:07, 23.91it/s]2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 35%|ββββ | 101/289 [00:04<00:07, 24.41it/s]2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 36%|ββββ | 104/289 [00:04<00:08, 20.70it/s]2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 37%|ββββ | 107/289 [00:05<00:11, 16.11it/s]2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 38%|ββββ | 110/289 [00:05<00:09, 18.39it/s]2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 39%|ββββ | 114/289 [00:05<00:08, 21.66it/s]2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:55 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 41%|ββββ | 118/289 [00:05<00:07, 24.12it/s]2025/07/28 20:07:56 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:56 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 42%|βββββ | 122/289 [00:05<00:06, 25.92it/s]2025/07/28 20:07:56 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 44%|βββββ | 128/289 [00:05<00:06, 23.89it/s]2025/07/28 20:07:56 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:56 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 45%|βββββ | 131/289 [00:06<00:06, 22.85it/s]2025/07/28 20:07:56 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 46%|βββββ | 134/289 [00:06<00:06, 23.46it/s]2025/07/28 20:07:56 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 47%|βββββ | 137/289 [00:06<00:06, 23.90it/s]2025/07/28 20:07:56 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:56 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 48%|βββββ | 140/289 [00:06<00:06, 23.84it/s]2025/07/28 20:07:56 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 52%|ββββββ | 149/289 [00:06<00:05, 24.60it/s]2025/07/28 20:07:57 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:57 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:57 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 54%|ββββββ | 155/289 [00:07<00:06, 22.09it/s]2025/07/28 20:07:57 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:57 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:57 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 55%|ββββββ | 158/289 [00:07<00:07, 18.30it/s]2025/07/28 20:07:57 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:57 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 56%|ββββββ | 161/289 [00:07<00:06, 19.50it/s]2025/07/28 20:07:57 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:57 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 57%|ββββββ | 164/289 [00:07<00:05, 21.21it/s]2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 58%|ββββββ | 168/289 [00:07<00:05, 23.87it/s]2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 60%|ββββββ | 172/289 [00:07<00:04, 25.66it/s]2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 61%|ββββββ | 175/289 [00:07<00:04, 26.17it/s]2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 62%|βββββββ | 178/289 [00:08<00:05, 20.48it/s]2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 63%|βββββββ | 181/289 [00:08<00:05, 19.97it/s]2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 64%|βββββββ | 184/289 [00:08<00:04, 21.03it/s]2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:58 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 65%|βββββββ | 187/289 [00:08<00:04, 21.89it/s]2025/07/28 20:07:59 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:59 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:59 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 66%|βββββββ | 190/289 [00:08<00:04, 20.94it/s]2025/07/28 20:07:59 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 67%|βββββββ | 193/289 [00:08<00:04, 21.33it/s]2025/07/28 20:07:59 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 68%|βββββββ | 196/289 [00:09<00:04, 21.37it/s]2025/07/28 20:07:59 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:07:59 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 69%|βββββββ | 199/289 [00:09<00:05, 17.97it/s]2025/07/28 20:07:59 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 70%|βββββββ | 201/289 [00:09<00:05, 16.87it/s]2025/07/28 20:07:59 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 70%|βββββββ | 203/289 [00:09<00:05, 14.73it/s]2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 71%|ββββββββ | 206/289 [00:09<00:04, 17.68it/s]2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 74%|ββββββββ | 213/289 [00:09<00:03, 23.63it/s]2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 75%|ββββββββ | 216/289 [00:10<00:02, 24.77it/s]2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 76%|ββββββββ | 219/289 [00:10<00:02, 25.95it/s]2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 77%|ββββββββ | 222/289 [00:10<00:02, 22.83it/s]2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 78%|ββββββββ | 225/289 [00:10<00:03, 19.59it/s]2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:00 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 79%|ββββββββ | 228/289 [00:10<00:03, 19.79it/s]2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 80%|ββββββββ | 231/289 [00:10<00:02, 20.88it/s]2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 81%|ββββββββ | 234/289 [00:10<00:02, 22.36it/s]2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 82%|βββββββββ | 237/289 [00:11<00:02, 22.83it/s]2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 83%|βββββββββ | 240/289 [00:11<00:02, 22.23it/s]2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 84%|βββββββββ | 243/289 [00:11<00:02, 21.50it/s]2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:01 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 85%|βββββββββ | 246/289 [00:11<00:02, 14.67it/s]2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 86%|βββββββββ | 249/289 [00:11<00:02, 16.99it/s]2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 87%|βββββββββ | 252/289 [00:11<00:01, 19.29it/s]2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 89%|βββββββββ | 256/289 [00:12<00:01, 22.46it/s]2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 90%|βββββββββ | 260/289 [00:12<00:01, 24.88it/s]2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 91%|βββββββββ | 263/289 [00:12<00:01, 24.21it/s]2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 92%|ββββββββββ| 266/289 [00:12<00:00, 25.37it/s]2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:02 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 93%|ββββββββββ| 269/289 [00:12<00:00, 20.30it/s]2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 94%|ββββββββββ| 272/289 [00:12<00:00, 19.67it/s]2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 95%|ββββββββββ| 275/289 [00:12<00:00, 20.71it/s]2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 96%|ββββββββββ| 278/289 [00:13<00:00, 21.31it/s]2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 97%|ββββββββββ| 281/289 [00:13<00:00, 22.55it/s]2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 98%|ββββββββββ| 284/289 [00:13<00:00, 22.90it/s]2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 99%|ββββββββββ| 287/289 [00:13<00:00, 23.65it/s]2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
2025/07/28 20:08:03 WARNING dspy.adapters.json_adapter: Failed to use structured output format, falling back to JSON mode.
Judging examples: 100%|ββββββββββ| 289/289 [00:13<00:00, 21.43it/s]
From the analysis above, we see that: - Majority of the errors for all our selected models are due to incorrect ground truth. - We also see cases where the model was unable to generate the answer in the format as expected by the ground truth. - Finally, somewhat surpringly, we see some results marked as βOKβ, even though we only selected records that didnβt match the ground truth using our exact match metric.
so what was the percentage change during this time?
7.605000e-02
7.6%
GROUND_TRUTH_INCORRECT
The question asks for a "percentage change". The model correctly c...
1
Single_ETR/2004/page_258.pdf-4
openai/o4-mini-2025-04-16
what is the percent change?
1.473800e-01
14.7%
GROUND_TRUTH_INCORRECT
The question asks for the "percent change". The predicted answer p...
3
Single_ADI/2011/page_83.pdf-2
openai/o4-mini-2025-04-16
what growth rate does this represent?
8.290600e-01
82.9%
GROUND_TRUTH_INCORRECT
The question asks for a 'growth rate', which is typically expresse...
4
Single_CB/2008/page_243.pdf-3
openai/o4-mini-2025-04-16
what was the percent change?
7.368000e-02
7.37
GROUND_TRUTH_INCORRECT
The question asks for the "percent change". The model correctly ca...
5
Single_AMT/2015/page_50.pdf-1
openai/o4-mini-2025-04-16
what was the low for share price for the quarter ended 12/31/15?
8.732000e+01
90.2
GROUND_TRUTH_INCORRECT
The question asks for the low share price for the quarter ended 12...
...
...
...
...
...
...
...
...
282
Single_SLG/2017/page_114.pdf-3
openai/o3-2025-04-16
so what was the percentage of pension plan contributions out of th...
2.302800e-01
23.03
GROUND_TRUTH_INCORRECT
The question asks for a "percentage". The model correctly calculat...
283
Single_JPM/2008/page_177.pdf-4
openai/o3-2025-04-16
what was the total amount of resale agreements in 2008, in millions?
2.080000e+04
200,265
GROUND_TRUTH_INCORRECT
The question asks for the 'total amount of resale agreements in 20...
284
Double_IPG/2014/page_95.pdf
openai/o3-2025-04-16
and what is it for the the 2009 one?
1.218121e+07
435259
GROUND_TRUTH_INCORRECT
The question asks for the value for "the 2009 one". The previous t...
286
Single_APTV/2018/page_36.pdf-2
openai/o3-2025-04-16
how much does the change in the value of the aptiv plc represent i...
3.080000e-01
30.8%
GROUND_TRUTH_INCORRECT
The question asks for the answer "in percentage". The model correc...
288
Single_RCL/2016/page_7.pdf-3
openai/o3-2025-04-16
what percentage change does this represent?
1.600000e-01
16.0
GROUND_TRUTH_INCORRECT
The question asks for a 'percentage change'. The model correctly c...
226 rows Γ 7 columns
Conclusion
Curriculum-first pass surfaced a gap between our metric and reality. Several βerrorsβ are actually correct answers hidden by formatting. Manual review shows many EM misses are due to surface form, not reasoning.
There are also cases where the ground-truth in the dataset is incorrect.
What broke EM
Numeric formatting: thousands separators, β0.5Mβ vs β500000β.
Units and scaling: $, %, M/B suffixes; percent vs decimal.
Rounding/tolerance: 2dp rounding vs full precision.
Boolean variants: yes/true/1 vs no/false/0.
The above results are not conclusive by any means, since the LLM-as-a-judge approach also has known flaws. However, it does give us some pointers on how to improve the model performance from here!
Note: LLM-as-judge remains imperfect. Weβll retain periodic human spot-checks. With cleaner metrics and logging, the next step is to test if DSPyβs optimizers actually lift EM under the EasyβMediumβHard schedule without inflating token cost.