2026年1月27日

開源AI-Agent聊天室 (OpenSource AI-Agent ChatRoom) - SongAiChat

前言:

之前曾在Threads上分享過別人寫的AI-Agent聊天室的MCP工具,但我用起來總覺得沒有很好用。
我在開發時,會遇到需要不同AI-Agent間通訊的問題,常見的就是跟AI-Agent說:
你給我一段說明,我轉給另一個處理的AI-Agent,然後問另一個AI-Agent,你看了有什麼疑問要我轉達?
或者是跟AI-Agent說:
你撰寫一份串接文件,我給其他AI-Agent閱讀和實做。
不論哪種,都要人工轉發,那是否能夠有一個聊天室,讓每個AI-Agent在裡面自己對話,我也能在裡面參與或了解對話內容呢?能夠紀錄更好。
於是,就有了寫個聊天室的念頭。

成果:

整份專案在
https://gitlab.com/ycfunet/songaichat

設計過程:

這套聊天室的設計過程很復古。😆
我其實想的原型是很早期的CGI聊天室,那種一堆人在裡面,然後一直洗版的那種聊天室,因此版面和系統設計借鑒了早期那種聊天室設計,加上了WebSocket(這邊我用的是SignalR)長連接的功能,達到即時通知的功能。
名字雖然是Song,但跟唱歌一點關係都沒有😂,它的命名是起源於高中松山工農時期的BBS站~松間小棧,我是那時候的站長😅。
因為源於松山 - Songshan,因此取前面的Song😁。
設計過程很復古吧。

實做過程:

這次實做換成Gemini-CLI實做。
Gemini-CLI使用感覺反應慢很多,可能是現在很多人在使用,很容易忙碌吧。
但以寫程式碼的穩定性,尤其是前端,感覺比GLM-4.7穩,React + FluentUI基本上一次完成,版型也沒什麼大問題,配色也是標準正常。
不過Gemini-CLI很多時候問它問題,它想到就直接改下去了,然後改的方向或作法可能是錯的,這時候就得從git退版,因此Gemini-CLI和GLM-4.7的git版控很重要,要經常讓它commit,有問題隨時退版。

這個版本目前算是v0.8.5 Beta,基本能用,還沒有仔細測試,每次測試都會修改增加功能或調整,因此沒有完整一輪測完,但基本功能使用上沒什麼問題。

雜談:

DotPusher之後,我原本寫OmniPusher,實做Electron版的WebFcm和WebPush推播,但實做差不多了才發現,Electron在WebFcm與WebPush相容性有問題,靠~於是就放著了。
另一點是,OmniPusher用GLM-4.7實做前端,寫的有點卡,讓它計劃書內畫Wireframe都畫了,結果實做時直接偷工,Sidebar沒處理乾淨,Main Content直接沒做,叫它用FluentUI做,又做成HTML簡易版,連基本的標題列和副標題列樣式都沒處理,變成單純的HTML,然後越改越撞busy,蠻昏倒的,寫到真的是不想看。

另一個點是這樣的,SongAiChat主要作用是AI-Agent間對話用的,我在考慮撰寫用AI開發比較大的專案,目前打算寫套名為GreeStorage的儲存系統,GreeStorage名字取自Great Storage的諧音
以前有段時間專門在弄Ceph,Ceph是Object Storage分散式儲存系統,架構比較大,那個作者很妙,作者就寫Ceph,一路寫一路發Paper,寫了10幾篇寫完博士讀完😆,然後就成立了公司賣儲存系統,接著又被RedHat收購。重點是,因為架構比較大,各組件也多,我在想有沒有可能定好架構後,一段一段讓AI寫,可能每個AI負責一段,然後就透過聊天室互相溝通和串接。這目前還在初期想法階段,如果能做出來,應該很屌😆。


2026年1月16日

開源推播通知服務閘道(Push Notification Service)系統 - DotPusher

前言:

手機要收通知,通常需要個Line、Telegram、DCard之類的通訊軟體,或者是pushover之類的推播軟體,如果是Line、Telegram串接太複雜,pushover要收費,原理不難,而且有現成的gorush可以參考,乾脆自己做。

成果:

整份專案在
https://gitlab.com/ycfunet/dotpusher

實做過程:

實做過程還好,事實上,整個專案還未完成,它的完整版應該包括2塊:
  1. DotPusher - 推播閘道:這個是把各平台的推播轉換成簡易的RESTFul API呼叫,並加上Queue處理
  2. OmniPusher - 使用者推播服務:這個是個推播帳號註冊平台,目前參考pushover實做中,它的功能是註冊使用者,綁定裝置到使用者,推播給使用者時,底層會直接呼叫DotPusher API進行裝置推播,其實就是使用者轉換成裝置的服務平台
設計上,DotPusher可能放在雲端,OmniPusher則可能放在Web應用服務端,甚至可能整合到Web應用服務當中。
DotPusher的定位是能支援各個推播平台的推播服務,目前能支援MacOS/iOS的Apple APNS、Android/Web的Google FCM、Web原生的WebPush,正在實做Windows的WNS以及華為的Push Kit。

喔~對了~測試過程中,Android收FCM遇到,連發3次,但只收到第1次,後面幾次收不到,雖然AI是說FCM節流,但我猜可能是Android端實做有問題,因此目前Android端測試程式沒放。

結論:

這次結論比較特殊 😄
這次的專案實做有個很大的不同點,這次第一次用GLM-4.7的Claude-Code開發,使用心得是:
以程式開發來說,GLM-4.7和Opus, Sonnet相比,基本上差異不大
Opus, Sonnet的語句理解能力的確比GLM-4.7精確,另外一個有趣的點是,GLM-4.7比較不討論,直接就做了,對話的語句比較少,跟它說,按照「這樣這樣」修改,它就改成「這樣這樣」,如果是Opus, Sonnet則會潤飾後寫出。
Opus, Sonnet通常會討論,會回應,你是否想這麼做,或者說,你覺得下面這些方案如何,GLM-4.7則比較直接回覆「你想要怎麼做?」,也比較不幽默 😄,我跟它說作者要寫你唷,它就只是把作者加上它名字,但在Opus, Sonnet則會說,我感到很榮幸。


2026年1月7日

開源 OIDC 單一登入(Single Sign-On, SSO)系統 - SSO-Yarper

 前言:

家裡有些Web服務使用反向代理,有網站沒有認證功能,需要個SSO。
之前工作做過SSO SAML IdP,這次就嘗試OIDC IdP + 反向代理 + Cookie-Based授權閘道。

成果:

整份專案在
https://gitlab.com/ycfunet/sso-yarper

實做過程:

這個實做其實不太順利,最早讓claude-code寫過OAuth2 Demo Site,看起來會動。
之後又讓claude-code寫過OIDC IdP,但OAuth2和OIDC IdP卻寫出不同的程式碼內容。
再者,claude-code寫yarp不太行,它會一直混淆yarp的設定檔設定,以及.NET Middleware,甚至都跟它說,就是要用yarp的pipeline都還會改在Middleware,最後是自己參考Microsoft的yarp sample實做後,要求claude-code按照我寫出的sample進行修改,並且指定修改程式碼位置才改出。
因為反向代理本來就有在用,要測試就得先關閉原服務測試,因此斷斷續續實做sso-yarper。
另外,早期規劃是把oidc和yarp實做在一起,但實際測試發現,yarper內的路由會和oidc的登入頁面衝突,登入頁面是SPA純前端,它會透過path在前端路由,yarper在認證狀態時,也會需要path,這造成兩個功能衝突,因此後來直接拆開,oidc idp歸idp,yarp認證時則改做成oidc rp,跳轉認證。
這套程式從DBML可以看得出,實做的時間跨度很長,事實上也在家裡運作一段時間了,還不錯用。

結論:

OIDC SSO是頗有價值的實做,跟Yarp結合是很關鍵的實現,cloudflare的零信任架構其實就是相同作法,透過反向代理與認證結合,做到Web Service安全防護。

2026年1月3日

雜談: AI Fine-tuning之我見,為何要Fine-tuning AI模型?

這是一篇雜談,自以為是的認知。😂

我先前在survey gemma3:270m fine-tuning時才發現,gemma3是不支援MCP的,而Twinkle AI的成果有把MCP功能,也就是function call的能力加進去。

於是我就疑惑了,看了才發現AI的秘密 - Tokenizer,也可算是Embedding模型,它作用是分詞,把整句話切成一個個單字、名詞、動詞。

LLM起手式第一動就是分詞模型分詞,這個分詞的詞就是Token,然後根據模型把每個Token的結果回覆。 簡單說,「這裡有一隻貓。」,經過Tokenizer之後,會切成「這裡」「有」「一隻」「貓」「。」,這一個個詞,會轉換成數字(句點會變成<end_oooooo>,這樣的特殊tag😁),稱為「Token」。

MCP的核心其實是function call,而function是以tag(<function>)的形式加在資料集裡面訓練的,沒有這個定義,AI不會知道要呼叫工具。 

白話說,<func>要定義在Tokenizer,要描述在Training Datasets,兩者都有,訓練後AI才會用工具。 今天的慶生會詢問後證實了,<function>無法透過RAG讓AI模型了解,只能透過fine-tuning在訓練集和Tokenizer加入。

例如:
Tokenizer 裡面定義 <func> = 呼叫工具 DataSet 裡面有一筆「問題: 請問台北的天氣如何?」「答案: 台北的天氣<func>。」

訓練後,當詢問時,如下:
「新竹現在天氣好不好?」
「天氣有<func>」=> 「是否允許呼叫 weather function 擷取天氣資訊? true」
「新竹的天氣,目前溫度58度,濕度125%」

最近LVA,機器人模型有些討論,但我們先不討論物理知識相關的訓練集處理,如何控制機器人? 機器人如何知道「往前走」=「A motor+B motor+C motor+D motor」的連續操作?是不是需要<function>。

非常多年前還在學校時,當時選修柔性計算有幾個機械系同學在做機器人,當時問他們,怎麼讓機器人動作? 它們跟我說: 「機器人所有關節都是伺服馬達,一個姿勢等於所有馬達的特定角度,可定義為一個frame,走的連續動作等於播放frames,像動畫片」 底層控制不會變,但LLM介入後,也許連續動作的控制能變成LLM自動生成。

那以前或者目前怎麼做? 常見的方式是人做動作後錄製,例如: 人彎腰,透過攝影機和關節姿勢擷取後,轉換成各個關節以及伺服馬達的角度,並且錄製。 接著讓機器人按照這些錄製的結果播放,因此很久前會看到機器人跌倒後,先定住,然後很制式的特定動作站起來。 這也是大陸很常看到的狀態,或者看到有人遙控機器人的情況。 Elon Musk機器人厲害的地方是,你看它動作行雲流水非常自然,這表示它各個關節的動作已經不是制式的play frames,而是根據動作,由LLM自動自然的生成,根據的不是單純的frames,而是有點像End-to-End的方式,讓AI直接理解行為,理解動作,把行為直接轉換成frame(motor控制動作)。

放了1個月沒提的知識點😁

結論:

訂閱AI重要,但AI fine-tuning模型裡面有些知識點,沒做過不會發現🤫  整理DataSets是苦工,而且不說沒人知道,說了也沒人知道能幹麻,它是「開發AI」的基礎,但不是AI應用的成果。 Fine-Tuning很重要,但參加活動問了人之後發現,幾乎都建議直接用RAG,我認真想過,也和AI討論過😂,目前Fine-Tuning在一般AI應用或開發中,成效有限,相同作用基本上都能在RAG中完成,除了Custom Tokenizer和Custom function之外。😂

發想:

基於貓砂機馬達控制FCM的延伸思考,結合function call和彈性化的增減function call工具的使用。 我在想是否根據特定情境修改和調整資料集,custom function tag,讓它能適應特定特殊應用。 而這點帶出2個延伸

一個是,以既有資料集修改增加tag以滿足特定問答時的特定工具應用。

一個是我在想的,用模板語言與特定語法進行Fine-Tuning,因為模板語言語意、語法和既有AI模型重疊度比較低,對於已有的模型影響也許比較小,那麼就能教會AI看特定的模板語言,就想像成我們用模板語言定義了瓦干答語,這個語言根本不存在,Fine-Tuning時等於讓AI學一個全新語言。 學會後,我們在RAG中根據瓦干答語~不是,是模板語言,寫出制式的語句和答案,那麼AI就能根據RAG查詢的的結果生成準確的答案。 這樣的應用,也許能用在機器人控制、End-To-End API、程式碼產生器,這些輸入或者輸出不是自然語言,或者用自然語言查詢(輸入)得出制式格式資料(輸出)的情境。

這應該能讓Fine-Tuning這件事變得有價值,如果輔以RAG進行模板語言查詢,應該能同時做到彈性和準確性兼備。 如果真如想像,那麼能帶出2點: 1. 地端或Edge端模型能和雲端模型搭配,Edge端負責控制,雲端負責行為判斷,例如,「小呆同學,我要喝水」,雲端AI能給出「水在水壺,水壺在廚房,到廚房拿杯子裝好水之後,拿到房間」,Edge端能給出「我控制腳步移動到廚房」「我控制手部抓取水杯」「我控制水壺倒水到水杯」「我拿起水杯」「腳步移動到房間」 當然,也可以是End-To-End,直接一個Edge端AI模型內部直接轉出成這些動作控制

2. 關鍵點會需要Training Model,這無法透過RAG處理,因此需要AI公司因應需求Fine-Tuning模型,或者根據需求新增RAG資料,而RAG資料的原型是模板語言,語法與Tag則是Fine-Tuning而成,應該能保護住知識產權

以上都是嘴砲,function calling的Fine-Tuning有拿網路上資料Training,但成果不明 😂 發想還沒實做,它的起手勢,要先學Mustache

雖然不願意承認,但「使用AI」比較容易,使用產品還是簡單些,要造輪子,太累了😂

2026年1月2日

跨平台SSH Tunnel GUI工具 - dot-gSTM

 前言:

Linux桌面環境中的SSH Tunnel GUI工具極少,以前找了一陣子後找到gSTM,但這套在2006-08-05就停更了,只支援到GTK2.0,gSTM-1.3.7幫它續命到GTK3.0,但也更新到2020-12-16。

很早前就想過重構gSTM,但它是GTK2.0或GTK3.0寫的,還用了GTK的glade GUI設計器,GTK的C Library與C的實做,讓gSTM的UI分佈在整個程式各個角落,glade GUI設計器現在幾乎失傳了,而且只支援GTK,這造成要重構它得要重畫整個界面,因此難度等同於重寫一套GUI應用程式。

有了AI,正好可以用AI嘗試重構既有程式,改用新的程式語言以及新的UI Framework重寫,又能讓AI分析既有程式的程式碼邏輯。

成果:

整份專案在
https://github.com/codyfu/dot-gstm

實做過程:

實做過程還算順利,目前覺得AvaloniaUI給AI實做還不錯,目前的盲點是,AvaloniaUI的Debug,還是它改了,我編譯我執行我測試,有問題截圖後貼給AI,流程比Web用playwright慢得多。
儘管如此,claude-code分析能力相當不錯,請它分析gSTM,問它底層呼叫ssh指令的程式碼位置和程式邏輯,大概有9成正確,讓它分析後,再要求它按照原始邏輯在.NET實做,基本上八成正確。
目前程式設計通常被推薦用async/await的非同步模式,但我要求.NET完全按照gSTM原始設計,使用執行緒+Process的方式實做,Queue的處理則要求使用mutex,初步看起來應該還ok。
AI用AvaloniaUI實做UI時,雖然它會說,跟原始的gSTM界面一致,但實際上根本就他自己亂想亂畫,要貼執行畫面給它,並且一來一回讓它修修修,才能改到和gSTM界面接近。

結論:

這次用AI重構了一個既有程式,一方面實現了願望,一方面也實測了AI重構既有軟體的能力和過程。
重構的對象是C + GTK Library,看起來效果還不錯。

2025年12月23日

P2P WebRTC檔案分享工具 - Anywhere Sender

前言:

一直以來都用SendAnywhere,但它現在Linux版好像有點問題,WebRTC一直不太會寫,正好拿AI練習,一方便讓AI幫忙寫WebRTC,另一方面嘗試用AI寫個包括前端、後端、應用程式的完整專案,看看實際運作會遇到哪些狀況。

程式取名為Anywhere Sender,希望能跟SendAnywhere一樣方便好用。😀

對了~除了手機版本與應用程式版本之外,還有CLI版本喔。

實做的時間比預期長,我本來還以為一週就能打完收工,沒想到修修改改修修改改弄了快3週,就算是現在我認為都還算是Beta版,WebRTC的部份看來還是得下去看過順過流程,看來AI開發這事,在除錯階段還是會花費很長時間。

成果:

整份專案在
https://gitlab.com/ycfunet/anywheresender

實做過程:

實做過程遇到不少問題,就算是目前Release,我認為都還需要優化,但已經玩了3週了,就先Release一個Beta版。
這邊會列出2種在開發和測試階段遇到的狀況,一種是純粹開發遇到的,一種是AI開發時會遇到的。

開發問題:
1. AvaloniaUI System Tray問題
System Tray在Windows和MacOS應該沒什麼問題,AvaloniaUI在Windows和MacOS的行為描述都還完整,但在Linux下面,我用的MATE Desktop就無法顯示,一查發現xembed和SNI的問題,光這個就花了些時間,AI在這時候帶來的好處是,寫測試程式很快,以往大概都要先花半天一天survey,survey包括測試程式要用的Library、SDK、原理,寫一個測試可能需要半天一天,然後第二個測試程式、第三個測試程式,這功能可能最快需要3天,AI寫測試,給它參考網站和技術文件,它就能寫,幾個小時就能寫出3~4個測試程式,整個問題排除只需要半天~一天,時間大幅壓縮。
測試時,問AI它會說可能是A, B, C, D什麼的,但其實都不對 😂
直接問它,那為何Electron正常,但AvaloniaUI不正常,AI就也沒答案,還是得survey,不過好處是,AI看程式碼很快,直接丟Electron程式碼和Qt程式碼給它,它就能從中給出它們寫了2種模式 😂

2. Web QR-Code掃描器元件
AI建議用Web的QR-Code掃描器Library,但用了之後,AI寫出遞迴地獄,造成QR-Code掃描器時好時壞,無法正常運作,而且怎麼改都改不正常,後來下去看QR-Code掃描器Library,自己先個Sample,讓AI看Sample改進去,遇到React還是改不成功,最後讓AI把Sample包成function,React直接呼叫function才改成功。
看來,AI在遇到複雜的程式碼狀態時,跟人一樣會混搖,老方法依然適用,讓AI寫Sample Code或人寫,然後包成API讓複雜程式碼呼叫。

3. Web的WebRTC與SIPSorcery的WebRTC相容問題
同樣是WebRTC,但SIPSorcery傳遞的預設參數和Web版的WebRTC不太一致,這應該正常,只要不同的SDK,很容易遇到通訊協定有些差異要調整的,這個顯然AI也會遇到,跟人Debug一樣,時間同樣無法變快,最後一樣是老方法,把SIPSorcery程式碼下載之後讓AI看,讓他自己分析裡面的參數缺少了什麼,才改出。優點是,AI看程式碼很快,給出明確方向,這種問題它能透過分析SIPSorcery、Send、Recv、Web WebRTC給出點和修改,這個人看的話,又要花好幾天,區別是,AI一開始會鬼打牆一直亂說找到問題點,一直亂改,直到你讓它停止,給它分析SIPSorcery和Web的WebRTC差異,它才找出問題點。

AI遇到的問題:
1. Web Framework框架不熟悉
一開始選用Konsta UI Svelte開發,結果寫超破,界面改不出,顯然AI還是要用React或Vue才能寫得好。

2. 檔案傳輸的緩存
AI寫檔案傳輸,預設就用個Web blob直接灌入整個檔案傳送和接收,這當然會造成大檔案傳輸會Memory不足或瀏覽器限制,但這個AI不會特別說,測試時被瀏覽器卡住了,才會說這是OOM(記憶體不足),顯然這不是正確方向,但它會給出建議縮小傳輸檔案大小。
我給AI要求解法,Web用Indexddb,Mobile用capacitor呼叫原生的FileSystem API,Desktop用檔案存取。

3. 兩端WebRTC檔案傳輸的訊息交換與非同步處理問題
這個其實還沒有完全解完,簡單的說,AI從Server、WebRTC傳送、接收的程式碼中,有可能還無法準確的把時序流程弄清楚,因此陸續改了一堆傳送端、接收端時序問題,像是傳送端丟完WebRTC斷線(接收端還沒收完)、Server信令交換在不同平台實做偏差(導致不同平台互傳漏流程,連線無法建立)、Web非同步動作造成時序的先後順序有問題。
目前我還沒下去完整看過WebRTC程式碼細節,但我認為目前Release 1.0.0版本,應該在Web UI Event(傳輸的狀態回傳)與WebRTC傳送、接收檔案的位置應該還有非同步或Event的問題,這可能是目前傳輸有時候會卡住或無法傳送的原因。

結論:

這次用AI實做了一個完整的專案,包括前、後端、手機、應用程式,速度快了不少,以往我不熟悉的知識領域(WebRTC、React、AvaloniaUI),透過AI能夠直接開發。
此外,以往工程師可能需要前端、後端、應用程式、手機,透過AI協作,可能真的減少為1~2位資深工程師就能處理。
這次開發的經驗,證實了網路流傳的說法,AI是資深工程師的開發加速器,但老實說對於新手工程師或中階工程師未必友好,因為它遇到問題時會鬼打牆,就算是Claude-Code這種等級,它不會在同一個點鬼打牆,卻會在沒答案的錯誤邏輯中鬼打牆出不來,此時需要經驗引導正確方向或作法,它才能改出,甚至在QR-Code掃描器的開發過程,程式碼複雜時,就算給出Sample Code,它還是會套用失敗,需要包成API用引用的方式才能改出,這表示工程師的經驗依然重要。

2025年11月30日

補作業之AI微調LLM - Gemma3:270m + 繁體中文支援

前言:

要學習微調LLM,那就跟隨前輩作業,試著將Gemma3:270m加上繁體中文支援。
https://www.facebook.com/groups/gaitech/posts/1461027975081413/

成果:

整份專案在
https://gitlab.com/ycfunet/mi50_training_test

實做過程:

我用MI50微調訓練,讓Claude Code實做微調程式,一開始直接用Transforms訓練,結果一直出現Grad norm = NaN,Grad norm = NaN並不是一開始出現,也不是固定位置出現,是隨機位置出現,可能80%出現,可能95%出現,都會讓訓練失敗,微調出的模型,回答要嘛沒內容,要嘛出現padding,或者常見的出現各國語言混雜一段一段的回答錯亂。
後來用unsloth之後,發現unsloth微調都能正常訓練完,微調出的模型,中文問答都能中文回答。
雖然還有些問題,但原則上都能正確回答。
另外,完整微調真的很花時間,MI50一張,500k的繁體中文資料集,需要連續60幾小時訓練。
unsloth的記憶體使用量比想像少很多,用unsloth訓練時,GPU VRAM是浮動的,但最多也就12%,用量還不到4GB顯卡記憶體。
花費2週,算是有點成果,細節熟悉度還不夠,但入門算有點點進展吧。

補充:
對了,先前用colab T4微調馬達狀態機,這次也移到MI50上,發現MI50訓練的時間,跟colab T4差不多,估計MI50和colab T4同等級。