Skip to content

Commit 2c21661

Browse files
authored
feat: allow the turning off of thinking (#4)
* feat: allow the turning off of thinking * tests: added tests for thinking * chore: added missing place where `do_thinking` should have been passed on
1 parent da1638f commit 2c21661

File tree

6 files changed

+122
-21
lines changed

6 files changed

+122
-21
lines changed

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,9 @@ prompt = (
109109

110110
result = run_prompt(prompt, use_grounding=True, inline_citations=True)
111111
pp(result)
112-
```
112+
```
113+
114+
## Thinking
115+
116+
You can enable or disable thinking in the model by toggling the `do_thinking` parameter.
117+
Only enable this if the task is complex enough to require it, because it makes things slow and expensive.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ license = { file = "LICENSE.md" }
99
requires-python = ">=3.10"
1010
dependencies = [
1111
"google-cloud-core>=2.4.3",
12-
"google-genai>=1.27.0",
12+
"google-genai>=1.59.0",
1313
"json-repair~=0.40.0",
1414
"pydantic>=2.11.7",
1515
"rapidfuzz>=3.13.0",

scripts/gemini_demo.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,12 @@ class Monarch(BaseModel):
7474

7575
answer_inline_citations = run_prompt(prompt, use_grounding=True, inline_citations=True)
7676
print("GROUNDING W/ CITATIONS", "\n", "-" * 100, "\n", answer_inline_citations, "\n\n")
77+
78+
# Thinking
79+
print("THINKING" + "\n" + "-" * 100)
80+
81+
test_prompt = """
82+
Why is fact checking important?
83+
""".strip()
84+
output = run_prompt(test_prompt, do_thinking=True)
85+
pp(output)

src/genai_utils/gemini.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,43 @@ def check_grounding_ran(response: types.GenerateContentResponse) -> bool:
293293
return bool(n_searches and n_chunks and n_supports)
294294

295295

296+
def get_thinking_config(
297+
model_name: str, do_thinking: bool
298+
) -> types.ThinkingConfig | None:
299+
"""
300+
Gets the thinking cofig required for the current model.
301+
Thinking is set differently before and after Gemini 3.0.
302+
Certain models like the 2.5 and 3.0 pro models, do not allow grounding to be disabled.
303+
"""
304+
if "gemini-2.5-pro" in model_name:
305+
if not do_thinking:
306+
_logger.warning(
307+
"It is not possible to turn off thinking with this model. Setting to minimum."
308+
)
309+
return types.ThinkingConfig(thinking_budget=128) # minimum thinking
310+
return types.ThinkingConfig(thinking_budget=-1) # dynamic budget
311+
312+
if (
313+
model_name < "gemini-2.6"
314+
): # there is no 2.6, but this means it will catch all 2.5 variants
315+
if do_thinking:
316+
return types.ThinkingConfig(thinking_budget=-1) # dynamic budget
317+
return types.ThinkingConfig(thinking_budget=0) # disable thinking
318+
319+
if model_name >= "gemini-3":
320+
if not do_thinking:
321+
if "pro" in model_name:
322+
_logger.warning(
323+
"Cannot disable thinking in this model. Setting thinking to low."
324+
)
325+
return types.ThinkingConfig(thinking_level=types.ThinkingLevel.LOW)
326+
return types.ThinkingConfig(thinking_level=types.ThinkingLevel.MINIMAL)
327+
return None
328+
329+
_logger.warning("Did not recognise the model provided, defaulting to None")
330+
return None
331+
332+
296333
def run_prompt(
297334
prompt: str,
298335
video_uri: str | None = None,
@@ -302,6 +339,7 @@ def run_prompt(
302339
safety_settings: list[types.SafetySetting] = DEFAULT_SAFETY_SETTINGS,
303340
model_config: ModelConfig | None = None,
304341
use_grounding: bool = False,
342+
do_thinking: bool = False,
305343
inline_citations: bool = False,
306344
labels: dict[str, str] = {},
307345
) -> str:
@@ -352,6 +390,10 @@ class Movie(BaseModel):
352390
and makes the output more likely to be factual.
353391
Does not work with structured output.
354392
See the docs (`grounding`_).
393+
do_thinking: bool
394+
Whether Gemini should use a thought process.
395+
This is more expensive but may yield better results.
396+
Do not use for bulk tasks that don't require complex thoughts.
355397
inline_citations: bool
356398
Whether output should include citations inline with the text.
357399
These citations will be links to be used as evidence.
@@ -379,6 +421,7 @@ class Movie(BaseModel):
379421
safety_settings=safety_settings,
380422
model_config=model_config,
381423
use_grounding=use_grounding,
424+
do_thinking=do_thinking,
382425
inline_citations=inline_citations,
383426
labels=labels,
384427
)
@@ -394,6 +437,7 @@ async def run_prompt_async(
394437
safety_settings: list[types.SafetySetting] = DEFAULT_SAFETY_SETTINGS,
395438
model_config: ModelConfig | None = None,
396439
use_grounding: bool = False,
440+
do_thinking: bool = False,
397441
inline_citations: bool = False,
398442
labels: dict[str, str] = {},
399443
) -> str:
@@ -444,6 +488,10 @@ class Movie(BaseModel):
444488
and makes the output more likely to be factual.
445489
Does not work with structured output.
446490
See the docs (`grounding`_).
491+
do_thinking: bool
492+
Whether Gemini should use a thought process.
493+
This is more expensive but may yield better results.
494+
Do not use for bulk tasks that don't require complex thoughts.
447495
inline_citations: bool
448496
Whether output should include citations inline with the text.
449497
These citations will be links to be used as evidence.
@@ -506,6 +554,7 @@ class Movie(BaseModel):
506554
safety_settings=safety_settings,
507555
**built_gen_config,
508556
labels=merged_labels,
557+
thinking_config=get_thinking_config(model_config.model_name, do_thinking),
509558
),
510559
)
511560

tests/genai_utils/test_gemini.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
import os
22
from unittest.mock import Mock, patch
33

4-
from google.genai import Client
4+
from google.genai import Client, types
55
from google.genai.client import AsyncClient
66
from google.genai.models import Models
77
from pydantic import BaseModel, Field
8+
from pytest import mark, param
89

910
from genai_utils.gemini import (
1011
DEFAULT_PARAMETERS,
1112
GeminiError,
1213
ModelConfig,
1314
generate_model_config,
15+
get_thinking_config,
1416
run_prompt_async,
1517
)
1618

@@ -143,3 +145,33 @@ async def test_error_if_citations_and_no_grounding(mock_client):
143145
return
144146

145147
assert False
148+
149+
150+
@mark.parametrize(
151+
"model_name,do_thinking,expected",
152+
[
153+
param("gemini-2.0-flash", False, types.ThinkingConfig(thinking_budget=0)),
154+
param("gemini-2.0-flash", True, types.ThinkingConfig(thinking_budget=-1)),
155+
param("gemini-2.5-flash-lite", False, types.ThinkingConfig(thinking_budget=0)),
156+
param("gemini-2.5-flash-lite", True, types.ThinkingConfig(thinking_budget=-1)),
157+
param("gemini-2.5-pro", False, types.ThinkingConfig(thinking_budget=128)),
158+
param("gemini-2.5-pro", True, types.ThinkingConfig(thinking_budget=-1)),
159+
param(
160+
"gemini-3.0-flash",
161+
False,
162+
types.ThinkingConfig(thinking_level=types.ThinkingLevel.MINIMAL),
163+
),
164+
param("gemini-3.0-flash", True, None),
165+
param(
166+
"gemini-3.0-pro",
167+
False,
168+
types.ThinkingConfig(thinking_level=types.ThinkingLevel.LOW),
169+
),
170+
param("gemini-3.0-pro", True, None),
171+
],
172+
)
173+
def test_get_thinking_config(
174+
model_name: str, do_thinking: bool, expected: types.ThinkingConfig
175+
):
176+
thinking_config = get_thinking_config(model_name, do_thinking)
177+
assert thinking_config == expected

uv.lock

Lines changed: 24 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)