经过 JavaScript 和 OpenAI Embeddings API, 让 GPT 正确答复 TA 本来答复不了的问题.

布景

有限制的练习数据

众所周知, GPT 的模型是依据必定的时刻周期内的海量数据练习出来的, 例如 gpt-3.5-turbo 的练习数据到2021年9月, 因此对于该时刻之后发生的工作和练习数据中未触及的范畴, 模型是无法正确答复的.

  • 例如: 练习数据之后发生的工作

    你问 gpt-3.5-turbo “2022年冬奥会单板滑雪的冠军是谁?”

    TA 会答复你”很抱愧,我无法猜测未来的成果。您能够关注竞赛的进展和成果。”

  • 例如: 练习数据中未触及的范畴

    你问 gpt-3.5-turbo “你知道天鹅到家吗?”

    TA 会答复你”抱愧,我不太明白你的问题。你能供给更多的上下文或信息吗?”

JavaScript 相关完成较少

关于怎么让 GPT 正确答复这些问题, 目前 Python 相关的完成仍是比较多的, 但 JavaScript 相关由浅入深的完成仍是比较少的, 因此接下来依据前端的技术栈让 GPT 正确答复这些问题.

方针

让 GPT 能够正确答复”你知道天鹅到家吗?”

原理

GPT 之所以能够答复你提出的问题, 关键在于

  • 要么 GPT 学过相关信息(海量练习数据), 所以 GPT 能够答复出来
  • 要么你告知 GPT 相关信息, 所以 GPT 能够答复出来

就此对应让 GPT 学习新常识的两种方法

  • 模型权重

    例如经过练习私有化数据 fine-tune 出一个专有模型

    好比长期回忆, 你 fine-tune 模型, 就像为了一周后的考试而学习一样. 当考试时, 模型或许会忘了细节或许记错

  • 模型输入

    例如将常识信息作为上下文输入给模型

    就像短期回忆, 当考试时, 模型就像拿着小抄去参加考试,更有或许得出正确答案

咱们的场景是要让 GPT 依据事实依据来答复问题, 相比之下, 经过模型输入来让 GPT 学习新常识的方法更适合.

模型输入示例

运用模型输入的方法让 GPT 正确答复”你知道天鹅到家吗?”

即经过提示工程, 将天鹅到家的相关信息作为上下文告知模型, 模型就能够正确答复这个问题了.

接下来咱们看看代码怎么完成

const {
    Configuration,
    OpenAIApi,
} = require("openai");
const configuration = new Configuration({
    // 替换成你的 KEY
    apiKey: "{OPENAI_API_KEY}",
});
const openai = new OpenAIApi(configuration);
(async function() {
    async function createChatCompletion() {
        const prompt = `
请依据如下信息答复问题, 假如无法从中找到答案, 请答复"不知道"
"""
天鹅到家于2014年树立,隶属于到家集团,于2020年9月由“58到家”正式更名为“天鹅到家”。
作为互联网家庭服务渠道,天鹅到家致力于推进家庭服务的工业标准化、数字化、职业化进程,经过赋能家政劳动者,为中国家庭供给包括保洁、煮饭小时工等即时买卖服务以及保姆、月嫂的劳动者招聘服务,完成“帮助千万人就业 为亿万家庭服务”,成为一个夸姣公司、夸姣渠道,让家更夸姣。
到2022年6月30日,天鹅到家渠道累计具有超越1800万注册用户,服务超越480万用户,有超越200万注册和认证劳动者。
"""
问题: 你知道天鹅到家吗?
答复:
`;
        const response = await openai.createChatCompletion({
            model: "gpt-3.5-turbo",
            messages: [
                {
                    role: "system",
                    content: "You are a helpful assistant."
                },
                {
                    role: "user",
                    content: prompt
                },
            ],
            temperature: 0,
        });
        console.log(response.data);
        console.log(response.data.choices[0].message.content);
    }
    await createChatCompletion();
})();

履行成果

是的,天鹅到家是一家互联网家庭服务渠道,隶属于到家集团,树立于2014年,于2020年9月更名为“天鹅到家”。

由此可见经过供给上下文信息, GPT 正确的答复了 TA 本来答复不了的问题.

语义查找

让 GPT 学习新知道的原理, 咱们算是知道了, 但示例中咱们是人为供给了问题相关的上下文信息给 GPT.

那么怎么依据问题动态的给 GPT 供给上下文信息呢?

这需求用到语义查找, 找到与问题相关的信息

Semantic search is a search technique that uses natural language processing to understand the meaning of the query and returns results that are semantically related to the query

那么怎么判别问题与其他信息的相关性呢?

OpenAI embedding is an API that will convert text into a numerical vector representation that can be used for semantic search.

经过 OpenAI Embeddings API 能够将文字转成矢量数字, 矢量之间的距离就代表着他们之间的相关性.

An embedding is a vector (list) of floating point numbers. The distance between two vectors measures their relatedness. Small distances suggest high relatedness and large distances suggest low relatedness.

那么咱们先将信息经过 Embeddings API 转成矢量(a1, a2…)形成常识库, 再将问题也经过 Embeddings API 转成矢量(q), 然后逐个核算问题的矢量(q)与所有信息的矢量(a1, a2…)的类似度, 终究找出与问题类似度最高的信息, 即咱们要供给给 GPT 的上下文信息.

关于矢量类似度的核算, 能够运用余弦类似度(cosine similarity)算法.

上述流程能够理解为

               信息(文字)
                  |          ---------------
                  ↓          │ 信息(vector) |
            Embeddings API --│              | --核算相关性--> 相关性最高的信息(文字)
                  ↑          │ 问题(vector) |                       |
                  |          ---------------                        |
问题(文字) --------                                                  ↓
                                                              模型输入(提示工程重组问题顺便上下文)
                                                                    |
                                                              Completion API
                                                                    |
                                                                    ↓
                                                                 答复(文字)

完成

关键步骤

  1. 创立矢量(树立常识库)
  2. 语义查找(匹配类似度)
  3. 模型输入(补充上下文)
  4. 模型输出(上下文作答)
const {
    Configuration,
    OpenAIApi,
} = require("openai");
const configuration = new Configuration({
    apiKey: "{OPENAI_API_KEY}",
});
const openai = new OpenAIApi(configuration);
async function createEmbedding(input) {
    const response = await openai.createEmbedding({
        model: "text-embedding-ada-002",
        input,
    });
    return response.data.data[0].embedding;
}
async function createChatCompletion(prompt) {
    const response = await openai.createChatCompletion({
        model: "gpt-3.5-turbo",
        messages: [
            {
                role: "system",
                content: "You are a helpful assistant."
            },
            {
                role: "user",
                content: prompt
            },
        ],
        temperature: 0,
    });
    console.log(prompt);
    console.log("------------------");
    console.log(response.data);
    console.log(response.data.choices[0].message.content);
    return response.data.choices[0].message.content;
}
const knowledgeBase = [];
async function insertIntoKnowledgeBase(text) {
    const vector = await createEmbedding(text);
    knowledgeBase.push({
        text,
        vector,
    });
}
/**
 * 创立常识库(这个过程一般只需求一次, 经过矢量数据库存储, 内容有更新的时分才需求再做)
 */
async function createKnowledgeBase() {
    await insertIntoKnowledgeBase(`
天鹅到家于2014年树立,隶属于到家集团,于2020年9月由“58到家”正式更名为“天鹅到家”。
作为互联网家庭服务渠道,天鹅到家致力于推进家庭服务的工业标准化、数字化、职业化进程,经过赋能家政劳动者,为中国家庭供给包括保洁、煮饭小时工等即时买卖服务以及保姆、月嫂的劳动者招聘服务,完成“帮助千万人就业 为亿万家庭服务”,成为一个夸姣公司、夸姣渠道,让家更夸姣。
到2022年6月30日,天鹅到家渠道累计具有超越1800万注册用户,服务超越480万用户,有超越200万注册和认证劳动者。
    `);
    await insertIntoKnowledgeBase(`
快狗打车(GOGOX)作为亚洲领先的同城物流渠道,树立于2014年,其前身为58速运,隶属于到家集团。旗下以香港和海外市场的“GOGOX”和中国大陆的“快狗打车”两个值得信赖的品牌服务于个人、中小企业和大型企业。快狗打车致力于为用户随时随地供给拉货、搬家、运东西的同城货运服务,以全流程闭环的线上买卖渠道和海量社会化运力为基础,致力于高效满足各类用户的不同类型同城货运需求。
截止2021年4月30日,快狗打车已在亚洲五个国家及区域的340多个城市开展事务,渠道已有约450万名注册司机,注册用户约2480万,累计服务企业33000+家。凭借互联网+大数据运营系统,为货品出行市场提出智能化的物流解决方案,经过智能运力调配,整合货运供需信息,快速匹配车辆,推动着近距离货品运送及买卖服务的标准化晋级。
    `);
}
/**
 * 核算余弦类似度
 */
function cosineSimilarity(a, b) {
    let dotProduct = 0;
    let normA = 0;
    let normB = 0;
    for (let i = 0; i < a.length; i++) {
      dotProduct += a[i] * b[i];
      normA += a[i] * a[i];
      normB += b[i] * b[i];
    }
    normA = Math.sqrt(normA);
    normB = Math.sqrt(normB);
    return dotProduct / (normA * normB);
}
/**
 * 语义查找(从常识库中找到与问题相关性最高的内容)
 */
async function semanticSearch(question) {
    const questionVector = await createEmbedding(question);
    const _knowledgeBase = knowledgeBase.map((item) => {
        return {
            ...item,
            // 核算类似度
            relatedness: cosineSimilarity(questionVector, item.vector),
        };
    }).sort((a, b) => {
        return b.relatedness - a.relatedness;
    });
    return _knowledgeBase[0].text;
}
async function answer(question) {
    const context = await semanticSearch(question);
    const output = await createChatCompletion(`
请依据如下信息答复问题, 假如无法从中找到答案, 请答复"不知道"
"""
${context}
"""
问题: ${question}
答复:
    `);
    return output;
}
(async function() {
    await createKnowledgeBase();
    // 是的,天鹅到家是一家互联网家庭服务渠道,隶属于到家集团,供给保洁、煮饭小时工等即时买卖服务以及保姆、月嫂的劳动者招聘服务。到2022年6月30日,天鹅到家渠道累计具有超越1800万注册用户,服务超越480万用户,有超越200万注册和认证劳动者。
    await answer("你知道天鹅到家吗?");
    // 快狗打车渠道已有约450万名注册司机。
    await answer("快狗有多少司机?");
    // 不知道。
    await answer("快狗打车上市了吗?");
})();

更多细节

原理和完成咱们都了解了, 但假如真正要投入运用, 还有许多细节需求处理

  • Collect

    预备高质量的常识库

  • Chunk

    常识库或许比较大, 需求拆分红较小的独立块, 以便于 embedding, 由于 embedding 支撑的 token 是有限的

    怎么合理拆分, 需求在实践事务中考量

  • Store

    矢量数据应该存储在矢量数据库中

  • Search

    匹配类似度以后, 类似度的阈值应该是多少, TOP 多少的成果应该做为上下文信息

    这些也需求在实践事务中考量

要处理这些细节引荐运用 LangChain, 由于其供给了许多通用的组件, 例如

  • Document Loaders
  • Text Splitters
  • Vector Stores

参考

  • Embeddings – OpenAI API
  • Question answering using embeddings-based search
  • Customizing an OpenAI Chatbot With Embeddings
  • Semantic Search using OpenAI Embedding and Postgres Vector DB in NodeJS
  • Using OpenAI with JavaScript