發表文章

極速ChatGPT開發者兵器指南 - 推薦序

圖片
這是出乎我意料之外的事情。 今(2024)年2月中旬的一個晚上,那時才開工沒多久,大家估計還在農曆年節的休假氣氛中。我邀請了本書的三位作者,一同來我的線上直播節目接受專訪。 談論的主題,當然是過去一整年資訊界無人可忽視的 --『生成式AI』。當天精彩的訪問與對談,在這邊我暫不贅述,有興趣的朋友可以在YT頻道搜尋 『.net walker - 與微軟AI MVP大神漫談生成式AI的發展與未來』,或掃描底下QR Code觀賞。 讓我出乎我意料的是,當天即時觀看的線上人數和日後點閱的人數,雙雙突破過去的紀錄,這還是在年假剛過、開工不久、加上沒有任何廣宣的狀況下。 當時,現場網友詢問問題之熱情,讓我和三位受訪者(也就是本書的三位作者),幾乎無法結束訪談,即便早已超過原本預定的受訪時間。 在節目現場,我的這三位好友,在我和線上網友的聯合提問夾擊之下,分享了生成式AI相關的許多重要技術概念,包含Embedding、RAG(檢索增強生成)、Semantic Kernel、向量資料庫…等,整個對談暢快淋漓、欲罷不能。 由於時間的限制,即便明知還有許多議題和網友提出的問題都還沒談到,身為主持人的我,也不得不讓三位作者暫時喘口氣。但讓人興奮的是,當天作者們分享的內容,以及後來來不及談論到的更多深入議題,都出現在您現在所看到的這本書當中。 這本書,有技術、有實務,而且有為數不少的實作範例,由三位身為微軟MVP、在AI領域首屈一指的專家們共同著作,相信對需要深入了解生成式AI應用與相關技術的你,是絕佳的選擇。 如果您遺漏了他們合著的上一本著作,這次,千萬別再錯過。 Microsoft Regional Director / Microsoft MVP / 光岩資訊資深技術顧問 董大偉

周末讀書會 - 一如既往

圖片
一般來說,我都是看完整本書之後,才會決定要不要推薦,能讓我還沒看完就忍不住推薦的書極少。 但『一如既往』,就是這極少中的之一。 這本書的主題很難界定,你既可以說它是在談投資、也可以說他在談經營或企管、有些內容說的是競爭、但有時候你會覺得他講的是人生。 然而重點在於,這本書寫得非常好看。 我超愛的科幻小說家倪匡,曾說過:『好看的小說非常簡單,必定要有豐富的情節、鮮活的人物,小說寫得不好看,裏面有再多的學問、道理、藝術價值,都沒有用。』 一如既往,這本書的作者厲害之處,就是他能夠把每一篇都寫得環環相扣、異常好看,然而即便我知道每篇文章的pattern,想要模仿也是很難(這是個苦功來著)。 基本上那個pattern就是…以引人入勝的故事開頭,使用對照法讓故事撐托出主題,以極具說服力的文字或數據讓主題凸顯出價值,讓讀者有所收穫,最後在最短的文字內把一篇文章總結,然後預告下一篇作者想要接著談論什麼。 就這樣,你會一篇接著一篇,不由自主的閱讀下去,每一篇,你都會有一些驚訝、會有一些省思、接著會有一些take a way。 整本書,看似信手拈來、行雲流水,一氣呵成。但我知道,這是精心設計與編排後的結果。 一本書,最要緊是好看。 好看,讓人讀得下去,裡面豐富的內容才對身為讀者的你有意義。 『一如既往』這本書做到了,而且做得很徹底。 我快看完了,看完之後,如果有時間,我還想針對裡面某幾篇特別分享,如果你等不及,不妨先找來看看。

使用Azure AI Question Answering 快速建立客服機器人

圖片
還記得疫情那時候嗎? 有一段時間,醫療院所內的護理師面對應接不暇的來電,都是為了詢問跟疫苗有關的問題。像是: 疫苗施打的順序? 何時可以輪到我? 如果有過敏該如何選擇? 注射時應該要注意些甚麼? 我能不能不打疫苗? 諸如此類的詢問,塞爆了正常的電話掛號系統,導致許多真正需要幫忙的病患,無法得到該有的醫療資源以及諮詢,而護理師也無法專注於本來應該進行的護理工作。 這時,有些醫院開始導入對談機器人,透過手機APP或是網頁,可以讓一般民眾詢問疫苗相關的問題,並且提供正確的回覆。 當時,還沒有 ChatGPT 這樣的大型語言模型,醫院的資訊單位也不是AI領域的專家,要如何在極短的時間內,建構出一個可以準確回答用戶疫苗相關QA問題的對談機器人? 來幫助醫院在面對突乎其來的詢問電話時,可以透過分流來舒緩客服壓力? 答案,就在底下這個影片裡。我們從這個影片中可以看到,要如何在幾分鐘內,將既有的 知識庫 轉換成對談機器人,讓用戶可以直接透過網頁或手機問問題: 底下這個影片,加碼介紹如何把這個QA對談機器人,變成LINE Bot(也就是LINE官方帳號),讓用戶只需要用LINE就可以直接得到答案: 參考 課程: https://www.studyhost.tw/NewCourses/LineBot

使用 GitHub Copilot 建立單元測試

圖片
過去,只要上到 DevOps 課程,我就會強調單元測試在 CI/CD Pipeline中的重要性,絕對是屬於必須的(must have)。自動化頻繁交付想要不斷的交付(產生)價值,而不是不斷的產生bug,那單元測試絕對不可或缺。 你可能會想,那最近幾年,敏捷開發與DevOps這麼普及,大家都號稱能夠頻繁交付,那想必單元測試實施的比例肯定也很高,對吧? 答案是:『不,並沒有』。 因為,開發團隊不寫單元測試的理由,比寫單元測試的理由實在多太多了,例如: 測試程式本身需要花額外的時間 寫功能/趕進度 的時間都不夠了,怎麼有時間寫單元測試 不是每一個人都知道怎麼開始寫 方法(Mrthod)或類別的 相依性/耦合度 太高,難以撰寫單元測試 團隊中沒有這個氛圍,推動沒多久就無疾而終 PM或老闆不認為單元測試有價值 … 隨手都可以舉出一大堆,這些都是上課時問學員,學員真實的回答。沒辦法,每個團隊都有各自難念的經,我尊重。 不過,那是去年。 今年開始,有一個非常大的理由,讓我覺得,可以重新要求開發人員,把 Unit Test 的建立視為標配,並且放入每一個 CI Pipeline當中。 沒錯,又是AI。 現在,透過 GitHub Copilot 你可以更輕鬆的建立單元測試,你可以用 GitHub Copilot 幫你產生測試案例,也可以用 GitHub Copilot 幫你重構,或是調整主程式,以配合單元測試的運行… 過去覺得需要花費大把時間、耗費許多工夫的作業,如今 GitHub Copilot 可以幫我省去近一半的時間。卡關不知道該怎麼做的時候,還能跟 GitHub Copilot Chat 聊聊,技術問題迎刃而解。 我底下錄了一段影片,展示了如何使用 GitHub Copilot 建立單元測試。如果,你的團隊過去也屬於(有諸多原因導致)無法傳寫單元測試的一族,不妨看一下影片,或許在新的一年,將有不同的可能性出現? 參考 課程: https://www.studyhost.tw/NewCourses/ALM

在POC或迷你專案中使用 LiteDB

圖片
3/24,我發了篇FB 貼文 ,提到我很久沒有在撰寫範例的時候使用關聯式資料庫了。這不是因為關聯式資料庫不好,而是使用場景和情境的問題。 大部分的教學文章或範例,為求讓主題專注不要失焦,我會讓範例盡可能地簡單。例如,用Console App 取代 Web 架構,用file取代DB。這樣學員的進入障礙會再降低一點,畢竟,我們不能假設每一位學員都對MVC框架或是資料庫存取的ORM有認識。 那篇貼文得到不少迴響,其中有位讀者建議,也可以考慮用 LiteDB ,我當時回覆說我會找個時間來試試看。既然說了出口,肯定是必須要測試一下的。 LiteDB 技術上來說,LiteDB 是一個嵌入式的 NoSQL 資料庫,特別是針對 .NET 開發者設計。其本質上是一個檔案,但它提供了類似於傳統關聯式資料庫管理系統的功能,包括存儲、檢索、更新和刪除資料操作。LiteDB 以單一檔案的形式儲存在專案資料夾中,這使得它非常適合於輕量級應用。不管是desktop app、mobile app或任何需要資料庫但又不希望安裝重量級資料庫伺服器的情境,都很適合。 你只需要針對專案安裝 NuGet 套件就可以使用: dotnet add package LiteDB 不需要伺服器、不用管帳號密碼、可以跨平台,所有的資料都存儲在單一檔案,便於管理和分發、佈署。簡單的說,當我寫好範例,在裡面放一些資料,丟上GitHub,你不管在哪一個平台(Windows, Linux),Clone下來之後,無須任何配置、設定,就可使用,資料也不會消失,無須重建。 確實,這對做範例非常方便。 你可以看看我在GitHub上的這個範例: git clone https://github.com/isdaviddong/TestLiteDB.git 下載下來之後,無須任何設定,直接 dotnet run 就可以執行: 專案中,包含了一個MyData.db檔案,就是資料庫實際儲存的位置: 你可以透過底下這樣的程式碼,即可使用: var db = new LiteDatabase ( "MyData.db" ) var col = db . GetCollection < Person > ( "persons" ) ; 其

使用 Airtable 在小型需求上取代傳統資料庫

圖片
我好幾年沒有用傳統的關聯式資料庫了。 老實說,傳統的關聯式資料庫,其實對於教育訓練和小型的專案來說,是一種負擔。 如果你想讓學員清楚的掌握一門技術,就好比說,對談機器人的開發吧,在整個教學的過程中,若是範例用到SQL或MySQL資料庫,無疑是一種節外生枝,把問題變得更複雜。因為,在對談機器人當中,儲存只是一種迫不得已的額外需求,是枝微末節,而非對談機器人技術的主體。 同樣的,如果你做一個小型專案或POC的話,『儲存』也往往不是重點,儲存只是『必要之惡』。其實,若是從這個角度廣義的來說,軟體開發的GUI、資料庫,都只是細節(枝微末節),都應該要是可以隨時被抽換或取代的部分,而非系統核心。 一套軟體或解決方案的真正核心,是商業邏輯。它(商業邏輯)才是一個應用程式真正展現價值的部分。 我們把主題拉回來。所以,我最近這幾年在上課的時候,盡量不讓範例程式碼涉及資料庫存取,特別是關聯式資料庫的存取。因為這對讀者或學員來說,變成了另一種必須學習的負擔。 但說的容易,如果範例中有碰到需要儲存資料的時候該怎麼辦呢? 有沒有什麼最簡單的儲存機制可以在程式碼中替代傳統資料庫? 這也是我最近幾年寫範例的時候,常常碰到的問題。因此,我特別花了一段時間,找看看有沒有什麼好用的『類』資料庫儲存體? 最後,我選擇了 Airtable。 Airtable Airtable 是一個靈活的雲端資料庫產品,結合了資料庫的功能和電子表格(data grid)的簡易性。它允許用戶以視覺化的方式存儲、組織和協作各種資訊: 白話一點說,就是它可以很自由的在Web畫面上設計欄位和維護(輸入、編輯)資料。 對我來說,它還有另一個重點,就是它擁有非常簡單的REST API,透過呼叫API就可以直接來讀寫資料。 它的API在使用上很簡單,只需要在設計好資料表之後,透過 https://airtable.com/create/tokens 站台建立一個 PAT(Personal Access Token): 建立PAT的時候,可以選擇要針對所有資料表,還是特定資料表,要只給這個token 讀取(Read)權限,還是要寫入(Write)權限: 有了token之後,可以透過很標準的REST API呼叫,進行連線的建立與資料的寫入: string ID = "👉air_tabl

Azure Web App 的基本驗證被停止了!

圖片
如果先不管自動化CD Pipeline,習慣使用Visual Studio的開發人員,若要對 Azure Web App 佈署網站,大概最喜歡採用的佈署方式,莫過於『發行設定檔』。這一招用很久了,直到最近你可能會發現,建立Azure Web App 的時候,會看到底下這樣的警告: 這也意味著,你無法下載發行設定檔了: 如此一來,Visual Studio 當然也無法佈署了! Azure 這個調整,當然是為了安全性提升。 使用基本驗證不安全嗎? 對,相對來說是的。 因為基本驗證只透過一組帳號密碼來做佈署,再加上發行設定檔還把這組帳密直接給放在裡面,誰拿到了這組帳密都能夠更新網站,沒有進一步的身分驗證,對一般個體戶小型專案的開發人員來說還行,但對企業來說顯然不是一個理想的選擇。 好吧,但這樣比較簡單啊。假設,你只是要快速的進行佈署,我們是否可以先把這個被 disabled 掉的功能暫時開啟呢? 可以的,在 Azure WebApp 的組態設定,將『基本驗證發佈認證』給開啟即可: 如此一來,發行設定檔又可以下載了(記得把網站 reload 一下): 下載到發行設定檔之後,我們在Visual Studio當中可以透過底下這樣的方式佈署網站: 然後選擇剛才下載的發行設定檔即可。 這種佈署方式雖然方便,但就如同前面說過的,發佈的過程並沒有嚴謹的身分驗證,也不支援AAD帳號或是RBAC等權限配置。因此,短期暫時將傳統的基本驗證開啟,取得發行設定檔佈署即便可行,建議未來還是採用AAD(Entra ID)驗證是比較理想的做法:

Semantic Kernel Plugin 的錯誤處理

圖片
先前我們 提到了 透過Semantic Kernel,可以讓AI/LLM在與用戶對談的過程中,自動在需要的時候去呼叫 PlugIn 物件的方法(Method),特別的事情是,這個呼叫並非是我們寫程式去做的,而是 AI 自己做的,我們並沒有寫這部分程式碼的邏輯,我們寫的只是提示(prompt)而已。 那問題來了,如果不是我們寫程式去呼叫這個方法,而是AI自己去呼叫的,那假設,這個被呼叫的方法裡面發生了 Exception ,那會發生什麼事情!? 我們看底下這段程式碼: public class LeaveRequestPlugin { [KernelFunction] [Description("取得請假天數")] public int GetLeaveRecordAmount([Description("要查詢請假天數的員工名稱")] string employeeName) { isRock.LineBot.Bot bot = new LineBot.Bot(ChannelAccessToken); bot.PushMessage(AdminUserId, $"[action : 查詢 {employeeName} 假單]"); if (employeeName.ToLower() == "david") return 3; else if (employeeName.ToLower() == "mary") throw new System.ArgumentOutOfRangeException("無法取得假單資料"); else return 5; } (...略...) } 請注意上面這段查詢員工請假天數的程式碼,你會發現,我們刻意在程式碼裡面,加入了底下這段 code: (...略...) else if (employeeName.ToLower() == "mary") throw new System.Ar

在 LINE Bot 開發中使用Semantic Kernel建立自然語言請假系統

圖片
身為 LAE(LINE API Expert) 與 LINE 的支持者,既然知道透過Semantic Kernel可以快速的開發對談機器人,那當然要嘗試用在 LINE Bot的開發上。 先前我們 介紹過 如何使用 Semantic Kernel 來開發一個支援記憶與對話前後文、可以用自然語言進行請假的對談機器人,但當時的架構是在 console 環境,負責記憶處理的 ChatHistory 是可以被長時間保存的實體物件,但換成了LINE Bot開發的WebAPI架構,一切就變的有所不同了。 首先,由於ChatHistory物件會隨著WebAPI行程消失而遺失,且我們的LINE Bot還得面對多個用戶,因此也無法簡單的用一個 ChatHistory 物件就保存所有用戶的對話紀錄。所以我們要做一些調整,為每一位用戶建立一個自己的ChatHistory物件。 因此,我們在 WebAPI 中撰寫了底下這樣的程式碼: static Dictionary<string, ChatHistory> ChatHistoryByUser = new Dictionary<string, ChatHistory>(); private ChatHistory getHistoryFromStaticRepo(string UserId) { if (ChatHistoryByUser.ContainsKey(UserId)) return ChatHistoryByUser[UserId]; else return new ChatHistory(); } private void saveHistory(string UserId, ChatHistory chatHistory) { if (ChatHistoryByUser.ContainsKey(UserId)) ChatHistoryByUser[UserId] = chatHistory; else ChatHistoryByUser.Add(UserId, chatHistory); } 這段程式碼以靜態方式儲存ChatHistory物件的Dictionary,搭配 getHistoryF

使用Semantic Kernel 建立自然語言請假系統

圖片
既然我們已經知道,可以透過 Semantic Kernel 輕易地建立聊天機器人/智能助理,我們之前(參考 這篇 )也看到了如何用自然語言驅動 AI ,來自動呼叫 IoT 控制開關燈類別中的方法,體驗過了它的威力,接著,我們就來實作一下,如何透過 Semantic Kernel 來建立一個可以透過自然語言請假的對談機器人。 我得說,我過去幾年做過無數次這個範例,試圖用自然語言以對談方式來完成請假。從最初LINE Bot 出現的時候,以手工苦刻的方式,來建立請假機器人,到使用 Azure AI 上的 Language Understanding 解決方案,讓機器人能夠『稍微』看懂用戶以自然語言的方式輸入的請假資訊,但整個過程從來沒有愉快過。 過去,電腦對自然語言的理解實在太差了,直到GPT的出現,直到有了LLM,一切才開始不同。現在,我們可以輕易地透過 Semantic Kernel 使用大語言模型,來建立一個類似底下這樣,表現非常好的自然語言請假系統: 你會發現,我們實作了一個可以幫助用戶請假的對談機器人。他會蒐集用戶的請假資訊,然後在資訊滿足之後,呼叫API來完成請假動作。 上面這段對談紀錄當中,黃色的部分就是AI自動進行的 Action,也就是具體的『請假』或是『查詢』動作,其他的則是自然語言的交談對話。 我們之前說過,透過 Semantic Kernel ,我們可以快速地完成上面這個功能的開發。為了完成這個需求,我們建立了底下這個 LeaveRequestPlugin 類別。這個類別裡面有三個方法,你可以從Description描述看到這些方法的功能(當然,範例裡面的Action暫且用示意的方式來呈現,不真的寫入資料庫): // 請假功能 Plugin public class LeaveRequestPlugin { [KernelFunction] [Description("取得請假天數")] public int GetLeaveRecordAmount([Description("要查詢請假天數的員工名稱")] string employeeName) { //修改顯示顏色 Console.ForegroundColor = Con