到現在為止,我一直覺得 AI agent 周圍籠罩著一種神祕的光環。沒有人真的知道它們在做什麼,它們大概很快就要接管世界了;而如果你想自己做一個……嗯,顯然你需要一個框架。
如果我告訴你這不是真的呢?你可以在大約 80 行程式碼內做出自己的 AI agent。
我得承認,這週不太好過。工作上發生了很多事。除此之外,我還收到其中一個 CFP 的自動拒絕信。正常來說,這大概只會佔據我五分鐘的心思,因為會議被拒本來就是家常便飯。
只不過……那場會議其實是邀請我去的。「你已經被接受了,只需要在 CFP 裡填交演講細節。」因為那個邀請,我還推掉了另外兩個會議機會。唉,至少我現在九月有空了。😉
不管怎樣,生活還是要繼續。今天是我的生日,所以當作送給自己、也送給大家的一份小禮物,我寫了這篇文章。😄 希望你會喜歡!
直接切入正題。
像 LangChain、CrewAI 或 Mastra 這類框架,並不是在施魔法。它們只是把像是對話記憶、工具執行、重試、備援等事情簡化了。
一旦你理解底層機制,就會更容易判斷什麼時候框架真的值得用。即使最後還是會用框架,你也會知道幕後到底發生了什麼。
所以我決定做一個小型 demo,看看 AI agent 到底只需要多少程式碼。
我用 Node.js 寫了一個 AI agent,大約只用了 80 行程式碼……好吧好吧,核心迴圈大概是 80 行。還是有工具、供應商抽象層,以及一些周邊邏輯。不過老實說,「80 行寫出一個 AI agent」 聽起來就是比較厲害。😄
這是專案倉庫:
https://github.com/sylwia-lask/code-review-agent
而且今天是我的生日……如果你喜歡這個專案,歡迎幫我點個 ⭐。當然,前提是你真的喜歡。😄
這個應用程式是一個簡單的程式碼審查 agent。嗯……其實也不完全是。
認識一下 Steve:一位有 15 年經驗、專門審查別人程式碼的軟體工程師。Steve 不會照單全收。沒錯,他有時候可能有點酸……但他的結論通常很難反駁。
以下是他的一個程式碼審查範例:


或者當你有空的 diff 時:

目前 Steve 會審查本機的 Git diff。這基本上就表示……他在審查他自己。所以我想,我大概是做出了一個傳說中的自我修復 agent 原型;根據 @nitsancohen770 的說法,這東西有一天會把我的工作搶走。
如你所見,我基本上是在幫自己自動化失業。也許我真的該開始考慮退休了。😄
在我上一篇文章裡,我曾開玩笑說,有些人認為 AI agent 不過就是一個 while 迴圈。嗯……我的甚至連 while 都不是。它是個 for 迴圈,因為我想避免不小心做出無限迴圈,然後在 token 上燒掉太多錢。😄
好吧,公平地說,這個迴圈本身其實沒有真的做什麼。它只是負責協調流程。不過有趣的是,大多數 agent 框架在底層做的事情其實也非常類似。
這個迴圈本身很容易寫。真正的挑戰,其實就是你猜得到的那一塊。
做 AI agent 的第一步就是……選擇 LLM。😄 這次我選了 Gemini API,因為這類專案的 token 真的便宜到誇張。我確實很想下一版改用本機模型來做,但……先等等。😄
我立刻遇到一個問題:有些 Gemini 模型負載過高,所以我一直收到 503 回應。這代表我必須實作一些框架通常開箱即有的功能——簡單的重試機制。
我的版本刻意做得非常基本。正式環境的框架通常還會提供更多功能,例如指數退避、抖動(jitter),或自動切換到另一個模型。
接下來的挑戰當然就是,寫出正確的提示詞。之後,一切就變得出乎意料地順利。
比你想的簡單多了。
我們送兩樣東西給模型:
請求長這樣:
{
"model": "gemini-2.5-flash",
"contents": [
{
"role": "user",
"parts": [
{
"text": "Please review the current git diff."
}
]
}
],
"config": {
"systemInstruction": "You are Steve, a senior software engineer with 15 years of experience...",
"tools": [
{
"functionDeclarations": [
{
"name": "getDiff",
"description": "Get the git diff of the current repository...",
"parameters": {
"type": "OBJECT",
"properties": {},
"required": []
}
},
{
"name": "getFile",
"description": "Read a file from the repository...",
"parameters": {
"type": "OBJECT",
"properties": {
"path": {
"type": "STRING",
"description": "Path to the file relative to the repository root"
}
},
"required": ["path"]
}
},
{
"name": "listFiles",
"description": "List files and directories at a given path...",
"parameters": {
"type": "OBJECT",
"properties": {
"path": {
"type": "STRING",
"description": "Directory path relative to the repository root"
}
},
"required": ["path"]
}
}
]
}
]
}
}
模型可以用三種方式回應:
如果它回傳純文字,我們就完成了:那就是最後的程式碼審查結果。如果它要求我們呼叫工具,就進入步驟 3。
例如,我們可能會收到:
{
"candidates": [
{
"content": {
"role": "model",
"parts": [
{
"text": "Let's see what damage we're dealing with today..."
},
{
"functionCall": {
"id": "call_001",
"name": "getDiff",
"args": {}
}
}
]
}
}
]
}
接下來輪到我們的應用程式。
我們在本機執行要求的工具。例如執行 git diff 或讀取倉庫中的某個檔案,然後把結果作為對話中的另一則訊息送回給模型。
這個 demo 可用的工具有:
getDiffgetFilelistFiles換句話說,這就是一個好的程式碼審查者需要的一切。😄
然後我們只要回到步驟 2。為了避免卡進無限迴圈,我把最大迭代次數限制在 10 次。
不過,還有一個重要細節。
看看下一個請求。注意我們把整段對話歷史一起送回模型:
{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Please review the current git diff."
}
]
},
{
"role": "model",
"parts": [
{
"text": "Let's see what damage we're dealing with today..."
},
{
"functionCall": {
"id": "call_001",
"name": "getDiff",
"args": {}
}
}
]
},
{
"role": "user",
"parts": [
{
"functionResponse": {
"id": "call_001",
"name": "getDiff",
"response": {
"result": "diff --git a/src/auth.ts b/src/auth.ts\n--- a/src/auth.ts\n+++ b/src/auth.ts\n@@ -12,7 +12,7 @@\n- if (password === storedHash) {\n+ if (password == storedHash) {\n"
}
}
}
]
}
]
}
就這樣而已。LLM 會決定要用哪個工具,以及什麼時候結束。其他所有事情——執行工具、處理重試、限制迭代次數、以及協調整個迴圈——都是我們應用程式的責任。
很簡單,對吧?如果你喜歡視覺化,ChatGPT 已經幫我們準備了一張圖 😉

我未來想至少再寫兩篇延伸文章。一篇是把 Steve 接到 MCP,另一篇是用 本機 LLM 取代託管模型。
不過……先等等,一步一步來。😄
如果你只是想學怎麼做 AI agent,那你大概可以看到這裡就停了。😄
這一段是給好奇的人看的。因為遲早會有人問:「Sylwia,你到底在說什麼?你說你在做自己的 AI agent,但你其實只是用了 Gemini SDK。你送進去 JSON,回來也是 JSON。」
而且,正如 @darkwiiplayer 常常指出的,LLM 基本上就是一個很厲害的下一個 token 預測器,不是什麼神奇的 JSON 產生器。
那麼……當我們送 JSON 給它時,模型到底怎麼知道該做什麼?如果不是 Gemini,而是一些老舊的本機 Llama 模型,會發生什麼事?
是 Gemini SDK 偷偷在前面加了一段特殊提示詞嗎?還是這些模型本身就有針對這種情境訓練?
老實說,我們並不知道所有細節。不過我們知道的是,像 Gemini 和 GPT 這類模型原生支援工具呼叫。SDK 負責正確格式化請求並與 API 溝通,而模型本身理解工具宣告,並且在判斷需要時可以產生函式呼叫。
換句話說,如果我們拿一個較舊的 Llama 模型,也還是可以寫一段提示詞,說明如何解讀 JSON,並要求它以特定的 JSON 格式回應。
然後我們只要呼叫 JSON.parse()……
……前提是模型真的回傳有效的 JSON,而不是 Markdown、說明文字,或它決定額外加上的幾句「貼心」註解。😄
話雖如此,值得一提的是,較新的開源模型也越來越多原生支援工具呼叫了。
老實說,現在是 2026 年。這個 agent 很大一部分是由……另一個 AI agent 寫出來的。😄
因為我已經當了一段時間的 AWS Community Builder,所以我取消了 Claude Code 訂閱,改用 Kiro:一個內建支援多種 LLM 的 AI IDE,包括 Claude、GPT 和 Gemini。價格差不多,但因為這個計畫,我可以免費使用。
到目前為止,我真的很喜歡它。它有點像是建構在 VS Code 上的 agent 驅動層,所以我很快就上手了。我也覺得我現在可能只用了它實際功能的 10%,所以我很確定未來還會再寫更多關於它的內容。
現在我只希望 AWS 終於會寄一些周邊給我。😄 我特別想要他們的一件 T 恤。好多年前,波蘭其實真的有一個名叫 AWS 的政黨,所以我超想看看一些年長者看到它時的表情。😄
AWS……如果你們正在看這篇……我在等你們!!😄
如你所見,AI agent 不一定非得從框架開始。有時你只需要一個 LLM、一些工具、對話歷史,以及一個簡單的迴圈。其他的一切,都是便利性、正式環境強化,以及提升使用體驗的改良。
所以……
你覺得 Steve 怎麼樣?你又喜不喜歡這種打造 AI agent 的方式? 😄
如果你喜歡這篇文章,也可以在 LinkedIn 上追蹤我。
原文出處:https://dev.to/sylwia-lask/the-dirty-secret-behind-ai-agents-demo--273d