文章目錄
- 一、引言
- 二、安裝Ollama
- 三、Linux部署GPT-OSS-20B模型
- 四、模型測試
- 4.1 AI幻覺檢測題
- 題目1:虛假歷史事件
- 題目2:不存在的科學概念
- 題目3:虛構的地理信息
- 題目4:錯誤的數學常識
- 題目5:虛假的生物學事實
- 4.2 算法題測試
- 題目1:動態規劃 - 最長公共子序列
- 題目2:圖算法 - 島嶼數量
- 4.3 SQL題測試
- 題目1:復雜查詢 - 員工薪資排名
- 題目2:數據分析 - 連續登錄用戶
- 題目3:窗口函數 - 移動平均
- 4.4 數學題測試
- 題目1:概率統計 - 條件概率與貝葉斯定理
一、引言
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官網:點擊跳轉
本教程是通過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
# 下載并安裝 Ollama
curl -fsSL https://ollama.com/install.sh | sh
隨后我們需要后臺運行ollama
# 后臺運行 ollama 服務
nohup ollama serve > ollama.log 2>&1 &
驗證服務狀態是否正常運行
# 檢查 ollama 進程是否正常運行
ps aux | grep ollama
ollama安裝并正常運行后,直接在命令行輸入oloama run gpt-oss:20b
即可拉取并運行
# 部署 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))`,但這里直接寫出最直觀的二維表即可)。```python
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] + 1else: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") == 3assert longest_common_subsequence("abc", "def") == 0assert longest_common_subsequence("", "abc") == 0assert longest_common_subsequence("AGGTAB", "GXTXAYB") == 4 # AGTBprint("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 Listdef num_islands(grid: List[List[str]]) -> int:"""統計 2 維網格中用 '1' 表示陸地、'0' 表示水的島嶼數量。參數:grid: List[List[str]],二維字符網格。返回:int:島嶼數量"""if not grid or not grid[0]:return 0rows, 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 + dcif 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 += 1dfs(i, j) # 或者改為遞歸方式return island_cntif __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) == 1test_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) == 3print("All tests passed.")運行后會輸出 `All tests passed.`,說明實現能夠正確統計島嶼數量。
4.3 SQL題測試
題目1:復雜查詢 - 員工薪資排名
問題:
– 給定員工表 employees 和部門表 departments
– employees 表結構:id, name, salary, department_id
– departments 表結構:id, name
– 查詢每個部門薪資前3名的員工信息,包括員工姓名、部門名稱、薪資和排名
輸出結果:
SELECTe.name AS employee_name,d.name AS department_name,e.salary,rn
FROM (SELECTe.id,e.name,e.salary,e.department_id,/* 在同一部門內按薪資降序給每位員工排序 */ROW_NUMBER() OVER (PARTITION BY e.department_idORDER BY e.salary DESC) AS rnFROM employees e) AS e
JOIN departments dON e.department_id = d.id
WHERE rn <= 3 -- 只保留前 3 名
ORDER BY d.id, rn; -- 可選:按部門號、薪資排名排序
題目2:數據分析 - 連續登錄用戶
– 給定用戶登錄表 user_logins
– 表結構:user_id, login_date
– 查找連續登錄天數超過7天的用戶ID
輸出結果:
/* 1?? 先把同一天多次登錄合并成一條記錄 */
WITH uniq AS (SELECT DISTINCT user_id, login_dateFROM user_logins
),/* 2?? 為每個用戶按日期排序并給行號 */
ranked AS (SELECTuser_id,login_date,ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rnFROM uniq
),/* 3?? 計算“組號”——(date – row_number) 的結果 */
gaps AS (SELECTuser_id,login_date,/* 以不同數據庫寫法為例:MySQL: DATE_SUB(login_date, INTERVAL rn DAY)PostgreSQL: login_date - rn * INTERVAL '1 day'SQL Server: DATEADD(day, -rn, login_date)Oracle: login_date - rn*//* 下面用標準 ANSI 兼容寫法,按數據庫自行替換 */(CASEWHEN @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 -- Oracle 及其它END) AS grpFROM ranked
),/* 4?? 組(island)內計算連續天數 */
islands AS (SELECTuser_id,grp,COUNT(*) AS consecutive_days -- 由于 ① 已去重,COUNT(*) 就是連續天數FROM gapsGROUP BY user_id, grp
)SELECT DISTINCT user_id
FROM islands
WHERE consecutive_days > 7;
題目3:窗口函數 - 移動平均
– 給定銷售表 sales
– 表結構:sale_date, amount
– 計算每天的銷售額以及最近7天的移動平均銷售額
-- 1?? 先把每天的總額匯總(如果有缺失天會缺失,后面再補齊)
WITH daily AS (SELECTsale_date,SUM(amount) AS daily_amountFROM salesGROUP BY sale_date
),-- 2?? 生成完整的日期序列(可選:只在需要填補空缺天時使用)
-- 下面給出 MySQL、PostgreSQL、SQL Server 與 Oracle 的做法,任選其一即可
date_seq AS (/* MySQL 8+ 示例 */SELECT DATE_ADD('2023-01-01', INTERVAL seq DAY) AS dFROM (SELECT 0 AS seq UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALLSELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6/* … 用遞歸 CTE 或 numbers 表生成更長序列 */) AS seq/* PostgreSQL: generate_series('2023-01-01'::date, '2023-12-31', interval '1 day') AS d *//* SQL Server: SELECT DATEADD(day, v.number, '2023-01-01') AS d FROM master..spt_values v WHERE v.type = 'P' *//* Oracle: SELECT TRUNC(TO_DATE('2023-01-01', 'YYYY-MM-DD') + LEVEL - 1) d FROM dual CONNECT BY LEVEL <= 365 */
),-- 3?? 把完整日期表與每天銷售額左連接,補齊缺失天
full_daily AS (SELECTd AS sale_date,COALESCE(daily_amount, 0) AS daily_amountFROM date_seq dLEFT JOIN daily USING (sale_date)
),-- 4?? 計算 7?天移動平均(窗口向前延伸 6 天)
moving_avg AS (SELECTsale_date,daily_amount,AVG(daily_amount) OVER (ORDER BY sale_dateROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS avg_7daysFROM full_daily
)SELECTsale_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%
通過以下圖片可以看出,模型給出了正確的答案