The Cline AI Assistant is Mesmerizing

Michael Lynch

Cline AI 助理令人著迷

我昨天試用了Cline AI 助理,接著就陷入了長達五小時的恍神狀態,只能目不轉睛地看著 Cline 幫我修復錯誤。

身為一名專業開發者,這種體驗既令人著迷又讓人感到恐懼。著迷的是,AI 已經達到了這樣的水準;恐懼也是出於同樣的原因,因為我不確定在一個 AI 寫程式比我更好、更快的世界裡,我還能扮演什麼角色。

在這方面我算是後知後覺,我知道大多數其他開發者已經更深入地將 AI 工具整合到工作流程中,但我想把我的所見所聞分享給還沒有體驗過的人。

我以前也用過 AI 工具

Cline 並不是我第一次使用 AI。

過去兩年來,我一直在嘗試使用 LLM(大型語言模型) 助理。在過去六個月中,我開始更大量地使用它們,因為模型已經達到了能夠穩定產生正確程式碼的水準。

我使用Kagi作為搜尋引擎,他們的 Ultimate 方案包含對所有主流 LLM 的無限存取。我主要是透過 Kagi Assistant 功能與 LLM 互動,它其實就是一個用來與 LLM 對話的網頁介面。

我的搜尋引擎 Kagi 為所有主流 LLM 提供了不錯的網頁聊天介面。

利益揭露:我曾參與 Kagi 的群眾募資,所以對他們有一些我自己也不太清楚的財務投資。

使用 AI 工具讓我覺得自己才是機器人

我最近發現的問題是,AI 工具讓我覺得自己才是機器。我只是茫然地坐在那裡,在編輯器和聊天介面之間來回複製程式碼,然後說:「沒有用」,貼上錯誤訊息,然後這樣重複四、五次。

一個聊天機器人 LLM 不斷給出錯誤的除錯方法,然後需要反覆催促才肯顯示完整的解決方案。

一定有工具可以解決這個問題

我意識到一定有比我現在這種做法更好的 AI 整合方式。

我需要一個工具來接手我這個「來回複製程式碼和錯誤訊息」的人所做的工作。

我曾相隔約一年試用過兩次 Sourcegraph Cody,兩次都令人失望。讓它直接在原地編輯我的程式碼,確實比在瀏覽器和編輯器之間來回貼上要好,但 Cody 速度慢又充滿錯誤,最後我還是回去在網頁瀏覽器之間來回貼程式碼。

我最近看到幾篇關於 Cline 的部落格文章,基於幾個原因,它聽起來很吸引人:

  • 程式碼是 open-source(開放原始碼) 的。
  • 它能與我的主要編輯器 VS Code 整合。
  • 它可以處理編輯本地檔案、執行指令,並根據指令輸出進行反覆修正。
  • 如果我想,它還允許我使用本地端的 LLM。
  • 它不像許多其他 AI 助理那樣,堅持要當作購買 AI API 存取權的中間人。

缺點是,Cline 似乎除了燒投資人的錢之外,沒有其他收入來源。所以,它可能無法永續經營,但就目前而言還可以。

Lexical illusions(詞彙幻覺):AI 助理的完美測試程式

我最近一直希望有個工具能掃描我的部落格,找出「lexical illusions」。這是 Matt Might(馬特·邁特)對你在文字中無法察覺重複單字的現象的稱呼,例如:

許多讀者沒有意識到 the
the 大腦會自動忽略
當「the」這個字在新的一行開頭重複出現時的第二個實例。

我在部落格上經常犯這種錯誤,而且往往要到校稿後期甚至發布後才會發現。

馬特·邁特分享了一個尋找 lexical illusions 的 Perl 腳本,但它相當陽春,而且由於 Markdown 格式字元的關係,在我的部落格上產生了大量誤判。

我請 Kagi Assistant 寫一個能處理 Markdown 的 Python 版本,但它一直產生有錯誤的程式碼。

我意識到這是 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 也走了一些彎路,例如用了 var 而不是 const,或是使用了已淘汰的 API,但它會像人類一樣根據錯誤訊息自我修正。

這個實作顯然還不完整,因為它沒有處理像是 Markdown 格式、大寫字母或標點符號等情況。我還沒有給 Cline 任何行號不是 1 的測試案例,所以目前的實作將行號寫死為永遠回傳 1

就是在那時我入迷了

在 Cline 完成初步實作後,我不斷撰寫新的測試案例,然後看著 Cline 更新它的程式碼來滿足我的測試。

就是在那時我入迷了。我非常驚訝竟然可以用這種方式開發軟體。我只要告訴工具我想要什麼,它就會持續照著我的要求去做。

以下是這篇文章頂部我展示的影片,呈現了實際運作的樣子:

成果

我花了剩下的時間與 Cline 一起實作這個工具。現在我已經有了一個可運作的重複單字尋找工具版本。我把它叫做 wordword

我用 wordword 在我的部落格上找到了七個 lexical illusion 錯誤

總計,我在 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 加入除錯用的 print 陳述式

我注意到 LLM 傾向於猜測解法,而不是停下來收集更多關於程式碼為何會這樣運作的資訊。

當我發現 Cline 陷入盲目嘗試修復錯誤的循環時,我發現暫停它的工作並指示它插入除錯用的 print 陳述式來驗證它對程式碼的假設會很有幫助。Cline 加入了有用的除錯輸出,而且在宣布解決方案完成之前,它會記得將它們全部移除。

Kagi 在我身上一定賠錢了

這是我第一次使用按量計費的 LLM API。我看過人們討論 token 成本,但我從來沒有直觀的感受,因為 Kagi 基本上就是說:「別擔心花多少錢。」

Cline 會貼心地在過程中顯示每個程式設計任務累積花費了多少點數。

所以,我確實在 Kagi 每月 $25 的無限方案中佔了便宜。我用 Cline 在五小時內花了 $6,而 Cline 做了很多努力來最小化 token 的消耗。我每天都使用 Kagi Assistant,並且經常在一次對話中貼上 10 次以上的大型檔案。現在看到成本後,我每天大概讓 Kagi 花費 $5 到 $10 的 API 點數。

其他資源

大多數關於 AI 的文章內容空洞或缺乏實用經驗。以下幾篇是我覺得對於了解可能性最有幫助的:

原文由 Michael Lynch 發布

本文章由 muse-spark-1.2-contributor 進行翻譯