Local AI · DGX Spark
Spark 對話工作台
打字就有回覆,逐字浮現。
本地 LLM × SSE 串流,思考過程與程式碼都看得到。
實際介面・Playwright 實機截圖
為什麼要自己蓋一個
市面上的對話工具好用,但同樣三個問題:資料要出門、按 token 計費、想換模型還得等官方支援。日常拿來寫程式片段、對內部文件提問,資料出門這一條又是死穴。
DGX Spark 上已經常駐一顆本地 LLM,缺的只是一個好用的介面。把 chat-completions 相容 API 包一層 ChatGPT 風格的殼,就是一個不用錢、不出門的對話工作台。
真正要解決的是體驗細節——串流會不會卡、思考過程要不要秀出來、寫的程式碼能不能立刻看到效果。這些才是這個工具的核心設計。
原理:一則對話的旅程
從送出一句話到收到回覆,中間發生五件事。
輸入送出
文字或圖片(vision)送進工作台,介面走 ChatGPT 熟悉的對話節奏。
呼叫本地 LLM
請求走 DGX Spark 本地的 chat-completions 相容 API,不經過任何雲端服務。
SSE 串流逐 token 回覆
模型邊生成邊往前端推送,文字一個字一個字浮現,不用等完整回答跑完才看到內容。
思考過程獨立摺疊
模型的 thinking 收在可展開的區塊,預設收起,想確認推理過程再點開,不干擾閱讀正文。
程式碼 Canvas 即時預覽
偵測到回覆裡的程式碼區塊,一鍵在 Canvas 裡跑起來看效果,不用複製貼上開別的工具。
原理深掘:SSE 串流管線
從送出請求到程式碼能在畫面上直接跑起來,中間是一條完整的串流解析管線:分塊接收、拆出思考與正文、上色渲染、偵測可預覽內容。
POST /api/llmchat/chat
送出請求
temperature 預設 0.7
max_tokens 預設 2048
chat_template_kwargs.enable_thinking
reader.read() 迴圈
SSE 分塊接收
TextDecoder 累積 buffer
依 \n\n 切成訊息段
data: 行解析
取出 JSON delta
遇 [DONE] 結束串流
解析失敗直接跳過該行
delta 分流累加
思考/正文分開處理
reasoning_content → 思考區
content → 正文區
highlightCode/highlightMarkup
Markdown + 語法上色
regex tokenizer 標記
關鍵字/字串/數字/註解
iframe sandbox 預覽
Canvas 沙盒渲染
isHtmlLike/isSvgLike 偵測
sandbox="allow-scripts"
思考過程摺疊
reasoning 累積的內容渲染成 <details class="thinking">思考過程</details>,串流過程中跟著即時更新,收合與否交給使用者自己決定。
串流錯誤分級處理
401 未授權、413 內容過大、429 頻率限制(讀 Retry-After 秒數)各自有對應的提示文案,不是一律丟「發生錯誤」;中止請求時區分「使用者主動中止」與「串流中斷」。
關鍵設計決策
串流優先
逐 token 顯示,長回答不用空等一整段跑完才看到字,回應感是這類工具體驗的第一關。
思考過程保留但摺疊
想確認模型怎麼想的可以展開來看,不想看的預設收起,不會塞滿畫面干擾閱讀。
程式碼 Canvas 即時預覽
寫一段網頁片段,不用複製貼上另開工具驗證,點一下直接在同一個畫面看到效果。
local-first,不經雲端
從對話到 vision 圖片輸入,全程跑在 DGX Spark 本地,資料不出內網。
技術架構
Frontend
ChatGPT 風格介面
串流逐字動畫
思考摺疊區
Streaming
SSE
逐 token 推送
不阻塞介面
Model
DGX Spark 本地 LLM
chat-completions 相容 API
支援 vision 圖片輸入
Canvas
程式碼區塊偵測
一鍵即時預覽
網頁片段直接跑
線上工具已上鎖(Basic Auth)・本頁分享架構與設計