2025/12/23

How Github Copilot Works

身為一個重度 GitHub Copilot 使用者,一直很好奇它在 IDE 背後是如何運作的,因此整理了公開資料與工程角度的理解,嘗試還原 Copilot 在你按下 Enter 鍵後所經歷的完整流程。

本文內容結合 GitHub 官方文件、公開技術文章,以及工程上合理的系統設計推論。

1. 核心 Pipeline:當你按下 Enter 後的生命週期

每一則 Prompt 或每一行自動補全的背後,大致可拆解為以下六個關鍵階段。

第一步:Context Retrieval(上下文檢索)

  • 責任方: IDE 插件 (Client-side)
  • 動作: 啟動 Prompt Library 掃描
  • Neighboring Tabs: 透過「向量嵌入語義搜尋 (Embedding-based Semantic Search)」,在目前開啟的標籤頁中檢索語義相關的程式碼片段,GitHub 在 2025 年部署的新 embedding model 提升了 37.6% 的檢索品質,吞吐量提高 2 倍,且記憶體使用量減少 8 倍
  • LSP Data: 透過 Language Server Protocol 獲取符號定義 (Definitions)、類型資訊與作用域。
  • Path Context: 考慮當前檔案在專案目錄中的位置。
  • Git Context: 讀取 Git 歷史資訊,包括:
    • Recent Commits: 最近的 commit 訊息,理解程式碼變更意圖
    • Commit Diff: 查看哪些檔案經常一起修改,推斷相關性
    • Blame Information: 了解程式碼區塊的作者和修改時間
    • Branch Context: 當前分支名稱(如 feature/auth)可幫助 Copilot 理解開發目標

第二步:Ranking & Pruning(排序與剪裁)

  • 責任方: Local Indexer / GitHub Proxy

  • 動作: 為避免超過模型可處理的 Context Window,對蒐集到的內容進行篩選與壓縮

  • Context Window 考量:
    不同底層模型在理論上支援不同大小的 context window,但 Copilot 實際送入的內容會依任務型態與效能需求動態調整,而非單純使用最大值

  • 優先權排序(推測性設計):

    • 匯入關係(Imports)
    • 最近編輯或鄰近游標的程式碼
    • 命名或結構相似度
  • 結構化摘要(可視為 Outline 模式):
    當相關檔案過大時,系統會傾向:

    • 移除具體實作細節
    • 保留類別結構、函數簽名與型別定義,以結構化摘要的方式降低 Token 使用量

第三步:Instruction Injection(指令注入)

  • 責任方: GitHub Proxy Layer
  • 動作: 在請求中注入系統層級的行為約束
  • Custom Instructions: 自動讀取 .github/copilot-instructions.md,讓團隊可定義一致的開發規範
  • System Prompt(黑箱實作):
    Copilot 會針對不同語言與使用情境,加入內部的偏好設定與引導指令,以提升產出品質與一致性

第四步:Model Routing(模型路由)

  • 責任方: GitHub Cloud Gateway

  • 動作: 根據任務性質選擇適合的模型:

    • 自動補全(Autocomplete) → 延遲極低的程式碼專用模型
    • Chat、複雜推理、Agent 任務 → 大型通用模型
  • 從系統架構角度來看,可以將 Copilot 視為建立了一層模型抽象/序列化層,負責將統一的上下文轉換為不同模型可理解的請求格式

第五步:Post-Processing & Validation(後處理與驗證)

  • 責任方: GitHub Proxy / Local IDE

  • 動作:

    • 語法與結構檢查: 對產出的程式碼進行快速的語法或結構驗證,以避免明顯錯誤
    • Safety & License Filter: 檢查是否涉及敏感資訊或潛在版權風險

第六步:Rendering(UI 渲染)

  • 動作:FIM(Fill-In-the-Middle) 形式顯示 Ghost Text,或在 Chat 視窗中輸出結構化 Markdown 內容

2. 核心技術解析

為什麼 Autocomplete 能做到毫秒級回應?

  • FIM 技術: Copilot 的模型能同時理解游標前(Prefix)與游標後(Suffix)的內容,因此能精準填補中間缺口,而不重複生成已存在的結構
  • 小型專用模型: 自動補全通常使用高度優化、延遲極低的程式碼模型,而非大型對話模型,以確保輸入時的即時性

如何降低幻覺風險?

  • 符號資訊作為 Grounding 訊號: Copilot 會利用 LSP 提供的符號與型別資訊,作為建議排序與可信度判斷的輔助
  • 語法層級的預過濾: 明顯無法通過語法解析的建議,通常不會顯示給使用者

MCP(Model Context Protocol)的角色

隨著 MCP 的導入,Copilot 開始支援「工具導向」的互動模式:

  • Tool Calling: 在支援的環境中,Copilot 可透過 MCP 與外部工具或系統互動
  • 跨工具整合:
    • MCP 提供一個標準化介面,讓 Copilot 能與開發環境中的各種工具協同運作
    • 相關支援仍在逐步擴展中,實際可用功能會依 IDE 與方案而有所差異

3. 給資深工程師的實戰建議

1️⃣ 管理 Context

Copilot 會優先參考目前開啟的檔案,當建議品質下降時,關閉不相關的 Tab 往往是最有效的調整方式。

2️⃣ 善用 .github/copilot-instructions.md

將團隊的風格、安全與工具使用規範明確寫入,能顯著提升一致性。

3️⃣ 使用 Few-shot Prompt

在 Chat 中提供輸入/輸出的範例,能快速對齊程式碼風格。

4️⃣ 明確負向約束

清楚告知「不要使用哪些技術或套件」,比事後修正更有效。

5️⃣ 分段互動 / 校正

  • 一次性完整描述(one-shot prompt)

    • 優點:上下文集中、token 使用效率高、理論上成本最低

    • 風險:

      • 需求理解一旦有偏差,整個輸出一起歪
      • 中途無法校正方向
      • 對複雜專案而言,不確定性很高
  • 分段 prompt(multi-step / iterative prompting)

    • 優點:

      • 可以逐步確認理解是否正確
      • 每一段都能修正假設
      • 對需求仍在釐清、會變動的專案特別安全
    • 缺點:token 成本較高、流程較慢

6️⃣ 先做規劃,再進入實作(Plan-first)

  • 在真正寫程式之前,先要求 AI 產出完整規劃,再進入執行階段
  • 不論是使用 Spec Kit、或是 Agent 的 plan 工具,都能有效降低實作期的不確定性
  • 規劃階段可涵蓋:
    • 功能拆解與模組邊界
    • 資料結構與介面設計
    • 關鍵技術決策與限制條件
    • 風險點與替代方案
  • 將這份規劃當作後續 vibe coding 的依據,你會明顯感受到:
    • 實作時幾乎不需要反覆來回修正方向
    • Copilot / Agent 的建議更貼近預期
    • 執行效率與最終成果品質都顯著提升

對資深工程師而言,AI 的最大價值往往不在「幫你寫幾行 code」,而是在 把模糊的需求,轉換成可執行的 roadmap

總結

GitHub Copilot 並不是單純「把程式碼丟給模型」,而是一套結合 IDE 上下文蒐集、結構化壓縮、模型路由與後處理驗證的完整系統,理解這些設計,有助於我們更有效地與 Copilot 協作,而不是把它當成黑箱魔法。

4. 推薦資源與延伸閱讀

📺 精選影片 (YouTube)

1. Context Engineering Clearly Explained (Tina Huang)

這部影片闡述了語境工程在建構 AI Agent 時的核心地位與實作架構。

  • 定義與區別

    • 語境工程 (Context Engineering):旨在設計動態系統,確保在對的時間以對的格式提供對的資訊給模型,這與單次對話式的「提示工程」不同,是專為構建 AI 應用程式(如 Agent)服務的技術
    • 核心目標:即是優化並打包上下文視窗(Context Window),為 AI Agent 撰寫一份詳盡的操作說明書
  • AI Agent 的六大組成(漢堡比喻)
    影片將 Agent 比喻為漢堡,必須具備以下組件,而語境工程則是整合這些組件的說明書:

    1. 模型 (Model):核心大腦(如 GPT, Claude 等)
    2. 工具 (Tools):與外部系統互動的能力(如讀取日曆、搜尋網頁)
    3. 知識與記憶 (Knowledge & Memory):儲存對話歷史或特定領域知識庫
    4. 音訊與語音 (Audio & Speech):提供更自然的互動介面
    5. 護欄 (Guardrails):確保行為安全與合規的機制
    6. 編排 (Orchestration):監控、部署與改進 Agent 的系統
  • 實作技巧

    • 結構化提示:使用 XML 標籤(如 <user query>)區分區塊,並要求 AI 以 JSON 格式輸出,清晰定義角色、任務步驟與限制
    • 多代理系統 (Multi-agent):對於複雜任務,建議拆解為多個 Agent(如一個負責搜尋,一個負責總結),並透過共享語境(Context)傳遞資訊

2. The Model Context Protocol (MCP) (Anthropic)

這部影片由 Anthropic 團隊介紹 MCP 協議,旨在解決 AI 工具與數據源連接的標準化問題。

  • MCP 的核心概念

    • 標準化協議:MCP 是一個開放標準,解決了 AI 應用程式(Client)與資料來源(Server)之間連線繁瑣的問題,避免開發者需針對每個工具單獨寫整合
    • 生態系效益:開發者只需建立一次 Server,就能對接所有支援 MCP 的客戶端(如 Claude Desktop、IDE),大幅降低整合門檻
  • MCP 的三大要素

    1. 工具 (Tools):模型可以執行的動作,例如執行程式碼或呼叫 API
    2. 資源 (Resources):提供給模型的原始數據或上下文,如檔案內容、日誌或資料庫數據
    3. 提示 (Prompts):預定義的提示模板(通常透過 slash command 觸發),讓使用者能快速載入特定任務設定
  • 發展與未來功能

    • 開源策略:透過開源不封閉生態系,讓產業界專注於構建模型智慧與工作流
    • Registry API:未來將允許模型主動搜尋並發現可用的 Server
    • 長時運行任務與反問 (Long-running & Elicitation):支援更長時間的任務執行,並允許 Server 反問使用者以獲取更多資訊

3. Your codebase, your rules: Customizing Copilot with context engineering (GitHub)

這部影片專注於如何在 VS Code 中透過語境工程客製化 GitHub Copilot,使其更貼合專案需求。

  • Copilot「開箱即用」的視野

    • Copilot 不僅讀取當前檔案,還能感知終端機輸出Linting 錯誤 (紅字波浪線)測試結果以及 VS Code 的 Tasks
    • 建議:確保專案安裝了正確的擴充套件並配置好 Linting,因為 Agent 會直接利用這些錯誤訊息來自我修正程式碼
  • 語境工程的三個層次

    1. Copilot Instructions:透過 .github/copilot-instructions.md 定義全專案通用的規則(如:不進行角色扮演、指定的 Coding Style),這是最基礎的客製化
    2. 領域特定指令 (Domain Specific):針對特定模式(如 Observable pattern)提供微型教學,僅在相關程式碼出現時載入,避免 AI 產生不存在的 API
    3. 提示與模式 (Prompts & Modes):設計可重複使用的指令(如 TDD RedTDD Green),將複雜的開發流程自動化
  • 進階技巧

    • 子代理 (Sub-agents) 與 Context 壓縮:利用子代理進行大量文件研究,但只回傳「執行任務所需的核心資訊」給主流程,以減少 Context window 的負擔
    • 計畫模式 (Plan Mode):限制 Agent 可使用的工具權限,使其專注於產生架構或實作計畫,而非直接寫碼

🔗 深度技術文檔

2025/12/20

Permanently Set Docker Socket Permissions to 666

從之前的 Vagrant 改到使用 wsl + docker 後,PhpStorm 的開發會連到 wsl 裡面的 Docker image 測試,速度還可以接受,Docker 預設情況下,/var/run/docker.sock 的權限為 660(srw-rw----),只有 root 用戶和 docker 組成員才能訪問。如果需要讓所有用戶都能訪問 Docker socket,需要將權限改為 666,通過 systemd 的 override 機制來永久設置 Docker socket 的權限。

步驟 1:創建 systemd 覆蓋配置

sudo mkdir -p /etc/systemd/system/docker.socket.d

步驟 2:創建配置文件

sudo tee /etc/systemd/system/docker.socket.d/override.conf > /dev/null << 'EOF'
[Socket]
SocketMode=0666
EOF

或者手動創建文件 /etc/systemd/system/docker.socket.d/override.conf,內容如下:

[Socket]
SocketMode=0666

步驟 3:應用配置

sudo systemctl daemon-reload
sudo systemctl restart docker.socket docker.service

步驟 4:驗證權限

ls -la /var/run/docker.sock

應該看到輸出類似:

srw-rw-rw- 1 root docker 0 Dec 20 00:15 /var/run/docker.sock

原理說明

  • Docker 的 socket 是由 systemd 的 docker.socket 單元管理的
  • 通過在 /etc/systemd/system/docker.socket.d/ 目錄下創建 override 配置文件,可以覆蓋默認的 socket 設置
  • SocketMode=0666 指定 socket 文件的權限為 666(所有用戶可讀寫)
  • 每次 Docker 啟動時,systemd 會自動應用這個權限設置

安全注意事項

⚠️ 警告:將 Docker socket 權限設置為 666 意味著系統上的任何用戶都可以訪問 Docker,這等同於給予所有用戶 root 權限。請確保你了解這樣做的安全風險:

  • 任何用戶都可以運行容器
  • 可以掛載宿主機的任何目錄
  • 可以以 root 權限執行命令

建議僅在開發環境或你完全信任所有用戶的環境中使用此配置。

配置文件位置

  • 配置文件:/etc/systemd/system/docker.socket.d/override.conf
  • Socket 文件:/var/run/docker.sock

恢復默認權限

如果需要恢復默認的 660 權限,刪除 override 配置文件並重啟服務:

sudo rm /etc/systemd/system/docker.socket.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart docker.socket docker.service

2025/12/07

How to Use Vim Modeline to Force Filetype and Formatting

在使用 Vim / Neovim 編輯設定檔(例如 nginx、Docker、env、conf)時,常常會遇到:

  • 副檔名看不出類型
  • 語法高亮錯誤
  • 縮排混亂
  • LSP / 補全失效

這時候可以使用一個超好用但很多人沒用過的功能:

👉 Vim Modeline

🔹 什麼是 Vim Modeline?

Modeline 是一種寫在檔案開頭或結尾的註解,用來告訴 Vim「這個檔案要用什麼設定」

Vim 開啟檔案時會自動讀取並套用。

最常見用途:

  • 指定語法類型(filetype)
  • 設定 tab 寬度
  • 控制縮排風格
  • 強制編碼

🔹 基本語法

# vim: set ft=nginx :

結構說明:

區段 說明
# 註解符號
vim: 宣告這是 Modeline
set 設定
ft=nginx 指定 filetype
: 結尾標記

等同於在 Vim 內手動輸入:

:set ft=nginx

✅ 精簡寫法

下面這三種「效果完全一樣」:

# vim: set ft=nginx :
# vim: ft=nginx :
# vim:ft=nginx

優點:

  • ✅ 超短
  • ✅ 不佔版面
  • ✅ 非常適合放在第一行
  • ✅ 設定檔實務最常用

✅ 精簡寫法也可以組合多個設定

# vim:ft=nginx ts=2 sw=2
# vim:ft=sh ts=2 sw=2 expandtab
# vim:ft=python ts=4 sw=4 expandtab

全部都是 ✅ 合法 Modeline。


✅ 最常用 Modeline 範例整理

✅ 強制指定語法類型(最常見用途)

# vim: set ft=nginx :
# vim: set ft=sh :
# vim: set ft=php :
# vim: set ft=python :
# vim: set ft=javascript :
# vim: set ft=typescript :
# vim: set ft=go :
# vim: set ft=lua :
# vim: set ft=json :
# vim: set ft=yaml :
# vim: set ft=dockerfile :

✅ 指定 Tab 與縮排格式

# vim: set ts=2 sw=2 :
# vim: set ts=4 sw=4 :
# vim: set expandtab :
# vim: set noexpandtab :
設定 功能
ts Tab 顯示寬度
sw 自動縮排寬度
expandtab Tab 轉為空白
noexpandtab 保留真實 Tab

✅ 組合技(實務最常用)

Nginx 設定檔

# vim: set ft=nginx ts=2 sw=2 :

Shell Script

# vim: set ft=sh ts=2 sw=2 expandtab :

Python

# vim: set ft=python ts=4 sw=4 expandtab :

Frontend 專案

// vim: set ft=javascript ts=2 sw=2 :

✅ 指定檔案編碼

# vim: set fileencoding=utf-8 :

✅ 放在檔案結尾的寫法(也合法)

# vim: set ft=nginx :

🔐 Modeline 安全性補充

某些 Vim 會預設關閉 Modeline,避免被惡意檔案注入指令。

你可以檢查:

:set modeline?

啟用方式:

:set modeline

永久啟用(vimrc / init.lua):

set modeline

✅ 什麼時候「一定要用」Modeline?

  • 副檔名錯誤的設定檔(.conf.env.tpl
  • 後端 mix 多種語言
  • Docker / K8s / Nginx / CI 設定
  • 團隊統一格式規範

2025/12/03

Using AI Turn My Requirement Into A Spec

LLM 最強大的就是你給予適當的內容,它可以幫你延伸很多你沒注意到的問題,最近常常把需求稍微梳理過後,加上一段 prompt 讓他整理成 spec,再將結果調整一下變可以開 redmine 的票。

widget 設定完成後,若使用者將 widget 的欄位刪除,有機率會造成計算或使用錯誤,經討論後端要先行驗證欄位是否存在,查找有問題後一律回覆 422 給前端

---

你的角色是網路工程師。請協助將我提供的功能簡述,轉換成規格(spec)格式。轉換後的 spec 需包含以下幾個內容:

- 功能標題
- 功能簡述
- 實作建議
- 測試建議
- 其他注意事項

允許使用 emoji 輔助

AI 產生的內容:

📌 Widget 欄位存在性驗證(後端)

📝 功能簡述

當使用者完成 widget 設定後,如果後續手動刪除了 widget 所需的欄位,可能導致運算錯誤或使用體驗異常。後端需在每次相關操作前進行欄位存在性驗證,若必填欄位不存在,統一回傳 HTTP 422 錯誤給前端。


🛠️ 實作建議

  1. 欄位驗證邏輯

    • 在 widget 運算、讀取前加入一段欄位檢查邏輯。
    • 驗證所有 widget 設定中宣告的欄位是否存在於資料來源(如資料庫欄位、配置檔或動態欄位列表)。
    • 若任一欄位不存在,立即中止流程並回傳 422。
  2. 統一錯誤格式

    • 使用統一格式,例如:
      {
        "message": "missing field",
        "code": "CO-ME108",
        "status": false
      }
      
      此 message 以及 code 為示意。

🧪 測試建議

  1. 正常情境

    • 所有欄位都存在 → 回傳 200 並正常執行邏輯。
  2. 單一欄位缺失

    • 刪除一個 widget 必要欄位 → 應回傳 422,且錯誤訊息不包含該欄位名稱。
  3. 多個欄位缺失

    • 模擬多個欄位被刪除 → 應回傳 422,且錯誤訊息不包含該欄位名稱。

其實他寫了相當多建議,這是我整理過後的結果,那些建議不一定符合我們需求,但可以當作參考也是相當不錯。