Skip to content

DRAFT (DO NOT MERGE) [TRTLLM-12498][feat] Add support for beam search in disaggregated serving - #14470

Closed
athena-nv wants to merge 20 commits into
NVIDIA:mainfrom
athena-nv:disagg_beam
Closed

DRAFT (DO NOT MERGE) [TRTLLM-12498][feat] Add support for beam search in disaggregated serving#14470
athena-nv wants to merge 20 commits into
NVIDIA:mainfrom
athena-nv:disagg_beam

Conversation

@athena-nv

@athena-nv athena-nv commented May 22, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

Release Notes

  • New Features

    • Added example configurations and scripts for disaggregated serving setup
    • Improved beam search support in disaggregated serving
    • Added tracking of cumulative beam scores through generation pipeline
  • Improvements

    • Enhanced KV cache handling for beam search scenarios in disaggregated mode
    • Expanded debugging output for better diagnostics in disaggregated serving

Description

Add beam search support to disaggregated serving for the Python Cache Transceiver and C++ KVCacheManager path.

TODO: add tests, remove logging

Test Coverage

This PR has not been tested yet.
See example scripts in examples/disaggregated/simpler_example/

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR implements beam search decoding support in disaggregated TensorRT-LLM serving. The changes remove KV cache formatting restrictions on beam width, propagate beam-structured block IDs through the cache-reuse and transceiver stack, and thread first-generation cumulative log probabilities from context to generation servers.

Changes

Beam search in disaggregated serving

Layer / File(s) Summary
Enable beam width > 1 in KV cache formatting
cpp/tensorrt_llm/batch_manager/cacheFormatter.cpp
The runtime check enforcing beamWidth == 1 is removed, allowing KV cache transfer to proceed for multi-beam requests.
Propagate beam_width through block ID retrieval
tensorrt_llm/_torch/disaggregation/resource/cache_reuse.py, tensorrt_llm/_torch/pyexecutor/resource_manager.py
Cache-reuse adapters read beam_width from sampling config and pass it to KVCacheManager.get_batch_cache_indices(), which now returns single-beam or per-beam block-ID arrays based on beam_width. A helper computes per-block token counts for logging.
Handle beam-structured block IDs in KV transfer
tensorrt_llm/_torch/disaggregation/base/transfer.py, tensorrt_llm/_torch/disaggregation/native/transfer.py, tensorrt_llm/_torch/disaggregation/transceiver.py
KV slice creation and transfer metadata are refactored to normalize 2D beam-oriented block ID arrays; serialization encodes shape metadata; alignment logic processes per-beam block lists; detailed logging tracks block-id shapes and beam-aware filtering.
Thread first_gen_cum_log_probs through parameters
tensorrt_llm/disaggregated_params.py, tensorrt_llm/serve/openai_protocol.py, tensorrt_llm/_torch/pyexecutor/llm_request.py, tensorrt_llm/executor/result.py
A new first_gen_cum_log_probs field carries cumulative beam scores from context to generation server; serialized in protocol messages and populated from backend responses. PyResult tracks and exposes the field via diff-based synchronization.
Seed first_gen_cum_log_probs into generation
tensorrt_llm/_torch/pyexecutor/py_executor.py, tensorrt_llm/_torch/pyexecutor/sampler.py
Generation server seeding logic copies first-gen cumulative log probs into the beam-search store; sampler extracts and stores these scores during context-phase completion; extensive logging instrumention provides beam-search state visibility.
Add logging for disaggregated service
tensorrt_llm/serve/openai_disagg_service.py
Detailed request/response logging added; single-choice validation removed to allow multi-beam context-server responses.

Design documentation and examples

Layer / File(s) Summary
Implementation notes and plan
implementation_notes.md, implementation_plan.md
Documents beam-flattening problem, call-chain analysis, beam search terminology, and detailed plan for propagating beam_width through block retrieval and handling first-generation log probabilities; includes caveats on downstream KV tail handling.
Example disaggregated setup
examples/disaggregated/simpler_example/*
Configuration files (agg_config.yaml, ctx_config.yaml, gen_config.yaml, disagg_config.yaml) and shell scripts (run.sh, run_agg.sh, kill.sh, kill_agg.sh, parse_output.sh) demonstrate end-to-end disaggregated serving with beam search; captured logs and output examples show successful multi-choice completion flows.

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • bo-nv
  • Tabrizian
  • Shixiaowei02
  • leslie-fang25
  • joyang-nv
  • suyoggupta
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description provides a brief explanation of changes (beam search support for Python Cache Transceiver and C++ KVCacheManager) and acknowledges incomplete work (tests and logging removal needed). However, it lacks detailed explanation of the issue, solution rationale, and comprehensive test coverage details required by the template. Expand the description to explain the problem being solved, the technical approach, why these specific changes are needed, and provide more concrete details on test coverage and example usage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly indicates this is a draft PR for adding beam search support to disaggregated serving, with proper formatting following the repository's template and a specific JIRA ticket reference.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch disagg_beam

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 14

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tensorrt_llm/serve/openai_disagg_service.py (2)

343-376: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Move these request-path dumps behind debug logging.

These logger.info calls emit per-request beam metadata, request IDs, and ctx_info_endpoint on every disaggregated request. That is a hot path, and it also exposes internal routing details in production logs. Please gate this behind debug/feature-flag logging or remove it before merge.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/serve/openai_disagg_service.py` around lines 343 - 376, The
per-request logger.info calls in _get_gen_request that log disagg_request_id,
ctx_info_endpoint and beam/request metadata should not run at INFO level on the
hot path; change them to be guarded debug/feature-flag logs. Replace the two
logger.info invocations with either logger.debug(...) or wrap them in an if
logger.isEnabledFor(logging.DEBUG): block (or check a feature flag like
self._verbose_logging) so that the messages from logger.info(...) in
_get_gen_request (and any logging of
request.disaggregated_params.ctx_info_endpoint, ctx_response.choices,
CompletionRequest/ChatCompletionRequest prompt token fields, and
DisaggregatedParams creation) are only emitted when debug/verbose logging is
enabled.

532-559: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Multi-choice ctx responses are still reduced to choices[0].

Commenting out the len(ctx_response.choices) != 1 check changes the contract, but the rest of this flow still validates and forwards only choices[0] (_verify_ctx_response, _need_gen, _get_gen_request). If beam search can produce multiple context choices here, the extra choices' disaggregation state and finish reasons are silently ignored.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/serve/openai_disagg_service.py` around lines 532 - 559, The code
currently drops all but choices[0] even when ctx_response.choices has multiple
entries; update the flow to handle multi-choice context responses instead of
reducing to the first choice: in the validation routine (where you currently
index into choice = ctx_response.choices[0]) iterate over ctx_response.choices
and validate each choice.disaggregated_params, ctx_request_id and
disagg_request_id (raising with contextual finish_reason and disagg/ctx ids for
that specific choice if invalid), and then either (A) return the full
ctx_response with all validated choices or (B) change the downstream callsites
(_verify_ctx_response, _need_gen, _get_gen_request) to accept and process a list
of choices (e.g., generate per-choice gen requests) so no disaggregation state
or finish_reason is silently ignored. Ensure all places that previously assumed
a single choice are updated to consume the list or handle branching per choice.
🟡 Minor comments (8)
examples/disaggregated/simpler_example/kill.sh-3-7 (1)

3-7: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard kill -9 when no matching process exists.

On Line 7, kill -9 runs even when pgrep finds nothing, which can fail the script path during normal “nothing to kill” runs.

Suggested fix
- export CTX_PROCESS_ID=$(pgrep -f "trtllm-serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --host localhost --port 8001 --config ./ctx_config.yaml")
- export GEN_PROCESS_ID=$(pgrep -f "trtllm-serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --host localhost --port 8002 --config ./gen_config.yaml")
- export DISAGG_PROCESS_ID=$(pgrep -f "trtllm-serve disaggregated -c ./disagg_config.yaml")
+ CTX_PROCESS_ID="$(pgrep -f "trtllm-serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --host localhost --port 8001 --config ./ctx_config.yaml" || true)"
+ GEN_PROCESS_ID="$(pgrep -f "trtllm-serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --host localhost --port 8002 --config ./gen_config.yaml" || true)"
+ DISAGG_PROCESS_ID="$(pgrep -f "trtllm-serve disaggregated -c ./disagg_config.yaml" || true)"
 
-kill -9 $CTX_PROCESS_ID $GEN_PROCESS_ID $DISAGG_PROCESS_ID
+PIDS=()
+[[ -n "${CTX_PROCESS_ID}" ]] && PIDS+=(${CTX_PROCESS_ID})
+[[ -n "${GEN_PROCESS_ID}" ]] && PIDS+=(${GEN_PROCESS_ID})
+[[ -n "${DISAGG_PROCESS_ID}" ]] && PIDS+=(${DISAGG_PROCESS_ID})
+(( ${`#PIDS`[@]} > 0 )) && kill -9 "${PIDS[@]}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/disaggregated/simpler_example/kill.sh` around lines 3 - 7, The kill
-9 invocation should be guarded so it only runs for PIDs that exist: check each
captured variable (CTX_PROCESS_ID, GEN_PROCESS_ID, DISAGG_PROCESS_ID) for
non-empty before calling kill, and invoke kill only with the subset of PIDs that
are present (or skip if none). Update the script around the pgrep assignments
and the kill line to build a list of non-empty PID variables (or test each with
[ -n "$VAR" ]), then call kill on that list or do nothing if the list is empty;
ensure this logic replaces the unconditional kill -9 $CTX_PROCESS_ID
$GEN_PROCESS_ID $DISAGG_PROCESS_ID.
examples/disaggregated/simpler_example/kill_agg.sh-3-4 (1)

3-4: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle empty PID before force-kill.

On Line 4, this can fail when the process is already stopped. Make the script no-op in that case.

Suggested fix
-export AGG_PROCESS_ID=$(pgrep -f "trtllm-serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --host localhost --port 8000 --config ./agg_config.yaml")
-kill -9 $AGG_PROCESS_ID
+AGG_PROCESS_ID="$(pgrep -f "trtllm-serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --host localhost --port 8000 --config ./agg_config.yaml" || true)"
+[[ -n "${AGG_PROCESS_ID}" ]] && kill -9 ${AGG_PROCESS_ID}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/disaggregated/simpler_example/kill_agg.sh` around lines 3 - 4, The
script currently assigns AGG_PROCESS_ID with pgrep and always runs kill -9
$AGG_PROCESS_ID which will fail if no PID was found; update the script to check
whether AGG_PROCESS_ID is non-empty (e.g., test -n "$AGG_PROCESS_ID" or [[ -n
"$AGG_PROCESS_ID" ]]) before calling kill -9, and only invoke kill when
AGG_PROCESS_ID contains a PID (ensure you quote the variable when used).
examples/disaggregated/simpler_example/output_agg.json-1-4 (1)

1-4: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep this artifact as valid JSON only.

Lines 1-3 make the file invalid JSON, which breaks tooling and parsers expecting a JSON document from output_agg.json.

Suggested fix
-  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
-                                 Dload  Upload   Total   Spent    Left  Speed
-...curl progress output...
 {"id":"cmpl-5cb435186c4542339c3168b176d51b08", ...}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/disaggregated/simpler_example/output_agg.json` around lines 1 - 4,
The file output_agg.json contains non-JSON progress lines before the JSON object
which break parsers; remove the leading curl/progress text lines (the three
lines starting with "% Total" and the two progress rows) so the file begins
directly with the JSON object starting with {"id":...}; ensure no other stray
characters precede or follow the JSON and that the remaining content is a single
well-formed JSON document.
examples/disaggregated/simpler_example/run.sh-6-10 (1)

6-10: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard process termination when no matching server is running.

Lines 6-10 unconditionally call kill -9 with possibly empty PID vars. This is brittle and can fail depending on how the script is invoked.

Suggested fix
-export CTX_PROCESS_ID=$(pgrep -f "trtllm-serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --host localhost --port 8001 --config ./ctx_config.yaml")
-export GEN_PROCESS_ID=$(pgrep -f "trtllm-serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --host localhost --port 8002 --config ./gen_config.yaml")
-export DISAGG_PROCESS_ID=$(pgrep -f "trtllm-serve disaggregated -c ./disagg_config.yaml")
+CTX_PROCESS_ID=$(pgrep -f "trtllm-serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --host localhost --port 8001 --config ./ctx_config.yaml" || true)
+GEN_PROCESS_ID=$(pgrep -f "trtllm-serve TinyLlama/TinyLlama-1.1B-Chat-v1.0 --host localhost --port 8002 --config ./gen_config.yaml" || true)
+DISAGG_PROCESS_ID=$(pgrep -f "trtllm-serve disaggregated -c ./disagg_config.yaml" || true)
 
-kill -9 $CTX_PROCESS_ID $GEN_PROCESS_ID $DISAGG_PROCESS_ID
+if [ -n "${CTX_PROCESS_ID}" ] || [ -n "${GEN_PROCESS_ID}" ] || [ -n "${DISAGG_PROCESS_ID}" ]; then
+    kill -9 ${CTX_PROCESS_ID} ${GEN_PROCESS_ID} ${DISAGG_PROCESS_ID}
+fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/disaggregated/simpler_example/run.sh` around lines 6 - 10, The
script unconditionally runs kill -9 on variables CTX_PROCESS_ID, GEN_PROCESS_ID,
DISAGG_PROCESS_ID which may be empty; update the shutdown logic to check each
PID variable (CTX_PROCESS_ID, GEN_PROCESS_ID, DISAGG_PROCESS_ID) is non-empty
(and optionally verify the PID is live) before calling kill, e.g. guard each
kill with a conditional or loop over the three variables and only invoke kill
for present PIDs, quoting variables to avoid word-splitting and handling
multiple PIDs safely.
implementation_plan.md-17-17 (1)

17-17: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix typo in a key implementation step (demensiondimension).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@implementation_plan.md` at line 17, Fix the typo "demension" → "dimension" in
the implementation plan and update the code so beam_width is made accessible in
_create_kv_slice and passed into get_block_ids and get_batch_cache_indices;
remove any logic that flattens the beam dimension and delete the assertion that
beam dimension == 1 in get_batch_cache_indices; update indexing in
get_batch_cache_indices (and any related block index handling) to treat
beam_width as an extra dimension in the block indices tensor so the functions
correctly handle beam_width > 1.
tensorrt_llm/_torch/pyexecutor/py_executor.py-3594-3601 (1)

3594-3601: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the Flake8 indentation error in _debug_request_tokens.

Line 3601 currently trips E126, so this helper will fail lint as written.

Suggested fix
     `@staticmethod`
     def _debug_request_tokens(req, beam_width, max_tokens=16):
-        return [{
-            "beam": beam,
-            "num_tokens": len(tokens),
-            "tail": tokens[-max_tokens:],
-        } for beam in range(beam_width)
-                for tokens in [list(req.get_tokens(beam))]]
+        return [
+            {
+                "beam": beam,
+                "num_tokens": len(tokens),
+                "tail": tokens[-max_tokens:],
+            }
+            for beam in range(beam_width)
+            for tokens in [list(req.get_tokens(beam))]
+        ]
As per coding guidelines `Python code should be indented with 4 spaces; do not use tabs`.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/pyexecutor/py_executor.py` around lines 3594 - 3601, The
list comprehension in _debug_request_tokens is mis-indented and triggers Flake8
E126; fix it by reformatting the comprehension so the continuation lines use
4-space indentation and align logically with the opening bracket — ensure the
inner "for tokens in [list(req.get_tokens(beam))]" and the "for beam in
range(beam_width)" parts are placed on their own properly indented lines under
the opening "[" within the _debug_request_tokens staticmethod to satisfy
PEP8/Flake8.
tensorrt_llm/_torch/pyexecutor/resource_manager.py-1215-1274 (1)

1215-1274: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make both zip() calls strict.

These loops assume a 1:1 mapping between request_ids, result, and the shaped result. Without strict=True, a binding-side length mismatch truncates silently and the logged layout no longer matches the returned data.

Suggested fix
-        for req_id, req_blocks in zip(request_ids, result):
+        for req_id, req_blocks in zip(request_ids, result, strict=True):
@@
-        for req_id, shaped_blocks in zip(request_ids, result):
+        for req_id, shaped_blocks in zip(request_ids, result, strict=True):
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/pyexecutor/resource_manager.py` around lines 1215 - 1274,
The two loops using zip(request_ids, result) in get_batch_cache_indices should
require equal lengths to avoid silent truncation; update both occurrences (the
first loop starting with "for req_id, req_blocks in zip(request_ids, result):"
and the later loop "for req_id, shaped_blocks in zip(request_ids, result):") to
use zip(request_ids, result, strict=True) so a length mismatch raises an error
and the logged token_layout/shaped_layout stay consistent with returned data.
tensorrt_llm/_torch/disaggregation/native/transfer.py-728-748 (1)

728-748: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace transfer-metadata asserts with explicit exceptions in _build_kv_write_meta()
The asserts guarding src_beam_block_ids.size/dst_beam_block_ids.size and the SWA task._prompt_len is not None check protect src_start/dst_start computation and _align_kv_blocks() slicing before pointer extraction; replace them with ValueError/RuntimeError so failures remain deterministic even if Python is run with assertions disabled.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/disaggregation/native/transfer.py` around lines 728 -
748, In _build_kv_write_meta(), replace the runtime assertions that guard
src_beam_block_ids.size and dst_beam_block_ids.size and the SWA prompt-length
check (currently using assert on task._prompt_len) with explicit exceptions:
raise ValueError with clear messages when src_beam_block_ids.size or
dst_beam_block_ids.size exceed total_blocks, and raise RuntimeError (or
ValueError) when task._prompt_len is None; keep the same diagnostic text
(including beam_idx, slice_end, tpb) and ensure these checks occur before
computing src_start/dst_start and before calling _align_kv_blocks() so failures
remain deterministic even when Python assertions are disabled.
🧹 Nitpick comments (1)
tensorrt_llm/_torch/pyexecutor/resource_manager.py (1)

1196-1201: ⚡ Quick win

Fix the return type for the beam-aware shape.

When beam_width > 1, this returns per-request per-beam block ID lists, not List[List[int]]. The current signature makes stale single-beam call sites look type-safe even when they are not. Please widen the return type or add overloads keyed on beam_width. As per coding guidelines, "Use @overload in Python when a return type depends on input type; alternatively use TypeVar if return type can be expressed using input type".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/pyexecutor/resource_manager.py` around lines 1196 - 1201,
The return type of get_batch_cache_indices is incorrect for beam_width > 1 — it
currently declares List[List[int]] but actually returns per-request per-beam
lists (i.e., List[List[List[int]]]). Update the signature to reflect both shapes
by adding `@overload` definitions: one overload for beam_width: int = 1 returning
List[List[int]] and another for beam_width: int > 1 returning
List[List[List[int]]>, or alternatively use a TypeVar/Union to express the
conditional return type; change the concrete implementation signature to a
widened return type (e.g., Union[List[List[int]], List[List[List[int]]]] or
List[Any]) while keeping the overloads for callers and type checkers; adjust any
callers if necessary to handle the beam-aware shape.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@examples/disaggregated/simpler_example/log_disagg`:
- Line 5: The committed runtime log file log_disagg contains sensitive local
environment details (local filesystem paths and internal endpoints/IPs); remove
this artifact from the commit or sanitize it by stripping or replacing
filesystem paths and any endpoint/IP addresses with generic placeholders (e.g.,
[REDACTED_PATH], [REDACTED_ENDPOINT]) and ensure no other runtime logs remain in
the file, then add log_disagg (or the logs directory) to .gitignore to prevent
future commits.

In `@examples/disaggregated/simpler_example/output.json`:
- Around line 1-4: The output.json file contains curl progress text mixed into
the JSON payload (curl progress lines injected into the JSON body), making it
invalid JSON; re-run the export/generation step using silent curl (use the
--silent/-s flag) or redirect curl's stderr to a separate file so only the raw
JSON response is written to output.json, then replace the file with the clean
JSON body and commit only that clean JSON; locate where the pipeline or script
writes to output.json (the command invoking curl) and change it to silent output
or separate stderr so no progress is embedded.
- Around line 3-4: The checked-in sample output exposes an internal endpoint
string in the JSON field disaggregated_params.ctx_info_endpoint; locate all
occurrences of "ctx_info_endpoint" in
examples/disaggregated/simpler_example/output.json and replace the actual
IP:port value (e.g. "tcp://10.176.16.44:40153") with a safe placeholder like
"tcp://<HOST>:<PORT>" or "REDACTED" so the artifact no longer leaks internal
topology details, ensuring every disaggregated_params.ctx_info_endpoint entry is
updated consistently.

In `@examples/disaggregated/simpler_example/parse_output.sh`:
- Around line 6-8: The Perl regex in the parse_output.sh one-liner is brittle
for JSON; replace the Perl extraction with a direct jq query that reads
output.json and extracts .choices[].text (e.g., use jq to pull .choices[].text,
then normalize newlines with gsub("[\r\n]+"; " ") and write to output.txt) so
the script uses jq end-to-end rather than the Perl regex.

In `@examples/disaggregated/simpler_example/run_agg.sh`:
- Around line 24-26: The health-check loop using curl against
"http://${HOST}:${PORT}/health" can hang forever; add a timeout by introducing a
deadline or max-wait variable (e.g., HEALTH_TIMEOUT or MAX_WAIT_SECS) and track
start time (or retry count) before entering the while loop that checks the curl
HTTP code, break out and exit non‑zero if the timeout is reached; update the
loop that references HOST and PORT so it fails fast with an error message and
non‑zero exit when the deadline expires.

In `@examples/disaggregated/simpler_example/run.sh`:
- Around line 33-35: The readiness loop in run.sh that polls
"http://localhost:8000/health" can hang indefinitely; modify the while loop that
currently checks curl's HTTP code to include a timeout mechanism (e.g., set a
MAX_WAIT_SECONDS variable, capture start time or decrement a counter each
iteration), break and exit non‑zero with a clear error message if the server
doesn't become healthy before timeout, and optionally print elapsed time or last
status before exiting so CI/automation can fail fast.

In `@implementation_plan.md`:
- Around line 39-40: The transfer pipeline is currently incorrect for beam_width
> 1 (Sender._build_kv_write_meta, _align_kv_blocks,
RecvReqInfo.to_bytes/from_bytes use block_ids_per_layer_groups as 1-D suffixes),
so either complete the sender/receiver metadata changes or add a hard runtime
guard; to fix quickly, add a clear runtime check at the request
construction/entry point (and mirror it in Sender._build_kv_write_meta and
RecvReqInfo construction) that rejects beam_width > 1 with a descriptive
error/exception (e.g., "beam_width > 1 not supported for KV transfer metadata
yet"), and ensure callers fail fast rather than proceeding into _align_kv_blocks
or RecvReqInfo.to_bytes/from_bytes; alternatively, if you implement full
support, update the src_start/dst_start math in Sender._build_kv_write_meta and
append per-beam tail block IDs on the destination side or move per-beam tails to
a dedicated channel and update RecvReqInfo.to_bytes/from_bytes to encode/decode
that format.

In `@tensorrt_llm/_torch/disaggregation/native/transfer.py`:
- Around line 64-69: The function _block_ids_debug_summary currently
materializes full block-id arrays via arr.tolist(), causing heavy allocations
and log spam; change the returned dict to include only metadata (e.g., "shape":
tuple(arr.shape) and "count": arr.size or len(arr)) and remove the "block_ids"
full dump, and if a full block-id list is still needed gate that materialization
behind an explicit debug-level check (e.g., only call arr.tolist() when
logger.isEnabledFor(logging.DEBUG) or when a debug flag is passed into
_block_ids_debug_summary). Apply the same change to the other similar debug
summary blocks mentioned (the sections around the second block, the large
transfer loop, and the later summary at 1421-1427), replacing full tolist()
dumps with counts/shapes and only producing full lists under the debug guard.

In `@tensorrt_llm/_torch/disaggregation/transceiver.py`:
- Line 160: The info-level logs in _create_kv_slice (e.g., the logger.info that
prints py_request_id and the places that call block_ids.tolist()) are
materializing potentially large block_ids arrays on the hot path; change these
to a lower level (debug/trace) and guard the tolist() calls behind a level check
so the array is only converted when that level is enabled (e.g., use
logger.isEnabledFor(logging.DEBUG) before calling block_ids.tolist()); apply the
same change for all similar logging sites in _create_kv_slice (the blocks around
the other info calls referenced in the comment, which reference block_ids and
req.py_request_id).

In `@tensorrt_llm/_torch/pyexecutor/py_executor.py`:
- Around line 3571-3580: The info-level log in py_executor.py that prints
request IDs, token tails, draft tokens and cumulative log-probs (the logger.info
call that includes req.py_request_id, beam_width, first_gen_tokens, getattr(...
'first_gen_cum_log_probs'), req.py_draft_tokens and self._debug_request_tokens)
should be removed or demoted to debug/trace only; update that logger.info to
logger.debug (or remove the sensitive fields) and ensure similar prints at the
other transfer-complete sites (the nearby logger calls around the other blocks
you noted at the other two locations) are changed consistently so token/score
dumps are not emitted at info level. Ensure the change affects the
methods/blocks using self._debug_request_tokens and the getattr(...,
'first_gen_cum_log_probs') extraction.

In `@tensorrt_llm/_torch/pyexecutor/sampler.py`:
- Around line 2886-2896: The logger.info call in
TorchSampler._prepare_beam_search that dumps beam_search_store, seq_slots_long
and related buffers should be removed (or moved to after the buffers are fully
initialized) because it can leak uninitialized or stale data; locate the
logger.info block that references _debug_tensor_slice(seq_slots_long),
beam_search_store.cum_log_probs, beam_search_store.cache_indirection,
cache_indirection_buffer, and beam_search_store.predecessor_beams and delete
that pre-reset dump so no beam-store buffers are logged before they are
reset/initialized.
- Around line 119-197: The debug helpers (_debug_tensor_slice,
_debug_new_tokens_host, _debug_cache_indirection_prefix,
_debug_batch_next_tokens) eagerly detach/copy tensors and even perform
per-request tensor indexing inside loops; gate or rewrite them so they do not
cause D2H on the hot path. Fix by either short-circuiting when debug is disabled
(return a lightweight placeholder) or by converting whole batched tensors once
to host Python lists up-front (use tensor.detach().cpu().tolist() or
tensor.tolist() once outside any per-request loop), then iterate over those
lists (handle prefix_lens being int vs tensor by converting to a list similarly)
– remove per-iteration .detach()/cpu()/indexing and per-request
tensor.index_select usage in _debug_cache_indirection_prefix and
_debug_new_tokens_host, and ensure _debug_tensor_slice and
_debug_batch_next_tokens only materialize when explicitly enabled.
- Around line 3331-3343: The info-level logging in
TorchSampler._add_metadata_to_grouped_requests exposes sensitive request/token
state; change the logger.info call to debug-level (logger.debug) and avoid
printing raw token/cached state—either redact actual token/log-prob values
(replace content from _debug_tensor_slice and _debug_cache_indirection_prefix
with shapes/lengths or "<redacted>") or log only non-sensitive summaries (e.g.,
tensor shapes, seq lengths, and counts). Also wrap the debug emission with a
debug-enabled check (logger.isEnabledFor(logging.DEBUG)) if expensive to
compute. Apply the same change for the similar logging blocks referenced (the
logger calls around the other ranges that call
_debug_tensor_slice/_debug_cache_indirection_prefix and metadata fields such as
metadata.seq_slots, metadata.seq_lens, metadata.cum_log_probs,
metadata.cache_indirection, metadata.predecessor_beams,
metadata.finished_beams).

In `@tensorrt_llm/executor/result.py`:
- Around line 521-527: The code currently builds first_gen_cum_log_probs by
filtering out None values from self._outputs, which can compress and misalign
beam indices; instead, in the block that sets
self._disaggregated_params.first_gen_cum_log_probs (using self._outputs and
self._disaggregated_params), only assign a list of cumulative_logprob values
when every out in self._outputs has a non-None cumulative_logprob and the
resulting list length equals the number of beams (otherwise leave
first_gen_cum_log_probs unset/None); locate the creation in the method
referencing self._outputs and replace the filtered-comprehension logic with a
check for any None (or compare lengths) before mapping to a list of
out.cumulative_logprob and assigning it to
self._disaggregated_params.first_gen_cum_log_probs.

---

Outside diff comments:
In `@tensorrt_llm/serve/openai_disagg_service.py`:
- Around line 343-376: The per-request logger.info calls in _get_gen_request
that log disagg_request_id, ctx_info_endpoint and beam/request metadata should
not run at INFO level on the hot path; change them to be guarded
debug/feature-flag logs. Replace the two logger.info invocations with either
logger.debug(...) or wrap them in an if logger.isEnabledFor(logging.DEBUG):
block (or check a feature flag like self._verbose_logging) so that the messages
from logger.info(...) in _get_gen_request (and any logging of
request.disaggregated_params.ctx_info_endpoint, ctx_response.choices,
CompletionRequest/ChatCompletionRequest prompt token fields, and
DisaggregatedParams creation) are only emitted when debug/verbose logging is
enabled.
- Around line 532-559: The code currently drops all but choices[0] even when
ctx_response.choices has multiple entries; update the flow to handle
multi-choice context responses instead of reducing to the first choice: in the
validation routine (where you currently index into choice =
ctx_response.choices[0]) iterate over ctx_response.choices and validate each
choice.disaggregated_params, ctx_request_id and disagg_request_id (raising with
contextual finish_reason and disagg/ctx ids for that specific choice if
invalid), and then either (A) return the full ctx_response with all validated
choices or (B) change the downstream callsites (_verify_ctx_response, _need_gen,
_get_gen_request) to accept and process a list of choices (e.g., generate
per-choice gen requests) so no disaggregation state or finish_reason is silently
ignored. Ensure all places that previously assumed a single choice are updated
to consume the list or handle branching per choice.

---

Minor comments:
In `@examples/disaggregated/simpler_example/kill_agg.sh`:
- Around line 3-4: The script currently assigns AGG_PROCESS_ID with pgrep and
always runs kill -9 $AGG_PROCESS_ID which will fail if no PID was found; update
the script to check whether AGG_PROCESS_ID is non-empty (e.g., test -n
"$AGG_PROCESS_ID" or [[ -n "$AGG_PROCESS_ID" ]]) before calling kill -9, and
only invoke kill when AGG_PROCESS_ID contains a PID (ensure you quote the
variable when used).

In `@examples/disaggregated/simpler_example/kill.sh`:
- Around line 3-7: The kill -9 invocation should be guarded so it only runs for
PIDs that exist: check each captured variable (CTX_PROCESS_ID, GEN_PROCESS_ID,
DISAGG_PROCESS_ID) for non-empty before calling kill, and invoke kill only with
the subset of PIDs that are present (or skip if none). Update the script around
the pgrep assignments and the kill line to build a list of non-empty PID
variables (or test each with [ -n "$VAR" ]), then call kill on that list or do
nothing if the list is empty; ensure this logic replaces the unconditional kill
-9 $CTX_PROCESS_ID $GEN_PROCESS_ID $DISAGG_PROCESS_ID.

In `@examples/disaggregated/simpler_example/output_agg.json`:
- Around line 1-4: The file output_agg.json contains non-JSON progress lines
before the JSON object which break parsers; remove the leading curl/progress
text lines (the three lines starting with "% Total" and the two progress rows)
so the file begins directly with the JSON object starting with {"id":...};
ensure no other stray characters precede or follow the JSON and that the
remaining content is a single well-formed JSON document.

In `@examples/disaggregated/simpler_example/run.sh`:
- Around line 6-10: The script unconditionally runs kill -9 on variables
CTX_PROCESS_ID, GEN_PROCESS_ID, DISAGG_PROCESS_ID which may be empty; update the
shutdown logic to check each PID variable (CTX_PROCESS_ID, GEN_PROCESS_ID,
DISAGG_PROCESS_ID) is non-empty (and optionally verify the PID is live) before
calling kill, e.g. guard each kill with a conditional or loop over the three
variables and only invoke kill for present PIDs, quoting variables to avoid
word-splitting and handling multiple PIDs safely.

In `@implementation_plan.md`:
- Line 17: Fix the typo "demension" → "dimension" in the implementation plan and
update the code so beam_width is made accessible in _create_kv_slice and passed
into get_block_ids and get_batch_cache_indices; remove any logic that flattens
the beam dimension and delete the assertion that beam dimension == 1 in
get_batch_cache_indices; update indexing in get_batch_cache_indices (and any
related block index handling) to treat beam_width as an extra dimension in the
block indices tensor so the functions correctly handle beam_width > 1.

In `@tensorrt_llm/_torch/disaggregation/native/transfer.py`:
- Around line 728-748: In _build_kv_write_meta(), replace the runtime assertions
that guard src_beam_block_ids.size and dst_beam_block_ids.size and the SWA
prompt-length check (currently using assert on task._prompt_len) with explicit
exceptions: raise ValueError with clear messages when src_beam_block_ids.size or
dst_beam_block_ids.size exceed total_blocks, and raise RuntimeError (or
ValueError) when task._prompt_len is None; keep the same diagnostic text
(including beam_idx, slice_end, tpb) and ensure these checks occur before
computing src_start/dst_start and before calling _align_kv_blocks() so failures
remain deterministic even when Python assertions are disabled.

In `@tensorrt_llm/_torch/pyexecutor/py_executor.py`:
- Around line 3594-3601: The list comprehension in _debug_request_tokens is
mis-indented and triggers Flake8 E126; fix it by reformatting the comprehension
so the continuation lines use 4-space indentation and align logically with the
opening bracket — ensure the inner "for tokens in [list(req.get_tokens(beam))]"
and the "for beam in range(beam_width)" parts are placed on their own properly
indented lines under the opening "[" within the _debug_request_tokens
staticmethod to satisfy PEP8/Flake8.

In `@tensorrt_llm/_torch/pyexecutor/resource_manager.py`:
- Around line 1215-1274: The two loops using zip(request_ids, result) in
get_batch_cache_indices should require equal lengths to avoid silent truncation;
update both occurrences (the first loop starting with "for req_id, req_blocks in
zip(request_ids, result):" and the later loop "for req_id, shaped_blocks in
zip(request_ids, result):") to use zip(request_ids, result, strict=True) so a
length mismatch raises an error and the logged token_layout/shaped_layout stay
consistent with returned data.

---

Nitpick comments:
In `@tensorrt_llm/_torch/pyexecutor/resource_manager.py`:
- Around line 1196-1201: The return type of get_batch_cache_indices is incorrect
for beam_width > 1 — it currently declares List[List[int]] but actually returns
per-request per-beam lists (i.e., List[List[List[int]]]). Update the signature
to reflect both shapes by adding `@overload` definitions: one overload for
beam_width: int = 1 returning List[List[int]] and another for beam_width: int >
1 returning List[List[List[int]]>, or alternatively use a TypeVar/Union to
express the conditional return type; change the concrete implementation
signature to a widened return type (e.g., Union[List[List[int]],
List[List[List[int]]]] or List[Any]) while keeping the overloads for callers and
type checkers; adjust any callers if necessary to handle the beam-aware shape.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b15de632-a9d3-42d9-97cc-409c44b0cbb2

📥 Commits

Reviewing files that changed from the base of the PR and between fac947c and f1b29bd.

📒 Files selected for processing (31)
  • cpp/tensorrt_llm/batch_manager/cacheFormatter.cpp
  • examples/disaggregated/simpler_example/agg_config.yaml
  • examples/disaggregated/simpler_example/ctx_config.yaml
  • examples/disaggregated/simpler_example/disagg_config.yaml
  • examples/disaggregated/simpler_example/gen_config.yaml
  • examples/disaggregated/simpler_example/kill.sh
  • examples/disaggregated/simpler_example/kill_agg.sh
  • examples/disaggregated/simpler_example/log_agg
  • examples/disaggregated/simpler_example/log_ctx_0
  • examples/disaggregated/simpler_example/log_disagg
  • examples/disaggregated/simpler_example/log_gen_0
  • examples/disaggregated/simpler_example/output.json
  • examples/disaggregated/simpler_example/output.txt
  • examples/disaggregated/simpler_example/output_agg.json
  • examples/disaggregated/simpler_example/parse_output.sh
  • examples/disaggregated/simpler_example/run.sh
  • examples/disaggregated/simpler_example/run_agg.sh
  • implementation_notes.md
  • implementation_plan.md
  • tensorrt_llm/_torch/disaggregation/base/transfer.py
  • tensorrt_llm/_torch/disaggregation/native/transfer.py
  • tensorrt_llm/_torch/disaggregation/resource/cache_reuse.py
  • tensorrt_llm/_torch/disaggregation/transceiver.py
  • tensorrt_llm/_torch/pyexecutor/llm_request.py
  • tensorrt_llm/_torch/pyexecutor/py_executor.py
  • tensorrt_llm/_torch/pyexecutor/resource_manager.py
  • tensorrt_llm/_torch/pyexecutor/sampler.py
  • tensorrt_llm/disaggregated_params.py
  • tensorrt_llm/executor/result.py
  • tensorrt_llm/serve/openai_disagg_service.py
  • tensorrt_llm/serve/openai_protocol.py

/usr/local/lib/python3.12/dist-packages/requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (6.0.0.post1)/charset_normalizer (3.4.4) doesn't match a supported version!
warnings.warn(
Multiple distributions found for package modelopt. Picked distribution: nvidia-modelopt
/home/scratch.athenac_coreai/pyuser/lib/python3.12/site-packages/modelopt/torch/__init__.py:36: UserWarning: transformers version 5.3.0 is incompatible with nvidia-modelopt and may cause issues. Please install recommended version with `pip install nvidia-modelopt[hf]` if working with HF models.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not commit raw runtime logs with environment details.

This file exposes local paths and internal endpoint/IP information (for example on Lines 5 and 40-42). Please remove this artifact from source control or sanitize it before committing.

Also applies to: 40-42

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/disaggregated/simpler_example/log_disagg` at line 5, The committed
runtime log file log_disagg contains sensitive local environment details (local
filesystem paths and internal endpoints/IPs); remove this artifact from the
commit or sanitize it by stripping or replacing filesystem paths and any
endpoint/IP addresses with generic placeholders (e.g., [REDACTED_PATH],
[REDACTED_ENDPOINT]) and ensure no other runtime logs remain in the file, then
add log_disagg (or the logs directory) to .gitignore to prevent future commits.

Comment on lines +1 to +4
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0100 219 0 0 100 219 0 182 0:00:01 0:00:01 --:--:-- 182100 219 0 0 100 219 0 99 0:00:02 0:00:02 --:--:-- 99100 219 0 0 100 219 0 68 0:00:03 0:00:03 --:--:-- 68{"id":"cmpl-103ca22caad247b789c73fccd5424a97","object":"text_completion","created":1779472663,"model":"TinyLlama/TinyLlama-1.1B-Chat-v1.0","choices":[{"index":0,"text":"their products are used in so many different industries. For example, NVIDIA's GPUs are used in the gaming industry, where they are used to create high-quality graphics for video games. NVIDIA's GPUs are also used in the automotive industry, where they are used to create high-performance engines. NVIDIA's GPUs are also used in the medical industry, where they are used to create high-quality medical imaging equipment. NVIDIA's GPUs are also used in the entertainment industry, where they are used to create high-quality visual effects for movies and TV shows. Overall, NVIDIA's products are used in a wide range of industries, and their products are used in many different applications.","token_ids":null,"logprobs":null,"context_logits":null,"finish_reason":"stop","stop_reason":null,"disaggregated_params":{"request_type":"generation_only","first_gen_tokens":[896,310,372,405],"first_gen_log_probs":null,"first_gen_cum_log_probs":[-0.8538165092468262,-1.5413165092468262,-1.6663165092468262,-3.791316509246826],"first_gen_logits":null,"ctx_request_id":15280142166110208,"encoded_opaque_state":null,"draft_tokens":null,"disagg_request_id":15280142166110208,"ctx_dp_rank":0,"ctx_info_endpoint":"tcp://10.176.16.44:40153","schedule_style":0,"conversation_id":null},"avg_decoded_tokens_per_iter":1.0},{"index":1,"text":"their products are used in so many different industries. For example, NVIDIA's GPUs are used in the gaming industry, where they are used to create high-quality graphics for video games. NVIDIA's GPUs are also used in the automotive industry, where they are used to create high-performance engines. NVIDIA's GPUs are also used in the medical industry, where they are used to create high-quality medical imaging equipment. NVIDIA's GPUs are also used in the entertainment industry, where they are used to create high-quality visual effects for movies and TV shows. Overall, NVIDIA's products are used in a wide variety of industries, and their products are used in many different applications.","token_ids":null,"logprobs":null,"context_logits":null,"finish_reason":"stop","stop_reason":null,"disaggregated_params":{"request_type":"generation_only","first_gen_tokens":[896,310,372,405],"first_gen_log_probs":null,"first_gen_cum_log_probs":[-0.8538165092468262,-1.5413165092468262,-1.6663165092468262,-3.791316509246826],"first_gen_logits":null,"ctx_request_id":15280142166110208,"encoded_opaque_state":null,"draft_tokens":null,"disagg_request_id":15280142166110208,"ctx_dp_rank":0,"ctx_info_endpoint":"tcp://10.176.16.44:40153","schedule_style":0,"conversation_id":null},"avg_decoded_tokens_per_iter":1.0},{"index":2,"text":"their products are used in so many different industries. For example, NVIDIA's GPUs are used in the gaming industry, where they are used to create high-quality graphics for video games. NVIDIA's GPUs are also used in the automotive industry, where they are used to create high-performance engines. NVIDIA's GPUs are also used in the medical industry, where they are used to create high-quality medical imaging equipment. NVIDIA's GPUs are also used in the entertainment industry, where they are used to create high-quality visual effects for movies and TV shows. Overall, NVIDIA's products are used in a wide range of industries, and their products are used in a variety of applications.","token_ids":null,"logprobs":null,"context_logits":null,"finish_reason":"stop","stop_reason":null,"disaggregated_params":{"request_type":"generation_only","first_gen_tokens":[896,310,372,405],"first_gen_log_probs":null,"first_gen_cum_log_probs":[-0.8538165092468262,-1.5413165092468262,-1.6663165092468262,-3.791316509246826],"first_gen_logits":null,"ctx_request_id":15280142166110208,"encoded_opaque_state":null,"draft_tokens":null,"disagg_request_id":15280142166110208,"ctx_dp_rank":0,"ctx_info_endpoint":"tcp://10.176.16.44:40153","schedule_style":0,"conversation_id":null},"avg_decoded_token100 5801 100 5582 100 219 1623 63 0:00:03 0:00:03 --:--:-- 1687
s_per_iter":1.0},{"index":3,"text":"their products are used in so many different industries. For example, NVIDIA's GPUs are used in the gaming industry, where they are used to create high-quality graphics for video games. NVIDIA's GPUs are also used in the automotive industry, where they are used to create high-performance engines. NVIDIA's GPUs are also used in the medical industry, where they are used to create high-quality medical imaging equipment. NVIDIA's GPUs are also used in the entertainment industry, where they are used to create high-quality visual effects for movies and TV shows. Overall, NVIDIA's products are used in a wide range of industries, and their products are used in a variety of different applications.","token_ids":null,"logprobs":null,"context_logits":null,"finish_reason":"stop","stop_reason":null,"disaggregated_params":{"request_type":"generation_only","first_gen_tokens":[896,310,372,405],"first_gen_log_probs":null,"first_gen_cum_log_probs":[-0.8538165092468262,-1.5413165092468262,-1.6663165092468262,-3.791316509246826],"first_gen_logits":null,"ctx_request_id":15280142166110208,"encoded_opaque_state":null,"draft_tokens":null,"disagg_request_id":15280142166110208,"ctx_dp_rank":0,"ctx_info_endpoint":"tcp://10.176.16.44:40153","schedule_style":0,"conversation_id":null},"avg_decoded_tokens_per_iter":1.0}],"usage":{"prompt_tokens":9,"total_tokens":676,"completion_tokens":667,"prompt_tokens_details":{"cached_tokens":0}},"prompt_token_ids":null}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

output.json is malformed and not machine-readable JSON.

curl progress output is mixed into the payload (including an injected progress line inside a JSON field), so this file cannot be parsed as JSON. Please regenerate with silent curl output (or redirect stderr separately) and commit only the JSON body.

🧰 Tools
🪛 Biome (2.4.15)

[error] 1-1: unexpected character %

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: unexpected character %

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: unexpected character %

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 1-1: String values must be double quoted.

(parse)


[error] 2-2: String values must be double quoted.

(parse)


[error] 2-2: String values must be double quoted.

(parse)


[error] 2-2: String values must be double quoted.

(parse)


[error] 2-2: String values must be double quoted.

(parse)


[error] 2-2: String values must be double quoted.

(parse)


[error] 2-2: String values must be double quoted.

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: End of file expected

(parse)

🪛 OpenGrep (1.21.0)

[ERROR] 3-3: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 3-3: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 3-3: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 4-4: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/disaggregated/simpler_example/output.json` around lines 1 - 4, The
output.json file contains curl progress text mixed into the JSON payload (curl
progress lines injected into the JSON body), making it invalid JSON; re-run the
export/generation step using silent curl (use the --silent/-s flag) or redirect
curl's stderr to a separate file so only the raw JSON response is written to
output.json, then replace the file with the clean JSON body and commit only that
clean JSON; locate where the pipeline or script writes to output.json (the
command invoking curl) and change it to silent output or separate stderr so no
progress is embedded.

Comment on lines +3 to +4
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0100 219 0 0 100 219 0 182 0:00:01 0:00:01 --:--:-- 182100 219 0 0 100 219 0 99 0:00:02 0:00:02 --:--:-- 99100 219 0 0 100 219 0 68 0:00:03 0:00:03 --:--:-- 68{"id":"cmpl-103ca22caad247b789c73fccd5424a97","object":"text_completion","created":1779472663,"model":"TinyLlama/TinyLlama-1.1B-Chat-v1.0","choices":[{"index":0,"text":"their products are used in so many different industries. For example, NVIDIA's GPUs are used in the gaming industry, where they are used to create high-quality graphics for video games. NVIDIA's GPUs are also used in the automotive industry, where they are used to create high-performance engines. NVIDIA's GPUs are also used in the medical industry, where they are used to create high-quality medical imaging equipment. NVIDIA's GPUs are also used in the entertainment industry, where they are used to create high-quality visual effects for movies and TV shows. Overall, NVIDIA's products are used in a wide range of industries, and their products are used in many different applications.","token_ids":null,"logprobs":null,"context_logits":null,"finish_reason":"stop","stop_reason":null,"disaggregated_params":{"request_type":"generation_only","first_gen_tokens":[896,310,372,405],"first_gen_log_probs":null,"first_gen_cum_log_probs":[-0.8538165092468262,-1.5413165092468262,-1.6663165092468262,-3.791316509246826],"first_gen_logits":null,"ctx_request_id":15280142166110208,"encoded_opaque_state":null,"draft_tokens":null,"disagg_request_id":15280142166110208,"ctx_dp_rank":0,"ctx_info_endpoint":"tcp://10.176.16.44:40153","schedule_style":0,"conversation_id":null},"avg_decoded_tokens_per_iter":1.0},{"index":1,"text":"their products are used in so many different industries. For example, NVIDIA's GPUs are used in the gaming industry, where they are used to create high-quality graphics for video games. NVIDIA's GPUs are also used in the automotive industry, where they are used to create high-performance engines. NVIDIA's GPUs are also used in the medical industry, where they are used to create high-quality medical imaging equipment. NVIDIA's GPUs are also used in the entertainment industry, where they are used to create high-quality visual effects for movies and TV shows. Overall, NVIDIA's products are used in a wide variety of industries, and their products are used in many different applications.","token_ids":null,"logprobs":null,"context_logits":null,"finish_reason":"stop","stop_reason":null,"disaggregated_params":{"request_type":"generation_only","first_gen_tokens":[896,310,372,405],"first_gen_log_probs":null,"first_gen_cum_log_probs":[-0.8538165092468262,-1.5413165092468262,-1.6663165092468262,-3.791316509246826],"first_gen_logits":null,"ctx_request_id":15280142166110208,"encoded_opaque_state":null,"draft_tokens":null,"disagg_request_id":15280142166110208,"ctx_dp_rank":0,"ctx_info_endpoint":"tcp://10.176.16.44:40153","schedule_style":0,"conversation_id":null},"avg_decoded_tokens_per_iter":1.0},{"index":2,"text":"their products are used in so many different industries. For example, NVIDIA's GPUs are used in the gaming industry, where they are used to create high-quality graphics for video games. NVIDIA's GPUs are also used in the automotive industry, where they are used to create high-performance engines. NVIDIA's GPUs are also used in the medical industry, where they are used to create high-quality medical imaging equipment. NVIDIA's GPUs are also used in the entertainment industry, where they are used to create high-quality visual effects for movies and TV shows. Overall, NVIDIA's products are used in a wide range of industries, and their products are used in a variety of applications.","token_ids":null,"logprobs":null,"context_logits":null,"finish_reason":"stop","stop_reason":null,"disaggregated_params":{"request_type":"generation_only","first_gen_tokens":[896,310,372,405],"first_gen_log_probs":null,"first_gen_cum_log_probs":[-0.8538165092468262,-1.5413165092468262,-1.6663165092468262,-3.791316509246826],"first_gen_logits":null,"ctx_request_id":15280142166110208,"encoded_opaque_state":null,"draft_tokens":null,"disagg_request_id":15280142166110208,"ctx_dp_rank":0,"ctx_info_endpoint":"tcp://10.176.16.44:40153","schedule_style":0,"conversation_id":null},"avg_decoded_token100 5801 100 5582 100 219 1623 63 0:00:03 0:00:03 --:--:-- 1687
s_per_iter":1.0},{"index":3,"text":"their products are used in so many different industries. For example, NVIDIA's GPUs are used in the gaming industry, where they are used to create high-quality graphics for video games. NVIDIA's GPUs are also used in the automotive industry, where they are used to create high-performance engines. NVIDIA's GPUs are also used in the medical industry, where they are used to create high-quality medical imaging equipment. NVIDIA's GPUs are also used in the entertainment industry, where they are used to create high-quality visual effects for movies and TV shows. Overall, NVIDIA's products are used in a wide range of industries, and their products are used in a variety of different applications.","token_ids":null,"logprobs":null,"context_logits":null,"finish_reason":"stop","stop_reason":null,"disaggregated_params":{"request_type":"generation_only","first_gen_tokens":[896,310,372,405],"first_gen_log_probs":null,"first_gen_cum_log_probs":[-0.8538165092468262,-1.5413165092468262,-1.6663165092468262,-3.791316509246826],"first_gen_logits":null,"ctx_request_id":15280142166110208,"encoded_opaque_state":null,"draft_tokens":null,"disagg_request_id":15280142166110208,"ctx_dp_rank":0,"ctx_info_endpoint":"tcp://10.176.16.44:40153","schedule_style":0,"conversation_id":null},"avg_decoded_tokens_per_iter":1.0}],"usage":{"prompt_tokens":9,"total_tokens":676,"completion_tokens":667,"prompt_tokens_details":{"cached_tokens":0}},"prompt_token_ids":null}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Redact internal endpoint details from committed sample output.

ctx_info_endpoint currently exposes an internal IP/port in a checked-in artifact. Please replace with a placeholder value in examples to avoid leaking internal topology details.

🧰 Tools
🪛 Biome (2.4.15)

[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: End of file expected

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: Minus must be followed by a digit

(parse)


[error] 4-4: End of file expected

(parse)

🪛 OpenGrep (1.21.0)

[ERROR] 3-3: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 3-3: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 3-3: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)


[ERROR] 4-4: Possible credit card number (PAN) detected in source code. Credit card numbers should never be hardcoded or stored in source files. Use a secrets manager or tokenization service instead.

(coderabbit.pii.credit-card-number)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/disaggregated/simpler_example/output.json` around lines 3 - 4, The
checked-in sample output exposes an internal endpoint string in the JSON field
disaggregated_params.ctx_info_endpoint; locate all occurrences of
"ctx_info_endpoint" in examples/disaggregated/simpler_example/output.json and
replace the actual IP:port value (e.g. "tcp://10.176.16.44:40153") with a safe
placeholder like "tcp://<HOST>:<PORT>" or "REDACTED" so the artifact no longer
leaks internal topology details, ensuring every
disaggregated_params.ctx_info_endpoint entry is updated consistently.

Comment on lines +6 to +8
perl -0ne 'while (/"text"[[:space:]]*:[[:space:]]*"((?:\\.|[^"\\])*)"/gs) { print "\"$1\"\n"; }' \
"${SCRIPT_DIR}/output.json" \
| jq -r 'gsub("[\r\n]+"; " ")' > "${SCRIPT_DIR}/output.txt" No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid regex parsing for JSON extraction.

On Line 6, Perl regex parsing is brittle for escaped sequences and edge cases. Use jq to extract .choices[].text directly.

Suggested fix
-# extract text of each choice from output.json and output to output.txt
-perl -0ne 'while (/"text"[[:space:]]*:[[:space:]]*"((?:\\.|[^"\\])*)"/gs) { print "\"$1\"\n"; }' \
-    "${SCRIPT_DIR}/output.json" \
-    | jq -r 'gsub("[\r\n]+"; " ")' > "${SCRIPT_DIR}/output.txt"
+# extract text of each choice from output.json and output to output.txt
+jq -r '.choices[].text | gsub("[\r\n]+"; " ")' \
+    "${SCRIPT_DIR}/output.json" > "${SCRIPT_DIR}/output.txt"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
perl -0ne 'while (/"text"[[:space:]]*:[[:space:]]*"((?:\\.|[^"\\])*)"/gs) { print "\"$1\"\n"; }' \
"${SCRIPT_DIR}/output.json" \
| jq -r 'gsub("[\r\n]+"; " ")' > "${SCRIPT_DIR}/output.txt"
# extract text of each choice from output.json and output to output.txt
jq -r '.choices[].text | gsub("[\r\n]+"; " ")' \
"${SCRIPT_DIR}/output.json" > "${SCRIPT_DIR}/output.txt"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/disaggregated/simpler_example/parse_output.sh` around lines 6 - 8,
The Perl regex in the parse_output.sh one-liner is brittle for JSON; replace the
Perl extraction with a direct jq query that reads output.json and extracts
.choices[].text (e.g., use jq to pull .choices[].text, then normalize newlines
with gsub("[\r\n]+"; " ") and write to output.txt) so the script uses jq
end-to-end rather than the Perl regex.

Comment on lines +24 to +26
while [ $(curl -s -o /dev/null -w "%{http_code}" "http://${HOST}:${PORT}/health") -ne 200 ]; do
sleep 1
done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a timeout to the health-check loop.

Line 24 can wait forever when startup fails, which makes this script hang indefinitely.

Suggested fix
-while [ $(curl -s -o /dev/null -w "%{http_code}" "http://${HOST}:${PORT}/health") -ne 200 ]; do
-    sleep 1
-done
+MAX_RETRIES=180
+retries=0
+while [ "$(curl -s -o /dev/null -w "%{http_code}" "http://${HOST}:${PORT}/health")" -ne 200 ]; do
+    retries=$((retries + 1))
+    if [ "$retries" -ge "$MAX_RETRIES" ]; then
+        echo "Aggregate server did not become ready in time" >&2
+        exit 1
+    fi
+    sleep 1
+done
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
while [ $(curl -s -o /dev/null -w "%{http_code}" "http://${HOST}:${PORT}/health") -ne 200 ]; do
sleep 1
done
MAX_RETRIES=180
retries=0
while [ "$(curl -s -o /dev/null -w "%{http_code}" "http://${HOST}:${PORT}/health")" -ne 200 ]; do
retries=$((retries + 1))
if [ "$retries" -ge "$MAX_RETRIES" ]; then
echo "Aggregate server did not become ready in time" >&2
exit 1
fi
sleep 1
done
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 24-24: Quote this to prevent word splitting.

(SC2046)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/disaggregated/simpler_example/run_agg.sh` around lines 24 - 26, The
health-check loop using curl against "http://${HOST}:${PORT}/health" can hang
forever; add a timeout by introducing a deadline or max-wait variable (e.g.,
HEALTH_TIMEOUT or MAX_WAIT_SECS) and track start time (or retry count) before
entering the while loop that checks the curl HTTP code, break out and exit
non‑zero if the timeout is reached; update the loop that references HOST and
PORT so it fails fast with an error message and non‑zero exit when the deadline
expires.

Comment on lines +3571 to +3580
logger.info(
"disagg generation transfer complete: "
f"request_id={req.py_request_id} beam_width={beam_width} "
f"first_gen_tokens={first_gen_tokens} "
f"first_gen_cum_log_probs="
f"{getattr(getattr(req, 'py_disaggregated_params', None), 'first_gen_cum_log_probs', None)} "
f"draft_tokens={req.py_draft_tokens} "
f"ctx_request_id={req.context_phase_params.req_id} "
f"tokens_before="
f"{self._debug_request_tokens(req, beam_width)}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Drop the info-level token and score dumps from this transfer-complete path.

This emits request IDs, token tails, draft tokens, and cumulative log probs for every completed disaggregated generation transfer. In a hot path that is both a throughput risk and a sensitive-data leak; please gate it behind a debug/trace-only path or remove it before merge.

Also applies to: 3585-3590, 3647-3650

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/pyexecutor/py_executor.py` around lines 3571 - 3580, The
info-level log in py_executor.py that prints request IDs, token tails, draft
tokens and cumulative log-probs (the logger.info call that includes
req.py_request_id, beam_width, first_gen_tokens, getattr(...
'first_gen_cum_log_probs'), req.py_draft_tokens and self._debug_request_tokens)
should be removed or demoted to debug/trace only; update that logger.info to
logger.debug (or remove the sensitive fields) and ensure similar prints at the
other transfer-complete sites (the nearby logger calls around the other blocks
you noted at the other two locations) are changed consistently so token/score
dumps are not emitted at info level. Ensure the change affects the
methods/blocks using self._debug_request_tokens and the getattr(...,
'first_gen_cum_log_probs') extraction.

Comment on lines +119 to +197
def _debug_tensor_slice(
tensor: torch.Tensor,
indices: torch.Tensor | None = None,
dim: int = 0,
):
try:
view = (
tensor.index_select(dim, indices.to(tensor.device).long())
if indices is not None
else tensor
)
return view.detach().cpu().tolist()
except (RuntimeError, TypeError, ValueError) as err:
return f"<unavailable: {err}>"


def _debug_new_tokens_host(
new_tokens_host: torch.Tensor,
seq_slots: torch.Tensor,
req_num_generated_tokens: torch.Tensor,
):
try:
new_tokens = new_tokens_host.tolist()
seq_slots_host = seq_slots.detach().cpu().tolist()
req_num_generated_tokens_host = req_num_generated_tokens.detach().cpu().tolist()
return [
{
"seq_slot": seq_slot,
"tokens": [
new_tokens[step][seq_slot]
for step in range(req_num_generated_tokens_host[req_idx])
],
}
for req_idx, seq_slot in enumerate(seq_slots_host)
]
except (RuntimeError, TypeError, ValueError, IndexError) as err:
return f"<unavailable: {err}>"


def _debug_cache_indirection_prefix(
cache_indirection: torch.Tensor,
seq_slots: torch.Tensor,
prefix_lens: torch.Tensor | int,
max_positions: int = 16,
):
try:
seq_slots_host = seq_slots.detach().cpu().tolist()
if isinstance(prefix_lens, int):
prefix_lens_host = [prefix_lens] * len(seq_slots_host)
else:
prefix_lens_host = prefix_lens.detach().cpu().tolist()

result = []
for req_idx, seq_slot in enumerate(seq_slots_host):
prefix_len = int(prefix_lens_host[req_idx])
start = max(0, prefix_len - max_positions)
values = cache_indirection[
seq_slot, :, start:prefix_len
].detach().cpu().tolist()
result.append({
"seq_slot": seq_slot,
"prefix_len": prefix_len,
"shown_range": [start, prefix_len],
"values": values,
})
return result
except (RuntimeError, TypeError, ValueError, IndexError) as err:
return f"<unavailable: {err}>"


def _debug_batch_next_tokens(
batch_next_tokens: torch.Tensor,
batch_req_indices: torch.Tensor,
):
try:
valid_rows = batch_req_indices.numel()
return batch_next_tokens[:valid_rows].detach().cpu().tolist()
except (RuntimeError, TypeError, ValueError, IndexError) as err:
return f"<unavailable: {err}>"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Gate or remove the debug tensor snapshot helpers.

These helpers do eager detach().cpu().tolist() materialization, and _debug_cache_indirection_prefix() additionally walks device-backed data inside a per-request loop. Since the call sites build f-strings unconditionally, beam-search decode now pays those D2H sync/copy costs on every iteration. That is too expensive for this hot path.

Based on learnings: In files under tensorrt_llm/_torch/pyexecutor, avoid accessing torch.Tensor objects inside for-loops when iterating over requests. Convert batched tensors to Python lists beforehand using tensor.tolist(), and then iterate over those lists. This improves performance by reducing tensor-bound operations inside hot loops.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/pyexecutor/sampler.py` around lines 119 - 197, The debug
helpers (_debug_tensor_slice, _debug_new_tokens_host,
_debug_cache_indirection_prefix, _debug_batch_next_tokens) eagerly detach/copy
tensors and even perform per-request tensor indexing inside loops; gate or
rewrite them so they do not cause D2H on the hot path. Fix by either
short-circuiting when debug is disabled (return a lightweight placeholder) or by
converting whole batched tensors once to host Python lists up-front (use
tensor.detach().cpu().tolist() or tensor.tolist() once outside any per-request
loop), then iterate over those lists (handle prefix_lens being int vs tensor by
converting to a list similarly) – remove per-iteration .detach()/cpu()/indexing
and per-request tensor.index_select usage in _debug_cache_indirection_prefix and
_debug_new_tokens_host, and ensure _debug_tensor_slice and
_debug_batch_next_tokens only materialize when explicitly enabled.

Comment on lines +2886 to +2896
logger.info(
"TorchSampler._prepare_beam_search before reset: "
f"seq_slots={_debug_tensor_slice(seq_slots_long)} "
f"max_prompt_len={max_prompt_len} "
f"cum_log_probs={_debug_tensor_slice(beam_search_store.cum_log_probs, seq_slots_long)} "
f"cache_indirection_prefix="
f"{_debug_cache_indirection_prefix(beam_search_store.cache_indirection, seq_slots_long, max_prompt_len)} "
f"cache_indirection_buffer_prefix="
f"{_debug_cache_indirection_prefix(beam_search_store.cache_indirection_buffer, seq_slots_long, max_prompt_len)} "
f"predecessor_beams={_debug_tensor_slice(beam_search_store.predecessor_beams, seq_slots_long)}"
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove the pre-reset beam-store dump.

This logs beam-search buffers before they are reset, but those buffers are backed by torch.empty(...) and reused seq slots. On a fresh allocation you'll emit uninitialized garbage; on slot reuse you'll emit stale state from a previous request. That's a real data-leak risk in a serving path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/pyexecutor/sampler.py` around lines 2886 - 2896, The
logger.info call in TorchSampler._prepare_beam_search that dumps
beam_search_store, seq_slots_long and related buffers should be removed (or
moved to after the buffers are fully initialized) because it can leak
uninitialized or stale data; locate the logger.info block that references
_debug_tensor_slice(seq_slots_long), beam_search_store.cum_log_probs,
beam_search_store.cache_indirection, cache_indirection_buffer, and
beam_search_store.predecessor_beams and delete that pre-reset dump so no
beam-store buffers are logged before they are reset/initialized.

Comment on lines +3331 to +3343
logger.info(
"TorchSampler._add_metadata_to_grouped_requests beam metadata: "
f"group_indices={_debug_tensor_slice(value.indices)} "
f"seq_slots={_debug_tensor_slice(metadata.seq_slots)} "
f"seq_lens={_debug_tensor_slice(metadata.seq_lens)} "
f"cum_log_probs={_debug_tensor_slice(metadata.cum_log_probs, metadata.seq_slots)} "
f"cache_indirection_prefix="
f"{_debug_cache_indirection_prefix(metadata.cache_indirection, metadata.seq_slots, metadata.seq_lens)} "
f"cache_indirection_buffer_prefix="
f"{_debug_cache_indirection_prefix(metadata.cache_indirection_buffer, metadata.seq_slots, metadata.seq_lens)} "
f"predecessor_beams={_debug_tensor_slice(metadata.predecessor_beams, metadata.seq_slots)} "
f"finished_beams={_debug_tensor_slice(metadata.finished_beams, metadata.seq_slots)}"
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't log request/token state at info level in serving code.

These messages include request_id, full beam tokens before/after append, generated-token snapshots, cumulative log-probs, and cache-indirection state. Leaving that at normal info level will persist user data in routine service logs and create a compliance/support burden. Please keep this behind a short-lived debug-only trace with redaction, or remove it before merge.

Also applies to: 3444-3491, 3935-3950, 4087-4096

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/_torch/pyexecutor/sampler.py` around lines 3331 - 3343, The
info-level logging in TorchSampler._add_metadata_to_grouped_requests exposes
sensitive request/token state; change the logger.info call to debug-level
(logger.debug) and avoid printing raw token/cached state—either redact actual
token/log-prob values (replace content from _debug_tensor_slice and
_debug_cache_indirection_prefix with shapes/lengths or "<redacted>") or log only
non-sensitive summaries (e.g., tensor shapes, seq lengths, and counts). Also
wrap the debug emission with a debug-enabled check
(logger.isEnabledFor(logging.DEBUG)) if expensive to compute. Apply the same
change for the similar logging blocks referenced (the logger calls around the
other ranges that call _debug_tensor_slice/_debug_cache_indirection_prefix and
metadata fields such as metadata.seq_slots, metadata.seq_lens,
metadata.cum_log_probs, metadata.cache_indirection, metadata.predecessor_beams,
metadata.finished_beams).

Comment on lines +521 to +527
first_gen_cum_log_probs = [
out.cumulative_logprob for out in self._outputs
if out.cumulative_logprob is not None
]
if first_gen_cum_log_probs:
self._disaggregated_params.first_gen_cum_log_probs = \
list(first_gen_cum_log_probs)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fallback cumulatives can silently misalign beam indices.

The current fallback drops beams with None (if out.cumulative_logprob is not None), which can compress the list and shift beam-score alignment. Prefer assigning only when all beams have values (or keep it unset), rather than filtering by value.

Suggested fix
-                if first_gen_cum_log_probs is None:
-                    first_gen_cum_log_probs = [
-                        out.cumulative_logprob for out in self._outputs
-                        if out.cumulative_logprob is not None
-                    ]
-                if first_gen_cum_log_probs:
+                if first_gen_cum_log_probs is None:
+                    fallback_cum = [out.cumulative_logprob for out in self._outputs]
+                    if all(v is not None for v in fallback_cum):
+                        first_gen_cum_log_probs = fallback_cum
+                if first_gen_cum_log_probs is not None:
                     self._disaggregated_params.first_gen_cum_log_probs = \
                         list(first_gen_cum_log_probs)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tensorrt_llm/executor/result.py` around lines 521 - 527, The code currently
builds first_gen_cum_log_probs by filtering out None values from self._outputs,
which can compress and misalign beam indices; instead, in the block that sets
self._disaggregated_params.first_gen_cum_log_probs (using self._outputs and
self._disaggregated_params), only assign a list of cumulative_logprob values
when every out in self._outputs has a non-None cumulative_logprob and the
resulting list length equals the number of beams (otherwise leave
first_gen_cum_log_probs unset/None); locate the creation in the method
referencing self._outputs and replace the filtered-comprehension logic with a
check for any None (or compare lengths) before mapping to a list of
out.cumulative_logprob and assigning it to
self._disaggregated_params.first_gen_cum_log_probs.

@Tabrizian Tabrizian left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please remove the examples/disaggregated/simpler_example folder

@athena-nv
athena-nv requested a review from a team as a code owner May 26, 2026 22:19

@Tabrizian Tabrizian left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please clean up the PR from the logging changes.

mpi::MpiComm::world().getRank(), "Start sending KV cache for request ID: %ld.", llmRequest.mRequestId);

TLLM_CHECK_WITH_INFO(llmRequest.mSamplingConfig.beamWidth == 1, "Currently, only beam width 1 is supported.");
// TLLM_CHECK_WITH_INFO(llmRequest.mSamplingConfig.beamWidth == 1, "Currently, only beam width 1 is supported.");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This line should be reverted, since we are only adding support in Python Cache Transceiver.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Remove debug prints

@leslie-fang25
leslie-fang25 removed their request for review June 30, 2026 04:17
@athena-nv

Copy link
Copy Markdown
Collaborator Author

Updated PR: #14876

@athena-nv athena-nv closed this Jul 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants