opencode×AI-Math
課後延伸

用 AGENTS.md 馴服 agent

工作坊上你已經會叫 opencode 幫你寫程式了。但你大概也遇過這些狀況:

  • 它用英文回你,你要的是中文
  • 它寫 python lab1.py,可是你的環境是 uv,跑起來找不到 numpy
  • 你叫它「手刻 k-means」,它偷偷 from sklearn.cluster import KMeans 交差
  • 每開一個新對話,你就要把上面這些規矩再講一次

這章要解決的就是最後一句。AGENTS.md 是一個放在專案根目錄的 Markdown 檔,opencode 每次開始工作都會先讀它。把規矩寫一次,之後每個對話都自動生效。


1. AGENTS.md 是什麼

它就是一個純文字 Markdown 檔,沒有特殊語法、沒有必填欄位。裡面寫的是你希望 agent 每次都遵守的規則:用什麼語言、用什麼指令跑程式、圖存哪裡、什麼事不准做。

opencode 會把這個檔案的內容接在系統提示後面送給模型。所以它的效力等同於「你每次對話開頭都手動貼上這段話」,只是你不用真的貼。

重點觀念:AGENTS.md 是給模型看的,不是給人看的。它不是 README。README 寫給同學看「這專案怎麼跑」,AGENTS.md 寫給 agent 看「你該怎麼動手」。兩者內容可以重疊,但目的不同。


2. opencode 什麼時候讀它

opencode 啟動時會依序尋找規則檔:

  1. 專案層:從目前目錄往上層逐層找 AGENTS.md(找不到才找 CLAUDE.md)
  2. 全域:~/.config/opencode/AGENTS.md
  3. Claude Code 相容:~/.claude/CLAUDE.md(除非關閉此相容性)

找到的檔案會一起合併使用,不是只取第一個。同一類別中 AGENTS.md 優先於 CLAUDE.md。

因為是「從目前目錄往上找」,所以有個很實際的後果:

在課前建立的專案資料夾開啟終端機,先確認位置:

pwd
ls

清單裡應有本課程的 AGENTS.md 與 opencode.json。如果沒有,先切回正確的資料夾,不要在目前位置另建一套。

養成習慣:一律 cd 進專案根目錄再打 opencode。 這是初學者最常見的「規則怎麼沒生效」原因。


3. AGENTS.md 與 instructions 設定的關係

你的 opencode.json 目前長這樣:

{
  "$schema": "https://opencode.ai/config.json",
  "model": "opencode/big-pickle",
  "permission": { "bash": "ask", "edit": "ask", "webfetch": "ask" },
  "instructions": ["AGENTS.md"]
}

很多人以為是 instructions 這行讓 AGENTS.md 生效的。不是。 根目錄的 AGENTS.md 是自動被找到的,不寫 instructions 也會讀。

instructions 真正的用途是追加其他檔案。它支援三種寫法:

{
  "instructions": [
    "AGENTS.md",
    "docs/math-conventions.md",
    ".cursor/rules/*.md",
    "https://example.com/team-rules.md"
  ]
}
  • 相對路徑(相對於設定檔位置)
  • glob 萬用字元(*.md)
  • 遠端 URL(有 5 秒逾時限制)

所有 instructions 指到的檔案,會和自動找到的 AGENTS.md 合併在一起。

所以起始專案裡那行 "instructions": ["AGENTS.md"] 其實是多餘的,寫明白一點而已,刪掉也不影響。但如果你之後想把規則拆成好幾個檔(例如 notes-style.md、plot-style.md),就要靠 instructions 把它們掛進來。

設定檔本身也是多層合併的,由低到高:

remote (.well-known/opencode)
  → 全域 ~/.config/opencode/opencode.json
  → OPENCODE_CONFIG 環境變數指定的檔
  → 專案根目錄 opencode.json          ← 教材一律用這層

後面的會覆蓋前面同名的鍵。這門課的所有設定都寫在專案根目錄的 opencode.json,這樣你的設定跟著專案走,換台電腦、交作業都不會掉。

.jsonc 是可以包含註解的 JSON 格式;本課程使用專案中的 opencode.json,不需要改全域設定。


4. 全域 vs 專案層的 AGENTS.md

全域 ~/.config/opencode/AGENTS.md專案 <專案>/AGENTS.md
適合放你個人的偏好這個專案的技術規則
例子「一律用繁體中文回答」「解釋時先講結論」「用 uv run python」「圖存 figs/」
會不會跟著作業一起交不會會(建議進版控)
換專案還在嗎在不在

判斷原則很簡單:換一個專案還成立的,放全域;只對這個專案成立的,放專案層。

「用繁體中文」兩邊都可以。放全域你每個專案都不用再寫;放專案層則讓同學拿到你的專案時,也能沿用相同的語言要求。這門課建議放專案層,讓規則和練習檔案一起保存。


5. /init 指令會做什麼

在 opencode 的對話介面裡輸入:

/init

它會掃描專案的重要檔案(pyproject.toml、目錄結構、既有設定等),可能問你幾個問題,然後產生或更新 AGENTS.md,內容涵蓋建置指令、架構、慣例。

什麼時候用:從零開始一個新專案,你懶得自己想要寫什麼,用 /init 生一份草稿再手動改。

/init 可能修改既有的 AGENTS.md。本課程已提供規則,現場不用再執行這個指令。

想在其他專案試 /init,請先完成 Git 安全網,保存目前狀態,再產生草稿並檢查差異。本章先練習閱讀與修改現成規則。


6. 實用寫法:六件值得寫進去的事

以下每一條都對應一個真實會出錯的狀況。

6.1 語言

## 語言
一律使用台灣繁體中文回答。程式碼、變數名稱、函式名稱、套件名稱保留英文。

要寫「保留英文」的部分,否則有些模型會很熱心地把 n_clusters 翻成 叢集數,程式就壞了。

6.2 執行環境(最重要的一條)

## 執行環境
本專案用 uv 管理環境。執行 Python 一律用:

    uv run python <檔案>

不要用 `python`、`python3`、`pip install`。要加套件用 `uv add <套件>`。

為什麼這條最重要:你的套件(numpy、sklearn)裝在專案的 .venv/ 裡。直接打 python lab1.py 用的是系統的 Python,看不到那些套件,會噴 ModuleNotFoundError。而 agent 的訓練資料裡絕大多數是 python xxx.py,不特別交代它就會照慣例寫。

同理,pip install 會裝到錯的地方或直接失敗;uv 的做法是 uv add,它會同時更新 pyproject.toml,環境才可重現。

6.3 可重現性

## 可重現性
任何用到隨機性的地方,一律設定 `random_state=0`(或 `np.random.seed(0)`)。
包括但不限於:train_test_split、KMeans、PCA 的 randomized solver、資料洗牌。

這是數學課的硬需求。沒固定亂數種子,你今天跑出來的圖和明天跑出來的不一樣,寫報告時你會不知道要相信哪一張。助教重跑你的程式也對不上你的數字。

6.4 不准偷呼叫現成函式充數

## 不要偷懶呼叫現成函式
如果我要求「手刻」「自己實作」某個方法,就不可以直接呼叫 sklearn 的對應
實作來充數。sklearn 只能當作**對照組**:手刻的結果算完後,可以再跑一次
sklearn 的版本,印出兩者的數值差異來驗證。

這是這門課最容易被 agent 陽奉陰違的一條。你說「幫我實作 PCA」,它回一個包了 sklearn.decomposition.PCA 的三行函式。程式會跑、結果會對,但你什麼都沒學到,作業分數是零。

寫成「sklearn 只能當對照組」比單純寫「不准用 sklearn」更好,因為前者給了 agent 一個合法的替代做法。純禁止的規則容易被繞過,給出路的規則比較會被遵守。

6.5 圖存哪裡

## 圖檔
所有圖存到 `figs/`,用 `matplotlib.pyplot.savefig()`,不要用 `plt.show()`
(這是無視窗環境,`show()` 不會有任何效果)。
檔名用英文小寫加底線,例如 `figs/pca_scree_plot.png`。

plt.show() 在終端機環境裡是靜默無效的:不會報錯,就是什麼都沒發生,然後你以為程式壞了。明確要求 savefig() 到固定目錄,你才找得到圖。

6.6 不准 commit

## 不要做的事
- 不要執行 `git commit`、`git push`,除非我明講。
- 不要改 `pyproject.toml` 以外的設定檔。
- 不要刪除 `figs/` 或 `notes/` 裡既有的檔案。

為什麼不准 agent commit:commit 是你檢查過之後的動作。如果 agent 改完自己就 commit,一般的 git diff 就不再顯示那些修改,需要再到歷史中比較。先看差異再存檔,較容易逐步確認。讓 agent 只負責改,你負責檢查和存檔。

git push 更是絕對不行,那會把東西推到網路上,收不回來。


7. 完整範例(可直接複製)

這是你的起始專案裡那份,可以直接用,也可以照自己的需要改:

# AI-Math 工作坊 專案規則

## 語言
一律使用台灣繁體中文回答。程式碼、變數名稱、函式名稱、套件名稱保留英文。

## 執行環境
本專案用 uv 管理環境。執行 Python **一律**用:

    uv run python <檔案>

不要用 `python`、`python3`、`pip install`。要加套件用 `uv add <套件>`。

## 數學程式的規矩
1. **可重現**:任何用到隨機性的地方,一律設定 `random_state=0`(或 `np.random.seed(0)`)。
2. **先說數學,再寫程式**:動手前先用兩三句話說明你要用的公式或演算法步驟。
3. **自己驗證**:寫完數值方法後,必須附一段驗證程式碼,並實際執行、印出比對結果。
   不可以只說「應該正確」。
4. **不要偷懶呼叫現成函式**:如果我要求「手刻」某個方法,就不可以直接呼叫
   `sklearn` 的對應實作來充數。`sklearn` 只能當作**對照組**。

## 圖檔
所有圖存到 `figs/`,用 `matplotlib.pyplot.savefig()`,不要用 `plt.show()`
(這是無視窗環境,`show()` 不會有任何效果)。

## 筆記
數學筆記寫在 `notes/` 底下的 `.md` 檔,數學式用 `$...$`(行內)與 `$$...$$`(獨立行)。

## 不要做的事
- 不要 `git commit`、`git push`,除非我明講。
- 不要改 `pyproject.toml` 以外的設定檔。
- 不要刪除 `figs/` 或 `notes/` 裡既有的檔案。

注意第 3 條「自己驗證」的寫法:它不只說「要驗證」,還說「必須實際執行、印出比對結果,不可以只說『應該正確』」。這個補充很關鍵。不加的話,agent 常常寫一段驗證程式碼然後直接宣稱通過,根本沒跑。


8. 反例:哪些寫法沒用或有反效果

反例 1:寫得像許願,沒有可判斷的標準

請寫出高品質、優雅、專業的程式碼。

沒用。「高品質」對模型來說沒有可操作的意義,它本來就在盡力產生它認為好的程式碼。這行字佔了 context 卻改變不了任何行為。

改成:說出可以檢查的具體要求。

每個函式都要有 docstring,說明輸入的 shape 與輸出的 shape。
例如:`X: (n_samples, n_features) -> (n_samples, n_components)`

反例 2:寫成「教學」而不是「規則」

PCA 是一種降維方法,它透過計算共變異數矩陣的特徵向量⋯⋯

沒用而且浪費空間。模型知道什麼是 PCA。AGENTS.md 要寫的是你的專案的特殊約定,不是通識教材。

反例 3:太長

塞三千字進去,效果通常比三百字差。規則一多,每條被遵守的機率就下降,而且長規則會擠壓真正重要的內容。

原則:只寫「不講就會做錯」的事。 講了跟沒講一樣的(例如「請寫正確的程式」),刪掉。

反例 4:自相矛盾

不要使用任何第三方套件。
...
用 sklearn 做交叉驗證。

矛盾的規則會讓模型行為變得不可預測,它可能隨機挑一條遵守。寫完整份檔案後從頭讀一次,確認沒有打架的條文。

反例 5:以為 AGENTS.md 能強制執行

這是最重要的一個認知:AGENTS.md 是提示,不是權限控制。

「不要 git push」寫在 AGENTS.md 裡,是請求 agent 不要做;模型絕大多數時候會聽,但不保證。真正的強制要靠 opencode.json 的 permission 設定:

{
  "permission": {
    "bash": {
      "*": "ask",
      "git push": "deny",
      "git push *": "deny"
    }
  }
}

設定完成後,用 opencode agent list 檢視解析後的權限。規則以樣式比對,最後一條符合的規則生效,因此一般規則放前面、特例放後面。

注意上面同時寫了 "git push" 和 "git push *" 兩條。前者擋不帶參數的 git push,後者擋 git push origin main 這類帶參數的。兩種形式都明列,閱讀設定時就能看出想限制哪些動作。

permission 的可用值是 "allow"、"ask"、"deny"。除了 bash、edit、webfetch,還有 read、glob、grep、task、skill、websearch、external_directory 等。

心法:想拜託的事寫 AGENTS.md,不能出事的事寫 permission。


9. 怎麼驗證 AGENTS.md 真的生效了

不要憑感覺。有三個層次的檢查。

層次 1:確認 opencode 讀到了你的設定

opencode debug config

起始專案中的輸出例子:

{
  "$schema": "https://opencode.ai/config.json",
  "model": "opencode/big-pickle",
  "permission": {
    "bash": "ask",
    "edit": "ask",
    "webfetch": "ask"
  },
  "instructions": [
    "AGENTS.md"
  ],
  "agent": {},
  "mode": {},
  "plugin": [],
  "command": {},
  "username": "phonchi"
}

這證明 opencode 找到了你的專案 opencode.json,模型是 opencode/big-pickle,權限是 ask。

注意這個指令的限制:它顯示的是合併後的設定,不會把 AGENTS.md 的內文印出來。所以它能證明「設定讀到了」,不能證明「規則被遵守了」。要驗證後者,往下看。

層次 2:請它說明執行方式

最快的行為測試,在專案根目錄執行:

opencode run "用一句話回答:依照專案規則,執行 Python 檔案應該用哪一個指令?"

輸出例子:

> build · big-pickle

`uv run python <檔案>`。

這次回答符合語言與執行方式的要求。接下來還要看它是否在實際任務中照做。

回答正確,還不能確認什麼

agent 可能先自己讀檔,再回答規則。這表示它找得到規則,但不能單靠一句回答判斷規則是不是自動載入。也不要只把檔案改名成 .bak 就當成「沒有規則」的對照,agent 仍可能找到它。

對這門課最實用的判斷,是查看下一個實際任務:它是否使用指定的執行方式,輸出是否放在正確位置。

層次 3:實際任務測試

最終還是要看真實行為。先執行 opencode,在互動介面貼上下面的小任務,閱讀並確認寫檔要求:

在 notes/ 寫一個 test.md,裡面用 LaTeX 寫出 PCA 的目標函式,並定義式子裡的符號。

然後檢查:檔案是不是寫在 notes/?數學式是不是用 $$...$$?說明是不是繁體中文?

有任何一項不符,就回頭把 AGENTS.md 那條規則寫得更具體。通常是規則太含糊,不是模型不聽話。

常見「規則沒生效」的原因

症狀最可能的原因怎麼修
完全不理會規則不在專案根目錄啟動 opencodecd 到根目錄再開
偶爾遵守偶爾不遵守規則太含糊,或整份檔案太長改具體、砍掉不重要的條文
改了 AGENTS.md 沒反應可能是舊對話的脈絡還在開新對話再試
某條永遠沒用跟另一條規則矛盾從頭讀一次,找出打架的條文

10. 本章重點

  1. AGENTS.md 放專案根目錄,自動被讀取,不需要靠 instructions 宣告。
  2. instructions 是用來追加其他檔案的(支援相對路徑、glob、遠端 URL)。
  3. 設定多層合併,這門課一律用專案根目錄的 opencode.json。
  4. 最該寫的規則:語言、uv run python、random_state=0、不准用 sklearn 充數、圖存 figs/、不准 commit。
  5. 規則要具體可檢查;許願式、教學式、過長、矛盾的寫法都沒用。
  6. AGENTS.md 是提示不是強制。不能出事的事情要用 permission 擋。
  7. 驗證三層次:opencode debug config 看設定、opencode run 問它規則、真實任務看行為。

練習

  1. 在你的專案跑 opencode debug config,確認 model 是 opencode/big-pickle。
  2. 跑一次層次 2 的行為測試,確認它答出 uv run python。
  3. 在 AGENTS.md 加一條你自己的規則(例如「所有 .py 檔開頭要有一行註解說明這支程式在做什麼」),開新對話,叫它寫一支小程式,檢查有沒有遵守。
  4. 想一想:你加的那條規則,應該放 AGENTS.md 還是 permission?為什麼?

資料來源