In [2]:
!pip install openai
Looking in indexes: https://mirrors.aliyun.com/pypi/simple/
Requirement already satisfied: openai in d:\environment_test\jupyter_environment\lib\site-packages (2.3.0)
Requirement already satisfied: anyio<5,>=3.5.0 in d:\environment_test\jupyter_environment\lib\site-packages (from openai) (4.11.0)
Requirement already satisfied: distro<2,>=1.7.0 in d:\environment_test\jupyter_environment\lib\site-packages (from openai) (1.9.0)
Requirement already satisfied: httpx<1,>=0.23.0 in d:\environment_test\jupyter_environment\lib\site-packages (from openai) (0.28.1)
Requirement already satisfied: jiter<1,>=0.10.0 in d:\environment_test\jupyter_environment\lib\site-packages (from openai) (0.11.0)
Requirement already satisfied: pydantic<3,>=1.9.0 in d:\environment_test\jupyter_environment\lib\site-packages (from openai) (2.12.0)
Requirement already satisfied: sniffio in d:\environment_test\jupyter_environment\lib\site-packages (from openai) (1.3.1)
Requirement already satisfied: tqdm>4 in d:\environment_test\jupyter_environment\lib\site-packages (from openai) (4.67.1)
Requirement already satisfied: typing-extensions<5,>=4.11 in d:\environment_test\jupyter_environment\lib\site-packages (from openai) (4.15.0)
Requirement already satisfied: exceptiongroup>=1.0.2 in d:\environment_test\jupyter_environment\lib\site-packages (from anyio<5,>=3.5.0->openai) (1.3.0)
Requirement already satisfied: idna>=2.8 in d:\environment_test\jupyter_environment\lib\site-packages (from anyio<5,>=3.5.0->openai) (3.11)
Requirement already satisfied: certifi in d:\environment_test\jupyter_environment\lib\site-packages (from httpx<1,>=0.23.0->openai) (2025.10.5)
Requirement already satisfied: httpcore==1.* in d:\environment_test\jupyter_environment\lib\site-packages (from httpx<1,>=0.23.0->openai) (1.0.9)
Requirement already satisfied: h11>=0.16 in d:\environment_test\jupyter_environment\lib\site-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai) (0.16.0)
Requirement already satisfied: annotated-types>=0.6.0 in d:\environment_test\jupyter_environment\lib\site-packages (from pydantic<3,>=1.9.0->openai) (0.7.0)
Requirement already satisfied: pydantic-core==2.41.1 in d:\environment_test\jupyter_environment\lib\site-packages (from pydantic<3,>=1.9.0->openai) (2.41.1)
Requirement already satisfied: typing-inspection>=0.4.2 in d:\environment_test\jupyter_environment\lib\site-packages (from pydantic<3,>=1.9.0->openai) (0.4.2)
Requirement already satisfied: colorama in d:\environment_test\jupyter_environment\lib\site-packages (from tqdm>4->openai) (0.4.6)
In [3]:
import notebook
print(notebook.__version__)
7.4.7
In [4]:
from openai import OpenAI
client = OpenAI(api_key="sk-5e002cf488964cae9a5a88915228453f", base_url="https://api.deepseek.com")
In [5]:
# Round 1
messages = [{"role": "user", "content": "9.11 和 9.8, 哪个数更大?"}]
response = client.chat.completions.create(
    model="deepseek-reasoner",
    messages=messages
)
In [6]:
print(response)
ChatCompletion(id='5c49cb75-2323-42a2-91d3-fbae8cb81fe2', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  \n- 9.11 相当于 9.11  \n- 9.80 相当于 9.80  \n\n由于 9.80 大于 9.11,因此 **9.8 更大**。  \n简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None, reasoning_content='首先,用户的问题是:“9.11 和 9.8, 哪个数更大?”这是一个比较两个小数的问题。我需要比较9.11和9.8。\n\n9.11是九点一一,而9.8是九点八。为了比较它们,我可以将它们视为小数:9.11相当于9.11,而9.8相当于9.80。因为9.8可以写成9.80,这样更容易比较。\n\n现在,比较9.11和9.80:9.80大于9.11,因为80比11大。所以,9.8应该比9.11大。\n\n我也可以考虑数字的位数:9.11有百分位是1,而9.8有十分位是8,但9.8的百分位是0,所以实际上9.8是9.80,比9.11大。\n\n另一个方式是减去它们:9.8 - 9.11 = 0.69,这是一个正数,所以9.8更大。\n\n因此,答案应该是9.8更大。\n\n用户是用中文写的,所以我应该用中文回复。'))], created=1760339845, model='deepseek-reasoner', object='chat.completion', service_tier=None, system_fingerprint='fp_ffc7281d48_prod0820_fp8_kvcache', usage=CompletionUsage(completion_tokens=348, prompt_tokens=19, total_tokens=367, completion_tokens_details=CompletionTokensDetails(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=231, rejected_prediction_tokens=None), prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=0), prompt_cache_hit_tokens=0, prompt_cache_miss_tokens=19))

方法一:看到 response 的格式,考虑将其强制转换成列表进行提取¶

In [7]:
response_to_list = list(response)
print(response_to_list)
# 从输出的结果可以看出,强制转换成列表后,每一个元素都是元素,回答的内容在列表的 1号位元组的 1 号位。
[('id', '5c49cb75-2323-42a2-91d3-fbae8cb81fe2'), ('choices', [Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  \n- 9.11 相当于 9.11  \n- 9.80 相当于 9.80  \n\n由于 9.80 大于 9.11,因此 **9.8 更大**。  \n简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None, reasoning_content='首先,用户的问题是:“9.11 和 9.8, 哪个数更大?”这是一个比较两个小数的问题。我需要比较9.11和9.8。\n\n9.11是九点一一,而9.8是九点八。为了比较它们,我可以将它们视为小数:9.11相当于9.11,而9.8相当于9.80。因为9.8可以写成9.80,这样更容易比较。\n\n现在,比较9.11和9.80:9.80大于9.11,因为80比11大。所以,9.8应该比9.11大。\n\n我也可以考虑数字的位数:9.11有百分位是1,而9.8有十分位是8,但9.8的百分位是0,所以实际上9.8是9.80,比9.11大。\n\n另一个方式是减去它们:9.8 - 9.11 = 0.69,这是一个正数,所以9.8更大。\n\n因此,答案应该是9.8更大。\n\n用户是用中文写的,所以我应该用中文回复。'))]), ('created', 1760339845), ('model', 'deepseek-reasoner'), ('object', 'chat.completion'), ('service_tier', None), ('system_fingerprint', 'fp_ffc7281d48_prod0820_fp8_kvcache'), ('usage', CompletionUsage(completion_tokens=348, prompt_tokens=19, total_tokens=367, completion_tokens_details=CompletionTokensDetails(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=231, rejected_prediction_tokens=None), prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=0), prompt_cache_hit_tokens=0, prompt_cache_miss_tokens=19))]
In [8]:
choices = response_to_list[1][1]
print(choices)
[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  \n- 9.11 相当于 9.11  \n- 9.80 相当于 9.80  \n\n由于 9.80 大于 9.11,因此 **9.8 更大**。  \n简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None, reasoning_content='首先,用户的问题是:“9.11 和 9.8, 哪个数更大?”这是一个比较两个小数的问题。我需要比较9.11和9.8。\n\n9.11是九点一一,而9.8是九点八。为了比较它们,我可以将它们视为小数:9.11相当于9.11,而9.8相当于9.80。因为9.8可以写成9.80,这样更容易比较。\n\n现在,比较9.11和9.80:9.80大于9.11,因为80比11大。所以,9.8应该比9.11大。\n\n我也可以考虑数字的位数:9.11有百分位是1,而9.8有十分位是8,但9.8的百分位是0,所以实际上9.8是9.80,比9.11大。\n\n另一个方式是减去它们:9.8 - 9.11 = 0.69,这是一个正数,所以9.8更大。\n\n因此,答案应该是9.8更大。\n\n用户是用中文写的,所以我应该用中文回复。'))]
In [9]:
# 上述 choices 包含了我们需要的回答内容 content 和推理的内容 reasoning_content
# 但是直接提取 content 会报错,仔细观察不难发现,这是长度为 1 ,是只包含单个元素的列表
# 列表中的元素是一个对象,而 content 实际上在 Choice.message 属性中。
# 需要注意的是列表本身不等同于元素,因此需要 choices[0] 来提取这个元素。
msg = choices[0].message

# content 又是 messages 里的一个属性。
content = msg.content
print(f'content: {content}')

print('\n')
reasoning_content = msg.reasoning_content
print(f'reasoning_content: {reasoning_content}')
content: 9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  
- 9.11 相当于 9.11  
- 9.80 相当于 9.80  

由于 9.80 大于 9.11,因此 **9.8 更大**。  
简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。


reasoning_content: 首先,用户的问题是:“9.11 和 9.8, 哪个数更大?”这是一个比较两个小数的问题。我需要比较9.11和9.8。

9.11是九点一一,而9.8是九点八。为了比较它们,我可以将它们视为小数:9.11相当于9.11,而9.8相当于9.80。因为9.8可以写成9.80,这样更容易比较。

现在,比较9.11和9.80:9.80大于9.11,因为80比11大。所以,9.8应该比9.11大。

我也可以考虑数字的位数:9.11有百分位是1,而9.8有十分位是8,但9.8的百分位是0,所以实际上9.8是9.80,比9.11大。

另一个方式是减去它们:9.8 - 9.11 = 0.69,这是一个正数,所以9.8更大。

因此,答案应该是9.8更大。

用户是用中文写的,所以我应该用中文回复。
In [10]:
# 因此上述流程下来可以简化成如下代码:
# reasoning_content = response.choices[0].message.reasoning_content
# content = response.choices[0].message.content

方法二:点 [.] 提取方法¶

In [11]:
# 先输出一下 response 看是否解包了(例如 zip 只能解包一次)
# 如果解包了,只能再运行一遍前面的大模型来获得 response
print(response)
ChatCompletion(id='5c49cb75-2323-42a2-91d3-fbae8cb81fe2', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  \n- 9.11 相当于 9.11  \n- 9.80 相当于 9.80  \n\n由于 9.80 大于 9.11,因此 **9.8 更大**。  \n简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None, reasoning_content='首先,用户的问题是:“9.11 和 9.8, 哪个数更大?”这是一个比较两个小数的问题。我需要比较9.11和9.8。\n\n9.11是九点一一,而9.8是九点八。为了比较它们,我可以将它们视为小数:9.11相当于9.11,而9.8相当于9.80。因为9.8可以写成9.80,这样更容易比较。\n\n现在,比较9.11和9.80:9.80大于9.11,因为80比11大。所以,9.8应该比9.11大。\n\n我也可以考虑数字的位数:9.11有百分位是1,而9.8有十分位是8,但9.8的百分位是0,所以实际上9.8是9.80,比9.11大。\n\n另一个方式是减去它们:9.8 - 9.11 = 0.69,这是一个正数,所以9.8更大。\n\n因此,答案应该是9.8更大。\n\n用户是用中文写的,所以我应该用中文回复。'))], created=1760339845, model='deepseek-reasoner', object='chat.completion', service_tier=None, system_fingerprint='fp_ffc7281d48_prod0820_fp8_kvcache', usage=CompletionUsage(completion_tokens=348, prompt_tokens=19, total_tokens=367, completion_tokens_details=CompletionTokensDetails(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=231, rejected_prediction_tokens=None), prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=0), prompt_cache_hit_tokens=0, prompt_cache_miss_tokens=19))
In [12]:
response.choices
Out[12]:
[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  \n- 9.11 相当于 9.11  \n- 9.80 相当于 9.80  \n\n由于 9.80 大于 9.11,因此 **9.8 更大**。  \n简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None, reasoning_content='首先,用户的问题是:“9.11 和 9.8, 哪个数更大?”这是一个比较两个小数的问题。我需要比较9.11和9.8。\n\n9.11是九点一一,而9.8是九点八。为了比较它们,我可以将它们视为小数:9.11相当于9.11,而9.8相当于9.80。因为9.8可以写成9.80,这样更容易比较。\n\n现在,比较9.11和9.80:9.80大于9.11,因为80比11大。所以,9.8应该比9.11大。\n\n我也可以考虑数字的位数:9.11有百分位是1,而9.8有十分位是8,但9.8的百分位是0,所以实际上9.8是9.80,比9.11大。\n\n另一个方式是减去它们:9.8 - 9.11 = 0.69,这是一个正数,所以9.8更大。\n\n因此,答案应该是9.8更大。\n\n用户是用中文写的,所以我应该用中文回复。'))]
In [13]:
# 看上述结果类似列表,因此尝试列表提取元素的方法
response.choices[0]
Out[13]:
Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  \n- 9.11 相当于 9.11  \n- 9.80 相当于 9.80  \n\n由于 9.80 大于 9.11,因此 **9.8 更大**。  \n简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None, reasoning_content='首先,用户的问题是:“9.11 和 9.8, 哪个数更大?”这是一个比较两个小数的问题。我需要比较9.11和9.8。\n\n9.11是九点一一,而9.8是九点八。为了比较它们,我可以将它们视为小数:9.11相当于9.11,而9.8相当于9.80。因为9.8可以写成9.80,这样更容易比较。\n\n现在,比较9.11和9.80:9.80大于9.11,因为80比11大。所以,9.8应该比9.11大。\n\n我也可以考虑数字的位数:9.11有百分位是1,而9.8有十分位是8,但9.8的百分位是0,所以实际上9.8是9.80,比9.11大。\n\n另一个方式是减去它们:9.8 - 9.11 = 0.69,这是一个正数,所以9.8更大。\n\n因此,答案应该是9.8更大。\n\n用户是用中文写的,所以我应该用中文回复。'))
In [14]:
# 元素结果有点像 Class 的属性
response.choices[0].message
Out[14]:
ChatCompletionMessage(content='9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  \n- 9.11 相当于 9.11  \n- 9.80 相当于 9.80  \n\n由于 9.80 大于 9.11,因此 **9.8 更大**。  \n简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None, reasoning_content='首先,用户的问题是:“9.11 和 9.8, 哪个数更大?”这是一个比较两个小数的问题。我需要比较9.11和9.8。\n\n9.11是九点一一,而9.8是九点八。为了比较它们,我可以将它们视为小数:9.11相当于9.11,而9.8相当于9.80。因为9.8可以写成9.80,这样更容易比较。\n\n现在,比较9.11和9.80:9.80大于9.11,因为80比11大。所以,9.8应该比9.11大。\n\n我也可以考虑数字的位数:9.11有百分位是1,而9.8有十分位是8,但9.8的百分位是0,所以实际上9.8是9.80,比9.11大。\n\n另一个方式是减去它们:9.8 - 9.11 = 0.69,这是一个正数,所以9.8更大。\n\n因此,答案应该是9.8更大。\n\n用户是用中文写的,所以我应该用中文回复。')
In [15]:
# 上述探究结束,设置变量名即可
msg = response.choices[0].message
content = msg.content
print(f'content: {content}')

print('-*-' * 10)

reasoning_content = msg.reasoning_content
print(f'reasoning_content: {reasoning_content}')
content: 9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  
- 9.11 相当于 9.11  
- 9.80 相当于 9.80  

由于 9.80 大于 9.11,因此 **9.8 更大**。  
简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。
-*--*--*--*--*--*--*--*--*--*-
reasoning_content: 首先,用户的问题是:“9.11 和 9.8, 哪个数更大?”这是一个比较两个小数的问题。我需要比较9.11和9.8。

9.11是九点一一,而9.8是九点八。为了比较它们,我可以将它们视为小数:9.11相当于9.11,而9.8相当于9.80。因为9.8可以写成9.80,这样更容易比较。

现在,比较9.11和9.80:9.80大于9.11,因为80比11大。所以,9.8应该比9.11大。

我也可以考虑数字的位数:9.11有百分位是1,而9.8有十分位是8,但9.8的百分位是0,所以实际上9.8是9.80,比9.11大。

另一个方式是减去它们:9.8 - 9.11 = 0.69,这是一个正数,所以9.8更大。

因此,答案应该是9.8更大。

用户是用中文写的,所以我应该用中文回复。
In [16]:
# 因此上述流程下来也可以简化成如下代码:
# reasoning_content = response.choices[0].message.reasoning_content
# content = response.choices[0].message.content
In [17]:
# Round 2
messages.append({'role': 'assistant', 'content': content})    # 把大模型的回答添加到 messages 里
# messages.append({'role': 'user', 'content': "How many Rs are there in the word 'strawberry'?"})
messages.append({'role': 'user', 'content': "我上一个问的问题是什么?"})
response = client.chat.completions.create(
    model="deepseek-reasoner",
    messages=messages
)
print(messages)
[{'role': 'user', 'content': '9.11 和 9.8, 哪个数更大?'}, {'role': 'assistant', 'content': '9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  \n- 9.11 相当于 9.11  \n- 9.80 相当于 9.80  \n\n由于 9.80 大于 9.11,因此 **9.8 更大**。  \n简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。'}, {'role': 'user', 'content': '我上一个问的问题是什么?'}]
In [18]:
# 发现上文输出的结果很难看,找起来非常麻烦,此时可以用 pprint 输出有一定格式的结果
from pprint import pprint
pprint(messages)
[{'content': '9.11 和 9.8, 哪个数更大?', 'role': 'user'},
 {'content': '9.11 和 9.8 都是小数,比较时可以将 9.8 视为 9.80(因为 9.8 = 9.80)。  \n'
             '- 9.11 相当于 9.11  \n'
             '- 9.80 相当于 9.80  \n'
             '\n'
             '由于 9.80 大于 9.11,因此 **9.8 更大**。  \n'
             '简单来说:9.8 是九点八,而 9.11 是九点一一,所以 9.8 更大。',
  'role': 'assistant'},
 {'content': '我上一个问的问题是什么?', 'role': 'user'}]

上文我们探究了如何将第一个问题的回答添加到 messages 里面,从而让大模型有记忆,那如何验证呢? 这是我们关于单词的问题回答: 问 strawberry 单词里有几个 r 的回答.png

现在我们把这个问题注释掉,询问我们问的上一个问题是什么?看看大模型如何回答,从而验证它是否有记忆。

In [19]:
pprint(response)
ChatCompletion(id='0114dec7-4860-4ea3-9410-ab6dc3b2bb18', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='你上一个问题是:  \n**“9.11 和 9.8, 哪个数更大?”**  \n\n而当前你问的是:“我上一个问的问题是什么?”。  \n所以严格来说,你现在这个问题本身,就是“上一个问题” 😄  \n\n如果还需要其他帮助,请随时告诉我!', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None, reasoning_content='嗯,用户突然问“我上一个问的问题是什么?”,这看起来是个简单的记忆查询需求。不过结合对话历史,其实有点微妙——因为上一个问题正是关于数字比较的,而当前提问本身就成了新的“上一个问题”。\n\n用户可能是在测试我的记忆连贯性,或者想确认对话上下文是否保存完整。考虑到人类对话中常用“上一个问题”指代历史记录中的前一条,但严格来说现在这个提问已经覆盖了之前的记录。\n\n需要明确区分两种理解:如果按对话轮次,当前问题就是“我上一个问的问题是什么”;如果按用户意图,他真正想知道的应该是“在本次对话中,我最早提出的那个问题”。从逻辑连贯性出发,选择后者更符合实际需求。\n\n采用分层次回复:先直接回答他可能真正想询问的历史问题内容,再说明当前提问造成的语义变化,最后提供进一步帮助的选项。这样既解决问题又避免机械式响应。'))], created=1760339861, model='deepseek-reasoner', object='chat.completion', service_tier=None, system_fingerprint='fp_ffc7281d48_prod0820_fp8_kvcache', usage=CompletionUsage(completion_tokens=258, prompt_tokens=145, total_tokens=403, completion_tokens_details=CompletionTokensDetails(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=194, rejected_prediction_tokens=None), prompt_tokens_details=PromptTokensDetails(audio_tokens=None, cached_tokens=0), prompt_cache_hit_tokens=0, prompt_cache_miss_tokens=145))

上一个问题是什么?的回答.png 我们看到回答里,对于“上一个问题是什么?”的回答,还是草莓的事情,是因为大模型本身的思考原因,还是因为我们代码中带过去的信息导致模型回答的混乱呢?

  1. 首先,API 没有记忆,所谓的记忆都是我们给的信息里包含的。
  2. 已经注释掉了这个问题,为何 API 还会记得? 这是因为我们之前已经跑过“How many Rs are there in the word 'strawberry'” 这个问题,jupyter 的特点就是会暂时保留输出结果,因此 messages 的内容已经被我们的回答覆盖了,所以运行这句代码:messages.append({'role': 'assistant', 'content': content}),即把大模型的回答添加到 messages 里时,也把关于单词的回答添加进去了,造成了回答的“错误”和混乱。
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]: