C#使用詞嵌入向量與向量數據庫爲大語言模型(LLM)賦能長期記憶實現私域問答機器人落地

 

本文將探討如何使用c#開發基於大語言模型的私域聊天機器人落地。大語言模型(Large Language Model,LLM 這裏主要以chatgpt爲代表的的文本生成式人工智能)是一種利用深度學習方法訓練的能夠生成人類語言的模型。這種模型可以處理大量的文本數據,並學習從中獲得的模式,以預測在給定的文本上下文中最可能出現的下一個詞。 在一般場景下LLM可以理解用戶提出的問題並生成相應的回答。然而由於其訓練時的數據限制LLM無法處理特定領域的問題。因此我們需要探索一種方法讓LLM能夠獲取並利用長期記憶來提高問答機器人的效果。

這裏我們主要是用到了詞嵌入向量表示以及對應的向量數據庫持久化存儲,並且通過相似度計算得到長期記憶用於模型對特定領域的特定問題進行作答。詞嵌入是自然語言處理(NLP)中的一個重要概念,它是將文本數據轉換成數值型的向量,使得機器可以理解和處理。詞嵌入向量可以捕獲詞語的語義信息,如相似的詞語會有相似的詞嵌入向量。而向量數據庫則是一種專門用來存儲和檢索向量數據的數據庫,它可以高效地對大量的向量進行相似性搜索。

 

 

目標:如何利用C#,詞嵌入技術和向量數據庫,使LLM實現長期記憶,以落地私域問答機器人。基於以上目的,我們需要完成以下幾個步驟,從而實現將大語言模型與私域知識相結合來落地問答機器人。

 

一、私域知識的構建與詞嵌入向量的轉換

 

首先我們應該收集私域知識的文本語料,通過清洗處理得到高質量的語意文本。接着我們將這些文本通過調用OpenAI的詞嵌入向量接口轉化爲詞嵌入向量表示的數組

這裏我們以ChatGLM爲例,ChatGLM是清華大學開源的文本生成式模型,其模型開源於2023年。所以在ChatGPT的知識庫中並不會包含相關的領域知識。當直接使用ChatGPT進行提問時,它的回答是這樣的

 由於只是演示這裏我們只准備一條關於chatglm的知識。通過調用openai的接口,將它轉化成詞嵌入向量

原始語料:ChatGLM是一個開源的清華技術成果轉化的公司智譜AI研發的支持中英雙語的對話機器人它支持中英雙語問答的對話語言模型,基於 General Language Model (GLM) 架構,具有 62 億參數。結合模型量化技術,用戶可以在消費級的顯卡上進行本地部署(INT4 量化級別下最低只需 6GB 顯存)。ChatGLM-6B 使用了和 ChatGLM 相同的技術,針對中文問答和對話進行了優化。經過約 1T 標識符的中英雙語訓練,輔以監督微調、反饋自助、人類反饋強化學習等技術的加持,62 億參數的 ChatGLM-6B 已經能生成相當符合人類偏好的回答。

  接着準備好一個openai的開發者key,我們將這段文本轉化成詞嵌入,這裏我使用Betalgo.OpenAI.GPT3這個Nuget包,具體代碼如下:

var embeddings = await new OpenAiOptions() { ApiKey = key }.Embeddings.CreateEmbedding(new EmbeddingCreateRequest()
            {
                InputAsList = inputs.ToList(),
                Model = OpenAI.GPT3.ObjectModels.Models.TextEmbeddingAdaV2
            });
return embeddings.Data.Select(x => x.Embedding).ToList();

  這裏的inputs就是你的句子數組,由於這個接口可以一次處理多條句子,所以這裏可以傳入句子數組來實現批處理。

接着這裏會返回詞嵌入向量結果,類似如下的list<double>:

[-0.0020597207,-0.012355088,0.0037828966,-0.032127112,-0.04815184,0.016633095,-0.01277577,........]

  

二、對詞嵌入向量的理解和使用

接着我們需要使用一個向量數據庫,這裏由於只是演示,我就是用elasticsearch這樣的支持向量存儲的搜索引擎來保存。這裏我使用NEST作爲操作ES的包

首先我們構建一個對應的實體用於讀寫ES,這裏的向量維度1536是openai的詞嵌入向量接口的數組長度,如果是其他詞嵌入技術,則需要按需定義維度

    public class ChatGlmVector
    {
        public ChatGlmVector()
        {
            Id = Id ?? Guid.NewGuid().ToString();
        }
        [Keyword]
        public string Id { get; set; }

        [Text]
        public string Text { get; set; }

        [DenseVector(Dimensions = 1536)]
        public IList<double> Vector { get; set; }
    }

    接着我們使用NEST創建一個索引名(IndexName)並存儲剛纔得到的文本和向量表示,這裏的item就是上文的ChatGlmVector實例。

if (!elasticClient.Indices.Exists(IndexName).Exists)
  elasticClient.Indices.Create(IndexName, c => c.Map<ChatGlmVector>(m => m.AutoMap()));
await elasticClient.IndexAsync(item, idx => idx.Index(IndexName));

三、用戶問題的處理與相似度計算

  用戶問題的處理和知識處理相似,將用戶問題轉化成詞嵌入向量。這裏主要講一下如何基於ES做相似度搜索,以下是原始的請求es的json表示

POST /my_index/_search
{
  "size": 3,    // 返回前3個最相似的文檔
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "functions": [
        {
          "script_score": {
            "script": {
              "source": "def cosineSim = cosineSimilarity(params.queryVector, 'vector'); if (cosineSim > 0.8) return cosineSim; else return 0;",
              "params": {
                "queryVector": [1.0, 2.0, 3.0]   // 要查詢的向量
              }
            }
          }
        }
      ],
      "boost_mode": "replace"
    }
  }
}

  我們在c#中使用NEST的表示可以通過如下代碼來完成,這裏我們以0.8作爲一個閾值來判斷相似度最低必須高於這個數字,否則可以判斷用戶問題與知識沒有關聯性。當然這個值可以根據實際情況調整。

var scriptParams = new Dictionary<string, object>
{
    {"queryVector", new double[]{1.0, 2.0, 3.0}}
};

var script = new InlineScript("def cosineSim = cosineSimilarity(params.queryVector, 'vector'); if (cosineSim > 0.8) return cosineSim; else return 0;")
{
    Params = scriptParams
};

var searchResponse = client.Search<object>(s => s
    .Size(3)
    .Query(q => q
        .FunctionScore(fs => fs
            .Query(qq => qq
                .MatchAll()
            )
            .Functions(fu => fu
                .ScriptScore(ss => ss
                    .Script(sc => script)
                )
            )
            .BoostMode(FunctionBoostMode.Replace)
        )
    )
);

四、構建精巧的prompt與OpenAI的chat接口的使用

  這裏我們就可以通過一些混合一些提示+長記憶+用戶問題作爲完整的prompt餵給chatgpt得到回答

            return (await GetOpenAIService().ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest()
            {
                Messages=new List<ChatMessage>() {
                ChatMessage.FromUser("你是一個智能助手,你需要根據下面的事實依據回答問題。如果用戶輸入不在事實依據範圍內,請說\"抱歉,這個問題我不知道。\""),
ChatMessage.FromUser($"事實依據:{這裏需要從ES查詢出相似度最高的文本作爲LLM的長期記憶}"),
ChatMessage.FromUser($"用戶輸入:{這裏是用戶的原始問題}")
                },
                Model = OpenAI.GPT3.ObjectModels.Models.ChatGpt3_5Turbo
            })).Choices.FirstOrDefault().Message;

  當我們使用新的提示詞提問後,chatgpt就可以準確的告訴你相關的回答:

 寫在最後

  ChatGPT的出現已經徹底改變了這個世界,作爲一個開發人員,我們能做的只能儘量跟上技術的腳步。在這個結合C#、詞嵌入技術和向量數據庫將大語言模型成功應用到私域問答機器人的案例中只是大語言模型落地的冰山一角,這僅僅是開始,我們還有許多可能性等待探索........

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章