openai-agents について
OpenAI Agents SDK を使ったマルチエージェントシステムの構築を、Python と Go の例やパターンで説明するスキルです。ツール、ハンドオフ、共有コンテキスト、トレース、Webhook 検証を扱います。
主な機能
- 01エージェント用ツールの定義
- 02ハンドオフによるタスク委任
- 03エージェント間のコンテキスト共有
- 04会話 ID による実行トレース
- 05Webhook 署名の検証
活用シーン
- 01マルチエージェントワークフローの構築
- 02専門エージェント間のタスク引き継ぎ
- 03会話単位での実行追跡
- 04受信 Webhook の検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ brojonat/ llmsrules --skill openai-agentsインストール後、Claude Code で/openai-agentsを入力して読み込まれたか確認します。
詳細
OpenAI Agents SDK
ツール定義、ハンドオフ、コンテキスト管理、トレース機能を使って、マルチエージェントシステムを構築します。
Python エージェントのフロー
from agents import (
Agent, Runner, RunContextWrapper,
function_tool, handoff, trace,
)
from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX
from pydantic import BaseModel
# Context shared across agents
class MyContext(BaseModel):
user_name: str | None = None
session_id: str | None = None
# Define tools with @function_tool
@function_tool(name_override="lookup_tool", description_override="Look up information.")
async def lookup_tool(question: str) -> str:
return f"Answer to: {question}"
@function_tool
async def update_record(
context: RunContextWrapper[MyContext], record_id: str, value: str
) -> str:
"""Update a record. Args: record_id, value."""
context.context.session_id = record_id
return f"Updated {record_id} to {value}"
# Define agents with handoffs
specialist = Agent[MyContext](
name="Specialist",
handoff_description="Handles specific tasks.",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
You are a specialist agent. Use your tools to help the customer.""",
tools=[update_record],
)
triage = Agent[MyContext](
name="Triage",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
You are a triage agent. Delegate to the appropriate specialist.""",
handoffs=[specialist],
)
# Allow circular handoffs
specialist.handoffs.append(triage)
# Run the agent loop
async def main():
current_agent = triage
input_items = []
context = MyContext()
conversation_id = uuid.uuid4().hex[:16]
while True:
user_input = input("You: ")
with trace("My workflow", group_id=conversation_id):
input_items.append({"content": user_input, "role": "user"})
result = await Runner.run(current_agent, input_items, context=context)
for item in result.new_items:
if isinstance(item, MessageOutputItem):
print(f"{item.agent.name}: {ItemHelpers.text_message_output(item)}")
elif isinstance(item, HandoffOutputItem):
print(f"Handed off: {item.source_agent.name} -> {item.target_agent.name}")
input_items = result.to_input_list()
current_agent = result.last_agent
Go エージェントのフロー
nlpodyssey/openai-agents-go を使用します。
import (
"github.com/nlpodyssey/openai-agents-go/agents"
"github.com/nlpodyssey/openai-agents-go/agents/extensions/handoff_prompt"
"github.com/nlpodyssey/openai-agents-go/tracing"
)
// Tools
type LookupArgs struct {
Question string `json:"question"`
}
func Lookup(_ context.Context, args LookupArgs) (string, error) {
return "Answer to: " + args.Question, nil
}
var LookupTool = agents.NewFunctionTool("lookup", "Look up information.", Lookup)
// Agents
var (
Specialist = agents.New("Specialist").
WithHandoffDescription("Handles specific tasks.").
WithInstructions(handoff_prompt.PromptWithHandoffInstructions(`...`)).
WithTools(LookupTool).
WithModel("gpt-4o")
Triage = agents.New("Triage").
WithInstructions(handoff_prompt.PromptWithHandoffInstructions(`...`)).
WithAgentHandoffs(Specialist).
WithModel("gpt-4o")
)
func init() {
Specialist.AgentHandoffs = append(Specialist.AgentHandoffs, Triage)
}
// Run
result, err := agents.RunInputs(ctx, Triage, inputItems)
主なパターン
- コンテキスト:エージェント間で状態を共有するには、Pydantic BaseModel(Python)または context.Value(Go)を使用します
- ハンドオフ:エージェントは互いに処理を委譲します。副作用の処理には
on_handoffフックを使用します - トレース:会話を追跡するため、実行を
trace()/tracing.RunTrace()で囲み、group_idを指定します - ツール:
@function_toolでデコレートします。SDK が関数シグネチャから引数を抽出します - 循環ハンドオフ:前方参照の問題を避けるため、エージェントの定義後にハンドオフを追加します
Webhook の検証
from fastapi import FastAPI, Request, Response
from openai import OpenAI, InvalidWebhookSignatureError
app = FastAPI()
client = OpenAI(webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"])
@app.post("/webhook")
async def webhook(request: Request):
try:
body = await request.body()
headers = dict(request.headers)
event = client.webhooks.unwrap(body, headers)
if event.type == "response.completed":
response = client.responses.retrieve(event.data.id)
print("Response output:", response.output_text)
return Response(status_code=200)
except InvalidWebhookSignatureError:
return Response(content="Invalid signature", status_code=400)
コメント
Markdown 対応