検索をコード生成として再考する(25 分読了)
Perplexity は、エージェント時代における従来の検索パイプラインの限界を克服するため、検索機能を SDK として直接アクセス可能なコード生成(Search as Code)へと再定義する新アーキテクチャを発表した。
キーポイント
検索のパラダイムシフト:モノリスからエージェントへ
従来の AI システムが検索を単なるクエリ応答のモノリスとして扱っていたのに対し、複雑なタスクを実行する現代のエージェントには、タスク固有の取得戦略をハネス内で直接定義できる「アジェンティックな検索」が必要であると主張している。
Search as Code (SaC) の導入
Perplexity は新アーキテクチャとして「Search as Code」を発表し、検索の構成要素を SDK としてエージェントハネスに直接組み込めるようにすることで、人間には不可能な数百から数千回の取得操作を数分で実行可能にする。
Perplexity Computer の実証事例
Perplexity Computer における単一タスクで数分間にわたる数百〜数千回の検索操作が行われるケースが示され、従来のデフォルト設定や関数呼び出しの限界を超えた、高度なワークフローの実現が可能であることを裏付けている。
検索クエリの構造化と制約
生成されたプログラムは、ソースクラスルールを直接クエリプランに埋め込み、ベンダー所有のアドバイザリ形式のみを対象とし、NVD やニュース等非公式ソースを除外する。
正確なフレーズ制約による精度向上
検索結果が後続処理に必要な CVE 詳細情報を既に含んでいるページに絞り込むため、厳密なフレーズ制約が適用される。
LLM を中間計画サブルーチンとして活用
LLM を使用して、どのベンダー・年ペアに候補ページが不足しているかを分析し、ターゲットを絞ったクエリ改善案を生成・検証する中間ステップを導入しています。
ハードコーディングされたクローラーの回避
特定の CVE アドバイザリー用クローラーを SDK に組み込むのではなく、検索パターン(サイト限定の完全一致フレーズや適応的なバックフィル)を動的に保持・利用することで柔軟性を確保しています。
影響分析・編集コメントを表示
影響分析
この記事は、AI エージェント開発における検索機能の扱い方を根本から変える重要な転換点を示しており、従来の「クエリ→結果」モデルから「コードによる動的制御」モデルへの移行を促すものです。Perplexity が自社の技術スタックで実証したこのアプローチが業界標準となることで、複雑なタスク実行能力を持つ次世代 AI アプリケーションの設計思想に大きな影響を与えるでしょう。
編集コメント
検索機能を単なるツールではなく、エージェントの論理の一部としてコードで定義する「Search as Code」は、複雑なタスクを処理する次世代 AI エージェントの実現に向けた決定的な技術的転換点と言えます。Perplexity のこの発表は、開発者が検索ロジックをより柔軟に制御できる新しいパラダイムを示唆しています。
検索は AI システムの中核的なプリミティブです。最先端モデルは月を追うごとに能力を向上させていますが、依然として広大な世界からの新鮮で正確かつ精選された知識へのアクセスが必要です。検索は AI システムがその知識にアクセスする主要な手段であり、結論を導き出し、行動を起こし、現実世界の業務を実行する必要があるあらゆる製品の基盤コンポーネントです。
私たちは、エージェントの時代において従来の検索パイプラインがますます時代遅れになっていると考えています。従来の検索はクエリに応答しますが、現代のエージェントは無数の形を取りうるタスクを完了します。これらのタスクには、エージェントがそのハーン(枠組み)内で直接、タスク固有の取得戦略を定義することが必要です。Perplexity Computer においては、単一のタスクで数分以内に数百、あるいは数千もの取得操作が呼び出される様子を目撃しています。これは人間にとっては不可能なワークフローですが、エージェントにとっては全く自然なことです。
この世界において、検索自体もエージェント化されなければなりません。その構成要素は、エージェントのハーン内で直接 SDK としてアクセス可能でなければなりません。私たちは、Perplexity の新たな参照検索アーキテクチャとして Search as Code (SaC) を導入します。
イントロダクション
Perplexity の検索スタックは、アプリケーションおよび API プラットフォーム全体で毎秒数千件のクエリを処理しています。2025 年 9 月には、検索システムに関する最初の アーキテクチャ概要 を公開しました。これらのシステム内における絶え間ないイノベーションは、Search API、Agent API、そして Computer といった新サービスの立ち上げを支えており、自己改善ループが検索スタックを最適化し、日々ユーザーにより良いサービスを提供しています。
従来、AI システムは検索をモノリスとして扱ってきました:AI モデルがクエリを発行すると、検索エンジンが事前に定義されたパイプラインを実行し、モデルはその結果をコンテキストとして消費します。概ねこのアプローチは、初期の AI ユーザーのニーズに対応するのに十分機能していました。彼らの要求が比較的単純であったため、検索パイプラインがどのように設計されているか、あるいはそのアーキテクチャが現在のタスクに対して最適かどうかについて懸念する必要はありませんでした。デフォルトの設定やインターフェース(関数呼び出しおよび MCPs)も十分に良好であると見なされていました。

Expand
Figure 1 | 従来の検索アーキテクチャは、呼び出しを逐次的にモデル化する単一の固定システムを公開する一方、「Search as Code」は、エージェントが生成されたコードを通じて構成する原子化された検索プリミティブを公開します。
しかし今日、このアプローチは月を追うごとに時代遅れになりつつあります。ユーザーは AI からの単発的な分析よりもはるかに多くのものを求めています。彼らは、エージェントが数時間、あるいは数日にわたってタスクをエンドツーエンドで完了することを期待しています。これらのタスクは複雑で開かれたものであり、情報ニーズにおいて非常に多様性があります。そして、モノリス型のアーキテクチャはこれらの要求の重みに耐えかねて崩れ始めています。
究極的なボトルネックは、最終的には*制御*の問題です。フロンティアモデルはすでに固定されたコンテキストに対する推論においては非常に優れています。しかし、最も強力な AI システムには、そのコンテキストをどのように取得し、処理し、集約し、モデルにレンダリングするかを操る能力が求められるでしょう。
従来の検索システムは、この程度の制御可能性を意識して設計されていません。そもそも、仮に提供されたとしても、人間ユーザーが検索パイプラインの内部に対して微細な制御を行使できるとは期待できません。初期の AI モデルは、関数呼び出しと MCP の線形的な軌跡を通じてのみ検索を制御できます。しかし今日、コード実行可能なエージェント・ハーンズによって駆動されるフロンティアモデルは、コンピュータコードを通じて想像しうるあらゆる計算プリミティブに対して微細な制御を行使することができます。私たちの課題は、適切なプリミティブを提供することです。
このニーズに応えるため、私たちは製品全体にわたって新しい検索アーキテクチャを導入します:Search as Code (SaC) です。この新アーキテクチャは、モデルが検索スタックの最終出力を単に消費するのではなく、検索スタックそのものへ*入り込む*ことを可能にします。核となる考え方はシンプルです:検索スタックの構成要素を SDK 内のプリミティブとして公開します。検索が必要なリクエストに対して、モデルはその特定の要求に合わせて、これらのプリミティブをオンデマンドで組み合わせて検索パイプラインを構築します。
このパイプラインの構築は、安全なサンドボックス内でのコード生成と実行を通じて行われます。他のコード生成駆動型の検索アプローチとは異なり、私たちは単に従来の検索 API をシェルや言語ランタイム内に埋め込むわけではありません。代わりに、最も原子レベルで検索の個々のビルディングブロックを公開する「Agentic Search SDK」を慎重に設計・構築しました。

Expand
Figure 2 | Search as Code (SaC) advances the performance frontier of agentic search across a diverse suite of benchmarks.
Armed with these building blocks, SaC gives models direct control over each individual search step: retrieval, ranking, filtering, fanouts, rendering, and more. It also gives the model efficient access to intermediate state such as candidate lists and ranking signals. Together, these twin levers of control and legibility allow agents to design bespoke search pipelines spanning thousands of retrieval operations, optimize those pipelines in-flight, and consume only the most useful information as model context.
This article describes SaC's motivation, design, and implementation, alongside empirical results on both existing and new benchmarks. SaC establishes a new cost-performance frontier for agentic search, and we're excited to share it with our users and the broader AI community.
The Rigidity of Traditional Search
The world's first search engines were built for human users. These users came to expect a predictable experience, typically consisting of a fixed number of relevance-ranked documents. Users did not want to micromanage the search process; they wanted to enter a query and find a useful result.
その結果、人間向けの検索エンジンは、入力されたクエリに対する上位 n 件のヒットを含む、人間に親和性の高い検索エンジン結果ページ(SERPs)を生成することを目的とした、共通のモノリス型アーキテクチャへと収束しました。このパターンは、消費者向け検索における数十年にわたる進展を支えてきました。これは高速で、慣れ親しんだものであり、人間のブラウジングには非常に効果的です。
その後、大規模言語モデル(LLM)が登場し、AI システムもまた検索の消費者となりました。Perplexity は 2022 年に回答エンジン(answer engine)を立ち上げることで、この転換を先導しました。それ以来、当社の検索エンジニアリングの取り組みは、AI モデルに対する検索結果の価値をいかに最適化するかという点に焦点を当ててきました。世界で最も正確かつ信頼性の高い AI を構築するためには、各トークンが可能な限り情報密度の高いものとなるよう設計された検索システムを開発する必要がありました。その結果生じた サブドキュメント検索、コンテキスト効率、意味理解、およびその他の主要分野におけるイノベーションは、AI システムが情報を取得し、それに基づいて行動する能力を劇的に向上させました。
しかし、AI 最適化されたシステムでさえも、従来の検索エンジンと同じ基本的な契約をほぼそのまま継承しています:クエリを受け取り、事前に定義された検索パイプラインを実行し、完全に処理された結果セットを返す。単純な要求に対してはこのアプローチは問題なく機能します。しかし、より複雑な要求においては、これがパフォーマンス、レイテンシ、コストを低下させる、ますます制限的なボトルネックとなっています。

Expand
Figure 3 | Traditional search systems force agentic workflows to sequence search through model-visible turns. Models must repeatedly call the same search pipelines across different query parameters and introduce all results into model context.
Failure Modes from Rigidity
従来の検索パイプラインは、単一の制御ポイントであるクエリパラメータを中心に設計されています。検索エンジンは、その事前定義されたロジックに従ってパイプラインの残りを管理し、モデルはそれに適応する必要があります。モデルにとって、クエリパラメータ以降のすべての要素は硬直的です——実際の計算の形状はモデルの制御範囲外にあります。
これは、消費者がリンクをスキャンする人間である場合には合理的な境界線です。しかし、閉じたループ内で知識集約的なタスクを解決しようとする AI モデルが消費者である場合には、この境界線は不適切です。私たちの経験では、この硬直性が 3 つの反復的な失敗モードを生み出します:
- 文脈の粗さ。AI モデルは、文脈の質とコンパクトさに敏感です。両方の要素はクエリに強く依存しており、モノリス型の検索パイプラインはすべてのクエリで最適に動作するように設計されていません。例えば、モデルが単一の、極めて特化した情報断片を必要とするにもかかわらず、リコール(再現率)を優先するエンドツーエンドの検索エンドポイントしか利用できない場合、そのエンドポイントを使用すると、モデルの文脈に大量の無関係な情報が混入してしまいます。逆に、モデルがそれぞれ異なる検索戦略を必要とする多数の情報断片を必要とする場合、それらすべてに対して同じ非最適なパイプラインを逐次的に呼び出すことを余儀なくされ、コストが膨張し、ノイズの多い文脈が生じます。
- ドメイン知識の活用不足。多くの場合、モデルは(トレーニングやエージェントスキル、メモリ、または LLM 軌道内の先行トークンから得た)ドメイン知識を持っており、それが検索戦略を導くべきです。しかし、硬直的な検索インターフェースは、モデルがその知識を活用することを妨げます。例えば、モデルは特定のリクエストに対して、レキシカル(語彙的)とセマンティック(意味的)の信号を特定の組み合わせで融合させるべきだと認識したり、特定のソースを優先すべきだと判断したり、特定のキーで結果を集約すべきだと考えたりするかもしれません。これらの洞察がクエリパラメータを通じて実装可能である偶然に頼る限り、モデルは実際にそれらに基づいて行動することはできません。
- 非効率な制御フローと文脈の汚染。多くの検索ワークフローは本質的に逐次的ではありません。クエリのバリエーションに対するファンアウト(分岐)、並列フェッチ、重複排除など、非線形かつ非同期の制御フローを必要とする操作が含まれることがあります。これらのステップをモデルのターンを繰り返すことで強制すると、レイテンシが増加し、ワークフローの最適化が困難になります。また、モデルの推論に役立たない可能性のあるノイズの多い中間状態がモデルの文脈を汚染し、パフォーマンスの低下や頻繁な圧縮(コンパクション)を引き起こします。
関数呼び出し & MCP の時代には、これらの課題に対処できることはほとんどありませんでした。各検索操作が LLM 推論への別々のラウンドトリップを必要とする場合、開発者は自然と、そのラウンドトリップでできるだけ多くの処理を行おうとします。つまり、モデルが直接消費できるように完全に処理された結果セットを返すエンドツーエンドの検索パイプラインが採用されることになります。
その結果、現在の AI 対応検索システムの多くは依然としてこの単一構造の契約の下で動作しています。しかし、モデルの知能とユーザーの要求が継続的に成長するにつれて、その契約の欠点がより顕著になっています。コードファーストなハーンネスの上に構築された今日の最も高度な AI システムは、1 分間に数千ものアクションを実行するタスク固有のワークフローを構成できます。検索システムはまだこの可能性を十分に実現していません。
私たちは長らく、AI ネイティブ検索の適切な境界はスタックの下位にあると疑ってきました。モデルは単に検索エンジンを呼び出すべきではなく、特定のタスクの要求に応じて検索スタックの個々の部品をオーケストレーションできるべきです。それには根本的に異なるアーキテクチャが必要です。
プログラマブルな検索アーキテクチャの設計
次世代の検索アーキテクチャは、中核となる原則に依存します:検索は AI エージェントによってネイティブにプログラム可能であるべきです。エージェントは事前に定められた一連の検索パイプラインに制限されるべきではありません。むしろ、エージェントは異なる抽象度レベルで設計されたコンポーザブルなビルディングブロックを使用して、特定のタスクが必要とするパイプラインを構築できる必要があります。
私たちの新しい「Search as Code (SaC)」アーキテクチャはこの原則を体現しています。SaC では、関数呼び出しや MCP インターフェースを通じて検索操作が単一でも実行されることはありません。すべての操作は、モデルによって生成された Python コードによってオーケストレーションされます。最も単純な検索ニーズの場合、このコードは高レベルの検索エンドポイントへの数回のリクエストで構成され得ます。しかし複雑なタスクにおいては、条件付き実行、非同期処理、並列処理、および幅広い低レベルプリミティブへの呼び出しを伴う必要に応じて極めて複雑なものとなり得ます。

Expand
図 4 | Search as Code (SaC) アーキテクチャは、Perplexity の検索インフラストラクチャの上に位置するモデル、計算用サンドボックス、および Agentic Search SDK からなるスタックに依存しています。
SaC は3つの密接に結合されたレイヤーから構成されます:
- モデルは制御プレーンとして機能します。ユーザー(または親エージェント)の指示について推論を行い、その指示をタスクに分解し、各タスクに必要な検索および処理パイプラインを決定し、それらのパイプラインを実装するためのコードを生成します。
- 計算サンドボックスは、安全なコード実行ランタイムを通じて決定的な計算を提供します。モデルが制御フロー、バッチ処理、リトライ、フィルタリング、結合、集計、およびその他の決定的な操作を実装するためのキャンバスとして機能します。
- 私たちの Agentic Search SDK は、Perplexity の検索スタックを合成可能なプリミティブとして公開しています。低レベルの検索操作から高レベルの意味解析に至るまで、ビルディングブロックを提供します。この SDK はサンドボックスの実行ランタイム内に埋め込まれており、モデルが単一の推論ターン内で最大数千回の操作をオーケストレーションできるようにしています。以下では、各レイヤーに対する私たちの設計決定について議論します。
The Agentic Search SDK
Agentic Search SDK は、プログラム可能な検索のためのビルディングブロックを定義しています。重要な点として、当社の SDK は既存の検索 API をライブラリとしてパッケージ化したものではありません。過去数ヶ月にわたり、当社のエンジニアリングチームは検索スタックをモジュール化され、合成可能なプリミティブへと再設計しました。私たちは、モデルがタスク固有の検索パイプラインをオーケストレーションするための、より強力なキャンバスを提供するために Agentic Search SDK を構築し、これらのプリミティブへの直接アクセスを実現しています。
高レベルのエンドツーエンド検索パイプラインは SDK 内に引き続き利用可能ですが、もはや唯一の選択肢ではありません。むしろ、これらは一般的な検索パターンに対する略記法として機能しています。モデルはタスクの要件に応じて、これらの機能を利用したり迂回したりする自由があります。
ランタイムの選択: SDK のランタイムとして Python、Rust、TypeScript、Bash を検討しました。その汎用性とデータ処理ライブラリのエコシステムを考慮すると、Python が最も自然な選択肢であると推測していました。内部テストによりこの推測が裏付けられ、本日ロールアウトされる SDK のバージョンは Python ベースとなっています。引き続き最適なエージェント体験を提供し続けるよう、ランタイムの選択については定期的に再評価していく予定です。
自己研究による継続的改善: 最先端の大規模言語モデル(LLM)向けに SDK の利便性を高めるため、反復的な自己研究ループを最適化しました。このループは数週間にわたり継続的に実行され、レイテンシ、コード生成の品質、および全体的なタスクパフォーマンスなどの指標に基づいて SDK の改善案を提案し検証します。この自己研究ループにより、SDK の構造と外観の両方に多数の変更が加えられ、すべての次元で顕著な向上が見られました。新たな最先端モデルや検索コンポーネントが登場するにつれて、さらに自己研究を通じて SDK を洗練させていく計画です。
サンドボックス
サンドボックスは、SaC パイプラインを定義および実行するための安全な環境を提供します。ここではモデルが生成したコードを実行し、個々の検索プリミティブとの対話を促進するために Agentic Search SDK へのアクセス権限が付与されます。
私たちはサンドボックスの最適化と堅牢性の向上に多大な投資を行ってきました。その全体的なシステム設計自体を論じる記事にする価値があります。ここでは、SaC(Search as Code)に関連する最も重要な設計上の考慮事項、すなわち中間状態の管理に焦点を当てます。
SaC は、エージェントが単一の推論ターン内で複雑なパイプラインをオーケストレーションすることを可能にします。しかし、特定の中間状態はターン間を通じて伝達される必要があります。例えば、モデルは 1 つ目のターンでいくつかのドキュメントを取得し、2 つ目のターンでそれらのドキュメントの一部を検査して次の行動を決定し、3 つ目以降のターンからこれらのドキュメントをさらに調査するための下流の検索パイプラインを開発したいと考えるかもしれません。前述した通り、トークン空間を通じて中間状態を渡すことは効果的な戦略ではありません。
ターン間における中間状態の管理については、2 つのアプローチを検討しました:
永続ファイルシステムと明示的なシリアライズ/デシリアライゼーション (serde): サンドボックスは、モデルがターン間で使用できるように永続ファイルシステムを公開できます。中間状態を保持したいモデルは、生成されたコード内にシリアライズ処理を含め、その後のターンでデシリアライズ処理を含めることができます(これはモデル自身の確認のため、または下流の用途のために利用されます)。このファイルシステムのアプローチにより、モデルは中間状態がターン間でどのように伝達されるかを直接的かつ明示的に制御できます。また、モデルが使用する情報の明確な識別と永続化を強制することで、追跡可能性も確保されます。一方、欠点としては、serde コードの生成に伴うレイテンシとコンテキストオーバーヘッドが発生することですが、適切に設計されたユーティリティ関数によってこのオーバーヘッドは緩和できます。
REPL: あるいは、サンドボックスは REPL スタイルの環境において、実行ランタイム自体をターン間で永続化することも可能です。これにより、モデルは変数をシリアライズする必要なく、メモリ上に中間状態を保持できます。これは、以前のターンで定義または変更された変数を、後のターンで単に名前によって参照できるためです。REPL アプローチは、serde コードの生成が必要ないため、トークン効率的です。しかし、明示的なシリアライズステップがないことは、100 セルの Jupyter ノートブックを扱った経験がある人なら誰もが知っている理由により、下流のパフォーマンスに悪影響を及ぼす可能性があります:変数ネームスペースが混雑してくると、ターン間で何 precisely が保持され、なぜそれが保持されているのかを追跡することがより困難になります。
両方のアプローチをテストした結果、通常の用途では同様の性能を発揮しますが、特に長いトジェクト(trajectories)においてはファイルシステムベースの serde がより高い信頼性を示すことがわかりました。そのため、私たちはファイルシステムベースの serde を解決策として採用します。モデルが状態を暗黙的にではなく宣言的に伝えることを要求することで、状態管理がより効果的になるのではないかと推測しています。これは暫定的な知見であり、両方のアプローチについて引き続き改善を重ねていきます。
Models
エージェント・ハネス(agent harnesses)を支えるモデルは、SaC の制御平面として機能します。Agentic Search SDK のビルディングブロックから動的に検索パイプラインを組み立て、各タスクのニーズに応じた後、そのパイプラインをコードとしてサンドボックス実行のために配信します。
Perplexity ではエージェント・ハネス内で多様なモデルを採用しており、最新のフロンティア(frontier)モデルが汎用的なコード生成において全体的に非常に効果的であることを発見しました。主な課題は、Agentic Search SDK に特化した効果的なコード生成を誘発することです。つまり、どのようにしてモデルが SDK のビルディングブロックを効果的に織り交ぜ、タスク最適化されたパイプラインを構築させるかという点です。
言語の標準ライブラリとは異なり、カスタムビルドの SDK は事前学習データに反映される可能性は低いです。autoresearch による SDK の利用性向上があったとしても、多くのモデルはまだ関数呼び出しや直接 MCP(Model Context Protocol)呼び出しを通じて検索システムと対話するように訓練されています。これらのモデルがソースコードと自動生成されたドキュメントのみで SDK を熟練して操ることは unlikely です。
この課題を解決するために、モデルが SDK を効果的に活用できるよう教えるために、高度に調整されたエージェントスキルを開発しました。初期バージョンは Perplexity のスキル設計原則に従って開発され、SDK 最適化と同じ指標に焦点を当てた専用の自己研究ループを通じて最適化されました。また、コンテキストの肥大化を防ぐためスキルのサイズを制限しており、最終版の SKILL.md ファイルのルートには 2000 トークン未満しか含まれていません。
最適化されたスキルは、SDK の利用可能なビルディングブロックを列挙するだけにとどまりません(これはランタイムリフレクションによっても容易に取得できることです)。トークンの大部分は、これらのブロックを複雑なパターンに組み込むための簡潔で汎用性の高いガイダンスと、few-shot 例(数ショットの事例)を提供することに費やされています。これらのスキルを活用することで、モデルが SDK を効果的に利用し、数千もの個別操作にスケールする検索パイプラインをオーケストレーションできることを確認しています。
コードによるオーケストレーターおよびギャップフィラー
これらのレイヤーを組み合わせることで、SaC はモデルと検索スタックの関係性を変革します。固定パイプラインの検索システムでは、モデルは検索の上に位置し、狭いシリアル呼び出しインターフェースを通じてのみ検索と対話します。一方、SaC ではモデルが検索プロセス自体をオーケストレーションする能動的な参加者となります。検索スタックのすべての要素がモデルによって直接プログラム可能となり、サンドボックスとアジェンティック検索 SDK がこれらの要素に対する必要なインターフェースを提供します。
では、ネイティブに存在しない機能についてはどうでしょうか。コードは既存の機能を調整するための強力な媒体です。しかし、コードの力は調整を超えています。また、検索スタックや SDK に含まれていない機能に対するギャップフィラーとしても機能します。エージェントは簡素さから恩恵を受け、SDK がすべての潜在的な操作を専用の関数でカバーするのは非効率的です。代わりに、SDK は最も基本的なプリミティブを提供し、モデルはコードを使って任意の追加コンポーネントをその場で構築できます。
例えば、検索システムの独自のクエリ構文では効率的に実装できない複雑な正規表現を考えてみましょう。コーディング機能がない場合、モデルはその最良の近似値を生成してクエリを実行し、非常にノイズの多い結果セット上でトークン空間フィルタリングを行うことを余儀なくされます。SaC を用いれば、モデルは代わりにプログラムを生成し、SDK に対して並列呼び出しを行って目的の正規表現の結果セットのスーパーセットを収集できます。SDK で重複排除を行った後、モデルは追加のコードを書き込んで結果を決定論的に絞り込み、正確な正規表現に一致させることができます。このようにして、エージェントは SDK を過度にニッチなサブルーチンで肥大化させることなく、カスタム検索機能を実装できます。
ケーススタディ:CVE ベンダーアドバイザリ
私たちは、テストスイート内の実世界のタスクに基づいたケーススタディを紹介します。このタスクでは、エージェントに 2023 年から 2025 年にかけての深刻度が高い CVE(Common Vulnerabilities and Exposures)を 200 件以上特定し、その特徴を記述させることを求めています。各記録には、影響を受けたベンダー自身のアドバイザリへの言及、対象製品と修正バージョンの名前、そしてその修正バージョンが特定の CVE に紐付けられていることの示唆が含まれる必要があります。
SaC(Search as Code)の回答は精度で 100% を達成し、非 SaC ベースラインと比較して総トークン使用量が 85.1% 減少しました(288.7K トークンから 42.9K トークンへ)。セクション 4 でより詳細に議論されている、Perplexity 以外のシステムでテストされたものはすべて、25% を下回るスコアでした。
SaC のプログラム可能性がモデルに効果的な戦略を実装させる方法を説明するために、軌跡から 3 つの定型化されたコードブロックを紹介します。
templates = [
("Mozilla",
'site:mozilla.org/en-US/security/advisories/mfsa{year} '
'"CVE-{year}-" "Fixed in" "Impact high"'),
("Jenkins",
'site:jenkins.io/security/advisory/{year} '
'"CVE-{year}" "Severity" "High" "Fix"'),
("Chrome",
'site:chromereleases.googleblog.com/{year} '
'"High CVE-{year}" "Stable channel has been updated"'),
("Android",
'source.android.com/docs/security/bulletin/{year}-{month:02d}-01 '
'"High" "CVE-{year}"'),
...
]
queries = [
{"vendor": vendor, "query": pattern.format(year=year, month=month)}
for year in [2023, 2024, 2025]
for vendor, pattern in templates
for month in ([1] if "{month" not in pattern else range(1, 13))
]
seed_hits = sdk.search.web_many(queries, limit_per_query=8, concurrency=12)
pages = [
{"vendor": q["vendor"], "url": h.url, "text": join_result_fields(h)}
for q, hits in zip(queries, seed_hits)
for h in hits
if official_vendor_advisory(h.url, q["vendor"])
]
この最初のブロックは純粋なオーケストレーションです。生成されたプログラムは、ソースクラスのルールをクエリプランに直接エンコードすることから始まります:関連するのはベンダー所有のアドバイザリ形式のみです。NVD、MITRE、CVE Details、ニュース記事、CERT ページ、およびサードパーティデータベースを含む非ベンダーソースは構造的に範囲外です。完全一致フレーズ制約もまた、後段で必要な正確な CVE 詳細が既にインデックスされたテキストに含まれているページへと検索を誘導します。
coverage = summarize(pages, by=["vendor", "year", "url_kind"])
prompt = """
Goal: 230+ high or critical CVEs from official vendor advisories.
Avoid aggregators, CERTs, news, NVD, MITRE, and CVE databases.
Current coverage:
{coverage}
Suggest more site-scoped exact-phrase queries for sparse vendor-years.
Prefer per-advisory pages over archive or month-index pages.
Return JSON lines with vendor and query.
""".format(coverage=coverage)
raw = query_llm(prompt)
expanded_queries = [
row for row in parse_jsonl(raw)
if official_scope(row["query"]) and mentions_cve_year(row["query"])
]
expanded_hits = sdk.search.web_many(
unique(expanded_queries),
limit_per_query=8,
concurrency=12,
)
2 つ目のブロックでは、LLM を中間の計画サブルーチンとして使用します。このコードは、どのベンダーと年の組み合わせが十分な候補ページを生成しているかを要約し、ターゲットを絞った改良を求め、実行前に各提案されたクエリを検証します。これにより、SDK に個別に CVE 勧告用クローラーを組み込むことなく、サイトスコープの完全一致フレーズプローブや適応的なバックフィルなど、軌跡から得られる有用なパターンを保持できます。
all_hits = dedupe_by_url(flatten(seed_hits) + flatten(expanded_hits))
items = [
{"url": h.url, "vendor_hint": infer_vendor(h.url),
"text": join_result_fields(h)}
for h in all_hits
if official_vendor_advisory(h.url, infer_vendor(h.url))
]
verified = sdk.llm.extract_many(
items,
instruction=(
"ページが特定の修正バージョン、ビルド、パッチ、またはセキュリティレベルと高重大度または重大な CVE を関連付けている場合のみ、ベンダーの勧告を保持してください。"
),
schema={
"matches": bool,
"cve": str,
"vendor": str,
"product": str,
"fix_version": str,
"severity": str,
"source_url": str,
"evidence": str,
"version_bound_to_cve": bool,
"confidence": float,
},
)
records = [
to_cve_record(x) for x in verified
if x.matches and x.version_bound_to_cve
if high_or_critical(x.severity) and x.confidence > 0.75
]
records = dedupe_by(records, key="cve")
最終ブロックは結果検証器であり、そのロジックはエージェントによってコード生成(codegen)によって完全に定義されます。検索サブルーチンは妥当なアドバイザリページを見つけることができますが、このタスクにはより厳格な関係性が要求されます。つまり、vendor 製のテキストにおいて、1 つの CVE が 1 つの対象製品と 1 つの修正バージョンに紐付けられている必要があります。スキーマはこの関係を明示的に定義しているため、後続のコードは CVE ごとに重複排除を行い、アグリゲータの URL を拒否し、弱いバージョン証拠を破棄し、レコード数の下限が満たされるまでバックフィルリングを継続できます。
Evaluation Results
SaC の有効性を包括的なベンチマークスイートで評価します。ここでは絶対性能とコストパフォーマンスのフロンティアの両方に焦点を当てています。
Benchmarks and Systems
当社のベンチマークスイートは合計 5 つのベンチマークから構成されており、さまざまなドメイン、タスク形式、複雑度レベルにわたる検索依存型 AI ワークフローの負荷テストを目的として設計されています。4 つの既存ベンチマークを使用します:DeepSearchQA (DSQA)、BrowseComp、Humanity's Last Exam (HLE)、および WideSearch。最初の 3 つのベンチマーク(DSQA、BrowseComp、HLE)については、主要指標として精度(accuracy)を報告します。WideSearch については、行ごとの F1 スコアを報告します。
また、新たに開発された WANDR ベンチマークも使用します。このベンチマークは、検索・計算・モデル推論の慎重な調整を必要とする困難な「広範な研究」タスクに焦点を当てています。WANDR は、Perplexity Computer がユーザーのために処理する知識集約型の専門業務に触発されたものであり、WideSearch や類似ベンチマークを発展させたものですが、より複雑なタスクとタスク構造を強調しています。WANDR ベンチマークは今後の数週間で公開予定です。
5 つのエージェントベースシステムを評価します。並列化の利点ではなく基盤となるアーキテクチャ自体のパフォーマンスを明確に分離するため、「N 個の実行からの最良値」スコアではなく、個別の実行結果を対象とします。各システムの構成は以下の通りです。
Perplexity (SaC): Perplexity の本番環境 Agent API 内で SaC アーキテクチャを評価します。基盤となるモデルには GPT 5.5(高推論)を使用します。
OpenAI: OpenAI Responses API を評価し、検索 (web_search) と Python ランタイム (code_interpreter) の両方を有効化します。基盤となるモデルには GPT 5.5(高推論)を使用します。
Anthropic: Anthropic Managed Agents を評価し、20260401 エージェントツールセットと自動許可コマンドを使用します。基盤となるモデルには Opus 4.7(高推論)を使用します。
Exa: Exa Agent を本番 API を経由して評価し、努力レベルを「high」に設定します。
Parallel: Parallel Tasks を本番 API を経由して評価し、プロセッサを ultra4x に設定します。
比較的性能
表1は、各システムのベンチマークスコアを報告しています。SaC は5つのベンチマークのうち4つで他のすべてのシステムを上回っています。残りの1つのベンチマーク(HLE)では、SaC は OpenAI Responses とほぼ同率首位となっています。図2(導入部より)は、これらのスコアをグラフ形式で視覚化しています。
ベンチマーク
Perplexity (SaC)
OpenAI
Anthropic
Exa
Parallel
DSQA
0.871
0.733
0.815
0.530
0.810
BrowseComp
0.805
0.720
0.598
0.380
0.560
HLE
0.612
0.614
0.566
0.387
0.515
WideSearch
0.651
0.522
0.590
0.471
0.584
WANDR
0.386
0.130
0.152
0.057
0.126
表1 | 評価された各システムのベンチマークスコア。各行の最高スコアを太字で表示。
SaC はベンチマークスイート全体で最先端のパフォーマンスを達成していますが、その優位性は特に WANDR で顕著です。図5は WANDR のスコアを内訳しており、Perplexity による SaC の実装が次点のシステムを2.5倍上回っていることが示されています。この大きな差にもかかわらず、WANDR はまだ飽和しておらず、SaC にとっても依然として挑戦的な課題となっています。私たちは、WANDR のタスクが必要とする複雑で非常に水平方向に広がる検索ワークフローには、一貫して高いパフォーマンスを達成するために、研究および検索エンジニアリングにおけるさらなる進展が必要であると信じています。

展開
Figure 5 | 評価されたシステム全体における WANDR スコア。Perplexity Agent API は、次点のシステムを 2.5 倍上回っています。
最後に、SaC と同じ Perplexity 検索インフラを活用するより伝統的な検索パイプラインとの相対的な改善度を測定しました。Figure 6 は、各ベンチマークにおける SaC アーキテクチャと非 SaC アーキテクチャのスコア差を示しています。全体を通じて、SaC はパフォーマンスに大幅な向上をもたらしており、DSQA では絶対値で最大の改善(+19.77 ポイント、29%)、WANDR では相対値で最大の改善(+12.00 ポイント、45%)を記録しました。

Expand
Figure 6 | 各ベンチマークにおける Perplexity ベースラインと SaC のスコア比較。絶対値および相対値の差分を注記付きで表示。
コストパフォーマンスフロンティア
実際には、ユーザーはコストに対するパフォーマンスを重視します。そのため、DSQA と WideSearch においてコストパフォーマンスフロンティアを評価しました。SaC のコストとパフォーマンスを、低・中・高のモデル推論レベル別に測定し、他のシステムと比較しました。Figure 7 および Figure 8 は、ベンチマークスコアをタスクあたりの価格に対してプロットしたものであり、x 軸は逆転しており、右側に行くほど安価で、上に行くほどパフォーマンスが高いことを示しています。

Expand
Figure 7 | DSQA スコアとタスクあたりの価格。破線は SaC モデルの推論設定を結んでいます。
DSQA では、SaC のすべての 3 つの設定が右上のフロンティア上に位置しています。低推論設定は他のすべてのシステムよりも安価でありながら、2 つのシステムより優れたパフォーマンスを発揮します。中推論設定は、タスクあたり 1 ドル未満で非 SaC システムすべてを上回ります。高推論設定は、競争力のあるコストで最高レベルのパフォーマンスを達成しています。

Expand
Figure 8 | WideSearch スコアとタスクあたりの価格。破線は SaC モデルの推論設定を結んでいます。
WideSearch も同様の形状のフロンティアを示しています。DSQA と同様、低推論設定は非 SaC システムすべてよりも低いコストで競争力のあるパフォーマンスを達成し、中推論と高推論の両方がタスクパフォーマンスにおいて非 SaC システムを上回ります。
計算のための新たなアーキテクチャへ向けて
Search as Code は、ソフトウェア設計におけるより広範な変化を反映しています。過去数十年にわたり、ソフトウェアシステムは CPU の従来のランタイムで実行される決定論的指令を中心に構成されてきました。フロンティアモデルは、新しい計算の形態をもたらしました。それは、指令に従うだけでなく生成も行うトークン空間内での推論です。最も能力の高い計算システムは、これら 2 つの計算形態の間で選択するのではなく、両方を組み合わせたものになるでしょう。
検索はこのハイブリッドアーキテクチャのための自然な実証の場です。モデルは、どのような証拠が必要か、不確実性をどのように解決すべきかを決定するのに適しています。一方、決定的なランタイム(deterministic runtime)は、バッチ処理、並列化、フィルタリング、ランキング、集約に適しています。検索インフラはユニバーサルな I/O レイヤーとして機能し、実行環境に対して世界の情報への有用なハンドルを提供し、毎分数千回の操作を維持可能にします。これらの要素が統合されると、結果として得られるシステムは、現実世界のタスクを達成する上ではるかに強力かつ効率的になります。
このアーキテクチャのすべての部分が、これらの能力を引き出すために必要です。インテリジェントなモデルがなければ、システムは検索戦略について推論できません。サンドボックス(sandbox)がなければ、モデルは直列 I/O と非効率なトークン空間処理に強制されます。また、原子化された検索スタックがなければ、モデルは調整する対象を失います。SaC が機能するのは、推論、決定的計算、I/O が各層の強みを相互に強化するように共同設計されているからです。
このコードデザインは、継続的な改善ループの開発を通じてさらに深化させることができます。例えば、Agentic Search SDK と SaC Agent Skills は、共通の自己研究ループ(autoresearch loop)の中で共同最適化される可能性があります。より野心的には、モデルを訓練して、SDK として公開された低レベルの検索プリミティブを活用できるようにすることもできます。さらには、モデルのトレーニングプロセス自体で SDK の設計を共進化させる試みも考えられます。私たちは将来の研究において、より積極的なコードデザイン戦略を追求することを楽しみにしています。
SaC を構築した目的は、モデルが検索結果を単に消費するのではなく、検索プロセス自体を制御できるようにすることです。私たちの結果はこの制御の力を証明しており、SaC は知識集約型エージェントベンチマークにおいて絶対性能とコストパフォーマンスのフロンティアの両方を向上させました。今日から Perplexity Computer と Agent API を通じて、ユーザーに SaC の機能を展開できることを嬉しく思います。今後もスタックのすべての層にわたって SaC アーキテクチャを最適化し続け、ユーザー(および彼らにサービスを提供するエージェント)が可能な限り強力かつ効率的な検索機能を利用できるようにしていきます。
原文を表示
Search is a core primitive for AI systems. Frontier models grow more capable by the month, but they still need access to fresh, accurate, and well-curated knowledge from the wider world. Search is the primary way that AI systems tap into that knowledge, and thus a foundational component of any product that needs to draw conclusions, take actions, and perform real-world work.
We believe that traditional search pipelines are increasingly outdated in the era of agents. Traditional search answers queries, but today’s agents complete tasks that can take on countless shapes. These tasks require agents to define task-specific retrieval strategies directly within their harnesses. Within Perplexity Computer, we’ve seen single tasks invoke hundreds or even thousands of retrieval operations within a few minutes: a workflow that is impossible for humans but absolutely natural for agents.
In this world, search itself must become agentic, with its building blocks accessible directly as SDKs within the agent harness. We are introducing Search as Code (SaC) as Perplexity’s new reference search architecture.
Introduction
Perplexity's search stack serves thousands of queries each second across our applications and API Platform. In September 2025, we published the first architectural overview of our search systems. Constant innovation within these systems has supported the launch of new offerings such as Search API, Agent API, and Computer, with self-improvement loops optimizing the search stack to better serve users with each passing day.
Traditionally, AI systems have treated search as a monolith: an AI model issues a query, the search engine runs its predefined pipeline, and the model consumes the results as context. For the most part, this worked fine to address the needs of early AI users. Given the relative simplicity of their requests, there was no reason to worry about exactly how the search pipeline was designed, or whether the pipeline's architecture was optimal for the task at hand. The defaults were presumed to be good enough, as were the default interfaces (function calling and MCPs).

Expand
Figure 1 | Traditional search architectures expose a single fixed system that models call serially, while Search as Code exposes atomized search primitives that agents compose through generated code.
Yet today this approach grows more outdated with each passing month. Users demand much more than single-shot analysis from AI. They expect agents to complete tasks end-to-end over hours or even days. These tasks can be complex, open-ended, and highly variable in their information needs, and monolithic architectures are buckling under the weight of these demands.
The key bottleneck is ultimately one of *control.* Frontier models are already quite good at reasoning over fixed context. However, the most powerful AI systems will require the ability to steer *how* that context is retrieved, processed, aggregated, and rendered to the model.
Traditional search systems were not designed with this degree of controllability in mind. After all, human users cannot be expected to exercise fine-grained control over search pipeline internals even if it were offered. Early AI models can control search only through a linear trajectory of function calls and MCPs. But today's frontier models, driven by code-capable agent harnesses, can exert fine-grained control over any computational primitives imaginable through computer code. Our task becomes to provide the right primitives.
To meet this need, we are introducing a new search architecture across our products: Search as Code (SaC). This new architecture empowers models to reach *into* the search stack itself rather than merely consume its final outputs. The core idea is straightforward: we expose the components of the search stack as primitives within an SDK. For any request that needs search, a model assembles these primitives on-demand into a retrieval pipeline tailored to that specific request.
Assembling this pipeline is done through code generation and execution within a secure sandbox. Unlike other codegen-driven approaches to search, we do not simply stick a traditional search API within a shell or language runtime. Instead, we've carefully engineered an Agentic Search SDK that exposes the individual building blocks of search at the most atomic level possible.

Expand
Figure 2 | Search as Code (SaC) advances the performance frontier of agentic search across a diverse suite of benchmarks.
Armed with these building blocks, SaC gives models direct control over each individual search step: retrieval, ranking, filtering, fanouts, rendering, and more. It also gives the model efficient access to intermediate state such as candidate lists and ranking signals. Together, these twin levers of control and legibility allow agents to design bespoke search pipelines spanning thousands of retrieval operations, optimize those pipelines in-flight, and consume only the most useful information as model context.
This article describes SaC's motivation, design, and implementation, alongside empirical results on both existing and new benchmarks. SaC establishes a new cost-performance frontier for agentic search, and we're excited to share it with our users and the broader AI community.
The Rigidity of Traditional Search
The world's first search engines were built for human users. These users came to expect a predictable experience, typically consisting of a fixed number of relevance-ranked documents. Users did not want to micromanage the search process; they wanted to enter a query and find a useful result.
As a result, human-facing search engines converged on a common monolithic architecture, geared toward producing human-friendly search engine results pages (SERPs) containing the top n hits for an input query. This pattern has powered decades of progress in consumer search. It is fast, familiar, and highly effective for human browsing.
Then came LLMs, and AI systems also became consumers of search. Perplexity pioneered this shift with the launch of our answer engine in 2022. Since then, our search engineering efforts have focused on how to optimize the value of search results for AI models. To build the world's most accurate and reliable AI, we had to engineer a search system focused on making each token as information-dense as possible. The resulting innovations in sub-document retrieval, context efficiency, semantic understanding, and other key areas led to dramatic improvements in AI systems' ability to retrieve and act on information.
However, even AI-optimized systems have largely inherited the same fundamental contract as traditional search engines: accept a query, run a predefined search pipeline, return a fully processed resultset. For simple requests, this approach works fine. But for more complex requests, this becomes an increasingly limiting bottleneck that degrades performance, latency, and cost.

Expand
Figure 3 | Traditional search systems force agentic workflows to sequence search through model-visible turns. Models must repeatedly call the same search pipelines across different query parameters and introduce all results into model context.
Failure Modes from Rigidity
Traditional search pipelines are designed around a single point of control: the query parameters. The search engine owns the rest of the pipeline according to its predefined logic, and the model must adapt to it. To the model, anything downstream of the query parameters is rigid—the shape of the actual computation is outside the model's control.
This is a sensible boundary when the consumer is a human scanning links. It is a poor boundary when the consumer is an AI model trying to solve knowledge-intensive tasks in a closed loop. In our experience, this rigidity creates three recurring failure modes:
- Coarse context. AI models are sensitive to the quality and compactness of context. Both quality and compactness are highly query-dependent, and monolithic search pipelines are not designed to perform optimally across all queries. For instance, if a model needs a single, highly surgical piece of information but only has access to an end-to-end search endpoint that prioritizes recall, using that endpoint will introduce a large amount of irrelevant information into the model context. On the other hand, if a model needs many pieces of information that each require different search strategies, it may be forced to serially invoke the same suboptimal pipeline for all of them, resulting in ballooning costs and noisy context.
- Failure to leverage domain knowledge. In many cases, the model may have domain knowledge (from its training, an Agent Skill, memory, or earlier tokens in the LLM trajectory) that should guide the search strategy. However, a rigid search interface prevents the model from leveraging that knowledge. For instance, the model may realize for a specific request that it should blend lexical and semantic signals in a particular way, prioritize certain sources, or aggregate results by a specific key. Unless those insights happen to be implementable through query parameters, the model cannot actually act on them.
- Inefficient control flow and context pollution. Many search workflows are not naturally serial. They might need fan-out over query variants, parallel fetching, deduplication, and other operations that require nonlinear and asynchronous control flow. Forcing these steps through repeated model turns adds latency and makes the workflow harder to optimize. It also pollutes model context with noisy intermediate state that may not be useful for the model's reasoning, resulting in poorer performance and more frequent compactions.
Not much could be done about these challenges during the function calling & MCP eras of AI. When each search operation requires its own roundtrip to LLM inference, developers naturally prefer to get as much done in that roundtrip. This means end-to-end search pipelines that return fully processed resultsets for direct consumption by a model.
As a result, most AI-facing search systems today still operate under this monolithic contract. However, with continued growth in model intelligence and user demands, the shortcomings of that contract become more pronounced. Today's most advanced AI systems, built atop code-first harnesses, can compose task-specific workflows that execute thousands of actions each minute. Search systems have yet to fully realize this potential.
We've long suspected that the right boundary for AI-native search is lower in the stack. Models should not merely call a search engine. They should be able to orchestrate the individual pieces of the search stack as the specific task demands. That requires a fundamentally different architecture.
Designing a Programmable Search Architecture
The next generation of search architectures will hinge on a core principle: search should be natively programmable by AI agents. An agent must not be limited to a set of preordained search pipelines. Rather, an agent must be able to construct the pipeline that the specific task requires, using composable building blocks designed at varying levels of abstraction.
Our new Search as Code (SaC) architecture embodies this principle. In SaC, not a single retrieval operation is dispatched through a function calling or MCP interface. All operations are instead orchestrated via model-generated Python code. For the simplest search needs, this code may consist of a handful of requests to a high-level search endpoint. But for complex tasks, the code can be as intricate as needed, involving conditional execution, asynchrony, parallelism, and calls to a wide range of low-level primitives.

Expand
Figure 4 | The Search as Code (SaC) architecture relies on a stack comprising models, compute sandboxes, and an Agentic Search SDK sitting atop Perplexity's search infrastructure.
SaC involves three tightly coupled layers:
- Models serve as the control plane. They reason about the user's (or parent agent's) directive, decompose the directive into tasks, decide which retrieval and processing pipelines are needed for each task, and generate code to implement those pipelines.
- Compute sandboxes provide deterministic compute through a secure code execution runtime. They provide a canvas for models to implement control flow, batching, retries, filtering, joining, aggregation, and other deterministic operations.
- Our Agentic Search SDK exposes Perplexity's search stack as composable primitives. It provides building blocks from low-level retrieval operations to high-level semantic parsing. The SDK is embedded within the sandboxes' execution runtimes, allowing models to orchestrate up to thousands of operations within a single inference turn. Below, we discuss our design decisions for each layer.
The Agentic Search SDK
The Agentic Search SDK defines the building blocks for programmable search. Importantly, our SDK is not a preexisting search API packaged as a library. Over the past few months, our engineering team has rearchitected our search stack into modular, composable primitives. We've built the Agentic Search SDK to provide direct access to these primitives, making for a much more powerful canvas on which the model can orchestrate task-specific retrieval pipelines.
High-level, end-to-end search pipelines are still available within the SDK, but they are no longer the only option. Rather, they serve as a form of shorthand for common search patterns. The model is free to use or bypass them as the task demands.
Choice of runtime: We considered Python, Rust, TypeScript, and Bash as the SDK runtime. We suspected that Python would be the most natural fit given its ubiquity and ecosystem of data processing libraries. Internal testing confirmed this to be the case, and the version of the SDK being rolled out today is Python-based. We expect to periodically reevaluate the choice of runtime to ensure that it continues to provide the best agent experience.
Continual improvement via autoresearch: We have also optimized the SDK's consumability for frontier LLMs through an iterative autoresearch loop. This loop, running continuously over weeks, proposes and validates SDK improvements against metrics including latency, codegen quality, and overall task performance. The autoresearch loop has already made numerous changes to both the structure and aesthetics of the SDK, with significant gains across all dimensions. We plan to further refine the SDK via autoresearch as new frontier models and search components emerge.
Sandboxes
Sandboxes provide secure environments for defining and running SaC pipelines. They execute model-generated code, providing access to the Agentic Search SDK to facilitate interaction with individual search primitives.
We've made significant investments in optimizing and hardening our sandboxes, and their overarching system design merits an article of its own. Here, we focus on the design consideration most relevant to SaC: managing intermediate states.
SaC empowers agents to orchestrate complex pipelines within a single inference turn. However, certain intermediate states need to be conveyed across turns. For instance, a model may want to fetch some documents in turn 1, inspect a subsample of those documents in turn 2 to decide what to do next, and then develop a downstream search pipeline to further investigate those documents from turn 3 onwards. As discussed above, passing intermediate states through token space is not an effective strategy.
We considered two approaches for managing intermediate states across turns:
Persistent filesystem + explicit serde: Sandboxes can expose persistent filesystems for models to use across turns. Models wishing to persist intermediate state can include a serialization step within the generated code for a turn, along with a deserialization step within a subsequent turn (either for the models' own inspection or for downstream use). The filesystem approach allows models to directly and explicitly control how intermediate state is conveyed across turns. It also ensures traceability by enforcing explicit identification and persistence of information used by the model. One downside is the latency & context overhead incurred from generating the serde code, though well-designed utility functions can mitigate this overhead.
REPL: Alternatively, a sandbox can persist the execution runtime itself across turns in a REPL-style environment. This allows models to maintain intermediate state in-memory without having to serialize it at all, since variables defined or modified in previous turns can simply be referenced by name in subsequent turns. The REPL approach is more token-efficient since it avoids the need to generate serde code. However, the lack of an explicit serialization step may hurt downstream performance for reasons familiar to anyone who's worked with a 100-cell Jupyter notebook: as the variable namespace becomes cluttered, it becomes more difficult to keep track of what precisely is persisted across turns and why.
We tested both approaches and found that while they perform similarly in ordinary use, filesystem-based serde provides better reliability on particularly long trajectories. We therefore adopt filesystem-based serde as our solution. We conjecture that requiring models to convey state declaratively rather than implicitly helps them manage that state more effectively. This is a tentative finding and we will continue to iterate on both approaches.
Models
The models powering agent harnesses serve as SaC's control plane: dynamically assembling search pipelines from the Agentic Search SDK's building blocks to meet the needs of each task, then dispatching those pipelines as code for sandbox execution.
Perplexity employs a variety of models within our agent harnesses, and we've found the latest frontier models to be quite effective across the board at general-purpose code generation. The main challenge is to induce effective code generation specifically for the Agentic Search SDK. That is, how can we make models effectively weave together our SDK's building blocks into task-optimized pipelines?
Unlike a language's standard library, a custom-built SDK is unlikely to be represented in pretraining data. Even with the SDK consumability improvements from autoresearch, many models are still trained to interact with search systems through function calls and direct MCP invocation. These models are unlikely to expertly wield the SDK with source code and autogenerated docs alone.
To solve this challenge, we've developed highly-tuned Agent Skills to teach models to effectively harness our SDK. The initial versions were developed according to Perplexity's design principles for Skills, and then optimized through a dedicated autoresearch loop focused on the same metrics used in SDK optimization. We also constrain skill size to guard against context bloat, and our final versions have fewer than 2000 tokens in their root SKILL.md files.
The optimized Skills go beyond listing the SDK's available building blocks (something that can just as easily be obtained via runtime reflection). The bulk of the tokens are spent providing concise, generalizable guidance and few-shot examples for composing these blocks into complex patterns. Armed with these Skills, we observe models effectively leverage the SDK to orchestrate search pipelines that scale to thousands of discrete operations.
Code as Orchestrator and Gap Filler
By combining these layers, SaC changes the relationship between models and the search stack. In fixed-pipeline search systems, the model sits above search and interacts with it through a narrow serial caller interface. In SaC, the model becomes an active participant in orchestrating the search process itself. All elements of the search stack become directly programmable by the model, with the sandbox and Agentic Search SDK providing the necessary interfaces to those elements.
But what about capabilities that don't exist natively? Code is a powerful medium for orchestrating preexisting capabilities. Yet code's power goes beyond orchestration. It can also serve as a gap-filler for capabilities that aren't present in the search stack or SDK. Agents benefit from parsimony, and it would be inefficient for the SDK to cover every potential operation with a dedicated function. Instead, the SDK provides the most fundamental primitives, and the model can build any additional components on the fly with code.
Consider, for instance, a complex regex that is not efficiently implementable via the search system's own query syntax. Without coding capabilities, the model would be forced to generate its best approximation, make a query, and perform token-space filtering on a very noisy resultset. With SaC, the model can instead generate a program that makes parallel SDK calls to collect a superset of the desired regex's resultset. After deduping via the SDK, the model can then write additional code to deterministically narrow the results to the exact regex. In this way, agents can implement custom search capabilities without bloating the SDK with overly niche subroutines.
Case Study: CVE Vendor Advisories
We present a case study based on a real-world task within our testing suite. This task asks an agent to identify and characterize over 200 high-severity CVEs from 2023–2025. Each record must cite the affected vendor's own advisory, name the product and fix version, and show that the fix version is tied to the specific CVE.
SaC's answer scored 100% on accuracy, with total token usage dropping 85.1% relative to the non-SaC baseline (from 288.7K tokens to 42.9K tokens). The tested non-Perplexity systems, discussed in more detail in Section 4, all scored lower than 25%.
We present three stylized code blocks from the trajectory to illustrate how SaC's programmability allows the model to implement effective strategies.
templates = [
("Mozilla",
'site:mozilla.org/en-US/security/advisories/mfsa{year} '
'"CVE-{year}-" "Fixed in" "Impact high"'),
("Jenkins",
'site:jenkins.io/security/advisory/{year} '
'"CVE-{year}" "Severity" "High" "Fix"'),
("Chrome",
'site:chromereleases.googleblog.com/{year} '
'"High CVE-{year}" "Stable channel has been updated"'),
("Android",
'source.android.com/docs/security/bulletin/{year}-{month:02d}-01 '
'"High" "CVE-{year}"'),
...
]
queries = [
{"vendor": vendor, "query": pattern.format(year=year, month=month)}
for year in [2023, 2024, 2025]
for vendor, pattern in templates
for month in ([1] if "{month" not in pattern else range(1, 13))
]
seed_hits = sdk.search.web_many(queries, limit_per_query=8, concurrency=12)
pages = [
{"vendor": q["vendor"], "url": h.url, "text": join_result_fields(h)}
for q, hits in zip(queries, seed_hits)
for h in hits
if official_vendor_advisory(h.url, q["vendor"])
]This first block is pure orchestration. The generated program starts by encoding the source-class rule directly into the query plan: only vendor-owned advisory formats are relevant. Non-vendor sources including NVD, MITRE, CVE Details, news stories, CERT pages, and third-party databases are structurally out of scope. The exact-phrase constraints also push search toward pages whose indexed text already contains the precise CVE details needed downstream.
coverage = summarize(pages, by=["vendor", "year", "url_kind"])
prompt = """
Goal: 230+ high or critical CVEs from official vendor advisories.
Avoid aggregators, CERTs, news, NVD, MITRE, and CVE databases.
Current coverage:
{coverage}
Suggest more site-scoped exact-phrase queries for sparse vendor-years.
Prefer per-advisory pages over archive or month-index pages.
Return JSON lines with vendor and query.
""".format(coverage=coverage)
raw = query_llm(prompt)
expanded_queries = [
row for row in parse_jsonl(raw)
if official_scope(row["query"]) and mentions_cve_year(row["query"])
]
expanded_hits = sdk.search.web_many(
unique(expanded_queries),
limit_per_query=8,
concurrency=12,
)The second block uses an LLM as an intermediate planning subroutine. The code summarizes which vendor-year pairs are producing enough candidate pages, asks for targeted refinements, and validates each proposed query before execution. This preserves useful patterns from the trajectory, such as site-scoped exact-phrase probes and adaptive backfilling, without hardcoding a bespoke CVE-advisory crawler into the SDK.
all_hits = dedupe_by_url(flatten(seed_hits) + flatten(expanded_hits))
items = [
{"url": h.url, "vendor_hint": infer_vendor(h.url),
"text": join_result_fields(h)}
for h in all_hits
if official_vendor_advisory(h.url, infer_vendor(h.url))
]
verified = sdk.llm.extract_many(
items,
instruction=(
"Keep only vendor advisories where the page ties a high or critical "
"CVE to a specific fixed version, build, patch, or security level."
),
schema={
"matches": bool,
"cve": str,
"vendor": str,
"product": str,
"fix_version": str,
"severity": str,
"source_url": str,
"evidence": str,
"version_bound_to_cve": bool,
"confidence": float,
},
)
records = [
to_cve_record(x) for x in verified
if x.matches and x.version_bound_to_cve
if high_or_critical(x.severity) and x.confidence > 0.75
]
records = dedupe_by(records, key="cve")The final block is a result verifier whose logic is entirely defined by the agent via codegen. While search subroutines can find plausible advisory pages, the task requires a stricter relation: the advisory must bind one CVE to one affected product and one fix version in vendor-authored text. The schema makes that relation explicit, so downstream code can dedupe by CVE, reject aggregator URLs, discard weak version evidence, and continue backfilling until the record-count floor is met.
Evaluation Results
We evaluate SaC's effectiveness on a comprehensive benchmark suite, focusing on both absolute performance and the cost-performance frontier.
Benchmarks and Systems
Our benchmark suite comprises five benchmarks in total, designed to stress test search-dependent AI workflows across a range of domains, task formats, and complexity levels. We use four preexisting benchmarks: DeepSearchQA (DSQA), BrowseComp, Humanity's Last Exam (HLE), and WideSearch. For the first three benchmarks (DSQA, BrowseComp, and HLE), we report accuracy as the topline metric. For WideSearch, we report F1 score by row.
We also use the newly-developed WANDR benchmark, which focuses on difficult “wide research” tasks requiring careful orchestration of search, compute, and model reasoning. WANDR is inspired by the knowledge-intensive professional tasks that Perplexity Computer handles for users. It iterates on WideSearch and similar benchmarks, but emphasizes more complex tasks and task structures. We will publish the WANDR benchmark in the coming weeks.
We evaluate five agent-based systems. We consider individual runs rather than “best-of-N” scores in order to isolate the performance of the underlying architecture rather than the benefits of parallelization. Each system's configuration is described below:
Perplexity (SaC): We evaluate the SaC architecture within Perplexity's production Agent API. GPT 5.5 (high reasoning) serves as the underlying model.
OpenAI: We evaluate the OpenAI Responses API with both search (web_search) and Python runtime (code_interpreter) enabled. GPT 5.5 (high reasoning) serves as the underlying model.
Anthropic: We evaluate Anthropic Managed Agents with the 20260401 agent toolset and auto-allowed commands. Opus 4.7 (high reasoning) serves as the underlying model.
Exa: We evaluate Exa Agent via the production API, with effort set to high.
Parallel: We evaluate Parallel Tasks via the production API, with the processor set to ultra4x.
Comparative Performance
Table 1 reports benchmark scores for each system. SaC outperforms all other systems on four of the five benchmarks. On the remaining benchmark (HLE), SaC is essentially tied for first place with OpenAI Responses. Figure 2 from the Introduction visualizes these scores in graphical form.
Table 1 | Benchmark scores for each evaluated system. Best score per row in bold.
Although SaC achieves state-of-the-art performance across the benchmark suite, its advantage is particularly pronounced on WANDR. Figure 5 breaks down the WANDR scores, showing that Perplexity's SaC implementation outperforms the next-best system by a factor of 2.5×. Despite this large margin, WANDR remains unsaturated and proves challenging even for SaC. We believe the complex, highly horizontal search workflows required by WANDR's tasks will require additional advances in research and search engineering to achieve consistently high performance.

Expand
Figure 5 | WANDR scores across evaluated systems. Perplexity Agent API leads the next-best system by a factor of 2.5×.
Finally, we measure the relative gains of SaC versus a more traditional search pipeline that leverages the same Perplexity search infrastructure. Figure 6 reports the difference in scores between the SaC and non-SaC architectures across each benchmark. Across the board, SaC provides a substantial boost in performance, with the largest absolute gain on DSQA (+19.77 pp, 29%) and the largest relative gain on WANDR (+12.00 pp, 45%).

Expand
Figure 6 | Perplexity baseline vs. SaC score on each benchmark, with absolute and relative deltas annotated.
Cost-Performance Frontier
In practice, users care about performance relative to cost. We therefore evaluate the cost-performance frontier on DSQA and WideSearch. We measure the cost and performance of SaC across low, medium, and high model reasoning levels, alongside the other systems. Figures 7 and 8 plot benchmark score against per-task price, with the x-axis reversed so points farther right are cheaper and points higher represent better performance.

Expand
Figure 7 | DSQA score versus per-task price. The dashed line connects the SaC model reasoning configurations.
On DSQA, all three SaC settings lie on the upper-right frontier. The low reasoning setting is cheaper than all other systems while performing better than two of them. The medium reasoning setting outperforms all non-SaC systems at under $1 per task. The high reasoning setting achieves top performance with a competitive cost.

Expand
Figure 8 | WideSearch score versus per-task price. The dashed line connects the SaC model reasoning configurations.
WideSearch shows a similarly shaped frontier. As with DSQA, the low reasoning setting achieves competitive performance at lower cost than all non-SaC systems, while both medium and high reasoning outperform non-SaC systems in task performance.
Toward a New Architecture of Computing
Search as Code reflects a broader change in software design. For decades, software systems were organized around deterministic instructions executed by traditional runtimes on CPUs. Frontier models introduce a new form of compute: token-space reasoning that can both follow and generate instructions. The most capable computational systems will combine these two forms of compute rather than choosing between them.
Search is a natural proving ground for this hybrid architecture. Models are well-suited to deciding what evidence is needed and how uncertainty should be resolved. Deterministic runtimes are well-suited to batching, parallelism, filtering, ranking, and aggregation. Search infrastructure serves as a universal I/O layer, providing the runtime with useful handles into the world's information that can sustain thousands of operations per minute. When these pieces are integrated, the resulting system is much more powerful and efficient in accomplishing real-world tasks.
Every part of this architecture is necessary to unlock these capabilities. Without intelligent models, the system cannot reason over search strategy. Without sandboxes, models are forced into serial I/O and inefficient token-space processing. And without an atomized search stack, the model has nothing to orchestrate. SaC works because reasoning, deterministic compute, and I/O are jointly designed to accentuate each layer's strengths.
This codesign can be taken even further through the development of continual improvement loops. For instance, the Agentic Search SDK and SaC Agent Skills could be jointly optimized in a common autoresearch loop. More ambitiously, models can be trained to take advantage of low-level search primitives exposed as an SDK. One might even try coevolving SDK design during the model training process itself. We look forward to pursuing more aggressive codesign strategies in future work.
We built SaC to allow models to control the search process, rather than merely consume its results. Our results prove the power of this control: SaC advances both absolute performance and the cost-performance frontier on knowledge-intensive agent benchmarks. We're excited to bring SaC's capabilities to our users, starting today with Perplexity Computer and Agent API. We will continue to optimize the SaC architecture across all layers of the stack to ensure our users (and the agents serving them) have the most powerful and efficient search capabilities possible.
関連記事
LangSmith ベンチマークの共有について
LangChain が開発した LangSmith のベンチマーク結果を公開し、AI アプリケーションの評価基準に関する情報を提供しました。
2026 年に LLM エンジニアになるためのロードマップ
KDnuggets が、2026 年までに大規模言語モデルエンジニアとして活躍するための学習経路と必要なスキルを提示した。
Google Cloud、AI エージェントに構造化された文脈を提供するベンダー中立の Markdown 仕様「Open Knowledge Format(OKF)」を発表
Google Cloud は、LLM の知識不足という課題に対処するため、表スキーマやメトリック定義などを整理した形式を標準化するオープン仕様の「Open Knowledge Format(OKF)」を発表しました。これにより、AI エージェントが散在する情報を統合的に活用できるようになります。
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み