AI 工具开发实战(9):开发一个 AI 搜索引擎聚合器——同时查多个 AI 搜索,对比结果
日常查技术问题要开多个 AI 搜索:Perplexity 查海外、秘塔查中文、DeepSeek 验证一下。这个工具把多个 AI 搜索聚合到一个页面上,一次提问、并行调用、对比展示。
核心代码
# metasearch.py
import asyncio
import aiohttp
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, StreamingResponse
import json
import os
app = FastAPI()
API_KEY = os.getenv("DEEPSEEK_API_KEY", "")
SEARCH_ENGINES = {
"deepseek": {
"name": "DeepSeek",
"url": "https://api.deepseek.com/v1/chat/completions",
"headers": {"Authorization": f"Bearer {API_KEY}"},
"body_template": lambda q: {
"model": "deepseek-chat",
"messages": [{"role": "user", "content": q}],
"stream": True,
},
},
}
HTML = """
AI 聚合搜索
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:sans-serif;max-width:1200px;margin:0 auto;padding:20px;background:#f8fafc}
h1{text-align:center;margin-bottom:20px;color:#1e293b}
.search-bar{display:flex;gap:8px;margin-bottom:24px}
input{flex:1;padding:12px 16px;border:2px solid #e2e8f0;border-radius:12px;font-size:16px;outline:none}
input:focus{border-color:#3b82f6}
button{padding:12px 24px;background:#3b82f6;color:#fff;border:none;border-radius:12px;font-size:16px;cursor:pointer}
button:hover{background:#2563eb}
.results{display:grid;grid-template-columns:repeat(auto-fit,minmax(350px,1fr));gap:16px}
.card{background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:16px}
.card h3{font-size:14px;color:#64748b;margin-bottom:8px;padding-bottom:8px;border-bottom:1px solid #f1f5f9}
.card .content{font-size:14px;line-height:1.6;color:#334155;white-space:pre-wrap}
.card .loading{color:#94a3b8}
🤖 AI 聚合搜索
🔍 搜索
async function search(){
const q=document.getElementById('q').value.trim();
if(!q)return;
document.getElementById('results').innerHTML='DeepSeek⏳ 搜索中...';
const resp=await fetch('/api/search?q='+encodeURIComponent(q));
const reader=resp.body.getReader();
const decoder=new TextDecoder();
let buffer='',content='';
while(true){
const{value,done}=await reader.read();
if(done)break;
buffer+=decoder.decode(value,{stream:true});
const lines=buffer.split('\\n');
buffer=lines.pop();
for(const line of lines){
if(line.startsWith('data: ')){
const d=line.slice(6);
if(d==='[DONE]')continue;
content+=d;
document.getElementById('results').innerHTML=
'DeepSeek'+content+'';
}
}
}
}
"""
@app.get("/", response_class=HTMLResponse)
async def index():
return HTML
@app.get("/api/search")
async def search(q: str):
async def generate():
async with aiohttp.ClientSession() as session:
async with session.post(
SEARCH_ENGINES["deepseek"]["url"],
headers=SEARCH_ENGINES["deepseek"]["headers"],
json=SEARCH_ENGINES["deepseek"]["body_template"](q),
) as resp:
async for line in resp.content:
text = line.decode().strip()
if text.startswith("data: "):
chunk = text[6:]
if chunk != "[DONE]":
yield f"data: {chunk}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(generate(), media_type="text/event-stream")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, port=8000)
使用方式
pip install fastapi aiohttp uvicorn
python metasearch.py
# 打开 http://localhost:8000
# 输入问题 → 流式展示结果
扩展更多引擎
SEARCH_ENGINES["perplexity"] = {
"name": "Perplexity",
"url": "https://api.perplexity.ai/chat/completions",
...
}
总结
一个轻量的 AI 聚合搜索页面,核心三步:FastAPI 做后端、SSE 流式输出、前端一个页面搞定。可以扩展接多个 AI 搜索 API 做对比展示。
本文是 《AI 开发者工具链实战》 系列的第 9 篇。
本文由 Zyentor(智元界)原创发布