The Cline AI Assistant is Mesmerizing

Michael Lynch

Cline AI 助手令人着迷

昨天我试用了Cline AI assistant,然后就陷入了长达五小时的恍惚状态,只能目不转睛地盯着 Cline 为我修复 bug。

作为一名专业开发者,这种体验既令人陶醉又令人恐惧。令人陶醉的是,AI 已经达到了如此高的水平;令人恐惧的原因也在于此,因为我不确定在一个 AI 写代码比我更好、更快的世界里,自己还能扮演什么角色。

在这方面我算是后知后觉了,我意识到大多数其他开发者已经更深入地将 AI 工具集成到了工作流程中,但我想把自己的所见分享给那些还没有体验过的人。

我以前也用过 AI 工具

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

在过去两年里,我一直在尝试使用 LLM 助手。在过去六个月里,随着模型已经达到了能够稳定生成正确代码的水平,我对它们的使用也变得更加频繁。

我使用Kagi作为搜索引擎,他们的 Ultimate 套餐可以无限制地访问所有主流 LLM。我主要通过 Kagi Assistant 功能与 LLM 交互,它只是一个用于与 LLM 聊天的网页界面。

我的搜索引擎Kagi为所有主流 LLM 提供了一个不错的网页聊天界面。

完全披露:我参与了 Kagi 的众筹,所以我在他们那里有一些我自己也不太明白的财务投资。

使用 AI 工具让我觉得自己才是机器人

我最近发现的问题是,AI 工具让我觉得自己才是机器。我只是麻木地坐在那里,在编辑器和聊天界面之间来回复制代码,然后说“不行”,粘贴错误信息,整个过程要重复四五遍。

聊天机器人 LLM 总是给出错误的 bug 修复方案,然后需要大量催促才会展示完整的解决方案。

肯定有工具能解决这个问题

我意识到一定有比我现在这种方式更好的 AI 集成方法。

我需要一个工具来接管我这个“来回复制代码和错误信息”的人的角色。

我曾两次尝试过Sourcegraph Cody,两次间隔大约一年,但两次都令人失望。让它直接在原地编辑我的代码比在浏览器和编辑器之间来回粘贴要好,但 Cody 速度慢且 bug 很多,最终我还是回到了在网页浏览器和编辑器之间来回粘贴代码的老路。

我最近看到了几篇关于Cline的博客文章,出于以下几个原因,它听起来很吸引人:

  • 代码是开源的。
  • 它能与我的主编辑器 VS Code 集成。
  • 它可以处理本地文件编辑、运行命令并对命令输出进行迭代。
  • 如果我愿意,它允许我使用本地托管的 LLM。
  • 它不像许多其他 AI 助手那样,坚持要作为购买 AI API 访问权限的中间商。

缺点是,Cline 除了烧投资人的钱之外,似乎没有收入来源。所以,它可能无法持续下去,但就目前而言还不错。

Lexical illusions(词汇幻觉):AI 助手的完美测试程序

最近我一直想要一个能扫描我博客中“lexical illusions”的工具。那是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.

我在博客中经常犯这种错误,而且往往要到校对后期甚至发布后才发现。

马特·迈特分享了一个用于查找 lexical illusions 的 Perl 脚本,但它比较 rudimentary( rudimentary),由于 Markdown 格式字符,在我的博客上产生了大量误报。

我让 Kagi Assistant 编写一个能识别 Markdown 的 Python 版本,但它总是生成有 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 走了一些弯路,比如用 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 使测试通过时,它有点崩溃了,试图想方设法证明行号为 1 是合理的,而明明应该是 3

鼓励 Cline 添加调试打印语句

我注意到 LLM 倾向于猜测解决方案,而不是停下来收集更多关于一段代码为何会如此表现的信息。

当我发现 Cline 陷入盲目尝试修复 bug 的循环时,我发现暂停其工作并指示它插入调试打印语句来验证其对代码的假设会很有帮助。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 进行翻译