`BaseDynamicContextProvider`(エージェントに動的な背景情報を注入するための基盤機能)を構築します。これにより、エージェントが実行されるたびに、名前と説明の付いた情報ブロックをシステムプロンプト(エージェントへの指示)に追加できます。 注入できる情報: - 現在時刻 - ユーザーの身元 - 検索結果から取得したドキュメント(RAG=データベースから関連情報を自動取得する機能) - セッションの状態 - キャッシュされたデータベースのスキーマ(データ構造) **次のような場合に使用:** - ユーザーが「コンテキストプロバイダーを追加したい」と依頼した場合 - 「プロンプトに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`.
コンテキストプロバイダーは、run() が呼ばれるたびに、名前とタイトルを持つブロックをエージェントのシステムプロンプトに注入します。ベースプロンプトは静的なまま維持され、呼び出しごとに変化するのはコンテキスト部分です。
キャッシュ戦略・非同期データソース・マルチエージェント共有パターンなど、より深い内容については ../framework/references/context-providers.md を参照してください。このスキルは実践的なパスです: 明確化 → 実装 → 登録。
framework スキルの使い分けframework スキル: Atomic Agents 全般に関する質問、またはプロバイダー作成以外のトピック。以下を1つのメッセージにまとめて確認します:
run() のたびに更新(デフォルト)、N秒ごとにキャッシュ、または各呼び出し前に外部から非同期リフレッシュ?文脈から明らかな項目はスキップして構いません。
以下を簡潔なブロックで確認します:
<project>/context_providers.py(またはそれを使うエージェントと同じ場所)。<Topic>Ctx(BaseDynamicContextProvider)。run() の合間にフィールドを書き換える(最も一般的)、メソッド経由でセットする、または非同期ソースの場合は await refresh() を使う。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)
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")
プロバイダーが正しく描画されるか、簡易スモークテストを実施します:
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 参照)。
以下をユーザーに伝えます:
register_context_provider で使用した名前、フィールドの更新方法。run() の合間にフィールドを更新すれば、プロンプトに自動的に反映される。create-atomic-agent スキル。atomic-examples/deep-research/ および ../framework/references/orchestration.md 参照。get_info() 内での遅いI/O — agent.run() のたびに実行されます。キャッシュするか外部でリフレッシュしてください。get_info() から文字列以外を返す — プロンプト生成時にエラーが発生します。register_context_provider(...) の呼び忘れ — プロバイダーがプロンプトに反映されません。マルチエージェント共有パターン・動的更新リサーチループ・非同期ソースパターンなど、より詳細な内容については ../framework/references/context-providers.md を参照してください。
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.
framework skillframework skill: questions about Atomic Agents in general, or about something other than authoring a provider.Bundle into one message:
run() (default), every N seconds (cache), or refreshed externally before each call (async data).Skip what's already obvious from context.
Confirm in one short block:
<project>/context_providers.py (or alongside the agent that owns it).<Topic>Ctx(BaseDynamicContextProvider).run() calls (most common), set via a method, or await refresh() for async sources.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.
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)
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")
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).
Tell the user:
register_context_provider, and how to mutate it.create-atomic-agent skill.atomic-examples/deep-research/ and ../framework/references/orchestration.md.get_info() — runs on every agent.run(). Cache it or refresh externally.get_info() — raises at prompt time.register_context_provider(...) — the provider never reaches the prompt.For deeper material — multi-agent sharing patterns, dynamic-update research loops, async source patterns — load ../framework/references/context-providers.md.
原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。