从零构建开源AI搜索引擎Farfalle:本地部署与云端配置全指南
1. 项目概述:打造你的开源AI搜索引擎
如果你对Perplexity这类AI搜索工具着迷,但又希望拥有一个完全可控、能运行在本地、并且可以深度定制的版本,那么Farfalle这个开源项目可能就是你的下一个“周末项目”。我最近花了不少时间折腾它,从本地部署到云端配置,踩了不少坑,也收获了很多实用的经验。简单来说,Farfalle是一个集成了大语言模型(LLM)能力的开源搜索引擎,它允许你使用本地模型(如通过Ollama运行的Llama 3、Mistral)或云端模型(如GPT-4o、Groq的Llama 3)来增强搜索结果的解读和呈现,目标是提供一个类似Perplexity的、对话式的智能搜索体验。它的核心价值在于将“搜索”和“理解”两个环节无缝衔接,让你不仅能得到网页链接列表,还能获得一个由AI生成的、基于多个来源的整合性答案。
这个项目特别适合几类人:一是对AI应用开发感兴趣的开发者,想学习如何将LLM与搜索API结合;二是注重隐私、希望将搜索和问答过程完全本地化的技术爱好者;三是想为自己或团队搭建一个内部知识检索工具的工程师。它的技术栈选型非常现代且务实:前端用Next.js和React构建响应式界面,后端用FastAPI提供高性能API,UI组件则基于流行的shadcn/ui和Tailwind CSS,整个架构清晰,易于理解和二次开发。接下来,我将从项目设计思路、核心配置、深度部署实践到问题排查,为你完整拆解如何从零开始驾驭Farfalle。
2. 核心架构与设计思路拆解
2.1 为什么是“搜索 + LLM”的架构?
Farfalle的设计核心在于解耦“信息获取”和“信息处理”。传统的搜索引擎只负责前者,返回一堆相关链接。而像Perplexity这样的产品,在获取信息后,多了一个用LLM进行总结、归纳和回答的步骤。Farfalle开源实现了这一流程。
2.1.1 搜索后处理(Search-then-Process)模式这是Farfalle采用的主要模式。其工作流可以拆解为:
- 查询理解与分发:用户输入问题后,后端首先将查询发送给一个或多个搜索提供商(如SearXNG、Tavily)。
- 并行信息获取:搜索提供商并发地抓取网络信息,返回结构化的搜索结果(标题、摘要、链接)。
- 上下文构建:后端将多个搜索结果的摘要、标题等关键信息拼接成一个长的“上下文”文本。
- LLM推理与生成:将这个上下文连同用户原始问题,一并提交给配置好的LLM(本地或云端),指令通常是“基于以下资料,请回答用户的问题”。
- 结果呈现:前端将LLM生成的答案,连同其引用的来源链接,清晰、美观地展示出来。
这种模式的优点是架构清晰,各模块职责单一。搜索模块专注于覆盖率和速度,LLM模块专注于理解和生成。你可以独立升级或更换其中任何一个组件。
2.1.2 智能体(Agent)搜索模式这是Farfalle一个更高级的特性。简单来说,它让LLM自己来规划搜索策略。流程如下:
- 规划:LLM先分析用户问题,判断是否需要搜索、需要搜索几次、每次应该用什么关键词。
- 执行与观察:系统执行LLM规划的搜索,并将结果返回给LLM“观察”。
- 反思与迭代:LLM根据观察到的结果,判断是否已回答问题,若未完成,则可能规划新一轮的搜索。
- 最终生成:经过多轮规划-执行后,LLM综合所有信息生成最终答案。
这个模式对复杂、多步骤的查询特别有效。例如,问“对比Llama 3和GPT-4在代码生成上的优劣,并给出最新的基准测试数据”,智能体可能会先搜索各自的官方文档,再搜索近期的评测文章,最后进行综合对比。在Farfalle中,你可以通过界面上的“Expert Search”选项启用此模式。
2.2 技术栈选型的深层考量
作者选择的技术栈并非追逐时髦,每一环都有其实际考量,这也为我们构建类似应用提供了参考。
- Next.js (前端):选择Next.js而不仅是React,看中的是其开箱即用的服务端渲染(SSR)和静态生成(SSG)能力。对于搜索应用,首屏加载速度至关重要。Next.js能很好地优化初始页面加载,并且其API Routes功能在项目初期也可以简化后端架构(虽然Farfalle用了独立的FastAPI)。此外,庞大的生态系统和Vercel平台的无缝部署体验也是加分项。
- FastAPI (后端):相比Django或Flask,FastAPI的异步支持是最大亮点。搜索和LLM调用都是I/O密集型操作,异步处理可以大幅提高并发能力,让服务器在等待外部API(如OpenAI)响应时,还能处理其他请求。其基于Pydantic的自动请求/响应验证以及自动生成的交互式API文档(Swagger UI),也极大地提升了开发效率。
- SearXNG (默认搜索源):这是一个关键且明智的选择。SearXNG本身是一个元搜索引擎,它聚合了Google、Bing、DuckDuckGo等众多引擎的结果,且可以自托管。这意味着:
- 去依赖化:你不需要立即申请Google、Bing等商业API的密钥,SearXNG直接提供了可用的搜索能力。
- 隐私保护:所有搜索请求通过你自己的SearXNG实例发出,降低了直接向大公司暴露查询的风险。
- 可定制性:你可以配置SearXNG使用哪些搜索引擎,调整结果数量等。
- LiteLLM (模型抽象层):这是项目灵活性的基石。LiteLLM是一个统一接口,将上百种不同的LLM API(OpenAI, Anthropic, Cohere, 本地Ollama等)封装成一致的格式。通过它,Farfalle后端只需编写一套调用逻辑,就可以通过简单的配置切换不同的模型提供商,甚至自定义的模型端点。这为未来扩展支持更多模型铺平了道路。
- Redis (速率限制):LLM API调用,尤其是云端的,通常有速率和用量限制。Redis作为一个高性能的内存数据库,非常适合实现精准、高效的速率限制中间件。它能快速计数和判断在特定时间窗口内,某个用户或IP的请求是否超限。
- shadcn/ui & Tailwind CSS (UI):选择这个组合意味着追求高度的可定制性和开发体验。shadcn/ui提供的是可直接复制粘贴到项目中的高质量React组件代码,而非一个黑盒式的组件库。这让你拥有对组件样式的完全控制权,并能与Tailwind CSS的实用类完美结合,快速构建出既美观又独特的界面。
注意:这个技术栈对初学者有一定门槛,尤其是需要同时理解前后端分离、异步编程、容器化部署等概念。但正因为其现代和完整,成功部署一次后,你对整个Web应用开发生态的理解会深刻很多。
3. 从零开始的详细部署与配置实战
官方提供了Docker一键部署,这确实是最快的方式。但为了真正理解这个系统,我建议我们先走一遍“自定义设置”,这能帮你解决未来可能遇到的大部分环境问题。
3.1 基础环境准备与深度配置
3.1.1 后端(FastAPI)环境搭建首先,我们抛开Docker,在本地手动设置后端,这能让你看清所有依赖。
# 1. 克隆项目 git clone https://github.com/rashadphz/farfalle.git cd farfalle/backend # 2. 创建虚拟环境(推荐使用uv或poetry,这里以venv为例) python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate # 3. 安装依赖 pip install -r requirements.txt关键依赖解析:
fastapi&uvicorn: Web框架和ASGI服务器。litellm: 核心,用于调用各类LLM。redis: 用于速率限制的客户端库。logfire: Pydantic出品的观测工具,用于记录日志和追踪,方便调试。httpx: 异步HTTP客户端,用于调用搜索API。
3.1.2 前端(Next.js)环境搭建
cd ../src/frontend npm install # 或 pnpm install / yarn install前端依赖相对标准,主要是Next.js、React、Tailwind CSS以及shadcn/ui的组件。
3.1.3 环境变量(.env)配置详解这是项目的核心配置文件。复制模板后,你需要仔细配置。
cd ../.. # 回到项目根目录 cp .env-template .env打开.env文件,我们来逐一拆解关键配置:
# 后端服务设置 BACKEND_HOST=0.0.0.0 # 后端监听地址,0.0.0.0表示允许所有网络访问 BACKEND_PORT=8000 # 后端服务端口 FRONTEND_URL=http://localhost:3000 # 前端地址,用于CORS配置 # 搜索提供商配置 - 至少需要配置一个 SEARXNG_INSTANCE_URL=http://localhost:8080 # 本地SearXNG实例,最常用 TAVILY_API_KEY=your_tavily_key_here # Tavily API密钥(付费,质量高) SERPER_API_KEY=your_serper_key_here # Serper API密钥(付费,针对Google搜索优化) BING_SUBSCRIPTION_KEY=your_bing_key_here # 微软Bing搜索API密钥 # LLM提供商配置 - 根据你想用的模型配置 # 本地模型(通过Ollama) OLLAMA_API_BASE=http://localhost:11434 # Ollama服务地址 OLLAMA_MODEL=llama3:latest # 默认使用的本地模型 # 云端模型 OPENAI_API_KEY=sk-... # OpenAI密钥,用于gpt-3.5-turbo, gpt-4o等 GROQ_API_KEY=gsk_... # Groq密钥,用于高速推理的Llama3等 # LiteLLM配置(用于自定义模型端点) LITELLM_MODEL=your_custom_model_name # 自定义模型名 LITELLM_API_BASE=https://your.endpoint/v1 # 自定义API地址 LITELLM_API_KEY=your_custom_key # 自定义API密钥 # 应用功能与安全配置 ENABLE_RATE_LIMITING=True # 是否启用API速率限制 REDIS_URL=redis://localhost:6379 # Redis连接地址,用于速率限制 LOGLEVEL=info # 日志级别实操心得:
- 对于初学者:强烈建议从
SEARXNG_INSTANCE_URL和OLLAMA_MODEL开始。这意味着你只需要部署SearXNG和Ollama,就可以实现完全本地、免费的AI搜索,无需任何API密钥和费用。 - 密钥管理:
.env文件包含敏感信息,务必将其添加到.gitignore中,切勿提交到代码仓库。在生产环境中,应使用服务器环境变量或密钥管理服务(如Vercel/ Render的环境变量配置、AWS Secrets Manager)。 - 多模型配置:LiteLLM的妙处在于,你可以在同一个
.env文件中配置多个模型相关的环境变量。后端代码会根据请求中指定的模型名称,自动选择对应的配置。你可以在前端界面下拉菜单中切换它们。
3.2 核心依赖服务部署:SearXNG与Ollama
要让Farfalle真正跑起来,SearXNG(搜索源)和Ollama(本地LLM)是两个最关键的独立服务。
3.2.1 部署SearXNG(你的私有搜索网关)SearXNG最好通过Docker运行,这能避免复杂的Python环境问题。
# 创建一个专用目录并下载docker-compose.yml mkdir searxng && cd searxng wget https://raw.githubusercontent.com/searxng/searxng-docker/master/docker-compose.yaml编辑下载的docker-compose.yaml文件,一个关键的修改是禁用不必要的限制,并设置一个简单的密钥(用于管理界面):
version: '3.7' services: searxng: image: searxng/searxng:latest container_name: searxng ports: - "8080:8080" # 将容器8080端口映射到宿主机的8080端口 volumes: - ./searxng:/etc/searxng:rw environment: - SEARXNG_SECRET_KEY=my_super_secret_key_change_me # 请务必修改这个密钥! - SEARXNG_BASE_URL=http://localhost:8080/ networks: - searxng redis: image: "redis:alpine" container_name: redis networks: - searxng networks: searxng:然后启动它:
docker-compose up -d访问http://localhost:8080,你应该能看到SearXNG的搜索界面。在Farfalle的.env文件中,将SEARXNG_INSTANCE_URL设置为这个地址。
注意事项:SearXNG默认配置可能屏蔽了一些搜索引擎。如果需要,你可以进入容器内部修改配置文件(
/etc/searxng/settings.yml),但初期测试用默认配置即可。另外,SEARXNG_SECRET_KEY用于保护管理页面,如果暴露在公网,一定要改成强密码。
3.2.2 部署Ollama(你的本地大模型引擎)Ollama的安装极其简单,它负责拉取和运行大型语言模型。
- 安装:前往 Ollama官网 下载对应操作系统的安装包,一键安装。
- 拉取模型:安装后,打开终端,拉取一个模型,例如Llama 3:
这个命令会下载约4.7GB的模型文件。你也可以选择更小的模型,如ollama pull llama3mistral(4.1GB)、gemma:2b(1.6GB)或phi3:mini(1.8GB),下载速度更快,对硬件要求更低。 - 运行服务:Ollama安装后通常会自动在后台运行一个服务,监听11434端口。你可以通过
ollama serve命令前台启动,或使用系统服务管理。在Farfalle的.env中,确保OLLAMA_API_BASE指向http://localhost:11434。
实操心得:模型选择取决于你的硬件。8GB内存的电脑运行llama3:8b(约4.7GB)会比较吃力,回答速度慢。phi3:mini(约1.8GB)在8GB内存上体验会流畅很多,虽然能力稍弱,但对于一般问答和总结足够用。永远先用小模型跑通流程。
3.3 启动与验证:让整个系统联动
现在,所有部件都准备好了。我们按照“自定义设置”来启动,而不是直接用docker-compose一键拉起所有服务,这样你能更清楚每个环节。
3.3.1 启动后端服务
# 在项目根目录下,确保虚拟环境已激活 cd backend uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload--reload参数允许代码修改后自动重启,方便开发。看到输出包含Uvicorn running on http://0.0.0.0:8000即表示成功。
3.3.2 启动前端服务打开另一个终端窗口:
cd src/frontend npm run dev前端服务通常启动在http://localhost:3000。
3.3.3 功能验证
- 打开浏览器,访问
http://localhost:3000。 - 在搜索框输入一个问题,例如:“解释一下量子计算的基本原理”。
- 在界面下方,选择“Search Provider”为
SearXNG,选择“Model”为Ollama - llama3(或你拉取的其他模型)。 - 点击搜索或按回车。
预期结果:前端会显示“Searching...”和“Thinking...”的状态。稍等片刻(本地模型推理可能需要10-30秒),你会看到一个结构化的答案,答案下方会列出引用的网页来源。点击来源链接可以跳转到原始网页。
如果遇到错误,请第一时间打开浏览器开发者工具(F12)的“网络(Network)”标签页,查看前端对后端(localhost:8000)的请求是否失败,以及失败的具体错误信息。同时,查看后端服务的终端日志,那里有更详细的错误堆栈。
4. 生产环境部署与高级配置指南
本地跑通只是第一步。如果你希望将它部署到公网,供自己或小团队使用,就需要考虑生产环境部署。官方推荐了Render(后端)和Vercel(前端)的组合,这是一个非常省心的方案。
4.1 后端部署到Render
Render是一个对开发者友好的PaaS平台,特别适合部署Python/Node.js应用,它提供了免费的PostgreSQL、Redis和Web服务额度。
- 一键部署:直接点击项目README中的“Deploy to Render”按钮。这会跳转到Render,并自动导入Farfalle的仓库。
- 环境变量配置:在Render的部署配置页,最关键的一步是设置环境变量。你需要将本地
.env文件中的所有配置(除了BACKEND_HOST、BACKEND_PORT这类本地设置),特别是各种API_KEY,逐一添加到Render的“Environment”选项卡中。REDIS_URL: 如果使用Render自带的Redis,创建后会得到一个外部连接字符串,格式如redis://red-xxxx:6379。SEARXNG_INSTANCE_URL: 如果你在公网部署了自己的SearXNG实例,就填其公网地址。否则,可以暂时注释掉,依赖其他搜索API(如Tavily)。- 所有API密钥(OPENAI, GROQ, TAVILY等)都需要在这里设置。
- 部署与获取URL:点击“Deploy”。部署完成后,在Render的Dashboard中找到你的Web服务,其提供的“URL”(如
https://farfalle-backend.onrender.com)就是你的后端API地址。复制这个URL。
重要提示:Render的免费实例有休眠策略(一段时间无请求会自动休眠,下次请求会有冷启动延迟)。对于个人使用的工具,这可以接受。如果要求高可用,需升级到付费计划。
4.2 前端部署到Vercel
Vercel是Next.js的“娘家”,部署体验无缝。
- 一键部署:点击README中的“Deploy with Vercel”按钮。
- 关联仓库与配置:授权Vercel访问你的GitHub仓库,它会自动检测为Next.js项目。
- 设置关键环境变量:在配置页面,你需要设置一个最重要的环境变量:
NEXT_PUBLIC_API_URL: 填入你在上一步从Render获取的后端URL,例如https://farfalle-backend.onrender.com。这个变量会被编译到前端代码中,用于所有API请求。
- 部署:点击部署。完成后,Vercel会给你一个前端应用的访问地址,如
https://farfalle.vercel.app。
至此,你已经拥有了一个完全在云上运行的、属于自己的Perplexity克隆版。你可以将这个Vercel地址分享给朋友或同事使用。
4.3 配置浏览器默认搜索引擎
为了让使用体验更接近Google,你可以将你的Farfalle实例设置为浏览器的默认搜索引擎。
以Chrome浏览器为例:
- 打开Chrome,进入
设置->搜索引擎->管理搜索引擎和网站搜索。 - 点击“添加”。
- 填写以下信息:
- 搜索引擎:给你的引擎起个名字,如“My Farfalle”。
- 关键字:设置一个触发词,如
ff。 - 网址:这是最关键的一步。格式为:
https://你的前端地址/api/search?q=%s。- 例如,如果你的前端部署在Vercel,地址是
https://farfalle.vercel.app,那么网址应填:https://farfalle.vercel.app/api/search?q=%s。 - 注意:这里指向的是前端应用的API路由(由Next.js处理),它会将请求代理到你配置的后端(
NEXT_PUBLIC_API_URL)。这是官方前端代码设计好的路径。
- 例如,如果你的前端部署在Vercel,地址是
- 保存后,在地址栏输入
ff [你的问题]然后按回车,就会直接用你的Farfalle进行搜索。
实操心得:这个功能极大地提升了工具的实用性。我将其关键字设为ai,现在在地址栏输入ai 如何修复Python的SSL证书错误比打开新标签页再输入要快得多。这真正让它变成了一个日常工具。
5. 深度使用技巧与问题排查实录
即使按照步骤部署,也难免会遇到问题。以下是我在部署和使用过程中遇到的一些典型问题及解决方案。
5.1 常见启动与连接问题
问题1:前端访问localhost:3000报错 “Failed to fetch” 或 “Network Error”。
- 排查思路:这几乎总是前后端连接问题。
- 检查后端是否运行:确认
http://localhost:8000可以访问,并看到FastAPI自动生成的Swagger文档页面(/docs)。 - 检查前端配置:打开浏览器开发者工具 -> 网络(Network),查看失败的请求URL是什么。它应该指向
http://localhost:8000。如果指向了其他地址(如http://localhost:3000/api/...),请检查前端代码中API base URL的配置。在Farfalle中,这个配置通常通过环境变量NEXT_PUBLIC_API_URL控制,在本地开发时,它可能在src/frontend/.env.local中设置为http://localhost:8000。 - 检查CORS:如果后端日志出现CORS错误,需要确认后端
app/main.py中CORS中间件配置的origins包含了前端地址http://localhost:3000。在Farfalle的代码中,这通常是从环境变量FRONTEND_URL读取的。
- 检查后端是否运行:确认
问题2:使用Ollama模型时,搜索后长时间卡在“Thinking...”,最后超时。
- 排查思路:本地LLM推理慢或出错。
- 查看Ollama服务:运行
ollama list确认模型已下载。运行ollama run llama3在命令行直接与模型对话,测试其是否正常工作。 - 查看后端日志:后端调用Ollama API时会有详细日志。查看是否有错误信息,如连接拒绝、模型不存在等。确认
.env中的OLLAMA_API_BASE正确。 - 检查硬件资源:打开系统资源监视器(如任务管理器、htop),查看CPU、内存和GPU(如果支持)的使用情况。运行
llama3:8b模型至少需要8GB可用内存。如果内存不足,模型加载或推理会极其缓慢甚至失败。尝试换用更小的模型,如phi3:mini。 - 调整超时设置:在后端代码中,调用Ollama的HTTP请求可能有超时设置。如果硬件较慢,可以尝试在代码中增加超时时间(timeout)。但根本上还是需要升级硬件或使用更小、更高效的模型。
- 查看Ollama服务:运行
问题3:部署到Render后,前端能打开,但搜索无结果,后端日志显示搜索API错误。
- 排查思路:云端环境变量缺失或网络问题。
- 确认环境变量:登录Render Dashboard,仔细检查你的Web服务的环境变量是否全部正确设置,特别是
SEARXNG_INSTANCE_URL、TAVILY_API_KEY等。注意:Render的环境变量中不能有注释(#后面的内容),需要删除。 - 测试SearXNG实例:如果你配置了公网SearXNG实例,直接在浏览器访问其地址,看是否能正常搜索。如果SearXNG实例部署在家庭网络且没有公网IP,那么Render云服务器是无法访问它的。这时你需要使用云端的搜索API(如Tavily),或者将SearXNG也部署到云端(例如同一个Render上,但需注意免费实例的限制)。
- 查看Render日志:Render提供了详细的构建和运行时日志。查看日志中是否有Python异常抛出,这能快速定位问题根源。
- 确认环境变量:登录Render Dashboard,仔细检查你的Web服务的环境变量是否全部正确设置,特别是
5.2 搜索与答案质量优化
技巧1:混合使用多个搜索源Farfalle支持配置多个搜索提供商。你可以在.env中同时配置TAVILY_API_KEY和SERPER_API_KEY。在后端代码逻辑中(通常是轮询或根据优先级选择),它可以依次尝试不同的搜索源,直到其中一个返回结果。这提高了搜索的鲁棒性。Tavily的API针对AI应用优化过,结果质量通常很高;Serper则是对Google搜索的廉价代理。
技巧2:调整“代理搜索(Expert Search)”的深度在启用“Expert Search”(智能体模式)时,LLM可能会进行多轮搜索,这虽然全面但耗时且消耗API调用次数(如果使用付费搜索API)。你可以在后端代码中搜索与agent相关的部分,找到控制最大迭代次数(max_iterations)或最大深度(max_depth)的参数,适当调低(例如从5调到3)以在质量和速度/成本间取得平衡。
技巧3:为本地模型设计更好的提示词(Prompt)答案的质量很大程度上取决于提交给LLM的提示词。Farfalle的后端代码中应该有一个构建最终提示词的函数。你可以找到它,并根据你使用的本地模型特性进行微调。例如,对于某些模型,在指令开头加上“你是一个有帮助的AI助手”可能效果更好。或者明确要求“如果根据提供资料无法回答,请诚实说明”,以减少模型胡编乱造(幻觉)的情况。
5.3 安全与性能考量
安全警告:
- API密钥:永远不要将包含真实API密钥的
.env文件提交到Git仓库。使用.gitignore排除它。 - 公网暴露:如果你将服务部署到公网(如Render+Vercel),那么你的搜索查询和答案(除非全程使用本地模型)会经过你的后端服务器。确保你的后端服务(Render)设置了合适的环境变量,并且没有在代码中硬编码敏感信息。
- 速率限制:务必启用
ENABLE_RATE_LIMITING并正确配置REDIS_URL。这可以防止你的API被滥用,尤其是在你使用付费的云LLM和搜索API时。你可以在后端代码中调整速率限制的规则(如每分钟每个IP最多10次请求)。
性能优化:
- 使用云LLM:如果你追求速度,Groq的Llama 3模型是惊人的快(每秒输出数百个token),且价格低廉。将
GROQ_API_KEY配置好,并在前端选择“Groq - llama3-70b-8192”,体验会远超本地模型。 - 缓存:对于常见问题,可以考虑在后端引入缓存机制(例如使用Redis缓存相同的查询和答案),这能显著减少对LLM和搜索API的调用,提升响应速度并降低成本。Farfalle目前没有内置缓存,这是一个可以贡献代码的优化点。
- 前端静态优化:利用Next.js的特性,将一些不常变化的页面(如关于页面、设置说明)进行静态生成(Static Generation),可以进一步提升前端加载速度。
经过以上步骤,你应该已经拥有了一个完全功能、可自定义、且能部署在云端或本地的AI搜索引擎。从本地模型到云端API,从简单搜索到智能体规划,Farfalle提供了一个绝佳的学习和实践平台。我个人的体会是,最大的收获不是搭建了一个工具,而是通过这个过程,透彻理解了现代AI应用如何将搜索、推理、呈现等多个模块优雅地串联起来。如果你在部署中遇到了上面没覆盖的问题,最好的去处就是项目的GitHub仓库的Issues页面,那里有作者和社区其他用户的讨论,通常能找到解决方案。
