TS之父的新項目Typechat預(yù)示著前端的未來
大家好,我卡頌。
最近兩年,整個前端圈都比較焦慮,主要有兩個原因:
- 經(jīng)濟下行造成工作不好找
- AIGC對行業(yè)未來的沖擊
其中第一條大環(huán)境如此,沒什么可抱怨的。第二條的焦慮則更多是「對未知的恐懼造成的」。
換言之,大家都知道AIGC(Artificial Intelligence Generated Content,生成式人工智能)會改變行業(yè)現(xiàn)狀,但不知道改變的方式是「取代工程師」還是「幫助工程師」?
最近,TypeChat[1]的發(fā)布讓前端未來的發(fā)展方向變得更清晰 —— 在不遠的未來,AIGC將會是工程師得力的助手,而不是取代工程師。
為什么這么說呢?本文會從以下角度闡述:
- 當前LLM(large language model,大語言模型)的問題
- TypeChat是什么,他是如何解決上述問題的
- TypeChat的實現(xiàn)原理
- TypeChat對前端行業(yè)的影響
LLM的問題
LLM應(yīng)用最廣、普及度最高的應(yīng)用場景是「聊天助手」(比如chatGPT)。
「聊天助手」場景的特點是:用戶輸入自然語言,模型輸出自然語言。
自然語言對話
如果模型僅能輸出自然語言,那他的應(yīng)用場景只能局限在「聊天助手」。畢竟,「自然語言」只能作為LLM的輸入,沒法作為其他應(yīng)用的輸入。
比如,我希望做一個輿情監(jiān)控應(yīng)用,周期性爬取全網(wǎng)關(guān)于某明星的言論,再分析言論的情緒是否正向,最終統(tǒng)計全網(wǎng)對該明星的整體評價。應(yīng)用實現(xiàn)思路是:
- 全網(wǎng)爬取言論數(shù)據(jù)
- 分析每一條言論數(shù)據(jù),輸出「情緒是否正向」的判斷
- 統(tǒng)計所有言論對應(yīng)的情緒
- 分析結(jié)果
其中第二步,我們可以讓LLM判斷輸入的言論情緒是否正向。
當輸入「雞哥辛苦訓(xùn)練了兩年半」,LLM判斷這段話的情緒是正向后,可能回復(fù)我:
- 這段話的情緒是正向的
- 結(jié)果是積極的
- 這是一段積極的對話
- ...或者其他啰嗦的回答
雖然上述結(jié)果都表達了「情緒是正向的」,但輸出結(jié)果也是自然語言描述的,且結(jié)果句式并不穩(wěn)定,沒法輸出給第三步的程序做統(tǒng)計。
好在,LLM也可以輸出結(jié)構(gòu)化數(shù)據(jù)(比如JSON)或者代碼,其中:
- 如果能輸出符合其他應(yīng)用規(guī)范的JSON,其他應(yīng)用可以直接讀取使用
- 如果能輸出符合其他應(yīng)用的代碼調(diào)用,可以直接調(diào)用其他程序(通過RPC通信)
比如,我們讓LLM對上述問題輸出JSON格式的結(jié)果,可能的輸出如下:
// 可能的結(jié)果
{"result": "positive"}
// 可能的結(jié)果
{"emotion": "positive"}
// 可能的結(jié)果
{"sentiment": "good"}
雖然程序可以讀取JSON,但輸出的字段可能是不穩(wěn)定的。假設(shè)第三步的統(tǒng)計程序統(tǒng)計的是result字段,但我們第二步輸出的結(jié)果是sentiment(情緒的意思)字段,這就沒法使用了。
為了解決「用戶輸入自然語言,LLM輸出穩(wěn)定的結(jié)構(gòu)化數(shù)據(jù)或函數(shù)調(diào)用」的問題,openAI推出了一個新功能 —— function-calling[2](即函數(shù)調(diào)用)。
當我們調(diào)用openAI API時,參數(shù)依次傳入:
- 用自然語言描述的需求
- 對輸出結(jié)果函數(shù)的類型定義
LLM會輸出符合類型定義的函數(shù)調(diào)用。
比如,我們依次輸入:
- 需求:判斷「雞哥辛苦訓(xùn)練了兩年半」情緒是否正向
- 函數(shù)定義:
{
"name": "mark_sentiment",
"description": "標記輸入語句的情緒是否正向",
"parameters": {
"type": "object",
"properties": {
"prompt": {
"type": "string"
},
"sentiment": {
"type": "string",
"enum": ["negative", "neutral", "positive"]
}
}
}
LLM的輸出結(jié)果為:
mark_sentiment({
prompt: "雞哥辛苦訓(xùn)練了兩年半",
sentiment: "positive"
})
只需要定義mark_sentiment方法,用于存儲「言論對應(yīng)的情緒」即可。
function-calling功能極大擴展了LLM的應(yīng)用場景(chatGPT的插件功能就是通過function-calling實現(xiàn)的):
但是,function-calling同樣存在缺點,比如:
- 只受限于openAI的模型,其他模型(比如Llama 2)沒有該功能
- LLM的響應(yīng)只有一個函數(shù)調(diào)用,無法在一次響應(yīng)中調(diào)用多個函數(shù)
- 函數(shù)的類型聲明對開發(fā)者不夠友好,內(nèi)部實現(xiàn)比較黑盒,當返回的函數(shù)調(diào)用不符合預(yù)期時,不好糾錯
TypeChat的出現(xiàn)解決了上述問題。
TypeChat是什么,有什么用
在聊function-calling缺點時,我們提到「函數(shù)的類型聲明對開發(fā)者不夠友好」,那么什么類型系統(tǒng)對前端開發(fā)來說是最熟悉、友好的呢?
答案不言而喻 —— TypeScript。
TypeChat[3]是TypeScript之父「Anders Hejlsberg」(同時也是C#之父)發(fā)布的新項目,他可以根據(jù):
- 自然語言描述的提示詞
- 對輸出產(chǎn)物類別的定義(是「表示數(shù)據(jù)的JSON」,還是「表示函數(shù)執(zhí)行的JSON」)
- 對輸出產(chǎn)物的TS類型聲明
讓LLM輸出符合類型聲明的JSON數(shù)據(jù)。
比如,對于上述「判斷言論情緒」的例子,可以向TypeChat輸入:
- 需求:判斷「雞哥辛苦訓(xùn)練了兩年半」情緒是否正向
- 輸出產(chǎn)物是「表示數(shù)據(jù)的JSON」
- 輸出產(chǎn)物的TS類型文件如下:
// 下面是對用戶輸入情緒的類型定義
export interface SentimentResponse {
// 情緒的可選項
sentiment: "negative" | "neutral" | "positive";
}
LLM輸出的結(jié)果會被嚴格限制在上述TS類型。
如果要簡單的類比,可以認為TypeChat是使用TS定義類型的function-calling。但實際上,TypeChat的能力不止如此。
首先,TypeChat不和任何LLM綁定,只要能同時理解自然語言與編程語言的LLM都可以使用TypeChat。
其次,輸出產(chǎn)物是JSON,JSON除了可以表示數(shù)據(jù),還能表示多個函數(shù)的執(zhí)行過程,這樣LLM的一次輸出可以是多個函數(shù)的連續(xù)執(zhí)行。
舉個例子,下面是我們的輸入:
- 需求:計算如下算式:「1 + 2的結(jié)果乘以3,再除以2」
- 輸出產(chǎn)物是「表示函數(shù)執(zhí)行的JSON」
- 輸出產(chǎn)物的TS類型文件如下:
// 下面是對四則運算的類型定義
export type API = {
// 兩個數(shù)字相加
add(x: number, y: number): number;
// 兩個數(shù)字相減
sub(x: number, y: number): number;
// 兩個數(shù)字相乘
mul(x: number, y: number): number;
// 兩個數(shù)字相除
div(x: number, y: number): number;
// 對一個數(shù)字求負數(shù)
neg(x: number): number;
// id
id(x: number): number;
// 未知情況
unknown(text: string): number;
}
LLM輸出結(jié)果為「由JSON表示的函數(shù)執(zhí)行過程」:
{
"@steps": [
{
"@func": "mul",
"@args": [
{
"@func": "add",
"@args": [1, 2]
},
3
]
},
{
"@func": "div",
"@args": [
{
"@ref": 0
},
2
]
}
]
}
其中@XXX是TypeChat中的關(guān)鍵詞,比如:
- @step代表執(zhí)行步驟,每個index對應(yīng)一個步驟。
- @func代表這是個函數(shù)執(zhí)行。
- @args代表函數(shù)的傳參。
- @ref代表引用某個步驟的執(zhí)行結(jié)果。
經(jīng)由TypeChat內(nèi)部轉(zhuǎn)換后,得到如下代碼:
import { API } from "./schema";
function program(api: API) {
const step1 = api.mul(api.add(1, 2), 3);
return api.div(step1, 2);
}
也就是說,我們告訴TypeChat下述信息后:
- 我們希望計算:「1 + 2的結(jié)果乘以3,再除以2」
- 輸出結(jié)果要表示為「函數(shù)執(zhí)行」
- 每個執(zhí)行的函數(shù)要符合我們定義的TS類型
TypeChat輸出的結(jié)果為:
import { API } from "./schema";
function program(api: API) {
const step1 = api.mul(api.add(1, 2), 3);
return api.div(step1, 2);
}
并且,這個結(jié)果是穩(wěn)定的(即使多次執(zhí)行,輸出結(jié)果的函數(shù)名、類型定義都不會變)。
除了上述功能外,TypeChat最大的亮點在于 —— 他能夠?qū)敵鼋Y(jié)果自動糾錯。
因為我們有「輸出結(jié)果的TS類型聲明」,所以可以用TS編譯器檢查輸出結(jié)果是否符合類型聲明,如果不符合,TypeChat可以將「TS報錯信息」連同「輸出結(jié)果」再次輸入給LLM,讓他糾錯后重新輸出。
比如,對于上述「檢查言論情緒」的例子,如果輸出結(jié)果為:
{sentiment: "good"}
經(jīng)由TS編譯器檢查后會報錯:
Type '"good"' is not assignable to type '"negative" | "neutral" | "positive"'.
TypeChat會將上述報錯信息連同輸出結(jié)果再輸入給LLM讓他糾錯。
TypeChat實現(xiàn)原理
TypeChat的實現(xiàn)原理可以用一張圖概括:
其中:
- 紅色路徑輸出結(jié)果為「表示數(shù)據(jù)的JSON」
- 藍色路徑輸出結(jié)果為「可執(zhí)行的代碼」
對于紅色路徑,以上述「檢查言論情緒」為例,TypeChat輸入給LLM的提示詞類似這樣:
你是個將用戶輸入轉(zhuǎn)換為JSON的系統(tǒng),轉(zhuǎn)換需要遵循下面的TS類型聲明:
${輸出產(chǎn)物TS類型聲明}
下面是用戶的輸入:
${"雞哥辛苦訓(xùn)練了兩年半"}
下面是用戶輸入轉(zhuǎn)換為JSON后的結(jié)果:
LLM接收以上提示詞后輸出JSON。
對于藍色路徑,以上述「四則運算」為例,TypeChat輸入給LLM的提示詞類似這樣:
你是個轉(zhuǎn)換系統(tǒng),將用戶輸入轉(zhuǎn)換為由JSON表示的程序,轉(zhuǎn)換需要遵循下面的TS類型聲明:
${對@step、@ref、@func等如何使用的類型聲明}
程序可以執(zhí)行由下面的TS類型定義的函數(shù):
${輸出產(chǎn)物TS類型聲明}
下面是用戶輸入轉(zhuǎn)換為JSON后的結(jié)果:
LLM接收以上提示詞后輸出代表程序執(zhí)行的JSON,該JSON再經(jīng)由TypeChat轉(zhuǎn)換后變?yōu)椤缚蓤?zhí)行的代碼」。
對輸出產(chǎn)物的糾錯
如果LLM返回的JSON有TS類型錯誤,那么TypeChat會拼接出下面的提示詞,并輸入給LLM:
${報錯的JSON數(shù)據(jù)}
上述JSON對象由于下述原因?qū)е滤欠欠ǖ模?${TS報錯信息}
下面是修正后的JSON:
TypeChat對前端行業(yè)的影響
不止是前端工程師,當前程序員使用LLM的主要方式還是:
- 用自然語言描述一段代碼需求
- LLM輸出代碼
- 程序員修改輸出的代碼,為項目所用
而業(yè)界預(yù)期的LLM終極形態(tài)是:產(chǎn)品經(jīng)理用自然語言描述產(chǎn)品需求,LLM直接寫代碼。
如果達到這種程度,程序員就完全沒有存在價值了,這也是大部分程序員焦慮的原因。
那么,制約「達到終極形態(tài)」的因素有哪些呢?有三點:
- LLM對「自然語言描述的需求」的理解能力
- LLM一次處理的提示詞長度(token數(shù)量限制)
- LLM生成代碼的穩(wěn)定性
對于第一點,當GPT-3.5出現(xiàn)后,好像LLM的理解能力突然上了好幾個臺階。所以,大家會焦慮是不是再過幾年,LLM的理解能力突然又爆發(fā)性提高,能夠完全理解自然語言描述的需求。
對于第二點,GPT-3.5有「最多4096token」的限制,但這一限制正在逐步放寬。這意味著在不遠的將來,LLM能夠輸出的代碼量會越來越多。
正是預(yù)見到以上兩個因素的變化趨勢,導(dǎo)致程序員產(chǎn)生「假以時日,會被AIGC取代」的焦慮。
但我們發(fā)現(xiàn),要達到終極形態(tài),還要考慮第三個因素 —— LLM生成代碼的穩(wěn)定性。
也就是說,LLM雖然可以幫我們編寫函數(shù)代碼、模塊代碼,但如果這些函數(shù)、模塊的代碼是不穩(wěn)定的,他們就沒法配合使用,需要工程師手動修改。
如果LLM生成的代碼經(jīng)常需要工程師手動修改,那就限制了「它能夠自動生成代碼的規(guī)?!?,那么他只能淪為工程師的編程助手,而不是取代工程師。
而要解決「生成代碼的穩(wěn)定性」問題,不管是通過openAI的function calling,還是TypeChat,都需要工程師能夠?qū)Ξa(chǎn)物做出精準的類型定義。
這就形成了一個悖論 —— AIGC要想取代工程師獨立完成項目,需要能生成穩(wěn)定的代碼。而為了生成穩(wěn)定的代碼,需要工程師理解業(yè)務(wù)邏輯后,編寫詳盡的類型聲明。
為了取代工程師,還需要工程師積極參與?那取代個der。
這頂多算是一種編程范式的遷移,類似之前前端用jQuery開發(fā)頁面,后來遷移到用前端框架開發(fā)頁面。
未來,前端工程師編寫詳盡的類型聲明,LLM再根據(jù)聲明生成框架代碼。就像現(xiàn)在前端通過框架編寫「狀態(tài)變化邏輯」,框架再去執(zhí)行具體的DOM操作一樣。
總結(jié)
有些同學(xué)會焦慮 —— 未來是AIGC的天下,我要不要轉(zhuǎn)行搞人工智能?
實際上,通過本文,我們能感受到一種趨勢,未來將會分化出三種工程師:
- 搞AIGC算法研究的工程師
這類工程師人數(shù)很少,都在頭部互聯(lián)網(wǎng)企業(yè)或人工智能企業(yè)的實驗室中。
- 負責公司AIGC基建的工程師
這類工程師負責將上一類工程師的產(chǎn)出與公司業(yè)務(wù)結(jié)合,他們的工作職責包括:
- 評估、部署各種開源模型
- 會使用各種工具,比如langChain、Pincecone,當然也包括本文介紹的TypeChat
- 根據(jù)公司業(yè)務(wù)場景,落地AI基建
- 業(yè)務(wù)工程師
比如前端工程師、后端工程師、全棧工程師。他們會在AIGC基建工程師開發(fā)的基建上,進行業(yè)務(wù)開發(fā)。
前端這個崗位會持續(xù)存在,只是要求會更高(對業(yè)務(wù)的抽象能力)、從業(yè)者會更少。
可以簡單的做個比喻,如果你當前小組的構(gòu)成是:
- 一個對業(yè)務(wù)更理解的前端組長
- 幾個負責業(yè)務(wù)開發(fā)的中級前端
那么未來的構(gòu)成會是:
- 一個理解業(yè)務(wù)的高級前端(可能是之前的前端組長),負責對業(yè)務(wù)進行抽象
- 編寫具體業(yè)務(wù)邏輯的AIGC基建
參考資料
[1]TypeChat:https://microsoft.github.io/TypeChat/。
[2]function-calling:https://openai.com/blog/function-calling-and-other-api-updates。
[3]TypeChat:https://microsoft.github.io/TypeChat/。