Skip to content

Commit 44c7cb4

Browse files
committed
big overall, got rid of Reasoned
1 parent 99fa07e commit 44c7cb4

12 files changed

+414
-264
lines changed

README.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ format_date("12/31/2008.") # returns '2008-12-31'
2424
Here is another example with a more structured output:
2525

2626
```python
27-
from gpt_function_decorator import gpt_function, Reasoned
27+
from gpt_function_decorator import gpt_function
2828

2929
@gpt_function
30-
def deduplicate_celebrities(names) -> Reasoned[list[str]]:
30+
def deduplicate_celebrities(names) -> list[str]:
3131
"""Return the deduplicated version of the celebrities list."""
3232

3333
celebrities = [
@@ -37,7 +37,7 @@ celebrities = [
3737
"Lionel Messi",
3838
"Leo diCaprio"
3939
]
40-
answer = deduplicate_celebrities(celebrities)
40+
answer = deduplicate_celebrities(celebrities, gpt_reasoning=true)
4141

4242
print (answer)
4343
# ['Leo Messi', 'Mozart', 'Leo diCaprio']
@@ -311,23 +311,25 @@ could_have_met("Chopin", celebrities=[
311311

312312
It turns out that this function struggles to find the right answer. Its output (generated by `gpt-4o-mini`) varies a lot and typically includes Peggy Lee, who lived in a different century. This is because this short prompt actually requires real reasoning from the GPT: first listing everyone's birth and death years, then checking who overlapped with Chopin.
313313

314-
To get a smarter answer, we provide a `Reasoned` constructor for the output schema. Concretely, it requests the GPT answer to have two fields, `reasoning` and `result`. The GPT answers is more verbose, and therefore slower and more costly, but also more helpful:
314+
To get a smarter answer, we provide a `gpt_reasoning` parameter to gpt-decorated functions. Concretely, it requests the GPT answer to have two fields, `reasoning` and `result` (the final result will have the reasoning under the `.__reasoning__` attribute). The GPT answers is more verbose, and therefore slower and more costly, but also more helpful:
315315
- The `reasoning` field gives the GPT room to "think through" the problem and produce better answers.
316316
- It is now possible for the user to see what the GPT's "reasoning" was, and whether a wrong answer was caused by a lack of knowledge, or logics, etc.
317317
- It reduces the risk that some of GPT's reasoning and formatting ends up polluting the result's schema.
318318

319-
So let's just change our function's output type hint to `Reasoned[list[str]]` and observe the improvement:
319+
So let's ask for a reasoning and observe the improvement:
320320

321321
```python
322-
from gpt_function_decorator import gpt_function, Reasoned
322+
from gpt_function_decorator import gpt_function
323323

324324
@gpt_function
325-
def could_have_met(person, celebrities) -> Reasoned[list[str]]:
325+
def could_have_met(person, celebrities) -> list[str]:
326326
"""List the names in {celebrities} that {person} could have met."""
327327

328-
answer = could_have_met("Chopin", celebrities=[
328+
celebrities = [
329329
"Napoleon", "Jefferson", "Mozart", "Julius Cesar", "Peggy Lee", "Beethoven"
330-
])
330+
]
331+
answer = could_have_met("Chopin", celebrities, gpt_reasoning=True)
332+
331333
print (answer)
332334
# ['Napoleon', 'Jefferson', 'Beethoven']
333335

@@ -352,6 +354,7 @@ print (answer.__reasoning__)
352354
The `gpt_function` decorator adds two parameters to the function it decorates:
353355
- `gpt_model`: this allows the function's user to switch between `gpt-4o-mini` (the default, fast and cheap but less capable) and `gpt-4o` (any compatible version).
354356
- `gpt_system_prompt`: this enables the user to tweak the answer as they would like by asking the GPT to focus on some aspects, or to roleplay.
357+
- `gpt_reasoning` as described in the previous section.
355358
- `gpt_debug`: this will cause the function to print the full prompt that it sends to the GPT (useful for troubleshooting or just getting a sense of what's going on).
356359

357360
As an example, let's start from this function:
@@ -419,8 +422,8 @@ GPTs are not yet fast and cheap enough to be used anywhere, but when they are it
419422
For instance instead of having developers write zillions of messages to help users troubleshoot errors, we'll use a function like this:
420423

421424
```python
422-
@gpt_function
423-
def help_troubleshoot(error_traceback: str) -> Reasoned[str]:
425+
@gpt_function(reasoning=True)
426+
def help_troubleshoot(error_traceback: str) -> str:
424427
"""Return a short analysis of the Python error: {error_traceback}"""
425428
```
426429

examples/async_function.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
"""This example demonstrates how to use the `gpt_function` decorator with
2+
async functions. We define an async function `write_story` that generates a
3+
short story about a given subject. We then run that story on three different
4+
subjects asynchronously using `asyncio.as_completed`, so that OpenAI's API
5+
generates the stories in parallel.
6+
"""
7+
18
from gpt_function_decorator import gpt_function
29
import asyncio
310

examples/games/cheater_guess_the_word.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
anymore without contradicting previous questions/answers.
44
"""
55

6-
from gpt_function_decorator import gpt_function, Reasoned
6+
from gpt_function_decorator import gpt_function
77
from pydantic import BaseModel, Field
88

99

@@ -12,10 +12,8 @@ class RandomWordSelection(BaseModel):
1212
could_find_a_word: bool
1313

1414

15-
@gpt_function
16-
def select_random_word(
17-
avoided_words=None, answers=None
18-
) -> Reasoned[RandomWordSelection]:
15+
@gpt_function(reasoning=True)
16+
def select_random_word(avoided_words=None, answers=None) -> RandomWordSelection:
1917
"""If it is possible, pick a word not in {avoided_words} for which you ALL
2018
of these answers are strictly true: {answers}. If not possible, set
2119
could_find_a_word=False"""
@@ -32,12 +30,11 @@ class InputEvaluation(BaseModel):
3230
)
3331
user_asked_to_quit: bool = Field(description="Does the user want to quit?")
3432

35-
36-
@gpt_function
37-
def evaluate_guess(text: str, secret_word: str) -> Reasoned[InputEvaluation]:
38-
"""In trying to guess secret word "{secret_word}", the user said "{text}".
39-
Evaluate this input
40-
"""
33+
@gpt_function(reasoning=True)
34+
def evaluate_guess(text: str, secret_word: str) -> "InputEvaluation":
35+
"""In trying to guess secret word "{secret_word}", the user said "{text}".
36+
Evaluate this input
37+
"""
4138

4239

4340
def play_cheater_guess_the_word(subject):

examples/games/guess_the_word.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
you will get a more random word.
1212
"""
1313

14-
from gpt_function_decorator import gpt_function, Reasoned
14+
from gpt_function_decorator import gpt_function
1515
from pydantic import BaseModel, Field
1616

1717

@@ -22,7 +22,7 @@ class RandomWordSelection(BaseModel):
2222

2323
@staticmethod
2424
@gpt_function
25-
def pick() -> Reasoned["RandomWordSelection"]:
25+
def pick() -> "RandomWordSelection":
2626
"""Pick a 3 random themes, then write a very random 100-word story about
2727
these subjects with any strange, unrelated events happening. List the noons
2828
in that story, and finally select the 7th noun in the list (make it singular
@@ -45,8 +45,8 @@ class InputEvaluation(BaseModel):
4545
user_tried_to_cheat: bool = Field(description="Did the user try to cheat?")
4646

4747
@staticmethod
48-
@gpt_function
49-
def from_user_text(text: str, secret_word: str) -> Reasoned["InputEvaluation"]:
48+
@gpt_function(reasoning=True)
49+
def from_user_text(text: str, secret_word: str) -> "InputEvaluation":
5050
"""In trying to guess secret word "{secret_word}", the user said
5151
"{text}". Evaluate this input.
5252
"""

examples/games/role_playing_game.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
"""In this example, we create a role-playing game where the player makes decisions
2+
that affect the story. The game has a "state" (the character's health and inventory)
3+
that is carried over from one turn to the next, and updated after each turn.
4+
"""
5+
16
from gpt_function_decorator import gpt_function
27
from pydantic import BaseModel, Field
38

0 commit comments

Comments
 (0)