技術 約9分で読めます

X Premium基本契約のままM4 Mac miniからHermes Agentのx_searchを叩いたら通ったが抽象クエリだとX検索が発動しなかった

いけさん目次

@MtkN1XBt さんのポストで、Hermes Agent本体を入れずに x_search_tool だけ叩く最小セットアップが流れてきたので、M4 Mac mini(16GB)から X Premium 基本契約で試した。

Hermes Agent の公式ドキュメントには「x_search は SuperGrok / X Premium+ tier 必須」と書いてあるが、わたしの X Premium 基本契約でも認証から実呼び出しまで普通に通った。Zenn にも同じ動作報告があるので、公式の文面より実装の方が緩いか、サイレントに門戸が広がっている可能性が高い。

ただし「動いた」だけで終わると罠にハマる。クエリの書き方によっては Grok の一般知識回答が返ってくるだけで、X検索が一切発動しない。実機で踏んだのでそこも残す。

何を確認したかったか

きっかけは @MtkN1XBt さんのスレッドで、要点は次のとおり。

  • x_search を使うだけなら Hermes Agent 本体のインストール・設定は不要
  • 必要なのは uv(uvx)と xAI の OAuth 認証だけ
  • Hermes 内部の Python API(tools.x_search_tool)を直接呼べば、Hermes本体のモデルに「x_search を使って…」と頼むより1段解釈が省ける

ここで気になったのが課金階層。Hermes Agent の公式ドキュメントを読むと、

The x_search tool requires either SuperGrok / X Premium+ tier authentication or a paid xAI API key

と書かれている。一方で Zenn の個人検証記事では「X Premium 基本でも grok-4.3 と x_search が動いた」という報告。

わたしのアカウントは X Premium 基本(Premium+ ではない)。どちらが正しいか実機で確かめる。

セットアップ: uvx + xAI OAuth

uvx を使うので Python 環境構築は不要。uv だけ入っていれば良い。

xAI の OAuth 認証はこのコマンド一発。

uvx --from hermes-agent hermes auth add xai-oauth

実行するとブラウザが開いて xAI のログイン画面に飛ぶ。http://127.0.0.1:56121/callback 宛にコールバックが返り、トークンが uvx の管理下に保存される。

Open this URL to authorize Hermes with xAI:
https://auth.x.ai/oauth2/authorize?response_type=code&client_id=...
Waiting for callback on http://127.0.0.1:56121/callback
Browser opened for xAI authorization.
Added xai-oauth OAuth credential #1: "xai-oauth-oauth-1"

X Premium 基本契約のアカウントで、ここでは弾かれずに通った。少なくとも認証フェーズで階層チェックは効いていない。

リモートホスト(SSH 越し)で同じことをやる場合は、コールバックポートのトンネルが必要。

ssh -L 56121:127.0.0.1:56121 user@remote-host \
  'uvx --from hermes-agent hermes auth add xai-oauth --no-browser'

手元のブラウザでURLを開き、SSHトンネル経由でリモート側のHermesにトークンが届く流れ。

検証1: 抽象クエリだとX検索が発動しない

OAuthが通ったので、ワンライナーで x_search_tool を直接叩く。

uvx --from hermes-agent python -c \
  'from tools.x_search_tool import x_search_tool; print(x_search_tool("test query about AI"))'

time 付きで実測したところ、全体で 8.4秒 で返ってきた。返ってきたJSON(一部):

{
  "success": true,
  "provider": "xai",
  "credential_source": "xai-oauth",
  "tool": "x_search",
  "model": "grok-4.20-reasoning",
  "query": "test query about AI",
  "answer": "**AI (Artificial Intelligence)** is the simulation of human intelligence processes by machines...",
  "citations": [],
  "inline_citations": []
}

ポイントは2つ。

  • success: true で X Premium 基本契約でも通った。credential_sourcexai-oauth になっているので、間違いなく OAuth クレデンシャルで叩けている
  • citationsinline_citations も空配列

answer の中身を読むと「AIとは何か」「Narrow AI / Generative AI / Multimodal AI / AGI」みたいな一般解説で、Xを検索した形跡がない。Grok が自分の知識ベースから答えただけになっている。

つまり、ここで分かったのは「動いた」と「X検索が発動した」が別の話だということ。クエリが抽象的すぎると Grok は X を検索せず、汎用 LLM として答えてしまう。

検証2: 具体クエリにすると citations が付く

期間・対象・件数を絞ったクエリで投げ直す。

uvx --from hermes-agent python -c \
  'from tools.x_search_tool import x_search_tool; print(x_search_tool("過去1週間でX上で話題になったAIコーディングエージェントやLLMの新リリースは何?投稿者ハンドルと該当ポストを5件挙げて"))'

こちらは同じく time 計測で 58.4秒。抽象クエリの7倍掛かる。X検索が実際に走っているサインとも言える。レスポンスの後半(要点を抜粋):

{
  "success": true,
  "model": "grok-4.20-reasoning",
  "answer": "...エンゲージメントが高く、具体的な新リリース/ツールを扱った投稿を5件挙げます...",
  "inline_citations": [
    {"url": "https://x.com/futurepedia_io/status/2056208900979151314", "title": "1", ...},
    {"url": "https://x.com/i/status/2056022182560665602", "title": "2", ...},
    {"url": "https://x.com/i/status/2055117211774181690", "title": "3", ...},
    {"url": "https://x.com/higgsfield_ai/status/2054989169446023181", "title": "4", ...},
    {"url": "https://x.com/i/status/2056292686458708178", "title": "5", ...},
    {"url": "https://x.com/ApollonVisual/status/2056647214110274050", "title": "6", ...}
  ]
}

今度は inline_citations に 8 件入った。answer 内では [[1]] [[2]] のような脚注番号で本文中の主張に元ポストURLが紐づいている。実際に挙がってきたポストは:

  • Anthropic の claude-code-setup プラグインを紹介する @Suryanshti777 のポスト
  • @higgsfield_ai の Supercomputer リリース告知
  • @ApollonVisual による Cursor Composer 2.5(Kimi K2.5ベース)の技術詳細

具体的な投稿者ハンドル + 元ポストURLが取れているので、Grok の要約を入口にして個別ポストへ降りていく使い方ができる。

検証1と2の差は何か

同じ x_search_tool を呼んでいるのに、片方は citations が空、片方は埋まる。差分はクエリの具体性だけ。

X検索を確実に発動させたい場合、クエリに少なくとも次のどれかを入れた方が良さそうだった。

  • 期間を明示する(「過去1週間」「2026年5月」のような時間軸)
  • 対象範囲を具体的に絞る(特定の技術領域・ハンドル・トピック)
  • 件数指定(「5件挙げて」など、リスト出力を要求する)
  • 「投稿者ハンドル」「該当ポスト」のような、X上のオブジェクトを名指しする語

抽象的に「○○について教えて」と投げると、Grok は内部知識で答えてしまう。これは Web 検索系エージェント全般にある癖だが、Hermes 経由の x_search でも同じ振る舞いだった。

レスポンス時間も判別材料になる。今回の計測では、X検索が発動するクエリは約58秒、知識回答だけのクエリは約8秒で、約7倍の差が出た。10秒以内で返ってきたら X 検索が発動していない可能性が高い、と当たりを付けられる。

レスポンス構造のおさらい

x_search_tool のレスポンスは以下のフィールドで構成される。

  • success: 成否
  • provider: 常に xai
  • credential_source: 認証方式(xai-oauth または API key)
  • tool: 常に x_search
  • model: 内部で動いた Grok モデル名(検証時は grok-4.20-reasoning
  • query: 投げたクエリそのまま
  • answer: Grok による Markdown フォーマットの回答本文
  • citations: トップレベルの引用配列(実機検証では常に空だった)
  • inline_citations: 本文中の脚注番号と元ポストURLのマッピング

外部URL(GitHub、論文、公式ドキュメント等)は inline_citations には入らず、answer 本文中に書かれる形式。元ポストの本文に外部URLが含まれていれば Grok がそれを拾って answer に書く、という挙動。

パラメータと、言語・地域フィルタが存在しない問題

Hermes Agent の公式ドキュメントによると、x_search_tool で受け取れるパラメータは次のとおり。

パラメータ説明
querystring(必須)検索クエリ
allowed_x_handlesstring array含めるハンドル(最大10、excluded_x_handles と相互排他)
excluded_x_handlesstring array除外するハンドル(最大10)
from_datestring開始日(YYYY-MM-DD
to_datestring終了日(YYYY-MM-DD
enable_image_understandingboolean投稿添付画像を xAI 側で解析させるか
enable_video_understandingboolean投稿添付動画を xAI 側で解析させるか

ここで気になるのは、language / country 相当のパラメータが存在しない点。クエリの言語フィルタも、地域フィルタも公式仕様にはない。

実機での挙動も、これと整合していた。日本語クエリ(「過去1週間でX上で話題になったAIコーディングエージェント…」)を投げたら、

  • answer 本文は日本語で返ってきた
  • 引用された6本のポスト(@Suryanshti777, @higgsfield_ai, @ApollonVisual ほか)は全部英語ポストだった

つまり「クエリの言語に合わせて要約を翻訳する」が、検索ソース側は言語フィルタなしで取ってきている。X 本体のタイムラインで Grok が勝手に英語ポストを日本語に翻訳して混ぜてくる挙動と、x_search の出力も同じ系統と見て良さそう。

翻訳挙動はクエリ本文で制御できる

パラメータには無いが、クエリ本文で「翻訳・要約せず原文のまま」と明示すると、Grokは原文のまま返してくる。試したクエリ:

最近のAIコーディングエージェント関連で話題になったポストを3件挙げて。
投稿者ハンドル・原文ポスト本文(翻訳・要約せず原文のまま)・含まれる外部URL のみ出力。
answer全体も英語ポストは英語のまま、日本語ポストは日本語のままで。
解説は不要。

返ってきた answer(抜粋):

**@noohelhadedy**
A Design.md file helps AI coding agents understand your design system instead of guessing your UI.
Colors, typography, spacing, components, visual rules, and brand style in one markdown file.
...
https://github.com/VoltAgent/awesome-design-md

**@tom_doerr**
Orchestrates AI coding agents with persistent memory
https://github.com/RedPlanetHQ/core

**@supabase**
Make sure you install the Supabase plugin for AI coding agents when building apps with AI and Supabase
https://supabase.com/docs/guides/ai-tools/plugins

3件とも英語ポストで、本文・GitHub URL・t.co短縮URLがそのまま並んでいる。要約フェーズが省ける分、レスポンス時間も約39秒と短くなった(前回の翻訳ありクエリは約58秒)。

つまり日本語ソースだけ拾いたい / 原文を保持したい場合の選択肢は、次のあたりに集約される。

  • クエリ本文で「日本語のポストに限る」「原文のまま」と明示する(パラメータに無くてもクエリで効く)
  • allowed_x_handles に対象アカウントを並べる(最大10)
  • from_date / to_date で期間を絞り、ノイズが入る前にカットする

逆に「英語ソースから拾って日本語で要約してほしい」という用途には、デフォルトの翻訳挙動がそのまま効く。検索全般のニュースクリッピングなら言語フィルタなしの方が網羅性は上がる。

設定ファイル ~/.hermes/config.yaml 側で握れる値は別系統で、以下が主要なもの。

  • x_search.model: 使う Grok モデル名(デフォルト grok-4.20-reasoning
  • x_search.timeout_seconds: タイムアウト秒数(デフォルト180、最小30)
  • x_search.retries: 5xx / ReadTimeout 等での自動リトライ回数(デフォルト2)

デフォルトのタイムアウトが180秒に設定されていることからも、xAI 側も「複雑クエリは1〜2分掛かる」前提で設計されているのが分かる。

注意点・限界

実機で触って気になった点。

  • レスポンスは速くない。実測でX検索が発動するクエリは約58秒、知識回答だけのクエリでも約8秒。複雑クエリは1分超を見込んでスキル設計する
  • 返ってくるのは「Grokによる X 検索結果の要約 + 脚注URL」であって、X 検索 API ではない。元ポストの本文をそのまま取りたい場合は別途 URL を取得する必要がある
  • @MtkN1XBt さんのポストでも釘を刺されているとおり、「X API がタダになった」というのは事実と違う
  • Grok の解釈バイアスが answer に乗る。サンプル検証でも「xAI / Grok / Claude」周辺のトピックが過大評価されている可能性は否定できない
  • X Premium 基本で通った事実は、xAI 側のポリシーが変われば明日にも撤回されうる。本番運用に組み込むなら Premium+ への切り替えコストも視野に入れた方が無難