BIGJUTT/5556 / gateway /ensemble.py
BIGJUTT's picture
download
raw
5.22 kB
# -*- coding: utf-8 -*-
"""
Darwin-60B-DUO Ensemble V_1 — MAJ@N self-consistency + cross-verification.
For MCQ / short-answer queries:
1) Each backend produces N samples at temperature τ (default 0.7)
2) Each backend's answer = its own majority vote (RSA / self-consistency)
3) If both majorities agree → return that answer
4) If they disagree → each backend verifies the pair (cross-verification)
and the gateway picks the tournament winner
5) Tiebreaker on split verdicts: majority-vote-count confidence
"""
import asyncio
import re
from collections import Counter
from typing import Any, Dict, List, Optional, Tuple
_LETTERS = "ABCD"
def _extract_letter(text: str) -> str:
"""Extract A/B/C/D letter answer from a free-form response."""
if not text:
return ""
# Strip CoT / thinking tags
cleaned = re.sub(r"<\|START_THINKING\|>.*?<\|END_THINKING\|>", "", text, flags=re.S)
cleaned = re.sub(r"<think>.*?</think>", "", cleaned, flags=re.S)
for tag in ["<|END_THINKING|>", "</think>", "<|START_RESPONSE|>", "<|END_RESPONSE|>"]:
if tag in cleaned:
cleaned = cleaned.split(tag)[-1]
# Common answer patterns
patterns = [
r"ANSWER:\s*\(?([A-D])\)?",
r"\\boxed\{\s*\(?([A-D])\)?\s*\}",
r"final answer\s*(?:is|:)?\s*\(?([A-D])\)?",
r"answer\s+is\s*\(?([A-D])\)?",
r"\(([A-D])\)\s*$",
]
for p in patterns:
m = re.search(p, cleaned, re.I | re.M)
if m:
return m.group(1).upper()
# Fallback: last A-D token
candidates = re.findall(r"\b([A-D])\b", cleaned)
return candidates[-1].upper() if candidates else ""
def _majority(letters: List[str]) -> Tuple[Optional[str], Dict[str, int]]:
valid = [l for l in letters if l in _LETTERS]
if not valid:
return None, {}
counter = Counter(valid)
top, _ = counter.most_common(1)[0]
return top, dict(counter)
_VERIFY_TEMPLATE = (
"You are a graduate-level expert verifier. Given the following multiple-"
"choice question and two candidate letter answers, decide which is more "
"likely correct.\n\n"
"QUESTION:\n{question}\n\n"
"CANDIDATE 1 says answer = {a1}\n"
"CANDIDATE 2 says answer = {a2}\n\n"
"Think briefly, then respond with exactly one line:\n"
"VERDICT: 1 (if candidate 1's letter is correct)\n"
"VERDICT: 2 (if candidate 2's letter is correct)"
)
def _parse_verdict(text: str) -> Optional[int]:
m = re.search(r"VERDICT:\s*([12])", text)
return int(m.group(1)) if m else None
def _last_user_text(messages: List[Dict[str, str]]) -> str:
for m in reversed(messages):
if m.get("role") == "user":
return m.get("content", "")
return ""
async def ensemble_v1(
darwin,
awaxis,
messages: List[Dict[str, str]],
temperature: float = 0.7,
max_tokens: int = 4096,
n_rsa: int = 8,
) -> str:
"""
Run V_1 ensemble. Returns the final answer string formatted as
"ANSWER: X" so downstream tooling can parse uniformly.
"""
# --- Phase 1: parallel RSA (each backend N samples) ---
d_task = darwin.chat(messages, temperature=temperature, max_tokens=max_tokens, n=n_rsa)
a_task = awaxis.chat(messages, temperature=temperature, max_tokens=max_tokens, n=n_rsa)
d_outs, a_outs = await asyncio.gather(d_task, a_task)
d_letters = [_extract_letter(o) for o in d_outs]
a_letters = [_extract_letter(o) for o in a_outs]
d_maj, d_votes = _majority(d_letters)
a_maj, a_votes = _majority(a_letters)
# --- Phase 2: agreement check ---
if d_maj is None and a_maj is None:
return "ANSWER: (no valid answer extracted)"
if d_maj is None:
return f"ANSWER: {a_maj}"
if a_maj is None:
return f"ANSWER: {d_maj}"
if d_maj == a_maj:
return f"ANSWER: {d_maj}"
# --- Phase 3: cross-verification on mismatch ---
question = _last_user_text(messages)
verify_prompt = _VERIFY_TEMPLATE.format(question=question, a1=d_maj, a2=a_maj)
verify_msgs = [{"role": "user", "content": verify_prompt}]
d_verify_task = darwin.chat(verify_msgs, temperature=0.0, max_tokens=2048, n=1)
a_verify_task = awaxis.chat(verify_msgs, temperature=0.0, max_tokens=2048, n=1)
d_verify_outs, a_verify_outs = await asyncio.gather(d_verify_task, a_verify_task)
d_verdict = _parse_verdict(d_verify_outs[0])
a_verdict = _parse_verdict(a_verify_outs[0])
# --- Phase 4: combine verdicts ---
if d_verdict == a_verdict and d_verdict is not None:
return f"ANSWER: {d_maj if d_verdict == 1 else a_maj}"
if d_verdict is None and a_verdict is None:
# Fall back to confidence (higher own-vote count wins)
d_conf = d_votes.get(d_maj, 0)
a_conf = a_votes.get(a_maj, 0)
return f"ANSWER: {d_maj if d_conf >= a_conf else a_maj}"
if d_verdict is None:
return f"ANSWER: {d_maj if a_verdict == 1 else a_maj}"
if a_verdict is None:
return f"ANSWER: {d_maj if d_verdict == 1 else a_maj}"
# Split — confidence tiebreaker
d_conf = d_votes.get(d_maj, 0)
a_conf = a_votes.get(a_maj, 0)
return f"ANSWER: {d_maj if d_conf >= a_conf else a_maj}"

Xet Storage Details

Size:
5.22 kB
·
Xet hash:
edc192594c67cd097cee3141fe1d29eda8d5a87e6878031bbf0d2b1100615907

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.