AI 文摘

大模型AI生成式搜索的简约实战:从PerplexityAI到基于duckduckgo+chatglm2-6b的搜索实现





作者: 老刘说NLP 来源: 老刘说NLP

今天是2024年1月16日,星期一,北京,天气晴,我们再来看看一些有趣的话题。

最近AI搜索受到大家关注,这种生成式AI搜索工具,使用OpenAI的GPT-4等基础语言模型和互联网上的最新信息,不仅能提供答案,还能提供答案来源的参考信息,解决用于训练模型的训练数据可能过时的局限性。通过返回用于提供答案的来源,以验证其准确性,最终解决语言模型生成错误答案的问题。

实际上,我们在之前的文章2023-04-05的**《如何解决类ChatGPT生成的时效性问题:基于duckduckgo_search+GLM-6B路线的一个简单实验分析》** (https://mp.weixin.qq.com/s/77lY9ITSaC_SwdwyLiN17A)就讲过类似的事情。

例如,引入实体链接,增强实时搜索相关性,提升query命中率,引入搜索结果,丰富上下文,以此作为输入,增强生成准确性。

而与此相关的另一个话题是这类技术如何进行评估,有个文章《Evaluating Verifiability in Generative Search Engines》(https://arxiv.org/pdf/2304.09848.pdf)从文本流畅度、感知有效性、引文回忆率和引文精确度四个角度对Bing Chat, NeevaAI, perplexity.ai和YouChat进行了评估。

本文主要介绍perplexity的简单实现以及基于duckduckgo+chatglm2-6b的搜索实现两个话题进行介绍,供大家一起参考。

对了,我们在文章《MOE、RAG、大模型、知识图谱的那些事儿回放:老刘说NLP2024第一个半月及2023年年终技术总结》(https://mp.weixin.qq.com/s/81YfjuvdYwfSQmU-zFlrRQ)中已经开放了《老刘说NLP的2024第一讲:—MOE、RAG搜索增强及大模型进展那些事儿》、《老刘说NLP的2023年终总结:关于大模型和知识图谱的那些有趣的事儿》两个报告回放和ppt,感兴趣的可以加入社区一起看看,干货满满。 ‍‍‍‍‍‍‍‍‍‍‍‍

一、perplexity的简单实现

PerplexityAI使用基础语言模型(如OpenAI的GPT-4)和互联网上的最新信息,它不仅能提供答案,还能提供这些答案的来源参考。

image

其功能界面如图所示,正如文章(https://mp.weixin.qq.com/s/0zUQFixXQ9vwWTCIR_b1iA)所提到的,与传统搜索引擎相比,回答引擎主要在以下几个方面进行了优化:理解用户问题的能力、总结搜索结果的能力、保留搜索结果索引的能力,以及扩展用户问题的能力。这些优化旨在降低用户使用门槛,节省用户在不同网页上搜索和浏览的时间,确保搜索结果的可靠性,同时为用户提供深入挖掘问题的能力。

image

其本质上就是做了一次搜索增强问答,开源项目地址:https://github.com/mklarqvist/ai-playground/blob/main/perplexity-clone/perplexity_clone.ipynb 给出了一个简单实现。

这就解决了语言模型生成错误答案的问题,工作流程如下:

1、用户提出问题

query = 'history of the human genome project' # The query to search Google for and ask the AI about  

2、使用该问题进行谷歌搜索

response = requests.get(f"https://www.google.com/search?q={query}") # Make the request  

3、下载前k个搜索结果或最相关的网页

soup = BeautifulSoup(response.text, "html.parser") # Parse the HTML  
links = soup.find_all("a") # Find all the links in the HTML  
# loop over `links` and keep only the one that have the href starting with "/url?q="  
urls = []  
for l in [link for link in links if link["href"].startswith("/url?q=")]:  
    # get the url  
    url = l["href"]  
    # remove the "/url?q=" part  
    url = url.replace("/url?q=", "")  
    # remove the part after the "&sa=..."  
    url = unquote(url.split("&sa=")[0])  
    # special case for google scholar  
    if url.startswith("https://scholar.google.com/scholar_url?url=http"):  
        url = url.replace("https://scholar.google.com/scholar_url?url=", "").split("&")[0]  
    elif 'google.com/' in url: # skip google links  
        continue  
    if url.endswith('.pdf'): # skip pdf links  
        continue  
    if '#' in url: # remove anchors (e.g. wikipedia.com/bob#history and wikipedia.com/bob#genetics are the same page)  
        url = url.split('#')[0]  
    # print the url  
    urls.append(url)

####4、通过LangChain将原始HTML数据转换为可用格式

from readabilipy import simple_json_from_html_string # Required to parse HTML to pure text  
from langchain.schema import Document # Required to create a Document object  
def scrape_and_parse(url: str) -> Document:  
    """Scrape a webpage and parse it into a Document object"""  
    req = requests.get(url)  
    article = simple_json_from_html_string(req.text, use_readability=True)  
    # The following line seems to work with the package versions on my local machine, but not on Google Colab  
    # return Document(page_content=article['plain_text'][0]['text'], metadata={'source': url, 'page_title': article['title']})  
    return Document(page_content='\n\n'.join([a['text'] for a in article['plain_text']]), metadata={'source': url, 'page_title': article['title']})  
# It's possible to optitimize this by using asyncio, but it's not necessary for this example  
documents = [scrape_and_parse(f) for f in urls] # Scrape and parse all the urls  

5、将所有文档分割成1000个字符的chunk块

from langchain.text_splitter import CharacterTextSplitter  
text_splitter = CharacterTextSplitter(separator=' ', chunk_size=1000, chunk_overlap=200)  
texts = text_splitter.split_documents(documents)  

6、计算每个文档块的嵌入,并将其存储在向量存储区(chromadb)中

from langchain.embeddings.openai import OpenAIEmbeddings  
# Get your own APU key at https://platform.openai.com/account/api-keys  
OPENAI_API_KEY = 'REPLACE_WITH_YOUR_KEY' # Replace with your own OpenAI API key  
embeddings = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY)  
from langchain.vectorstores import Chroma  
docsearch = Chroma.from_documents(texts, embeddings)  

7、使用步骤1中的用户问题和所有通过LangChain获取的网络数据创建提示

query = "Who were the main players in the race to complete the human genome? And what were their approaches? Give as much detail as possible."  

8、查询OpenAI模型以生成答案

from langchain.llms import OpenAIChat # Required to create a Language Model  
# Pick an OpenAI model  
llm = OpenAIChat(model_name='gpt-3.5-turbo', openai_api_key=OPENAI_API_KEY)  
from langchain import  VectorDBQA # Required to create a Question-Answer object using a vector  
import pprint # Required to pretty print the results  
# Stuff all the information into a single prompt (see https://docs.langchain.com/docs/components/chains/index_related_chains#stuffing)  
qa = VectorDBQA.from_chain_type(llm=llm, chain_type="stuff", vectorstore=docsearch, return_source_documents=True)  
query = "Who were the main players in the race to complete the human genome? And what were their approaches? Give as much detail as possible."  
result = qa({"query": query})  
pprint.pprint(result)  

9、识别有助于生成答案的文档,并将其作为参考材料返回

{'query': "What happened to Craig Venter's company following the completion of "  
          'the human genome project? Give as much detail as possible.',  
 'result': 'Following the completion of the human genome project, Craig '  
           "Venter's company, Celera Genomics, faced a decision on what type "  
           'of company it would become. It added sequences from three '  
           'different mouse strains to its database and briefly ventured into '  
           'proteomics. However, Venter resigned as CEO in January 2002, and '  
           'the company decided to focus on drug discovery rather than '  
           'information. Despite being timed to coincide with the celebrations '  
           'of the 50th anniversary of the Watson-Crick discovery of the '  
           'double-helical structure of DNA, there was less fanfare '  
           'surrounding the official date of completion of the HGP in April '  
           '2003. Celera remained a threat, as the validity of the WGS '  
           'sequencing approach was demonstrated in March 2000 when Celera and '  
           'the Berkeley Drosophila Genome Project published the sequence of '  
           'D. melanogaster. However, the rivalry between Celera and the HGP '  
           'ended when they joined forces, thus speeding up the completion of '  
           'the rough draft sequence of the human genome.',  
 'source_documents': [Document(page_content='NIH scientist J. Craig Venter, began to compete with and potentially undermine the publicly funded HGP. At the heart of the competition was the prospect of gaining control over potential patents on the genome sequence, which was considered a pharmaceutical treasure trove. Although the legal and financial reasons remain unclear, the rivalry between Celera and the NIH ended when they joined forces, thus speeding completion of the rough draft sequence of the human genome. The completion of the rough draft was announced in June 2000 by Collins and Venter. For the next three years, the rough draft sequence was refined, extended, and further analyzed, and in April 2003, coinciding with the 50th anniversary of the publication that described the double-helical structure of DNA, written by British biophysicist Francis Crick and American geneticist and biophysicist James D. Watson, the HGP was declared complete. Britannica Quiz Genetics Quiz Science behind the HGP To appreciate the magnitude,', metadata={'source': 'https://www.britannica.com/event/Human-Genome-Project', 'page_title': 'Human Genome Project (HGP) | History, Timeline, & Facts'})  

二、基于duckduckgo+chatglm2-6b的搜索实现

实时性,一直是大家对chatgpt这类应用发问较多的问题,而通过借助搜索引擎的结果,我们可以在此基础上,通过搜索的结果进行简单拼接、摘要、截断等方式,快速获得一个较好的结果。

1、实现思想

我们可以基于glm6b来搭建一个服务,直接将该服务的接口作为chatgpt生成答案的平替。ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型,基于 General Language Model (GLM) 架构,具有 62 亿参数。

结合模型量化技术,用户可以在消费级的显卡上进行本地部署(INT4 量化级别下最低只需 6GB 显存)。 ChatGLM-6B 使用了和 ChatGPT 相似的技术,针对中文问答和对话进行了优化。

地址:https://github.com/THUDM/ChatGLM-6B

思路很简单:首先,我们给定一个query,调用duckduckgo_search,得到实时结果后,调用glm6b的生成服务,得到最终答案。

整个实现思路,很朴素,但核心就两个半,一个是底层大模型,另一个是实时搜索。还有半个,是对应的prompt。

2、chatglm-6b搭建服务

#!/usr/bin/env python  
# -*- coding: UTF-8 -*-  
import os  
import json  
from flask import Flask, request  
from transformers import AutoModel, AutoTokenizer  
  
os.environ["CUDA_VISIBLE_DEVICES"] = "3"  
tokenizer = AutoTokenizer.from_pretrained(r"chatglm-6b", trust_remote_code=True,  
                                          revision="main")  
model = AutoModel.from_pretrained(r"chatglm-6b", trust_remote_code=True,  
                                  revision="main").half().quantize(4).cuda()  
model = model.cuda()  
model = model.eval()  
app = Flask(import_name=__name__)  
  
def predict(input_string, history):  
    if history is None:  
        history = []  
    try:  
        response, history = model.chat(tokenizer, input_string, history)  
        return {"msg": "success", "code": 200, "response": response}  
    except Exception as error:  
        return {"msg": "error", "code": 500, "response": error}  
  
@app.route("/chat_with_history", methods=["POST", "GET"])  
def chat_with_history():  
    data = json.loads(request.data)  
    input_text = data['input_text']  
    history = data.get("history", None)  
    if history is not None:  
        history = json.loads(history)  
    return predict(input_text, history)  
  
if __name__ == '__main__':  
    app.run(port=12345, debug=True, host='0.0.0.0')  # 如果是0.0.0.0,则可以被外网访问  

3、使用duckduckgo_search输出结果,完成实时搜索

我们以实时的百度热搜,进行时效性检测,下面是具体热搜榜单:  
  
图片  
下面是具体的结果,效果看起来还不错,本质上是一个MRC任务:  

enter an query to search:马克龙在什么时候来北京了最近  
query: 马克龙在什么时候来北京了最近  
answer: 马克龙于 2023 年 4 月 5 日至 7 日对中国进行国事访问。  

enter an query to search:谁最近停售了张继科肖像产品  
query: 谁最近停售了张继科肖像产品  
answer: 蝴蝶乒乓球用品公司最近停售了张继科肖像产品。  

enter an query to search:特朗普认罪了么,最高会判几年  
query: 特朗普认罪了么,最高会判几年  
answer: 特朗普没有认罪,并且这些指控可能会导致他被判处136年的监禁。  

enter an query to search:张继科最近犯了啥事  
query: 张继科最近犯了啥事  
answer: 张继科最近犯了一些法律事件,其中包括恋爱期间劈腿、涉赌、泄露他人隐私视频以及欠下巨额债务,其中债主拿着他的前女友的私密视频去抵债,景甜对此表示愤怒并告了这位债主,这位债主目前还在服刑中。  

enter an query to search:北京最新天气  
query: 北京最新天气  
answer: 根据最新的天气预报,北京最新天气为多云转晴,最高气温为12°C,最低气温为3°C,风力较小,只有2、3级。  

enter an query to search:今天几号  
query: 今天几号  
answer: 今天是 2023 年 4 月 4 日,是农历闰二月十四,同时也是阳历的星期四。  

enter an query to search:当前黄金价格多少  
query: 当前黄金价格多少  
answer: 根据提供的信息,今天是2023年4月4日,中国上海黄金交易所的黄金价格是439.6元人民币/克。这是裸黄金价格,商场的黄金首饰价格会在此基础上加上加工费等。按当前的汇率计算,1盎司黄金的价格约为1990.3美元。因此,当前黄金价格是439.6元人民币/克,1盎司黄金的价格约为1990.3美元。  

enter an query to search:马克龙访华,有哪三点值得关注  
query: 马克龙访华,有哪三点值得关注  
answer: 马克龙访华,值得关注的三点包括:  
1. 中法合作新成果:这是马克龙首次访华,也是中法两国元首继去年G20巴厘岛峰会后再一次面对面对话。双方将继续就共同关心的国际和地区问题进行沟通和协商,推动中法合作不断迈上新台阶。  
2. 经贸务实合作:马克龙此次访华将重点探讨双方合作的未来规划和经贸务实合作,包括贸易、投资、知识产权保护等领域。双方还将继续深化中法物流合作,促进数字经济等领域合作。  
3. 应对全球挑战:马克龙此前表示,应对全球挑战是中法两国共同使命。他此次访华将重点探讨应对气候变化、难民问题、恐怖主义等全球挑战,以及如何在多边框架内应对全球性问题。双方还将继续就非洲发展、国际合作等问题进行沟通和协商。  

总结

本文主要介绍了perplexity的简单实现、基于duckduckgo+chatglm2-6b的搜索实现,感兴趣的可以进一步看看其中的链接深入扩展阅读。

我们在文章《MOE、RAG、大模型、知识图谱的那些事儿回放:老刘说NLP2024第一个半月及2023年年终技术总结》(https://mp.weixin.qq.com/s/81YfjuvdYwfSQmU-zFlrRQ)中已经开放了《老刘说NLP的2024第一讲:—MOE、RAG搜索增强及大模型进展那些事儿》、《老刘说NLP的2023年终总结:关于大模型和知识图谱的那些有趣的事儿》两个报告回放和ppt,感兴趣的可以加入社区一起看看,干货满满。

参考文献

1、https://github.com/mklarqvist/ai-playground/blob/main/perplexity-clone/perplexity_clone.ipynb

2、https://mp.weixin.qq.com/s/77lY9ITSaC_SwdwyLiN17A

3、https://arxiv.org/pdf/2304.09848.pdf

关于我们

老刘,刘焕勇,NLP开源爱好者与践行者,主页:https://liuhuanyong.github.io。

老刘说NLP,将定期发布语言资源、工程实践、技术总结等内容,欢迎关注。

对于想加入更优质的知识图谱、事件图谱、大模型AIGC实践、相关分享的,可关注公众号,在后台菜单栏中点击会员社区->会员入群加入

更多AI工具,参考Github-AiBard123国内AiBard123

可关注我们的公众号:每天AI新工具