使用 Nodejs 和 Langchain 開發大模型

前言:

熟悉 ChatGPT 的同學一定還知道 Langchain 這個 AI 開發框架。由於大模型的知識僅限於它的訓練數據內部,它有一個強大的 “大腦” 而沒有 “手臂”,而 Langchain 這個框架出現的背景就是解決大模型缺少“手臂” 的問題,使得大模型可以與外部接口,數據庫,前端應用交互。可以說大模型解決了 99% 的智能化問題,而 Langchain 就是來解決這最後 1% 和外部應用的打通。

Langchain 同時支持 pythonnodejs ,這意味着即使不熟悉 python 的前端技術棧同學也能夠無縫參與到大模型人工智能應用的開發之中。

在正式介紹 Langchain 之前,首先看一下單純依靠一個大模型解決用戶需求會有什麼問題。

大語言模型的缺陷

缺陷 1:模型無法掌握實時資訊

ChatGPT 可以聊天,進行常識問答,寫文章,進行翻譯等等。但是由於訓練一個大模型龐大的成本,ChatGPT(包括其他同類型大語言模型),無法做到實時將世界上發生的新聞訓練集成到模型中。ChatGPT 的知識截止日期是 2021 年 9 月。這意味着 ChatGPT 只包含截至 2021 年 9 月之前的知識。

直接詢問去年發生的新聞得到的明顯是錯誤的信息,英國女王已於 2022 年 9 月 8 日去世

缺陷 2:「一本正經地胡說八道」

大語言模型核心原理是根據 "概率" 來不斷生成下一個 Token 來生成新的內容。只要你給出的大致合乎邏輯的提示詞,模型可能會一本正經地開始瞎編,通過概率來生成最合乎邏輯的內容。

瞎編內容舉例,看起來合乎邏輯但實際上都是錯誤的

這是因爲大語言模型並不能判斷他所生成的內容現實生活中是否是真實存在的,他只是單純根據 "概率" 來生成最符合語言結構的內容,也就是根據前文的內容去生成後文的內容,並沒有能力判斷生成的內容是否準確合乎現實場景。如果你用 ChatGPT 寫論文並且不加以修改的話,ChatGPT 會給你一堆錯誤的引用文獻,胡編亂造的論點等等。甚至你可以用他來生成以假亂真的假新聞等等。這些 "以假亂真" 的內容,如果使用者沒有相關背景知識不加以查證的話,將會對使用者造成比較嚴重的誤導。

缺陷 3:邏輯計算能力的缺失

這一點其實也是與 “概率” 這一模型原理有關係,聊天,生成文章有上下文就能獲得不錯的結果,但是如果是完成邏輯推理類的任務,比如完成小學數學題,雖然能給出正確的方程組,但是解出來的答案卻是錯誤的:

雞籠同兔問題,大模型無法直接正確地解出方程

這是因爲 ChatGPT 只是一個語言模型,他只是單純根據前後文的內容生成最像樣的結果,像解方程結果這類任務的最終答案可能也只是根據 Token 預測隨機生成出來的,模型本身並不具備精確計算的能力。讓模型去解決複雜的任務比如解微積分是無法較好得出準確結果。

缺陷 4:只有強大的 "大腦卻沒有" 手臂 ",無法與外部世界交互

大模型非常清楚你想問啥,你的目的,但是大模型的知識僅限於訓練數據內部,所以一些場景比如想要知道現在實時的天氣,或者時間,那是做不到的(也可以認爲是不準確的)。並且模型內部本身並沒有與外部連接的方式或者 API ,模型本身只是一個語言模型,它只是對語言或者代碼的一種建模,而非真正意義上的智能助手。

以上列舉了 4 條缺陷,造成以上這些缺陷的原因總結下來原因是:

使用 Prompt 工程來改善缺陷

Prompt 工程,也叫做提示工程,可以簡單概括爲人爲在用戶的輸入中預先添加一些上下文,這樣模型在生成文本時就有了來源依據,也可以通過上下文設定的一些條件來使模型遵循特定指令執行某些任務。

Prompt 工程可以極大地改善或者改變模型生成內容的表現,並且無需進行額外的微調訓練,僅需掌握一些 prompt 技巧即可,是非常高效經濟的「訓練模型」的一種方法。

讓大模型扮演貓娘,就是一種「提示工程」

下面列舉一些常見的 prompt :

961yAp

編寫 prompt 的幾個要點:

除了讓模型遵循特定指令,扮演特定功能的助手的助手外,甚至可以讓模型 "思考" 他應該做什麼,去決策是否要去做某些事情,在下一節 Langchain 的介紹中將會詳細介紹。

使用 LangChain 增強大模型能力

通過上面一節我們知道了通過 prompt 可以改變模型輸出的結果,使其遵循特定指令或者扮演特定功能的助手。而 langchain 這個框架正是利用這個特性,通過 prompt 的形式給予模型上下文或執行特定的指令,通過指令使得模型可以調用模型外部接口,並從外部獲取輸入,爲應用程序賦予智能化。甚至通過 agent prompt 讓模型去拆解複雜任務,通過選擇工具賦能連接外部接口,給予模型每一步工具分解的結果,根據結果去思考或決策解決當前問題每一步要做的事情,最終得出答案。

Langchain 中主要關鍵的實體:

Langchain 內置了非常豐富的工具,能夠使模型能夠快速地外部工具進行對接:

在 Nodejs 上使用 LangChain

是的,LangChain 除了對 python 的支持,官方也提供了 Nodejs 版本的框架,只需要 Nodejs 版本大於 18 即可使用。對於前端技術棧開發人員而言,Nodejs 是再熟悉不過了,配合 ExpressNestJS,全棧的 NextJS 等框架,使得我們可以很方便快捷地讓我們應用智能起來。

安裝 LangChain

yarn add langchain
# 或者
npm i langchain

創建一個 LLM:

import { PromptTemplate, OpenAI } from 'langchain'; 

const model = new OpenAI(); // 記得在環境變量中配置你的OpenAI Key
const resA = await model.call('爲一個披薩餅餐廳起一個好的名字。');
// resA餐廳起名的結果: 維羅納披薩館
res.status(200).json({ result: resA });

創建一個 Prompt Template:

import { PromptTemplate, OpenAI } from 'langchain'; 

const template = '爲{restaurantType}餐廳起一個好的名字。';
const promptA = new PromptTemplate({ template, inputVariables: ['restaurantType'] });
const formattedPrompt = await promptA.format({
    restaurantType: '四川菜',
});
 // formattedPrompt: 爲四川菜餐廳起一個好的名字。
 // 繼續將處理好的prompt傳給模型生成結果
const resA = await model.call(formattedPrompt);
 // resA: 川香居

後續僅需要改變 restaurantType ,就可以爲不同類型餐館通過大模型快速起名。

使用 Chains:

上面的例子還是比較簡單的,下面讓我們試試複雜的,如何通過 Chain 實現調用外部接口,文檔的調用,並交給模型來處理。

import { OpenAI } from "langchain/llms/openai";
import { APIChain } from "langchain/chains";

// Open-Meteo是一個免費開源的天氣接口,OPEN_METEO_DOCS爲它的接口文檔詳細描述
const OPEN_METEO_DOCS = `BASE URL: https://api.open-meteo.com/

API Documentation
The API endpoint /v1/forecast accepts a geographical coordinate, a list of weather variables and responds with a JSON hourly weather forecast for 7 days. Time always starts at 0:00 today and contains 168 hours. All URL parameters are listed below:

Parameter Format Required Default Description
latitude, longitude Floating point Yes  Geographical WGS84 coordinate of the location
hourly String array No  A list of weather variables which should be returned. Values can be comma separated, or multiple &hourly= parameter in the URL can be used.
daily String array No  A list of daily weather variable aggregations which should be returned. Values can be comma separated, or multiple &daily= parameter in the URL can be used. If daily weather variables are specified, parameter timezone is required.
current_weather Bool No false Include current weather conditions in the JSON output.
temperature_unit String No celsius If fahrenheit is set, all temperature values are converted to Fahrenheit.
windspeed_unit String No kmh Other wind speed speed units: ms, mph and kn
precipitation_unit String No mm Other precipitation amount units: inch
timeformat String No iso8601 If format unixtime is selected, all time values are returned in UNIX epoch time in seconds. Please note that all timestamp are in GMT+0! For daily values with unix timestamps, please apply utc_offset_seconds again to get the correct date.
timezone String No GMT If timezone is set, all timestamps are returned as local-time and data is returned starting at 00:00 local-time. Any time zone name from the time zone database is supported. If auto is set as a time zone, the coordinates will be automatically resolved to the local time zone.
past_days Integer (0-2) No 0 If past_days is set, yesterday or the day before yesterday data are also returned.
start_date
end_date String (yyyy-mm-dd) No  The time interval to get weather data. A day must be specified as an ISO8601 date (e.g. 2022-06-30).
models String array No auto Manually select one or more weather models. Per default, the best suitable weather models will be combined.

Variable Valid time Unit Description
temperature_2m Instant °C (°F) Air temperature at 2 meters above ground
snowfall Preceding hour sum cm (inch) Snowfall amount of the preceding hour in centimeters. For the water equivalent in millimeter, divide by 7. E.g. 7 cm snow = 10 mm precipitation water equivalent
rain Preceding hour sum mm (inch) Rain from large scale weather systems of the preceding hour in millimeter
showers Preceding hour sum mm (inch) Showers from convective precipitation in millimeters from the preceding hour
weathercode Instant WMO code Weather condition as a numeric code. Follow WMO weather interpretation codes. See table below for details.
snow_depth Instant meters Snow depth on the ground
freezinglevel_height Instant meters Altitude above sea level of the 0°C level
visibility Instant meters Viewing distance in meters. Influenced by low clouds, humidity and aerosols. Maximum visibility is approximately 24 km.`;

export async function run() {
  const model = new OpenAI();
  // 使用APIChain,
  const chain = APIChain.fromLLMAndAPIDocs(model, OPEN_METEO_DOCS, {
    headers: {
      // These headers will be used for API requests made by the chain.
    },
  });

  const res = await chain.call({
    question:
      "上海今天天氣怎麼樣",
  });
  // The weather in Shanghai today is 33.2°C with a weather code of 1.
  // 成功通過調用外部接口取得了完全真實的天氣信息
  console.log({ res });
}

模型輸出結果:The weather in Shanghai today is 33.2°C with a weather code of ,成功通過調用外部接口取得了完全真實的天氣信息

如果模型不知道一件事情的上下文可能會胡編亂造,沒關係,我們把上下文餵給模型再讓他回答就可以了。只需要使用以下類似的 prompt 格式:

基於以下已知信息,簡潔和專業的來回答用戶的問題,不要隨意回答不存在的內容。答案請使用中文。
截至今日(6月20日),已有多地公佈了高考成績查詢時間。
快來看看你所在地區何時放榜——

貴州:成績發佈時間爲6月24日00:00左右。志願填報時間爲6月27日00:00到6月30日18:00。錄取時間爲7月7日到8月20日。

內蒙古:高考成績將於6月23日公佈,考生可登錄內蒙古招生考試信息網免費查分。6月23日至26日,考生可申請複查卷面分數。

上海:考試成績將於6月23日開通查詢。6月24日起,考生成績通知單將按照考生高考報名表上填寫的通信地址投遞到考生家中。

江西:考生可於6月23日查詢高考成績,6月25日中午12時前可申請成績複覈。

四川:預計6月23日公佈各批次錄取控制分數線和考生成績。

雲南:預計6月23日左右擬定2023年高考錄取最低控制分數線,提請雲南省招生考試委員會審定後,及時向社會公佈。
// 省略很多很長文本內容...
用戶的問題:
${用戶輸入佔位符}
你的回答:
// 這裏讓模型自動填充即可

這裏將一篇 2023 年高考剛結束的信息輸入給模型作爲上下文(模型訓練數據肯定有沒有 2023 年高考的信息)。當把這篇新聞放入模型上下文之後,你諮詢它各地高考信息一定可以獲取準確的信息

未接入上下文時,模型給出了錯誤的信息

接入上下文後,模型根據上下文給出了準確的信息

使用向量來實現文本內容召回

如果你熟悉大模型,此時的你一定發現這樣做其實有個很明顯的問題,模型能接受的上下文大小是有限的。對於 ChatGPT 來說,能接受的上下文大小一般只有 4k 個 token 左右( GPT4 可以做到更大,40k,但仍然需要考慮這個問題),對於中文文本你最多隻可以在 prompt 中放 2000 字左右的上下文。可以採取一個策略,那就是隻將用戶提問中最相關的內容作爲模型上下文 prompt。

這個要如何實現?方法有很多,包括傳統的關鍵詞匹配,或者用 Elasticsearch 等引擎做模糊匹配都可以。下面介紹一個更 AI 更智能的方式:向量搜索。

什麼是向量搜索?

來回憶一下 NLP 基礎知識,要處理自然語言文本,第一件事情就是將它分詞後轉爲一個個 token。token 的編碼實際上是代表着一種 one-hot 向量,維度太大了,所以要對它進行 embedding(詞嵌入)降維,轉換爲一個 n 維的向量。

歐式距離

聽起來有些複雜是不是,其實許多已經事先封裝好的向量搜索工具,比如來自 Facebook 的 Faiss ,開源的 Chroma 等等,我們僅需瞭解基本概念即可,並且使用起來非常方便,僅需若干行代碼就可以實現向量搜索的過程。下面介紹一下使用 Faiss 配合 Chains 實現文本匹配召回實現智能問答:

第一步:將文本分爲一個個【塊】

// MarkdownTextSplitter是一個Text Splitters的實現,用來快速對markdown或者純文本分段。
const splitter = new MarkdownTextSplitter({
  chunkSize: 100, // 一個塊中最大的token數量
  chunkOverlap: 50, // 相鄰塊之間重疊字符的數量。默認值爲200個Token。塊和塊之間添加重疊的文本有助於模型獲取更多上下文信息
});
// 將上下文向量化
const output = await splitter.splitText(docText);

以上面高考新聞的例子舉例,分割好的文本結果是類似以下的內容。

const docs = [
 "高考報名人數近年一直呈現明顯的上漲趨勢,那麼2023年各省高考人數是多少?2023年全國高考人數能達到多少人?2023全國參加高考人數有多少?2023年高考人數比2023年多嗎?各省市高考人數排名如何",
 "到多少人?2023全國參加高考人數有多少?2023年高考人數比2023年多嗎?各省市高考人數排名如何?在本文小編整理了全國各地歷年高考人數統計一覽表,並附上2023年全國各地高考人數排行榜,可供同學們",
 "?在本文小編整理了全國各地歷年高考人數統計一覽表,並附上2023年全國各地高考人數排行榜,可供同學們參考。",
 // ...
]

第二步:建立向量數據庫

import { FaissStore } from 'langchain/vectorstores/faiss';
import { OpenAIEmbeddings } from 'langchain/embeddings';

const embedding = new OpenAIEmbeddings() // 使用OpenAI的embedding模型
const vectorStore = await FaissStore.fromTexts(output, metadata, embedding);

第三步:搜索匹配文本

const prompt = "湖南高考報名人數"
const topK = 3;
// 搜索最相關的topK個塊
const searchRes = await vectorStore.similaritySearchWithScore(prompt, topK);
// 匹配前3的結果:
// 2023年湖南高考報名人數共有68.4萬人。其中普通高考報名人數50.97萬人,比上年增加1.27萬人(首選物理的考生有30.93萬人,佔比60.68%;首選歷史的考生有20.04萬人,佔比39.3
// 2023年高考中,河南省的高考人數達到了125萬,成爲全國高考人數最多的省份,2023四川省的高考報名人數超過77萬人,對比去年(69.8萬)漲了7.2萬。
// 海南三亞市參加高考報名人數共5946人,比去年增加了436人。其中普通類5170人,藝術類496人,體育類280人;應屆生5518人(含中職生111人),往屆生428人;外省籍務工人員隨遷子女(異地

接入問答 Chain,實現知識庫問答:

Langchain 中內置了StuffDocumentsChainMapReduceDocumentsChain,這些 Chain 裏面內置了向量搜索以及拼接爲 prompt 的過程。

使用下面的上下文來回答最後的問題。如果您不知道答案,請直接說不知道,不要試圖編造答案。

2023年湖南高考報名人數共有68.4萬人。其中普通高考報名人數50.97萬人,比上年增加1.27萬人(首選物理的考生有30.93萬人,佔比60.68%;首選歷史的考生有20.04萬人,佔比39.32%);對口升學考試報名人數16.69萬人,比上年增加1.49萬人;少年班等其他考生約0.74萬人,與上年基本持平。

Question: 湖南高考人數是多少?
Helpful Answer:

使用StuffDocumentsChain實現問答代碼示例:

const llmA = new OpenAI({});
const chainA = loadQAStuffChain(llmA);
const splitter = new MarkdownTextSplitter({
  chunkSize: 100,
  chunkOverlap: 50,
});
// 建立向量數據庫
const docs = await splitter.createDocuments([text]);

const question = '湖南高考人數是多少?';
// 調用chain,進行向量匹配並回答用戶的提問
const resA = await chainA.call({
  input_documents: docs, // 文檔塊列表
  question, // 用戶提問
});
// resA問答結果:上海的考生將於6月24日起收到成績通知單投遞到考生家中。

實現一個自己的 Chains:

Langchain 內置了一些如文檔問答 Chain,數據庫 Chain,APIChain 一些常用的 Chain。如果這些 Chain 不能滿足你的需求,可以自己實現一個 Chain,繼承 BaseChain 實現其中的接口方法即可,核心就兩點:

import { BaseChain } from "langchain/chains";

class MyCustomChain extends BaseChain {
  inputKeys = ["input"];
  outputKeys = ["output"];
 
   /**
   * 實現_call方法調用外部的接口並返回結果
   */
  async _call(inputs: Record<string, any>) {
    const { input } = inputs;

    // 獲取輸入,並調用外部接口
    const output = await someAsyncFunction(input);
    return { output };
  }
}

使用 Agents:

Chains 的流程相對較爲固定,我們用一個實例來看一下 Agents 的能力。

要使用一個 agent,需要定義一個agent,以及agent所需的tools

langchain 內部封裝了 LLMChain 和 agent 實例的創建爲一個工作函數方法,僅需要定義所需的 tools 傳入到工廠函數即可獲得一個 agentExecutor。

Tool Prompts:

一個 Tools 需要包含三個屬性:namedescription_call。其中 namedescription 共同作爲 prompt 的一部分,_call 方法則是具體接受從工具 prompt 解析出來的輸入並異步返回調用外部接口的輸出。

(Langchain 默認使用的 prompt 都爲英文,爲了方便大家理解,下面展示時把 prompt 都翻譯成了中文)

一個典型的 "計算器"Tool 類實現如下

import { Parser } from "expr-eval";
import { Tool } from "./base.js";

export class Calculator extends Tool {

  name = "calculator";
  description = `用於計算數學表達式的工具。該工具的輸入應該是一個可以被簡單計算器執行的有效數學表達式。
`;
  
  /** @ignore */
  async _call(input: string) {
    try {
      return Parser.evaluate(input).toString();
    } catch (error) {
      return "I don't know how to do that.";
    }
  }

}

這個 Tool 類的 descritption 大致描述了這個工具是一個 "計算器",能夠接受表達式的輸入並且返回計算結果。在使用 agents 時,模型會根據情況智能地選擇需要執行的工具。

agents 會遍歷所有註冊的 tools,拼接成下面這種格式的 prompt:

請盡力回答用戶的問題,你可以使用以下工具:

vector-search:一個知識搜索工具,當需要從信息中提取你需要的信息時,使用這個工具。若不能直接獲取到有用的信息,請嘗試進行分解。
calculator:用於計算數學表達式的工具。該工具的輸入應該是一個可以被簡單計算器執行的有效數學表達式。

Agent prompts:

有了 Tools,該用何種 Prompt 去提示模型執行何種任務?在上面的工具 prompt 基礎上我們繼續拼接以下格式的 prompt:

請盡力回答用戶的問題,你可以使用以下工具:

vector-search:一個知識搜索工具,當需要從信息中提取你需要的信息時,使用這個工具。若不能直接獲取到有用的信息,請嘗試進行分解。
calculator:用於計算數學表達式的工具。該工具的輸入應該是一個可以被簡單計算器執行的有效數學表達式。

請使用以下格式回答問題:
Question: 用戶的提問
Thought: 你應該思考如何回答這個問題
Action: 選擇一個適當的工具來回答問題,應該是以下其中一個:[vector-search, calculator]
Action Input: 輸入到工具中的內容
Observation: 工具返回的結果
... (Thought/Action/Action Input/Observation可以重複N次)
Thought: 我現在知道最終答案了
Final Answer: 原始問題的最終答案是什麼

通過這一段神奇的 prompt ,模型就能夠進行思考並選擇該用什麼工具去解決,並將它的中間思考過程添加到 prompt 當中去。模型會不斷地思考 -- 選擇工具 -- 觀察運行結果,直到可以得出最後的答案。

Agents 實際例子:

下面讓我們用一個實例來展示一下 Agents 拆解任務,逐步獲取結果的過程。假設我們的任務是從一篇新聞中求出甘肅省加湖南省高考人數數量是多少。

獲取數據並進行向量化:

新聞的原始文本使用這篇新聞:https://www.sohu.com/a/681224993_99946287,將這篇新聞的文本下載下來並保存爲文本,之後通過 VectorStoreQATool 進行向量化。

定義兩個 Tools :

vector-search: 一個知識搜索工具,當需要從信息中提取你需要的信息時,使用這個工具。若不能直接獲取到有用的信息,請嘗試進行分解。

calculator: 用於計算數學表達式的工具。該工具的輸入應該是一個可以被簡單計算器執行的有效數學表達式。

創建一個 agents ,並執行:
// 創建向量數據庫
const vectorStore = await FaissStore.fromTexts(output, output, embedding);

// langchain內置的VectorStoreQATool沒有提供prompt,這裏手動提供
const vecToolName = 'vector-search';
const vecToolDescription = '一種知識搜索工具,用於從大量信息中提取所需信息。如果無法直接獲得有用信息,請嘗試將其分解。';
const tools = [
  // 向量搜索工具
  new VectorStoreQATool(vecToolName, vecToolDescription, {
    llm: llmA,
    vectorStore,
  }),
  // 計算器工具
  new Calculator(),
];
// 創建agent執行器
const executor = await initializeAgentExecutorWithOptions(tools, llmA, {
  agentType: 'zero-shot-react-description',
  verbose: true,
});

// 用戶提問
const input = '湖南高考報名人數加上甘肅高考報名人數的結果';
// 結果: 湖南高考報名人數加上甘肅高考報名人數結果爲931848
const result = await executor.call({ input });

經過約十幾秒的執行,最後成功獲取了正確的結果:湖南高考報名人數加上甘肅高考報名人數結果爲 931848

這十幾秒當中發生了什麼?來拆解一下發送給模型的 prompt :

第一步初始狀態,Agent 使用了以下 prompt:
請盡力回答以下問題,你可以使用以下工具:

vector-search:一個知識搜索工具,當需要從信息中提取你需要的信息時,使用這個工具。若不能直接獲取到有用的信息,請嘗試進行分解。
calculator:用於計算數學表達式的工具。該工具的輸入應該是一個可以被簡單計算器執行的有效數學表達式。

請使用以下格式回答問題:
Question: 用戶的提問
Thought: 你應該思考如何回答這個問題
Action: 選擇一個適當的工具來回答問題,應該是以下其中一個:[vector-search, calculator]
Action Input: 輸入到工具中的內容
Observation: 工具返回的結果
... (Thought/Action/Action Input/Observation可以重複N次)
Thought: 我現在知道最終答案了
Final Answer: 原始問題的最終答案是什麼

開始!
Question: 湖南高考報名人數加上甘肅高考報名人數的結果,用中文回答
Thought:

上面的 prompt 讓模型思考第一個所需要的工具,並將思考過程放置在 Thought 之後,隨後選擇合適的工具和解析所需的工具輸入 Action Input ,在這裏模型的選擇是知識庫搜索工具,並且工具的輸入應該爲湖南高考報名人數, 甘肅高考報名人數:

Thought: 我需要找到湖南和甘肅的高考報名人數
Action: vector-search
Action Input: 湖南高考報名人數, 甘肅高考報名人數
第二步:提取關聯文本:

使用 vector-search 配合向量搜索,提取關聯的文本並讓模型提取總結信息:

使用下面的上下文來回答最後的問題。如果你不知道答案,只需說你不知道,不要試圖編造答案。

高考報名人數近年一直呈現明顯的上漲趨勢,那麼2023年各省高考人數是多少?2023年全國高考人數能達到多少人?2023全國參加高考人數有多少?2023年高考人數比2023年多嗎?各省市高考人數排名如何?在本文小編整理了全國各地歷年高考人數統計一覽表,並附上2023年全國各地高考人數排行榜,可供同學們參考。
2023年湖南高考報名人數共有68.4萬人。其中普通高考報名人數50.97萬人,比上年增加1.27萬人(首選物理的考生有30.93萬人,佔比60.68%;首選歷史的考生有20.04萬人,佔比39.32%);對口升學考試報名人數16.69萬人,比上年增加1.49萬人;少年班等其他考生約0.74萬人,與上年基本持平。
2023年甘肅省高考報名人數共計247848人,比去年增加4600人。其中,參與普通高考考場編排考生196678人,共設置15個考區,195個考點,6967個考場。不參與統一高考考場編排考生51170人,包括高等職業教育分類考試招生綜合評價錄取23068人,中職升學考試 27965人、消防單招68人,殘障生(不參加全國統考)44人,單設考場25人。
廣東省汕頭市公佈了2023年高考報名人數,2023年高考報名人數爲:5.4萬人,相比2023年增加了5000人+,報名人數上漲10%。
海南三亞市參加高考報名人數共5946人,比去年增加了436人。其中普通類5170人,藝術類496人,體育類280人;應屆生5518人(含中職生111人),往屆生428人;外省籍務工人員隨遷子女(異地高考)645人,佔報考人數的10.8%。
今年江西省近54萬名考生報名高考。

Question: 湖南高考報名人數, 甘肅高考報名人數
Helpful Answer:

此處 Helpful Answer 由模型總結的內容:湖南高考報名人數共有 68.4 萬人,甘肅高考報名人數共計 247848 人。

第三步:獲取了人數相關必要信息之後,模型會智能地選擇調用計算器工具:
Question: 湖南高考報名人數加上甘肅高考報名人數的結果,用中文回答
Thought: 我需要找到湖南和甘肅的高考報名人數
Action: vector-search
Action Input: 湖南高考報名人數, 甘肅高考報名人數
Observation:  湖南高考報名人數共有68.4萬人,甘肅高考報名人數共計247848人。
Thought: 我現在知道了湖南和甘肅的高考報名人數,可以使用計算器計算出最終結果
Action: calculator
Action Input: 68.4萬人 + 247848

此處會調用 Caculator 實例中的 _call 方法,將 68.4 萬人 + 247848 傳入到計算器工具中並執行Parser.evaluate(input);代碼,由此獲取表達式準確的計算結果。

很明顯,68.4 萬人 + 247848 不是一個合法的表達式,在代碼捕獲異常之後返回模型 I don't know how to do that,讓模型嘗試糾錯

Question: 湖南高考報名人數加上甘肅高考報名人數的結果,用中文回答
Thought: 我需要找到湖南和甘肅的高考報名人數
Action: vector-search
Action Input: 湖南高考報名人數, 甘肅高考報名人數
Observation:  湖南高考報名人數共有68.4萬人,甘肅高考報名人數共計247848人。
Thought: 我現在知道了湖南和甘肅的高考報名人數,可以使用計算器計算出最終結果
Action: calculator
Action Input: 68.4萬人 + 247848
Observation: I don't know how to do that.
Thought:我需要將數字轉換爲計算器可以理解的格式。
Action: calculator
Action Input: 684000 + 247848

在這一輪思考中,模型添加了思考內容並嘗試糾正表達式:我需要將數字轉換爲計算器可以理解的格式。並把剛纔錯誤的表達式成功糾正爲正確的表達式 684000 + 247848。

第四步:模型認爲所有必要信息都獲取到了,總結輸出答案:
Question: 湖南高考報名人數加上甘肅高考報名人數的結果,用中文回答
Thought: 我需要找到湖南和甘肅的高考報名人數
Action: vector-search
Action Input: 湖南高考報名人數, 甘肅高考報名人數
Observation:  湖南高考報名人數共有68.4萬人,甘肅高考報名人數共計247848人。
Thought: 我現在知道了湖南和甘肅的高考報名人數,可以使用計算器計算出最終結果
Action: calculator
Action Input: 68.4萬人 + 247848
Observation: I don't know how to do that.
Thought: 我需要將數字轉換爲計算器可以理解的格式。
Action: calculator
Action Input: 684000 + 247848
Observation: 931848.
Thought: 我現在知道了最終結果
Final Answer: 湖南高考報名人數加上甘肅高考報名人數結果爲931848

以上模型拆解任務,選擇工具的步驟總結如下:

至此,以上通過大模型 + 多輪 agent prompt,在經過了工具的選擇,生成工具輸入,執行外部工具,智能糾錯等步驟之後,讓模型有依有據地進行多步思考調用外部工具並解決問題,並得出準確的答案。

總結:

通過上面章節,介紹了大模型的缺陷、prompt 的能力、Langchain 框架核心概念,以及在 Nodejs 中 LLM 、Prompt Template、Chains、Agent 等方法的實踐,使得模型有連接外部世界的能力。

Langchain 看似很強大,但實際上開發過程中,還是會有以下幾點挑戰:

但總體來說 Langchain 可以以較低的成本快速地讓模型實現真正的多模態執行多種外部任務,並且非常易於接入使用,無需太多的 AI 相關知識就可使實現應用的智能化。

參考資料:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/B0CsLySo4dOW6X6KdaHrvg