| # -*- 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.