openAIの最近の発表
追加されたアップデート
- Response APIが追加された
- エージェント構築に特化してユーザーに代わってタスクを自律的に実行するシステムの構築を支援する
- Web検索やファイル検索、コンピューターの利用といった新しい組み込みツールをサポートしているため単一のAPI呼び出しで複数のツールとモデルの端を利用してより複雑なタスクを解決することができる
- ChatCompletion API
- 主に会話のコンテキストに基づいてテキストを生成する
つまり、レスポンスAPIの登場によってより高度なエージェントの構築を簡単に構築できるようになったということ。
Agent SDK
上記のようなAPIにプラスアルファでエージェントSDKと言われるものが追加され、そこでは複数のエージェントとのやり取りやトレーシング、デバッグなどの方法なども構築されておりより開発者にとってスムーズに開発が進められるようなものとなっている
コアコンセプト
- エージェント
- ツールを利用しながら、特定のタスクを実行するための主体であると考えられる
- エージェントは特定の指示と利用可能なツールを用い単独であるいは他のエージェントと連携してユーザーの代わりにタスクを自律的に実行するLLMのこと
- ハンドオフ
- あるエージェントが処理できないタスクや、別の専門のエージェントがより適切に対応できるタスクが発生した場合に、そのタスクの制御を別のエージェントに引き渡す
- ガードレール
- ユーザーからの入力や他のエージェントからの引渡しにおける入力が期待される形式や内容であるかをチェックして不適切な入力による誤作動やセキュリティ上のリスクを防ぐ
- また出力の検証、エージェントが生成する出力が特定の基準を満たしているか安全な内容であるかをチェックする
- trace
- エージェントの実行の過程を可視化しデバッグやパフォーマンスの最適化を行う仕組み
エージェントとは、以下の資格を持つLLM
- 指示(システムプロンプトや動的な指示)
- 呼び出せるツール
- ハンドオフ(他のエージェントへの委任)
- 入力または出力用のオプショナルのガードレール
- 追加設定(モデルパラメータ、出力タイプ、フック)
エージェントの動作
- ユーザーの入力でエージェントを呼び出すとエージェントループが実行される。
- エージェントはこれまでの会話(ユーザー入力、以前のツール結果、システムメッセージを含む)を確認する
- そして以下のいずれかを決定する
- 最終的な答えを生成してループを終了する
- ツールを呼び出す
- 別のエージェントに引き継ぐ
- エージェントが最終的な回答を出すか、別のエージェントに引き継ぐとループは終了する
このようにAgentSDKはLLMがタスクを達成するために必要な推論、ツールの選択と実行、そして必要に応じた他へのエージェントへの引き渡しといった一連の判断をあらかじめ設定された指示や利用可能なツールに基づいて自律的に行うことを可能にする。
これによって開発者は複雑なオーケストレーションロジックを個別に実装する手間が省け、より効率的に信頼性の高いエージェントアプリケーションを構築することが可能になる。
以下の例では、英語とスペイン語を話すエージェントを定義してそれをtriage_agentにhandoffとして渡す。
そうすることで裏側で適切なエージェントを選択して結果を返してくれる。
from agents import Agent, Runner
import asyncio
spanish_agent = Agent(
name="Spanish agent",
instructions="You only speak Spanish.",
)
english_agent = Agent(
name="English agent",
instructions="You only speak English",
)
triage_agent = Agent(
name="Triage agent",
instructions="Handoff to the appropriate agent based on the language of the request.",
handoffs=[spanish_agent, english_agent],
)
async def main():
result = await Runner.run(triage_agent, input="hello?")
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
ツール
ツールを使用するとエージェントは外部感想を呼び出すことができる例えばAPIへのアクセスやコードの実行、検索の実行など。LLMは実行時に引数を指定して感想を呼び出し、結果を確認してそれを使用して次のステップに通知することができる。
ツールを定義するためにはデコレーターを利用する
from agents.tool import function_tool
@function_tool
def get_weather(location: str, unit: str = "C") -> str:
"""
Fetch the weather for a given location, returning a short description.
"""
# Example logic
return f"The weather in {location} is 22 degrees {unit}."
コンテキスト
複数のツールを呼び出しやステップに渡ってセッションデータ、クレデンシャル、または様々な状態を保持する必要があるこのSDKを利用することでコンテキストオブジェクトを実行に渡すことができる。
そしてツールはそのコンテキストにアクセスしデータを読み更新することができる。
import asyncio
from dataclasses import dataclass
from agents import Agent, RunContextWrapper, Runner, function_tool
@dataclass
class UserInfo: # (1)!
name: str
uid: int
@function_tool
async def fetch_user_age(wrapper: RunContextWrapper[UserInfo]) -> str: # (2)!
return f"User {wrapper.context.name} is 47 years old"
async def main():
user_info = UserInfo(name="John", uid=123) # (3)!
agent = Agent[UserInfo]( # (4)!
name="Assistant",
tools=[fetch_user_age],
)
result = await Runner.run(
starting_agent=agent,
input="What is the age of the user?",
context=user_info,
)
print(result.final_output) # (5)!
# The user John is 47 years old.
if __name__ == "__main__":
asyncio.run(main())
ガードレール
Guardrailはエージェントの入力または出力に対して許可されていないコンテンツのブロックやデータの整合性の検証などを適用することができる
from agents.guardrails import CustomGuardrail
async def is_not_swearing(msgs, context) -> bool:
content = " ".join(m["content"] for m in msgs if "content" in m)
return "badword" not in content.lower()
my_guardrail = CustomGuardrail(
guardrail_function=is_not_swearing,
tripwire_config=lambda output: not output # if 'False', raise error
)
agent = Agent(
name="my_agent",
input_guardrails=[my_guardrail]
)
out = await AgentRunner.run(agent, ["some text"])
# If "badword" is in input, GuardrailTripwireTriggered is raised.
Discussion