ChatGPT实战-Embeddings打造定制化AI智能客服

news2025/1/4 8:31:59

本文介绍Embeddings的基本概念,并使用最少但完整的代码讲解Embeddings是如何使用的,帮你打造专属AI聊天机器人(智能客服),你可以拿到该代码进行修改以满足实际需求。

ChatGPT的Embeddings解决了什么问题?

如果直接问ChatGPT:What is langchain? If you do not know please do not answer.,由于ChatGPT不知道2021年9月份之后的事情,而langchain比较新,是在那之后才有的,所以ChatGPT会回答不知道:

I’m sorry, but I don’t have any information on “langchain.” It appears to be a term that is not widely recognized or used in general knowledge.

如果我们用上Embeddings,用上面的问题提问,它可以给出答案:

LangChain is a framework for developing applications powered by language models.

有了这个技术,我们就可以对自己的文档进行提问,从而拓展ChatGPT的知识范围,打造定制化的AI智能客服。例如在官网接入ChatGPT,根据网站的文档让他回答用户的问题。

Embeddings相关基本概念介绍

什么是Embeddings?

在跳进代码之前,先简要介绍一下什么是Embeddings。在介绍Embeddings之前我们需要先学习一下「向量」这个概念。

我们可以将一个事物从多个维度来描述,例如声音可以从「时域」和「频域」来描述(傅里叶变换可能很多人都听过),维度拆分的越多就越能描述一个事物,在向量空间上的接近往往意味着这两个事物有更多的联系,而向量空间又是比较好计算的,于是我们可以通过计算向量来判断事物的相似程度。
向量
在自然语言处理 (NLP) 的中,Embeddings是将单词或句子转换为数值向量的一种方法。这些向量捕获单词或句子的语义,使我们能够对它们执行数学运算。例如,我们可以计算两个向量之间的余弦相似度来衡量它们在语义上的相似程度。
embedding

Embeddings使用流程讲解

如何让ChatGPT回答没有训练过的内容?流程如下,一图胜千言。
在这里插入图片描述
分步解释:

  • 首先是获取本地数据的embeddings结果,由于一次embeddings调用的token数量是有限制的,先将数据进行分段然后以依次行调用获得所有数据的embeddings结果。
  • 然后我们开始提问,同样的,将提问的内容也做一次embedding,得到一个结果。
  • 再将提问的intending结果和之前所有数据的embedded结果进行距离的计算,这里的距离就是指向量之间的距离,然后我们获取距离最近的几段段数据来作为我们提问的「上下文」(例如这里找到data2/data3是和问题最相关的内容)。
  • 获得上下文之后我们开始构造真正的问题,问题会将上下文也附属在后面一并发送给chat gpt,这样它就可以回答之前不知道的问题了。

总结来说:

之所以能够让ChatGPT回答他不知道的内容,其实是因为我们把相关的上下文传递给了他,他从上下文中获取的答案。如何确定要发送哪些上下文给他,就是通过计算向量距离得到的。

embedding实战代码(python)

让我来看看实际的代码。

前置条件

  • Python 3.6 或更高版本。
  • OpenAI API 密钥,或者其他提供API服务的也可以。
  • 安装了以下 Python 软件包: requestsbeautifulsoup4pandastiktokenopenainumpy
  • 私有文本数据集。在这个示例中,使用名为 langchainintro.txt 的文本文件,这里面是langchain官网的一些文档说明,文档比较新所以ChatGPT肯定不知道,以此来测试效果。

代码:

代码来自于OpenAI官网,我做了一些改动和精简。

import os
import numpy as np
import openai
import pandas as pd
import tiktoken
from ast import literal_eval
from openai.embeddings_utils import distances_from_embeddings
import traceback

tokenizer = tiktoken.get_encoding("cl100k_base")


def get_api_key():
    return os.getenv('OPENAI_API_KEY')


def set_openai_config():
    openai.api_key = get_api_key()
    openai.api_base = "https://openai.api2d.net/v1"


def remove_newlines(serie):
    serie = serie.str.replace('\n', ' ')
    serie = serie.str.replace('\\n', ' ')
    serie = serie.str.replace('  ', ' ')
    serie = serie.str.replace('  ', ' ')
    return serie


def load_text_files(file_name):
    with open(file_name, "r", encoding="UTF-8") as f:
        text = f.read()
    return text


def prepare_directory(dir_name="processed"):
    if not os.path.exists(dir_name):
        os.mkdir(dir_name)


def split_into_many(text, max_tokens):
    # Split the text into sentences
    sentences = text.split('. ')

    # Get the number of tokens for each sentence
    n_tokens = [len(tokenizer.encode(" " + sentence)) for sentence in sentences]

    chunks = []
    tokens_so_far = 0
    chunk = []

    # Loop through the sentences and tokens joined together in a tuple
    for sentence, token in zip(sentences, n_tokens):

        # If the number of tokens so far plus the number of tokens in the current sentence is greater
        # than the max number of tokens, then add the chunk to the list of chunks and reset
        # the chunk and tokens so far
        if tokens_so_far + token > max_tokens:
            chunks.append(". ".join(chunk) + ".")
            chunk = []
            tokens_so_far = 0

        # If the number of tokens in the current sentence is greater than the max number of
        # tokens, split the sentence into smaller parts and add them to the chunk
        while token > max_tokens:
            part = sentence[:max_tokens]
            chunk.append(part)
            sentence = sentence[max_tokens:]
            token = len(tokenizer.encode(" " + sentence))

        # Otherwise, add the sentence to the chunk and add the number of tokens to the total
        chunk.append(sentence)
        tokens_so_far += token + 1

    # Add the last chunk to the list of chunks
    if chunk:
        chunks.append(". ".join(chunk) + ".")

    return chunks


def shorten_texts(df, max_tokens):
    shortened = []

    # Loop through the dataframe
    for row in df.iterrows():
        # If the text is None, go to the next row
        if row[1]['text'] is None:
            continue

        # If the number of tokens is greater than the max number of tokens, split the text into chunks
        if row[1]['n_tokens'] > max_tokens:
            shortened += split_into_many(row[1]['text'], max_tokens)

        # Otherwise, add the text to the list of shortened texts
        else:
            shortened.append(row[1]['text'])

    df = pd.DataFrame(shortened, columns=['text'])
    df['n_tokens'] = df.text.apply(lambda x: len(tokenizer.encode(x)))

    return df


def create_embeddings(df):
    df['embeddings'] = df.text.apply(
        lambda x: openai.Embedding.create(input=x, engine='text-embedding-ada-002')['data'][0]['embedding'])
    df.to_csv('processed/embeddings.csv')
    return df


def load_embeddings():
    df = pd.read_csv('processed/embeddings.csv', index_col=0)
    df['embeddings'] = df['embeddings'].apply(literal_eval).apply(np.array)
    return df


def create_context(
        question, df, max_len=1800, size="ada"
):
    """
    Create a context for a question by finding the most similar context from the dataframe
    """
    # print(f'start create_context')
    # Get the embeddings for the question
    q_embeddings = openai.Embedding.create(input=question, engine='text-embedding-ada-002')['data'][0]['embedding']
    # print(f'q_embeddings:{q_embeddings}')

    # Get the distances from the embeddings
    df['distances'] = distances_from_embeddings(q_embeddings, df['embeddings'].values, distance_metric='cosine')
    # print(f'df[distances]:{df["distances"]}')

    returns = []
    cur_len = 0

    # Sort by distance and add the text to the context until the context is too long
    for i, row in df.sort_values('distances', ascending=True).iterrows():
        # print(f'i:{i}, row:{row}')
        # Add the length of the text to the current length
        cur_len += row['n_tokens'] + 4

        # If the context is too long, break
        if cur_len > max_len:
            break

        # Else add it to the text that is being returned
        returns.append(row["text"])

    # Return the context
    return "\n\n###\n\n".join(returns)


def answer_question(
        df,
        model="text-davinci-003",
        question="Am I allowed to publish model outputs to Twitter, without a human review?",
        max_len=1800,
        size="ada",
        debug=False,
        max_tokens=150,
        stop_sequence=None
):
    """
    Answer a question based on the most similar context from the dataframe texts
    """
    context = create_context(
        question,
        df,
        max_len=max_len,
        size=size,
    )
    # If debug, print the raw model response
    if debug:
        print("Context:\n" + context)
        print("\n\n")

    prompt = f"Answer the question based on the context below, \n\nContext: {context}\n\n---\n\nQuestion: {question}\nAnswer:"
    messages = [
        {
            'role': 'user',
            'content': prompt
        }
    ]
    try:
        # Create a completions using the questin and context
        response = openai.ChatCompletion.create(
            messages=messages,
            temperature=0,
            max_tokens=max_tokens,
            stop=stop_sequence,
            model=model,
        )
        return response["choices"][0]["message"]["content"]
    except Exception as e:
        # print stack
        traceback.print_exc()
        print(e)
        return ""


def main():
    # 设置API key
    set_openai_config()

    # 载入本地数据
    texts = []
    text = load_text_files("langchainintro.txt")
    texts.append(('langchainintro', text))
    prepare_directory("processed")

    # 创建一个dataframe,包含fname和text两列
    df = pd.DataFrame(texts, columns=['fname', 'text'])
    df['text'] = df.fname + ". " + remove_newlines(df.text)
    df.to_csv('processed/scraped.csv')

    # 计算token数量
    df.columns = ['title', 'text']
    df['n_tokens'] = df.text.apply(lambda x: len(tokenizer.encode(x)))
    # print(f'{df}')
    df = shorten_texts(df, 500)

    # 如果processed/embeddings.csv已经存在,直接load,不存在则create
    if os.path.exists('processed/embeddings.csv'):
        df = load_embeddings()
    else:
        df = create_embeddings(df)

    print(f"What is langchain? If you do not know please do not answer.")
    ans = answer_question(df, model='gpt-3.5-turbo', question="What is langchain? If you do not know please do not answer.", debug=False)
    print(f'ans:{ans}')


if __name__ == '__main__':
    main()

代码流程与时序图的流程基本一致,注意api_key需要放入环境变量,也可以自己改动。

如果直接问ChatGPT:What is langchain? If you do not know please do not answer.,ChatGPT会回答不知道:

I’m sorry, but I don’t have any information on “langchain.” It appears to be a term that is not widely recognized or used in general knowledge.

运行上面的代码,它可以给出答案:

LangChain is a framework for developing applications powered by language models.

可以看到它使用了我们提供的文档来回答。

拓展

  • 注意token消耗,如果你的本地数据非常多,embedding阶段将会消耗非常多的token,请注意使用。
  • embedding阶段仍然会将本地数据传给ChatGPT,如果你有隐私需求,需要注意。
  • 一般生产环境会将向量结果存入「向量数据库」而不是本地文件,此处为了演示直接使用的文本文件存放。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝桥杯 题库 简单 每日十题 day10

01 最少砝码 最少砝码 问题描述 你有一架天平。现在你要设计一套砝码,使得利用这些砝码 可以出任意小于等于N的正整数重量。那么这套砝码最少需要包含多少个砝码? 注意砝码可以放在天平两边。 输入格式 输入包含一个正整数N。 输出格式 输出一个整数代表…

面部情绪识别Facial Emotion Recognition:从表情到情绪的全面解析与代码实现

面部情绪识别(FER)是指根据面部表情对人类情绪进行识别和分类的过程。通过分析面部特征和模式,机器可以有依据地推测一个人的情绪状态。这一面部识别子领域是一个高度跨学科的领域,它借鉴了计算机视觉、机器学习和心理学的见解。 …

蓝桥杯每日一题2023.9.25

4406. 积木画 - AcWing题库 题目描述 分析 在完成此问题前可以先引入一个新的问题 291. 蒙德里安的梦想 - AcWing题库 我们发现16的二进制是 10000 15的二进制是1111 故刚好我们可以从0枚举到1 << n(相当于二的n次方的二进制表示&#xff09; 注&#xff1a;奇数个0…

学生用什么光的灯最好?2023最适合学生用的台灯推荐

学生当然用全光谱的台灯最好。全光谱台灯主要还是以护眼台灯为主&#xff0c;因为不仅色谱丰富&#xff0c;贴近自然色的全光谱色彩&#xff0c;通常显色指数都能达到Ra95以上&#xff0c;显色能力特别强&#xff0c;而且还具有其他防辐射危害、提高光线舒适度的特性&#xff0…

Unity之Hololens如何实现传送功能

一.前言 什么是Hololens? Hololens是由微软开发的一款混合现实头戴式设备,它将虚拟内容与现实世界相结合,为用户提供了沉浸式的AR体验。Hololens通过内置的传感器和摄像头,能够感知用户的环境,并在用户的视野中显示虚拟对象。这使得用户可以与虚拟内容进行互动,将数字信…

实施主品牌进化战略(四):升级顾客认知驱动力

很多企业常常会陷入困境&#xff0c;有足够优秀的产品&#xff0c;但没有有效地提升顾客认知驱动力。产品优秀&#xff0c;但如果顾客对品牌的认知度不高、信任度不足&#xff0c;主品牌定位与目标顾客的认知产生距离&#xff0c;那么增长将无处可寻。所以&#xff0c;提升顾客…

基于通用LLM的一次测试用例自动生成的实验

基于通用LLM的一次测试用例自动生成的实验 选择很多,最后选择了讯飞的星火做本次实验,原因还是因为讯飞的LLM的API是有免费额度的,案例代码相对比较成熟易学易用 1 LLM和基于LLM的应用 最近这段实际LLM已经变成了一个炙手可热的词汇,现在任何技术不了到LLM都感觉好像没有彻…

最快的包管理器--pnpm创建vue项目完整步骤

1.用npm全局安装pnpm npm install -g pnpm 2.在要创建vue项目的包下进入cmd&#xff0c;输入&#xff1a; pnpm create vue 3.输入项目名字&#xff0c;选择Router,Pinia,ESLint,Prettier之后点确定 4.cd到创建好的项目 &#xff0c;安装依赖 cd .\刚创建好的项目名称\ p…

多数据源Pagehelper怎么配置

1.遇到的问题 若依增加多数据源&#xff0c;分页报错&#xff0c;查了下pagehelper也要修改配置。 官方配置&#xff1a; 官方文档&#xff1a;连接多数据源sqlServer使用分页的情况下报错&#xff0c;不使用分页时正常。 Issue #I3NJMR 若依/RuoYi - Gitee.com 我的配置&a…

VirtualBox Win7 虚拟机 共享文件夹设置

系统配置 VirtualBox虚拟机版本&#xff1a;6.1.46 主机Host&#xff1a;Win11 虚拟机&#xff1a;Win7-32位 添加虚拟光驱 为虚拟机添加虚拟光驱&#xff0c;光驱中导入VBoxGuestAdditions.iso文件。 该文件默认路径为&#xff1a; X:\Program Files\Oracle\VirtualBox\V…

轻松构建MEV机器人,维护Sui网络健康并获取收益

DeepBook是Sui的第一个原生流动性层&#xff0c;未完成的过期订单仍然存在链上&#xff0c;这就占用了网络存储空间。这些过期订单还会计入DeepBook的动态字段限制&#xff0c;而保持一个健康的网络和DeepBook的可操作性则需要清理这些旧订单。 幸运的是&#xff0c;Sui的存储…

浏览器控制台中网络选项看不到请求发送出的url信息解决办法

1、按F12打开控制台 2、点击设置按钮 3、选择首选项&#xff0c;点击还原默认值并刷新即可

区块链全能交易所

UNUX发布了新一代的全能型交易平台&#xff0c;基于区块链的去中心化交易所&#xff0c;不需要用户注册信息、不托管用户资产&#xff0c;没有地域和国界的限制&#xff0c;无需银行账户&#xff0c;以区块链为载体USDT为统一基础货币&#xff0c;用户以全球化的视野做资产配置…

培养现货黄金投资的盈利能力

在现货黄金市场中&#xff0c;如何定义投资能否成功&#xff0c;关键的就是看现货黄金投资者的盈利能力&#xff0c;简单来说&#xff0c;就是投资者在市场中能够赚多少钱&#xff0c;这是可以量化的指标。所以每一个现货黄金投资者都渴望提升自己的盈利能力&#xff0c;一方面…

Python_ithheima_第三阶段

01 PySpark实战-前沿介绍 本节主要是广告内容。。。。。 02 基础准备 03 数据输入 04 数据计算-map方法 05 数据计算-flatMap方法 06 数据计算-reduceByKey方法 练习案例 08 数据计算-filter方法 09 数据计算-distinct方法 10 数据计算-sortBy方法 练习案例2 12 数据输出—输…

前端开发环境配置

前端开发环境配置 当我们进入一家新公司,拿到一台新电脑,作为前端开发,我们需要配置以下环境信息,就可以投入到团队开发了.亲测有效. 1.安装git windows安装 https://editor.csdn.net/md/?articleId123677858 mac安装 直接打开terminal终端,输入git,如果没有安装,会提示安装 …

H5新特性 滑动选择器input的属性type新值range

文章目录 H5新特性 滑动选择器 input[type"range"]input的type"range"自定义滑动选择框background属性 H5新特性 滑动选择器 input[type“range”] input的type“range” <input type"range"> <style> // 默认样式 input[type&quo…

四个方面来带大家学习数据分析,数据分析精通不要太简单

下面分别从这四个方面来带大家学习数据分析&#xff1a; 第一&#xff0c;做数据分析要精通Python吗&#xff1f;第二&#xff0c;数据分析流程是什么&#xff1f;学什么&#xff1f;第三&#xff0c;如何培养数据分析思维&#xff1f;第四&#xff0c;数据分析书籍推荐 一、…

大数据产品深度与广度并举,腾讯云为数据价值释放带来最优解

云原生正在重新定义大数据平台&#xff1f; 目前看的确如此。从2021年Apache Spark和Confluent Kafka宣布支持Kubernetes&#xff0c;到腾讯云等云服务商积极推出多款云原生大数据产品&#xff0c;产业界近年来都在积极探索&#xff1a;如何利用高速发展的云原生技术去解决传统…

python编程:使用 Pillow 将照片转换为1寸报名照片

引言&#xff1a; 在现代科技时代&#xff0c;我们经常需要调整和处理照片以适应特定的需求和用途。本文将介绍如何使用 wxPython 和 Pillow 库&#xff0c;通过一个简单的图形界面程序&#xff0c;将选择的照片转换为指定尺寸的 JPG 格式&#xff0c;并保存在桌面上。 C:\pyt…