#我的鸿蒙开发手记# 打造本地智能搜索体验:从 SearxNG 到 HarmonyOS 的全栈实践 原创 精华
在大语言模型和智能体应用快速发展的当下,“如何构建自主可控的搜索引擎”正成为越来越多开发者关注的话题。如果能将开源搜索引擎与本地知识库整合,再无缝接入鸿蒙 App,将极大提升产品的智能性与交互体验。
本篇将带你完成一次从“本地部署”到“前端交互”的全流程实践,涵盖:
- 使用 Docker 快速部署 SearxNG 搜索服务
- 用 Python 构建聚合服务端,融合网络与本地知识
- 基于 ArkTS 实现 HarmonyOS 前端搜索界面
最终产出是一个支持自然语言检索、JSON 标准输出、前后端解耦、即插即用的本地智能搜索系统。
一、部署 SearxNG:启动你的本地元搜索引擎
SearxNG 是一个可自托管的元搜索引擎,聚合了多个公开搜索源,支持 JSON 接口输出,非常适合智能体插件、LLM 工具链对接使用。
✅ 部署要求:
- macOS 系统(Apple Silicon / Intel)
- 安装 Docker 与 Docker Compose
🛠️ 快速部署步骤:
# 创建目录
mkdir ~/searxng && cd ~/searxng
# 编写 settings.yml,启用 JSON 输出与国内搜索源
# 示例内容见文末附录
# 创建 docker-compose.yml
# 示例内容见文末附录
# 启动服务
docker compose up -d
浏览器访问 http://localhost:8090
,若能看到搜索页面即部署成功。
📸 图1:SearxNG 首页界面
接口调用测试:
curl "http://localhost:8090/search?q=鸿蒙系统&format=json"
二、Python 实现聚合服务:本地知识库 + 网络搜索
通过 Flask + FAISS + SentenceTransformers 构建一个双通道搜索接口:
/search_web
:封装 SearxNG 网络聚合查询/search_kb
:基于向量化检索本地知识库文档/search
:聚合上述两类结果并统一格式返回
服务运行后,访问:
curl "http://localhost:5001/search?q=HarmonyOS"
📸 图2:终端中启动 Python 聚合搜索服务并测试调用结果
三、ArkTS 构建鸿蒙前端界面:即输即搜,动态展示
HarmonyOS 的 ArkTS 框架提供了现代化 UI 构建能力,适合开发轻量高效的前端页面。
本部分构建一个聚合搜索界面,用户输入关键词后实时调用本地服务,并渲染结果列表。
🔧 页面组件结构:
SearchApp/
├── pages/Index.ets # 主页面
├── components/SearchDisplay.ets # 结果展示组件
├── services/SearchService.ets # 请求与解析逻辑
├── utils/HttpClient.ets # 通用请求封装
├── types/SearchTypes.ets # 类型定义
├── configs/Config.ets # API URL 配置
📸 图3:用户在鸿蒙 App 中输入关键词“HarmonyOS”并触发搜索
📸 图4:返回结果列表展示聚合内容
💡 ArkTS 关键代码实现:
配置文件(Config.ets)
export const config = {
searchApiUrl: "http://localhost:5001/search"
}
类型定义(SearchTypes.ets)
export interface SearchResponse {
title: string
content: string
url: string
}
export interface SearchResultList {
results: SearchResponse[]
}
服务调用逻辑(SearchService.ets)
import { httpRequestText } from '../utils/HttpClient'
import { http } from '@kit.NetworkKit'
import { SearchResponse, SearchResultList } from '../types/SearchTypes'
export class SearchService {
constructor(private apiUrl: string) {}
public async search(query: string): Promise<SearchResponse[]> {
const url = `${this.apiUrl}?q=${encodeURIComponent(query)}`
let buffer = ''
await httpRequestText(url, http.RequestMethod.GET, '', 60000, chunk => buffer += chunk)
const parsed = JSON.parse(buffer) as SearchResultList
return parsed.results
}
}
结果展示组件(SearchDisplay.ets)
import { SearchResponse } from '../types/SearchTypes'
@Component
export struct SearchDisplay {
private item!: SearchResponse
build() {
Column() {
Text(this.item.title).fontSize(18).fontWeight('bold').margin({ bottom: 4 })
Text(this.item.content).fontSize(14).margin({ bottom: 4 })
Text(this.item.url).fontSize(12).fontColor('#888')
}
.padding(10)
.backgroundColor('#F5F5F5')
.margin({ bottom: 10 })
}
}
主页面实现(Index.ets)
import { SearchDisplay } from '../components/SearchDisplay'
import { config } from '../configs/Config'
import { SearchService } from '../services/SearchService'
import { SearchResponse } from '../types/SearchTypes'
@Entry
@Component
export struct Index {
@State query: string = 'HarmonyOS'
@State results: SearchResponse[] = []
async fetchData(): Promise<void> {
const service = new SearchService(config.searchApiUrl)
this.results = await service.search(this.query)
}
build() {
Column() {
TextInput({ text: this.query, placeholder: '输入关键词' })
.onChange(value => this.query = value)
.width('match_parent')
.height(50)
.margin({ bottom: 12 })
Button('搜索')
.width('match_parent')
.height(50)
.onClick(() => this.fetchData())
.margin({ bottom: 20 })
ForEach(this.results, item => SearchDisplay({ item }))
}
.padding({ left: 20, right: 20, top: 20 })
}
}
四、实用价值与扩展方向
✅ 本项目的价值:
- 🔧 可脱离云端,构建本地智能搜索引擎
- 🔄 灵活扩展,支持自定义搜索源、本地知识库内容
- 🧠 支持 Dify、Agent 插件等工具集成
- 🧩 提供 HarmonyOS 原生前端界面,适配国产生态
📈 下一步可拓展功能:
- 分页加载 / 无限滚动
- 多语言支持与翻译结果聚合
- 接入语音识别 / 语音播报,实现多模态交互
- 接入向量数据库(如 Qdrant、Weaviate)提升扩展性
- ✅ 使用 ArkTS 状态管理实现搜索结果缓存与结果分类视图
- ✅ 接入统一样式表及图标集,优化跨端体验与样式一致性
- ✅ 为每个结果项支持点击跳转及复制分享功能,提高可用性
附录:关键文件示例
settings.yml
use_default_settings: true
search:
formats:
- html
- json
engines:
- name: baidu
engine: baidu
categories: [general]
disabled: false
- name: bing
disabled: false
- name: bilibili
engine: bilibili
shortcut: bil
disabled: false
docker-compose.yml
version: '3.7'
services:
searxng:
image: searxng/searxng:latest
container_name: searxng
ports:
- "8090:8080"
volumes:
- ./settings.yml:/etc/searxng/settings.yml
environment:
- BASE_URL=http://localhost:8090
restart: unless-stopped
结语
这不仅是一个技术实践项目,更是一种探索本地智能交互未来形态的尝试。当模型不再完全依赖外部知识源,而是结合实时搜索与本地知识,AIGC 的能力边界也将随之扩展。
你准备好在自己的鸿蒙 App 中实现这一能力了吗?👨💻📱
SearxNG完整部署:
https://blog.csdn.net/weixin_44217688/article/details/147835360