refactor: centralize all hyperparameters into config/govon.yaml#697
Conversation
- Create config/govon.yaml as single source of truth for all LLM/serving/context hyperparameters - Add GovOnConfig class to runtime_config.py: YAML loading + env var overrides + singleton - Replace 30+ hardcoded constants in nodes.py, api_server.py, schemas.py with config references - Support legacy GEN_* env vars alongside new GOVON_* namespace for backward compatibility - Make vLLM LoRA params (MAX_LORAS, MAX_LORA_RANK) configurable via env vars in entrypoint.sh
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
Configuration Infrastructure config/govon.yaml, src/inference/runtime_config.py |
Added unified GovOnConfig system with frozen dataclasses for generation, serving, context, tools, rate limiting, and validation. Includes YAML loader with env var override precedence and legacy GEN_* compatibility. Singleton govon_config exported for module-wide consumption. |
API Server & Request Validation src/inference/api_server.py, src/inference/schemas.py |
Updated sampling parameter defaults, vLLM client timeouts, draft-generation requests, LLM instantiation temperatures, and rate limit decorators to use govon_config values. Modified Pydantic Field constraints to reference configuration-derived constants for prompt length, token ceilings, and iteration limits. |
Entrypoint Script scripts/entrypoint.sh |
Introduced configurable LoRA limits (MAX_LORAS, MAX_LORA_RANK) with defaults, replacing hardcoded values in vLLM argument construction. |
Graph Context Management src/inference/graph/nodes.py |
Replaced hardcoded context/windowing constants (rejection thresholds, message retention, summarization triggers, token budgets, tool result truncation) with govon_config.context.* values. |
Sequence Diagram(s)
sequenceDiagram
participant env as Environment Variables
participant yaml as YAML File
participant loader as runtime_config<br/>Loader
participant config as GovOnConfig<br/>Singleton
participant modules as Consuming<br/>Modules
env->>loader: 1. _env() reads env vars<br/>(precedence check)
yaml->>loader: 2. _load_yaml() parses<br/>config/govon.yaml
loader->>loader: 3. Merge with dataclass<br/>defaults (env > yaml > defaults)
loader->>config: 4. Create frozen<br/>dataclass instances
config->>modules: 5. Exposed via<br/>govon_config singleton
modules->>modules: Use config values for<br/>timeouts, rates,<br/>sampling, budgets
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
🐰 A config to bind them all,
No hardcoded walls to stall,
YAML speaks, env vars sing,
Unified settings—now the thing!
Generation, serving, tools in grace,
Configuration finds its place. ✨
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 78.95% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title 'refactor: centralize all hyperparameters into config/govon.yaml' accurately captures the main objective of the PR—consolidating scattered hyperparameters into a unified YAML configuration file. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
📝 Generate docstrings
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
refactor/centralize-hyperparameters
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
🧹 Nitpick comments (5)
src/inference/runtime_config.py (2)
587-587:stop_sequencesnot env-overridable — document or add support.
stop_sequencesis only sourced from YAML/defaults with noGOVON_GENERATION_STOP_SEQUENCESenv var override. This is likely intentional since parsing a list from an env var requires a delimiter convention. Consider adding a brief comment explaining this is YAML-only, or implement env var support with comma-separated parsing if runtime override is needed.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/inference/runtime_config.py` at line 587, The stop_sequences value in runtime_config.py (constructed from gen_raw and set via stop_sequences=gen_raw.get("stop_sequences", ["[|endofturn|]"])) is not overridable via environment variables; either document that stop_sequences is YAML-only or add env support: read a GOVON_GENERATION_STOP_SEQUENCES env var, split it on a chosen delimiter (e.g., comma) and strip items, and fall back to gen_raw if the env var is absent/empty; implement this logic where stop_sequences is assigned so callers using stop_sequences get the env-parsed list.
498-507: Frozen dataclass with mutableDictfield — works but document the contract.
_ToolsConfigisfrozen=Truebut containsoverrides: Dict[str, _ToolDefaultConfig]. While the dict reference is immutable (you can't reassignself.overrides), the dict contents could theoretically be mutated after construction. This is safe here because:
- The dict is only populated in
GovOnConfig.load()and never modified afterward_ToolDefaultConfigis also frozenConsider adding a brief docstring note that callers must not mutate
overrides, or useMappingProxyTypefor true immutability if this becomes a concern.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/inference/runtime_config.py` around lines 498 - 507, _toolsConfig is declared frozen but contains a mutable dict `overrides`, which can be mutated after construction; update _ToolsConfig to enforce immutability or document the contract: either wrap `overrides` in an immutable view (e.g., use MappingProxyType on the dict provided in GovOnConfig.load()) so the `overrides` field truly cannot be mutated, or add a brief docstring on _ToolsConfig stating callers must not mutate `overrides` after construction; reference symbols: _ToolsConfig, overrides, _ToolDefaultConfig, GovOnConfig.load(), and for_tool when making the change.src/inference/graph/nodes.py (1)
653-656: Minor inconsistency:MAX_TOOL_RESULT_CHARSread inside function vs module-level.Unlike other constants (lines 35-51) which are read at module import time,
MAX_TOOL_RESULT_CHARSis read insidemake_tools_node_v3(). This creates a minor inconsistency — the value is captured when the factory is called rather than at import time. While functionally equivalent given the frozen config, consider moving this to module level for consistency:♻️ Optional: Move to module level for consistency
_AGENT_INPUT_BUDGET = govon_config.context.agent_input_budget +_MAX_TOOL_RESULT_CHARS = govon_config.context.max_tool_result_charsThen reference
_MAX_TOOL_RESULT_CHARSin the function.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/inference/graph/nodes.py` around lines 653 - 656, The constant MAX_TOOL_RESULT_CHARS is being read inside make_tools_node_v3 which is inconsistent with other module-level constants; move the read to module scope by defining a module-level variable (e.g., _MAX_TOOL_RESULT_CHARS = govon_config.context.max_tool_result_chars) near the other constants and update make_tools_node_v3 to reference _MAX_TOOL_RESULT_CHARS instead of reading govon_config again.src/inference/api_server.py (1)
79-87: Verifydefault_factoryusage in non-frozen dataclass.Using
default_factory=lambda: govon_config.generation.max_tokensis valid but creates a closure that reads fromgovon_configat instance creation time rather than at class definition time. Sincegovon_configis frozen and immutable after module load, this works correctly. However, if you want the default captured at class definition time (like other modules), consider using a module-level constant:♻️ Alternative: Use module-level constants for consistency
+_DEFAULT_SAMPLING_MAX_TOKENS = govon_config.generation.max_tokens +_DEFAULT_SAMPLING_TEMPERATURE = govon_config.generation.temperature `@dataclass` class SamplingParams: """Sampling parameters for vLLM HTTP API. Works without a direct vLLM import.""" - max_tokens: int = field(default_factory=lambda: govon_config.generation.max_tokens) - temperature: float = field(default_factory=lambda: govon_config.generation.temperature) + max_tokens: int = _DEFAULT_SAMPLING_MAX_TOKENS + temperature: float = _DEFAULT_SAMPLING_TEMPERATURE🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/inference/api_server.py` around lines 79 - 87, The SamplingParams dataclass currently uses default_factory lambdas that defer reading govon_config until instance creation; to capture defaults at module-import time for consistency, define module-level constants (e.g., MAX_TOKENS_DEFAULT, TEMPERATURE_DEFAULT) assigned from govon_config.generation.* and then use those constants as the dataclass field defaults (replace field(default_factory=...) with field(default=MAX_TOKENS_DEFAULT) / field(default=TEMPERATURE_DEFAULT) for the corresponding fields in SamplingParams) so the values are fixed at class-definition time.config/govon.yaml (1)
124-134: Clarify intent: Some tool overrides only specifytimeout_sec.
issue_detector,stats_lookup, anddemographics_lookuponly overridetimeout_secwithoutmax_retries. According toruntime_config.py(lines 714-717), missing keys fall back totls_defaults, which meansmax_retries=0. This is likely intentional, but consider adding a brief comment to make this explicit for operators tuning the config.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@config/govon.yaml` around lines 124 - 134, Add an inline comment in the overrides block clarifying that omitting max_retries for api entries (specifically issue_detector, stats_lookup, and demographics_lookup) is intentional because runtime_config.py falls back to tls_defaults (resulting in max_retries=0); reference the overrides keys (issue_detector, stats_lookup, demographics_lookup) and the tls_defaults/max_retries behavior so operators know this omission is deliberate when tuning timeouts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@config/govon.yaml`:
- Around line 124-134: Add an inline comment in the overrides block clarifying
that omitting max_retries for api entries (specifically issue_detector,
stats_lookup, and demographics_lookup) is intentional because runtime_config.py
falls back to tls_defaults (resulting in max_retries=0); reference the overrides
keys (issue_detector, stats_lookup, demographics_lookup) and the
tls_defaults/max_retries behavior so operators know this omission is deliberate
when tuning timeouts.
In `@src/inference/api_server.py`:
- Around line 79-87: The SamplingParams dataclass currently uses default_factory
lambdas that defer reading govon_config until instance creation; to capture
defaults at module-import time for consistency, define module-level constants
(e.g., MAX_TOKENS_DEFAULT, TEMPERATURE_DEFAULT) assigned from
govon_config.generation.* and then use those constants as the dataclass field
defaults (replace field(default_factory=...) with
field(default=MAX_TOKENS_DEFAULT) / field(default=TEMPERATURE_DEFAULT) for the
corresponding fields in SamplingParams) so the values are fixed at
class-definition time.
In `@src/inference/graph/nodes.py`:
- Around line 653-656: The constant MAX_TOOL_RESULT_CHARS is being read inside
make_tools_node_v3 which is inconsistent with other module-level constants; move
the read to module scope by defining a module-level variable (e.g.,
_MAX_TOOL_RESULT_CHARS = govon_config.context.max_tool_result_chars) near the
other constants and update make_tools_node_v3 to reference
_MAX_TOOL_RESULT_CHARS instead of reading govon_config again.
In `@src/inference/runtime_config.py`:
- Line 587: The stop_sequences value in runtime_config.py (constructed from
gen_raw and set via stop_sequences=gen_raw.get("stop_sequences",
["[|endofturn|]"])) is not overridable via environment variables; either
document that stop_sequences is YAML-only or add env support: read a
GOVON_GENERATION_STOP_SEQUENCES env var, split it on a chosen delimiter (e.g.,
comma) and strip items, and fall back to gen_raw if the env var is absent/empty;
implement this logic where stop_sequences is assigned so callers using
stop_sequences get the env-parsed list.
- Around line 498-507: _toolsConfig is declared frozen but contains a mutable
dict `overrides`, which can be mutated after construction; update _ToolsConfig
to enforce immutability or document the contract: either wrap `overrides` in an
immutable view (e.g., use MappingProxyType on the dict provided in
GovOnConfig.load()) so the `overrides` field truly cannot be mutated, or add a
brief docstring on _ToolsConfig stating callers must not mutate `overrides`
after construction; reference symbols: _ToolsConfig, overrides,
_ToolDefaultConfig, GovOnConfig.load(), and for_tool when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bfdb1c22-0a77-4824-b884-4786b07642ef
📒 Files selected for processing (6)
config/govon.yamlscripts/entrypoint.shsrc/inference/api_server.pysrc/inference/graph/nodes.pysrc/inference/runtime_config.pysrc/inference/schemas.py
Related Issue
Background
All LLM/serving/context hyperparameters were hardcoded across multiple source files (
nodes.py,api_server.py,schemas.py,entrypoint.sh), making it impossible for users to tune the system for different GPU environments without modifying source code.Key Changes
config/govon.yaml: New unified configuration file with 6 sections (generation, serving, context, tools, rate_limit, validation) and GPU-tier guidelines in commentssrc/inference/runtime_config.py: AddGovOnConfigclass with YAML loading, env var overrides (GOVON_*namespace), legacyGEN_*backward compatibility, and module-levelgovon_configsingletonsrc/inference/graph/nodes.py: Replace 7 hardcoded constants (_MAX_CONSECUTIVE_REJECTIONS,_TOOL_CLEAR_AFTER_ITERATION,_TOOL_KEEP_RECENT,_SUMMARY_THRESHOLD_RATIO,_MAX_MESSAGE_TOKENS,_KEEP_RECENT,_AGENT_INPUT_BUDGET,MAX_TOOL_RESULT_CHARS) with config referencessrc/inference/api_server.py: Replace hardcodedSamplingParamsdefaults,httpx.Timeout(300.0, connect=30.0),temperature=0.0× 2,max_tokens=2048, temperature=0.7in domain_adapter_tool,2000overhead constant, and all@_rate_limit("30/minute")decorators with config referencessrc/inference/schemas.py: Replace hardcoded default values (max_tokens=512,temperature=0.7,top_p=0.9,max_iterations=10,max_prompt_length=4096,max_tokens_ceiling=4096) with config referencesscripts/entrypoint.sh: Make--max-lorasand--max-lora-rankconfigurable viaMAX_LORASandMAX_LORA_RANKenv varsTest Results
config/govon.yamlloads correctly (graceful fallback to defaults when PyYAML absent)Additional Notes
pyyaml>=6.0.0) is already declared inpyproject.toml. When not installed,GovOnConfig.load()falls back to hardcoded defaults with a warning log — no crash.GOVON_<SECTION>_<KEY>> legacyGEN_*>config/govon.yaml> dataclass defaults.Merge Checklist
Reviewer Guide
[MUST][MUST] API key is exposed in logs.[SHOULD][SHOULD] This logic should be extracted into a separate function.[NITS][NITS] \parsed_output` is clearer than `result` as a variable name.`[QUESTION][QUESTION] Can this condition ever be always True?Summary by CodeRabbit
Release Notes
New Features
config/govon.yamlfor unified control over generation parameters, GPU/serving settings, context management, tool execution defaults, API rate limiting, and request validation thresholds.Improvements