有沒有過這樣的經驗:
坐在你隔壁的同事用 Cursor 或 Copilot 開發速度飛快。明明使用的是相同的工具,但在自己的專案裡卻完全不順,AI 會產生偏離目標的程式碼,每次都要重複相同的說明,漸漸開始覺得「果然 AI 沒什麼用」。
…請稍等一下。
老實說,我一開始也是這樣。導入 Claude Code 或 Cursor,帶著期待開始使用,但也曾覺得「好像沒有想像中好」。直到有一天我意識到:
問題不是 AI 的能力,而是你提供給它的「文脈」品質不同。
更具體地說,整個「程式碼倉庫本身」是否對 AI 友好,會決定 AI 輸出的品質。無論你怎麼優化 prompt,如果程式碼庫的結構對 AI 來說難以理解,根本就有限制。
本文從三大支柱實作說明,如何讓 AI agent「從一開始就成為戰力」:AGENTS.md / CLAUDE.md 的撰寫方式、目錄結構最佳化、驗證(validation)策略。
文章內會附上可直接使用的範本與檢查清單,請從你有興趣的地方開始試試看。
本章重點:AI 如何理解程式碼,以及「容易閱讀」的程式庫條件
AI agent 有一個稱為「上下文視窗」的概念,指的是它一次能看到的範圍。到 2026 年為止,Claude 3.5 可處理約 200K token、GPT‑4o 約 128K token、Gemini 2.0 Pro 最多可達 1,000K token。
拿人來類比就是:
上下文視窗越大 = 桌上可以攤開的文件越多。但即便桌子很大,如果文件亂成一團,也沒辦法完成工作。
對 AI 來說,比起能塞多少資訊進視窗,更重要的是「以什麼結構把資訊給它」。
當 AI 程式碼輔助工具(Cursor、Claude Code、GitHub Copilot 等)理解一個程式碼庫時,它主要在看:
tree 命令的整體概況.d.ts、OpenAPI 規格反過來說,如果這些項目沒有整理好,AI 就像在「黑暗中摸索」。每次被問「這個專案用哪個 framework?」「測試怎麼跑?」時,就是 AI 無法抓住文脈的證據。
本章重點:各檔案的角色、設計原則、可複製的範本
建議的使用方式如下:
實用技巧:若以 CLAUDE.md 為主管理,可以在 AGENTS.md 建立符號連結(symlink)讓兩者共用。
範例:
# 以 CLAUDE.md 為主,AGENTS.md 建符號連結
ln -s CLAUDE.md AGENTS.md
撰寫良好 AGENTS.md / CLAUDE.md 的五項原則如下:
原則 1:規則要附上「為什麼」
如果沒有「為什麼」,AI(以及新成員)在遇到例外情況時容易判斷錯誤。知道理由的人比較能靈活應用規約。
原則 2:明確 NEVER(絕對禁止)區塊
AI 傾向犯的錯誤要明確列出禁止事項。對 AI 而言,「不能做的事」比「可以做的事」更容易遵守。
## NEVER(絕對不能做)
- 不使用 default export(僅允許 named export)
- 不直接修改 node_modules/ 或 vendor/
- 不把 .env 檔案加入程式碼
- 不刪除既有測試(可修正)
- 不在生產程式碼遺留 console.log
原則 3:提供 2–3 個程式碼範例
文字描述不如實例來得清楚,範例可顯著提升傳達效果。
// API Route 範例
// app/api/users/route.ts
import { NextResponse } from 'next/server'
import { z } from 'zod'
const querySchema = z.object({
page: z.coerce.number().min(1).default(1),
limit: z.coerce.number().min(1).max(100).default(20),
})
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const query = querySchema.parse(Object.fromEntries(searchParams))
// ... 實作
return NextResponse.json({ data, pagination })
}
原則 4:安裝 / 啟動命令用一行寫好
AI 想要嘗試東西時,一行能啟動的指令會直接提升生產力。需要五個步驟的設定,對 AI(及人)都是障礙。
# 範例
npm install && npm run dev # 啟動開發伺服器
npm test # 執行所有測試
npm run lint # 執行 linter
npm run typecheck # 型別檢查
原則 5:明確劃定權限邊界
要讓 AI 清楚知道哪些可以直接改、哪些需要先確認、哪些絕對不可以做。
## 權限
### 可以自由修改
- src/ 底下的程式碼
- 新增或修正測試
- 更新文件
### 需先確認
- package.json 的相依套件新增
- 資料庫 schema 變更
- 新增環境變數
### 絕對不可以
- 修改 .env* 檔案
- 變更 CI/CD pipeline 設定
- 直接存取生產資料庫
以下為可填寫的 AGENTS.md 範本,請把 {...} 替換成專案相應內容。
# AGENTS.md
## 專案概要
{專案名稱} 是 {一句話描述專案}。
技術棧: {Next.js / TypeScript / MongoDB / etc.}
## 架構
- 使用 {App Router / Pages Router / etc.}
- 狀態管理: {Zustand / Redux / etc.}
- DB: {MongoDB / PostgreSQL / etc.} with {ORM: Prisma / Mongoose / etc.}
- 認證: {NextAuth / Clerk / etc.}
## 目錄結構
{tree 輸出或目錄結構概述}
## 程式碼規範
- 命名規則: {camelCase / PascalCase 等}
- import 順序規則
- 元件寫法規範
## 設定(Setup)
```bash
{安裝指令}
{啟動開發伺服器}
{執行測試}
{執行 linter}
{貼上 2–3 個代表性範例}
這些地方需要靠你自己思考,不適合完整複製貼上:
把 AGENTS.md 當成「會演進的文件」,在與 AI 共事的過程中發現錯誤就加到 NEVER,持續養成。
本章重點:針對既有程式庫,讓它更 AI 友好的 5 個具體改法
AI agent 最常要執行的是「測試」和「Lint」。能否用一條指令把它們跑完會大幅影響效率。
在 package.json 中加入如下 scripts:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"test": "vitest run",
"test:watch": "vitest",
"lint": "eslint . --ext .ts,.tsx",
"typecheck": "tsc --noEmit",
"validate": "npm run typecheck && npm run lint && npm run test"
}
}
重點是 validate 指令:型別檢查 → Lint → 測試 一次跑完。AI 做完修改後跑 npm run validate,就能立即知道有沒有破壞東西。
分層式架構(Layered Architecture)範例:
src/
├── controllers/
│ ├── userController.ts
│ ├── orderController.ts
│ └── productController.ts
├── services/
│ ├── userService.ts
│ ├── orderService.ts
│ └── productService.ts
├── repositories/
│ ├── userRepository.ts
│ ├── orderRepository.ts
│ └── productRepository.ts
└── models/
├── user.ts
├── order.ts
└── product.ts
Vertical Slice(功能切片)範例:
src/
├── features/
│ ├── users/
│ │ ├── api.ts
│ │ ├── service.ts
│ │ ├── repository.ts
│ │ ├── schema.ts
│ │ ├── types.ts
│ │ └── __tests__/
│ │ └── users.test.ts
│ ├── orders/
│ │ ├── api.ts
│ │ ├── service.ts
│ │ └── ...
│ └── products/
│ ├── ...
└── shared/
├── db.ts
├── auth.ts
└── errors.ts
為什麼推薦 Vertical Slice?因為對 AI 而言,將一個功能相關的檔案集中在同個資料夾,比起在 controllers/、services/、repositories/ 之間橫跨尋找,更容易把需要的資訊完整放進上下文視窗。對人類也是一樣:新成員問「使用者功能在哪裡?」直接說「看 features/users/」就好。
對 AI 來說,型別定義是理解專案領域模型(domain model)的捷徑。多寫型別和 JSDoc 註解,會讓 AI 更精準推斷驗證與行為。
範例:
// src/features/users/types.ts
/** 使用者建立請求 */
export interface CreateUserInput {
/** 電子郵件(符合 RFC 5322) */
email: string
/** 顯示名稱(2-50 字) */
displayName: string
/** 角色(預設: member) */
role?: 'admin' | 'member' | 'viewer'
}
/** 使用者回傳(不包含密碼雜湊等內部資訊) */
export interface UserResponse {
id: string
email: string
displayName: string
role: 'admin' | 'member' | 'viewer'
createdAt: string
updatedAt: string
}
/** 使用者列表的分頁回傳 */
export interface UsersListResponse {
users: UserResponse[]
pagination: {
page: number
limit: number
total: number
hasNext: boolean
}
}
JSDoc 註解很重要。AI 會讀到像「email 要符合 RFC 5322」「displayName 需 2–50 字」的資訊,能推測該實作什麼驗證邏輯。花時間在型別與註解上,遠比事後修正 AI 生成錯誤來得省時。
當 AI 產生的程式碼出錯時,若專案使用結構化錯誤(含錯誤碼、訊息、HTTP status、details),修正效率會大幅提升。
範例:
// src/shared/errors.ts
export class AppError extends Error {
constructor(
public readonly code: string,
message: string,
public readonly statusCode: number = 500,
public readonly details?: Record<string, unknown>
) {
super(message)
this.name = 'AppError'
}
}
// 使用方式
throw new AppError('USER_NOT_FOUND', `User with id ${userId} not found`, 404, { userId })
// ❌ 不建議
throw new Error('not found') // 無法知道是哪個資源找不到
如果有像 USER_NOT_FOUND 這樣的錯誤碼,AI 就能立刻理解「這是使用者不存在的情境」,並提出適當修正。只寫「not found」,上下文就丟失了。
大型專案僅靠根目錄的 AGENTS.md 常不夠。每個主要功能資料夾放一個小型 README,讓 AI 在需要時可以取得關鍵文脈。
範例:src/features/users/README.md
# Users Feature
## 概要
負責使用者的 CRUD 與角色管理。
## 相依
- MongoDB(透過 Mongoose)
- NextAuth(認證)
## 測試
```bash
npm test -- --filter users
這對 monorepo 或大型專案特別有效。當 AI 要處理 users 功能時,讀這個 README 就能知道「是用軟刪除」「bcrypt rounds=12」等專案細節。
本章重點:用測試、linter、CI 自動保證 AI 輸出的品質
把 AI 產生的程式碼放著「看起來能跑就算了」,其實風險很高。人寫的程式也要被 code review,AI 的程式也需要自動驗證機制。
有趣的現象是:專案測試覆蓋率越高,AI 的輸出品質傾向越高。
原因很簡單:AI 會把測試當成「規格書」來讀。測試越完整,AI 就越能清楚知道「這個函式對哪些輸入要回傳什麼輸出」。沒有測試,AI 只能憑猜測實作,容易遺漏重複檢查、驗證等重要行為。
測試範例:
// src/features/users/__tests__/users.test.ts
import { describe, it, expect } from 'vitest'
import { createUser } from '../service'
describe('createUser', () => {
it('能用有效輸入建立使用者', async () => {
const input = {
email: '[email protected]',
displayName: '測試太郎',
role: 'member' as const,
}
const user = await createUser(input)
expect(user.email).toBe(input.email)
expect(user.displayName).toBe(input.displayName)
expect(user.role).toBe('member')
expect(user.id).toBeDefined()
})
it('重複郵件應回傳錯誤', async () => {
await createUser({ email: '[email protected]', displayName: 'A' })
await expect(
createUser({ email: '[email protected]', displayName: 'B' })
).rejects.toThrow('USER_EMAIL_DUPLICATE')
})
it('不合法郵件應回傳驗證錯誤', async () => {
await expect(
createUser({ email: 'invalid', displayName: 'C' })
).rejects.toThrow('VALIDATION_ERROR')
})
})
有了這些測試,AI 能完整理解 createUser 的行為。沒有測試就有遺漏重複檢查或驗證的風險。
至少設定以下項目可以顯著穩定 AI 產出品質:
.husky/pre-commit:
npm run typecheck && npm run lint
並在 package.json 加入 lint-staged:
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"]
}
}
這樣能阻擋型別錯誤與違反 linter 規則的程式碼被 commit。AI 生成的程式碼也必須通過這些關卡才能進入倉庫。
建立一個 validation 的 GitHub Actions workflow:
# .github/workflows/validate.yml
name: Validate
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- run: npm ci
- run: npm run typecheck
- run: npm run lint
- run: npm run test -- --coverage
- name: Coverage check
run: |
COVERAGE=$(npx vitest run --coverage --reporter=json | jq '.total.lines.pct')
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "Coverage $COVERAGE% is below 80% threshold"
exit 1
fi
重點是設定「覆蓋率閾值」。有這個機制時,AI 新增程式碼就必須同時新增測試,否則 CI 會失敗。不需每次口頭要求 AI 寫測試,機制會強制執行。
請用下列檢查表測試你的程式庫目前有多「AI‑Ready」。
評分參考:
感謝看到這裡。
本文想傳達的核心是:
AI 編程工具之間的性能差距已經越來越小。到 2026 年為止,Cursor、Copilot、Claude Code 等都已經相當強大。決定差異的是你交給工具的「文脈品質」,也就是程式庫設計。
只要多加一個 AGENTS.md 檔、調整目錄結構、或是補一點測試,都會產生很大的差異。不需要一次全部做完,選一件今天就能做的小事開始即可。
我個人感受到工程師的工作在改變:從「寫程式的人」變成「設計 AI 可讀文脈的人」。這是詮釋會讓職務被取代,還是提升工作品質,端看你的觀點。不過至少對我來說,花時間設計要給 AI 的文脈,是最有創意也最有趣的工作。
今天就做的三件事建議:
npm run validate,讓測試、linter、型別檢查一鍵跑完小步快跑,但能確實改變與 AI 協作的品質。
原文出處:https://qiita.com/akira_papa_AI/items/0385b6d1468e6d564b50