AI大模型探索之路-实战篇:智能化IT领域搜索引擎之知乎网站数据获取(流程优化)

系列篇章💥

No.文章
1AI大模型探索之路-实战篇:智能化IT领域搜索引擎的构建与初步实践
2AI大模型探索之路-实战篇:智能化IT领域搜索引擎之GLM-4大模型技术的实践探索
3AI大模型探索之路-实战篇:智能化IT领域搜索引擎之知乎网站数据获取(初步实践)
4AI大模型探索之路-实战篇:智能化IT领域搜索引擎之知乎网站数据获取(函数封装)
5AI大模型探索之路-实战篇:智能化IT领域搜索引擎之知乎网站数据获取(流程优化)
6AI大模型探索之路-实战篇:智能化IT领域搜索引擎之github网站在线搜索
7AI大模型探索之路-实战篇:智能化IT领域搜索引擎之HuggingFace网站在线搜索

目录

  • 系列篇章💥
  • 一、前言
  • 二、总体概览
  • 三、流程优化
    • 1、文件名优化
    • 2、重新改造搜索服务
    • 3、构建判别模型
    • 4、搜索词优化
    • 5、外部函数流程优化
  • 四、全流程代码总结
    • 1、大模型客户端创建
    • 2、google搜索函数
    • 3、创建文件名称函数
    • 4、知乎内容查询函数
    • 5、大模型判断函数
    • 6、关键词获取函数
    • 7、问题答案获取函数
    • 8、funcation calling函数信息生成器
    • 9、大模型调用函数
    • 10、最外层的结果查询函数
  • 结语


一、前言

在上一篇文章中,我们对智能搜索中涉及的核心函数进行了精心的封装,为智能化IT领域搜索引擎的实现奠定了坚实基础。本文将致力于智能搜索流程中相关函数和工具的进一步优化与整理,旨在提升整个搜索引擎的效率和用户体验。

二、总体概览

本章将重点关注智能搜索流程的优化,通过简化函数调用流程、消除冗余代码、优化算法效率等手段,进一步提升搜索引擎的性能。同时,我们将对使用的工具方法进行改造升级,确保它们能够更好地支持当前的搜索功能。

三、流程优化

在流程优化环节,我们将对数据获取、处理、索引和搜索等关键环节进行细致入微的调整。通过采用更高效的数据结构、更先进的算法和更合理的系统架构,我们希望能够在保证搜索准确性的前提下,大幅度提高搜索速度,降低系统资源消耗。

1、文件名优化

文件名里有特殊字符的,在创建文件的时候会创建失败

def windows_create_name(s, max_length=255):
    """
    将字符串转化为符合Windows文件/文件夹命名规范的名称。
    
    参数:
    - s (str): 输入的字符串。
    - max_length (int): 输出字符串的最大长度,默认为255。
    
    返回:
    - str: 一个可以安全用作Windows文件/文件夹名称的字符串。
    """

    # Windows文件/文件夹名称中不允许的字符列表
    forbidden_chars = ['<', '>', ':', '"', '/', '\\', '|', '?', '*']

    # 使用下划线替换不允许的字符
    for char in forbidden_chars:
        s = s.replace(char, '_')

    # 删除尾部的空格或点
    s = s.rstrip(' .')

    # 检查是否存在以下不允许被用于文档名称的关键词,如果有的话则替换为下划线
    reserved_names = ["CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", 
                      "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"]
    if s.upper() in reserved_names:
        s += '_'

    # 如果字符串过长,进行截断
    if len(s) > max_length:
        s = s[:max_length]

    return s

文件名测试

# 测试
input_str = "这是一个包含不允许的字符,如 <, >, :, \, /, |, ?, * 等的很长的字符串..."
print(windows_create_name(input_str))

输出:

这是一个包含不允许的字符,如 _, _, _, _, _, _, _, _ 等的很长的字符串

2、重新改造搜索服务

def get_search_text(q, url):

    cookie = "q_c1=3c10baf5bd084b3cbfe7eece648ba243|1704976541000|1704976541000; _zap=086350b3-1588-49c4-9d6d-de88f3faae03; d_c0=AGCYfYvO_RePTvjfB1kZwPLeke_N5AM6nwo=|1704949678; _xsrf=qR1FJHlZ9dvYhhoj4SUj43SAIBUwPOqm; __snaker__id=wNWnamiJKBI0kzkI; q_c1=d44e397edb6740859a7d2a0d4155bfab|1706509753000|1706509753000; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1706509695,1706589529,1706765465,1708650963; z_c0=2|1:0|10:1713167971|4:z_c0|80:MS4xOGRHQVNnQUFBQUFtQUFBQVlBSlZUYjZqOTJaLXVDSjdRSmJKMHgyVEhxTE13UGN1TUJBdHZnPT0=|15b2c2ece393ac4ea374d9b36cde5af7304f8ee7632e060fe6835bfadb5e4132; KLBRSID=9d75f80756f65c61b0a50d80b4ca9b13|1713170212|1713167958"
    user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
    title = None
    
    code_ = False
    headers = {
        'authority': 'www.zhihu.com',
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'cache-control': 'max-age=0',
        'cookie': cookie,
        'upgrade-insecure-requests': '1',
        'user-agent':user_agent,
    }

    # 普通问答地址
    if 'zhihu.com/question' in url:
        res = requests.get(url, headers=headers).text
        res_xpath = etree.HTML(res)
        title = res_xpath.xpath('//div/div[1]/div/h1/text()')[0]
        text_d = res_xpath.xpath('//div/div/div/div[2]/div/div[2]/div/div/div[2]/span[1]/div/div/span/p/text()')
    
    # 专栏地址
    elif 'zhuanlan' in url:
        headers['authority'] = 'zhaunlan.zhihu.com'
        res = requests.get(url, headers=headers).text
        res_xpath = etree.HTML(res)
        title = res_xpath.xpath('//div[1]/div/main/div/article/header/h1/text()')[0]
        text_d = res_xpath.xpath('//div/main/div/article/div[1]/div/div/div/p/text()')
        code_ = res_xpath.xpath('//div/main/div/article/div[1]/div/div/div//pre/code/text()')  
            
    # 特定回答的问答网址
    elif 'answer' in url:
        res = requests.get(url, headers=headers).text
        res_xpath = etree.HTML(res)
        title = res_xpath.xpath('//div/div[1]/div/h1/text()')[0]
        text_d = res_xpath.xpath('//div[1]/div/div[3]/div/div/div/div[2]/span[1]/div/div/span/p/text()')

    if title == None:
        return None
    
    else:
        title = windows_create_name(title)

        # 创建问题答案正文
        text = ''
        for t in text_d:
            txt = str(t).replace('\n', ' ')
            text += txt

        # 如果有code,则将code追加到正文的追后面
        if code_:
            for c in code_:
                co = str(c).replace('\n', ' ')    
                text += co

        encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")     
        json_data = [
            {
                "link": url,
                "title": title,
                "content": text,
                "tokens": len(encoding.encode(text))
            }
        ]

        with open('./auto_search/%s/%s.json' % (q, title), 'w') as f:
            json.dump(json_data, f)

        return title

3、构建判别模型

为了让大模型调用流程更稳定,创建一个判别模型

import random
import string

def generate_random_key(length=30):
    return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(length))

定义模型判断函数

def identify_model(q):
    
    # 创建密钥
    sk = generate_random_key()
    
    # 调用模型进行判别
    response = client.chat.completions.create(
            model="glm-4",
            messages=[
                {"role": "system", "content": "你是一个用户问题判断器,专门用于判别你是否知道用户当前问题的答案。\
                如果不知道,请回答“%s”,若知道,请正常回答" % sk},
                {"role": "user", "content": "请问,GPT-3.5微调总共分为几步?"},
                {"role": "assistant", "content": "%s" % sk},
                {"role": "user", "content": q}
            ]
        )
    res = response.choices[0].message.content
    
    if sk in res or '对不起' in res or '抱歉' in res or '超出知识库' in res:
        return(True)
    else:
        return(res)

判断函数测试(询问大模型知识库知道的问题)

q = '请问什么是机器学习?'
print(identify_model(q))

输出:

机器学习是人工智能(AI)的一个分支,它赋予计算机从数据中学习的能力,使其能够通过经验改进处理任务的能力。机器学习算法利用统计学方法,让计算机系统在不需要进行显式编程的情况下,通过识别数据中的模式和特征来自动改进其性能。它广泛应用于各种领域,包括语音识别、图像处理、医学诊断、推荐系统等。机器学习主要包括监督学习、非监督学习、半监督学习和强化学习等几种方法。

判断函数测试(询问大模型知识库不知道的问题)

q = '介绍一下北京今天的天气'
print(identify_model(q))  

输出:

True

判断函数测试

q = '介绍一下DB-GPT项目?'
print(identify_model(q))

输出:

DB-GPT是一个开源项目,旨在通过结合大型语言模型(LLMs)和数据库技术,实现数据处理的自动化和优化。这个项目的核心是利用本地部署的大模型来与数据和环境进行交互,以此保护数据隐私和安全。DB-GPT支持在独立私有环境中部署,可以根据业务需求进行模块化部署,确保大模型的能力在私域内是绝对私有、安全和可控的。

该项目主要具有以下特点:

  1. 数据安全和隐私保护:通过本地化部署,避免了数据泄露的风险,确保用户数据的安全和隐私。

  2. 全流程自动化:整合了数据摄取、结构化和访问等多个流程,通过增强型大型语言模型来优化这些流程。

  3. 多模型框架:基于RAG框架设计,采用了多源RAG、自适应上下文学习等技术,提供了面向服务的多模型框架。

  4. 知识库构建与处理:原生支持知识库的构建和处理,通过langchain提供私域知识库问答能力。

  5. 插件模式:支持Auto-GPT等插件,提高了与数据交互的效率。

  6. 文本转SQL细化调整:包含文本转SQL任务的语言模型,能够更好地理解和处理自然语言查询。

  7. 多源知识整合:能够整合多源知识库,支持双语查询和生成数据分析。

DB-GPT的架构包括多个关键模块,例如用于知识构建、知识检索、自适应交互式编程和响应生成的模块,这些模块协同工作,以提高性能和效率。

项目的代码在GitHub上开源,地址是:https://github.com/eosphoros-ai/DB-GPT。该项目鼓励社区参与和贡献,共同推动数据库与大型语言模型结合的技术发展。

4、搜索词优化

用户提出的问题并不一定是最适合在知乎上进行搜索的关键词,例如用户提问“我想要知道“GPT-3.5微调总共需要几步”,此时应该将其转化为更加准确凝练的关键词并输入到知乎上进行搜索,方可提高搜索结果准确性。这里我们也完全可以让大模型自主将用户提的问题转化为适合在知乎上进行搜索的搜索关键词。当然,为达此目的,我们需要首先测试大模型是否知道知乎,以及大模型是否知道如何设计搜索关键词:
1)测试大模型是否知道知乎

response = client.chat.completions.create(
        model="glm-4",
        messages=[
            {"role": "user", "content": "你知道什么是知乎么?"}
        ]
    )
response.choices[0].message.content

输出:

'当然知道。知乎是中国领先的知识分享和社交平台,以问答的形式构建了一个信息分享、经验交流、意见互动的在线社区。它由北京智者天下科技有限公司运营,成立于2011年1月26日,其名称寓意在文言文中“知道吗”。\n\n知乎的目标是构建一个高质量的问答社区,让用户可以找到解决问题的答案,同时也能分享自己的知识与见解。随着时间的推移,知乎逐渐发展成为一个综合性内容平台,不仅提供问答服务,还涵盖了图文、音频、视频等多种内容形式。\n\n用户可以在知乎上提出问题,其他用户则可以回答问题或者对已有的回答进行评论。知乎的社区氛围以认真、专业和友善著称,吸引了大量专业人士和领域专家参与讨论。\n\n根据提供的信息,知乎在2019年完成了F轮融资,并推出了包括“盐选会员”在内的多项服务。到了2024年,知乎进一步拓展了其业务范围,不仅在社区建设上持续发力,还推出了结合AI技术的功能,如“发现·AI搜索”,以及“海盐计划6.0:航海家”和“灯塔计划”等项目,旨在通过技术赋能,提升用户体验,并推动平台持续进化。\n\n截至2020年12月,知乎拥有超过4400万条问题和2.4亿条回答,月活跃付费用户数超过250万,显示了其强大的用户基础和商业潜力。知乎不仅是一个问答社区,更是一个内容创作和知识分享的重要平台。'

2)咨询大模型设计关键词有什么方法

response = client.chat.completions.create(
        model="glm-4",
        messages=[
            {"role": "user", "content": "我如果想在知乎上搜索一些问题的答案,在设计搜索关键词方面,有什么技巧么?"}
        ]
    )
response.choices[0].message.content

输出:

'在设计搜索关键词以便在知乎上找到满意的问题答案时,以下是一些有用的技巧:\n\n1. **明确搜索意图**:\n   - 在开始搜索前,明确你想要解决的问题或者你感兴趣的话题。\n   - 确定你的搜索目标是寻找具体信息、教程、观点对比还是案例分析。\n\n2. **选择准确的关键词**:\n   - 选择与问题主题密切相关的关键词。\n   - 使用专业术语或行话,如果适用,以获取更精准的结果。\n   - 考虑使用同义词或近义词,以扩大搜索范围。\n\n3. **组合关键词**:\n   - 使用组合关键词来提高搜索的针对性。例如,如果你的问题是关于“数据分析工具”,可以组合成“数据分析工具比较”、“数据分析软件推荐”等。\n   - 尝试不同的组合方式,如“最佳”、“如何”、“教程”、“区别”等,以找到不同角度的答案。\n\n4. **利用长尾关键词**:\n   - 长尾关键词通常更具体,竞争也较小,可以帮助你找到更精确的信息。例如,“Python数据分析入门教程”就比单独的“Python”更具体。\n\n5. **避免过度堆砌关键词**:\n   - 过度堆砌关键词可能导致搜索结果不准确,降低搜索效率。\n\n6. **利用知乎的搜索提示**:\n   - 知乎的搜索栏通常会有相关搜索提示,可以参考这些提示来调整和优化你的关键词。\n\n7. **注意关键词的顺序**:\n   - 有时关键词的顺序也会影响搜索结果,尝试不同的顺序来获得更准确的搜索结果。\n\n8. **检查拼写和语法**:\n   - 确保关键词的拼写和语法正确,以免影响搜索效果。\n\n9. **使用高级搜索选项**:\n   - 如果知乎支持高级搜索,利用这些功能,如时间筛选、用户筛选等,来进一步优化搜索结果。\n\n通过上述技巧,你可以设计出更有效的搜索关键词,提高在知乎上找到高质量答案的几率。'

3)咨询大模型怎么设计关键词

response = client.chat.completions.create(
        model="glm-4",
        messages=[
            {"role": "user", "content": "例如,我想要知道“GPT-3.5微调总共需要几步”,\
            现在围绕这个问题在知乎上进行搜索,应该怎样设计这个问题的搜索关键词呢?"}
        ]
    )
response.choices[0].message.content

输出:

'若要在知乎上搜索关于“GPT-3.5微调总共需要几步”的信息,可以设计以下关键词进行搜索:\n\n1. GPT-3.5 微调流程\n2. GPT-3.5定制步骤\n3. GPT-3.5模型训练几步走\n4. GPT-3.5 Turbo 微调指南\n5. GPT-3.5自定义模型步骤\n6. GPT-3.5训练数据生成与微调流程\n7. GPT-3.5 RAG混合方法步骤\n\n以下是一些可能的搜索短语:\n\n- “GPT-3.5微调需要哪些步骤?”\n- “如何对GPT-3.5进行定制训练?”\n- “GPT-3.5从数据生成到微调的流程介绍”\n- “OpenAI GPT-3.5微调流程详解”\n- “GPT-3.5 Turbo训练与微调步骤”\n\n组合这些关键词和短语,可以更准确地找到关于GPT-3.5微调步骤的相关讨论和答案。在搜索时,也可以根据需要添加一些限定词,比如“2023”,“最新指南”等,以获取最新的信息。'

4)让大模型帮忙提取问题关键词

response = client.chat.completions.create(
        model="glm-4",
        messages=[
             {"role": "system", "content": "你专门负责将用户的问题转化为知乎网站搜索关键词,只返回一个你认为最合适的搜索关键词即可"},
             {"role": "user", "content": "请问,GPT-3.5微调总共分为几步?"},
             {"role": "assistant", "content": "GPT-3.5微调流程"},
             {"role": "user", "content": "请问ChatGPT企业版都有哪些功能?"}
        ]
    )
response.choices[0].message.content

5)封装关键词设计的函数

def convert_keyword(q):
    """
    将用户输入的问题转化为适合在知乎上进行搜索的关键词
    """
    response = client.chat.completions.create(
            model="glm-4",
            messages=[
                 {"role": "system", "content": "你专门负责将用户的问题转化为知乎网站搜索关键词,只返回一个你认为最合适的搜索关键词即可"},
                 {"role": "user", "content": "请问,GPT-3.5微调总共分为几步?"},
                 {"role": "assistant", "content": "GPT-3.5微调流程"},
                 {"role": "user", "content": q}
            ]
        )
    q = response.choices[0].message.content
    return q

6)基于关键词设计函数,智能助手函数

def get_answer(q):
    """
    智能助手函数,当你无法回答某个问题时,调用该函数,能够获得答案
    :param q: 必选参数,询问的问题,字符串类型对象
    :return:某问题的答案,以字符串形式呈现
    """
    # 调用转化函数,将用户的问题转化为更适合在知乎上进行搜索的关键词
    q = convert_keyword(q)
    
    # 默认搜索返回10个答案
    print('正在接入谷歌搜索,查找和问题相关的答案...')
    results = google_search(query=q, num_results=2, site_url='https://zhihu.com/')
    
    # 创建对应问题的子文件夹
    folder_path = './auto_search/%s' % q
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)
    
    # 单独提取links放在一个list中
    print('正在读取搜索的到的相关答案...')
    num_tokens = 0
    content = ''
    for item in results:
        url = item['link']
        title = get_search_text(q, url)
        with open('./auto_search/%s/%s.json' % (q, title), 'r') as f:
            jd = json.load(f)
        num_tokens += jd[0]['tokens']
        if num_tokens <= 12000:
            content += jd[0]['content']
        else:
            break
    print('正在进行最后的整理...')
    return(content)

5、外部函数流程优化

而既然是依据“密钥”来判断是否调用搜索功能,那么该外部函数的调用就不能再使用此前定义的auto function calling功能了,而是需要我们手动来调用这个外部函数(即接收到密钥时一定要调用外部函数)

functions_list=[get_answer]
tools = auto_functions(functions_list)
tools

在这里插入图片描述

1)外部函数调用测试

response = client.chat.completions.create(
        model="glm-4",
        messages=[
            {"role": "user", "content": "今天的北京天气如何?"},
            
        ],
        tools=tools,
        tool_choice={"type": "function", "function": {"name": "get_answer"}},  
    )
response.choices[0].message

在这里插入图片描述

2)优化前的大模型调用

def run_conversation(messages, functions_list=None, model="glm-4", function_call="auto"):
    """
    能够自动执行外部函数调用的对话模型
    :param messages: 必要参数,字典类型,输入到Chat模型的messages参数对象
    :param functions_list: 可选参数,默认为None,可以设置为包含全部外部函数的列表对象
    :param model: Chat模型,可选参数,默认模型为glm-4
    :return:Chat模型输出结果
    """
    # 如果没有外部函数库,则执行普通的对话任务
    if functions_list == None:
        response = client.chat.completions.create(
                        model=model,
                        messages=messages,
                        )
        response_message = response.choices[0].message
        final_response = response_message.content
        
    # 若存在外部函数库,则需要灵活选取外部函数并进行回答
    else:
        # 创建functions对象
        tools = auto_functions(functions_list)

        # 创建外部函数库字典
        available_functions = {func.__name__: func for func in functions_list}

        # 第一次调用大模型
        response = client.chat.completions.create(
                        model=model,
                        messages=messages,
                        tools=tools,
                        tool_choice=function_call, )
        response_message = response.choices[0].message


        tool_calls = response_message.tool_calls

        if tool_calls:

            #messages.append(response_message)
            messages.append(response.choices[0].message.model_dump())
            for tool_call in tool_calls:
                function_name = tool_call.function.name
                function_to_call = available_functions[function_name]
                function_args = json.loads(tool_call.function.arguments)
                ## 真正执行外部函数的就是这儿的代码
                function_response = function_to_call(**function_args)
                messages.append(
                    {
                        "role": "tool",
                        "content": function_response,
                        "tool_call_id": tool_call.id,
                    }
                ) 
            ## 第二次调用模型
            second_response = client.chat.completions.create(
                model=model,
                messages=messages,
                tools=tools
            ) 
            # 获取最终结果
            print(second_response.choices[0].message)
            final_response = second_response.choices[0].message.content
        else:
            final_response = response_message.content
                
    return final_response

3)优化后的智能机器人逻辑编写

def auto_search_answer(q):
    # 调用判别模型
    res = identify_model(q)
    if res == True:
        messages = [{"role": "user", "content": q}]
        res =run_conversation(messages=messages, 
                              functions_list=[get_answer], 
                              model="glm-4", 
                              function_call={"type": "function", "function": {"name": "get_answer"}})
    return(res)
auto_search_answer("北京2024年5月1日的天气如何?")

在这里插入图片描述

auto_search_answer("什么是大模型?")

输出:

'大模型指的是参数规模极大、计算能力极强、能够处理非常复杂任务的人工智能模型。通常这些模型的参数量达到百亿、千亿甚至更多,例如GPT-3、天工3.0等。大模型具有卓越的理解能力、生成能力和泛化能力,能够应用于多种场景,如图像识别、自然语言处理、音乐生成等,为人工智能在各个领域的应用提供了强大的支持。随着算力的提升和算法的发展,大模型在推动人工智能技术进步方面发挥着越来越重要的作用。'

四、全流程代码总结

对整个智能搜索的代码进行全面的梳理和总结,为后续的其他技术平台的搜索提供清晰的指导。

1、大模型客户端创建

import os
import openai
from openai import OpenAI
import glob
import shutil

import numpy as np
import pandas as pd

import json
import io
import inspect
import requests
import re
import random
import string

from googleapiclient.discovery import build
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
import base64


from bs4 import BeautifulSoup
import dateutil.parser as parser
import tiktoken
from lxml import etree

## 初始化客户端
api_key = os.getenv("ZHIPUAI_API_KEY")


from zhipuai import ZhipuAI
client = ZhipuAI(api_key=api_key)

2、google搜索函数

def google_search(query, num_results=10, site_url=None):
    
    api_key = os.getenv("GOOGLE_SEARCH_API_KEY")
    cse_id = os.getenv("CSE_ID")
    
    url = "https://www.googleapis.com/customsearch/v1"

    # API 请求参数
    if site_url == None:
        params = {
        'q': query,          
        'key': api_key,      
        'cx': cse_id,        
        'num': num_results   
        }
    else:
        params = {
        'q': query,         
        'key': api_key,      
        'cx': cse_id,        
        'num': num_results,  
        'siteSearch': site_url
        }

    # 发送请求
    response = requests.get(url, params=params)
    response.raise_for_status()

    # 解析响应
    search_results = response.json().get('items', [])

    # 提取所需信息
    results = [{
        'title': item['title'],
        'link': item['link'],
        'snippet': item['snippet']
    } for item in search_results]

    return results

3、创建文件名称函数

def windows_create_name(s, max_length=255):
    """
    将字符串转化为符合Windows文件/文件夹命名规范的名称。
    
    参数:
    - s (str): 输入的字符串。
    - max_length (int): 输出字符串的最大长度,默认为255。
    
    返回:
    - str: 一个可以安全用作Windows文件/文件夹名称的字符串。
    """

    # Windows文件/文件夹名称中不允许的字符列表
    forbidden_chars = ['<', '>', ':', '"', '/', '\\', '|', '?', '*']

    # 使用下划线替换不允许的字符
    for char in forbidden_chars:
        s = s.replace(char, '_')

    # 删除尾部的空格或点
    s = s.rstrip(' .')

    # 检查是否存在以下不允许被用于文档名称的关键词,如果有的话则替换为下划线
    reserved_names = ["CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", 
                      "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"]
    if s.upper() in reserved_names:
        s += '_'

    # 如果字符串过长,进行截断
    if len(s) > max_length:
        s = s[:max_length]

    return s

4、知乎内容查询函数

def get_search_text(q, url):

    cookie = "q_c1=3c10baf5bd084b3cbfe7eece648ba243|1704976541000|1704976541000; _zap=086350b3-1588-49c4-9d6d-de88f3faae03; d_c0=AGCYfYvO_RePTvjfB1kZwPLeke_N5AM6nwo=|1704949678; _xsrf=qR1FJHlZ9dvYhhoj4SUj43SAIBUwPOqm; __snaker__id=wNWnamiJKBI0kzkI; q_c1=d44e397edb6740859a7d2a0d4155bfab|1706509753000|1706509753000; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1706509695,1706589529,1706765465,1708650963; z_c0=2|1:0|10:1713167971|4:z_c0|80:MS4xOGRHQVNnQUFBQUFtQUFBQVlBSlZUYjZqOTJaLXVDSjdRSmJKMHgyVEhxTE13UGN1TUJBdHZnPT0=|15b2c2ece393ac4ea374d9b36cde5af7304f8ee7632e060fe6835bfadb5e4132; KLBRSID=9d75f80756f65c61b0a50d80b4ca9b13|1713170212|1713167958"
    user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"  

    code_ = False
    headers = {
        'authority': 'www.zhihu.com',
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'cache-control': 'max-age=0',
        'cookie': cookie,
        'upgrade-insecure-requests': '1',
        'user-agent':user_agent,
    }

    # 普通问答地址
    if 'zhihu.com/question' in url:
        res = requests.get(url, headers=headers).text
        res_xpath = etree.HTML(res)
        title = res_xpath.xpath('//div/div[1]/div/h1/text()')[0]
        text_d = res_xpath.xpath('//*[@id="root"]/div/main/div/div/div[3]/div[1]/div/div[2]/div/div/div/div[2]/span[1]/div/div/span/p/text()')
    
    # 专栏地址
    elif 'zhuanlan' in url:
        headers['authority'] = 'zhaunlan.zhihu.com'
        res = requests.get(url, headers=headers).text
        res_xpath = etree.HTML(res)
        title = res_xpath.xpath('//div[1]/div/main/div/article/header/h1/text()')[0]
        text_d = res_xpath.xpath('//div/main/div/article/div[1]/div/div/div/p/text()')
        code_ = res_xpath.xpath('//div/main/div/article/div[1]/div/div/div//pre/code/text()')  
            
    # 特定回答的问答网址
    elif 'answer' in url:
        res = requests.get(url, headers=headers).text
        res_xpath = etree.HTML(res)
        title = res_xpath.xpath('//div/div[1]/div/h1/text()')[0]
        text_d = res_xpath.xpath('//div[1]/div/div[3]/div/div/div/div[2]/span[1]/div/div/span/p/text()')

    # 创建问题答案正文
    text = ''
    for t in text_d:
        txt = str(t).replace('\n', ' ')
        text += txt
        
    # 如果有code,则将code追加到正文的追后面
    if code_:
        for c in code_:
            co = str(c).replace('\n', ' ')    
            text += co
    
    encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")     
    json_data = [
        {
            "link": url,
            "title": title,
            "content": text,
            "tokens": len(encoding.encode(text))
        }
    ]

    with open('./auto_search/%s/%s.json' % (q, title), 'w') as f:
        json.dump(json_data, f)
    
    return title

5、大模型判断函数

import random
import string

def generate_random_key(length=30):
    return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(length))

def identify_model(q):
    
    # 创建密钥
    sk = generate_random_key()
    
    # 调用模型进行判别
    response = client.chat.completions.create(
            model="glm-4",
            messages=[
                {"role": "system", "content": "你是一个用户问题判断器,专门用于判别你是否知道用户当前问题的答案。\
                如果不知道,请回答“%s”,若知道,请正常回答" % sk},
                {"role": "user", "content": "请问,GPT-3.5微调总共分为几步?"},
                {"role": "assistant", "content": "%s" % sk},
                {"role": "user", "content": q}
            ]
        )
    res = response.choices[0].message.content
    
    if sk in res or '对不起' in res or '抱歉' in res or '超出知识库' in res:
        return(True)
    else:
        return(res)

6、关键词获取函数

def convert_keyword(q):
    """
    将用户输入的问题转化为适合在知乎上进行搜索的关键词
    """
    response = client.chat.completions.create(
            model="glm-4",
            messages=[
                 {"role": "system", "content": "你专门负责将用户的问题转化为知乎网站搜索关键词,只返回一个你认为最合适的搜索关键词即可"},
                 {"role": "user", "content": "请问,GPT-3.5微调总共分为几步?"},
                 {"role": "assistant", "content": "GPT-3.5微调流程"},
                 {"role": "user", "content": q}
            ]
        )
    q = response.choices[0].message.content
    return q

7、问题答案获取函数

def get_answer(q):
    """
    智能助手函数,当你无法回答某个问题时,调用该函数,能够获得答案
    :param q: 必选参数,询问的问题,字符串类型对象
    :return:某问题的答案,以字符串形式呈现
    """
    # 调用转化函数,将用户的问题转化为更适合在知乎上进行搜索的关键词
    q = convert_keyword(q)
    
    # 默认搜索返回10个答案
    print('正在接入谷歌搜索,查找和问题相关的答案...')
    results = google_search(query=q, num_results=2, site_url='https://zhihu.com/')
    
    # 创建对应问题的子文件夹
    folder_path = './auto_search/%s' % q
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)
    
    # 单独提取links放在一个list中
    print('正在读取搜索的到的相关答案...')
    num_tokens = 0
    content = ''
    for item in results:
        url = item['link']
        title = get_search_text(q, url)
        with open('./auto_search/%s/%s.json' % (q, title), 'r') as f:
            jd = json.load(f)
        num_tokens += jd[0]['tokens']
        if num_tokens <= 12000:
            content += jd[0]['content']
        else:
            break
    print('正在进行最后的整理...')
    return(content)

8、funcation calling函数信息生成器

def auto_functions(functions_list):
    """
    Chat模型的functions参数编写函数
    :param functions_list: 包含一个或者多个函数对象的列表;
    :return:满足Chat模型functions参数要求的functions对象
    """
    def functions_generate(functions_list):
        # 创建空列表,用于保存每个函数的描述字典
        functions = []
        # 对每个外部函数进行循环
        for function in functions_list:
            # 读取函数对象的函数说明
            function_description = inspect.getdoc(function)
            # 读取函数的函数名字符串
            function_name = function.__name__

            system_prompt = '以下是某的函数说明:%s,输出结果必须是一个JSON格式的字典,只输出这个字典即可,前后不需要任何前后修饰或说明的语句' % function_description
            user_prompt = '根据这个函数的函数说明,请帮我创建一个JSON格式的字典,这个字典有如下5点要求:\
                           1.字典总共有三个键值对;\
                           2.第一个键值对的Key是字符串name,value是该函数的名字:%s,也是字符串;\
                           3.第二个键值对的Key是字符串description,value是该函数的函数的功能说明,也是字符串;\
                           4.第三个键值对的Key是字符串parameters,value是一个JSON Schema对象,用于说明该函数的参数输入规范。\
                           5.输出结果必须是一个JSON格式的字典,只输出这个字典即可,前后不需要任何前后修饰或说明的语句' % function_name

            response = client.chat.completions.create(
                              model="glm-4",
                              messages=[
                                {"role": "system", "content": system_prompt},
                                {"role": "user", "content": user_prompt}
                              ]
                            )
            json_str=response.choices[0].message.content.replace("```json","").replace("```","")
            json_function_description=json.loads(json_str)
            json_str={"type": "function","function":json_function_description}
            functions.append(json_str)
        return functions
    ## 最大可以尝试4次
    max_attempts = 4
    attempts = 0

    while attempts < max_attempts:
        try:
            functions = functions_generate(functions_list)
            break  # 如果代码成功执行,跳出循环
        except Exception as e:
            attempts += 1  # 增加尝试次数
            print("发生错误:", e)
            if attempts == max_attempts:
                print("已达到最大尝试次数,程序终止。")
                raise  # 重新引发最后一个异常
            else:
                print("正在重新运行...")
    return functions

9、大模型调用函数

def run_conversation(messages, functions_list=None, model="glm-4", function_call="auto"):
    """
    能够自动执行外部函数调用的对话模型
    :param messages: 必要参数,字典类型,输入到Chat模型的messages参数对象
    :param functions_list: 可选参数,默认为None,可以设置为包含全部外部函数的列表对象
    :param model: Chat模型,可选参数,默认模型为glm-4
    :return:Chat模型输出结果
    """
    # 如果没有外部函数库,则执行普通的对话任务
    if functions_list == None:
        response = client.chat.completions.create(
                        model=model,
                        messages=messages,
                        )
        response_message = response.choices[0].message
        final_response = response_message.content
        
    # 若存在外部函数库,则需要灵活选取外部函数并进行回答
    else:
        # 创建functions对象
        tools = auto_functions(functions_list)

        # 创建外部函数库字典
        available_functions = {func.__name__: func for func in functions_list}

        # 第一次调用大模型
        response = client.chat.completions.create(
                        model=model,
                        messages=messages,
                        tools=tools,
                        tool_choice=function_call, )
        response_message = response.choices[0].message


        tool_calls = response_message.tool_calls

        if tool_calls:

            #messages.append(response_message)
            messages.append(response.choices[0].message.model_dump())
            for tool_call in tool_calls:
                function_name = tool_call.function.name
                function_to_call = available_functions[function_name]
                function_args = json.loads(tool_call.function.arguments)
                ## 真正执行外部函数的就是这儿的代码
                function_response = function_to_call(**function_args)
                messages.append(
                    {
                        "role": "tool",
                        "content": function_response,
                        "tool_call_id": tool_call.id,
                    }
                ) 
            ## 第二次调用模型
            second_response = client.chat.completions.create(
                model=model,
                messages=messages,
                tools=tools
            ) 
            # 获取最终结果
            print(second_response.choices[0].message)
            final_response = second_response.choices[0].message.content
        else:
            final_response = response_message.content
                
    return final_response

10、最外层的结果查询函数

def auto_search_answer(q):
    # 调用判别模型
    res = identify_model(q)
    if res == True:
        messages = [{"role": "user", "content": q}]
        res =run_conversation(messages=messages, 
                              functions_list=[get_answer], 
                              model="glm-4", 
                              function_call={"type": "function", "function": {"name": "get_answer"}})
    return(res)

结语

随着本章的结束,我们已经成功实现了知乎网站数据的智能搜索,并将其整合到了我们的智能化IT领域搜索引擎中。这一成果不仅提升了搜索引擎的数据覆盖范围和准确性,也为后续的开发工作奠定了坚实的基础。然而,我们仍需认识到,搜索引擎的优化和升级是一个持续不断的过程。因此,在接下来的工作中,下一篇章我们将完成Github网站搜索的接入。

在这里插入图片描述

🎯🔖更多专栏系列文章:AIGC-AI大模型探索之路

😎 作者介绍:我是寻道AI小兵,资深程序老猿,从业10年+、互联网系统架构师,目前专注于AIGC的探索。
📖 技术交流:建立有技术交流群,可以扫码👇 加入社群,500本各类编程书籍、AI教程、AI工具等你领取!
如果文章内容对您有所触动,别忘了点赞、⭐关注,收藏!加入我,让我们携手同行AI的探索之旅,一起开启智能时代的大门!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/713548.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【在线OJ】vue分页+SpringBoot分页模板代码

一、Vue <template><div><el-table:data"user"style"width: 120%"><el-table-columnlabel"id"width"180"><template slot-scope"scope"><i class"el-icon-time"></i>&…

几个小创新模型,KAN组合网络(LSTM、GRU、Transformer)时间序列预测,python预测全家桶...

截止到本期&#xff0c;一共发了8篇关于机器学习预测全家桶Python代码的文章。参考往期文章如下&#xff1a; 1.终于来了&#xff01;python机器学习预测全家桶 2.机器学习预测全家桶-Python&#xff0c;一次性搞定多/单特征输入&#xff0c;多/单步预测&#xff01;最强模板&a…

中国城市建设统计年鉴(1978-2022年)

数据年份&#xff1a;1978-2022 数据格式&#xff1a;excel、pdf 数据内容&#xff1a;以2022年为例&#xff0c;《中国城市建设统计年鉴—2022》根据各省、自治区和直辖市建设行政主管部门上报的2022年及历年城市建设统计数据编辑。 共分13个部分&#xff0c;包括城市市政公用…

Java课程设计:基于swing + mysql的酒店管理系统

文章目录 一、项目介绍二、项目展示三、源码展示四、源码获取 一、项目介绍 项目功能 1、散客开单&#xff1a;完成散客的开单&#xff0c;可一次最多开5间相同类型的房间。 2、团体开单&#xff1a;完成团体的开单&#xff0c;开放数量没有限制&#xff0c;可同时开不同类型…

Java阻塞队列:ArrayBlockingQueue

Java阻塞队列&#xff1a;ArrayBlockingQueue ArrayBlockingQueue是Java中的一个阻塞队列&#xff08;Blocking Queue&#xff09;实现&#xff0c;它是线程安全的&#xff0c;并且基于数组实现。ArrayBlockingQueue常用于生产者-消费者模型&#xff0c;在这种模型中&#xff…

北京人工智能数据运营平台发布,并开源大规模数据集

6月14日&#xff0c;AI行业顶级盛会2024北京智源大会正式拉开帷幕。作为大会的重要组成部分&#xff0c;智源大会“人工智能数据新基建”论坛同步召开。本论坛由北京智源人工智能研究院主办&#xff0c;中国互联网协会人工智能工委会和中国移动研究院承办。本次论坛邀请到来自中…

2-5 基于matlab的信号的希尔伯特-黄变换

基于matlab的信号的希尔伯特-黄变换&#xff0c;IMF分解&#xff0c;对IMF进行Hilbert处理&#xff0c;绘制二维/三维时-频图&#xff0c;时间-能量图(瞬时能量谱) &#xff0c;频率-能量图&#xff08;希尔伯特谱&#xff09;。程序已调通&#xff0c;可直接运行。 2-5 希尔伯…

java Springboot网上音乐商城(源码+sql+论文)

1.1 研究目的和意义 随着市场经济发展&#xff0c;尤其是我国加入WTO &#xff0c;融入经济全球化潮流&#xff0c;已进入国内外市场经济发展新时期&#xff0c;音乐与市场联系越来越紧密&#xff0c;我国音乐和网上业务也进入新历史发展阶段。为了更好地服务于市场&#xff0…

11.泛型、trait和生命周期(上)

标题 一、泛型数据的引入二、改写为泛型函数三、结构体/枚举中的泛型定义四、方法定义中的泛型 一、泛型数据的引入 下面是两个函数&#xff0c;分别用来取得整型和符号型vector中的最大值 use std::fs::File;fn get_max_float_value_from_vector(src: &[f64]) -> f64…

.net8 blazor auto模式很爽(五)读取sqlite并显示(2)

在BlazorApp1增加文件夹data&#xff0c;里面增加类dbcont using SharedLibrary.Models; using System.Collections.Generic; using Microsoft.EntityFrameworkCore;namespace BlazorApp1.data {public class dbcont : DbContext{public dbcont(DbContextOptions<dbcont>…

Python进阶:从函数到文件的编程艺术!!!

第二章&#xff1a;Python进阶 模块概述 函数是一段可重复使用的代码块&#xff0c;它接受输入参数并返回一个结果。函数可以用于执行特定的任务、计算结果、修改数据等&#xff0c;使得代码更具模块化和可重用性。 模块是一组相关函数、类和变量的集合&#xff0c;它们被封…

vs+qt5.0 使用poppler 操作库

Poppler 是一个用来生成 PDF 的C类库&#xff0c;从xpdf 继承而来。vs编译库如下&#xff1a; vs中只需要添加依赖库即可 头文件&#xff1a;

2.2 抽头

目录 为什么要抽头 什么是抽头 接入系数 怎么抽头 信号源端抽头 负载端抽头 例题分析 要点总结 为什么要抽头 阻抗转换&#xff0c;使信号源内阻Rs与负载电阻RL变得很大&#xff0c;分流小&#xff0c;再使用并联方式。 什么是抽头 接入系数 电容越大&#xff0c;分压越…

初识PHP

一、格式 每行以分号结尾 <?phpecho hello; ?>二、echo函数和print函数 作用&#xff1a;两个函数都是输出内容到页面中&#xff0c;多用于代码调试。 <?php echo "<h1 styletext-align: center;>test</h1>"; print "<h1 stylet…

使用python绘制三维曲线图

使用python绘制三维曲线图 三维曲线图定义特点 效果代码 三维曲线图 三维曲线图&#xff08;3D曲线图&#xff09;是一种用于可视化三维数据的图表&#xff0c;它展示了数据在三个维度&#xff08;X、Y、Z&#xff09;上的变化。 定义 三维曲线图通过在三维坐标系中绘制曲线…

AI大模型技术揭秘-参数,Token,上下文和温度

深入理解 AI 大模型:参数、Token、上下文窗口、上下文长度和温度 人工智能技术的飞速发展使AI大模型大放异彩,其中涉及的“参数”、“Token”、“上下文窗口”、“上下文长度”及“温度”等专业术语备受瞩目。这些术语背后究竟蕴含何意?它们如何影响AI大模型的性能?一起揭开…

htb_Freelancer

端口扫描 80 88 389 445 扫描ldap协议相关漏洞&#xff0c;没有发现 扫描子域名&#xff0c;加入/etc/hosts&#xff08;后面发现没用&#xff09; 枚举域用户 目录扫描&#xff0c;发现一个/admin目录 访问后发现要账号密码 访问80端口&#xff0c;注册一个freelancer用…

关于二分法的理解(以JS为例)

算法介绍 基本概念 二分查找算法&#xff0c;又称折半查找算法&#xff0c;是一种在有序数组中查找特定元素的高效方法。它的核心思想是将数组分成两半&#xff0c;然后根据目标值与中间元素的比较结果来决定是继续在左半部分还是右半部分进行搜索。 工作原理 初始化&#…

Vue3+Vite报错:vite忽略.vue扩展名 Failed to resolve import ..... Does the file exist?

Vue3Vite报错&#xff1a;vite忽略.vue扩展名 Failed to resolve import … Does the file exist? 先看报错&#xff1a; 分析原因 原因是我们没有写后缀名 建议你在你的vite.config.js中加上如下配置 import { defineConfig } from "vite"; import vue from &qu…

股指期货功能

其金融期货的本质&#xff0c;决定了股指期货具有以下几方面特点&#xff1a; &#xff08;1&#xff09;交割方式为现金交割&#xff1b; &#xff08;2&#xff09;股指期货的持有成本较低&#xff1b; &#xff08;3&#xff09;股指期货的保证金率较低&#xff0c;杠杆性…