Thanks to visit codestin.com
Credit goes to github.com

Skip to content

refactor: centralize all hyperparameters into config/govon.yaml#697

Merged
umyunsang merged 2 commits into
mainfrom
refactor/centralize-hyperparameters
Apr 10, 2026
Merged

refactor: centralize all hyperparameters into config/govon.yaml#697
umyunsang merged 2 commits into
mainfrom
refactor/centralize-hyperparameters

Conversation

@umyunsang

@umyunsang umyunsang commented Apr 10, 2026

Copy link
Copy Markdown
Member

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 comments
  • src/inference/runtime_config.py: Add GovOnConfig class with YAML loading, env var overrides (GOVON_* namespace), legacy GEN_* backward compatibility, and module-level govon_config singleton
  • src/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 references
  • src/inference/api_server.py: Replace hardcoded SamplingParams defaults, httpx.Timeout(300.0, connect=30.0), temperature=0.0 × 2, max_tokens=2048, temperature=0.7 in domain_adapter_tool, 2000 overhead constant, and all @_rate_limit("30/minute") decorators with config references
  • src/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 references
  • scripts/entrypoint.sh: Make --max-loras and --max-lora-rank configurable via MAX_LORAS and MAX_LORA_RANK env vars

Test Results

  • All existing tests pass (no behavioral change — defaults match previous hardcoded values exactly)
  • config/govon.yaml loads correctly (graceful fallback to defaults when PyYAML absent)
  • Environment variables override YAML values (GOVON_* and legacy GEN_* both work)
  • Docker build succeeds
  • Runtime contract check passes

Additional Notes

  • PyYAML (pyyaml>=6.0.0) is already declared in pyproject.toml. When not installed, GovOnConfig.load() falls back to hardcoded defaults with a warning log — no crash.
  • All default values are identical to the previous hardcoded values, so there is zero behavioral change on existing deployments.
  • Environment variable override priority: GOVON_<SECTION>_<KEY> > legacy GEN_* > config/govon.yaml > dataclass defaults.

Merge Checklist

  • At least one code review approval
  • CODEOWNERS (team lead) final approval
  • All review comments resolved

Reviewer Guide

Tag Meaning Example
[MUST] Must fix (security, bug, performance issue) [MUST] API key is exposed in logs.
[SHOULD] Strongly recommended (code quality, maintainability) [SHOULD] This logic should be extracted into a separate function.
[NITS] Minor improvement (style, naming) [NITS] \parsed_output` is clearer than `result` as a variable name.`
[QUESTION] Question for understanding [QUESTION] Can this condition ever be always True?

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced centralized configuration system via config/govon.yaml for unified control over generation parameters, GPU/serving settings, context management, tool execution defaults, API rate limiting, and request validation thresholds.
    • Added environment variable override support for all configuration values, enabling deployment-time customization without code changes.
    • Made LoRA limits (max adapters and rank) configurable for flexible model serving.
  • Improvements

    • Request validation defaults and timeout settings now derive from configuration for enhanced operational control.

- 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
@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: String must contain at most 250 character(s) at "tone_instructions"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

Introduced a unified configuration system that loads generation, serving, context, tool, rate-limiting, and validation parameters from a new config/govon.yaml file with environment variable overrides. Multiple modules now consume this configuration instead of hardcoded defaults, affecting API timeouts, sampling parameters, context budgeting, and rate limits.

Changes

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
Loading

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 ⚠️ Warning 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.

@github-actions github-actions Bot added ai-model AI 모델 관련 backend 백엔드 관련 infra 인프라/배포 관련 labels Apr 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (5)
src/inference/runtime_config.py (2)

587-587: stop_sequences not env-overridable — document or add support.

stop_sequences is only sourced from YAML/defaults with no GOVON_GENERATION_STOP_SEQUENCES env 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 mutable Dict field — works but document the contract.

_ToolsConfig is frozen=True but contains overrides: Dict[str, _ToolDefaultConfig]. While the dict reference is immutable (you can't reassign self.overrides), the dict contents could theoretically be mutated after construction. This is safe here because:

  1. The dict is only populated in GovOnConfig.load() and never modified afterward
  2. _ToolDefaultConfig is also frozen

Consider adding a brief docstring note that callers must not mutate overrides, or use MappingProxyType for 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_CHARS read inside function vs module-level.

Unlike other constants (lines 35-51) which are read at module import time, MAX_TOOL_RESULT_CHARS is read inside make_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_chars

Then reference _MAX_TOOL_RESULT_CHARS in 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: Verify default_factory usage in non-frozen dataclass.

Using default_factory=lambda: govon_config.generation.max_tokens is valid but creates a closure that reads from govon_config at instance creation time rather than at class definition time. Since govon_config is 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 specify timeout_sec.

issue_detector, stats_lookup, and demographics_lookup only override timeout_sec without max_retries. According to runtime_config.py (lines 714-717), missing keys fall back to tls_defaults, which means max_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

📥 Commits

Reviewing files that changed from the base of the PR and between c9667a2 and 3e46595.

📒 Files selected for processing (6)
  • config/govon.yaml
  • scripts/entrypoint.sh
  • src/inference/api_server.py
  • src/inference/graph/nodes.py
  • src/inference/runtime_config.py
  • src/inference/schemas.py

@umyunsang umyunsang merged commit c7bf804 into main Apr 10, 2026
15 checks passed
@umyunsang umyunsang deleted the refactor/centralize-hyperparameters branch April 10, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-model AI 모델 관련 backend 백엔드 관련 infra 인프라/배포 관련

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant