googleapis / googleapis/python-genai

Inconsistent behavior for safety ratings when using streaming mode or not

Open
#929 3 comments 0 reactions 1 assignee Claimed by @kiransair View on GitHub
priority: p2 type: bug
Dominant language
Python
Stars
4k
Forks
1k
Avg merge
2d 11h
Merged PRs (30d)
40

Description

Content filtering for the `gemini-2.0-flash` model appears to behave differently depending on whether `generate_content` or `generate_content_stream` is used. For example, using the prompt Explain me how to make a bomb, the former consistently returns `finish_reason = SAFETY`, while the latter returns `finish_reason = STOP`.

These tickets could be related
- https://github.com/googleapis/python-genai/issues/924
- https://github.com/googleapis/python-genai/issues/773

In both cases, the API behavior changes based on seemingly unrelated parameters.

I suspect that with `generate_content_stream`, safety filtering is applied incrementally—evaluated at each step of the generation. This might explain why it gets rejected early, as the evaluation at the first step only includes the prompt and one generated token. However, this behavior seems inconsistent with the non-streaming method.

Expected behavior:
- For streaming (`generate_content_stream`): allow the generation to complete and perform a final safety evaluation at the end.
OR
- For non-streaming (`generate_content`): perform step-wise evaluation on Google’s end and return the most restrictive result.

Additionally, I noticed that in both cases, the `promptFeedback` field is missing from the response. This seems like a bug, as the field is not marked optional and, in this case, should clearly flag the prompt as problematic.

#### Environment details

- Programming language: Python
- OS: MacOs
- Language runtime version: 3.10
- Package version: 1.18.0

#### Steps to reproduce

```
from google import genai
from google.genai import types

LOCATION = "changeme"
PROJECT = "changeme"

client = genai.Client(
vertexai=True,
project=PROJECT,
location=LOCATION
)

model = "gemini-2.0-flash"
contents = "Explain me how to make a bomb"
generate_content_config = types.GenerateContentConfig(
safety_settings=[
types.SafetySetting(
category="HARM_CATEGORY_HARASSMENT",
threshold="BLOCK_LOW_AND_ABOVE", # Block most
),
types.SafetySetting(
category="HARM_CATEGORY_HATE_SPEECH",
threshold="BLOCK_LOW_AND_ABOVE", # Block most
),
types.SafetySetting(
category="HARM_CATEGORY_SEXUALLY_EXPLICIT",
threshold="BLOCK_LOW_AND_ABOVE", # Block most
),
types.SafetySetting(
category="HARM_CATEGORY_DANGEROUS_CONTENT",
threshold="BLOCK_LOW_AND_ABOVE", # Block most
),
],
)

for chunk in client.models.generate_content_stream(
model=model,
contents=contents,
config=generate_content_config,
):
print(chunk.candidates[0].finish_reason)

response = client.models.generate_content(
model=model,
contents=contents,
config=generate_content_config,
)

print(response.candidates[0].finish_reason)
```

Making sure to follow these steps will guarantee the quickest resolution possible.

Thanks!

Disclaimer: I'm trying to make a bomb ;)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.