claude-skills/

Anthropic公式スキル・プラグインの日本語ディレクトリ

last sync 22h ago
スキルOfficialdevelopment

💉create-atomic-context-provider

プラグイン
atomic-agents

説明

`BaseDynamicContextProvider` を構築します。これは、エージェントの `run()` が呼び出されるたびに、名前とタイトルを持つブロックをシステムプロンプトに注入するものです。注入できる情報の例としては、現在時刻、ユーザーID、RAGで取得したドキュメント、セッション状態、キャッシュされたDBスキーマなどがあります。 次のような場合に使用: - 「コンテキストプロバイダーを追加したい」 - 「X をプロンプトに注入したい」 - 「エージェントに動的なコンテキストを持たせたい」 - 「RAG を組み込みたい」 - 「`BaseDynamicContextProvider` を作りたい」 - `/atomic-agents:create-atomic-context-provider` を実行したとき

原文を表示

Build a `BaseDynamicContextProvider` that injects a named, titled block into an agent's system prompt at every `run()` — current time, user identity, retrieved RAG docs, session state, cached DB schema. Use when the user asks to "add a context provider", "inject X into the prompt", "give the agent dynamic context", "wire up RAG", "make a `BaseDynamicContextProvider`", or runs `/atomic-agents:create-atomic-context-provider`.

ユースケース

  • コンテキストプロバイダーを追加したい
  • プロンプトに情報を注入したい
  • エージェントに動的なコンテキストを持たせたい
  • RAGを組み込みたい

本文(日本語訳)

Atomic Agents コンテキストプロバイダーの作成

コンテキストプロバイダーは、run() が呼ばれるたびに、名前とタイトルを持つブロックをエージェントのシステムプロンプトに注入します。ベースプロンプトは静的なまま維持され、呼び出しごとに変化するのはコンテキスト部分です。

キャッシュ戦略・非同期データソース・マルチエージェント共有パターンなど、より深い内容については ../framework/references/context-providers.md を参照してください。このスキルは実践的なパスです: 明確化 → 実装 → 登録。


このスキルと上位の framework スキルの使い分け

  • このスキル: プロバイダーを追加したい場合 — 「ユーザー名をプロンプトに注入したい」「現在時刻をエージェントに見せたい」「検索結果のドキュメントをプロンプトに渡したい」「セッション状態を2つのエージェント間で共有したい」など。
  • framework スキル: Atomic Agents 全般に関する質問、またはプロバイダー作成以外のトピック。

フェーズ 1 — 明確化

以下を1つのメッセージにまとめて確認します:

  1. プロンプトに何を入れるか? 1文で。プロバイダーの役割を定義します。
  2. データはどこから来るか? コードが更新するインメモリの状態?ベクターDBの検索結果?RESTコール?クロック?
  3. どの程度の鮮度が必要か? run() のたびに更新(デフォルト)、N秒ごとにキャッシュ、または各呼び出し前に外部から非同期リフレッシュ?
  4. どのエージェントが使うか? 1つのエージェント、または複数エージェント間で共有?

文脈から明らかな項目はスキップして構いません。


フェーズ 2 — 設計確認

以下を簡潔なブロックで確認します:

  • ファイル: <project>/context_providers.py(またはそれを使うエージェントと同じ場所)。
  • クラス名: <Topic>Ctx(BaseDynamicContextProvider)
  • タイトル(プロンプト内のセクションヘッダーとして表示)— 同一エージェントに登録するプロバイダー間でユニークである必要があります。
  • 更新の仕組み: run() の合間にフィールドを書き換える(最も一般的)、メソッド経由でセットする、または非同期ソースの場合は await refresh() を使う。

フェーズ 3 — 実装

スケルトン

from atomic_agents.context import BaseDynamicContextProvider


class UserCtx(BaseDynamicContextProvider):
    def __init__(self):
        super().__init__(title="User Context")
        self.name: str = ""
        self.role: str = ""

    def get_info(self) -> str:
        if not self.name:
            return "No user is logged in."
        return f"User: {self.name} (role: {self.role})"

get_info()同期的に動作し、agent.run()たびに実行されます。処理は軽量に保ってください。HTTP通信・DBクエリ・ファイルI/Oは禁物です。遅いソースはキャッシュするか(後述の「Cached」パターン参照)、非同期ソースの場合はエージェントを呼ぶ前にループ側で await provider.refresh() を実行してください。


よく使うパターン

時刻 — 読み取り専用、状態の変更不要:

from datetime import datetime, timezone

class TimeCtx(BaseDynamicContextProvider):
    def __init__(self):
        super().__init__(title="Current Time")

    def get_info(self) -> str:
        return datetime.now(timezone.utc).isoformat()

RAG / 検索ドキュメント — 外部からセットし、get_info() 内で読み取る:

class RAGCtx(BaseDynamicContextProvider):
    def __init__(self):
        super().__init__(title="Retrieved Documents")
        self.docs: list[dict] = []

    def set(self, docs: list[dict]) -> None:
        self.docs = docs

    def get_info(self) -> str:
        if not self.docs:
            return "No relevant documents retrieved."
        return "\n\n".join(f"[{d['source']}] {d['content']}" for d in self.docs)

# 呼び出し側: agent.run() の直前に実行
rag.set(vector_db.search(query, k=4))
agent.run(query_input)

セッション — エージェント間で共有できるミュータブルなキー/バリュー状態:

class SessionCtx(BaseDynamicContextProvider):
    def __init__(self):
        super().__init__(title="Session")
        self._data: dict[str, str] = {}

    def set(self, key: str, value: str) -> None:
        self._data[key] = value

    def get_info(self) -> str:
        if not self._data:
            return "No session state."
        return "\n".join(f"- {k}: {v}" for k, v in self._data.items())

キャッシュ — 遅いソース(DBスキーマ、コストの高い計算)向け:

import time

class DBSchemaCtx(BaseDynamicContextProvider):
    def __init__(self, conn, ttl_seconds: int = 300):
        super().__init__(title="Database Schema")
        self._conn = conn
        self._ttl = ttl_seconds
        self._cached: str = ""
        self._at: float = 0.0

    def get_info(self) -> str:
        now = time.time()
        if not self._cached or now - self._at > self._ttl:
            self._cached = render_schema(self._conn)
            self._at = now
        return self._cached

非同期ソース — 外部でリフレッシュし、内部では同期的に読み取る:

class AsyncCtx(BaseDynamicContextProvider):
    def __init__(self):
        super().__init__(title="Async Data")
        self._cached = ""

    async def refresh(self) -> None:
        self._cached = format(await fetch_remote())

    def get_info(self) -> str:
        return self._cached

# 呼び出し側
await ctx.refresh()
await agent.run_async(input_data)

フェーズ 4 — 登録

ctx = UserCtx()
agent.register_context_provider("user", ctx)

# 各 run() の前に必要に応じてフィールドを更新:
ctx.name = "Alice"; ctx.role = "admin"
agent.run(...)

1つのプロバイダーインスタンスを複数のエージェントで共有することも可能です。更新内容は登録済みのすべてのエージェントに反映されます:

shared = SessionCtx()
agent_a.register_context_provider("session", shared)
agent_b.register_context_provider("session", shared)
shared.set("locale", "en-GB")  # 両エージェントから参照可能

登録状況の確認や登録解除:

"user" in agent.context_providers
agent.unregister_context_provider("user")

フェーズ 5 — 動作確認

プロバイダーが正しく描画されるか、簡易スモークテストを実施します:

uv run python -c "from <project>.context_providers import UserCtx; c = UserCtx(); c.name='Alice'; c.role='admin'; print(c.get_info())"

次に、agent.system_prompt_generator.generate_prompt(...) を確認するか、エージェントを実際に動かして completion:kwargs フック経由で最初のリクエストのペイロードを検査し、システムプロンプトにプロバイダーのセクションが含まれていることを確認します(フックの詳細は ../framework/references/hooks.md 参照)。


フェーズ 6 — 引き渡し

以下をユーザーに伝えます:

  • プロバイダーの格納場所、register_context_provider で使用した名前、フィールドの更新方法。
  • ライフサイクルの説明: 登録は一度だけ行い、run() の合間にフィールドを更新すれば、プロンプトに自動的に反映される。
  • 任意の次のステップ:
    • このプロバイダーを使うエージェントの作成 → create-atomic-agent スキル。
    • ループ内でプロバイダーを更新するリサーチ / RAG ループ → atomic-examples/deep-research/ および ../framework/references/orchestration.md 参照。

アンチパターン

  • get_info() 内での遅いI/Oagent.run() のたびに実行されます。キャッシュするか外部でリフレッシュしてください。
  • get_info() から文字列以外を返す — プロンプト生成時にエラーが発生します。
  • register_context_provider(...) の呼び忘れ — プロバイダーがプロンプトに反映されません。
  • 同一エージェント上でのタイトルの重複 — セクションが衝突します。タイトルはユニークにしてください。
  • プロバイダーへの機密情報の保存 — すべてのLLMリクエストに含まれてしまいます。モデルが推論に必要な情報のみを注入してください。

マルチエージェント共有パターン・動的更新リサーチループ・非同期ソースパターンなど、より詳細な内容については ../framework/references/context-providers.md を参照してください。

原文(English)を表示

Create an Atomic Agents Context Provider

A context provider injects a named, titled block into the agent's system prompt at every run(). The base prompt stays static; the context is what changes between calls.

For deep material (caching strategies, async data sources, multi-agent sharing patterns), the authority is ../framework/references/context-providers.md. This skill is the action-oriented path: clarify → write → register.

When this fires vs the umbrella framework skill

  • This skill: the user wants to add a provider — "inject the user's name", "make the agent see the current time", "feed retrieved docs into the prompt", "share session state across two agents".
  • framework skill: questions about Atomic Agents in general, or about something other than authoring a provider.

Phase 1 — Clarify

Bundle into one message:

  1. What goes into the prompt? One sentence. Defines the provider's job.
  2. Where does the data come from? In-memory state mutated by your code? A vector DB lookup? A REST call? A clock?
  3. How fresh must it be? Per-run() (default), every N seconds (cache), or refreshed externally before each call (async data).
  4. Which agent(s)? One agent, or shared across multiple agents?

Skip what's already obvious from context.

Phase 2 — Plan

Confirm in one short block:

  • File: <project>/context_providers.py (or alongside the agent that owns it).
  • Class: <Topic>Ctx(BaseDynamicContextProvider).
  • Title (rendered as the section header in the prompt) — must be unique across providers on the same agent.
  • Update mechanism: mutate fields between run() calls (most common), set via a method, or await refresh() for async sources.

Phase 3 — Implement

Skeleton

from atomic_agents.context import BaseDynamicContextProvider


class UserCtx(BaseDynamicContextProvider):
    def __init__(self):
        super().__init__(title="User Context")
        self.name: str = ""
        self.role: str = ""

    def get_info(self) -> str:
        if not self.name:
            return "No user is logged in."
        return f"User: {self.name} (role: {self.role})"

get_info() is synchronous and runs on every agent.run() — keep it cheap. No HTTP, no DB queries, no file I/O. Cache slow sources (see "Cached" pattern below). For async data sources, await provider.refresh() from your loop before calling the agent.

Common patterns

Time — read-only, no state mutation needed:

from datetime import datetime, timezone

class TimeCtx(BaseDynamicContextProvider):
    def __init__(self):
        super().__init__(title="Current Time")

    def get_info(self) -> str:
        return datetime.now(timezone.utc).isoformat()

RAG / retrieved docs — set externally, read inside get_info():

class RAGCtx(BaseDynamicContextProvider):
    def __init__(self):
        super().__init__(title="Retrieved Documents")
        self.docs: list[dict] = []

    def set(self, docs: list[dict]) -> None:
        self.docs = docs

    def get_info(self) -> str:
        if not self.docs:
            return "No relevant documents retrieved."
        return "\n\n".join(f"[{d['source']}] {d['content']}" for d in self.docs)

# In the calling code, just before agent.run():
rag.set(vector_db.search(query, k=4))
agent.run(query_input)

Session — mutable key/value state shared across agents:

class SessionCtx(BaseDynamicContextProvider):
    def __init__(self):
        super().__init__(title="Session")
        self._data: dict[str, str] = {}

    def set(self, key: str, value: str) -> None:
        self._data[key] = value

    def get_info(self) -> str:
        if not self._data:
            return "No session state."
        return "\n".join(f"- {k}: {v}" for k, v in self._data.items())

Cached — for slow sources (DB schema, expensive computation):

import time

class DBSchemaCtx(BaseDynamicContextProvider):
    def __init__(self, conn, ttl_seconds: int = 300):
        super().__init__(title="Database Schema")
        self._conn = conn
        self._ttl = ttl_seconds
        self._cached: str = ""
        self._at: float = 0.0

    def get_info(self) -> str:
        now = time.time()
        if not self._cached or now - self._at > self._ttl:
            self._cached = render_schema(self._conn)
            self._at = now
        return self._cached

Async source — refresh outside, read sync inside:

class AsyncCtx(BaseDynamicContextProvider):
    def __init__(self):
        super().__init__(title="Async Data")
        self._cached = ""

    async def refresh(self) -> None:
        self._cached = format(await fetch_remote())

    def get_info(self) -> str:
        return self._cached

# Caller
await ctx.refresh()
await agent.run_async(input_data)

Phase 4 — Register

ctx = UserCtx()
agent.register_context_provider("user", ctx)

# Mutate before each run as needed:
ctx.name = "Alice"; ctx.role = "admin"
agent.run(...)

Sharing one provider instance across agents is allowed — updates propagate to every agent that registered it:

shared = SessionCtx()
agent_a.register_context_provider("session", shared)
agent_b.register_context_provider("session", shared)
shared.set("locale", "en-GB")  # visible to both agents

Inspect or unregister:

"user" in agent.context_providers
agent.unregister_context_provider("user")

Phase 5 — Verify

Quick smoke test that the provider renders:

uv run python -c "from <project>.context_providers import UserCtx; c = UserCtx(); c.name='Alice'; c.role='admin'; print(c.get_info())"

Then confirm the rendered system prompt includes the provider's section by inspecting agent.system_prompt_generator.generate_prompt(...) or by running the agent and checking the first request's payload via the completion:kwargs hook (see ../framework/references/hooks.md).

Phase 6 — Hand off

Tell the user:

  • Where the provider lives, what name was used in register_context_provider, and how to mutate it.
  • The lifecycle: register once, mutate fields between calls, the prompt picks up the change automatically.
  • Optional next steps:
    • The agent that consumes it → create-atomic-agent skill.
    • A research / RAG loop that updates the provider in a loop → see atomic-examples/deep-research/ and ../framework/references/orchestration.md.

Anti-patterns

  • Slow I/O inside get_info() — runs on every agent.run(). Cache it or refresh externally.
  • Returning a non-string from get_info() — raises at prompt time.
  • Forgetting register_context_provider(...) — the provider never reaches the prompt.
  • Duplicate titles across providers on the same agent — sections collide. Use unique titles.
  • Storing secrets in the provider — they end up in every LLM request. Inject only what the model needs to reason about.

For deeper material — multi-agent sharing patterns, dynamic-update research loops, async source patterns — load ../framework/references/context-providers.md.

原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。