#我的鸿蒙开发手记# 打造本地智能搜索体验:从 SearxNG 到 HarmonyOS 的全栈实践 原创 精华

SoraLuna
发布于 2025-5-6 21:37
浏览
1收藏

在大语言模型和智能体应用快速发展的当下,“如何构建自主可控的搜索引擎”正成为越来越多开发者关注的话题。如果能将开源搜索引擎与本地知识库整合,再无缝接入鸿蒙 App,将极大提升产品的智能性与交互体验。

本篇将带你完成一次从“本地部署”到“前端交互”的全流程实践,涵盖:

  • 使用 Docker 快速部署 SearxNG 搜索服务
  • 用 Python 构建聚合服务端,融合网络与本地知识
  • 基于 ArkTS 实现 HarmonyOS 前端搜索界面

最终产出是一个支持自然语言检索、JSON 标准输出、前后端解耦、即插即用的本地智能搜索系统


一、部署 SearxNG:启动你的本地元搜索引擎

SearxNG 是一个可自托管的元搜索引擎,聚合了多个公开搜索源,支持 JSON 接口输出,非常适合智能体插件、LLM 工具链对接使用。

✅ 部署要求:

🛠️ 快速部署步骤:

# 创建目录
mkdir ~/searxng && cd ~/searxng

# 编写 settings.yml,启用 JSON 输出与国内搜索源
# 示例内容见文末附录

# 创建 docker-compose.yml
# 示例内容见文末附录

# 启动服务
docker compose up -d

浏览器访问 http://localhost:8090,若能看到搜索页面即部署成功。

📸 图1:SearxNG 首页界面
#我的鸿蒙开发手记# 打造本地智能搜索体验:从 SearxNG 到 HarmonyOS 的全栈实践-鸿蒙开发者社区

接口调用测试:

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 聚合搜索服务并测试调用结果
#我的鸿蒙开发手记# 打造本地智能搜索体验:从 SearxNG 到 HarmonyOS 的全栈实践-鸿蒙开发者社区


三、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”并触发搜索
#我的鸿蒙开发手记# 打造本地智能搜索体验:从 SearxNG 到 HarmonyOS 的全栈实践-鸿蒙开发者社区

📸 图4:返回结果列表展示聚合内容
#我的鸿蒙开发手记# 打造本地智能搜索体验:从 SearxNG 到 HarmonyOS 的全栈实践-鸿蒙开发者社区

💡 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 中实现这一能力了吗?👨‍💻📱

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
1
收藏 1
回复
举报
1条回复
按时间正序
/
按时间倒序
SoraLuna
SoraLuna
回复
2025-5-10 18:17:17
回复
    相关推荐