Regândirea căutării ca generare de cod
Evoluția căutării de la servicii monolitice la primitive programabile pentru era mediilor de execuție ale agenților.
Căutarea este o primitivă esențială pentru sistemele AI. Modelele de frontieră devin mai capabile de la o lună la alta, dar au în continuare nevoie de acces la cunoștințe proaspete, exacte și bine organizate din lumea exterioară. Căutarea este modalitatea principală prin care sistemele AI accesează aceste cunoștințe și, prin urmare, reprezintă o componentă fundamentală a oricărui produs care trebuie să tragă concluzii, să ia măsuri și să efectueze activități în lumea reală.
Considerăm că fluxurile de lucru tradiționale de căutare sunt din ce în ce mai depășite în era agenților. Căutarea tradițională oferă răspunsuri la interogări, dar agenții de astăzi finalizează sarcini care pot lua nenumărate forme. Aceste sarcini le cer agenților să definească strategii de regăsire specifice sarcinilor direct în cadrul mediilor lor de execuție (harnesses). În cadrul Perplexity Computer, am observat că o singură sarcină apelează sute sau chiar mii de operațiuni de regăsire în câteva minute: un flux de lucru care este imposibil pentru oameni, dar absolut natural pentru agenți.
În această lume, căutarea însăși trebuie să devină agentică, având componentele de bază accesibile direct ca SDK-uri în cadrul mediului de execuție al agentului. Introducem Search as Code (SaC) ca noua arhitectură de căutare de referință a Perplexity.
Introducere
Stiva de căutare Perplexity gestionează mii de interogări în fiecare secundă în cadrul aplicațiilor și al platformei noastre API. În septembrie 2025, am publicat prima prezentare generală a arhitecturii sistemelor noastre de căutare. Inovarea constantă din cadrul acestor sisteme a sprijinit lansarea de noi oferte, cum ar fi Search API, Agent API și Computer, buclele de auto-îmbunătățire optimizând stiva de căutare pentru a deservi mai bine utilizatorii pe zi ce trece.
În mod tradițional, sistemele AI au tratat căutarea ca pe un monolit: un model AI emite o interogare, motorul de căutare își rulează fluxul de lucru predefinit, iar modelul consumă rezultatele ca și context. În cea mai mare parte, acest lucru a funcționat bine pentru a răspunde nevoilor primilor utilizatori de AI. Având în vedere simplicitatea relativă a cererilor acestora, nu exista niciun motiv de îngrijorare cu privire la modul exact în care a fost proiectat fluxul de lucru de căutare sau dacă arhitectura acestuia era optimă pentru sarcina în cauză. S-a presupus că valorile implicite sunt suficient de bune, la fel ca și interfețele implicite (apelarea funcțiilor și MCP-urile).
Cu toate acestea, astăzi această abordare devine din ce în ce mai învechită pe măsură ce trece fiecare lună. Utilizatorii cer mult mai mult decât o analiză unică din partea AI. Ei se așteaptă ca agenții să ducă la bun sfârșit sarcini cap-coadă în decursul a ore sau chiar zile. Aceste sarcini pot fi complexe, deschise și extrem de variabile în ceea ce privește nevoile lor de informații, iar arhitecturile monolitice se prăbușesc sub greutatea acestor cerințe.
Blocajul cheie este, în cele din urmă, cel al controlului. Modelele de frontieră sunt deja destul de bune la raționamentul pe un context fix. Cu toate acestea, cele mai puternice sisteme AI vor necesita capacitatea de a dirija modul în care acest context este regăsit, procesat, agregat și redat modelului.
Sistemele de căutare tradiționale nu au fost concepute având în minte acest grad de controlabilitate. La urma urmei, nu ne putem aștepta ca utilizatorii umani să exercite un control detaliat asupra elementelor interne ale fluxului de lucru de căutare, chiar dacă acesta le-ar fi oferit. Modelele AI timpurii pot controla căutarea doar printr-o traiectorie liniară de apeluri de funcții și MCP-uri. Însă modelele de frontieră de astăzi, conduse de medii de execuție capabile de cod, pot exercita un control detaliat asupra oricăror primitive computaționale imaginabile prin intermediul codului de calculator. Sarcina noastră devine aceea de a oferi primitivele potrivite.
Pentru a satisface această nevoie, introducem o nouă arhitectură de căutare în toate produsele noastre: Search as Code (SaC). Această nouă arhitectură le permite modelelor să pătrundă în interiorul stivei de căutare în sine, în loc să se limiteze doar la consumul rezultatelor sale finale. Ideea de bază este simplă: expunem componentele stivei de căutare ca primitive în cadrul unui SDK. Pentru orice cerere care necesită căutare, un model asamblează aceste primitive la cerere într-un flux de lucru de regăsire adaptat la acea cerere specifică.
Asamblarea acestui flux de lucru se realizează prin generarea și execuția codului într-un sandbox securizat. Spre deosebire de alte abordări ale căutării bazate pe generarea de cod, noi nu ne limităm la a introduce pur și simplu un API de căutare tradițional într-un shell sau într-un runtime de limbaj. În schimb, am proiectat cu atenție un SDK de căutare agentică (Agentic Search SDK) care expune blocurile de construcție individuale ale căutării la cel maiatomic nivel posibil.
Înarmați cu aceste blocuri de construcție, SaC oferă modelelor control direct asupra fiecărui pas de căutare individual: regăsire, clasificare (ranking), filtrare, ramificare (fanouts), randare și multe altele. De asemenea, oferă modelului acces eficient la starea intermediară, cum ar fi listele de candidați și semnalele de clasificare. Împreună, aceste două pârghii de control și legibilitate le permit agenților să proiecteze fluxuri de lucru de căutare personalizate care să se întindă pe parcursul a mii de operațiuni de regăsire, să optimizeze acele fluxuri de lucru în timpul executării și să consume doar cele mai utile informații ca și context al modelului.
Acest articol descrie motivația, designul și implementarea SaC, alături de rezultatele empirice pe benchmark-uri existente și noi. SaC stabilește o nouă frontieră cost-performanță pentru căutarea agentică și suntem încântați să o împărtășim cu utilizatorii noștri și cu comunitatea AI mai largă.
Rigiditatea căutării tradiționale
Primele motoare de căutare din lume au fost construite pentru utilizatori umani. Acești utilizatori au ajuns să se aștepte la o experiență predictivă, constând de obicei dintr-un număr fix de documente clasificate în funcție de relevanță. Utilizatorii nu doreau să micro-gestioneze procesul de căutare; ei doreau să introducă o interogare și să găsească un rezultat util.
Ca urmare, motoarele de căutare orientate spre oameni au convergit spre o arhitectură monolitică comună, orientată spre producerea de pagini de rezultate ale motoarelor de căutare (SERP) prietenoase cu utilizatorul, care conțin primele n rezultate pentru o interogare de intrare. Acest model a susținut decenii de Progres în căutarea pentru consumatori. Este rapid, familiar și extrem de eficient pentru navigarea umană.
Apoi au apărut modelele lingvistice mari (LLM), iar sistemele AI au devenit, de asemenea, consumatoare de căutare. Perplexity a fost pionierul acestei schimbări odată cu lansarea motorului nostru de răspuns în 2022. De atunci, eforturile noastre de inginerie a căutării s-au concentrat pe modul de optimizare a valorii rezultatelor căutării pentru modelele AI. Pentru a construi cel mai precis și mai fiabil AI din lume, a trebuit să proiectăm un sistem de căutare concentrat pe transformarea fiecărui token într-un conținut cât mai dens în informații. Inovațiile rezultate în regăsirea la nivel de sub-document, eficiența contextului, înțelegerea semantică și alte domenii cheie au dus la îmbunătățiri dramatice ale capacității sistemelor AI de a regăsi informații și de a acționa pe baza acestora.
Cu toate acestea, chiar și sistemele optimizate pentru AI au moștenit în mare măsură același contract fundamental ca și motoarele de căutare tradiționale: acceptă o interogare, rulează un flux de lucru de căutare predefinit, returnează un set de rezultate complet procesat. Pentru cererile simple, această abordare funcționează bine. Dar pentru cererile mai complexe, aceasta devine un blocaj din ce în ce mai limitativ care degradează performanța, latența și costul.
Moduri de eșec datorate rigidității
Fluxurile de lucru de căutare tradiționale sunt proiectate în jurul unui singur punct de control: parametrii de interogare. Motorul de căutare deține restul fluxului de lucru conform logicii sale predefinite, iar modelul trebuie să se adapteze la aceasta. Pentru model, tot ceea ce se află în aval de parametrii de interogare este rigid – forma calculului efectiv se află în afara controlului modelului.
Aceasta este o limită rezonabilă atunci când consumatorul este un om care scanează linkuri. Este o limită slabă atunci când consumatorul este un model AI care încearcă să rezolve sarcini intensive în cunoștințe într-o buclă închisă. Din experiența noastră, această rigiditate creează trei moduri de eșec recurrente:
Context grosier. Modelele AI sunt sensibile la calitatea și compactitatea contextului. Atât calitatea, cât și compactitatea depind în mare măsură de interogare, iar fluxurile de lucru de căutare monolitice nu sunt proiectate să funcționeze optim pentru toate interogările. De exemplu, dacă un model are nevoie de o singură informație extrem de chirurgicală, dar are acces doar la un punct final (endpoint) de căutare cap-coadă care prioritizează rememorarea (recall), utilizarea acelui punct final va introduce o cantitate mare de informații irelevante în contextul modelului. Pe de altă parte, dacă un model are nevoie de multe bucăți de informație care necesită fiecare strategii de căutare diferite, el poate fi forțat să invoce în serie același flux de lucru sub-optim pentru toate, rezultând costuri în creștere și un context zgomotos.
Eșecul în valorificarea cunoștințelor de domeniu. În multe cazuri, modelul poate avea cunoștințe de domeniu (din antrenamentul său, o aptitudine de agent - Agent Skill, memorie sau tokenuri anterioare din traiectoria LLM) care ar trebui să ghideze strategia de căutare. Cu toate acestea, o interfață de căutare rigidă împiedică modelul să valorifice aceste cunoștințe. De exemplu, modelul poate realiza pentru o cerere specifică că ar trebui să îmbine semnalele lexicale și semantice într-un anumit mod, să acorde prioritate anumitor surse sau să agregeze rezultatele după o cheie specifică. Dacă acele perspective nu pot fi implementate prin intermediul parametrilor de interogare, modelul nu poate acționa efectiv pe baza lor.
Flux de control ineficient și poluare a contextului. Multe fluxuri de lucru de căutare nu sunt în mod natural seriale. Este posibil să aibă nevoie de ramificare (fan-out) pe variante de interogare, preluare în paralel, deduplicare și alte operațiuni care necesită un flux de control nelinear și asincron. Forțarea acestor pași prin intermediul unor ture repetate ale modelului adaugă latență și face ca fluxul de lucru să fie mai greu de optimizat. De asemenea, poluează contextul modelului cu o stare intermediară zgomotoasă care poate să nu fie utilă pentru raționamentul modelului, rezultând o performanță mai slabă și compactări mai frecvente.
Nu s-a putut face mare lucru în privința acestor provocări în epele apelării de funcții și ale MCP-urilor din AI. Atunci când fiecare operațiune de căutare necesită propria sa călătorie dus-întors (roundtrip) la inferența LLM, dezvoltatorii preferă în mod natural să ducă la bun sfârșit cât mai multe lucruri în acea călătorie dus-întors. Aceasta înseamnă fluxuri de lucru de căutare cap-coadă care returnează seturi de rezultate complet procesate pentru consumul direct de către un model.
Ca urmare, majoritatea sistemelor de căutare orientate spre AI operează și astăzi în cadrul acestui contract monolitic. Cu toate acestea, odată cu creșterea continuă a inteligenței modelelor și a cerințelor utilizatorilor, neajunsurile acestui contract devin mai pronunțate. Cele mai avansate sisteme AI de astăzi, construite pe baza unor medii de execuție axate pe cod (code-first harnesses), pot compune fluxuri de lucru specifice sarcinilor care execută mii de acțiuni în fiecare minut. Sistemele de căutare nu și-au valorificat încă pe deplin acest potențial.
Bănuim de mult timp că limita potrivită pentru căutarea nativă AI se află mai jos în stivă. Modelele nu ar trebui să se limiteze doar la a apela un motor de căutare. Ele ar trebui să poată orchestra piesele individuale ale stivei de căutare în funcție de cerințele specifice ale Sarcinii. Acest lucru necesită o arhitectură fundamental diferită.
Proiectarea unei arhitecturi de căutare programabile
Următoarea generație de arhitecturi de căutare va depinde de un principiu de bază: căutarea ar trebui să fie programabilă în mod nativ de către agenții AI. Un agent nu trebuie să fie limitat la un set de fluxuri de lucru de căutare predeterminate. Mai degrabă, un agent trebuie să poate construi fluxul de lucru pe care îl cere sarcina specifică, utilizând blocuri de construcție compozibile concepute la diferite niveluri de abstracție.
Noua noastră arhitectură Search as Code (SaC) întruchipează acest principiu. În SaC, nicio operațiune de regăsire nu este trimisă printr-o interfață de apelare de funcții sau MCP. În schimb, toate operațiunile sunt orchestrate prin intermediul codului Python generat de model. Pentru cele mai simple nevoi de căutare, acest cod poate consta dintr-un număr mic de cereri către un punct final de căutare de nivel superior. Însă pentru sarcini complexe, codul poate fi la fel de complex pe cât este necesar, implicând execuție condiționată, asincronicitate, paralelism și apeluri către o gamă largă de primitive de nivel inferior.
SaC implică trei straturi strâns cuplate:
Modelele servesc drept plan de control. Ele raționează cu privire la directiva utilizatorului (sau a agentului părinte), descompun directiva în sarcini, decid ce fluxuri de lucru de regăsire și procesare sunt necesare pentru fiecare sarcină și generează cod pentru a implementa acele fluxuri de lucru.
Sandbox-urile de calcul asigura calcul determinist printr-un mediu de execuție de cod securizat. Ele oferă o pânză pentru ca modelele să implementeze fluxul de control, procesarea în loturi (batching), reîncercările, filtrarea, unirea (joining), agregarea și alte operațiuni deterministe.
Agentic Search SDK-ul nostru expune stiva de căutare a Perplexity ca primitive compozibile. Acesta oferă blocuri de construcție, de la operațiuni de regăsire de nivel inferior până la parsare semantică de nivel superior. SDK-ul este încorporat în mediile de execuție ale sandbox-urilor, permițând modelelor să orchestreze până la mii de operațiuni într-o singură tură de inferență. Mai jos, discutăm deciziile noastre de proiectare pentru fiecare strat.
Agentic Search SDK
Agentic Search SDK definește blocurile de construcție pentru căutarea programabilă. Important de menționat este că SDK-ul nostru nu este un API de căutare preexistent ambalat ca bibliotecă. În ultimele luni, echipa noastră de ingineri și-a rearhitecturat stiva de căutare în primitive modulare și compozibile. Am construit Agentic Search SDK pentru a oferi acces direct la aceste primitive, creând o pânză mult mai puternică pe care modelul poate orchestra fluxuri de lucru de regăsire specifice sarcinilor.
Fluxurile de lucru de căutare de nivel superior, cap-coadă, sunt în continuare disponibile în cadrul SDK-ului, dar ele nu mai sunt singura opțiune. Mai degrabă, ele servesc drept o formă de prescurtare pentru modelele comune de căutare. Modelul este liber să le folosească sau să le ocolească în funcție de cerințele sarcinii.
Alegerea mediului de execuție (runtime): Am luat în considerare Python, Rust, TypeScript și Bash ca mediu de execuție pentru SDK. Am bănuit că Python va fi cea mai naturală potrivire, având în vedere omniprezența sa și ecosistemul de biblioteci de procesare a datelor. Testele interne au confirmat acest lucru, iar versiunea SDK-ului lansată astăzi este bazată pe Python. Ne așteptăm să reevaluăm periodic alegerea mediului de execuție pentru a ne asigura că acesta continuă să ofere cea mai bună experiență pentru agenți.
Îmbunătățire continuă prin auto-cercetare (autoresearch): De asemenea, am optimizat capacitatea de utilizare a SDK-ului pentru modelele lingvistice mari de frontieră (LLM) printr-o buclă iterativă de auto-cercetare. Această buclă, care rulează continuu timp de săptămâni, propune și validează îmbunătățiri aduse SDK-ului în raport cu valori precum latența, calitatea generării de cod și performanța generală a sarcinilor. Bucla de auto-cercetare a adus deja numeroase modificări atât structurii, cât și esteticii SDK-ului, cu câștiguri semnificative în toate dimensiunile. Planificăm să perfecționăm în continuare SDK-ul prin auto-cercetare pe măsură ce apar noi modele de frontieră și componente de căutare.
Sandbox-uri
Sandbox-urile oferă medii sigure pentru definirea și rularea fluxurilor de lucru SaC. Ele execută codul generat de model, oferind acces la Agentic Search SDK pentru a facilita interacțiunea cu primitivele de căutare individuale.
Am făcut investiții semnificative în optimizarea și securizarea sandbox-urilor noastre, iar designul general al sistemului lor merită un articol propriu. Aici ne concentrăm pe aspectul de proiectare cel mai relevant pentru SaC: gestionarea stărilor intermediare.
SaC le permite agenților să orchestreze fluxuri de lucru complexe într-o singură tură de inferență. Cu toate acestea, anumite stări intermediare trebuie transmise de la o tură la alta. De exemplu, un model poate dori să preia unele documente în tura 1, să inspecteze un subeșantion din acele documente în tura 2 pentru a decide ce să facă în continuare, iar apoi să dezvolte un flux de lucru de căutare în aval pentru a investiga în continuare acele documente începând cu tura 3. Așa cum s-a discutat mai sus, transmiterea stărilor intermediare prin spațiul de tokenuri nu este o strategie eficientă.
Am luat în considerare două abordări pentru gestionarea stărilor intermediare de la o tură la alta:
Sistem de fișiere persistent + serde explicit: Sandbox-urile pot expune sisteme de fișiere persistente pe care modelele le pot folosi între ture. Modelele care doresc să persiste starea intermediară pot include o etapă de serializare în cadrul codului generat pentru o tură, împreună cu o etapă de deserializare în cadrul unei ture subsecvente (fie pentru propria inspecție a modelelor, fie pentru utilizare în aval). Abordarea bazată pe sistemul de fișiere permite modelelor să controleze direct și explicit modul în care starea intermediară este transmisă între ture. De asemenea, asigură trasabilitatea prin impunerea identificării și persistenței explicite a informațiilor utilizate de model. Un dezavantaj îl reprezintă latența și consumul suplimentar de context generate de crearea codului serde, deși funcțiile utilitare bine concepute pot atenua acest cost.
REPL: Alternativ, un sandbox poate persista mediul de execuție în sine între ture într-un mediu de tip REPL. Acest lucru le permite modelelor să mențină starea intermediară în memorie fără a fi nevoie să o serializeze deloc, deoarece variabilele definite sau modificate în turele anterioare pot fi pur și simplu referite prin nume în turele subsecvente. Abordarea REPL este mai eficientă în ceea ce privește tokenurile, deoarece evită necesitatea de a genera cod serde. Cu toate acestea, lipsa unei etape explicite de serializare poate afecta performanța în aval din motive familiare oricărei persoane care a lucrat cu un notebook Jupyter cu 100 de celule: pe măsură ce spațiul de nume al variabilelor devine aglomerat, devine mai dificil de urmărit ce anume este persistat între ture și de ce.
Am testat ambele abordări și am constatat că, deși au o performanță similară în utilizarea obișnuită, serde-ul bazat pe sistemul de fișiere oferă o fiabilitate mai bună pe traiectorii deosebit de lungi. Prin urmare, adoptăm serde-ul bazat pe sistemul de fișiere ca soluție a noastră. Conjecturăm că a cere modelelor să transmită starea în mod declarativ, mai degrabă decât implicit, le ajută să gestioneze acea stare mai eficient. Aceasta este o concluzie provizorie și vom continua să iterăm asupra ambelor abordări.
Modele
Modelele care alimentează mediile de execuție ale agenților servesc drept plan de control al SaC: asamblează în mod dinamic fluxuri de lucru de căutare din blocurile de construcție ale Agentic Search SDK pentru a satisface nevoile fiecărei sarcini, transmițând apoi aceste fluxuri de lucru sub formă de cod pentru a fi executate în sandbox.
Perplexity folosește o varietate de modele în cadrul mediilor de execuție ale agenților noștri și am constatat că cele mai recente modele de frontieră sunt destul de eficiente în ansamblu în ceea ce privește generarea de cod cu scop general. Principala provocare este de a induce o generare eficientă de cod în mod specific pentru Agentic Search SDK. Adică, cum putem face ca modelele să împletească în mod eficient blocurile de construcție ale SDK-ului nostru în fluxuri de lucru optimizate pentru sarcini?
Spre deosebire de biblioteca standard a unui limbaj, un SDK personalizat nu va fi probabil reprezentat în datele de pre-antrenare. Chiar și cu îmbunătățirile aduse utilizabilității SDK-ului prin auto-cercetare, multe modele sunt încă antrenate să interacționeze cu sistemele de căutare prin apeluri de funcții și apelare directă MCP. Este puțin probabil ca aceste modele să mânuiască cu expertiză SDK-ul bazându-se doar pe codul sursă și pe documentele generate automat.
Pentru a rezolva această provocare, am dezvoltat aptitudini de agent extrem de optimizate (Agent Skills) pentru a învăța modelele să utilizeze eficient SDK-ul nostru. Versiunile inițiale au fost dezvoltate în conformitate cu principiile de proiectare ale Perplexity pentru Skills și apoi optimizate printr-o buclă dedicată de auto-cercetare concentrată pe aceleași valori utilizate în optimizarea SDK-ului. De asemenea, limităm dimensiunea aptitudinilor pentru a ne proteja împotriva umflarii contextului, iar versiunile noastre finale au mai puțin de 2000 de tokenuri în fișierele lor rădăcină SKILL.md.
Aptitudinile optimizate (Skills) merg dincolo de simpla listare a blocurilor de construcție disponibile în SDK (ceva ce poate fi obținut la fel de ușor prin reflexia runtime). Cea mai mare parte a tokenurilor este cheltuită oferind ghidaj concis, generalizabil și exemple puține (few-shot) pentru compunerea acestor blocuri în modele complexe. Înarmați cu aceste Skills, observăm cum modelele utilizează eficient SDK-ul pentru a orchestra fluxuri de lucru de căutare care se extind la mii de operațiuni discrete.
Codul ca orchestrator și umplutură de goluri
Combinând aceste straturi, SaC schimbă relația dintre modele și stiva de căutare. În sistemele de căutare cu flux de lucru fix, modelul se situează deasupra căutării și interacționează cu aceasta printr-o interfață îngustă de apelant în serie. În SaC, modelul devine un participant activ în orchestrarea procesului de căutare în sine. Toate elementele stivei de căutare devin direct programabile de către model, sandbox-ul și Agentic Search SDK oferind interfețele necesare către acele elemente.
Dar ce se întâmplă cu capabilitățile care nu există în mod nativ? Codul este un mediu puternic pentru orchestrarea capabilităților preexistente. Cu toate acestea, puterea codului merge dincolo de orchestrare. De asemenea, acesta poate servi drept umplutură de goluri pentru capabilitățile care nu sunt prezente în stiva de căutare sau în SDK. Agenții beneficiază de parsimonie și ar fi ineficient ca SDK-ul să acopere fiecare operațiune potențială cu o funcție dedicată. În schimb, SDK-ul oferă cele mai fundamentale primitive, iar modelul poate construi orice componente suplimentare din mers cu ajutorul codului.
Luați în considerare, de exemplu, o expresie regulată (regex) complexă care nu poate fi implementată eficient prin propriul limbaj de interogare al sistemului de căutare. Fără capabilități de codare, modelul ar fi forțat să genereze cea mai bună aproximare a sa, să efectueze o interogare și să realizeze o filtrare în spațiul de tokenuri pe un set de rezultate foarte zgomotos. Cu SaC, modelul poate genera în schimb un program care face apeluri SDK paralele pentru a colecta un supraset al setului de rezultate al regex-ului dorit. După deduplicare prin intermediul SDK-ului, modelul poate scrie apoi cod suplimentar pentru a restrânge în mod determinist rezultatele exact la regex. În acest fel, agenții pot implementa capabilități de căutare personalizate fără a umfla SDK-ul cu subrutine excesiv de nișate.
Studiu de caz: Recomandări ale furnizorilor pentru CVE
Prezentăm un studiu de caz bazat pe o sarcină din lumea reală din cadrul suitei noastre de testare. Această sarcină cere unui agent să identifice și să caracterizeze peste 200 de vulnerabilități (CVE) cu severitate ridicată din perioada 2023–2025. Fiecare înregistrare trebuie să citeze propria recomandare (advisory) a furnizorului afectat, să denumească produsul și versiunea de remediere și să arate că versiunea de remediere este legată de CVE-ul specific.
Răspunsul SaC a obținut un punctaj de 100% în ceea ce privește acuratețea, utilizarea totală a tokenurilor scăzând cu 85,1% față de linia de bază non-SaC (de la 288,7K tokenuri la 42,9K tokenuri). Sistemele testate care nu aparțin Perplexity, discutate mai detaliat în Secțiunea 4, au obținut toate un punctaj mai mic de 25%.
Prezentăm trei blocuri de cod stilizate din traiectorie pentru a ilustra modul în care programabilitatea SaC permite modelului să implementeze strategii eficiente.
# Part 1 of 3: fan out over official advisory formats.
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"])
]Acest primul bloc este pură orchestrare. Programul generat începe prin codificarea regulii clasei de surse direct în planul de interogare: doar formatele de recomandare aparținând furnizorilor sunt relevante. Sursele care nu aparțin furnizorilor, inclusiv NVD, MITRE, CVE Details, articole de știri, pagini CERT și baze de date ale terților, sunt în mod structural în afara scopului. Constrângerile de frază exactă împing, de asemenea, căutarea către pagini al căror text indexat conține deja detaliile CVE precise necesare în aval.
# Part 2 of 3: synthesize refinements for sparse vendor-years.
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,
)Cel de-al doilea bloc utilizează un LLM ca subrutină de planificare intermediară. Codul rezumă ce perechi furnizor-an produc suficiente pagini candidate, solicită rafinamente țintite și validează fiecare interogare propusă înainte de execuție. Acest lucru păstrează modele utile din traiectorie, cum ar fi sondajele cu frază exactă filtrate pe site și completarea adaptivă (adaptive backfilling), fără a codifica rigid un crawler de recomandări CVE personalizat în SDK.
# Part 3 of 3: verify CVE-to-version binding.
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")Blocul final este un verificator de rezultate a cărui logică este definită în întregime de agent prin intermediul generării de cod. În timp ce subrutinele de căutare pot găsi pagini de recomandare plauzibile, sarcina necesită o relație mai strictă: recomandarea trebuie să lege un CVE de un produs afectat și o versiune de remediere într-un text scris de furnizor. Schema face această relație explicită, astfel încât codul din aval poate face deduplicarea după CVE, poate respinge URL-urile de agregator, poate discerne dovezile slabe privind versiunile și poate continua completarea până când se atinge pragul minim al numărului de înregistrări.
Rezultatele evaluării
Evaluăm eficacitatea SaC pe o suită cuprinzătoare de benchmark-uri, concentrându-ne atât pe performanța absolută, cât și pe frontiera cost-performanță.
Benchmark-uri și sisteme
Suita noastră de benchmark-uri cuprinde cinci benchmark-uri în total, concepute pentru a testa riguros fluxurile de lucru AI dependente de căutare într-o gamă largă de domenii, formate de sarcini și niveluri de complexitate. Folosim patru benchmark-uri preexistente: DeepSearchQA (DSQA), BrowseComp, Humanity's Last Exam (HLE) și WideSearch. Pentru primele trei benchmark-uri (DSQA, BrowseComp și HLE), raportăm acuratețea ca metrică principală. Pentru WideSearch, raportăm scorul F1 pe rând.
De asemenea, folosim noul benchmark WANDR, care se concentrează pe sarcini dificile de „cercetare amplă” (wide research) care necesită o orchestrare atentă a căutării, calculului și raționamentului modelului. WANDR este inspirat de sarcinile profesionale intensive în cunoștințe pe care Perplexity Computer le gestionează pentru utilizatori. Acesta se bazează pe WideSearch și pe benchmark-uri similare, dar pune accent pe sarcini și structuri de sarcini mai complexe. Vom publica benchmark-ul WANDR în săptămânile următoare.
Evaluăm cinci sisteme bazate pe agenți. Luăm în considerare rulări individuale, mai degrabă decât scoruri „best-of-N”, pentru a izola performanța arhitecturii de bază, mai degrabă decât beneficiile paralelizării. Configurația fiecărui sistem este descrisă mai jos:
Perplexity (SaC): Evaluăm arhitectura SaC în cadrul API-ului Agent de producție al Perplexity. GPT 5.5 (raționament ridicat) servește drept model de bază.
OpenAI: Evaluăm API-ul OpenAI Responses cu atât căutarea (web_search), cât și mediul de execuție Python (code_interpreter) activate. GPT 5.5 (raționament ridicat) servește drept model de bază.
Anthropic: Evaluăm Anthropic Managed Agents cu setul de instrumente pentru agenți 20260401 și comenzi permise automat. Opus 4.7 (raționament ridicat) servește drept model de bază.
Exa: Evaluăm Exa Agent prin intermediul API-ului de producție, cu nivelul de efort setat la ridicat.
Parallel: Evaluăm Parallel Tasks prin intermediul API-ului de producție, cu procesorul setat la ultra4x.
Performanță comparativă
Tabelul 1 raportează scorurile benchmark pentru fiecare sistem. SaC depășește toate celelalte sisteme pe patru din cele cinci benchmark-uri. Pe benchmark-ul rămas (HLE), SaC este practic la egalitate pentru locul întâi cu OpenAI Responses. Figura 2 din Introducere vizualizează aceste scoruri sub formă grafică.
Benchmark | 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 |
Tabelul 1 | Scorurile benchmark pentru fiecare sistem evaluat. Cel mai bun scor pe rând este îngroșat.
Deși SaC obține o performanță de nivel superior (state-of-the-art) în cadrul suitei de benchmark-uri, avantajul său este deosebit de pronunțat pe WANDR. Figura 5 descompune scorurile WANDR, arătând că implementarea SaC a Perplexity depășește sistemul următor ca performanță cu un factor de 2,5×. În ciuda acestei marje mari, WANDR rămâne nesaturat și se dovedește a fi provocator chiar și pentru SaC. Credem că fluxurile de lucru de căutare complexe, puternic orizontale, cerute de sarcinile WANDR vor necesita progrese suplimentare în cercetare și inginerie a căutării pentru a obține o performanță constant ridicată.
În cele din urmă, măsurăm câștigurile relative ale SaC în comparație cu un flux de lucru de căutare mai tradițional care utilizează aceeași infrastructură de căutare Perplexity. Figura 6 raportează diferența de scoruri între arhitecturile SaC și non-SaC pe fiecare benchmark. Per total, SaC oferă un impuls substanțial în performanță, cu cel mai mare câștig absolut pe DSQA (+19,77 pp, 29%) și cel mai mare câștig relativ pe WANDR (+12,00 pp, 45%).
Frontiera cost-performanță
În practică, utilizatorii sunt interesați de performanță în raport cu costul. Prin urmare, evaluăm frontiera cost-performanță pe DSQA și WideSearch. Măsurăm costul și performanța SaC la niveluri de raționament ale modelului scăzut, mediu și ridicat, alături de celelalte sisteme. Figurile 7 și 8 reprezintă grafic scorul benchmark în funcție de prețul pe sarcină, cu axa x inversată, astfel încât punctele situate mai spre dreapta sunt mai ieftine, iar punctele mai sus reprezintă o performanță mai bună.
Pe DSQA, toate cele trei setări SaC se află pe frontiera superioară-dreaptă. Setarea de raționament scăzut este mai ieftină decât toate celelalte sisteme, având în același timp o performanță mai bună decât două dintre ele. Setarea de raționament mediu depășește toate sistemele non-SaC la un cost mai mic de 1 dolar pe sarcină. Setarea de raționament ridicat obține performanțe de top la un cost competitiv.
WideSearch arată o frontieră cu o formă similară. La fel ca în cazul DSQA, setarea de raționament scăzut obține o performanță competitivă la un cost mai mic decât toate sistemele non-SaC, în timp ce atât raționamentul mediu, cât și cel ridicat depășesc sistemele non-SaC în ceea ce privește performanța sarcinilor.
Spre o nouă arhitectură de calcul
Search as Code reflectă o schimbare mai amplă în designul software-ului. Timp de decenii, sistemele software au fost organizate în jurul unor instrucțiuni deterministe executate de medii de execuție tradiționale pe procesoare (CPU). Modelele de frontieră introduc o nouă formă de calcul: raționamentul în spațiul de tokenuri care poate atât să urmeze, cât și să genereze instrucțiuni. Cele mai capabile sisteme computaționale vor combina aceste două forme de calcul, în loc să aleagă între ele.
Căutarea este un teren de testare natural pentru această arhitectură hibridă. Modelele sunt bine echipate pentru a decide ce dovezi sunt necesare și cum ar trebui rezolvată incertitudinea. Mediile de execuție deterministe sunt bine adaptate pentru procesarea în loturi (batching), paralelism, filtrare, clasificare și agregare. Infrastructura de căutare servește drept un strat universal de I/O, oferind mediului de execuție puncte de acces utile la informațiile lumii care pot susține mii de operațiuni pe minut. Atunci când aceste piese sunt integrate, sistemul rezultat este mult mai puternic și mai eficient în realizarea sarcinilor din lumea reală.
Fiecare parte a acestei arhitecturi este necesară pentru a debloca aceste capabilități. Fără modele inteligente, sistemul nu poate raționa cu privire la strategia de căutare. Fără sandbox-uri, modelele sunt forțate la I/O serial și la o procesare ineficientă în spațiul de tokenuri. Și fără o stivă de căutare atomizată, modelul nu are ce să orchestreze. SaC funcționează deoarece raționamentul, calculul determinist și I/O sunt concepute în mod comun pentru a accentua punctele forte ale fiecărui strat.
Această co-proiectare poate fi dusă și mai departe prin dezvoltarea unor bucle de îmbunătățire continuă. De exemplu, Agentic Search SDK și aptitudinile SaC Agent Skills ar putea fi optimizate în comun într-o buclă comună de auto-cercetare. Mai ambițios, modelele pot fi antrenate să profite de primitivele de căutare de nivel inferior expuse ca SDK. S-ar putea chiar încerca co-evoluția designului SDK în timpul procesului de antrenare a modelului în sine. Așteptăm cu nerăbdare să urmăm strategii de co-proiectare mai agresive în lucrările viitoare.
Am construit SaC pentru a permite modelelor să controleze procesul de căutare, în loc să se limiteze doar la consumul rezultatelor sale. Rezultatele noastre dovedesc puterea acestui control: SaC avansează atât performanța absolută, cât și frontiera cost-performanță pe benchmark-urile de agenți intensive în cunoștințe. Suntem încântați să aducem capabilitățile SaC utilizatorilor noștri, începând de astăzi cu Perplexity Computer și Agent API. Vom continua să optimizăm arhitectura SaC pe toate straturile stivei pentru a ne asigura că utilizatorii noștri (și agenții care îi deservesc) dispun de cele mai puternice și eficiente capabilități de căutare posibile.
Citare
@online{perplexity2026RethinkingSearchAsCodeGeneration,
author = {{Perplexity} and Denis Bykov and Aleksandr Nikolenko and Artur Zayats and Maksim Gaiduk and Vitalii Polshkov and Akshay Nair and James Liounis and Kirill Priemko and Ryan Buchmayer and Phi Hoang and Jerry Ma},
title = {{Rethinking search as code generation}},
date = {2026-06-01},
url = {https://perplexity.coolkeypoint.com/hub/blog/rethinking-search-as-code-generation}
}