天天看點

Redis之父的大語言模型程式設計實踐

作者:CSDN

【編者按】Redis 之父 Antirez 在自己的部落格中分享到,借助 ChatGPT 等語言輔助程式設計工具可以節省查詢文檔等時間,可以直接讓 GPT 生成解釋或者代碼,對于臨時性代碼,則可以讓 LLM 直接生成,他最後還提到:“程式員沒有理由不去使用 LLM 輔助程式設計。”

原文連結:http://antirez.com/news/140

譯文連結:https://baoyu.io/translations/llm/llms-and-programming-in-the-first-days-of-2024

本文經授權轉載寶玉老師的個人部落格(微網誌@寶玉xp )

作者 | Antirez 責編 | 夢依丹

出品 | baoyu.io

首先我要明确,這篇文章并不旨在回顧大語言模型。顯而易見,2023 年對人工智能來說是不平凡的一年,再去強調這一點似乎沒有多大必要。這篇文章更多是作為一位程式員的個人體驗分享。

自從 ChatGPT 出現,再到使用本地運作的大語言模型,我就開始廣泛應用這項新技術。我的目标不僅僅是提高編碼效率,更重要的是,我不想在程式設計中那些無需過多精力投入的地方浪費時間。不願意花費大量時間去查找某些專業且無趣的文檔,不想為了學習一些過于複雜且往往無需如此的 API 而勞心費力,也不想編寫那些幾小時後就會被我抛棄的臨時代碼。尤其是如今 Google 成了一個充斥着垃圾資訊的海洋,我們隻能在其中努力尋找那少數有用資訊。

同時,我也不是程式設計領域的新手。我完全有能力在沒有任何輔助的情況下編寫代碼,而且我也常常這麼做。随着時間的推移,我越來越頻繁地借助大語言模型來編寫進階代碼,特别是 Python 代碼,而在 C 語言方面則相對少一些。在體驗大語言模型的過程中,我深刻認識到,應該在何時使用它們,以及何時它們的使用反而會拖慢我的步伐。我還了解到,大語言模型有點類似于維基百科和 YouTube 上琳琅滿目的視訊課程:它們對那些有意願、有能力和自律的人大有裨益,但對于其他人來說,幫助有限。我擔心,至少在初始階段,它們更多的是惠及那些本就占據優勢的人。但我們還是一步一個腳印來吧!

Redis之父的大語言模型程式設計實踐

全知全能還是鹦鹉學舌?在機器學習新浪潮中,最讓人擔憂的是 AI 專家們難以接受自己知識的局限性。人類發明了神經網絡,更關鍵的是,還發明了一個自動優化神經網絡參數的算法。随着硬體能力的提升,能夠訓練更大的模型,利用資料的統計知識(即先驗知識),通過不斷的嘗試和錯誤,逐漸找到了一些比其他架構更有效的模型設計。但不管怎樣,神經網絡本質上還是相當複雜且不透明的。面對大語言模型一些新的無法解釋的能力,謹慎的科學家們反而低估了它們。許多人認為,大語言模型不過是稍微進階點的馬爾科夫鍊 (Markov chains),最多隻能重複訓練集裡有限變化的内容。然而,越來越多的證據表明,這種看法幾乎可能是大錯特錯的。同時,很多吃瓜群衆過分誇大了大語言模型的能力,認為它們擁有現實中根本不存在的超自然力量。事實上,大語言模型最多隻能在其訓練資料所代表的空間内進行插值,即使如此,它們的這一能力也已經相當驚人。真要是今天的大語言模型能夠在看過的所有代碼構成的空間内自如插值,它們即便不能創造真正的新穎事物,也足以取代 99% 的程式員。但現實情況要并沒有這麼樂觀。大語言模型确實可以編寫一些它之前未曾見過的程式,展示出将不同思想的訓練資料融合的能力,但這種能力目前還有很大的限制,尤其是在需要細膩推理時,它們往往無法勝任。盡管如此,它們仍代表着從人工智能誕生至今的最偉大成就,這一點似乎無庸置疑。

Redis之父的大語言模型程式設計實踐

無知卻博學确實,大語言模型大體上隻能進行初級的推理,這些推理經常不準确,甚至會摻雜着一些關于不存在事實的幻覺。但它們卻擁有海量的知識。在程式設計領域,以及其他有高品質資料的領域,大語言模型就像是了解力有限卻知識淵博的人。如果要和這樣的夥伴進行結對程式設計(對我來說,結對程式設計本身就是個痛苦),可能會很糟糕:它們可能提出一些荒謬的想法,我們需要不斷鬥争才能貫徹我們自己的想法。但如果這個博學的傻瓜能夠聽從我們的指令,回答我們提出的所有問題,那一切都會變得不同。現有的大語言模型雖然不能引領我們超越已知的路徑,但如果我們想探索一個不熟悉的領域,它們往往能夠幫我們從一無所知到掌握足夠的知識來獨立前行。在程式設計領域,直到二十或三十年前,這些能力可能還不太引人注目。那時,你需要掌握幾種程式設計語言、經典算法以及那些基本的庫。其餘的則依靠你自己的智慧、專業知識和設計能力。具備這些素質,你就能成為一名全能的專家級程式員。然而,随着時間的推移,我們見證了架構、程式設計語言、各種庫的大量湧現。這種複雜性通常是不必要的,甚至無法自圓其說,但事實就是如此。在這樣的情況下,一個無所不知的“白癡”成了寶貴的盟友。我來舉個例子:我對機器學習的實驗最初是用 Keras 進行的,持續了至少一年。後來因各種原因,我轉向了 PyTorch。我已經了解什麼是嵌入(Embedding)或殘差網絡(Residual Networks, ResNets),但我并不想深入研究 PyTorch 的文檔(就像我學習 Keras 那樣,那時 ChatGPT 還不存在)。有了大語言模型,用 Torch 編寫 Python 代碼變得非常容易。我隻需清楚地了解我想要建構的模型,并提出合适的問題。

Redis之父的大語言模型程式設計實踐

應用案例我要讨論的不是那些簡單的問題,比如“嘿,類 X 是如何執行 Y 操作的?”如果隻是這些問題,那些對大語言模型保持懷疑态度的人可能就有理由了。但實際上,更複雜的模型能做的事情遠遠超出這些。幾年前,這些還被認為是不可思議的魔法。我可以這樣對 GPT4 下指令:看,這是我在 PyTorch 中實作的神經網絡模型。這裡是我的資料批次。我想調整這些張量的大小,以便它們能與神經網絡輸入的要求相比對,并且我希望以這種特别的方式展現它們。你能幫我寫出調整這些張量尺寸的代碼嗎?GPT4 幫我寫出了代碼,我接下來要做的,就是在 Python 指令行界面中測試這些張量是否真的符合我需要的大小,以及資料結構是否正确。再舉一個例子。不久前,我需要為基于 ESP32 的裝置開發一個藍牙低能耗 (BLE) 用戶端。經過研究後,我發現多平台藍牙程式設計接口大都不好用。解決方法很簡單,就是用 Objective C 和 macOS 的原生 API 來編寫代碼。但這樣一來,我就面臨着兩個問題:一是學習 Objective C 中複雜的 BLE API,這些 API 充滿了我認為完全沒有必要的複雜設計(作為一個極簡主義者,這些設計與我所認為的“好設計”截然相反);二是回憶起怎樣使用 Objective C 程式設計。我上次使用 Objective C 編寫程式是十年前了,很多細節,比如事件循環、記憶體管理等,我都已經記不清了。最後的結果就是這段代碼,雖然它看起來不是很美觀,但它完成了它的任務。我在極短的時間内就編寫完成了。否則根本不可能做到這一點。https://github.com/antirez/freakwan/blob/main/osx-bte-cli/SerialBTE.m這段代碼主要是通過在 ChatGPT 上複制粘貼我想實作但不太确定如何着手的功能來編寫的,是以最初它們并未能正确運作。然後,大語言模型幫我指出了問題所在并告訴我如何解決。雖然大部分代碼不是由 LLM 直接編寫的,但它确實極大地加快了程式設計速度。不用 ChatGPT 我也能完成這個任務嗎?答案是肯定的,但更有趣的不僅是它節省了我很多時間:事實上,如果沒有 ChatGPT,我連嘗試的勇氣都沒有,因為那似乎并不值得。這一點至關重要。對于我的項目來說,編寫這樣一個不重要的程式的努力與其帶來的好處的比例本來是不劃算的。此外,這個過程産生了一個比程式本身更有用的副作用:為了這個項目,我對 linenoise(我用于行編輯的一個庫)進行了改造,使其可以在多路複用環境下運作。這是另一個例子,更多地涉及到資料解釋而非代碼編寫。我打算用一個我在網上發現的卷積神經網絡 (Convolutional Neural Network) 設定一個 Python 腳本,但這個網絡缺乏詳細文檔。網絡的一大優勢是它采用了 ONNX (Open Neural Network Exchange) 格式,這使我能夠輕松地識别出網絡的輸入和輸出以及它們對應的名稱。我對這個卷積網絡了解的唯一一點是:它能識别圖像中的特定特征。但我不知道所需輸入圖像的格式和大小,更何況,網絡的輸出比我預想的要複雜得多(我原本以為它是一個二進制分類器 (binary classifier),用于判斷觀察到的圖像是否正常或存在問題。我原以為它隻有兩個輸出,但實際上有數百個)。我首先把 ONNX 網絡的中繼資料輸出複制粘貼到 ChatGPT 中,并向助手闡述了我所知道的關于網絡的有限資訊。ChatGPT 推測了輸入的組織方式,以及輸出可能是标準化後的框,用于指出圖像中潛在缺陷的部分,還有其他輸出表示這些缺陷的可能性。經過幾分鐘的交流,我得到了一個能進行網絡推斷的 Python 腳本,以及将起始圖像轉換為适合輸入的張量等必要代碼。讓我印象深刻的是,當 ChatGPT 觀察到測試圖像上的原始輸出值(基本上是邏輯單元 (logits))時,它終于“了解”了網絡的運作方式:一系列浮點數為識别輸出的确切細節和标準化提供了上下文,比如框是否居中或指定了左上角等細節。

Redis之父的大語言模型程式設計實踐

一次性程式

我曾經遇到過很多類似的情況,就像我之前叙述的那樣。但記錄這些并沒有太大意義,因為這些情況重複的故事基本相同。我的問題是,我需要迅速了解一些事情,特别是在大語言模型給出的回答可能是無稽之談時,我得能夠驗證這些資訊的真實性。在這種情況下,我會利用大語言模型加快我的知識擷取速度。但在其他情況下,我會讓大語言模型完全編寫代碼。舉個例子,當我需要編寫一個基本可以随時丢棄的程式時。比如這個:簡單語言模型示例程式我需要可視化一個小型神經網絡學習過程中的損失曲線(loss curve)。我向 GPT4 展示了 PyTorch 程式在學習過程中生成的 CSV 檔案格式,然後我提出了一個需求:如果我在指令行中指定了多個 CSV 檔案,我不想再看到同一實驗的訓練和驗證損失曲線,而是想比較不同實驗的驗證損失曲線。上面就是 GPT4 生成的結果,總共用了三十秒。類似地,我需要一個程式來讀取 AirBnB 的 CSV 報告,并按月份和年份對我的較高價的電梯大廈進行分組。接着,它會考慮清潔成本和每次預訂的夜晚數量,統計不同月份的平均租金價格。這個程式對我非常有用,但編寫它又極其無聊,因為過程中沒有什麼新穎之處。是以,我把 CSV 檔案的一部分複制粘貼到 GPT4 上,告訴大語言模型我要解決的問題。程式第一次嘗試就運作成功了,下面是完整的展示。

import pandas as pd              pd.set_option('display.max_rows', None)              df = pd.read_csv('listings.csv')              reservations = df[df['Type'] == 'Reservation']              reservations['Start Date'] = pd.to_datetime(reservations['Start Date'])              reservations['Year'] = reservations['Start Date'].dt.year              reservations['Month'] = reservations['Start Date'].dt.month              reservations['Nightly Rate'] = (reservations['Amount'] - reservations['Cleaning Fee']) / reservations['Nights']              all_listings = reservations['Listing'].unique()              all_years = reservations['Year'].unique()              all_months = range(1, 13)              index = pd.MultiIndex.from_product([all_listings, all_years, all_months], names=['Listing', 'Year', 'Month'])              all_data = pd.DataFrame(index=index).reset_index()              merged_data = pd.merge(all_data, reservations, on=['Listing', 'Year', 'Month'], how='left')              average_nightly_rates = merged_data.groupby(['Listing', 'Year', 'Month'])['Nightly Rate'].mean().fillna(0)           

要準确地了解如何對這些原本分散和無序的資料進行分組,需要一些簡單的邏輯推理。這不是大語言模型僅憑重複它所見過的語言模式就能簡單解決的問題。雖然 GPT4 在訓練中肯定觀察到了類似的程式,但幾乎可以肯定它沒有看到一個程式需要以我所要求的方式,在具有特定格式的 CSV 檔案中對資料進行分組。這證明了(至少在我看來),大語言模型能夠在其訓練集中不同程式所勾勒的範圍内進行一定程度的創新和推理。在我個人看來,編寫這類程式可能是對時間的不明智使用。一個大語言模型能替我完成這項工作,顯著提升了我程式設計的效率。這意味着,我能将精力集中在真正重要的事務上。

Redis之父的大語言模型程式設計實踐

當事情不按計劃進行:系統程式設計的挑戰

在大語言模型和程式設計領域,我取得了一定的成功。但是,當我使用 C 語言編寫程式時,我通常隻把 LLM 作為一種更便捷的文檔工具。作為一名系統程式設計專家,我發現隻有在 LLM 能進行複雜的推理分析時,它們才對我有實際用處。而在這方面,LLM 經常無法滿足期望。讓我們看一個實驗例子:試着概述一個高效、小型但完整的 C 語言實作的布隆過濾器(Bloom Filter)的要求,重點在于哈希(hashing)功能的關鍵要素。然後用優質的 C 語言編寫它。另外,考慮到你的例子應該可以存儲 100,000 個元素,并且誤報機率不超過 5%。添加的元素是以空字元結尾的字元串。以下是輸出結果:

#include <stdio.h>              #include <stdlib.h>              #include <string.h>              #include <math.h>                  #define N 100000 // Number of elements              #define P 0.05 // False positive probability              #define M (int)(-(N * log(P)) / (log(2) * log(2))) // Size of bit array              #define K (int)(M / N * log(2)) // Number of hash functions                  unsigned char bitArray[M / 8 + 1];                  void setBit(int n) {              bitArray[n / 8] |= 1 << (n % 8);              }                  int getBit(int n) {              return bitArray[n / 8] & (1 << (n % 8));              }                  // Basic hash functions (for demonstration purposes)              int hash1(char *str) {              int hash = 5381;              int c;              while ((c = *str++))              hash = ((hash << 5) + hash) + c;              return abs(hash % M);              }                  int hash2(char *str) {              unsigned long hash = 0;              int c;              while ((c = *str++))              hash = c + (hash << 6) + (hash << 16) - hash;              return abs(hash % M);              }                  void add(char *str) {              setBit(hash1(str));              setBit(hash2(str));              // Add more hash functions if needed              }                  int is_in(char *str) {              return getBit(hash1(str)) && getBit(hash2(str));              // Check more hash functions if used              }                  int main() {              char *testStr = "testString";              add(testStr);                  if (is_in(testStr)) {              printf("%s is probably in the set.\n", testStr);              } else {              printf("%s is definitely not in the set.\n", testStr);              }                  return 0;              }           

GPT4 所生成的布隆過濾器實作上并不算很出色。布隆過濾器應用廣泛,并不是什麼稀奇古怪的資料結構。然而,要編寫一個合格的布隆過濾器,需要更高層次的抽象思維。比如,需要找到一種有效的方法,對同一個字元串進行多次哈希處理,同時確定這些哈希值互相之間的獨立性。但是,如果你明确訓示 GPT4 改進哈希函數,使之能産生多個互不相關的輸出,它提出的方案就顯得更加合理:

unsigned int hash(const char* str, unsigned int hash_id) {              unsigned int hash = 5381;              int c;              while ((c = *str++)) {              hash = ((hash << 5) + hash) + c + hash_id;              }              return hash % BF_SIZE;              }           

如果 GPT4 能夠自行提出這種方案,它編寫的布隆過濾器将會有所不同,可能會使用單一的哈希函數一次性設定多個位。GPT4 能夠獨立完成編寫合适且更通用哈希函數的任務。但在整個布隆過濾器的編寫過程中,它未能表現出足夠的推理能力。相反,它隻是提供了兩種不同但相似的哈希函數,這種結果更像是從一篇關于布隆過濾器的低品質文章中看到的。大語言模型在推理能力上的不足,加上可能缺乏高品質的相關資料,甚至還可能存在大量低品質的資料,共同造成了這種不盡人意的結果。事實上,這并非個例。在算法或系統程式設計領域,我嘗試使用 LLM 的體驗通常都很差勁,哪怕在類似 Python 程式設計這樣的領域,LLM 表現出來的推理能力并不算高。與此同時,GPT-4 不僅能反編譯它生成的函數(在另一個獨立會話中),還能精準地了解該函數的用途:https://chat.openai.com/share/f54b64d7-d19a-4be4-8f10-08553aa812f1是以,認為 GPT-4 在系統程式設計領域無用的說法顯然是不恰當的。有趣的是,這些情況下,小型與大型模型之間的差異顯著。來看看兩個本地模型的對比表現。例如,Mistral 的專家模型 (MoE) Mixtral,對同樣的問題給出了以下回應:

unsigned int hash(const char* str, unsigned int hash_id) {              unsigned int hash = 5381;              int c;              while ((c = *str++)) {              hash = ((hash << 5) + hash) + c;              }              return hash + hash_id;              }           

顯然,僅在最後加入 hash_id 是一個非常不佳的解決方案。Mixtral 對許多應用而言是一個優秀的模型,但對于大語言模型本就有限的推理能力來說,目前的規則顯然是:越大越好。這是我與本地大型語言模型 deepseek-coder 的對話記錄。由于 RAM 有限,我隻能将模型量化到 4 位來使用。盡管如此,作為一個擁有 340 億參數的龐大模型,它在這個問題上的推理能力似乎相當出色。以下是我用 llama.cpp 進行的聊天記錄:

我有一個哈希函數,它應該為相同的資料輸出 N 個不同的哈希。但是,我發現當我改變 hash_id 的值時,生成的哈希分布非常差:
unsigned int hash(const char* str, unsigned int hash_id) {              unsigned int hash = 5381;              int c;              while ((c = *str++)) {              hash = ((hash << 5) + hash) + c;              }              return hash + hash_id;              }           

可能是我使用的加鹽政策不夠好?我該如何改進呢?[Deep-seek coder 的回複]你的實作中可能存在的一個問題是,你隻是簡單地在哈希的末尾添加了 hash_id。這可能會導緻分布不均,尤其是當 hash_id 過大或分布不均時更為明顯。考慮使用位運算來混合 hash_id。這裡有一個使用異或 (XOR) 運算的例子:

unsigned int hash(const char* str, unsigned int hash_id) {              unsigned int hash = 5381;              int c;              while ((c = *str++)) {              hash = ((hash << 5) + hash) ^ c + hash_id; // Using XOR to mix in the hash_id              }              return (hash ^ hash_id); // Mixing the hash_id one more time at the end              }           

這樣做可以比簡單添加更有效地分布 hash_id,進而使哈希分布更均勻。[省略……實際回複更詳盡]在我的 MacBook M1 Max 上運作的這個模型表現得相當不錯。它成功地将求和和異或操作混合使用了。在這個案例中,模型得到了我提供的關于問題的線索的幫助,但最終是模型自己識别出了問題的真正所在,并提出了一個有效的解決方案。這樣的成就是任何書籍、文檔或 Google 搜尋都無法達到的。不管你如何看待這個模型——無論是作為一個初級的、基于插值的結果,還是以其他方式——它确實展現了某種形式的推理能力。在這個特定案例中,如果我們認為識别問題的根源和找到可能的解決方案是一種推理,那麼它确實做到了這一點。但無論我們如何看待大語言模型,斷言它們對程式員無用是非常草率的。然而,根據我過去幾個月的經驗,對于系統程式設計來說,如果你已是資深程式員,大語言模型往往無法提供令人滿意的解決方案。我來舉一個真實世界中的例子。我的最新項目,ggufflib,涉及到開發一個讀寫 GGUF 格式檔案的庫,而這正是 llama.cpp 用來加載量化模型的格式。起初,為了弄懂量化編碼的工作原理(因為速度原因,每個量化比特都以特殊方式存儲),我試過使用 ChatGPT,但最後我選擇了對 llama.cpp 代碼進行逆向工程,這樣更加迅速。一個能夠有效協助系統程式員的大語言模型,在看到資料編碼的結構聲明和解碼函數後,應該能夠重建資料格式的文檔。雖然 llama.cpp 的功能足夠簡短,可以完全放入 GPT4 的上下文中,但它的輸出卻毫無用處。在這些情況下,我們還是得回歸傳統方式:紙筆在手,細讀代碼,尋找解碼器提取的比特在哪裡注冊。為了讓你更好地了解上述案例,如果你感興趣,可以嘗試一下。這裡有一個來自 llama.cpp 實作的結構。

// 6-bit quantization              // weight is represented as x = a * q              // 16 blocks of 16 elements each              // Effectively 6.5625 bits per weight              typedef struct {              uint8_t ql[QK_K/2]; // quants, lower 4 bits              uint8_t qh[QK_K/4]; // quants, upper 2 bits              int8_t scales[QK_K/16]; // scales, quantized with 8 bits              ggml_fp16_t d; // super-block scale              } block_q6_K;           

然後是用于執行去量化的函數:

void dequantize_row_q6_K(const block_q6_K * restrict x, float * restrict y, int k) {              assert(k % QK_K == 0);              const int nb = k / QK_K;              for (int i = 0; i < nb; i++) {              const float d = GGML_FP16_TO_FP32(x[i].d);              const uint8_t * restrict ql = x[i].ql;              const uint8_t * restrict qh = x[i].qh;              const int8_t * restrict sc = x[i].scales;              for (int n = 0; n < QK_K; n += 128) {              for (int l = 0; l < 32; ++l) {              int is = l/16;              const int8_t q1 = (int8_t)((ql[l + 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32;              const int8_t q2 = (int8_t)((ql[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32;              const int8_t q3 = (int8_t)((ql[l + 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32;              const int8_t q4 = (int8_t)((ql[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32;              y[l + 0] = d * sc[is + 0] * q1;              y[l + 32] = d * sc[is + 2] * q2;              y[l + 64] = d * sc[is + 4] * q3;              y[l + 96] = d * sc[is + 6] * q4;              }              y += 128;              ql += 64;              qh += 32;              sc += 8;              }              }              }           

當我請求 GPT4 編寫關于使用格式的概述時,它難以清晰地說明“ql”中上下四位的資料塊是如何存儲的,這與權重位置有關。在撰寫這篇部落格時,我還嘗試讓它編寫一個簡化版本的函數來展示資料的存儲方式(可能它難以用文字解釋,但可以通過代碼來表達)。然而,它生成的函數存在諸多問題,比如索引不正确,從 6 位到 8 位的符号擴充處理錯誤(僅僅是将其轉換為 uint8_t 類型),等等。對了,這是我最終自己編寫的代碼:

} else if (tensor->type == GGUF_TYPE_Q6_K) {              uint8_t *block = (uint8_t*)tensor->weights_data;              uint64_t i = 0; // i-th weight to dequantize.              while(i < tensor->num_weights) {              float super_scale = from_half(*((uint16_t*)(block+128+64+16)));              uint8_t *L = block;              uint8_t *H = block+128;              int8_t *scales = (int8_t*)block+128+64;              for (int cluster = 0; cluster < 2; cluster++) {              for (uint64_t j = 0; j < 128; j++) {              f[i] = (super_scale * scales[j/16]) *              ((int8_t)              ((((L[j%64] >> (j/64*4)) & 0xF) |              (((H[j%32] >> (j/32*2)) & 3) << 4)))-32);              i++;              if (i == tensor->num_weights) return f;              }              L += 64;              H += 32;              scales += 8;              }              block += 128+64+16+2; // Go to the next block.              }              }           

從上述函數中,我移除了這段代碼的核心貢獻:即長篇注釋,詳細記錄了 llama.cpp 中 Q6_K 編碼使用的确切格式。現在,如果 GPT 能夠幫我完成這一工作,那将非常有幫助。我相信這隻是時間問題,因為這類任務在沒有技術突破的情況下也是可行的,隻需适當的擴充即可。

Redis之父的大語言模型程式設計實踐

重新審視程式設計工作不得不說,這是一個事實:現今的程式設計大多是在微調同樣的内容,隻是形式略有變化。這種工作并不需要太高的推理能力。大語言模型在這方面表現出色,盡管它們的能力仍然受限于上下文長度。這個現象應該引起程式員的深思:真的值得去編寫這類程式嗎?雖然可以賺到不錯的收入,但如果大語言模型也能完成其中一部分工作,那麼在未來五到十年,這可能并非最佳的職業發展方向。再來看,大語言模型真的具備一定的推理能力,還是隻是表面上的假象?有時候,它們似乎在進行推理,但這可能隻是因為,像符号學家所說,使用的“符号”造成了一種實際上并不存在的意義錯覺。足夠了解大語言模型的人會明白,事實并非如此:這些模型整合既有資訊的能力,遠非簡單的詞彙重複。它們在預訓練期間的訓練主要是預測下一個 Token,這個過程迫使模型建構了一種抽象的模型。雖然這個模型可能脆弱、零散且不完美,但從我們觀察到的現象來看,它确實存在。在數學确定性存在疑問,且領域内頂尖專家意見分歧的情況下,相信自己的直覺似乎是明智之舉。最後,今天還有什麼理由不去使用大語言模型輔助程式設計呢?正确地向大語言模型提問是一項關鍵技能。這項技能練習得越少,利用 AI 改善工作的能力就越弱。而且,無論是與大語言模型還是與人類交流,清晰描述問題同樣重要。溝通不暢是一個嚴重的障礙,很多程式員盡管在自己的專業領域很有能力,但在溝通上卻做得很糟糕。現在,連 Google 都變得不那麼好用了,是以即便是将大語言模型作為一種壓縮文檔的方式來使用,也是個不錯的主意。至于我,我将繼續大量使用它們。我從來不喜歡去深究某個晦澀的通訊協定的細節,或者去了解由某些想要炫耀自己技術的人編寫的複雜庫方法。這些對我來說就像是"無用知識"。有了大語言模型,我就能免于這些困擾,每天都能感覺到它帶來的幫助。

Redis之父的大語言模型程式設計實踐

繼續閱讀