feat(moa): add reference_max_tokens to cap advisor output and cut turn latency (#56756)

MoA per-turn latency is dominated by advisor GENERATION: turn wall time
correlates ~0.88 with output tokens and ~-0.03 with input tokens (measured over
52 turns). Each turn waits for the slowest advisor to finish writing, and
advisors were uncapped — writing multi-thousand-token essays the aggregator
only needs the gist of.

Add an opt-in per-preset reference_max_tokens knob (mirrors reference_temperature)
that caps ADVISOR output only; the acting aggregator is never capped. Default
None = uncapped, so existing presets are byte-for-byte unchanged (no regression).
Wired through both MoA execution paths (MoAChatCompletions.create and
aggregate_moa_context).

E2E: same task, closed preset uncapped vs reference_max_tokens=600 -> 59s to 33s
(~44% faster), final answer identical/correct.

- hermes_cli/moa_config.py: _coerce_int_or_none helper + reference_max_tokens
  in _normalize_preset/_default_preset/flattened view
- agent/moa_loop.py: read preset.reference_max_tokens, pass to reference fan-out
- agent/conversation_loop.py: pass reference_max_tokens on the per-turn path
- tests + docs
This commit is contained in:
Teknium 2026-07-02 00:16:35 -07:00 committed by GitHub
parent 9be39de0f2
commit 543d305bbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 117 additions and 5 deletions

View file

@ -42,6 +42,24 @@ def _coerce_int(value: Any, default: int) -> int:
return default
def _coerce_int_or_none(value: Any) -> int | None:
"""Coerce to a positive int, or None when unset/blank/invalid/non-positive.
Used for optional caps (e.g. reference_max_tokens) where None means
'no cap' the safe default that preserves prior uncapped behavior.
"""
if value is None or value == "":
return None
try:
n = int(value)
except (TypeError, ValueError):
try:
n = int(float(value))
except (TypeError, ValueError):
return None
return n if n > 0 else None
def _clean_slot(slot: Any) -> dict[str, str] | None:
if not isinstance(slot, dict):
return None
@ -66,6 +84,7 @@ def _default_preset() -> dict[str, Any]:
"reference_temperature": 0.6,
"aggregator_temperature": 0.4,
"max_tokens": 4096,
"reference_max_tokens": None,
"enabled": True,
}
@ -94,6 +113,15 @@ def _normalize_preset(raw: Any) -> dict[str, Any]:
"reference_temperature": _coerce_float(raw.get("reference_temperature"), 0.6),
"aggregator_temperature": _coerce_float(raw.get("aggregator_temperature"), 0.4),
"max_tokens": _coerce_int(raw.get("max_tokens"), 4096),
# Optional cap on how much each reference ADVISOR may generate per turn.
# None (default) = uncapped: advisors write full-length advice, matching
# prior behavior so existing presets are unchanged. Set a value (e.g.
# 600) to make advisors give concise advice — the dominant MoA latency
# is advisor generation (turn latency correlates ~0.88 with output
# tokens), and the aggregator only needs the gist of each advisor's
# judgement, so capping roughly halves per-turn wall time. Does NOT cap
# the acting aggregator (its output is the user-visible answer).
"reference_max_tokens": _coerce_int_or_none(raw.get("reference_max_tokens")),
}
@ -139,6 +167,7 @@ def normalize_moa_config(raw: Any) -> dict[str, Any]:
"reference_temperature": active["reference_temperature"],
"aggregator_temperature": active["aggregator_temperature"],
"max_tokens": active["max_tokens"],
"reference_max_tokens": active.get("reference_max_tokens"),
"enabled": active["enabled"],
}