본문으로 건너뛰기
cccskills
무료GitHub에 공개

large-class-style

Guide changes and reviews for SGLang’s Scheduler, TokenizerManager, and ModelRunner classes. Keep initialization in small, replaceable helpers and separate computation from coordination so large classes retain clear responsibilities and explicit dependencies.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

원문원문 설명 보기

Code style for SGLang large classes `Scheduler`, `TokenizerManager`, and `ModelRunner`: frozen-code conventions and `__init__` orchestration style. Use when modifying any of these three classes or reviewing changes to them.

설치 방법 보기

이럴 때 유용합니다

  • Reviewing changes to SGLang’s three large classes
  • Splitting initialization into replaceable helpers
  • Moving computation out of ModelRunner
  • Checking dependencies and ownership of field assignments

포함된 파일(1)

  • SKILL.md7.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Code Style for Scheduler / TokenizerManager / ModelRunner

Conventions for SGLang's three large classes:

  • Scheduler — python/sglang/srt/managers/scheduler.py
  • TokenizerManager — python/sglang/srt/managers/tokenizer_manager.py
  • ModelRunner — python/sglang/srt/model_executor/model_runner.py

1. Frozen Code

  • Some core files are frozen: orchestration-only — a thin composition root that constructs collaborators, wires them, delegates to them, and coordinates the calls. They must stay that way.
  • Domain logic does not belong in a frozen file; it lives in a collaborator class in its own module.

1.1 Why

  • The file is a thin orchestrator over collaborator classes; freezing keeps it that way and stops it growing back into a god class.
  • Keeping domain logic in collaborators (their own files) is what makes per-file code ownership, single responsibility, and unit testing possible.
  • The orchestrator is the composition root: it may know about every collaborator, because wiring and sequencing them is its job. Coordination stays here — domain logic does not.

1.2 Frozen files

  • python/sglang/srt/model_executor/model_runner.py

1.3 Allowed: orchestration

Every statement refers to a collaborator and is one of:

  1. Construct — a short init_<thing> helper whose body is essentially a single construction (follows §2); use maybe_init_<thing> with a one-line gate when conditional.
  2. Wire — a short call that runs the helper from the orchestrator (e.g. in __init__).
  3. Delegate — calls to a collaborator's methods at the necessary call sites (self.foo.run(...)).
  4. Coordinate — the minimal control flow that selects or orders the above: an if choosing whether / which collaborator to wire or call, the order of calls, threading one call's result into the next.
  • Heuristic: a statement is allowed only if it constructs, wires, delegates, or selects/orders those — never if it computes or transforms a value beyond passing arguments and results through.
# model_runner.py — orchestration only.
def init_foo(self):                        # construct
    self.foo = FooManager(server_args=self.server_args, device=self.device)

self.init_foo()                            # wire (in __init__)

if self.server_args.enable_bar:            # coordinate: select
    self.bar.prepare(forward_batch)        # delegate
out = self.foo.run(forward_batch)          # delegate
self.baz.consume(out)                      # coordinate: thread result into next delegate

1.4 Not allowed: domain logic

  • Config building, data transformation, algorithm bodies, math, post-processing — any branch or loop that computes rather than coordinates.
  • It belongs in the collaborator.
# NOT allowed in a frozen file: domain logic inlined.
self.foo = None
if self.server_args.enable_foo:
    config = build_foo_config(self.model_config, self.device)   # config logic in frozen file
    self.foo = FooManager(config)                               # inline construction, not via (maybe_)init_foo
    out = [step(x) for x in batch]                              # computation, not coordination
  • Fix: move that body into FooManager (its __init__ or a factory) plus a (maybe_)init_foo helper.

1.5 Where coordination logic goes

  1. Default: extract. Pull cohesive coordination into a low-coupling collaborator (an initializer, a forward pipeline) and delegate to it.
  2. Residue stays. Coordination that can't be cohesively extracted may remain — but only the minimal Coordinate form above, kept pseudocode-readable. This is the explicit exception, not a fallback; note why it stays.
  • When the residue outgrows pseudocode, that is the signal to extract a dedicated coordinator — not to keep inlining.

1.6 Pass what the collaborator needs, not the god object

  • When you extract domain logic into a collaborator (a factory, an initializer, a pipeline), give it the specific values it needs — model_config, device, the sizes — not the whole frozen object (ModelRunner, Scheduler).

  • Passing the god object back re-creates the coupling the split was meant to remove: the module still reads dozens of attributes off it, can't be unit-tested without building the whole class, and every field rename ripples back in.

  • Default to narrow, keyword args. Reference shape: layer_setup.resolve_layer_indices(*, model, model_config, is_draft_worker, spec_algorithm).

  • Return a small frozen struct and let the orchestrator assign it onto its own fields. The collaborator should not reach back in and mutate the god object.

  • If a leaf genuinely needs the live object — its constructor contract already takes the runner, or it reads state that mutates after init — confine that dependency to the smallest leaf and pass narrow args everywhere above it. Note why it can't be narrowed.

1.7 If you do pass the god object, keep it read-only

  • A callee that genuinely takes the live object should read fields off it and return results; it writes fields back only when there is genuinely no other way.
  • The orchestrator owns the assignment onto its own fields.
  • Why: a callee that mutates the god object scatters its writes across other modules — you can no longer see what ModelRunner owns by reading model_runner.py, the hidden writes race with the orchestrator's own ordering, and the callee silently depends on being invoked at exactly the right moment.
# Good — callee reads the runner and returns a small frozen struct; the orchestrator
# owns the writes.
# model_runner.py
class ModelRunner:
    def bar(self):
        self.foo_result = foo(self)

# another_file.py
def foo(model_runner) -> FooResult:
    return FooResult(a=xx, b=yy, c=zz)

# Avoid — callee reaches back in and writes the runner's fields.
# model_runner.py
class ModelRunner:
    def bar(self):
        foo(self)

# another_file.py
def foo(model_runner):
    model_runner.a = xx
    model_runner.b = yy
    model_runner.c = zz

2. __init__ style

Apply when modifying the __init__ of the three classes above.

2.1 Why

  • Downstream forks override one piece (tokenizer, KV cache, IPC, …).
  • Inline logic forces them to copy the whole __init__, which rots against upstream.
  • Splitting into init_* helpers lets them override exactly what they need.
  • Reference shape: TokenizerManager.__init__ in python/sglang/srt/managers/tokenizer_manager.py.

2.2 Rules

  • __init__ is an orchestrator. Sequence of self.init_*(...) calls + minimal glue. No non-trivial construction inlined.
  • One helper per overridable unit. Each init_* = one concern a subclass might swap. Don't lump.
  • Naming: init_<thing> (snake_case, names the component). Conditional construction → maybe_init_<thing>, gate inside the helper.
  • No silent state coupling. A helper only reads self.* set by earlier helpers. Ordering lives in __init__. Shared intermediates → pass as args, not via self.*.
  • New logic = new helper. Default to adding init_<thing>, not another inline block. One-line self.foo = server_args.foo is fine; structured logic is not.
  • Preserve override points. Prefer additive changes to existing init_* signatures. Breaking changes → call out in PR.

2.3 Scope

  • Only the three classes listed above.
  • Not other manager-style classes, not small dataclass/utility constructors.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Develop lightweight CUDA operations for SGLang using JIT, which compiles code on first use. A tensor-scaling example explains implementation conventions, input validation, memory access helpers, and when to choose this approach.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Add a lightweight CUDA operation to SGLang
  • Choose between JIT and ahead-of-time compilation
  • Validate tensor inputs in a kernel launcher
sgl-project/sglang3.7만2026년 10월 19일 업데이트

Add a CUDA/C++ GPU operation to sgl-kernel using AOT, meaning compilation before use. Follow the implementation through PyTorch registration, Python API exposure, SGLang integration, correctness tests, and benchmarks that account for cache reuse.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Adding a CUDA/C++ operation to sgl-kernel
  • Registering an operation with PyTorch and exposing a Python API
  • Testing numerical results and invalid inputs
sgl-project/sglang3.7만2026년 10월 19일 업데이트

Monitor selected GitHub Actions checks on an SGLang pull request until they pass on its latest commit. Diagnose failures, push small validated fixes, and retry only failed jobs within defined limits.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Monitor selected PR checks until they pass
  • Separate code failures from infrastructure problems
  • Apply small fixes and track the resulting checks
sgl-project/sglang3.7만2026년 10월 19일 업데이트

Review existing tests and CI, the automated checks run during development, for redundant coverage, misplaced tests, and opportunities to reduce runtime or cost. Receive file-specific recommendations based on documented improvement patterns, with uncertain findings separated.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Investigating a slow test suite
  • Finding redundant or misplaced tests
  • Reviewing CI runtime and cost
sgl-project/sglang3.7만2026년 10월 19일 업데이트

Understand and modify SGLang's CI pipelines, including test stage order, start conditions, early stopping after failures, and workload splitting. Use the guide to add jobs and investigate failed, skipped, or cancelled checks.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Add a test job to an SGLang CI stage
  • Investigate failed or skipped CI checks
  • Update test partitions and waiting job counts
sgl-project/sglang3.7만2026년 10월 19일 업데이트

Collect and review SGLang startup logs to identify unnecessary output and trace its source. Get saved logs and specific cleanup proposals while preserving useful diagnostics, with runtime changes left for user approval.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Investigating repeated messages in startup logs
  • Checking which startup warnings need attention
  • Comparing startup logs across models and GPU counts
sgl-project/sglang3.7만2026년 10월 19일 업데이트

sgl-project의 스킬 모두 보기

이 스킬의 문제 신고