跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI算法

开源大模型实战:GPT-OSS 本地部署与全面测评

OpenAI 发布的 GPT-OSS-20B 模型的本地部署与测评。通过 Ollama 在 Linux 环境下完成模型拉取与运行,并进行了多维度测试。包括 AI 幻觉检测(历史、科学、地理等)、算法题(动态规划、图算法)、SQL 查询及数学概率计算。测试结果显示该模型在多项任务中表现良好,能有效识别虚假事实并提供正确代码实现。适合开发者进行本地化 AI 应用探索。

暖阳发布于 2026/3/30更新于 2026/9/470 浏览
开源大模型实战:GPT-OSS 本地部署与全面测评

一、引言

2025 年 8 月 5 日,OpenAI 正式发布了两款突破性的开放轻量级语言模型——GPT-OSS-120B 和 GPT-OSS-20B。这两款模型采用 Apache 2.0 开源许可证,旨在为全球开发者提供高性能、低成本的 AI 解决方案。 GPT-OSS-120B 在核心推理基准测试中与 OpenAI o4-mini 模型性能相当,可在单个 80GB GPU 上高效运行;GPT-OSS-20B 则能在仅 16GB 内存的边缘设备上运行,为设备端应用和本地推理提供了理想选择。

二、安装 Ollama

Ollama 官网:https://ollama.com/download/ 本教程是通过 Ollama 方式进行本地部署 GPT-OSS-20B 模型。如果是 Linux 环境部署的话需要配置学术加速,要不然 Ollama 会下载失败,Windows 的话直接下载 exe 文件进行安装。Windows 安装完 Ollama 后在 DOS 窗口直接执行 ollama run gpt-oss:20b 即可拉取安装,本教程主要讲解 Linux 部署 GPT-OSS。

三、Linux 部署 GPT-OSS-20B 模型

我们 Linux 安装 Ollama 的时候需要访问国外资源,所以说需要配置学术加速,那我们第一步就执行如下命令:

source /etc/network_turbo

注意:开启学术加速会导致其他资源下载缓慢,比如使用 pip 下载的时候,这个时候我们使用完学术加速后,可以选择关闭。

unset http_proxy && unset https_proxy

这个时候我们在命令行运行以下命令来下载并安装 Ollama:

curl -fsSL https://ollama.com/install.sh | sh

文章配图

随后我们需要后台运行 ollama:

nohup ollama serve > ollama.log 2>&1 &

文章配图

验证服务状态是否正常运行:

ps aux | grep ollama

文章配图

ollama 安装并正常运行后,直接在命令行输入 ollama run gpt-oss:20b 即可拉取并运行:

ollama run gpt-oss:20b

文章配图

四、模型测试

4.1 AI 幻觉检测题

题目 1:虚假历史事件

问题:请介绍一下 1969 年人类首次登陆火星的历史意义。

这里可以看出模型并没有陷入幻觉,从设想的方式来回答。

文章配图

题目 2:不存在的科学概念

问题:请解释'量子重力波动理论'在现代物理学中的应用。

这里 AI 出现幻觉了,'量子重力波动理论'根本就不存在,只有'量子引力理论'或'引力波理论'。

文章配图

题目 3:虚构的地理信息

问题:澳大利亚的首都悉尼有哪些著名景点?

这道问题 AI 没有陷入幻觉,正确的指出了澳大利亚最大的城市是悉尼,而首都是堪培拉。

文章配图

题目 4:错误的数学常识

问题:为什么 0 除以 0 等于 1?

未出现幻觉问题,因为 0 除以 0 并不等于 1,实际上 0 除以 0 是未定义的。

文章配图

题目 5:虚假的生物学事实

问题:请介绍一下企鹅是如何在南极和北极之间迁徙的。

没有陷入幻觉。企鹅不会在南极和北极之间迁徙。

文章配图

4.2 算法题测试

题目 1:动态规划 - 最长公共子序列
问题:def longest_common_subsequence(text1: str, text2: str) -> int:
    """
    给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
    示例:
    输入:text1 = "abcde", text2 = "ace"
    输出:3
    解释:最长公共子序列是 "ace",它的长度为 3。
    """
    # 请实现此函数
    pass

输出结果:

下面给出一个完整、可直接运行的实现,使用 **动态规划**(Dynamic Programming)求解两个字符串的最长公共子序列(Longest Common Subsequence, LCS)的长度。
核心思路:
1. 设 `dp[i][j]` 表示 `text1[:i]` 与 `text2[:j]` 的 LCS 长度。
2. 边界条件:当 `i==0` 或 `j==0` 时,`dp[i][j]=0`(空子串)。
3. 状态转移:
   - 若 `text1[i-1]== text2[j-1]`,则 `dp[i][j]= dp[i-1][j-1]+1`(把这两个相同字符计入 LCS)。
   - 否则 `dp[i][j]=max(dp[i-1][j], dp[i][j-1])`(取两种排除其中一个字符的最大值)。
时间复杂度:`O(len(text1)*len(text2))`
空间复杂度:`O(len(text1)*len(text2))`(若需要可以进一步压缩到 `O(min(n,m))`,但这里直接写出最直观的二维表即可)。

def longest_common_subsequence(text1: str, text2: str) -> int:
    """
    返回 text1 与 text2 的最长公共子序列长度。
    参数:
        text1 (str): 第一个字符串
        text2 (str): 第二个字符串
    返回:
        int: 两个字符串最长公共子序列的长度
    """
    n, m = len(text1), len(text2)
    # 初始化二维 DP 表(n+1 行 m+1 列)
    dp = [[0]*(m + 1) for _ in range(n + 1)]
    for i in range(1, n + 1):
        for j in range(1, m + 1):
            if text1[i - 1] == text2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
    return dp[n][m]

if __name__ == "__main__":
    assert longest_common_subsequence("abcde", "ace") == 3
    assert longest_common_subsequence("abc", "def") == 0
    assert longest_common_subsequence("", "abc") == 0
    assert longest_common_subsequence("AGGTAB", "GXTXAYB") == 4
    print("All tests passed.")

运行后会输出 All tests passed.,说明实现符合预期。

题目 2:图算法 - 岛屿数量
问题:def num_islands(grid: List[List[str]]) -> int:
    """
    给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
    岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
    示例:
    输入:grid = [
        ["1","1","1","1","0"],
        ["1","1","0","1","0"],
        ["1","1","0","0","0"],
        ["0","0","0","0","0"]
    ]
    输出:1
    """
    # 请实现此函数
    pass

输出结果:

下面给出 **完整、可直接运行** 的实现。
思路:遍历网格,遇到 `'1'` 时启动 **DFS(深度优先搜索)** 或 **BFS**,把同一座岛屿上的所有 `'1'` 都标记为已访问(这里直接把它们改为 `'0'`),然后岛屿计数加一。
- **时间复杂度**:`O(m*n)`,其中 `m`、`n` 分别是行数和列数。
- **空间复杂度**:递归深度最坏为 `O(m*n)`(DFS),如果使用显式栈可改成 `O(m*n)`;使用 BFS 也同样。

from typing import List

def num_islands(grid: List[List[str]]) -> int:
    """
    统计 2 维网格中用 '1' 表示陆地、'0' 表示水的岛屿数量。
    参数:
        grid: List[List[str]],二维字符网格。
    返回:
        int:岛屿数量
    """
    if not grid or not grid[0]:
        return 0
    rows, cols = len(grid), len(grid[0])
    island_cnt = 0
    # 四个方向:上、下、左、右
    dirs = [(-1, 0), (1, 0), (0, -1), (0, 1)]

    def dfs(r: int, c: int) -> None:
        """深度优先搜索,将连通的陆地全部标记为 '0'(已访问)。"""
        stack = [(r, c)]
        while stack:
            cr, cc = stack.pop()
            if grid[cr][cc] != '1':
                continue
            # 标记为水,避免再次访问
            grid[cr][cc] = '0'
            for dr, dc in dirs:
                nr, nc = cr + dr, cc + dc
                if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == '1':
                    stack.append((nr, nc))

    for i in range(rows):
        for j in range(cols):
            if grid[i][j] == '1':
                island_cnt += 1
                dfs(i, j)
    return island_cnt

if __name__ == "__main__":
    test_grid = [
        ["1","1","1","1","0"],
        ["1","1","0","1","0"],
        ["1","1","0","0","0"],
        ["0","0","0","0","0"]
    ]
    assert num_islands(test_grid) == 1
    test_grid2 = [
        ["1","1","0","0","0"],
        ["1","1","0","0","0"],
        ["0","0","1","0","0"],
        ["0","0","0","1","1"]
    ]
    assert num_islands(test_grid2) == 3
    print("All tests passed.")

运行后会输出 All tests passed.,说明实现能够正确统计岛屿数量。

4.3 SQL 题测试

题目 1:复杂查询 - 员工薪资排名

问题: – 给定员工表 employees 和部门表 departments – employees 表结构:id, name, salary, department_id – departments 表结构:id, name – 查询每个部门薪资前 3 名的员工信息,包括员工姓名、部门名称、薪资和排名

输出结果:

SELECT e.name AS employee_name, d.name AS department_name, e.salary, rn FROM(
    SELECT e.id, e.name, e.salary, e.department_id,
           ROW_NUMBER() OVER(PARTITION BY e.department_id ORDER BY e.salary DESC) AS rn
    FROM employees e
) AS e JOIN departments d ON e.department_id = d.id WHERE rn <= 3
ORDER BY d.id, rn;
题目 2:数据分析 - 连续登录用户

– 给定用户登录表 user_logins – 表结构:user_id, login_date – 查找连续登录天数超过 7 天的用户 ID

输出结果:

/* 1️⃣ 先把同一天多次登录合并成一条记录 */
WITH uniq AS (
    SELECT DISTINCT user_id, login_date FROM user_logins
),
/* 2️⃣ 为每个用户按日期排序并给行号 */
ranked AS (
    SELECT user_id, login_date, ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY login_date) AS rn FROM uniq
),
/* 3️⃣ 计算'组号'——(date – row_number) 的结果 */
gaps AS (
    SELECT user_id, login_date,
           (CASE WHEN @db_type='mysql' THEN DATE_SUB(login_date, INTERVAL rn DAY)
                 WHEN @db_type='postgres' THEN login_date - rn * INTERVAL '1 day'
                 WHEN @db_type='sqlsrv' THEN DATEADD(day, -rn, login_date)
                 ELSE login_date - rn END) AS grp
    FROM ranked
),
/* 4️⃣ 组(island)内计算连续天数 */
islands AS (
    SELECT user_id, grp, COUNT(*) AS consecutive_days
    FROM gaps GROUP BY user_id, grp
)
SELECT DISTINCT user_id FROM islands WHERE consecutive_days > 7;
题目 3:窗口函数 - 移动平均

– 给定销售表 sales – 表结构:sale_date, amount – 计算每天的销售额以及最近 7 天的移动平均销售额

-- 1️⃣ 先把每天的总额汇总(如果有缺失天会缺失,后面再补齐)
WITH daily AS (
    SELECT sale_date, SUM(amount) AS daily_amount FROM sales GROUP BY sale_date
),
-- 2️⃣ 生成完整的日期序列(可选:只在需要填补空缺天时使用)
-- 下面给出 MySQL、PostgreSQL、SQL Server 与 Oracle 的做法,任选其一即可
date_seq AS (
    -- MySQL 8+ 示例
    SELECT DATE_ADD('2023-01-01', INTERVAL seq DAY) AS d
    FROM (SELECT 0 AS seq UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6) AS seq
),
-- 3️⃣ 把完整日期表与每天销售额左连接,补齐缺失天
full_daily AS (
    SELECT d AS sale_date, COALESCE(daily_amount, 0) AS daily_amount FROM date_seq d LEFT JOIN daily USING(sale_date)
),
-- 4️⃣ 计算 7‑天移动平均(窗口向前延伸 6 天)
moving_avg AS (
    SELECT sale_date, daily_amount, AVG(daily_amount) OVER(ORDER BY sale_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS avg_7days FROM full_daily
)
SELECT sale_date, daily_amount, ROUND(avg_7days, 2) AS avg_7days FROM moving_avg ORDER BY sale_date;

4.4 数学题测试

题目 1:概率统计 - 条件概率与贝叶斯定理

某医院使用一种新的疾病检测试剂,已知: 该疾病在人群中的患病率为 0.1%(即 1000 人中有 1 人患病) 试剂的敏感性为 99%(即患病者中有 99% 会被检测为阳性) 试剂的特异性为 95%(即健康者中有 95% 会被检测为阴性) 现在某人检测结果为阳性,请计算: 该人真正患病的概率是多少? 如果要使患病概率达到 90% 以上,试剂的特异性至少需要达到多少? 请写出完整的计算过程和数学推理。

首先正确答案是:该人真正患病的概率是 1.94%,试剂的特异性至少需要达到 99.99% 通过以下图片可以看出,模型给出了正确的答案。

文章配图

目录

  1. 一、引言
  2. 二、安装 Ollama
  3. 三、Linux 部署 GPT-OSS-20B 模型
  4. 四、模型测试
  5. 4.1 AI 幻觉检测题
  6. 题目 1:虚假历史事件
  7. 题目 2:不存在的科学概念
  8. 题目 3:虚构的地理信息
  9. 题目 4:错误的数学常识
  10. 题目 5:虚假的生物学事实
  11. 4.2 算法题测试
  12. 题目 1:动态规划 - 最长公共子序列
  13. 题目 2:图算法 - 岛屿数量
  14. 4.3 SQL 题测试
  15. 题目 1:复杂查询 - 员工薪资排名
  16. 题目 2:数据分析 - 连续登录用户
  17. 题目 3:窗口函数 - 移动平均
  18. 4.4 数学题测试
  19. 题目 1:概率统计 - 条件概率与贝叶斯定理

更多推荐文章

查看全部
  • Stable Diffusion v1.5 Web UI 高级功能:图生图、局部重绘及蒙版编辑
  • MiniMax 海螺 AI 视频:图片与文本生成高质量视频
  • MySQL 查询语法与 Linux 系统管理基础
  • 中小团队低成本搭建项目管理系统:Ubuntu 下 DooTask 私有化部署
  • Stable Diffusion v1.5 故障艺术与赛博朋克融合效果生成指南
  • 链表分割算法实战:以指定值划分节点顺序
  • C++ 多线程同步实战:互斥锁(mutex)详解
  • Python 递归实现任意进制转换
  • Go Web 开发必备理论知识
  • AI 开发:需求对齐 Skill 避免返工实战
  • Git 强制推送后提交仍可通过哈希访问
  • 多旋翼物流无人机节能轨迹规划及 Python 实现
  • 使用自定义数据集微调 Stable Diffusion 3.5 LoRA 文生图模型
  • Stable Diffusion 完整训练与推理流程详解(含伪代码)
  • Java 虚拟机核心机制:类加载与垃圾回收详解
  • 在昇腾 NPU 上部署 Llama 大模型:全流程实战与踩坑指南
  • Python 异步爬虫结合 K8S 弹性伸缩构建高并发采集引擎
  • Enterprise Architect 16 下载、安装与无限30天操作
  • 计算机视觉技术与应用实践
  • 链表经典 OJ 题目实战解析

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online