作业打卡:第三章《大语言模型基础》——本地运行 Qwen 并实现循环问答

学习日期:2026-09-19

实践内容:本地部署开源大语言模型、单轮问答、多轮循环问答

使用模型:Qwen/Qwen1.5-0.5B-Chat

参考资料:Datawhale Hello-Agents 第三章《大语言模型基础》1

本章主要介绍了语言模型的发展、Transformer 架构、提示工程、文本分词以及开源大语言模型的本地调用。本文重点记录我在第三章中的动手实践过程:在本地运行一个轻量级 Qwen 对话模型,并在教程代码基础上增加循环问答功能。


一、实践目标

本次实践主要完成以下任务:

  1. 在本地加载开源对话模型;
  2. 使用分词器将自然语言转换为 Token ID;
  3. 调用模型的 generate() 方法生成回答;
  4. 将模型输出的 Token ID 解码为文本;
  5. 在原有单轮问答基础上,增加循环问答和上下文记忆功能;
  6. 记录实践过程中遇到的网络和依赖问题。

二、实践环境

本次实践使用的是本地 Jupyter Notebook 环境:

  • 操作系统:Windows
  • Python 环境:Anaconda asr
  • 运行设备:CPU
  • 模型来源:ModelScope
  • 模型名称:Qwen/Qwen1.5-0.5B-Chat

由于直接访问 Hugging Face 时出现了连接超时问题,本次实践改用 ModelScope 下载模型。ModelScope 可以提供相同的 Qwen 模型,并且在国内网络环境下更加稳定。


三、相关知识点回顾

1. 大语言模型的生成方式

本次使用的 Qwen 模型属于 Decoder-Only 架构。它的基本工作方式是自回归生成:

  1. 输入已有文本;
  2. 模型预测下一个最可能出现的 Token;
  3. 将新 Token 加入输入;
  4. 重复这个过程,直到生成完整回答。

因此,大语言模型并不是一次性生成完整句子,而是一个 Token 一个 Token 地逐步生成。

2. 分词器的作用

计算机不能直接处理自然语言文本,需要使用分词器将文本转换为 Token ID。例如,本次实践中的输入:

text 复制代码
你好,请介绍你自己。

经过分词器编码后,会变成类似下面的张量:

text 复制代码
{'input_ids': tensor([[151644, 8948, 198, 2610, 525, 264, ...]]),
 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, ...]])}

模型实际处理的是这些数字,而不是原始汉字。

3. 对话模板

对话模型通常需要按照固定格式组织输入。Qwen 提供了 apply_chat_template() 方法,可以把 systemuserassistant 等角色转换成模型能够理解的对话格式。


四、加载本地模型

首先导入 PyTorch 和 ModelScope 中的模型加载类:

python 复制代码
import torch
from modelscope import AutoModelForCausalLM, AutoTokenizer

model_id = "Qwen/Qwen1.5-0.5B-Chat"

device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Using device: {device}")

tokenizer = AutoTokenizer.from_pretrained(model_id)

model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype="auto"
).to(device)

print("模型和分词器加载完成!")

我的电脑没有使用 GPU,因此输出为:

text 复制代码
Using device: cpu
模型和分词器加载完成!

第一次运行时会自动下载模型文件。下载完成后,后续运行会直接使用本地缓存,不需要重新下载完整模型。


五、实现单轮问答

教程中的基础代码是构造一个 messages 列表,然后使用对话模板进行编码:

python 复制代码
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "你好,请介绍你自己。"}
]

text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True
)

model_inputs = tokenizer([text], return_tensors="pt").to(device)

接着调用 generate() 生成回答:

python 复制代码
generated_ids = model.generate(
    model_inputs.input_ids,
    max_new_tokens=512
)

generated_ids = [
    output_ids[len(input_ids):]
    for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]

response = tokenizer.batch_decode(
    generated_ids,
    skip_special_tokens=True
)[0]

print("模型的回答:")
print(response)

运行结果为:

text 复制代码
模型的回答:
我是来自阿里云的大规模语言模型,我叫通义千问。

这一步让我完整看到了大语言模型从文本输入到文本输出的过程:

text 复制代码
用户文本
   ↓
对话模板
   ↓
Token ID
   ↓
模型生成新的 Token ID
   ↓
分词器解码
   ↓
自然语言回答

六、改进:增加循环问答功能

教程中的代码只能完成一次问答。为了更接近真实聊天场景,我在原代码基础上增加了循环问答功能。

1. 改进内容

主要增加了以下功能:

  • 使用 while True 持续接收用户输入;
  • 使用 messages 保存对话历史;
  • 最多保留最近 6 轮问答,避免上下文过长;
  • 支持 quitexitbye退出再见 等退出命令;
  • 支持 /clear 清空对话历史;
  • 使用 attention_mask 参与生成;
  • 只解码模型新生成的 Token;
  • 增加空输入和异常处理。

2. 关键代码

python 复制代码
messages = [
    {"role": "system", "content": "你是一个有帮助的中文助手,回答请简洁、准确。"}
]

MAX_HISTORY_TURNS = 6
EXIT_COMMANDS = {"quit", "exit", "bye", "退出", "再见"}
CLEAR_COMMANDS = {"/clear", "clear", "清空", "清空历史"}

while True:
    try:
        user_input = input("用户:").strip()
    except (EOFError, KeyboardInterrupt):
        print("\n助手:对话已结束。")
        break

    if not user_input:
        print("助手:请输入内容后再发送。")
        continue

    if user_input.lower() in EXIT_COMMANDS:
        print("助手:再见!")
        break

    if user_input.lower() in CLEAR_COMMANDS:
        messages = [
            {"role": "system", "content": "你是一个有帮助的中文助手,回答请简洁、准确。"}
        ]
        print("助手:对话历史已清空。")
        continue

    messages.append({"role": "user", "content": user_input})

    # 只保留 system 和最近几轮问答
    if len(messages) > 1 + MAX_HISTORY_TURNS * 2:
        messages = [messages[0]] + messages[-MAX_HISTORY_TURNS * 2:]

    text = tokenizer.apply_chat_template(
        messages,
        tokenize=False,
        add_generation_prompt=True
    )

    model_inputs = tokenizer([text], return_tensors="pt").to(device)

    with torch.no_grad():
        generated_ids = model.generate(
            **model_inputs,
            max_new_tokens=256,
            do_sample=True,
            temperature=0.7,
            top_p=0.8,
            repetition_penalty=1.05,
            pad_token_id=tokenizer.eos_token_id
        )

    new_token_ids = generated_ids[0][model_inputs.input_ids.shape[-1]:]
    response = tokenizer.decode(
        new_token_ids,
        skip_special_tokens=True
    ).strip()

    messages.append({"role": "assistant", "content": response})
    print(f"助手:{response}\n")

3. 循环问答运行结果

程序启动后显示:

text 复制代码
已进入循环问答模式
输入 quit / exit / bye / 退出 / 再见 可以结束对话
输入 /clear 可以清空对话历史

我进行了两轮关于 AI 经济的测试:

text 复制代码
用户:你觉得AI经济存在泡沫吗?
助手:AI经济的发展确实存在一定的泡沫现象,因为AI技术的快速发展导致了大量的人才失业和就业机会减少,这给社会带来了不确定性。另外,AI技术的广泛应用也可能会带来一些不可预见的风险,比如数据安全问题等。因此,我们需要在推动AI经济发展的同时,也要关注其可能带来的风险,采取相应的措施来防范和应对这些风险。

用户:AI经济泡沫会在几年内破裂呢?
助手:AI经济泡沫破裂的时间取决于许多因素,包括AI技术的成熟度、市场环境的变化、政策法规的调整等。目前来看,AI经济泡沫还没有完全破裂,但随着技术的不断进步和政策法规的不断完善,未来几年内AI经济泡沫的可能性可能会进一步降低。

从结果可以看到,第二个问题使用了第一个问题的上下文,说明 messages 中保存的对话历史已经生效。

不过也能看出,小模型的回答比较笼统,缺少数据和明确依据。这正好对应了本章提到的模型幻觉和可靠性问题:模型可以生成看似合理的回答,但回答内容不一定经过事实验证。


七、实践中遇到的问题及解决方法

1. Hugging Face 连接超时

最开始使用 Hugging Face 下载模型时,出现了连接超时:

text 复制代码
WinError 10060
由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。

原因是当前网络无法稳定访问 Hugging Face。解决方法是改用 ModelScope:

python 复制代码
from modelscope import AutoModelForCausalLM, AutoTokenizer

并将模型来源改为:

python 复制代码
model_id = "Qwen/Qwen1.5-0.5B-Chat"

2. ModelScope 依赖版本不兼容

使用 ModelScope 时,还遇到过下面的错误:

text 复制代码
ImportError: cannot import name 'DEFAULT_CREDENTIALS_PATH'
from 'modelscope_hub.compat.constants'

这个错误说明 modelscopemodelscope-hub 版本不匹配。解决方法是卸载后安装兼容版本:

bash 复制代码
D:\anaconda3\envs\asr\python.exe -m pip uninstall -y modelscope modelscope-hub

D:\anaconda3\envs\asr\python.exe -m pip install --no-cache-dir "modelscope==1.40.1" "modelscope-hub==0.4.3" -i https://pypi.tuna.tsinghua.edu.cn/simple

安装后重启 Jupyter Kernel,再运行下面的代码检查:

python 复制代码
import modelscope_hub.compat.constants as constants

print(constants.DEFAULT_CREDENTIALS_PATH)
print("modelscope-hub 检查通过")

检查通过后,模型就可以正常加载。

3. TqdmWarning

运行过程中还出现了:

text 复制代码
TqdmWarning: IProgress not found

这个提示只是 Jupyter 进度条组件的警告,不影响模型下载和运行,可以暂时忽略。


八、学习心得

通过本次实践,我对第三章的内容有了更直观的理解。

首先,我认识到大语言模型并不是直接"理解文字",而是通过分词器将文本转换为 Token ID,再由模型基于上下文逐步生成新的 Token。apply_chat_template()generate()decode() 分别对应输入格式化、模型生成和输出解码三个关键步骤。

其次,我在原有代码基础上增加了循环问答功能。这让我理解了对话历史中 systemuserassistant 三种角色的作用,也认识到上下文窗口不能无限增长,因此需要限制保留的历史轮数。

最后,这次实践也让我看到了小模型的局限。它可以完成基本对话,但在回答开放性问题时可能会给出比较笼统、缺少依据的内容。因此,在实际构建智能体时,还需要结合检索、工具调用和人工校验,不能完全相信模型生成的结果。


九、参考资料

1 Datawhale. Hello-Agents:第三章 大语言模型基础EB/OL. https://github.com/datawhalechina/hello-agents

2 ModelScope. Qwen1.5-0.5B-Chat 模型页EB/OL. https://modelscope.cn/models/Qwen/Qwen1.5-0.5B-Chat

相关推荐
码狂☆1 小时前
GPT-6 Astra 上线 Codex:1.4 折接入教程
人工智能·gpt
Omics Pro1 小时前
上海AI Lab孙思琦×高张阳:虚拟细胞代码库智能体
数据库·人工智能·算法·机器学习·自然语言处理
goujunwe1 小时前
企业 GEO 落地三步法:诊断、内容重构、AI 引用效果监测
大数据·人工智能·学习方法·传媒
jingli91 小时前
恶意退款怎么办、仅退款怎么申诉:六类恶意退款识别特征+取证证据链+反制全流程(商家实操版)
人工智能·自动化·用户运营
浅安的邂逅1 小时前
260919-报道称:美军曾因一份 AI 幻觉情报,险些误判并准备拦截一艘中国船只
人工智能·大模型·ai编程·行业动态·ai日报
Anastasiozzzz1 小时前
重新定义 Agent 基建:Redis 在现代 AI 与智能体系统中的工程实践
java·人工智能·redis·ai
染指11101 小时前
120.Agent-LangChain核心组件-中间件-摘要中间件(SummarizationMiddleware)
人工智能·langchain·agent·agents
Nolla1 小时前
Tool Calling Agent:ToolNode、消息状态与常见踩坑
人工智能
hrrrrxeeeee2 小时前
文件读取→比对→风险标记,拆解采购 AI 完整工作链路
大数据·人工智能·机器学习·prompt