译:我如何用 Amp
原文: https://ampcode.com/how-i-use-amp
作者: Thorsten Ball
译者: Gemini 2.5 Pro
从今天起,我们的 AI 代理编程工具 Amp (agentic coding tool) 向所有人开放。等待名单已经取消——去吧,快去注册使用吧!
在过去的 10 周里,Amp 是我开发软件的主要工具。而且——我们使用的工具终将改变我们,这个事实又一次得到了印证——它从根本上改变了我开发软件的方式。
所以我想,我应该借此机会写一写我个人是如何使用 Amp 的。
在 VS Code 里
你可以通过 VS Code 扩展或 CLI 来使用 Amp。我主要是在 VS Code 里用它,让它常驻在右侧边栏,不停地按 ⌘I
和 ⌘L
。
如果你在四个月前告诉我,我会把 VS Code 当作我的主编辑器,我肯定不会相信。但事实就是如此。我唯一的解释是:我用哪个文本编辑器,这件事对我来说似乎不那么重要了。我没有确切的数字,但我猜,我现在提交的代码里,有 70-80% 是 Amp 写的。
没错——我几乎不再亲手写代码了。如果我需要打字写代码,那就算得上是件大事了。
数字填色编程
我把用 agent 编程看作是“数字填色编程” (paint-by-numbers programming):我定好数字和轮廓,然后 agent 去填充颜色。
Agent 不会为我做架构决策,不会在没有我密切监督的情况下编写关键代码,也不会给代码库引入全新的结构。这些都是我做的事。但一旦我知道了最终的样貌,我就会把我所知的一切——架构、可能的边界情况、约束条件、要添加、扩展和运行哪些测试——都放进一个 prompt 里,然后派 agent 去执行。
保持简短的 Threads
总的来说——我稍后会给你一些例外——我会尽量让 threads,也就是我和模型的对话,保持简短。
目前,我们底层使用的模型是 Claude Sonnet 4。根据之前使用 Claude 3.7 Sonnet 的经验,我估计 Claude Sonnet 4 也是一样,当上下文窗口达到 10 万个 token 后,事情就开始变得模糊、不精确。当上下文窗口变得太大时,Claude 会开始忘记第一个 prompt 里的指令,或者陷入科学家们所说的“厄运循环” (doom loop)——也就是它会一遍又一遍地尝试修复同一个测试,却收效甚微。
有时我只让它从暂存的代码中移除调试语句。其他时候,我会让它实现一个我知道不会触及超过几个文件的小功能,比如为这个网站添加 RSS feed。或者我希望它简化单个 UI 组件的设计。
重申一下,总的来说,我认为很多新手在使用 agent 时遇到的问题,都可以追溯到他们开启新 thread 的频率不够高。
添加新功能
这可能是最经典的使用场景:让 agent 实现一个新功能,或者修改一个现有功能。
在过去几周里,我被多次问到同一个问题:现在有了 agent,你觉得我们是不是再也不用学软件知识了?
我的回答是,不,不,当我为 agent 写 prompt 时,我所知的关于软件开发的一切都融汇其中:我对架构的思考,我怀疑陷阱在哪,我知道相关代码的位置,我认为重构该如何进行,什么样的测试是好的,什么是必要的权衡,如何将功能呈现给用户。
我不会写这样的 prompt:
给 agent 构建一个批处理工具
而是会写这样的东西:
我需要你帮忙实现这个:https://raw.githubusercontent.com/anthropics/anthropic-cookbook/refs/heads/main/tool_use/parallel_tools_claude_3_7_sonnet.ipynb
我们在 core/src/tools/tools.ts(以及其他文件)中定义了工具,现在我想实现这个批处理工具。我猜想类型处理会有点棘手,所以我希望你深入思考一下,找到一个不会导致大量复杂类型的实用解决方案。我们应该从非常简单的东西开始,然后逐步迭代。
或者是这样的:
一个用户遇到了你在截图中看到的这个 bug。问题似乎出在 core/src/threads/thread-worker.ts 和 core/src/inference/backends/anthropic.ts
看起来我们需要确保在出错时不发送 thinking block。
我知道我们已经有了一些处理 thinking block 的逻辑,但我希望你分析一下我们目前是如何处理的。
然后我会追问:
我们目前移除 thinking block 的逻辑是什么?我们不是在 core/src/threads/thread-worker.ts 或 core/src/threads/thread-delta.ts 的某个地方移除了它们吗?
最后,我下达指令:
好的,就这么改!
让它截图!
这是我用 agent 时最喜欢的功能之一,没有之一:给它们的工作提供视觉反馈。而且,你猜怎么着,只要你给它们一个 URL,它们就能自己截图。
在我们的 Amp 代码库里,我们为 UI 组件准备了一个 storybook。我总是让它运行在 http://localhost:7001
,打开那个 URL,我可以看到我们大部分的组件都整齐地排列着,并展示出它们可能处于的不同状态。
所以,如果我想让 agent 更改某个 UI 组件,我就会让它去看看 storybook——只要你在设置里添加了 Playwright MCP server,它就能做到——然后通过截图来检查自己的工作。
我给你举个例子。几天前,我想让 agent 更新我们 storybook 里的一个现有 story。这是我的 prompt:
提交后,agent 就开始工作,修改了 storybook 以包含这些变更。下面是它如何确认自己所做的修改是有效的:
“文件更改现在正确显示了!”它截完图后兴奋地说道——能活在这个时代真好,不是吗?
但更妙的还在后头。我认为截图作为反馈,在 agent 的修改没有成功时效果尤其好。因为它会在截图或浏览器控制台里看到错误,然后不断重试直到成功为止。试试看,这简直是魔法。
运行构建并修复错误
有时我的 prompt 就这么简单:
运行构建并修复所有错误
因为“构建”是什么,已经在 AGENT.md
文件里写明了,所以 agent 会直接运行命令,然后修复错误。
审查代码
我经常让 agent 做下面这件事:
运行 `git diff` 查看别人写的代码。仔细审查并给我一份报告
当然,那个“别人”不是别人,正是——鼓声响起——agent 自己!但它不知道,不是吗?所以它就去运行 git diff
,然后告诉我代码看起来不错,或者很干净,或者有一些 bug。如果是后者,我会在判断它的分析是否正确后,让它修复其中一个 bug。
清理代码
比方说,我让 agent 写了几百行代码,中途为了搞清楚为什么功能不符合预期,我让它加了一些调试语句。
我常常不知道它把调试语句加在了哪里,而且我也没有打开任何相关文件。所以一旦我知道功能正常了,准备提交代码时,我就会开一个新的 thread,让另一个 agent 的“化身”去移除那些调试语句:
运行 `git diff` 查看有哪些改动,然后移除调试语句
粘贴截图
我超爱截图,Amp 也一样:
没错:你可以用 ⌘-v
/ctrl-v
粘贴截图,然后 agent 会“阅读”它们。
我一直都在用这个功能,粘贴过别人在 Slack 里报告 bug 的截图,粘贴过那些我无法方便复制粘贴(或者懒得复制)的错误信息,还有 UI 上的 bug。
这个功能处理文本效果最好,因为这些模型非常擅长“阅读”截图里的文字,但我也曾让 agent “把我在这张截图中标记的两个按钮对调一下”,它也做到了。
不管怎么说:这真的很有趣。
用图表解释代码
Amp 内置了对 Mermaid 图表的支持。当你想弄清楚某段代码是如何工作时,这非常方便。
我的意思是,你快看这个:
而我只用了下面这个 prompt:
带我过一遍这个分支的代码(和 `main` 对比),给我解释一下自动补全是怎样接入 vscode 的,基本上就是通过代码带我走一遍自动补全的生命周期
措辞算不上优雅,对吧?我甚至都没说它应该创建一个图表,但这次它奇迹般地做到了。(在其他情况下,如果我知道我想要图表,我会明确告诉它。)
阅读 commit
一个 git commit 包含了海量的元信息:谁做的改动,他们如何描述改动,哪些文件被一起修改了,文件的路径,以及部分文件内容。
Fred Brooks 在《人月神话》中写道:
给我看你的流程图,但藏起你的数据表,我会一头雾水。给我看你的数据表,我通常就不需要你的流程图了,一切都会一目了然。
现在我要说:给我看一个 commit,我就能知道足够的信息来构建类似的东西。
我经常利用原始 commit 包含大量信息这一点,在 prompt 中注入相关上下文,方法很简单,就是让 agent 在做任何事之前先去看一个特定的 commit。
这里有个例子:
这个测试 web/src/lib/components/thread/thread-sharing-dropdown-menu.test.ts 最近被这个 commit 搞坏了:3ec95344d5d5a55ab2342d5daa53f3c3155391dd
运行
pnpm -C web test --run thread-sharing
来看看失败的测试。
然后检查那个 commit。
然后告诉我们怎么修复这个测试。
或者我让 agent 帮我找到一个 commit 然后阅读它:
查看 core/src/tools/builtin/filesystem/edit_file.common.ts 的 git 历史
在某个时候我移除了那个文件里的 vscode 实现。
找到那个 vscode 实现,然后向我解释我们当时是如何在编辑后重新加载文件的。
做完这些之后,我们就拥有了修改实现所需的全部相关上下文。
搜索代码
有时候我只是想在代码库里找出某段代码的位置,并不想让 agent 做任何修改。
这种情况下,我只会告诉它:
找到那段确保未认证用户也能查看 /how-to-build-an-agent 页面的代码
或者,这是几周前的一个例子:
我们在代码库的哪里定义了数据库默认值,使得新用户的邀请数为 0?我猜是在数据库迁移文件或者什么地方。你需要在 `server` 目录里找找
我知道我也可以想出一些关键词来搜索,但 agent 通常更快。而且如果我之后想改点什么,你猜怎么着?所有上下文都已经在那里了。
与同事分享 thread
可以把 thread 分享给同事或公众,这个功能非常方便。
当然是为了知识共享,或者解释你和你的 agent 是如何构建某个东西的,但也是为了,你懂的,当 agent 一次就搞定时可以炫耀一下。我的意思是,看看这个:
告诉它我想要什么
当人们和 agent 协作不顺时,问题常常可以归结为一句话:
我以为 agent 会这么做,但它没有,为什么?
嗯,不管 agent 有多厉害,它都不是全知的。它们可能对世界了解一二,但如果你不告诉它们,它们就不知道你想要什么。
所以,与其想着“我希望 agent 刚刚用 super-build --dry-run
命令就好了,但它没用”,不如直接告诉它!
不要用模糊的指令:
你能找出是谁写的这个组件吗?
直接告诉它你希望它做什么:
用 git blame 告诉我谁写的这个组件
构建一个,然后扔掉
有了 agent,实践“构建一个,然后扔掉” (build one to throw one away) 的原则变得可行多了(或者至少:没那么痛苦了)。你再也不会有那种沉没成本的感觉,心里有个声音在说:“但这其实没那么糟,对吧?我们真的要把它全扔掉吗?”
相反,你可以让 agent 去实现它,等五分钟,看看代码,然后决定是保留还是扔掉。
我这么干过很多次了。很多时候,我学到的最重要的一点是,我不想用那种方式来构建功能。或者,我发现我根本就不知道自己想要什么。
使用 git 暂存区
我觉得我过去 10 年使用 git 暂存区 (staging area) 的次数,都没有过去 10 周多。结果发现它非常方便。谁能想到呢?
但为什么呢?
我们没有采用检查点和“应用/拒绝”模式与 agent 交互(我们不认为这仍然是正确的方法),而是让 agent 放手去做。安全网永远是版本控制——我们绝不想破坏这个安全网。
这反过来意味着你可以最大限度地利用 git:让 agent 做点什么,看到结果不错,就把它暂存起来,然后再让它做别的事,看到结果不好,就丢弃未暂存的改动。
写 SQL
让一个 agent 连接到你的数据库,所带来的喜悦,与看着它截图并迭代 UI 组件的快乐,非常非常接近。
方法如下。
首先,告诉 agent 使用 psql
(或任何其他 CLI 工具)或 postgres
MCP server(或任何适用于你数据库的 MCP server)提供的工具来连接到你的数据库。
然后,向它提问,比如:
更新我的用户账户(邮箱以 thorsten 开头),使其拥有无限邀请次数
或者:
返回一个用户列表,按 thread 数量降序排列
然后 agent 会尽其所能返回你想要的列表:搞清楚数据库的 schema,试试这个查询,试试那个查询。
看,这里我想修改我的本地开发数据库。它不知道 schema 是什么,所以它首先尝试搞清楚,而且它做到了——通过并行运行四个命令:
这太棒了。
这是一种不同的、仍然陌生的编程方式
让 agent 做这个,让 agent 做那个,这里截个图,那里截个图,几乎不用打字——是的,听起来很奇怪,不是吗?
作为一个曾经把文本编辑器 logo T恤穿在身上的人,请允许我这么说:像这样编程感觉很奇怪。
Quinn 和我在我们的播客里几乎每一集都在讨论这种感觉。我们俩都编程很久了,现在我们正在重新学习如何通过 agent 来编程,感觉就是很奇怪。
因为它确实很奇怪。它是新的。你需要时间去适应。你需要去学习如何做。我打赌,至少在接下来的六到十二个月里,你仍然需要学习如何写好 prompt。
但我还有另一个赌注:一旦你看到 agent 做出了你以前认为不可能的事情,那一刻,你的感觉就会从“我不太确定我喜不喜欢这个……”转变为“好吧,哇,我还能用它做什么,我打赌它还能——”
就在那一刻,感觉从奇怪变成了 exhilarating (振奋)。
就在那一刻,你意识到,当与 agent 一起编程时,引用 Mary Rose Cook 的话,“每一步都超越了步伐本身。你从地面上腾空而起。这需要更多的深思熟虑,但是,因为你每一步都取得了更大的进展,感觉就像在飞翔。”