モジュール 05 · 第 3 回

ツールの設計

同じ三つのツールでも、名前と説明があいまいだとモデルは 30 回中 14 回しか正しく選べず、はっきり書くと 30 回すべて正解しました。ツールの名前、説明、引数、戻り値、エラーメッセージをそれぞれどう書くべきかを説明します。

  • 約 35 分
  • 難易度:中級
  • 検証:2026-09-14 deepseek-flash

コードと実行結果は実際に動かしたときのまま載せているため、コメントと出力は中国語です。

エージェントが使いやすいかどうかは、大半がツールで決まります。モデルに見えるのはツールの名前、説明、引数の定義だけで、あなたのコードは見えません。説明書があいまいだと、モデルは推測するしかありません。このツールは何ができるのか。いつ使うべきか。引数に何を入れるのか。

この課ではまず実験で説明書の良し悪しの差を測り、それから具体的な書き方を説明します。

実験:あいまいな説明とはっきりした説明

同じ三つの機能です。ドキュメントを検索する、ドキュメントのファイルを読む、PyPI でバージョン番号を調べる。説明書を二組書きます。

あいまいな組:名前は汎用的な動詞で、説明は二、三語だけです。

VAGUE = [
    fn("search", "搜索", q="内容"),
    fn("read", "读取", x="要读的东西"),
    fn("lookup", "查找信息", name="名字"),
]

はっきりした組:名前は操作の対象を示し、説明には何ができるか、いつ使うか、引数をどう埋めるかをはっきり書きます。

CLEAR = [
    fn("search_docs", "在 httpx 官方文档里按英文关键词全文搜索,返回匹配的文件名和行号。"
       "用户问 httpx 某个功能怎么用、某个参数是什么意思时,先用它。",
       keyword="英文关键词,例如 timeout、proxy、follow_redirects"),
    fn("read_doc", "读取 httpx 文档里某个文件的内容。通常在 search_docs 找到文件名之后使用。",
       path="文档文件路径,例如 advanced/timeouts.md"),
    fn("get_pypi_info", "查询某个 Python 包在 PyPI 上的最新版本号和发布信息。只在用户问版本号、是否已发布新版本时使用。",
       package="PyPI 上的包名,例如 httpx"),
]

fn はツールの説明書を生成する小さな関数です。完全なコードは code/05-agents/tool_design.py。)

次に 10 問を用意し、それぞれ第 1 ステップでどのツールを呼ぶべきかを付けておきます。そのうち「你好」(こんにちは)の正解は、どのツールも呼ばないことです。各問題を各説明書で 3 回ずつ聞き、モデルが第 1 ステップでどのツールを選んだかだけを見て、実際には実行しません。

QUESTIONS = [
    ("httpx 怎么设置代理?", "search_docs"),
    ("httpx 最新版本是多少?", "get_pypi_info"),
    ("帮我看看 advanced/ssl.md 里写了什么", "read_doc"),
    ("follow_redirects 参数是干什么的?", "search_docs"),
    ("requests 现在出到哪个版本了?", "get_pypi_info"),
    ("httpx 怎么上传文件?", "search_docs"),
    ("你好", None),
    ("把 quickstart.md 的内容给我看一下", "read_doc"),
    ("httpx 有没有发布 1.0 正式版?", "get_pypi_info"),
    ("httpx 的 event hooks 怎么用?", "search_docs"),
]

結果です。

含糊的工具:14/30 次选对
    httpx 怎么设置代理?  应该用 search_docs,实际 {'None': 2, 'search_docs': 1}
    httpx 最新版本是多少?  应该用 get_pypi_info,实际 {'search_docs': 3}
    帮我看看 advanced/ssl.md 里写了什么  应该用 read_doc,实际 {'read_doc': 2, 'get_pypi_info': 1}
    follow_redirects 参数是干什么的?  应该用 search_docs,实际 {'search_docs': 1, 'None': 1, 'get_pypi_info': 1}
    requests 现在出到哪个版本了?  应该用 get_pypi_info,实际 {'get_pypi_info': 1, 'search_docs': 2}
    httpx 怎么上传文件?  应该用 search_docs,实际 {'None': 3}
    httpx 有没有发布 1.0 正式版?  应该用 get_pypi_info,实际 {'search_docs': 3}
清楚的工具:30/30 次选对

同じモデルで、説明書が違うだけで、正答率が 47% から 100% になりました。

あいまいな説明書のどこが悪いのか

ツールがどの範囲を扱うのかわからない。「搜索」(検索)はどこを検索するのか。Web ページか、ドキュメントか、コードか。モデルにはわかりません。そのため「httpx の最新バージョンは?」に対して 3 回とも search を選びました。「検索」が最も汎用的に聞こえるからです。

いつ使うべきかわからない。「httpx でファイルをアップロードするには」では、3 回ともどのツールも呼ばず、モデルは記憶でそのまま答えました。search を使えばもっと信頼できる答えが見つかることを知らないので、使う理由がないのです。

名前と機能が合っていないlookup は実は PyPI のバージョンを調べるものですが、「情報を探す」という説明では「読む」や「検索」と区別できず、モデルは適当に選ぶしかありません。「follow_redirects パラメータは何をするもの?」では、3 回で 3 つの違う結果になりました。

はっきりした説明書はこれらをすべて明記しています。検索するのは「httpx の公式ドキュメント」で、「ユーザーが httpx のある機能の使い方を聞いたら、まずこれを使う」。バージョンを調べるツールは「ユーザーがバージョン番号を聞いたときだけ使う」。モデルは推測する必要がありません。

名前

  • 操作の対象をはっきりさせるsearch_docssearch よりよく、get_pypi_infolookup よりよいです。ツールが増えると、汎用的な名前はすぐにぶつかります。
  • 動詞で始め、一貫させるget_search_read_create_ と、一組のルールを最後まで使います。
  • 略語を使わないgpi があなたには何かわかっても、モデルにはわかりません。

説明

よい説明は三つの問いに答えます。

  1. 何ができるか? 「httpx の公式ドキュメントを英語のキーワードで全文検索し、マッチしたファイル名と行番号を返す」。
  2. いつ使うべきか? 「ユーザーが httpx のある機能の使い方を聞いたら、まずこれを使う」。
  3. いつ使うべきでないか? 「ユーザーがバージョン番号や新しいバージョンが出たかどうかを聞いたときだけ使う」。

ツールどうしが混同しやすいとき、三つ目は特に重要です。また、説明にはツールどうしの連携を書いてもかまいません。たとえば read_doc の「ふつうは search_docs でファイル名が見つかった後に使う」と書けば、モデルは先に検索してから読むことがわかります。

引数

  • どの引数にも説明を書き、できれば例を付ける。「英語のキーワード。例:timeout、proxy、follow_redirects」。例はモデルに形式を伝え、「ドキュメントは英語なので英語で検索する」ことも暗に示します。
  • 引数は少ないほどよい。ツールに引数が七つも八つもあると、モデルは埋め忘れたり間違えたりしやすくなります。既定値を付けられるものは付けます。
  • 列挙で値を限定する。引数がいくつかの決まった値しか取れないなら、スキーマで enum として並べます(モジュール 02 第 4 課で使いました)。
  • 名前と型をはっきりさせるxqname のような引数名より、pathkeywordpackage のほうがよいです。

戻り値

ツールの戻り値はそのままコンテキストに入り、後のすべてのステップでその分を支払います。ですから次のようにします。

  • 役に立つ情報だけを返す。前の課の get_pypi_info は、バージョン番号、概要、Python のバージョン要件という四つのフィールドだけを選び、PyPI が返す数十 KB の生の JSON を丸ごと詰め込んではいませんでした。
  • 長さを制限する。前の課の grep_docs は最大 20 件、read_doc は一度に最大 80 行で、ループにはさらに 3000 文字の切り詰めがありました。
  • モデルが次のステップで使いやすくするgrep_docs は「ファイル名:行番号:内容」を返すので、モデルはファイル名と行番号をそのまま使って read_doc を呼べます。
  • 結果が空のときははっきり言う。空文字列ではなく「pool timeout は見つかりませんでした」と返します。空文字列はモデルを困惑させます。ツールが壊れたのか、本当に何もないのか。

エラーメッセージ

エラーメッセージはモデルに向けて書くもので、モデルが直せるよう手助けするべきです。

错误:没有这个文件 advanced/timeout.md,请先用 list_docs 查看有哪些文件

この一文は三つのことをはっきりさせています。何が間違っているか、どの引数が間違っているか、次に何をすべきか。Python の既定の FileNotFoundError: [Errno 2] No such file or directory と比べてください。モデルにも意味はわかりますが、正しいファイル名を探すのにどのツールを呼べばよいかはわかりません。

ツールが増えたらどうするか

ツールが多いほど、モデルは正しく選びにくくなり、毎回のリクエストの説明書も長くなります。いくつかの経験則です。

  • 機能の近いツールをまとめるsearch_docssearch_api_reference の違いをあなた自身も説明できないなら、一つにまとめて引数で区別します。
  • 場面ごとにグループ分けする。タスクごとに関係するツールだけを渡します。第 6 課のマルチエージェントでこの考え方を使います。
  • 軌跡を見る。よく誤用されるツールこそ、説明書を直すべきツールです。

練習問題

  1. tool_design.py のはっきりした組で、search_docs の説明から「ユーザーが httpx のある機能の使い方を聞いたら、まずこれを使う」を削除して実行し直してください。「httpx でファイルをアップロードするには」の結果は変わりましたか。
  2. 両方の組に機能を一つ加えてください。すべてのドキュメントのファイルを一覧する list_docs です。あいまいな組では list という名前で説明は「一覧」とし、はっきりした組はこの課の方法で書きます。これをテストする問題を 2 問加えてください。
  3. 以前書いた関数を一つ選び、この課の方法でツールの説明書を書いて、モデルにそれを呼ばせてください。

確認テスト

1. よいツールの説明は、どんな問いに答えるべきですか?

何ができるか。いつ使うべきか。いつ使うべきでないか(特に他のツールと混同しやすいとき)。さらに、他のツールとどう連携するか、たとえば「ふつうは search_docs の後に使う」と書いてもかまいません。

2. ツールの戻り値をできるだけ短くすべきなのはなぜですか?

戻り値はそのままメッセージのリストに入り、エージェントの後のすべてのステップでそれを持ってモデルを呼び出し、その分を支払うことになります。戻り値が長すぎるとモデルが要点をつかめなくなり、コンテキストウィンドウをいっぱいにしてしまうこともあります。役に立つフィールドだけを返し、長さの上限を設けます。

3. ツールのエラーメッセージはどう書くのが一番よいですか?

モデルに向けて書き、何が間違っているか、どこが間違っているか、次に何をすべきかをはっきり伝えます。たとえば「X というファイルはありません。まず list_docs でどんなファイルがあるか確認してください」。こうすればモデルは同じ間違いを繰り返さずに、自分で直せます。

質問と議論

このレッスンでつまずいたところは、ここで質問してください。他の人の質問に答えるのも歓迎です。

質問で 3 ポイント、回答で 6 ポイント。審査を通過すると公開されます。

議論を読み込んでいます…