0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

n8nでPerplexityもどきを作ってみた話

0
Posted at

n8nでPerplexityもどきを自作した話

記事を書くのは初めてなので,至らない点が多くあると思いますが,ご了承くださいませ.

TL;DR

  • Perplexity Proが恋しく,n8nで検索エージェントを作成した
  • 速く,深い検索のために,Webhookノードを使った検索エージェントの並列化を行った
  • 深く調査して,回答するフローを構築することができた

背景

Perplexity Proの検索が良かった

AIで調べ物したい時,やはりリアルタイム情報がないとアウトプットを信頼できません.
学生向け無料プランで使っているGeminiは「ちょこっとweb検索する」という機能がついておらず,全て自分の知識で答えてくる気がします.かといって,Deep Researchは時間がかかりすぎるので小回りが効かないのです.

Perplexityのpro searchは,2,3分でいい感じにソースを調査してくれるので,とても使いやすかったのです.しかし,無料Pro期間が切れてしまい,一日3回のpro searchしかできなくなってしまいました.

n8n使ってみたい

n8n1はワークフロー自動化ツールで,APIやMCPツール,LLMを組み込んだワークフローをノーコードで構築できるのが特徴です.

少し触ってみて,認証トークンを入力するだけでGoogleをはじめとした様々なサービスと簡単に統合できて,とても便利だと感じました.Difyと似たツールではありますが,ワークフロー作成のUIは圧倒的にn8nが優れている気がします.

やりたいこと

こうした背景から,n8nを試すがてらPerplexity Proぐらい深い検索ができるフローを作りたいと思いました.

  • 「じっくり調べてくれるけど,徹底的な調査はいらない」そんな時に使えるちょうどいい検索エージェントを作る
  • n8nを使ったワークフロー構築を試す

準備

実行環境

n8nはOrbStackを使ってセルフホストしました.

  • PC:Macbook M4
  • コンテナ実行環境:OrbStack2 (Dockerの軽量版)

↓参考にさせていただきました
https://zenn.dev/digilaweb/articles/d2918deeeb5c25
https://docs.n8n.io/hosting/installation/docker/

n8nとツールのセットアップ

APIの制限に引っかかったりするのが面倒だったため,主要な機能はできるだけセルフホストしたいと思いました.n8nに加え,エージェントが検索に使うツールとして,メタ検索エンジンSearXNG3とPlaywright MCP4サーバーを起動します.

  • n8n:ワークフロー作成と実行
  • SearXNG:複数の検索エンジン(Google検索+DuckDuckGo+bing+...)に横断して検索をかけて情報を集めることができます
    SearXNGの検索カテゴリと検索エンジン一覧
  • Playwright MCP:動的なレンダリングが行われるwebページなどで,エージェントが内容取得に困った際,ブラウザ操作がどうしても必要な場合に利用します
SearXNGの読み方 X=>$\chi$(カイ-chi)=>chi(チ)という発想から,Searchingと読むらしいです(?) https://github.com/searxng/searxng/discussions/2522

docker compose upでこれらを起動します.

docker-compose.yml
services:
  # n8n
  n8n:
    image: n8nio/n8n:latest # 最新版のn8nイメージを指定
    container_name: n8n_local # コンテナ名を指定 (任意)
    restart: unless-stopped # コンテナが停止した場合、手動で停止しない限り再起動
    ports:
      - "5678:5678" # ホストOSの5678番ポートをコンテナの5678番ポートに接続
    environment:
      # 重要: ワークフローの認証情報などを暗号化するためのキー
      # 下記のコマンドで生成したランダムな文字列を設定してください
      - N8N_ENCRYPTION_KEY=1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
      # タイムゾーンを日本時間に設定
      - GENERIC_TIMEZONE=Asia/Tokyo
      - EXECUTIONS_TIMEOUT=3600   # seconds, example: 1 hour
      - EXECUTIONS_TIMEOUT_MAX=7200  # max per‑workflow timeout users can set
      - NODE_FUNCTION_ALLOW_EXTERNAL=node-fetch # code nodeにてfetchを使用可能にする
    volumes:
      # n8nの設定データやワークフローデータを永続化するためのボリューム
      - ./n8n_data:/home/node/.n8n
    depends_on:
      # searxngが起動してからn8nを起動するように指定
      - searxng
  # SearXNG
  searxng:
    image: searxng/searxng:latest
    container_name: searxng
    restart: unless-stopped
    volumes:
      # 設定ファイルをマウント
      - ./searxng:/etc/searxng:rw
    environment:
      - SEARXNG_BASE_URL=http://localhost:8080/
      - SEARXNG_UWSGI_WORKERS=4
      - SEARXNG_UWSGI_THREADS=4
      - GRANIAN_BLOCKING_THREADS=4
      - GRANIAN_WORKERS=5
    ports:
      - "127.0.0.1:8080:8080"
  # playwright mcp
  playwright-mcp:
    image: mcr.microsoft.com/playwright/mcp
    container_name: playwright-mcp
    # volumes:
    #   - ./path/to/your/config.json:/app/config.json:ro
    restart: unless-stopped
    # --init に相当:ゾンビプロセスを防止し、ブラウザを安全に終了させる
    init: true
    # -i (interactive) に相当:標準入力を開いたままにする
    stdin_open: true
    # --entrypoint node に相当
    # 2. npxコマンドの引数に対応する部分を記述
    entrypoint: ["node"]
    command: 
      - "cli.js"
      - "--port"
      - "8931"
      - "--headless" # cli.js 以降の引数に相当
      - "--browser"
      - "chromium"
      - "--no-sandbox"
      - "--host"
      - "0.0.0.0"
      - "--allowed-hosts"
      - "*"
    ports:
      - "8931:8931"
    deploy:
      resources:
        limits:
          cpus: '0.7'
          memory: 4000M
SearXNGは,デフォルト設定だと無効化されている検索エンジンがあったり,サブエージェントが同時にアクセスするとリクエストを処理し切れずにタイムアウトしてしまうことがあります.

そのため,SearXNGの設定を書き換えるため,設定ファイルをコンテナにマウントします.主要な設定は以下の通りです.

  • search.formats:n8nで検索結果を扱えるようにするため,JSON形式で結果を返すことを許可します
  • engines:検索エンジンを利用するかを決めたり,認証トークンが必要なものはここで明示的に指定します.GitHubのリポジトリや論文プレプリントデータベースであるArxivの利用を指定しています
  • outgoing:タイムアウトやプールサイズを変更します.ここでは,タイムアウトを長くすることで,並列アクセスが起きた時にもエラーが起きにくいようにします
./searxng/settings.yml
# https://docs.searxng.org/admin/settings/settings.html#settings-yml-location
# searxng/settings.yml
use_default_settings: true

server:
  # サーバーが許可するフォーマット
  # セキュリティキー(適当な長い文字列に変更してください)
  secret_key: "12345"

search:
  safe_search: 0 # 0: Off, 1: Moderate, 2: Strict
  autocomplete: ""
  formats:
    - html
    - json
# 使用する検索エンジンの設定(必要に応じて追加)
# refer to: https://github.com/searxng/searxng/blob/master/searx/settings.yml
engines:
  - name: google
    engine: google
    shortcut: go
  - name: duckduckgo
    engine: duckduckgo
    shortcut: ddg
  - name: github
    engine: github
    shortcut: gh
    disabled: false
  - name: github code
    engine: github_code
    shortcut: ghc
    disabled: false
    api_token: "GitHubのPersonalAccessToken" 
  - name: huggingface
    engine: huggingface
    shortcut: hf
    disabled: false
  - name: semantic scholar
    engine: semantic_scholar
    shortcut: se
    disabled: false
  - name: google scholar
    engine: google_scholar
    shortcut: gos
    disabled: false
  - name: arxiv
    engine: arxiv
    shortcut: arx
# リクエストのタイムアウト設定
# サブエージェントによる同時アクセス時のタイムアウトを低減
outgoing:
   request_timeout: 20.0
   max_request_timeout: 20.0
   pool_maxsize: 100

以上でn8n,SearXNG,Playwright MCPのセットアップは完了です.次に,検索結果から見つけたWebページの内容を取得するためのツールを準備します.

JINA Reader API

SearXNGでは,Google検索の結果ページに現れるようなURLとプレビューコンテンツしか取得できません.Webページにアクセスし,コンテンツを取得する必要があります.当初,Playwright MCPでのコンテンツ取得を計画していましたが,Playwrightで取得できるスナップショットにはタグなどの余分な情報が含まれており,LLMのコンテクストを圧迫します.

そこで,今回はJINA Reader API5を利用しました.JINA Readerは,WebページをLLMが読みやすいよう,綺麗に整形してくれるため,無駄なコンテクスト消費を抑えることができると考えました.アカウント登録等なしでAPIトークンを取得でき,すぐに試すことができます.

ワークフローの構成

実現したいワークフローの手順

しっかり深く調査したい+エージェントが調査を直列実行する遅さは避けたい,という想いから次のようなフローにしました.

  1. ユーザーの質問を理解
  2. 調査計画を作成 => 網羅性を担保
  3. 調査を並列に実行 => 調査の効率化
  4. 調査結果を統合
  5. 調査結果が十分であると判断した場合質問に回答,そうでなければ,再度step.2から調査を実行

並列調査の実現のため,作成したワークフローではユーザーとのやり取りのコンテクストを保持し,計画を行うオーケストレーターと,個別の調査を担うサブエージェントにフローを分割することを考えました.

並列調査の実装における問題点

n8nでの並列処理の難しさ

n8nは,デフォルトでワークフローを並列実行することができません.フローを分岐させても,上にあるフローから逐次実行されてしまいます.

↓下のフローが上のフローの実行完了を待っている様子
Screenshot 2026-02-16 at 15.57.29.png

並列でエージェントを動かしたかったので調べたところ,次のようなディスカッションを見つけました.ここによれば,webhookをワークフローのトリガーとして使うことで,ワークフローを並列実行できるとのことでした.

エージェントが同じ情報を拾ってしまう

また,サブエージェントはそれぞれ独立しているため,他のエージェントがどのようなことを調べているのか分かりません.これでは,サブエージェントが同じURLから同じような情報を抽出した場合,オーケストレーターに冗長な情報が渡ることになります.

そこで,n8nのDataTableを複数のサブエージェント間の共有メモリとして活用することで,他のサブエージェントがどのようなソースを調査したのかを把握できるようにします.

作成したワークフロー

作成したワークフローは,メインワークフロー(チャット画面でアクセスするところ)と4つのサブワークフローから構成されます.

agent_flow.png
↑n8nワークフローのJSONファイルからClaudeさんがdrawioで描いてくれました!

  • main(オーケストレーター):オーケストレーターは,質問に答えるための検索トピックをいくつか生成し,サブエージェントに仕事を投げます
  • 並列調査マネージャーサブエージェントの仕事を管理するフローです.オーケストレーターが生成したトピックごとにサブエージェントを配備し,調査させます.全てのサブエージェントの調査が終わるまで待機し,結果をオーケストレーターに返します
  • 検索エージェント(サブエージェント)並列調査マネージャーから指示されたトピックに対して,自律的に調査を行います.SearXNGを利用したキーワード検索の結果に基づいて,各種ツールに基づいた詳細調査を実行します
  • JINA_API_with_shared_DB:JINA APIを叩くためのラッパワークフローです.調べるURLをDBに書き込み,並列で動作している他のエージェントが同じソースを調べないようにガードします
  • searxng_search:SearXNGを呼び出し,余分な情報を取り除くためmarkdownへの整形を行います.これにより,コンテクスト・トークン消費の削減を試みます

並列調査マネージャーはコードノード一つで実装しています.
サブエージェントはwebhookへのPOSTリクエストを待ち受けているため,JavaScriptでPOSTリクエストを送るコードを記述することでサブエージェントに指示出しを行います.サブエージェントへのPOSTリクエストを非同期関数として定義し,Promise.all()することで,全てのエージェントを並列で実行しつつ,実行結果は一元的にまとめてオーケストレーターに返すというロジックを実装しました.

エージェント並列処理(並列調査マネージャー)の実装

↓大体Geminiさんが書いてくれました

const items = $input.all();
const input_json = items[0].json;

// 検索クエリ
const queries = input_json.search_queries;
const search_goals = input_json.search_goals;

if (queries.length !== search_goals.length) {
  // エラーもn8n形式で返すと扱いやすいです
  return [{
    json: { error: "The query length and goal length must be same" }
  }];
}

const search_topics = queries.map((q, i) => {
  return {
    search_goal: search_goals[i],
    search_query: q
  }
})

// ユーザーの質問
const context = input_json.user_query;
const fetch = require('node-fetch');

// 共有DBのID
const shared_db_id = input_json.shared_db_id

// サブエージェントを呼び出す非同期関数
const searchRequest =  async function(topic) {
  const url = 'http://localhost:5678/webhook/a839d203-3491-4ee5-9d78-325e98e9db26';
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ 
        search_topic: topic.search_query,
        search_goal: topic.search_goal,
        user_query: context,
        shared_db_id: shared_db_id
      })
    });
    
    if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
    const data = await response.json();
    
    return { 
      status: 'fulfilled', 
      search_topic: topic.search_query, 
      search_goal: topic.search_goal,
      data: data
    };
  } catch (error) {
    // エラーでも止まらないようにエラー情報を返す
    return { 
      status: 'rejected', 
      search_topic: topic.search_query, 
      search_goal: topic.search_goal,
      error: error.message 
    };
  }
};

// 全クエリを並列実行し、全ての結果が返るのを待つ
const promises = search_topics.map(t => searchRequest(t));
const results = await Promise.all(promises);

// 成功した結果だけをフィルタリングして返す
const successResults = results.filter(r => r.status === 'fulfilled').map((r) => {
  return {
    search_topic: r.search_topic,
    search_goal: r.search_goal,
    result: r.data.output
  }
});

return successResults

コードノードでfetchを使うには,docker-compose.yml
environment.NODE_FUNCTION_ALLOW_EXTERNAL=node-fetch
を設定する必要があります.

調査を試す

mainにアクセスすると,こんな画面でチャットができます.

dfe01705353ade3724014718dce1b6db.png

試しに,「今月中に東京都で開催されるクラシックコンサートを教えてください」と聞いてみました.ちなみに,実行したのは2026年2月16日です.

n8nで作った検索エージェントの回答
2026年2月後半(16日〜28日)に東京都内で開催される主なクラシックコンサートの情報をお伝えします。

今月後半は、巨匠エリア・インバル指揮によるマーラーの「一千人の交響曲」や、チョン・ミョンフン指揮の東京フィル、さらに世界最高峰ベルリン・フィルのメンバーによる室内楽など、非常に注目度の高い公演が予定されています。

2月後半の主要コンサート・スケジュール
日程	公演名・出演者	会場	プログラム(予定)
2/17(火)	東京都交響楽団<br>指揮:エリア・インバル	東京文化会館	マーラー:交響曲第8番「一千人の交響曲」
2/18(水)	東京フィルハーモニー交響楽団<br>指揮:チョン・ミョンフン、Vn:岡本誠司	サントリーホール	ブルッフ:Vn協奏曲第1番、マーラー:交響曲第5番 等
2/23(月祝)	読売日本交響楽団<br>(祝日マチネ)	サントリーホール	メンデルスゾーン:交響曲第1番、ウェーバー:Cl協奏曲第1番 等
2/23(月祝)	東京フィルハーモニー交響楽団<br>指揮:チョン・ミョンフン	Bunkamura オーチャードホール	メンデルスゾーン:交響曲第3番「スコットランド」 等
2/26(木)	ベルリン・フィル八重奏団<br>(来日公演)	サントリーホール	シューベルト:八重奏団 他
2/27(金)	新日本フィルハーモニー交響楽団<br>(クラシックの扉シリーズ)	すみだトリフォニーホール	チャイコフスキー:交響曲第6番「悲愴」、プロコフィエフ:Vn協奏曲第2番
2/27(金)・28(土)	NHK交響楽団<br>指揮:角田鋼亮	東京芸術劇場	すぎやまこういち:交響組曲「ドラゴンクエスト」
注目公演のポイント
東京都交響楽団(2/17): 指揮者インバルの得意とするマーラーの中でも、最大規模の編成を誇る「一千人の交響曲」が演奏されます。滅多に生で聴く機会のない大作です。
東京フィル(2/18, 23): 名誉音楽監督チョン・ミョンフンが登場。サントリーホールとオーチャードホールでプログラムが一部異なる場合がありますが、巨匠の情熱的なタクトが期待されます。
ベルリン・フィル八重奏団(2/26): 世界最強のオーケストラ、ベルリン・フィルの主要メンバーによるアンサンブルです。チケットは完売に近い可能性があります。
N響 ドラゴンクエスト(2/27-28): すぎやまこういちの名曲をN響の重厚なサウンドで楽しむ人気シリーズです。
ご案内
東京オペラシティ コンサートホールは、施設改修のため2026年2月末日まで休館となっており、今月中の公演予定はありません。
チケットの最新の販売状況については、各オーケストラの公式サイトまたはチケットぴあ等のプレイガイドをご確認ください。
参考文献 [1] サントリーホール 公演スケジュール 2026年2月 (suntory.co.jp) [2] 東京都交響楽団 コンサートスケジュール (tmso.or.jp) [3] 東京フィルハーモニー交響楽団 公演情報 (tpo.or.jp) [4] NHK交響楽団 公演情報 (nhkso.or.jp) [5] 東京オペラシティ 休館のお知らせ (operacity.jp)

無課金ChatGPTのweb search結果も貼ります.

無課金ChatGPTの回答
2026年**今月(2月)中に東京都で開催予定のクラシックコンサート**の主なイベントをまとめました(東京会場中心)。内容は一般に公開されているコンサート情報をもとにしています。([AllEvents][1])

### 🎻 2月開催のクラシックコンサート(東京都)

**🌟 2月5日(木)**

* **東京多元交響楽団 ニューイヤーコンサート**
  池袋・東京芸術劇場 コンサートホールにて開催。交響曲や映画音楽を交えた祝祭的なプログラムです。([Holiday Travel][2])

**🎻 2月10日(火)**

* **川井郁子 オーケストラ響 如月―情熱×雅 新日本フィルハーモニー交響楽団特別演奏会**
  すみだトリフォニーホールで開催されるクラシックコンサート。([AllEvents][1])

**🎶 2月13日(金)**

* **黒崎拓海 × 山田唯雄 ピアノ&ギター デュオリサイタル《音景と解像度》** – ヤマハ銀座店で開催。([AllEvents][1])

**🎻 2月14日(土)**

* **東京ユヴェントス・フィル 第29回定期演奏会** – すみだトリフォニーホール大ホール公演。([AllEvents][1])
* **アフタヌーン・コンサート(若手アーティストの演奏)** – 東京文化会館 小ホールで開催。([t-bunka.jp][3])

**🎼 2月15日(日)**

* **吉田あかねと素敵な仲間たち Vol.8** – カワイ表参道パウゼでのリサイタル。([AllEvents][1])

**🎻 2月17日(火)**

* **レイ・チェン 2つの「四季」** – 「四季」をテーマにしたコンサート がすみだトリフォニーホールで開催。([AllEvents][1])

**🎶 2月25日(水)**

* **チャリティーコンサートクラシック2026(東京交響楽団)** – 第一生命ホールでのオーケストラ公演(フルート協奏曲、交響曲など)。([東京交響楽団 TOKYO SYMPHONY ORCHESTRA -][4])

---

### ✨ 2月以降のクラシック関連情報(参考)

* **2月28日(土)** に ジョー・ヒサイシ(映画音楽等)のライブコンサートが **すみだトリフォニーホール** で予定されています(クラシック寄りプログラムを含む可能性あり)。([avanzert.com][5])

※前売りチケットの発売状況や会場の詳細は、それぞれの公式サイト・販売サイト(e+、チケットぴあ等)で確認することをおすすめします。

---

必要なら、**各コンサートのチケットリンクや詳細ページ**も探せるので、気になる公演を教えてください!(公演名や開催日など)

[1]: https://allevents.in/tokyo/classical-music?utm_source=chatgpt.com "Classical Music events in Tokyo, Today and Upcoming Classical Music events in Tokyo | TYO events"
[2]: https://www.haveagood-holiday.com/en/articles/tokyo-tagen-symphony-orchestra-new-year-concert-2026?utm_source=chatgpt.com "Tokyo Tagen Symphony Orchestra New Year Concert at Tokyo Metropolitan Theatre on February 5, 2026 - Holiday Travel"
[3]: https://www.t-bunka.jp/stage/29684/?utm_source=chatgpt.com "アフタヌーン・コンサート | 東京文化会館"
[4]: https://tokyosymphony.jp/concert/59384?utm_source=chatgpt.com "チャリティーコンサートクラシック2026 - 東京交響楽団 TOKYO SYMPHONY ORCHESTRA"
[5]: https://avanzert.com/concert/joe-hisaishi-sumida-triphony-hall-2026-02-28/?utm_source=chatgpt.com "Joe Hisaishi | Concert In Tokyo | Feb. 28, 2026"

両者を比較すると...

  • スピード:ChatGPTが数秒で完了し圧倒的に速い.検索エージェントは3分ほどかかる
  • 網羅性:検索エージェントは,今日(2月16日)以降の日付にあるコンサートをたくさん持ってきてくれている.一方,ChatGPTは日付の密度で言うとかなりスパースである
  • 情報の詳しさ:検索エージェントは各公演の曲目や指揮者の解説まで踏み込んでいる.ChatGPTは公演名・会場の列挙に留まる

顕在化した問題点

結局お金がかかる

ワークフロー作成中に何も考えずにAgentノードを回しまくってたので,作成期間だけで1,000円近く蒸発しました.

ee4d51b5cbf800b7efa9908cdeb01dd9.png
↑3日ほどで1,000円消費

もちろん,ちょこっと使うだけならそんなにかからないのですが,Perplexity Proが月額約1,400円(2026年2月16日現在)であることを考えると,Perplexity Proが破格に感じてきました.
やっぱり,何かしらAIサービスをサブスクしないとかな,思いました.

SearXNGが安定しない

サブエージェントがwebデータの取得を諦めてしまい,なんの成果もなしにマネージャーに報告するという事態が頻発しました.SearXNGのsettings.ymlを書き換えることで多少は改善しましたが,完全には直りませんでした.根本原因は特定できていないです.

今後の展望

  • 開発コストの削減:モックエージェント的なものを用意し,LLM APIを叩かずにフローの動作確認ができるようにしたい
  • 調査結果の記録:調査結果をスプレッドシートやNotionに自動で書き出す
  • 通知連携:調査が終わったらSlackやLINEに通知する
  • ローカルLLMの活用:コスト削減のためOllamaなどのローカルLLMとの組み合わせも検討

まとめと作った感想

今回,Perplexity Proのような検索エージェントが欲しかったのと,n8nを試したいということで,n8nを使った検索エージェントの構築を行いました.また,深い調査を効率的に実行できるよう,検索エージェントの並列実行を試してみました.

コスパ的にはPerplexity Proに劣る気はしますが,ワークフローの構築を通してn8nの便利さを体感することはできました!n8nの真価はGoogleやNotionのサービスとの連携を使ったワークフローの自動化にあると思うので,そちらも試してみたいです!

ここまでご覧いただきありがとうございました!

  1. https://github.com/n8n-io/n8n

  2. https://orbstack.dev/

  3. https://github.com/searxng/searxng/tree/master

  4. https://github.com/microsoft/playwright-mcp/tree/main

  5. https://jina.ai/reader/

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?