西蒙·威尔森用代理提示添加“节奏”内容类型
Simon Willison··作者 Simon Willison
关键信息
该提示同时引用了源博客仓库和现有功能(Atom订阅源),指导AI复制相同的逻辑来处理“节奏”内容。解决方案在一次拉取请求中完成,表明意图与结果之间的摩擦极小。
资讯摘要
西蒙·威尔森使用一个自定义工具从他的博客文章自动生成Substack邮件列表。最近,他新增了一种名为‘节奏’的内容类型——来自外部来源的简短更新,比如开源项目发布或博物馆参观记录。为了将这些内容整合进邮件列表,他使用了一个简洁的一次性提示,指向Claude Code网页版。
该提示指示AI克隆他的博客仓库,更新邮件生成器以仅包含带描述的节奏内容(类似于Atom订阅源的工作方式),并在本地运行测试。结果是在一次拉取请求中就实现了完整的功能,证明了精心设计的提示可以驱动复杂的自动化,且几乎无需人工干预。
资讯正文
<p><em><a href="https://simonwillison.net/guides/agentic-engineering-patterns/">代理工程模式</a> ></em></p>
<p>这是一个看似简短但实际在单次操作中完成大量工作的提示示例。</p>
<p>首先说明背景。我每周大约发送一次免费的Substack通讯,内容是从我的博客复制粘贴而来。本质上,我在用Substack作为轻量级方式,让人们通过邮件订阅我的博客。</p>
<p>我使用自己的<a href="https://tools.simonwillison.net/blog-to-newsletter">博客转通讯工具</a>生成这份通讯——这是一个HTML和JavaScript应用程序,从<a href="https://datasette.simonwillison.net/">这个Datasette实例</a>获取我最新的内容,并将其格式化为富文本HTML,然后我可以复制到剪贴板并粘贴进Substack编辑器。这里有一篇<a href="https://simonwillison.net/2023/Apr/4/substack-observable/">详细的解释</a>说明它是如何运作的。</p>
<p>最近,我向博客添加了一种新的内容类型,用来记录发布在其他地方的内容,我称之为“beats”。这包括我开源项目的发布、新开发的工具、参观过的博物馆(来自<a href="https://www.niche-museums.com/">niche-museums.com</a>)以及其他外部内容。</p>
<p>我希望将这些内容也包含在生成的通讯中。这是我运行在托管我<code>blog-to-newsletter</code>工具的<a href="https://github.com/simonw/tools">simonw/tools</a>仓库上的提示,使用的是<a href="https://code.claude.com/docs/en/claude-code-on-the-web">Claude Code网页版</a>:</p>
<p><pre>从GitHub克隆simonw/simonwillisonblog到/tmp以供参考
更新blog-to-newsletter.html,使其包含带有描述的beats内容——类似于博客上Atom全部内容源的功能
用python -m http.server运行它,并使用`uvx rodney --help`测试——对比一下通讯中显示的内容与https://simonwillison.net主页上的内容</pre></p>
<p>这个提示帮我得到了我需要的<a href="https://github.com/simonw/tools/pull/268">确切解决方案</a>。我们来拆解一下这个提示。</p>
<blockquote>
<p><code>从GitHub克隆simonw/simonwillisonblog到/tmp以供参考</code></p>
</blockquote>
<p>我经常使用这种模式。编码代理可以克隆GitHub代码,而告诉它们查看相关代码通常是解释问题的最佳方式。通过要求它们克隆到<code>/tmp</code>,我确保它们不会意外地把参考代码包含进自己后续的提交中。</p>
<p><a href="https://github.com/simonw/simonwillisonblog">simonw/simonwillisonblog</a>仓库包含了我基于Django的<a href="https://simonwillison.net/">simonwillison.net</a>博客的源代码,其中包括我新“beats”功能的逻辑和数据库结构。</p>
<blockquote>
<p><code>更新blog-to-newsletter.html,使其包含带有描述的beats内容——类似于博客上Atom全部内容源的功能</code></p>
</blockquote>
引用 <code>blog-to-newsletter.html</code> 就足以告诉 Claude,它应该修改那个 <code>simonw/tools</code> 仓库中超过 200 个 HTML 应用程序中的哪一个。
节拍(beats)会自动从多个来源导入。通常它们并不特别有趣——比如我某个小型开源项目的一次小版本修复补丁。
我的博客提供了一种方式,让我可以为任意节拍添加额外描述,这不仅提供了更多评论,还标记了这些节拍比那些未做任何注释的更值得关注。
我已经用这种方式来区分哪些节拍会出现在我网站的 <a href="https://simonwillison.net/about/#atom">Atom 订阅源</a> 中。告诉 Claude 模仿这个逻辑,让我省去了额外解释规则的麻烦。
<blockquote>
<p><code>使用 python -m http.server 运行它,并用 `uvx rodney --help` 测试 —— 对比一下邮件内容与 https://simonwillison.net 主页上的内容差异</code></p>
</blockquote>
编码代理最有效的方式是拥有某种验证机制,可以用来测试自己的工作成果。
在这种情况下,我希望 Claude Code 能主动检查它对工具所做的更改是否能正确获取并显示最新数据。
我提醒它使用 <code>python -m http.server</code> 作为静态服务器,因为我过去曾遇到过一些应用在直接从磁盘读取文件而不是通过本地主机服务器运行时出现问题的情况。在这个特定案例中可能其实并不需要这么做,但我的提示习惯已经把这个命令深深植入脑海!
我在 <a href="https://simonwillison.net/guides/agentic-engineering-patterns/agentic-manual-testing/#using-browser-automation-for-web-uis">代理手动测试章节</a> 中介绍了 <code>uvx rodney --help</code> 这个技巧。Rodney 是一种浏览器自动化软件,可通过 <code>uvx</code> 安装,其 <code>--help</code> 输出设计得能让代理了解使用该工具所需的一切信息。
我认为告诉 Claude 将邮件中的结果与我博客首页的内容进行比较,就足够让它自信地验证新改动是否正常工作了,因为我最近发布的内容正好符合新的要求。
你可以查看 <a href="https://claude.ai/code/session_01BibYBuvJi2qNUyCYGaY3Ss">完整对话记录</a>,或者如果无法访问,我还有一个 <a href="https://gisthost.github.io/?e906e938100ab42f4d6a932505219324/page-001.html#msg-2026-04-18T00-13-57-081Z">替代文本版本</a>,展示了所有单独的工具调用过程。
<a href="https://github.com/simonw/tools/pull/268">最终的 PR</a> 做出了完全正确的修改:它向获取博客内容的 SQL 查询中添加了一个额外的 UNION 子句,过滤掉草稿节拍以及 <code>note</code> 列为空的节拍:
<p><div class="codehilite"><pre><span></span><code><span class="p">...</span>
<span class="k">union</span><span class="w"> </span><span class="k">all</span>
select
id,
'beat' as type,
title,
created,
slug,
'No HTML' as html,
json_object(
'created', date(created),
'beat_type', beat_type,
'title', title,
'url', url,
'commentary', commentary,
'note', note
) as json,
url as external_url
from blog_beat
where coalesce(note, '') != '' and is_draft = 0
union all
</code></pre></div>
它还成功识别出了不同 beat 类型与其正式名称之间的映射关系,这大概是从它在探索参考代码库时读取的 <a href="https://github.com/simonw/simonwillisonblog/blob/2e9d7ebe64da799b3927e61b4f85d98f7e9bc9aa/blog/models.py#L545-L551">Django ORM 定义</a> 中推导出来的。
const beatTypeDisplay = {
release: '发布',
til: '今日一学',
til_update: '更新了今日一学',
research: '研究',
tool: '工具',
museum: '博物馆'
};
告诉代理使用另一个代码库作为参考,是一种强大的捷径,可以在提示中只需极少额外信息就能传达复杂概念。
标签: <a href="https://simonwillison.net/tags/ai">ai</a>, <a href="https://simonwillison.net/tags/llms">llms</a>, <a href="https://simonwillison.net/tags/prompt-engineering">prompt-engineering</a>, <a href="https://simonwillison.net/tags/coding-agents">coding-agents</a>, <a href="https://simonwillison.net/tags/ai-assisted-programming">ai-assisted-programming</a>, <a href="https://simonwillison.net/tags/generative-ai">generative-ai</a>, <a href="https://simonwillison.net/tags/agentic-engineering">agentic-engineering</a>, <a href="https://simonwillison.net/tags/github">github</a>
来源与参考
收录于 2026-04-19