The Cline AI Assistant is Mesmerizing

Michael Lynch

Cline AI 助手令人着迷

原文由 Michael Lynch 发布,订阅该博客

昨天我试用了Cline AI 助手,结果一下子就陷入了长达五小时的恍惚状态,只能目不转睛地盯着 Cline 帮我修 bug。

作为一名专业开发者,这种体验既让人着迷,又让人恐惧。着迷的是,AI 已经达到了如此高的水平;恐惧的也正是这一点——在一个 AI 写代码比我又好又快的世界里,我不知道自己还能扮演什么角色。

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

我以前也用过 AI 工具

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

过去两年里,我一直在尝试各种大语言模型助手。最近半年,随着模型已经能够稳定地生成正确的代码,我使用它们的频率也大大增加了。

我用Kagi作为搜索引擎,它的 Ultimate 套餐可以无限制地使用所有主流大模型。我主要通过 Kagi Assistant 功能与大模型交互,它其实就是一个与大模型聊天的网页界面。

我的搜索引擎Kagi为所有主流大模型提供了一个好用的网页聊天界面。

利益披露:我参与了 Kagi 的众筹,所以对他们有一笔我自己也说不清的财务投入。

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

我最近发现的问题是,AI 工具让我觉得自己变成了机器。我只是机械地在编辑器和聊天界面之间来回复制代码,然后说一句“没起作用”,再贴上报错信息,如此反复四五遍。

聊天机器人大模型一直在为一个 bug 提供错误的修复方案,还得经过多次催促才肯给出完整的解决方法。

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

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

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

我隔了一年试了两次Sourcegraph Cody,两次都挺失望的。让它直接在原地修改代码,确实比在浏览器和编辑器之间来回粘贴要好,但 Cody 又慢又多 bug,最后我还是回到了在网页浏览器里来回粘贴代码的老办法。

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

  • 代码是开源的
  • 它能与 VS Code 集成,而 VS Code 是我的主力编辑器。
  • 它可以处理本地文件编辑、执行命令,并根据命令输出进行迭代。
  • 如果我愿意,它还允许我使用本地部署的大模型。
  • 它不像许多其他 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 美元的大模型额度后,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 添加调试打印语句

我注意到,大模型往往倾向于猜测解决方案,而不是停下来收集更多信息,去弄清一段代码为何会如此表现。

当我发现 Cline 陷入盲目尝试修复 bug 的循环时,我发现暂停它的工作、让它插入调试打印语句来验证它对代码的假设会很有帮助。Cline 会添加有用的调试输出,并且在宣布解决方案完成之前,还会记得把它们全部移除。

Kagi 肯定在我身上亏钱了

这是我第一次使用按量计费的大模型 API。我见过人们讨论 token 成本,但我一直没有直观的感受,因为 Kagi 基本上就是说:“别担心花多少钱。”

Cline 会在你进行的过程中,贴心地显示每个编程任务已经消耗了多少额度。

所以,我在 Kagi 每月 25 美元的无限套餐上肯定是占了大便宜。我用 Cline 五小时就花了 6 美元,而 Cline 还做了很多事来尽量减少 token 消耗。我每天都用 Kagi Assistant,经常在一次对话中就往聊天里粘贴十几次巨大的文件。现在看到了成本,我估计自己每天要让 Kagi 消耗 5 到 10 美元的 API 额度。

其他资源

大多数关于 AI 的文章都内容空洞,缺乏实用的经验。我发现以下几篇在展示可能性方面最有用:

本文章由 muse-spark-1.2-contributor 进行翻译

评论