👋大家好,好久未更新掘金了,最近一直在自研自己的AI产品-帝阅DeepRead,没有时间写博客。最近在研发新功能的时候,需要用上AI搜索引擎,经过多日的摸索,找到一个比较合适又简单的AI搜索引擎的方式。
那今天就来唠唠如何实现这个AI搜索引擎的 😊
一.AI搜索引擎设计
1. AI搜索引擎与传统搜索引擎的区别
传统搜索引擎主要依赖于关键词匹配,用户需要输入准确的关键词才能获得相关的搜索结果。 而AI搜索引擎通过深度学习和自然语言处理技术,具备了强大的语义理解能力。 它能够更好地理解用户的问题,甚至可以理解上下文,从而提供更准确的搜索结果
简单来说,AI搜索引擎是对传统搜索引擎的一层封装,利用大模型的语义理解能力将搜索引擎提供的信息进行归纳总结,直接提供给人们最期望的答案。
2.利用LLM Tool和Prompt的能力制作Agent(智能体)
目前LLM Agent本质上都是使用了Prompt+Tool两个方面的能力 以我们AI搜索引擎 Agent为例:
- 将根据用户搜索关键词,去调用Tool收集信息
- 将收集到的信息通过与system prompt等提示词组合,输入到大模型
- 大模型将依据收集到的上下文,提供更符合用户要求的搜索答案
二.AI搜索引擎的实现
介绍完一些基础信息,我们来讲一下我是如何实现AI搜索引擎的
1.选择一个合适的搜索引擎工具
上面介绍的AI搜索引擎本质上还需要依赖传统搜索引擎,传统的搜索引擎就有很多了,比如 Bing、Chrome、百度等 我们该如何选择呢?
来,我们今天的主角SearXNG隆重登场~
以下内容摘取自 SearXNG 官方文档 https://docs.searxng.org/
SearXNG 是一个免费的互联网元搜索引擎,它汇总了来自 70 多个搜索服务的结果。用户既不被跟踪也不被分析。
SearXNG 如何保护隐私:
无论实例的类型(私有、公共)如何,SearXNG 都以多种方式保护其用户的隐私。从搜索请求中删除私人数据有三种形式:
- 从前往搜索服务的请求中删除私人数据
- 不通过搜索服务(例如广告)转发来自第三方服务的任何内容
- 从转到结果页面的请求中删除私有数据
删除私人数据意味着不向外部搜索引擎发送 cookie 并为每个请求生成随机浏览器配置文件。因此,公共或私有实例是否处理请求并不重要,因为它在两种情况下都是匿名的。IP 地址将是实例的 IP。
与大多数搜索服务不同,SearXNG 不提供广告或跟踪内容。因此,私人数据不会转发给可能将其货币化的第三方。除了保护用户免受搜索服务之外,引用页面和搜索查询都对访问的结果页面隐藏。
免费、私有、隐私保护,都是SearXNG的优点,我们只需要自己搭建一个环境就能拥有一个自己专属的搜索引擎,还有一个好处就是我们无需对接多个搜索引擎和注册多个账号去获取API,国内注册谷歌和Bing的账号还需要信用卡(实在麻烦)
所以我们就选择SearXNG作为我们搜索引擎工具
2. 部署SearXNG
由于 SearXNG 需要访问外网,建议部署选择外网服务器,以下部署示例选择以腾讯云轻量服务器-Centos系统为例
根据 github.com/searxng/sea... 教程,按照以下操作,容器化部署SearXNG
sh
# 拉取代码
git clone https://github.com/searxng/searxng-docker.git
cd searxng-docker
# 修改域名和录入邮箱
vim .env
# 启动docker
docker compose up
查看容器起来后,浏览器访问输入的域名或地址
显示搜索页面说明部署成功 👏
3.使用LangChain构建AI搜索引擎Agent
LangChain自不必说,目前最大的LLM 框架,用它来构建AI应用效率很高
3.1 实现SearXNG搜索工具
以下是基于LangChain BaseRetriever简单封装了SearXNG搜索信息召回类
python
class SearxSearchRetriever(BaseRetriever):
search: Optional[SearxSearchWrapper] = None
num_search_results = 3
def _get_relevant_documents(
self, query: str, *, run_manager: CallbackManagerForRetrieverRun
) -> List[Document]:
if not os.environ.get("SEARX_HOST", None):
raise Exception("No SEARX_HOST provided")
if not self.search:
self.search = SearxSearchWrapper()
# Get search questions
print("Generating questions for Searx Search ...")
# Get urls
print("Searching for relevant urls...")
urls_to_look = []
search_results = self.search.results(
query,
language="zh-CN",
safesearch=1,
categories="general",
engines=["bing", "brave", "duckduckgo"],
num_results=self.num_search_results,
)
print("Searching for relevant urls...")
print(f"Search results: {search_results}")
for res in search_results:
if res.get("link", None):
urls_to_look.append(res["link"])
print(urls_to_look)
loader = AsyncHtmlLoader(urls_to_look)
html2text = Html2TextTransformer()
print("Indexing new urls...")
docs = loader.load()
docs = list(html2text.transform_documents(docs))
print("Get html docs done...")
for i in range(len(docs)):
if search_results[i].get("title", None):
docs[i].metadata["title"] = search_results[i]["title"]
return docs
3.2 文档信息过滤
搜索引擎得到的信息往往比较多,可以通过TextSplitter和Embeddings进行文档分割和相似性过滤,最后得到不同的关键搜索信息
这些LangChain都已经封装好现成的类与方法,我们直接用就行
python
embeddings = OpenAIEmbeddings()
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=20)
relevance_filter = EmbeddingsFilter(embeddings=embeddings, similarity_threshold=0.8)
pipeline_compressor = DocumentCompressorPipeline(
transformers=[splitter, relevance_filter]
)
base_searx_retriever = SearxSearchRetriever()
searx_retriever = ContextualCompressionRetriever(
base_compressor=pipeline_compressor, base_retriever=base_searx_retriever
)
searx_retriever 就是我们最终的搜索召回工具
3.3将召回的搜索信息组合成Prompt,发送给大模型
以下是参考Prompt
markdown
You are an expert researcher and writer, tasked with answering any question.
Generate a comprehensive and informative, yet concise answer of 250 words or less for the \
given question based solely on the provided search results (URL and content). You must \
only use information from the provided search results. Use an unbiased and \
journalistic tone. Combine search results together into a coherent answer. Do not \
repeat text. Cite search results using [${{number}}] notation. Only cite the most \
relevant results that answer the question accurately. Place these citations at the end \
of the sentence or paragraph that reference them - do not put them all at the end. If \
different results refer to different entities within the same name, write separate \
answers for each entity. If you want to cite multiple results for the same sentence, \
format it as `[${{number1}}] [${{number2}}]`. However, you should NEVER do this with the \
same number - if you want to cite `number1` multiple times for a sentence, only do \
`[${{number1}}]` not `[${{number1}}] [${{number1}}]`
You should use bullet points in your answer for readability. Put citations where they apply \
rather than putting them all at the end.
If there is nothing in the context relevant to the question at hand, just say "Hmm, \
I'm not sure." Don't try to make up an answer.
Anything between the following `context` html blocks is retrieved from a knowledge \
bank, not part of the conversation with the user.
<context>
{context}
<context/>
REMEMBER: If there is no relevant information within the context, just say "Hmm, I'm \
not sure." Don't try to make up an answer. Anything between the preceding 'context' \
html blocks is retrieved from a knowledge bank, not part of the conversation with the \
user. The current date is {current_date}.
3.4 详细交互图
综合以上三点,形成我们SearXNG+LangChain的实现的AI搜索引擎完整详细交互图
4.最终效果
4.1 简单网页交互
可以展示搜索信息来源与大模型综合回答情况
4.2 LangSmith 调试跟踪情况
LangSmith可以展示大模型与工具的调用链帮助我们直观了解大模型工作流程,我们看一下我们实现的AI搜索引擎的调用情况
三.总结
这篇文章简单介绍了AI搜索引擎的原理,介绍了通过SearXNG+LangChain的实现的AI搜索引擎的方法。 由于在这篇文章写作时,相关代码还在完善中,如果大家觉得这个有帮助,可以点赞收藏噢,如果有很多朋友需要的话,我后续会将代码开源放到github。
后续完整版的AI搜索引擎我会上架到我自研的AI产品 帝阅DeepRead
「帝阅」
是一款个人专属知识管理与创造的 AI Native 产品
为用户打造一位专属的侍读助理,帮助提升用户获取知识效率和发挥创造力
让用户更好地去积累知识、管理知识、运用知识
🎉 感谢大家支持~ 也欢迎大家在评论区多多与我留言与讨论AI相关的产品与技术~