LiteLLMChatTarget does not flag or survive output-token truncation
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 84/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- python
調査の方向性
pyrit/prompt_target/litellm_chat_target.py から始め、レスポンスの処理を pyrit/prompt_target/openai/_response_adapter.py および openai_chat_target.py と比較します。tests/unit/prompt_target/target/test_litellm_chat_target.py を実行し、再現された両方のケースを対象にします。finish_reason="length" のレスポンスは切り詰められたものとしてマークされ、空の切り詰められたレスポンスは例外を発生させずに空の要素を返します。
索引モデルが issue の本文から書いたものです。
説明
Describe the bug
LiteLLMChatTarget does not handle output-token truncation, even though it speaks the same OpenAI-compatible Chat Completions shape that OpenAIChatTarget already handles.
With max_tokens set (pyrit/prompt_target/litellm_chat_target.py:138), a response that stops at the limit arrives with finish_reason == "length", and two things go wrong:
- A clipped answer is stored as a complete one.
MessagePiece.mark_as_truncatedexists for exactly this (pyrit/models/messages/message_piece.py:196): "A truncated piece may still carry a partial answer withresponse_error == "none", so without this flag a consumer cannot tell a complete answer from a clipped one."is_truncatedstaysFalsefor aLiteLLMChatTargetpiece, so a scorer or a red teamer reads a cut-off answer as the model's real answer. - A truncation that empties the response aborts the turn.
validate_chat_completion_responseraisesEmptyResponseExceptionwhen there is no content, audio or tool call (pyrit/prompt_target/common/chat_completions_response_parser.py:107), and it runs before the construct step. This target is deliberately not wrapped inpyrit_target_retry(LiteLLM owns retry vianum_retries), so nothing catches it — the conversation just stops.
How OpenAIChatTarget already handles the same case
pyrit/prompt_target/openai/openai_chat_target.py:314-331 warns, flags the first piece, and returns a graceful empty piece when truncation left nothing. pyrit/prompt_target/openai/_response_adapter.py:105-114 is the shape to mirror: validate() warns and returns early when is_truncated, otherwise calls validate_chat_completion_response; is_truncated() is get_finish_reason(response=response) == "length".
warn_truncated_response documents that its wording lives in common "to keep targets from drifting apart" (pyrit/prompt_target/common/utils.py:197), and build_empty_truncated_response is already shared for this case.
Steps/Code to Reproduce
Reproduced on main at 7b533109, through the public entry point (tests/unit/prompt_target/target/test_litellm_chat_target.py, litellm stubbed so no provider call is made). Two tests, one per failure mode:
truncated = _mock_response(content="The answer is", finish_reason="length")
litellm_stub.acompletion = AsyncMock(return_value=truncated)
result = await target.send_prompt_async(message=_user_message())
assert result[0].message_pieces[0].is_truncated is True # currently False
empty = _mock_response(content=None, finish_reason="length")
empty.choices[0].message.content = None
litellm_stub.acompletion = AsyncMock(return_value=empty)
result = await target.send_prompt_async(message=_user_message()) # currently raises
assert result[0].message_pieces[0].response_error == "empty"
Expected Results
The first assertion holds; the second call returns a graceful empty piece instead of raising.
Actual Results
FAILED test_token_limit_truncation_marks_the_piece
E AssertionError: assert False is True
... 'finish_reason': 'length'}).is_truncated
FAILED test_token_limit_truncation_with_no_content_does_not_raise
E pyrit.exceptions.exception_classes.EmptyResponseException: Status Code: 204,
Message: The chat returned an empty response (no content, audio, or tool_calls).
pyrit/prompt_target/common/chat_completions_response_parser.py:109: EmptyResponseException
Screenshots
Not applicable.
Versions
- OS: macOS
- Python version: 3.11+
- PyRIT version:
mainat7b533109
Proposed change
Confined to pyrit/prompt_target/litellm_chat_target.py: add _is_truncated_response on the existing get_finish_reason helper; warn via warn_truncated_response(..., limit_parameter="max_tokens") and skip strict validation when truncated; in _construct_message_from_response_async, mark_as_truncated() the first piece and return build_empty_truncated_response(...) when truncation left no pieces.
One question, since this changes error behaviour: should a truncated-but-empty LiteLLM response continue as error="empty" like the OpenAI target, or is aborting the turn preferred here? Happy to follow whichever the project prefers. A branch with the change and both tests is on feiiiiii5:fix/litellm-truncation-marker if you want to look at the diff.
- 主要言語
- Python
- スター
- 4.5k
- フォーク
- 896
- 平均マージ
- 3日 1時間
- マージ済み PR(30日)
- 208
環境構築
このプロジェクトの環境構築ファイルはまだ確認していません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
microsoft/PyRIT のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 91/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
メンテナーはふだん 1 日以内に返信
-
Bug: triage GUI help wanted
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
microsoft/PyRIT#2868 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
microsoft/PyRIT の issue をすべて見る
似ている issue
-
pydanty:is-working
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
pydantic/pydantic-ai#8843 ·
メンテナーはふだん 1 日以内に返信
-
breaking change enhancement server
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
sktime/sktime#11310 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
needs-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
メンテナーはふだん 1 日以内に返信