Cline AI 助理令人著迷
原文由 Michael Lynch 于 發布,訂閱此部落格
昨天我試用了 Cline AI 助理,結果整整五個小時陷入恍神狀態,只能目不轉睛地看著 Cline 幫我修 bug。
身為一名專業開發者,這種體驗既讓人著迷,又讓人感到恐懼。著迷的是,人工智慧已經達到了這樣的水準;恐懼的也是同一個原因——在人工智慧寫程式比我又好又快的世界裡,我還能扮演什麼角色,我完全不確定。
在這方面我算是後知後覺,我知道大多數開發者早就更深入地把 AI 工具整合進工作流程了,但我想把自己的所見分享給還沒體驗過的人。
我以前就用過 AI 工具
Cline 並不是我第一次使用人工智慧。
過去兩年來我一直在嘗試 LLM 助理。最近半年我用得更頻繁了,因為模型已經進步到能夠穩定地產出正確的程式碼。
我用 Kagi 當作搜尋引擎,它的 Ultimate 方案可以無限使用所有主流的 LLM。我主要透過 Kagi Assistant 這項功能跟 LLM 互動,它其實就是一個網頁版的聊天介面。

我的搜尋引擎 Kagi 為所有主流 LLM 提供了很不錯的網頁聊天介面。
利益揭露:我有參與 Kagi 的群眾募資,所以對他們有一些財務上的投資,雖然我自己也不太清楚細節。
用 AI 工具讓我覺得自己才是機器人
我最近發現的問題是,AI 工具讓我覺得自己才是機器。我只是呆坐在那裡,機械式地在編輯器和聊天介面之間複製貼上程式碼,然後說一句「沒用」,再貼上錯誤訊息,整個流程重複個四、五次。


聊天機器人 LLM 不斷給出錯誤的修復方式,還得費好大功夫催促,它才肯給出完整的解法。
一定有工具能解決這個問題
我意識到,一定有比我現在這種做法更好的 AI 整合方式。
我需要一個工具來接手我這個「來回複製程式碼和錯誤訊息」的工作。
我隔了大約一年試了兩次 Sourcegraph Cody,兩次都很失望。讓它直接在原地修改程式碼,確實比在瀏覽器和編輯器之間貼來貼去好,但 Cody 慢又有 bug,最後我還是回去用瀏覽器複製貼上的老方法。
最近我看到幾篇關於 Cline 的部落格文章,因為幾個原因覺得它很吸引人:
- 程式碼是 開源的。
- 它能整合進 VS Code,也就是我主要使用的編輯器。
- 它能處理編輯本地檔案、執行指令,並根據指令的輸出持續迭代。
- 如果我想用的話,它也允許我使用本地端的 LLM。
- 它不像許多其他 AI 助理那樣,硬要當作購買 AI API 的中間商。
缺點是,Cline 除了燒投資人的錢之外,似乎沒有什麼營收來源。所以它可能無法長久維持,但目前用起來還行。
詞彙幻覺:測試 AI 助理的完美題目
最近我一直想要一個能掃描部落格中「詞彙幻覺」的工具。這是 Matt Might 所說的一種現象,指的是你在文字中沒發現重複的單字,例如:
Many readers are not aware that the
the brain will automatically ignore
a second instance of the word “the”
when it starts a new line.
我在部落格上經常犯這種錯,而且往往要到校稿後期甚至發布後才會發現。
Matt Might 曾分享過一個用來找出詞彙幻覺的 Perl 腳本,但它很陽春,而且因為我部落格裡的 Markdown 格式符號,產生了很多誤判。
我請 Kagi Assistant 用 Python 寫一個能辨識 Markdown 的版本,但它一直產出有 bug 的程式碼。
我意識到這是測試 Cline 的完美案例,因為問題很容易定義。我應該只要不斷給 AI 助理展示我想要的行為所對應的測試案例,它就能不斷修改程式碼,直到測試通過為止。
這也是一個用 Zig 來寫的藉口,因為我希望這個工具在掃描大量檔案時能跑得越快越好,而且我 很喜歡用 Zig。
定義問題
我這個工具的主要介面很簡單:它需要接收檔案內容作為一個字串(在 Zig 中是 [] const u8),然後產生一份重複單字的清單,並附上各自所在的行號。
基本的核心介面長這樣:
pub const DupeWord = struct {
line_number: u32,
word: []const u8,
};
pub fn FindAdjacentDupes(allocator: std.mem.Allocator,
input: []const u8) !ArrayList(DupeWord) {
// TODO: Implement this.
}而這是我最初的單元測試:
test "FindAdjacentDupes" {
// Don't consider distinct words to be duplicates.
try testFindDupes("cat dog", &[_]DupeWord{});
// Find simple dupes.
try testFindDupes("cat cat", &[_]DupeWord{
.{ .line_number = 1, .word = "cat" },
});
}
fn testFindDupes(input: []const u8, expected: []const DupeWord) !void {
const allocator = testing.allocator;
var result = try FindAdjacentDupes(allocator, input);
defer {
for (result.items) |item| {
allocator.free(item.word);
}
result.deinit();
}
try testing.expectEqual(expected.len, result.items.len);
for (expected, 0..) |expected_dupe, i| {
try testing.expectEqual(expected_dupe.line_number, result.items[i].line_number);
try testing.expect(std.mem.eql(u8, expected_dupe.word, result.items[i].word));
}
}Cline 的初步成果
在大約 30 秒內、花了 0.09 美元的 LLM 額度後,Cline 就讓測試通過了:

Cline 把 FindAdjacentDupes 更新成這樣的實作:
pub fn FindAdjacentDupes(allocator: std.mem.Allocator, input: []const u8) !ArrayList(DupeWord) {
var result = ArrayList(DupeWord).init(allocator);
var it = std.mem.splitScalar(u8, input, ' ');
var prev_word: ?[]const u8 = null;
while (it.next()) |word| {
if (prev_word) |prev| {
if (std.mem.eql(u8, prev, word)) {
const dupe_word = try allocator.dupe(u8, word);
try result.append(DupeWord{
.line_number = 1,
.word = dupe_word,
});
}
}
prev_word = word;
}
return result;
}Cline 走了一些彎路,像是把 const 寫成 var 或是用到已被棄用的 API,但它像人一樣,會根據錯誤訊息自我修正。
這個實作顯然還不完整,因為它沒有處理 Markdown 格式、大小寫或標點符號。我也還沒給 Cline 看過任何行號不是 1 的測試案例,所以目前的實作直接把行號寫死成 1。
就是在那時我入迷了
在 Cline 完成初步實作後,我不斷寫新的測試案例,然後看著 Cline 更新程式碼來滿足我的測試。
也就是在那時我徹底入迷了。我非常驚訝竟然可以用這種方式開發軟體。我只要告訴工具我想要什麼,它就會完全照著我的要求去做。
以下是這篇文章開頭那支影片,展示了實際操作起來的樣子:
成果
我花了剩下的整天時間跟 Cline 一起實作這個工具。現在我已經有一個可用的重複單字搜尋工具了,我叫它 wordword:
我用 wordword 在我的部落格上找到了 七處詞彙幻覺的錯誤。
總計,我在 OpenRouter 上只花了 6 美元的額度,這相當於連續跟 Cline 工作了五個小時。
到目前為止我學到什麼
無人監督的運作不是最佳解,但便宜到無所謂
Cline 有個選項,會在每個步驟前請你確認計畫。我很快就厭倦了每五秒就要按一次「Approve」,乾脆設成自動核准讀取檔案、寫入檔案和執行指令。
我發現如果我完全不去管它,Cline 偶爾會卡在死胡同裡,反覆嘗試注定會失敗的策略。
儘管如此,我還是大多讓 Cline 在無人監督的情況下跑到找到解法或達到 20 次嘗試的上限為止。這些死胡同會消耗一些 API 額度,但不過就是幾分錢的規模,比起緊盯著助理,我寧願冒險浪費幾分錢。
Cline 無條件信任你,所以要謹慎用詞
Cline 最混亂的時候,就是我不小心寫了行為錯誤的測試案例時。
這是我寫得太匆忙的一個測試案例:
// Detect duplicates after a heading
try testFindDupes(
\\## Foods
\\
\\These potatoes potatoes are the best!
, &[_]DupeWord{
.{ .line_number = 1, .word = "potatoes" },
}我不小心把行號寫成 1,但其實應該是 3。
當我要求 Cline 讓這個測試通過時,它有點崩潰,拼命想辦法去合理化為什麼明明應該是 3 的行號,卻要被指定為 1。
鼓勵 Cline 加入除錯的列印訊息
我注意到 LLM 傾向於猜測解法,而不是停下來收集更多資訊來了解程式碼為什麼會那樣運作。
當我發現 Cline 陷入盲目嘗試修 bug 的迴圈時,我發現暫停它的工作、指示它插入除錯的列印訊息來驗證它對程式碼的假設,會很有幫助。Cline 會加上有用的除錯輸出,而且在宣告完成解法前,會記得把它們全部移除。
Kagi 肯定在我身上賠錢了
這是我第一次使用按用量計費的 LLM API。我看過人們討論 token 的成本,但我從來沒有直觀的感受,因為 Kagi 基本上就是跟你說:「別擔心要花多少錢。」
Cline 很貼心地會在過程中即時顯示每個程式任務花了多少額度。

所以,我絕對是占了 Kagi 每月 25 美元無限方案的便宜。我跟 Cline 合作五小時就花了 6 美元,而且 Cline 已經做了很多事來減少 token 的消耗。我每天都用 Kagi Assistant,而且經常在一次對話中就貼上十幾次巨大的檔案。現在看到這些成本,我大概每天要讓 Kagi 花掉 5 到 10 美元的 API 額度。
其他資源
大多數關於 AI 的文章內容空洞,也沒什麼實用的心得。我覺得在了解可能性方面最有用的是這幾篇:
- “Everything I built with Claude Artifacts this week” 由 Simon Willison 撰寫
- “How I Use ‘AI’” 由 Nicholas Carlini 撰寫
- “How I program with LLMs” 由 David Crawshaw 撰寫
隨機一篇部落格
留言
登入後參與討論