0-qwen3-chat-demo.ipynb 代码说明

这份 notebook 在做什么

这份 notebook 是一个最小文本对话 demo。
它的目标不是训练模型,而是让学生先看到:

  1. 本地 Ollama 可以直接运行一个预训练文本模型
  2. 我们只需要一个 prompt,就能拿到回答
  3. 调用方式本质上就是一次本地 HTTP 请求

如果你把它和 5/2-prog/0-qwen3-vl-demo.ipynb 对照着看,会发现:

所以这份 notebook 可以看成视觉 notebook 的更简单基础版。

整体结构

这份 notebook 的流程非常短:

  1. 导入依赖
  2. 写一个 prompt
  3. 构造请求体
  4. 请求本地 Ollama
  5. 读取模型回答
  6. 改一个新问题,再请求一次

Cell 0:标题页

这一格说明:

它帮助学生先建立一个边界:

Cell 1:准备依赖

这一格是提示说明,不执行代码。
它的作用是让学生知道:

Cell 2:导入依赖

代码是:

import json
import os
import urllib.request
import urllib.error

逐个解释:

和前面的视觉版本相比,这里没有:

因为文本对话不需要读图片,也不需要处理文件。

Cell 3:写一个 prompt

这一格告诉学生:

Cell 4:定义 prompt

prompt = '请用三句话解释什么是预训练,以及它为什么改变了 NLP。'
prompt

逐行解释:

为什么要先用变量,而不是直接把文本写死在下面的请求里?

因为这样更方便:

Cell 5:说明要构造请求体

这一格的意义是让学生知道:

Cell 6:构造 payload

代码是:

payload = {
    'model': 'qwen3.5:0.8b',
    'stream': False,
    'messages': [
        {
            'role': 'user',
            'content': prompt,
        }
    ],
}

payload

逐项解释:

为什么 messages 是列表?

因为对话可能有多轮:

这里只做最简单的一轮,所以列表里只有一条用户消息。

Cell 7:说明要请求本地 Ollama

这一步帮助学生切换思路:

Cell 8:请求本地 Ollama

代码是:

request = urllib.request.Request(
    'http://localhost:11434/api/chat',
    data=json.dumps(payload).encode('utf-8'),
    headers={'Content-Type': 'application/json'},
    method='POST',
)

逐行解释:

接下来:

for key in [
    'http_proxy',
    'https_proxy',
    'HTTP_PROXY',
    'HTTPS_PROXY',
    'all_proxy',
    'ALL_PROXY',
]:
    os.environ.pop(key, None)
opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))

这一段的作用是:

为什么要这么做?

因为很多同学电脑里会有:

这些配置有时会把本地 localhost 请求也一起带偏。

os.environ.pop(key, None) 的意思是:

然后:

urllib.request.ProxyHandler({})

表示:

最后:

with opener.open(request) as response:
    result = json.loads(response.read().decode('utf-8'))

这一段表示:

  1. 发请求
  2. 拿到返回
  3. 把返回内容从 JSON 解析回 Python 对象

Cell 9:说明下一步要看输出

这一格是过渡说明。
它的意义是告诉学生:

Cell 10:读取回答

result['message']['content']

这里是最简单、但最值得学生记住的一格。

它说明:

Cell 11:说明要换一个问题

这一格告诉学生:

看输出会怎样变化

Cell 12:换一个更贴近课堂的问题

代码是:

payload['messages'][0]['content'] = '请比较 GPT、BERT、T5 三条路线的主要差别。'

这一句的作用是:

这是一种很适合教学的写法,因为它能让学生看到:

后面这段请求代码和前面几乎一样:

最后:

result['message']['content']

直接显示新的回答。

这份 notebook 最值得学生带走什么

  1. 文本模型的调用接口其实非常简单。
  2. 本地模型调用的本质就是一次本地 HTTP 请求。
  3. payload 里最核心的三个字段是:modelstreammessages
  4. 改 prompt,比改代码更能直接影响模型行为。
  5. 很多“跑不起来”的问题,其实来自代理、服务没开、模型名写错,而不是 Python 本身。

最常见的 3 个问题

1. 本地服务没开

现象:

说明:

2. 模型名不对

现象:

说明:

3. 代理干扰

现象:

说明:

这也是为什么这里专门清理代理配置。