Perplexica:Perplexity开源平替

Perplexica:Perplexity开源平替
Perplexica:Perplexity开源平替

Perplexica通过 SearXNG 搜索网络,可选地使用嵌入/相似性重新排序结果,然后使用 LLM 生成带引用的响应。

SearXNG 是一个免费的互联网元搜索引擎,聚合了多达 245 个搜索服务的结果。用户不会被跟踪或建立画像。此外,SearXNG 可以通过 Tor 使用以实现在线匿名。

Perplexica 提供几个很酷的功能:

  • 提供商无关: 随附 Ollama 或可插入 OpenAI/Claude/Gemini/Groq。
  • 模式: 速度、平衡、质量,以权衡延迟、深度和成本。
  • 源控制: 根据任务使用网络、讨论或学术搜索。
  • 小部件: 用于快速查找的即时卡片(天气、计算、股票)。
  • 私有网络搜索: 目前是 SearxNG,稍后会有更多检索集成。
  • 图像 + 视频: 答案不仅仅是文章。
  • 文件问答: 上传文档并查询它们。
  • 域范围搜索: 针对特定站点/文档。
  • 智能建议: 更好的查询,更快的响应。

本地历史: 随时回顾研究。

None
在开始之前,请务必获取2026 年获胜的智能体 SaaS 模式 ***https://stan.store/agentnative***我们每周都会发送这里显示的每一层的详细分析。

让我们看看如何快速设置 Perplexica。

1、Perplexica 入门

你有两个选项来运行 Perplexica。

(1) Docker Compose

git clone https://github.com/ItzCrazyKns/Perplexica.git cd Perplexica # 创建配置 cp sample.config.toml config.toml # 使用所需的密钥/端点编辑 config.toml docker compose up -d # 打开 http://localhost:3000 

对于 Docker + Ollama,通常使用 http://host.docker.internal:11434 作为 Ollama API URL。

你可以在 UI 的"设置对话框"中稍后更改模型密钥/设置

(2) 非 Docker

  • 安装 SearXNG 并在 SearXNG 设置中允许 JSON 格式。
  • 克隆存储库并将 sample.config.toml 文件重命名为根目录中的 config.toml。
  • (确保完成此文件中的所有必填字段)
  • 然后运行:
npm i npm run build npm run start 

如果有任何问题,你可以在这里找到更多信息

2、架构和请求流程

Perplexica 将系统描述为:

  1. UI
  2. 智能体/链
  3. SearXNG 用于网络源
  4. LLM 用于推理/回答/引用
  5. 嵌入模型用于重新排序
    概念流程是:
(1) 请求 (2) 链决定是否需要网络搜索 + 生成查询 (3) SearXNG 搜索 (4) 嵌入 + 相似性重新排序 (5) 响应生成器流式传输到 UI 

这通过特定焦点模式处理器和可重用的智能体实现。

src/lib/search/index.ts 是最重要的"产品地图"文件之一。

它将焦点模式注册为 MetaSearchAgent 的实例,设置包括:

  • activeEngines(例如,学术使用 arxiv/scholar/pubmed;youtube 使用 youtube;reddit 使用 reddit)
  • rerankrerankThreshold
  • searchWeb 对比"不搜索网络"(writingAssistant 设置 searchWeb: false
  • summarizer(为 webSearch 启用)
    src/lib/search/metaSearchAgent.ts 是编排器,它:
  • 构建"搜索检索器链"(温度为 0 的 LLM 用于查询生成)
  • 可以摄取"直接链接"输出(当启用 summarizer 时,获取并总结页面),按 URL 对文档进行分组,并使用结构化的系统提示将它们总结为 2-4 段
  • 使用 SearXNG 搜索(searchSearxng),然后使用相似性评分(computeSimilarity)重新排序/选择源(如文档中所述)

3、服务器 API

由于 Perplexica 是一个 Next.js App Router 项目,端点位于 src/app/api/* 下。

None

/api/search(文档化的"搜索 API"),其 POST 主体包括:

  • focusModeoptimizationModequeryhistory
  • chatModelembeddingModel(提供商 + 模型名称)
  • 可选的 systemInstructions
  • 可选的 stream
    Perplexica/src/app/api/search/route.ts
import ModelRegistry from '@/lib/models/registry'; import { ModelWithProvider } from '@/lib/models/types'; import SessionManager from '@/lib/session'; import { ChatTurnMessage } from '@/lib/types'; import { SearchSources } from '@/lib/agents/search/types'; import APISearchAgent from '@/lib/agents/search/api'; interface ChatRequestBody { optimizationMode: 'speed' | 'balanced' | 'quality'; sources: SearchSources[]; chatModel: ModelWithProvider; embeddingModel: ModelWithProvider; query: string; history: Array<[string, string]>; stream?: boolean; systemInstructions?: string; } export const POST = async (req: Request) => { try { const body: ChatRequestBody = await req.json(); if (!body.sources || !body.query) { return Response.json( { message: 'Missing sources or query' }, { status: 400 }, ); } body.history = body.history || []; body.optimizationMode = body.optimizationMode || 'speed'; body.stream = body.stream || false; const registry = new ModelRegistry(); const [llm, embeddings] = await Promise.all([ registry.loadChatModel(body.chatModel.providerId, body.chatModel.key), registry.loadEmbeddingModel( body.embeddingModel.providerId, body.embeddingModel.key, ), ]); const history: ChatTurnMessage[] = body.history.map((msg) => { return msg[0] === 'human' ? { role: 'user', content: msg[1] } : { role: 'assistant', content: msg[1] }; }); const session = SessionManager.createSession(); const agent = new APISearchAgent(); agent.searchAsync(session, { chatHistory: history, config: { embedding: embeddings, llm: llm, sources: body.sources, mode: body.optimizationMode, fileIds: [], systemInstructions: body.systemInstructions || '', }, followUp: body.query, chatId: crypto.randomUUID(), messageId: crypto.randomUUID(), }); if (!body.stream) { return new Promise( ( resolve: (value: Response) => void, reject: (value: Response) => void, ) => { let; let sources: any[] = []; session.subscribe((event: string, data: Record<string, any>) => { if (event === 'data') { try { if (data.type === 'response') { message += data.data; } else if (data.type === 'searchResults') { sources = data.data; } } catch (error) { reject( Response.json( { message: 'Error parsing data' }, { status: 500 }, ), ); } } if (event === 'end') { resolve(Response.json({ message, sources }, { status: 200 })); } if (event === 'error') { reject( Response.json( { message: 'Search error', error: data }, { status: 500 }, ), ); } }); }, ); } const encoder = new TextEncoder(); const abortController = new AbortController(); const { signal } = abortController; const stream = new ReadableStream({ start(controller) { let sources: any[] = []; controller.enqueue( encoder.encode( JSON.stringify({ type: 'init', data: 'Stream connected', }) + '\n', ), ); signal.addEventListener('abort', () => { session.removeAllListeners(); try { controller.close(); } catch (error) {} }); session.subscribe((event: string, data: Record<string, any>) => { if (event === 'data') { if (signal.aborted) return; try { if (data.type === 'response') { controller.enqueue( encoder.encode( JSON.stringify({ type: 'response', data: data.data, }) + '\n', ), ); } else if (data.type === 'searchResults') { sources = data.data; controller.enqueue( encoder.encode( JSON.stringify({ type: 'sources', data: sources, }) + '\n', ), ); } } catch (error) { controller.error(error); } } if (event === 'end') { if (signal.aborted) return; controller.enqueue( encoder.encode( JSON.stringify({ type: 'done', }) + '\n', ), ); controller.close(); } if (event === 'error') { if (signal.aborted) return; controller.error(data); } }); }, cancel() { abortController.abort(); }, }); return new Response(stream, { headers: { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache, no-transform', Connection: 'keep-alive', }, }); } catch (err: any) { console.error(`Error in getting search results: ${err.message}`); return Response.json( { message: 'An error has occurred.' }, { status: 500 }, ); } }; 

src/app/api/chat/route.ts 是"聊天运行时":

  • 接受 messagehistoryfiles、模型选择、焦点模式、优化模式、systemInstructions
  • 使用相同的 searchHandlers[focusMode].searchAndAnswer(...) 机制
    流式传输的事件如:
  • { type: "message", data: "...", messageId }
  • { type: "sources", data: [...], messageId }
  • { type: "messageEnd", messageId }
    它还通过 Drizzle 持久化聊天/消息(chatsmessages 架构),并在存在时将源存储在消息元数据中。

你可能接触的其他 API 路由来自 src/app/api 文件夹列表:modelsconfigsuggestionsimagesvideosuploadsweather 等。

4、模型提供商和选择

Perplexica 将模型抽象在"提供商"之后,路由处理器请求:

  • “可用的聊天模型提供商”
  • “可用的嵌入模型提供商”
    提供商的配置密钥位于 config.tomlMODELS.*)中,并通过辅助函数如 getOpenaiApiKey()getGroqApiKey() 等读取。

支持的提供商通过以下方式反映:

  • 配置模板(sample.config.toml
  • 提供商目录列表(OpenAI、Ollama、Groq、Anthropic、Gemini、DeepSeek、LM Studio、自定义端点、AI/ML API、transformers)
    这是非流式搜索的最小"API 使用"示例:
curl -X POST http://localhost:3000/api/search \ -H "Content-Type: application/json" \ -d '{ "focusMode": "webSearch", "optimizationMode": "balanced", "query": "What is Perplexica?", "history": [], "stream": false }' 

以及流式搜索:

curl -N -X POST http://localhost:3000/api/search \ -H "Content-Type: application/json" \ -d '{ "focusMode": "webSearch", "optimizationMode": "balanced", "query": "Explain how Perplexica reranks sources", "history": [], "stream": true }' 

如果你正在构建搜索或深度研究智能体,一定要试试看,我很乐意在评论中听到你的经验。


原文链接:Perplexica:Perplexity开源平替 - 汇智网

Read more

大模型微调新姿势:用Llama Factory一键搞定LlaMA 3定制

大模型微调新姿势:用Llama Factory一键搞定LlaMA 3定制 如果你正在寻找一种快速、高效的方式来微调LlaMA 3模型,那么Llama Factory可能是你的理想选择。作为一个开源的低代码大模型微调框架,Llama Factory集成了业界广泛使用的微调技术,支持通过Web UI界面零代码微调大模型。这类任务通常需要GPU环境,目前ZEEKLOG算力平台提供了包含该镜像的预置环境,可快速部署验证。 为什么选择Llama Factory进行LlaMA 3微调 Llama Factory之所以成为AI创业团队的首选工具,主要因为它解决了以下几个痛点: * 环境搭建复杂:传统微调需要手动安装CUDA、PyTorch等依赖,耗时且容易出错 * 学习曲线陡峭:需要掌握大量命令行操作和参数配置 * 资源消耗大:本地部署需要高性能GPU,成本高昂 * 方法选择困难:不同微调方法效果差异大,难以快速对比 Llama Factory预装了所有必要组件,包括: * 主流微调方法:LoRA、全参数微调、增量预训练等 * 多种模型支持:LlaMA 3、Qwen、Cha

By Ne0inhk

揭秘VSCode Copilot无法登录原因:5步快速恢复访问权限

第一章:VSCode Copilot无法登录问题概述 Visual Studio Code(VSCode)中的GitHub Copilot作为一款智能代码补全工具,极大提升了开发者的编码效率。然而,在实际使用过程中,部分用户频繁遭遇Copilot无法正常登录的问题,导致功能受限或完全不可用。该问题可能由多种因素引发,包括网络连接异常、身份验证失效、插件配置错误或系统环境限制等。 常见表现形式 * 点击“Sign in to GitHub”后无响应或弹窗无法加载 * 登录完成后仍提示“GitHub authentication failed” * Copilot状态始终显示为“Not signed in” 基础排查步骤 1. 确认网络可正常访问GitHub服务,必要时配置代理 2. 检查VSCode是否已更新至最新版本 3. 重新安装GitHub Copilot及GitHub Authentication扩展 验证身份认证状态 可通过开发者工具查看认证请求是否成功发出。在VSCode中按 F1,输入 Developer: Open

By Ne0inhk
copilot学生认证2026-github copilot学生认证(手把手教会)

copilot学生认证2026-github copilot学生认证(手把手教会)

1.前言 博主在24年的时候发过一篇copilot认证成功的帖子,当时也是领到了一年的pro 文章链接:github copilot学生认证(手把手一小时成功)-ZEEKLOG博客 如今26年了,copilot的申请增加了一年的时间,博主也进入了研究生生涯,前段时间也是再次进行了申请,现在已经用上了,Pro 版直接解锁无限制基础功能 + 海量高级模型,我的感受是:真香!:   既然官方的申请有变化,咱们教程也得与时俱进,下面就开始手把手教大家如何进行申请copilot学生会员。 2.完善 GitHub 账号基础配置 在Emails里面加入你对应学校的教育邮箱(以edu.cn结尾),打开教育邮箱点击GitHub发送的验证邮件链接,即可完成邮箱认证 3.Github学生认证 完成上述步骤后,打开学生认证申请链接,依旧还是在设置里面,这里也可以用手机操作,因为上传证明材料用手机拍照更方便: 选择身份为学生,下滑填写学校信息,输入学校的英文,最后选择自己的学校教育邮箱,点击continue(还得分享位置) 接下来就是上传证明材料: * 可以使用手机摄像头拍摄,证件

By Ne0inhk

Windows 环境下 llama.cpp 编译 + Qwen 模型本地部署全指南

在大模型落地场景中,本地轻量化部署因低延迟、高隐私性、无需依赖云端算力等优势,成为开发者与 AI 爱好者的热门需求。本文聚焦 Windows 10/11(64 位)环境,详细拆解 llama.cpp 工具的编译流程(支持 CPU/GPU 双模式,GPU 加速需依赖 NVIDIA CUDA),并指导如何通过 modelscope 下载 GGUF 格式的 Qwen-7B-Chat 模型,最终实现模型本地启动与 API 服务搭建。 1.打开管理员权限的 PowerShell/CMD,执行以下命令克隆代码: git clone https://github.com/ggml-org/llama.cpp mkdir

By Ne0inhk