perplexity-migration-deep-dive
Provides strategies to replace legacy search APIs with the Perplexity Sonar engine.
Install
mkdir -p .claude/skills/perplexity-migration-deep-dive && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/5397" && unzip -o skill.zip -d .claude/skills/perplexity-migration-deep-dive && rm skill.zipInstalls to .claude/skills/perplexity-migration-deep-dive
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Migrate to Perplexity Sonar from other search/LLM APIs using the stranglerKey capabilities
- →Migrate from traditional search APIs to Perplexity Sonar
- →Replace multi-step search and LLM pipelines with a single API call
- →Implement a feature-flagged traffic split for gradual migration
- →Compare search results between old and new adapters
- →Simplify post-migration architecture to a single API step
How it works
The skill replaces traditional search APIs or legacy LLMs with Perplexity Sonar by building an adapter layer and using a feature-flagged traffic split for gradual migration. It compares results between the old and new systems to validate the migration.
Inputs & outputs
When to use perplexity-migration-deep-dive
- →Switching from Google Custom Search to Perplexity
- →Replacing multi-step LLM search pipelines
- →Re-platforming search infrastructure
- →Legacy search API sunsetting
About this skill
Perplexity Migration Deep Dive
Current State
!npm list openai 2>/dev/null | grep openai || echo 'N/A'
!grep -rn "google.*search\|bing.*api\|serpapi\|pplx-7b\|pplx-70b" --include="*.ts" --include="*.py" . 2>/dev/null | head -5 || echo 'No legacy search APIs found'
Overview
Migrate from traditional search APIs (Google Custom Search, Bing, SerpAPI) or legacy LLMs to Perplexity Sonar. Key advantage: Perplexity combines search + LLM summarization in a single API call, replacing a multi-step pipeline.
Migration Comparison
| Feature | Google CSE / Bing | Perplexity Sonar |
|---|---|---|
| Returns | Raw search results (links + snippets) | Synthesized answer + citations |
| Answer generation | Requires separate LLM call | Built-in |
| Citation handling | Manual extraction | Automatic citations array |
| Cost structure | Per-search ($5/1K queries) | Per-token + per-request |
| Recency filter | Date range parameters | search_recency_filter |
| Domain filter | Site restriction | search_domain_filter |
Instructions
Step 1: Assess Current Integration
set -euo pipefail
# Find existing search API usage
grep -rn "googleapis.*customsearch\|bing.*search\|serpapi\|serper\|tavily" \
--include="*.ts" --include="*.py" --include="*.js" \
. 2>/dev/null || echo "No search APIs found"
# Count integration points
grep -rln "search.*api\|customsearch\|bing.*web" \
--include="*.ts" --include="*.py" --include="*.js" \
. 2>/dev/null | wc -l
Step 2: Build Adapter Layer
// src/search/adapter.ts
export interface SearchResult {
answer: string;
citations: string[];
rawResults?: Array<{ title: string; url: string; snippet: string }>;
}
export interface SearchAdapter {
search(query: string, opts?: { recency?: string; domains?: string[] }): Promise<SearchResult>;
}
// Legacy adapter (existing Google/Bing implementation)
class GoogleSearchAdapter implements SearchAdapter {
async search(query: string): Promise<SearchResult> {
// Existing Google CSE code
const results = await googleCustomSearch(query);
return {
answer: "", // No built-in answer generation
citations: results.items.map((i: any) => i.link),
rawResults: results.items.map((i: any) => ({
title: i.title,
url: i.link,
snippet: i.snippet,
})),
};
}
}
// New Perplexity adapter
class PerplexitySearchAdapter implements SearchAdapter {
private client: OpenAI;
constructor() {
this.client = new OpenAI({
apiKey: process.env.PERPLEXITY_API_KEY!,
baseURL: "https://api.perplexity.ai",
});
}
async search(query: string, opts?: { recency?: string; domains?: string[] }): Promise<SearchResult> {
const response = await this.client.chat.completions.create({
model: "sonar",
messages: [{ role: "user", content: query }],
...(opts?.recency && { search_recency_filter: opts.recency }),
...(opts?.domains && { search_domain_filter: opts.domains }),
} as any);
return {
answer: response.choices[0].message.content || "",
citations: (response as any).citations || [],
rawResults: (response as any).search_results || [],
};
}
}
Step 3: Feature Flag Traffic Split
// src/search/factory.ts
function getSearchAdapter(): SearchAdapter {
const perplexityPercent = parseInt(process.env.PERPLEXITY_TRAFFIC_PERCENT || "0");
if (Math.random() * 100 < perplexityPercent) {
return new PerplexitySearchAdapter();
}
return new GoogleSearchAdapter();
}
// Migration schedule:
// Week 1: PERPLEXITY_TRAFFIC_PERCENT=10 (canary)
// Week 2: PERPLEXITY_TRAFFIC_PERCENT=50 (half traffic)
// Week 3: PERPLEXITY_TRAFFIC_PERCENT=100 (full migration)
// Week 4: Remove Google adapter code
Step 4: Validate Migration Quality
// Compare results between old and new adapter
async function compareSearchResults(query: string): Promise<{
perplexity: SearchResult;
google: SearchResult;
citationOverlap: number;
}> {
const [perplexity, google] = await Promise.all([
new PerplexitySearchAdapter().search(query),
new GoogleSearchAdapter().search(query),
]);
// Check citation overlap (shared domains)
const pplxDomains = new Set(perplexity.citations.map((u) => new URL(u).hostname));
const googleDomains = new Set(google.citations.map((u) => new URL(u).hostname));
const overlap = [...pplxDomains].filter((d) => googleDomains.has(d)).length;
return {
perplexity,
google,
citationOverlap: overlap / Math.max(pplxDomains.size, 1),
};
}
Step 5: Simplify Post-Migration
// Before migration: 3-step pipeline
// 1. Google Custom Search API → raw results
// 2. Send results to LLM for summarization
// 3. Extract citations manually
// After migration: 1-step
async function search(query: string): Promise<{ answer: string; sources: string[] }> {
const client = new OpenAI({
apiKey: process.env.PERPLEXITY_API_KEY!,
baseURL: "https://api.perplexity.ai",
});
const response = await client.chat.completions.create({
model: "sonar",
messages: [{ role: "user", content: query }],
});
return {
answer: response.choices[0].message.content || "",
sources: (response as any).citations || [],
};
}
Rollback Plan
set -euo pipefail
# Instant rollback: set traffic to 0%
# kubectl set env deployment/search-app PERPLEXITY_TRAFFIC_PERCENT=0
# The adapter layer keeps both implementations live until decommissioned
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Citation format differs | Google returns titles, Perplexity returns URLs | Normalize in adapter |
| No raw results | Perplexity returns synthesized answer | Use search_results field if available |
| Higher latency | Perplexity does search + synthesis | Expected; cache to compensate |
| Cost increase | Perplexity uses more tokens | Route simple queries to sonar, limit max_tokens |
Output
- Adapter layer abstracting search implementations
- Feature-flagged traffic split for gradual migration
- Quality comparison between old and new search
- Simplified single-API architecture post-migration
Resources
Next Steps
For advanced troubleshooting, see perplexity-advanced-troubleshooting.
When not to use it
- →When the existing search API already provides synthesized answers and citations
- →When the project does not use Google Custom Search, Bing, or SerpAPI
- →When not migrating from legacy pplx-api models
Limitations
- →Perplexity returns synthesized answers, while Google CSE/Bing return raw search results
- →Perplexity returns URLs for citations, while Google returns titles
- →Perplexity may have higher latency due to combining search and synthesis
How it compares
This skill replaces separate search and LLM calls with Perplexity's combined API, which differs from manually integrating multiple services for search and summarization.
Compared to similar skills
perplexity-migration-deep-dive side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| perplexity-migration-deep-dive (this skill) | 1 | 27d | Review | Intermediate |
| mcp-builder | 136 | 3mo | Review | Advanced |
| api-design-principles | 72 | 2mo | No flags | Intermediate |
| langchain-architecture | 8 | 2mo | Review | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by jeremylongshore
View all by jeremylongshore →You might also like
mcp-builder
anthropics
Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
api-design-principles
wshobson
Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.
langchain-architecture
wshobson
Design LLM applications using the LangChain framework with agents, memory, and tool integration patterns. Use when building LangChain applications, implementing AI agents, or creating complex LLM workflows.
nodejs-backend-patterns
wshobson
Build production-ready Node.js backend services with Express/Fastify, implementing middleware patterns, error handling, authentication, database integration, and API design best practices. Use when creating Node.js servers, REST APIs, GraphQL backends, or microservices architectures.
springboot-patterns
affaan-m
Spring Boot 架构模式、REST API 设计、分层服务、数据访问、缓存、异步处理和日志记录。适用于 Java Spring Boot 后端工作。
backend-architect
sickn33
Expert backend architect specializing in scalable API design, microservices architecture, and distributed systems. Masters REST/GraphQL/gRPC APIs, event-driven architectures, service mesh patterns, and modern backend frameworks. Handles service boundary definition, inter-service communication, resilience patterns, and observability. Use PROACTIVELY when creating new backend services or APIs.