Recreate Perplexity Search With LangFlow

guide2026-06-0215 min read

Build a Perplexity-like search system by separating URL discovery, page reading, evidence ranking, answer generation, and citation validation.

langflowperplexitysearchcitations

Summary

This note records how I approached a Perplexity-style search replica in LangFlow. The working shape is not one magic “web search” node; it is a pipeline that plans searches, calls a search provider, filters and reranks results, opens selected URLs, chunks evidence, asks an LLM to answer from labeled sources, and checks whether the answer cites known chunks. The implementation is deliberately modular. Search-only, search-with-content, Sonar-style answering, agent tool calls, and crawler debugging are separate flows or subflows. That made the system easier to test and kept failures local. All URLs, flow IDs, and service domains below are public-safe examples. The real deployment uses private LangFlow and search endpoints with API keys kept outside the note.

What This Solves

Perplexity feels useful because it combines several behaviors:
  • It searches the live web instead of only using model memory.
  • It opens and reads selected pages.
  • It ranks evidence before answering.
  • It returns citations tied to sources.
  • It can expose different API shapes: search-only, chat-style answer, and agent-style tool traces.
The implementation goal was to reproduce that product workflow in LangFlow with inspectable components. The realistic target is a self-controlled Perplexity-like answer engine, not a perfect clone of Perplexity’s proprietary index, ranking system, or freshness signals.
The most important design decision was to split discovery from reading: search providers find candidate URLs, while crawler components read the content of those URLs.

Who This Is For

This is for a future self or teammate who wants to understand how the Perplexity-like LangFlow search system is assembled and how to improve it. It assumes the reader has:
  • A LangFlow server with API access.
  • A search provider such as SearXNG, Brave Search, Serper, Google Programmable Search, or Exa.
  • A crawler or page reader such as an Onyx-style crawler, Firecrawl, Exa content retrieval, or Playwright.
  • An LLM node for the final grounded answer.
  • A way to test flows through the LangFlow playground or REST API.

Prerequisites

  • LangFlow reachable through a local or remote base URL.
  • A LangFlow API key stored as $LANGFLOW_API_KEY.
  • A main Sonar-style flow stored as $FLOW_ID.
  • Optional project MCP endpoint stored as $PROJECT_ID.
  • A search service that can return JSON search results.
  • curl and jq for command-line testing.
Example shell setup:
export LANGFLOW_BASE_URL="https://langflow.example.com"
export LANGFLOW_API_KEY="set-this-in-your-shell"
export FLOW_ID="replace-with-main-flow-id"
Do not publish real LangFlow domains, search domains, API keys, flow IDs, or project IDs. Use example.com, $LANGFLOW_API_KEY, $FLOW_ID, and $PROJECT_ID in public notes.

The Workflow

1

Define the Perplexity-like surfaces

I split the product into three API-shaped flows:
  • Search API: returns structured search results.
  • Sonar-style API: searches, reads pages, and answers with citations.
  • Agent Web Search API: lets an agent call web_search and open_url tools and preserve a step trace.
This makes the system easier to debug because search-only failures, crawler failures, and answer-generation failures are separate.
2

Build the shared search core

The shared search core accepts a query plus optional controls such as domain filters, max_results, language, recency, and source preferences.The search provider should return normalized records:
{
  "title": "Example documentation page",
  "url": "https://docs.example.com/page",
  "snippet": "Short search result text",
  "date": null,
  "last_updated": null
}
At this stage, the flow should not generate an answer. It should only find candidate pages and keep enough metadata for later ranking.
3

Plan searches before calling the provider

A planner node can turn one user question into better search inputs. For example:
Compare Firecrawl, Exa, and SearXNG for a LangFlow web search agent.
can become targeted queries for official documentation, GitHub repositories, and recent comparison pages. The planner can also infer domain allowlists when the user asks for official sources.The planner should return structured JSON instead of prose:
{
  "queries": [
    "Firecrawl documentation LLM web scraping markdown",
    "Exa API neural search documentation",
    "SearXNG documentation metasearch API"
  ],
  "domain_allowlist": [
    "docs.firecrawl.dev",
    "docs.exa.ai",
    "docs.searxng.org",
    "github.com"
  ],
  "max_results_per_query": 5
}
4

Filter and rerank before opening URLs

Search results are candidates, not evidence. Before crawling pages, the flow deduplicates URLs, applies allow or deny filters, boosts official docs and GitHub sources, and keeps only a small set of URLs to open.The current MVP uses rule-based scoring. A stronger version should add embeddings, a reranker model, or LLM listwise ranking.A simple first score can combine:
final_score =
  search_provider_rank_score
  + official_domain_bonus
  + docs_or_github_bonus
  + freshness_bonus
  - deny_domain_penalty
  - duplicate_penalty
5

Read pages with a crawler layer

The crawler is responsible for page content, not discovery. Its job is:
  • Validate URLs and block unsafe internal targets.
  • Fetch HTML or PDF content.
  • Clean HTML into readable text.
  • Extract PDF text when needed.
  • Use Playwright fallback for JavaScript-heavy pages when appropriate.
  • Return success or failure metadata per URL.
The crawler output should include scrape_successful and failure_reason, so bad pages do not silently poison the answer context.A useful crawler result shape is:
{
  "url": "https://docs.example.com/page",
  "title": "Example Docs",
  "content_type": "text/html",
  "text": "Clean page text for evidence extraction...",
  "scrape_successful": true,
  "failure_reason": null
}
6

Chunk evidence and assign source IDs

After reading pages, the flow converts content into source chunks. Each source and chunk receives a stable citation identifier such as [1.1], [1.2], or [2.1].Example context:
Source [1]
Title: Firecrawl Docs
URL: https://docs.example.com/firecrawl

Chunk [1.1]
Firecrawl converts web pages into LLM-ready markdown...
This gives the LLM something concrete to cite.
7

Keep the LLM answer node separate

The final answer should be generated by a separate LLM node that receives only labeled evidence, not raw unbounded web pages.The answer prompt should require:
  • Answer only from provided source chunks.
  • Use chunk IDs for citations.
  • Admit insufficient evidence when the chunks do not support a claim.
  • Avoid citing URLs that are not in the source map.
8

Validate citations after generation

The response formatter extracts detected citations, detected URLs, and warning messages.A healthy output shape is:
{
  "answer": "SearXNG is useful for self-hosted recall, while Firecrawl is useful for page extraction [1.1][2.1].",
  "detected_chunk_citations": ["1.1", "2.1"],
  "detected_urls": [],
  "citation_warnings": []
}
Citation validation is what makes the system more Perplexity-like than a generic web-connected chatbot.The validator should check three things:
  • Every citation ID exists in the source map.
  • The answer does not cite raw URLs that were never opened.
  • The answer warns when claims are not grounded in the retrieved chunks.
9

Test through LangFlow API

Run the main flow from the terminal:
curl --compressed -sS \
  -H "x-api-key: $LANGFLOW_API_KEY" \
  -H "content-type: application/json" \
  -X POST \
  --data '{
    "input_value": "Compare Firecrawl, Exa, and SearXNG for a LangFlow web search agent",
    "input_type": "chat",
    "output_type": "chat"
  }' \
  "$LANGFLOW_BASE_URL/api/v1/run/$FLOW_ID"
The first check is not whether the prose is beautiful. The first check is whether the response contains an answer, source URLs, chunk citations, and no unexplained citation warnings.

Implementation Shape

The full system can be understood as this pipeline:
User question
-> Search planner
-> Search provider
-> Result normalizer
-> Domain and recency filters
-> Deduplication and reranking
-> URL selector
-> Crawler / open_url
-> Source map
-> Chunk builder
-> LLM answer node
-> Citation formatter
-> JSON response
In LangFlow, I treated each major boundary as a visible node or small subflow. That made it possible to test the search-only path, crawler-only path, Sonar-style answer path, and agent-tool path independently.

Data Contracts

The system became easier to maintain once every stage had a stable input and output shape.

Search Request

{
  "query": "Compare Firecrawl, Exa, and SearXNG for a LangFlow web search agent",
  "max_results": 8,
  "search_domain_filter": [
    "docs.firecrawl.dev",
    "docs.exa.ai",
    "docs.searxng.org",
    "github.com"
  ],
  "search_recency_filter": "year",
  "search_language_filter": ["en"]
}

Normalized Result

{
  "rank": 1,
  "title": "Firecrawl Docs",
  "url": "https://docs.firecrawl.dev/",
  "snippet": "Scrape, crawl, and extract web data for AI applications.",
  "provider": "searxng",
  "published_date": null,
  "last_updated": null,
  "score": 0.82
}

Evidence Chunk

{
  "source_id": 1,
  "chunk_id": "1.1",
  "title": "Firecrawl Docs",
  "url": "https://docs.firecrawl.dev/",
  "text": "Firecrawl converts websites into clean markdown for AI applications.",
  "token_estimate": 12
}

Final Response

{
  "answer": "SearXNG is useful for open metasearch, while Firecrawl is stronger for page extraction [1.1][2.1].",
  "sources": [
    {
      "source_id": 1,
      "title": "Firecrawl Docs",
      "url": "https://docs.firecrawl.dev/"
    }
  ],
  "detected_chunk_citations": ["1.1", "2.1"],
  "citation_warnings": []
}

LangFlow Node Map

This is the practical canvas layout I aimed for:
Chat Input
-> Request Parser
-> Search Planner
-> Search Provider
-> Result Normalizer
-> Filter Engine
-> Deduplicator
-> Reranker
-> URL Selector
-> Webpage Reader
-> Chunk Builder
-> Source Map Builder
-> Answer Prompt Builder
-> LLM
-> Citation Formatter
-> JSON Output
The important part is that the LLM is not hidden inside the crawler or the search provider. The LLM answer node remains visible, so the evidence entering the model can be inspected.

Planner Prompt Shape

The planner node should be conservative. It should not answer the user’s question; it should only prepare better searches.
You are a search planner. Convert the user question into 1-4 web search queries.
Prefer official documentation, source repositories, standards pages, and primary sources.
Return JSON only with:
- queries
- domain_allowlist
- domain_denylist
- recency
- language
- max_results_per_query
Do not answer the question.
The output goes into the search provider node, not into the final answer.

Reranking Rules

The MVP reranker was intentionally simple because simple scoring is easy to debug in LangFlow. Recommended first-pass rules:
  • Boost official docs, GitHub repositories, and vendor documentation.
  • Penalize low-signal domains when the user asks for technical evidence.
  • Deduplicate URL variants by canonical URL.
  • Keep multiple providers from returning the same page twice.
  • Prefer recent pages only when recency matters.
  • Keep enough diversity so one domain does not dominate the whole context.
Do not open every search result. Open the best few pages, then spend model context on clean evidence rather than noisy search snippets.

Citation Validation Rules

Citation validation should be stricter than normal answer formatting. The formatter should fail softly when it sees problems:
{
  "detected_chunk_citations": [],
  "citation_warnings": [
    "The answer did not include chunk citations. Ask the model to cite source chunks like [1.1]."
  ]
}
If a model cites [9.4] but the source map only contains [1.1], [1.2], and [2.1], the formatter should warn and either remove the bad citation or ask for a repair pass.

API Facade Plan

LangFlow’s run API is enough for development, but a Perplexity-style product should eventually expose cleaner API surfaces:
EndpointPurposeBacking Flow
/v1/searchReturn normalized search resultsSearch API MVP
/v1/chat/completionsReturn grounded answer with citationsSonar-style flow
/v1/agent/runsReturn tool trace and final answerAgent Runs flow
The facade can be a thin FastAPI service that receives clean external requests, calls LangFlow’s run API internally, and returns stable product-shaped responses.

Flow Inventory

The current system is easiest to maintain as several flows instead of one oversized canvas:
FlowPurpose
Search API MVPReturn structured search results without answering
Search With ContentSearch and open selected pages
Web Search Tools MVPProvide web_search and open_url tool-shaped outputs
Basic Sonar MVPSearch, crawl, and answer with a separate LLM node
Planner Reranker Citations MVPMain flow with planning, reranking, chunks, and citation checks
Agent Runs MVPEarly agent-style schema and trace foundation
Visual Crawler PipelineDebug URL safety, HTTP fetch, HTML cleaning, PDF extraction, and fallback behavior
The main testing target is the planner, reranker, and citation flow. The smaller flows exist so individual parts can be debugged without running the whole pipeline.

What Was Actually Replicated

CapabilityCurrent StatusReplication LevelNotes
Real-time searchWorking MVPMediumUses an external or self-hosted search provider for recall, not a proprietary web index
Search planningWorking MVPMedium-highPlanner can split broad questions into focused queries
Domain filteringWorking MVPMedium-highAllowlists and denylists work for official-source tests
Language, region, and recency filtersPartialLow-mediumProvider capability mapping is not complete
Page readingWorking MVPMedium-highCrawler/open-url path reads selected HTML and PDF pages
Source chunkingWorking MVPMedium-highEvidence chunks get stable IDs such as [1.1]
CitationsWorking MVPMediumChunk citation detection exists, but claim-level support checking is still separate work
RerankingBasicLow-mediumRule-based scoring works; semantic or listwise reranking is still needed
Agent loopEarlyLow-mediumTool schemas and traces exist, but not a full autonomous loop
StreamingNot doneLowFuture facade work after non-streaming validation is stable
OpenAI-compatible API facadeNot doneLow-mediumLangFlow run API works, but /v1/search and /v1/chat/completions facade is separate work
The current milestone is “Perplexity-like answer engine: working MVP.” It is not yet “Perplexity-grade search engine.”

Evaluation Loop

The system should be evaluated as a retrieval and grounding pipeline, not only by whether the final answer sounds good. Use a small fixed test set and record these fields per run:
{
  "question": "Compare Firecrawl, Exa, and SearXNG for a LangFlow search agent.",
  "queries_generated": 3,
  "results_returned": 12,
  "urls_opened": 5,
  "successful_pages": 4,
  "chunks_sent_to_llm": 10,
  "answer_has_citations": true,
  "invalid_citation_count": 0,
  "evidence_gap": false
}
Track at least these metrics:
MetricWhy It Matters
Search recallWhether the provider finds plausible candidate pages
Open success rateWhether selected pages can actually be read
Source diversityWhether the answer depends on more than one page or domain
Citation coverageWhether important claims include chunk citations
Invalid citationsWhether the LLM cites nonexistent chunks
Evidence humilityWhether the answer admits insufficient evidence
LatencyWhether the pipeline is usable as an interactive search product
When quality is bad, inspect the first failing layer. Bad final answers often come from weak search recall, unreadable pages, duplicate sources, or missing chunks rather than from the final LLM alone.

Debugging Order

Debug in this order:
  1. Search provider returns relevant URLs.
  2. Filters keep the right URLs and remove the wrong ones.
  3. Reranker selects useful pages to open.
  4. Crawler returns clean text instead of empty content or challenge pages.
  5. Chunk builder produces readable evidence chunks.
  6. Prompt builder includes source IDs and chunk IDs.
  7. LLM answer uses chunk citations.
  8. Citation formatter detects and validates the citations.
This order prevents wasting time tuning the final prompt when the real issue is upstream evidence quality.

Test Prompts

Use these tests to check different parts of the pipeline.

Full Pipeline

Compare Firecrawl, Exa, and SearXNG for a LangFlow web search agent.
Checks search planning, result collection, page extraction, evidence chunking, and citations.

Official Source Filtering

{
  "messages": [
    {
      "role": "user",
      "content": "What are the main differences between LangGraph and LangFlow for building search agents?"
    }
  ],
  "search_domain_filter": [
    "docs.langchain.com",
    "docs.langflow.org",
    "github.com"
  ],
  "max_results": 8
}
Checks whether the flow prefers official docs and admits when evidence is insufficient.

Citation Discipline

What does Firecrawl provide for web scraping and LLM-ready content extraction? Answer with citations.
Checks whether chunk IDs such as [1.1] or [2.1] appear and whether citation warnings stay empty.

Evidence Humility

{
  "messages": [
    {
      "role": "user",
      "content": "Compare Exa and SearXNG specifically for LangFlow integration. Only use official documentation."
    }
  ],
  "search_domain_filter": [
    "docs.exa.ai",
    "docs.searxng.org",
    "docs.langflow.org"
  ],
  "max_results": 5
}
Checks whether the system admits insufficient evidence instead of inventing integration details when official sources are thin.

Deny Filtering

{
  "messages": [
    {
      "role": "user",
      "content": "Find reliable documentation for building web search agents with LangFlow."
    }
  ],
  "search_domain_filter": [
    "-reddit.com",
    "-medium.com",
    "-pinterest.com"
  ],
  "max_results": 8
}
Checks whether low-signal domains are excluded before crawling and whether the answer still uses grounded evidence.

Open-Source Research

Research open-source alternatives to Perplexity AI. Compare Perplexica, Scira, Fireplexity, and Open Deep Research. Include citations.
Checks multi-source research behavior, table-style answer quality, source diversity, and citation coverage across project documentation and repositories.

Chinese Answer With English Sources

帮我比较 Firecrawl、Exa、SearXNG 哪个更适合做一个自托管的 Perplexity-like 搜索问答系统,并给出引用。
Checks Chinese answer quality, English source handling, and citation formatting.

Roadmap

The next improvements should be made in this order:
  1. Add semantic reranking before the crawler opens pages.
  2. Add claim-level citation validation after answer generation.
  3. Add provider capability mapping for date, region, language, and freshness filters.
  4. Add a real agent loop with scratchpad, max step count, tool trace, and stop condition.
  5. Add streaming only after the non-streaming response format is stable.
  6. Add the API facade for /v1/search, /v1/chat/completions, and /v1/agent/runs.
Do not add streaming too early. Streaming makes the system feel more polished, but it also hides structured validation problems if the underlying non-streaming response is not stable yet.

Common Failure Modes

If detected_chunk_citations is empty, the LLM likely ignored the required citation format. Strengthen the answer prompt or add a second formatter and validator pass.
If a domain-filtered request returns too little evidence, do not let the model invent an answer. The right behavior is to say that the selected sources were insufficient.
If the crawler returns empty content, do not pass that page into the final LLM context as if it were evidence. Preserve the failure_reason and skip or downrank the source.
Rule-based reranking can boost docs and GitHub, but it is not enough for high-quality research. Add a semantic reranker before judging the system by Perplexity standards.

Final Checklist

  • Search provider returns normalized result objects.
  • Search planner can generate or refine queries.
  • Domain filters are applied before crawling.
  • URL deduplication happens before page reading.
  • Crawler returns content plus success or failure metadata.
  • Source chunks receive stable citation IDs.
  • LLM answer prompt requires citations from known chunks.
  • Citation formatter reports detected_chunk_citations.
  • Flow can be run from the LangFlow API with $LANGFLOW_API_KEY.
  • Public notes use example domains and variables, not private flow IDs or API keys.

What To Remember

Perplexity-like search is a pipeline, not a single capability. The useful split is:
search finds URLs
crawler reads URLs
ranker chooses evidence
LLM writes from evidence
validator checks citations
That separation is what made the LangFlow implementation debuggable. The next quality improvements should go into semantic reranking, stronger citation validation, provider capability mapping for date and language filters, and a thin API facade that exposes /v1/search, /v1/chat/completions, and /v1/agent/runs.

Metadata

Quick Reference

Typeguide
Statuspublished
Date2026-06-02

Retrieval Tags

langflowperplexitysearchcitationscrawler
Related
LangFlowWeb SearchRAGCitation Validation