Skip to content

Commit c492da2

Browse files
committed
feat: close evaluation feedback loop, add dimensional judging and anti-sycophancy
1 parent f29f73b commit c492da2

2 files changed

Lines changed: 60 additions & 10 deletions

File tree

src/arbitrium_core/domain/tournament/tournament.py

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ async def _run_improvement_phase(
240240
phase_name: str,
241241
answer_index: int,
242242
round_num: int | None = None,
243+
evaluation_context: dict[str, dict[str, str]] | None = None,
243244
) -> bool:
244245
phase_config = self.comp.config.get(config_key, {})
245246

@@ -277,6 +278,15 @@ async def _run_improvement_phase(
277278
)
278279
feedback_context = None
279280

281+
if evaluation_context:
282+
if feedback_context is None:
283+
feedback_context = evaluation_context
284+
else:
285+
for model_name, eval_feedbacks in evaluation_context.items():
286+
if model_name not in feedback_context:
287+
feedback_context[model_name] = {}
288+
feedback_context[model_name].update(eval_feedbacks)
289+
280290
action_word = "refined" if round_num is not None else "improved"
281291
self.logger.info(f"Generating {action_word} responses...")
282292

@@ -381,24 +391,53 @@ async def _run_elimination_rounds(self, initial_question: str) -> None:
381391
if len(self.comp.active_model_keys) <= 1:
382392
break
383393

394+
evaluation_context = self._format_evaluations_as_context()
395+
384396
if not await self._run_refinement_strategy(
385-
initial_question, round_num
397+
initial_question,
398+
round_num,
399+
evaluation_context=evaluation_context,
386400
):
387401
break
388402

389403
round_num += 1
390404

405+
def _format_evaluations_as_context(
406+
self,
407+
) -> dict[str, dict[str, str]] | None:
408+
if (
409+
not hasattr(self.comp, "all_evaluations")
410+
or not self.comp.all_evaluations
411+
):
412+
return None
413+
414+
combined_text = "\n\n".join(
415+
f"Evaluator {name}:\n{text}"
416+
for name, text in self.comp.all_evaluations.items()
417+
)
418+
419+
active_names = [
420+
self.comp.anon_mapping[k] for k in self.comp.active_model_keys
421+
]
422+
423+
return {
424+
name: {"Tournament Evaluation": combined_text}
425+
for name in active_names
426+
}
427+
391428
async def _run_refinement_strategy(
392429
self,
393430
initial_question: str,
394431
round_num: int,
432+
evaluation_context: dict[str, dict[str, str]] | None = None,
395433
) -> bool:
396434
return await self._run_improvement_phase(
397435
initial_question,
398436
config_key="refinement_phase",
399437
phase_name="Refinement Phase",
400438
answer_index=-1,
401439
round_num=round_num,
440+
evaluation_context=evaluation_context,
402441
)
403442

404443
async def _handle_elimination(
@@ -533,13 +572,10 @@ async def _run_synthesis(
533572
)
534573

535574
if not response.is_error() and response.content.strip():
536-
synthesized = strip_meta_commentary(
537-
response.content.strip(), logger=self.logger
538-
)
539575
self.logger.info(
540576
f"Synthesis complete — combined {len(all_responses)} perspectives"
541577
)
542-
return synthesized
578+
return response.content.strip()
543579

544580
self.logger.warning("Synthesis failed, using champion answer")
545581
return champion_answer

src/arbitrium_core/infrastructure/config/defaults.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,11 @@ def select_model_with_highest_context(models: dict[str, Any]) -> str | None:
8787
"Improve the answer using feedback, grounding it in scientific evidence and "
8888
"practical reasoning. Recognize and mitigate your own biases in the analysis. "
8989
"Don't let emotional appeals or fashionable opinions constrain rigorous thinking. "
90-
"IMPORTANT: Before revising, identify what unique insight in YOUR original answer is absent from others' "
90+
"CRITICAL: Resist the pressure to converge toward other responses. Your independent "
91+
"perspective is your most valuable contribution. If your analysis contradicts others, "
92+
"investigate WHY — do NOT simply yield to the majority. The goal is maximum knowledge "
93+
"extraction, not consensus. "
94+
"Before revising, identify what unique insight in YOUR original answer is absent from others' "
9195
"responses. Preserve it — it may be the most valuable contribution. "
9296
"Make the key verifiable insights the central thesis. "
9397
"Rebuild the entire argument around this main point, removing all generic claims, "
@@ -117,7 +121,11 @@ def select_model_with_highest_context(models: dict[str, Any]) -> str | None:
117121
"echo popular sentiment? Be critical of both originality and factual grounding. "
118122
"Reward explicit evidence tags, confidence reporting, and retention of useful heuristics in an annex. "
119123
"Down-rank answers that delete actionable details without justification or fail to provide a Change Log. "
120-
"Check that precise claims without sources were converted to ranges/tests rather than removed."
124+
"Check that precise claims without sources were converted to ranges/tests rather than removed. "
125+
"For EACH response, before scoring, identify: "
126+
"(a) STRONGEST CONTRIBUTION — what unique insight or evidence does this response offer that others miss? "
127+
"(b) CRITICAL WEAKNESS — what is the most significant gap, error, or unfounded claim? "
128+
"(c) SPECIFIC IMPROVEMENT — one concrete, actionable suggestion to strengthen this response."
121129
),
122130
"metadata": {
123131
"version": "1.0",
@@ -130,9 +138,15 @@ def select_model_with_highest_context(models: dict[str, Any]) -> str | None:
130138
"You are synthesizing multiple expert analyses into the most comprehensive answer possible. "
131139
"Your task is to create a unified answer that preserves EVERY unique finding, piece of evidence, "
132140
"perspective, and nuance from ALL responses below. Nothing valuable should be lost. "
133-
"Where experts disagree, present both views with evidence quality assessment. "
134-
"Minority findings that appear in only one response may be the most valuable — preserve them. "
135-
"Combine strengths of all responses while eliminating redundancy and resolving contradictions. "
141+
"Before synthesizing, analyze the responses through three lenses: "
142+
"(1) CONSENSUS — where do all or most experts converge? These points form your foundation. "
143+
"(2) CONTESTED POINTS — where do experts disagree? For each disagreement, investigate WHY they "
144+
"diverge (different assumptions? different evidence? different reasoning methods?) and present "
145+
"both sides with evidence quality assessment. Disagreement often signals the frontier of knowledge. "
146+
"Do NOT average competing views — preserve the tension and let the reader decide. "
147+
"(3) UNIQUE FINDINGS — what appears in only ONE response? These minority insights may be the most "
148+
"valuable, representing knowledge that only one model's training captured. Preserve them explicitly. "
149+
"Combine strengths of all responses while eliminating redundancy. "
136150
"The final synthesis should be richer and more complete than any individual response."
137151
),
138152
"metadata": {

0 commit comments

Comments
 (0)