こんにちは
KIYONOのエンジニアです。
今回はpydantic AIというAIエージェントを作成するフレームワークを使用して自社サービスにchat型検索エージェントを導入した話を紹介します。
弊社のテックブログでは他にもAI Agentに関する記事を発信しているので、
興味がある方は合わせてこちらもご覧いただければと思います。
pydantic AIとは
pydantic AIは2024 年末〜25 年初に公開されたLLM/AI エージェント開発フレームワークです。
pydantic AI は 「型安全でテストしやすい AI エージェント」 を Python だけで構築できます。
まずはpyadanticAIの特徴を説明していきます。
依存関係
PydanticAI uses a dependency injection system to provide data and services to your agent’s system prompts, tools and output validators.
Matching PydanticAI’s design philosophy, our dependency system tries to use existing best practice in Python development rather than inventing esoteric “magic”, this should make dependencies type-safe, understandable easier to test and ultimately easier to deploy in production.
Pydantic AI では、エージェント用のシステムプロンプト・ツール・出力バリデータへデータやサービスを渡すために「依存性注入(Dependency Injection)」という仕組みを採用しています。
そして、この仕組みはpythonの既存のベストプラクティスに則っています。
依存関係の方が明示されるのでバグが防ぎやすく、テスト時にモックへ簡単に差し替えられるためテストが書きやすいといったメリットがあると記述されています。
例えば、下記のようにエージェントを定義することができます。
この時、
from dataclasses import dataclass
import httpx
from pydantic_ai import Agent
@dataclass
class MyDeps:
api_key: str,
http_client: httpx_AsyncClient
agent = Agent(
'openai:gpt-4o',
deps_type=MyDeps,
)
async defmain():
async with httpx.AsyncClient() as client:
deps = MyDeps('foobar', client)
result = await agent.run(
'Tell me a joke.',
deps=deps,
)
MyDepsのように、エージェントに渡す依存関係を明示することで、先ほど説明した依存性注入の恩恵を受けることができます。
また、上記のようにエージェントの作成が非常にシンプルなのもpydantic AIの大きなメリットだと思います。
関数ツール
→@agent.tool だけでLLM呼び出し関数が完成
エージェントにツールを登録する方法はいくつかあります。
- デコレータ経由 @agent.tool -エージェントのコンテキストのアクセスする必要があるツール用
- デコレータ経由 @agent.tool_plain – エージェントコンテキストへのアクセスを必要としないツール用
- tools キーワード引数を介してAgentに直接渡す
例えば、サイコロゲームを行うエージェントを作成するとします。
importrandom from pydantic_ai import Agent,RunContext agent = Agent( 'google-gla:gemini-1.5-flash', deps_type=str, system_prompt=( "You're a dice game, you should roll the die and see if the number " "you get back matches the user's guess. If so, tell them they're a winner. " "Use the player's name in the response." ), )
@agent.tool_plain def roll_die() -> str: """Roll a six-sided die and return the result.""" retur nstr(random.randint(1,6)) @agent.tool def get_player_name(ctx:RunContext[str])->str: """Get the player's name.""" return ctx.deps dice_result=agent.run_sync('My guess is 4',deps='Anne')print(dice_result.output)
自社サービスにAIエージェント導入してみた
導入対象のサービスは弊社で現在社内リリース中のSFAにChat型の検索エージェントを導入してみました。
SFA内にはざっと下記のような情報が管理されています。
- 案件情報
- フェーズ
- 紹介元
- 顧客
- 受注確度
- カテゴリ
- 社内情報
- 担当者
- 計上部署
- 売上情報
- 活動履歴
- 顧客情報
- 顧客名
- 接点のきっかけ
- ユーザ情報
- ユーザ名
- 所属部署
社内の要望としては、特に売上関連の数値を簡単にチャットで教えてくれると嬉しいという声が上がりました。
「今月の売上・粗利は?」
「予算達成率は?」
「受注確度Bまでにすると各数値はどうなる?」
「昨年同月比は?」
SFA内にレポート機能があり、こういった数値は見ることができますが、見たい断面に応じてフィルタリングを設定する必要があるため、少々面倒だったりします。
チャット内でこういった質問にパッと答えられたら、UX的にも非常にいいので、今回はこういった目的で導入することにしました。
今回作成したツールは大まかに以下のようなものです。
- 各種(案件、顧客、ユーザー)一覧を取得するツール
- 1案件の情報を全て取得するツール
- 条件に応じた案件を抽出し、売上・粗利を算出するツール
- 作対比を計算するツール
- 昨年同月比を計算するツール
- 前月比を計算するツール
- 予算達成率を計算するツール
例えば、案件の一覧を取得するツールであれば、
@agent.tool
def list_projects
"""
顧客の名前の一覧をもじれつでか文字列で返す
"""
projects = Project.objects.filter(
company_id=ctx.company_id, is_active=True
)
return "案件一覧:\n" + "\n".join([project.name for project in projects])
このようにfilter関数を使用して、ctx: RunContext[str]にある必要な情報を使用しつつ、案件の一覧を取得します。
他のツールも同じような要領で、関数の引数に基づいて、filterをかけてオブジェクトを取得し、
必要に応じて出力を算出するための演算処理を記述するようなツールになっています。
該当のツールを作成すれば、実際に「案件一覧を教えて」みたいな質問を投げるとそのツールを使用した結果が帰ってきます。「おお〜」ってなりました
- (例)案件の一覧を聞いてみた
- 作対比を聞いてみた
こんな感じでチャットで聞いた質問に対して、必要なツールを自動で呼び出して得た出力を返してくれてます。
実際にAI Agentを作ってみて難しいなあと思ったのは、「ツールの抽象度」と「ユーザの意図の汲み取り」です。
ポイント①:ツールの抽象度
ツールの抽象度については、例えば今回の場合予算達成率や作対比などは、それらを計算するようのツールをそれぞれ作成するような構成にしました。
ただ、この場合各ツールはそれ以外の用途に使用できず、汎用性が全くないツールになってしまっています。
一方で、これらのツールに汎用性を持たせようとすると、使用してほしいタイミングでそのツールが使用されなかったり、意図しない挙動を起こしたりと、エージェントの制御が難しくなるのが問題です。
ツールはできるだけ抽象度が高い方が、エージェントの可能領域の幅も広くなり、サービスとしての性能は向上しますが、なかなか上手い具合の抽象度のツールを作成するのに苦戦し、今回はひとまず目的が明確であるツールを作成しました。
ポイント②ユーザーの意図の汲み取り
ユーザーの意図の汲み取りについては、ユーザーの入力は必ずしもエージェントが知っている名称ではないことがあります。
例えば、弊社では部署を、部署ではなくユニットと呼びます。
「私のユニットは」と聞くと、おそらく「ユニット」が何を指しているのか、をエージェント側で解釈できず、うまく回答ができていません。「私の部署は」と聞くと正常に返せていることがわかります。
これは、案件名や企業名の略称でも同様のことが起こってしまうので、今後ブラッシュアップするべき部分です。
また、今後の展望としてチャット内で案件や顧客などの情報を登録できるようにしていきます。
チャットで情報取得も登録も編集も全て完結するようなエージェントを目指していきます。
最後に
いかがでしたでしょうか。
今回はpydantic AIというフレームワークを使用して、自社のサービスにAIエージェントを導入した事例についてお話ししました。
実際の挙動はまだ不安定であり、導入するには不十分な点も多いので、今後どんどんブラッシュアップしていく予定です。
本記事がAIエージェントを開発しようとしている人の助けになれば幸いです。
コメント