| 1 | # SPDX-License-Identifier: Apache-2.0 |
| 2 | # SPDX-FileCopyrightText: Copyright contributors to the vLLM project |
| 3 | """Build the ``system_fingerprint`` string returned by the OpenAI-compatible |
| 4 | server. |
| 5 | |
| 6 | Four modes, configured via ``--fingerprint-mode``: |
| 7 | |
| 8 | * ``full`` (default): ``vllm-<version>[-<parallelism>]-<hash8>`` — encodes |
| 9 | server version, any non-trivial parallelism degree (tp/pp/dp/ep), and an |
| 10 | 8-char prefix of ``vllm_config.compute_hash()`` (covers model identity, |
| 11 | quant config, speculative, attention backend, etc.). |
| 12 | * ``hash``: ``vllm-<version>-<hash8>`` — parallelism stripped. |
| 13 | * ``custom``: user-provided literal via ``--fingerprint-value``. |
| 14 | * ``none``: the field is omitted (serialized as ``null``). |
| 15 | |
| 16 | ``get_system_fingerprint`` is only called at serving-class init (a handful |
| 17 | of times per server); each subclass caches the returned string on |
| 18 | ``self.system_fingerprint``, so per-request cost is one attribute read. |
| 19 | """ |
| 20 | |
| 21 | from __future__ import annotations |
| 22 | |
| 23 | from typing import Any, Literal |
| 24 | |
| 25 | FingerprintMode = Literal["full", "hash", "custom", "none"] |
| 26 | |
| 27 | _DEFAULT_MODE: FingerprintMode = "full" |
| 28 | _CUSTOM_VALUE: str | None = None |
| 29 | |
| 30 | |
| 31 | def set_default_fingerprint_mode( |
| 32 | mode: FingerprintMode, |
| 33 | custom_value: str | None = None, |
| 34 | ) -> None: |
| 35 | """Configure the fingerprint mode for subsequent ``get_system_fingerprint`` |
| 36 | calls. Called once at server startup.""" |
| 37 | global _DEFAULT_MODE, _CUSTOM_VALUE |
| 38 | _DEFAULT_MODE = mode |
| 39 | _CUSTOM_VALUE = custom_value |
| 40 | |
| 41 | |
| 42 | def get_system_fingerprint(vllm_config: Any) -> str | None: |
| 43 | """Return the fingerprint for ``vllm_config`` using the mode configured by |
| 44 | ``set_default_fingerprint_mode``.""" |
| 45 | return build_system_fingerprint(vllm_config, _DEFAULT_MODE, _CUSTOM_VALUE) |
| 46 | |
| 47 | |
| 48 | def build_system_fingerprint( |
| 49 | vllm_config: Any, |
| 50 | mode: FingerprintMode = "full", |
| 51 | custom_value: str | None = None, |
| 52 | ) -> str | None: |
| 53 | if mode == "none": |
| 54 | return None |
| 55 | if mode == "custom": |
| 56 | return custom_value |
| 57 | |
| 58 | from vllm import __version__ as vllm_version |
| 59 | |
| 60 | try: |
| 61 | hash8 = vllm_config.compute_hash()[:8] |
| 62 | except Exception: |
| 63 | hash8 = "nohash" |
| 64 | |
| 65 | if mode == "hash": |
| 66 | return f"vllm-{vllm_version}-{hash8}" |
| 67 | |
| 68 | # mode == "full" |
| 69 | parts: list[str] = [f"vllm-{vllm_version}"] |
| 70 | pc = getattr(vllm_config, "parallel_config", None) |
| 71 | if pc is not None: |
| 72 | tp = getattr(pc, "tensor_parallel_size", 1) |
| 73 | if tp > 1: |
| 74 | parts.append(f"tp{tp}") |
| 75 | pp = getattr(pc, "pipeline_parallel_size", 1) |
| 76 | if pp > 1: |
| 77 | parts.append(f"pp{pp}") |
| 78 | dp = getattr(pc, "data_parallel_size", 1) |
| 79 | if dp > 1: |
| 80 | parts.append(f"dp{dp}") |
| 81 | if getattr(pc, "enable_expert_parallel", False): |
| 82 | parts.append("ep") |
| 83 | parts.append(hash8) |
| 84 | return "-".join(parts) |