Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

Artifacts のベストプラクティス

最終更新 Markdown で表示Agent セットアップ

Artifacts は、作業を分離し、アクセス範囲を狭く保ち、メタデータを分けておき、ストレージを意図的に分割すると、最もうまく使えます。

エージェント、自動化、共有システム向けにリポジトリを構成するときは、次のパターンを使います。

分離のためにリポジトリを整理する

エージェント、セッション、アプリケーションごとにリポジトリを作る

自律的な作業の単位ごとに、リポジトリを 1 つ作ります。エージェントが 10,000 あるなら、リポジトリも 10,000 作ります。

こうすると、各エージェントの変更、失敗、クリーンアップのライフサイクルが分かれます。共有リポジトリ 1 つが、競合、大きな差分、誤上書きの集中箇所になることも避けられます。

次のような場合に、このパターンを使います。

  • あるエージェントの作業を、別のエージェントの作業から分離する
  • リポジトリを 1 つのセッションまたはユーザーアプリケーションに渡す
  • 作業を独立してレビュー、マージ、アーカイブ、削除する

共同作業者が同じライフサイクルを共有し、同じリポジトリで作業する必要がある場合にだけ、ブランチを使います。多数の自律エージェントのキューとして、共有リポジトリ 1 つを使わないでください。

一意な名前を使う

リポジトリ名は、名前空間内で一意です。複数のエージェントが 1 つの名前空間で同じベースラインリポジトリの分離コピーを必要とする場合は、docs-site のような短い共有名を再利用しないでください。

リポジトリ名には、エージェント名、セッション ID、ユーザー ID、ワークフロー ID など、安定した識別子を含めます。${agentName}-${sessionId}-${repoName} のような名前は、${repoName} より安全です。衝突を避けられ、クリーンアップも簡単になります。

次の例では、リポジトリを作る前に一意なリポジトリ名を組み立てます。

src/index.jsjs
async function createRepoCopy(env, agentName, sessionId, repoName) {
	const uniqueRepoName = `${agentName}-${sessionId}-${repoName}`;

	return env.ARTIFACTS.create(uniqueRepoName);
}
src/index.tsts
interface Env {
	ARTIFACTS: Artifacts;
}

async function createRepoCopy(
	env: Env,
	agentName: string,
	sessionId: string,
	repoName: string,
) {
	const uniqueRepoName = `${agentName}-${sessionId}-${repoName}`;

	return env.ARTIFACTS.create(uniqueRepoName);
}

安定したベースラインからフォークする

エージェントが同じスターターファイル、プロンプト、アプリケーション構成を必要とするときは、信頼できるベースラインから新しいリポジトリを始めます。レビュー済みリポジトリからのフォークは、新しいリポジトリごとにファイルを手でコピーするより安全です。

開始点が揃い、下流の差分もレビューしやすくなります。取り込みたい結果だけをマージバックすることもできます。

次の例では、レビュー済みのベースラインリポジトリを、セッション固有のリポジトリへフォークします。

src/index.jsjs
async function forkFromBaseline(env, sessionId) {
	const baseline = await env.ARTIFACTS.get("starter-repo");
	const forked = await baseline.fork(`starter-repo-${sessionId}`, {
		description: `Fork for session ${sessionId}`,
		defaultBranchOnly: true,
		readOnly: false,
	});

	return {
		name: forked.name,
		remote: forked.remote,
	};
}
src/index.tsts
interface Env {
	ARTIFACTS: Artifacts;
}

async function forkFromBaseline(env: Env, sessionId: string) {
	const baseline = await env.ARTIFACTS.get("starter-repo");
	const forked = await baseline.fork(`starter-repo-${sessionId}`, {
		description: `Fork for session ${sessionId}`,
		defaultBranchOnly: true,
		readOnly: false,
	});

	return {
		name: forked.name,
		remote: forked.remote,
	};
}

アクセス範囲を狭くする

最小権限のリポジトリトークンを発行する

Artifacts のトークンはリポジトリ単位です。クローン、インデックス、レビュー、取得には read トークンを優先します。

write トークンは、変更をプッシュする必要があるエージェントまたはシステムにだけ使います。トークンの有効期間は短くし、エージェントセッションごとに新しいトークンを再発行します。

次の例では、Workers バインディング を使い、リポジトリ向けの短命な read トークンを発行します。

このルートがトークンを返す前に、呼び出し元はすでに認証・認可済みであるとします。

src/index.jsjs
export default {
	async fetch(request, env) {
		const url = new URL(request.url);
		const repoName = url.searchParams.get("repo") ?? "starter-repo";

		const repo = await env.ARTIFACTS.get(repoName);
		const token = await repo.createToken("read", 900);

		return Response.json({
			repo: repoName,
			scope: token.scope,
			expiresAt: token.expiresAt,
			token: token.plaintext,
		});
	},
};
src/index.tsts
interface Env {
	ARTIFACTS: Artifacts;
}

export default {
	async fetch(request: Request, env: Env): Promise<Response> {
		const url = new URL(request.url);
		const repoName = url.searchParams.get("repo") ?? "starter-repo";

		const repo = await env.ARTIFACTS.get(repoName);
		const token = await repo.createToken("read", 900);

		return Response.json({
			repo: repoName,
			scope: token.scope,
			expiresAt: token.expiresAt,
			token: token.plaintext,
		});
	},
} satisfies ExportedHandler<Env>;

変更をプッシュする必要があるセッションを Worker が認可したあとでのみ、同じパターンで write トークンを使います。

長寿命の write トークンをすべてのエージェントに発行しないでください。発行するトークンは、できる限り狭い権限で、できる限り短い期間にします。

ハーネスのメタデータは別に保存する

プロンプトとモデル出力には git notes を使う

git notes を使い、コミットオブジェクトや作業ツリーを変えずに、プロンプト、モデル出力、実行 ID、その他のハーネスメタデータをコミットに付けます。

こうすると、Artifacts をエージェント作業のバージョン管理されたファイルシステムと、エージェントハーネスの信頼できる情報源の両方として使えます。ファイルは成果物に集中し、実行の文脈はコミットの notes に残します。

次の例では、現在のコミットにユーザープロンプトとアシスタントの要約を保存し、その note を読み戻します。

git notes add -m 'user: Add a best-practices section for unique repo names.' HEAD
git notes append -m 'assistant: Added naming guidance and a code example.' HEAD
git notes show HEAD

システム間でリポジトリを同期する場合、notes は別の ref に置かれる点に注意してください。そのメタデータをリポジトリと一緒に運ぶときは、ほかのリポジトリデータとあわせて refs/notes/* を push / fetch します。

名前空間を意図的に分割する

環境、チーム、高レートのワークロードを分ける

運用上の境界を分けるために、名前空間を使います。リポジトリの分離は作業単位を分け、名前空間の分離は所有権、環境、トラフィックパターンを分けます。

利用が増えたら、すべてのリポジトリを 1 つのデフォルト名前空間に置かないでください。所有権を明確にしたい場合や、名前空間ごとの リクエストレート制限 の中でスケールする余地が必要な場合は、名前空間を分割します。

用途 名前空間の例 理由
環境 staging, prod テストトラフィックと本番トラフィックを分けます。
チームの境界 sales, finance, devtools 所有権、アクセス、クリーンアップ方針を分けます。
トラフィックの分離 agents-batch, agents-realtime あるワークロードが、別のワークロードの制限を消費しないようにします。

1 つの名前空間が過熱したら、共有名前空間をさらに大きくするのではなく、新しいリポジトリを追加の名前空間に分散します。

役に立ちましたか?