できることを蓄積せよ
本文の状態
日本語全文を表示中
詳細モードで約5分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
Simon Willison Blog
著者Simon Willison氏が、コーディングエージェントを生産的に活用するためのヒントとして「できることを蓄積する」重要性を述べている。これは、ソフトウェア構築において何が可能か不可能かを理解し、実現方法の見通しを持つことが重要であるという従来からのキャリアアドバイスを拡張したものだ。
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
*Agentic Engineering Patterns >*
コーディングエージェントと生産的に作業するための私の多くのヒントは、それらなしでも私がキャリアで有用だと見つけたアドバイスからの拡張です。その素晴らしい例の一つがこれです:自分がやり方を知っていることは蓄積しておく。
ソフトウェアを構築する際のスキルの大きな部分は、何が可能で何が不可能かを理解し、少なくともそれらをどのように達成できるかのおおよそのアイデアを持っていることです。
これらの質問は広範なものから非常にニッチなもののまで様々です。ウェブページが JavaScript だけで OCR(光学文字認識)操作を実行できますか?アプリが実行されていない状態でも iPhone アプリが Bluetooth デバイスとペアリングできますか?100GB の JSON ファイルを、まず全体をメモリに読み込まずに Python で処理できますか?
このような質問に対する答えをあなたがどれだけ多く持っていればいるほど、他の人がまだ考えていない方法で技術を展開して問題を解決する機会を見出す可能性が高まります。
何かが理論的に可能であることを知っていることと、実際に自分でそれを成し遂げたのを見ることは同じではありません。ソフトウェア専門家として育むべき重要な資産は、このような質問に対する深い回答のコレクションであり、できれば実行可能なコードによって裏付けられたものが理想的です。
私は、このような解決策をさまざまな方法で収集・蓄積しています。私の blog や TIL blog には、私がやり方を理解した事柄に関するノートがぎっしりと詰め込まれています。また、1000 を超える GitHub リポジトリ を持っており、そこにはさまざまなプロジェクトのために書いたコードや、重要なアイデアを実証する小規模な概念実装(proof-of-concepts)が多く含まれています。
最近では、LLM(大規模言語モデル)を活用して、興味深い問題に対するコード解決策のコレクションを拡大しています。
tools.simonwillison.net は、私が LLM の支援を受けたツールやプロトタイプを収集した最大のコレクションです。ここでは、私は HTML ツール と呼ぶものを集めています。これは JavaScript や CSS を埋め込み、特定の課題を解決する単一の HTML ページのことです。
私の simonw/research リポジトリには、より大規模で複雑な例が収められています。ここではコーディングエージェント(コード生成 AI)に問題調査を命じ、動作するコードと、その発見内容を詳細に記した報告書を作成させるという挑戦を行っています。
蓄積したものから再構成する
なぜこれほど多くのものを収集するのか?自分の能力を構築・拡張するのに役立つことに加え、この過程で生成された資産は、コーディングエージェントにとって極めて強力な入力となります。
私が最も好きなプロンプト(指示)のパターンの一つは、既存の動作する例を 2 つ以上組み合わせて、新しい何かを構築するようにエージェントに命じるというものです。
この手法の有効性を明確に示してくれたプロジェクトの一つが、私のツールコレクションに最初に追加したものであり、ブラウザベースの OCR ツール です。詳細は こちら で解説されています。
私は、PDF ファイルからのページを OCR 処理するための、手軽でブラウザ上で動作するツールを求めていました。特に、テキストバージョンが一切提供されておらず、スキャンされた画像のみで構成されている PDF を対象としていました。
以前、ブラウザ内で Tesseract.js OCR ライブラリ の実行を試みたことがあり、非常に能力が高いと感じました。このライブラリは、成熟した Tesseract OCR エンジンの WebAssembly 版を提供しており、JavaScript から呼び出して画像からテキストを抽出することができます。
しかし、私は画像を扱うのではなく、PDF を扱いたかったのです。そこで思い出したのは、Mozilla の PDF.js ライブラリでも作業したことがあるという点です。このライブラリは、PDF の個々のページをレンダリングされた画像に変換する機能などを持っています。
私はこれらの両方のライブラリに関する JavaScript のスニペットをメモに残していました。
私がモデル(当時 Claude 3 Opus)に入力した完全なプロンプトは以下の通りです。これは私の二つの例を組み合わせて、私が探していた解決策を説明するものです:
このコードは、PDF を開き、ページごとに画像に変換する方法を示しています:
html>
head>
title>PDF to Imagestitle>
script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.9.359/pdf.min.js">script>
style>
.image-container img {
margin-bottom: 10px;
}
.image-container p {
margin: 0;
font-size: 14px;
color: #888;
}
style>
head>
body>
input type="file" id="fileInput" accept=".pdf" />
div class="image-container">div>
script>
const desiredWidth = 800;
const fileInput = document.getElementById('fileInput');
const imageContainer = document.querySelector('.image-container');
fileInput.addEventListener('change', handleFileUpload);
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.9.359/pdf.worker.min.js';
async function handleFileUpload(event) {
const file = event.target.files[0];
const imageIterator = convertPDFToImages(file);
for await (const { imageURL, size } of imageIterator) {
const imgElement = document.createElement('img');
imgElement.src = imageURL;
imageContainer.appendChild(imgElement);
const sizeElement = document.createElement('p');
sizeElement.textContent = Size: ${formatSize(size)};
imageContainer.appendChild(sizeElement);
}
}
async function* convertPDFToImages(file) {
try {
const pdf = await pdfjsLib.getDocument(URL.createObjectURL(file)).promise;
const numPages = pdf.numPages;
for (let i = 1; i < numPages; i++) {
const page = await pdf.getPage(i);
const viewport = page.getViewport({ scale: 1 });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = desiredWidth;
canvas.height = (desiredWidth / viewport.width) * viewport.height;
const renderContext = {
canvasContext: context,
viewport: page.getViewport({ scale: desiredWidth / viewport.width }),
};
await page.render(renderContext).promise;
const imageURL = canvas.toDataURL('image/jpeg', 0.8);
const size = calculateSize(imageURL);
yield { imageURL, size };
}
} catch (error) {
console.error('Error:', error);
}
}
function calculateSize(imageURL) {
<
原文を表示
*Agentic Engineering Patterns >*
Many of my tips for working productively with coding agents are extensions of advice I've found useful in my career without them. Here's a great example of that: hoard things you know how to do.
A big part of the skill in building software is understanding what's possible and what isn't, and having at least a rough idea of how those things can be accomplished.
These questions can be broad or quite obscure. Can a web page run OCR operations in JavaScript alone? Can an iPhone app pair with a Bluetooth device even when the app isn't running? Can we process a 100GB JSON file in Python without loading the entire thing into memory first?
The more answers to questions like this you have under your belt, the more likely you'll be able to spot opportunities to deploy technology to solve problems in ways other people may not have thought of yet.
Knowing that something is theoretically possible is not the same as having seen it done for yourself. A key asset to develop as a software professional is a deep collection of answers to questions like this, ideally illustrated by running code.
I hoard solutions like this in a number of different ways. My blog and TIL blog are crammed with notes on things I've figured out how to do. I have over a thousand GitHub repos collecting code I've written for different projects, many of them small proof-of-concepts that demonstrate a key idea.
More recently I've used LLMs to help expand my collection of code solutions to interesting problems.
tools.simonwillison.net is my largest collection of LLM-assisted tools and prototypes. I use this to collect what I call HTML tools - single HTML pages that embed JavaScript and CSS and solve a specific problem.
My simonw/research repository has larger, more complex examples where I’ve challenged a coding agent to research a problem and come back with working code and a written report detailing what it found out.
Recombining things from your hoard
Why collect all of this stuff? Aside from helping you build and extend your own abilities, the assets you generate along the way become incredibly powerful inputs for your coding agents.
One of my favorite prompting patterns is to tell an agent to build something new by combining two or more existing working examples.
A project that helped crystallize how effective this can be was the first thing I added to my tools collection - a browser-based OCR tool, described in more detail here.
I wanted an easy, browser-based tool for OCRing pages from PDF files - in particular PDFs that consist entirely of scanned images with no text version provided at all.
I had previously experimented with running the Tesseract.js OCR library in my browser, and found it to be very capable. That library provides a WebAssembly build of the mature Tesseract OCR engine and lets you call it from JavaScript to extract text from an image.
I didn’t want to work with images though, I wanted to work with PDFs. Then I remembered that I had also worked with Mozilla’s PDF.js library, which among other things can turn individual pages of a PDF into rendered images.
I had snippets of JavaScript for both of those libraries in my notes.
Here’s the full prompt I fed into a model (at the time it was Claude 3 Opus), combining my two examples and describing the solution I was looking for:
This code shows how to open a PDF and turn it into an image per page:
html>
head>
title>PDF to Imagestitle>
script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.9.359/pdf.min.js">script>
style>
.image-container img {
margin-bottom: 10px;
}
.image-container p {
margin: 0;
font-size: 14px;
color: #888;
}
style>
head>
body>
input type="file" id="fileInput" accept=".pdf" />
div class="image-container">div>
script>
const desiredWidth = 800;
const fileInput = document.getElementById('fileInput');
const imageContainer = document.querySelector('.image-container');
fileInput.addEventListener('change', handleFileUpload);
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.9.359/pdf.worker.min.js';
async function handleFileUpload(event) {
const file = event.target.files[0];
const imageIterator = convertPDFToImages(file);
for await (const { imageURL, size } of imageIterator) {
const imgElement = document.createElement('img');
imgElement.src = imageURL;
imageContainer.appendChild(imgElement);
const sizeElement = document.createElement('p');
sizeElement.textContent = Size: ${formatSize(size)};
imageContainer.appendChild(sizeElement);
}
}
async function* convertPDFToImages(file) {
try {
const pdf = await pdfjsLib.getDocument(URL.createObjectURL(file)).promise;
const numPages = pdf.numPages;
for (let i = 1; i numPages; i++) {
const page = await pdf.getPage(i);
const viewport = page.getViewport({ scale: 1 });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = desiredWidth;
canvas.height = (desiredWidth / viewport.width) * viewport.height;
const renderContext = {
canvasContext: context,
viewport: page.getViewport({ scale: desiredWidth / viewport.width }),
};
await page.render(renderContext).promise;
const imageURL = canvas.toDataURL('image/jpeg', 0.8);
const size = calculateSize(imageURL);
yield { imageURL, size };
}
} catch (error) {
console.error('Error:', error);
}
}
function calculateSize(imageURL) {
<
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み