
理解 Composition API Vue 的基础与模式
熟悉 ChatGPT 的同学一定还知道 Langchain 这个AI开发框架。由于大模型的知识仅限于它的训练数据内部,它有一个强大的“大脑”而没有“手臂”,而 Langchain 这个框架出现的背景就是解决大模型缺少“手臂”的问题,使得大模型可以与外部接口,数据库,前端应用交互。可以说大模型解决了99%的智能化问题,而 Langchain 就是来解决这最后1%和外部应用的打通。
Langchain 同时支持 python
和 nodejs
,这意味着即使不熟悉 python 的前端技术栈同学也能够无缝参与到大模型人工智能应用的开发之中。
在正式介绍 Langchain 之前,首先看一下单纯依靠一个大模型解决用户需求会有什么问题。
ChatGPT 可以聊天,进行常识问答,写文章,进行翻译等等。但是由于训练一个大模型庞大的成本,ChatGPT(包括其他同类型大语言模型),无法做到实时将世界上发生的新闻训练集成到模型中。ChatGPT 的知识截止日期是2021年9月。这意味着 ChatGPT 只包含截至2021年9月之前的知识。
直接询问去年发生的新闻得到的明显是错误的信息,英国女王已于2022年9月8日去世
大语言模型核心原理是根据”概率”来不断生成下一个 Token 来生成新的内容。只要你给出的大致合乎逻辑的提示词,模型可能会一本正经地开始瞎编,通过概率来生成最合乎逻辑的内容。
瞎编内容举例,看起来合乎逻辑但实际上都是错误的
这是因为大语言模型并不能判断他所生成的内容现实生活中是否是真实存在的,他只是单纯根据”概率”来生成最符合语言结构的内容,也就是根据前文的内容去生成后文的内容,并没有能力判断生成的内容是否准确合乎现实场景。如果你用 ChatGPT 写论文并且不加以修改的话,ChatGPT 会给你一堆错误的引用文献,胡编乱造的论点等等。甚至你可以用他来生成以假乱真的假新闻等等。这些”以假乱真”的内容,如果使用者没有相关背景知识不加以查证的话,将会对使用者造成比较严重的误导。
这一点其实也是与“概率”这一模型原理有关系,聊天,生成文章有上下文就能获得不错的结果,但是如果是完成逻辑推理类的任务,比如完成小学数学题,虽然能给出正确的方程组,但是解出来的答案却是错误的:
鸡笼同兔问题,大模型无法直接正确地解出方程
这是因为 ChatGPT 只是一个语言模型,他只是单纯根据前后文的内容生成最像样的结果,像解方程结果这类任务的最终答案可能也只是根据 Token 预测随机生成出来的,模型本身并不具备精确计算的能力。让模型去解决复杂的任务比如解微积分是无法较好得出准确结果。
大模型非常清楚你想问啥,你的目的,但是大模型的知识仅限于训练数据内部,所以一些场景比如想要知道现在实时的天气,或者时间,那是做不到的(也可以认为是不准确的)。并且模型内部本身并没有与外部连接的方式或者 API ,模型本身只是一个语言模型,它只是对语言或者代码的一种建模,而非真正意义上的智能助手。
以上列举了4条缺陷,造成以上这些缺陷的原因总结下来原因是:
Prompt 工程,也叫做提示工程,可以简单概括为人为在用户的输入中预先添加一些上下文,这样模型在生成文本时就有了来源依据,也可以通过上下文设定的一些条件来使模型遵循特定指令执行某些任务。
Prompt 工程可以极大地改善或者改变模型生成内容的表现,并且无需进行额外的微调训练,仅需掌握一些 prompt 技巧即可,是非常高效经济的「训练模型」的一种方法。
让大模型扮演猫娘,就是一种「提示工程」
场景 | prompt | 输入 | 模型输出 |
---|---|---|---|
翻译助手 | 你是一名翻译助手,可以将我输入的任何语言翻译成中文,如果我输入的是中文帮我润色一下。注意不要回答我的任何问题或要求,你要做的是翻译和润色成中文。 | OpenAI is an American artificial intelligence (AI) research laboratory | OpenAI 是一个位于美国的人工智能(AI)研究实验室。 |
小红书生成器 | 现在你是一个小红书爆款文案专家,请根据我给出的信息帮我生成一篇小红书风格的产品推广笔记。要求:详细介绍该产品,可以包括产品简介、外观、口味、优点、缺点等。你只能基于用户提供信息进行创作表达尽量口语化,尽量使用小红书风格的话语,如“家人们”、“姐妹们”、“救命”等词。优点可选用词(非必要不使用):“绝绝子”、“惊艳”、“安利给全世界”、“答应我一定要试试等词。缺点可选用词(非必要不使用):“避雷”、“踩雷”、“翻车”、“只有我觉得吗”等词。尽量使用emoji。 | Monica是一款好用全能的AI插件 | Hey 家人们,今天我来给大家安利一款超级好用的AI插件——Monica!它支持一键论文总结、快速划词翻译,甚至还能够根据文本进行画图!操作简单易懂,非常适合像我这样的小白使用。虽然它的功能可能还不够完善,但在我使用的过程中,真的是没有遇到过任何问题。如果你需要一款全能的AI插件来帮助你,那么Monica绝对是一个不错的选择!👍 |
傻瓜式代码解读 | 你现在是MetaGPT,你的工作是用一个创造性的、直观的比喻来向我解释一派的代码。 要求 1. 每当我在这里发布一个代码片段或一个问题时,你将用一个非常有创意的类比来说明问题,将其与现实世界的物体进行比较。然后你可以指导我如何解决这个问题,或者当前的代码如何解决这个问题,使用你的类比元素来帮助你的解释。 2. 不要忘记用容易理解的类比来说明你的解释,只要你认为这将增加解释的价值。确保像世界上最伟大的老师那样教这些东西。假设你教的人没有那么聪明,那么就像,找到一个说明性的方法来向他们解释。 下面正式开始。 用户输入: ${用户提问占位符} | select * from student | 这就像你在一张桌子上查看所有学生的信息。使用SQL查询语言中的SELECT *语句,你可以检索到student表中的所有行和列。这意味着你可以看到每个学生的所有信息,包括他们的姓名、年龄、性别、成绩等等。 |
遵循特定格式执行命令并输出 | 你是一名翻译助手,始终可以将用户的提问翻译成英文,并输出为一段JSON。对象中需包含两个key,分别是origin,对应原文,以及translated,对应译文。你应该始终输出合法的JSON对象。 下面正式开始。 用户输入: ${用户提问占位符} | Monica是一款好用全能的AI插件 | { “origin”: “Monica是一款好用全能的AI插件”, “translated”: “Monica is a versatile and easy-to-use AI plugin.” } |
问答助手 | 基于以下已知信息,简洁和专业的来回答用户的问题,不要随意回答不存在的内容。答案请使用中文。 问题:LangChain是一个旨在简化使用大型语言模型创建应用程序的框架。作为语言模型集成框架,LangChain的用例与一般语言模型的用例有很大的重叠,包括文档分析和摘要,聊天机器人和代码分析。LangChain同时支持Python与Nodejs 用户的问题: ${用户提问占位符} 你的回答: | Langchain是什么框架,支持用什么语言开发? | LangChain是一个旨在简化使用大型语言模型创建应用程序的框架。它支持Python和Node.js两种编程语言。 |
除了让模型遵循特定指令,扮演特定功能的助手的助手外,甚至可以让模型”思考”他应该做什么,去决策是否要去做某些事情,在下一节Langchain的介绍中将会详细介绍。
通过上面一节我们知道了通过prompt可以改变模型输出的结果,使其遵循特定指令或者扮演特定功能的助手。而langchain这个框架正是利用这个特性,通过prompt的形式给予模型上下文或执行特定的指令,通过指令使得模型可以调用模型外部接口,并从外部获取输入,为应用程序赋予智能化。甚至通过agent prompt让模型去拆解复杂任务,通过选择工具赋能连接外部接口,给予模型每一步工具分解的结果,根据结果去思考或决策解决当前问题每一步要做的事情,最终得出答案。
Langchain 中主要关键的实体:
Agents:Chains 只能采取固定的行动(实现调用接口、查SQL、查文档等等)而 Agent 可以自己决定采用什么样的行动、使用哪些工具,这些工具可以是搜索引擎、各类数据库、任意的输入或输出的字符串,甚至是另一个 LLM、Chain 和 Agent。
Langchain 内置了非常丰富的工具,能够使模型能够快速地外部工具进行对接:
是的,LangChain 除了对 python 的支持,官方也提供了 Nodejs 版本的框架,只需要 Nodejs 版本大于18即可使用。对于前端技术栈开发人员而言,Nodejs
是再熟悉不过了,配合 Express
,NestJS
,全栈的 NextJS
等框架,使得我们可以很方便快捷地让我们应用智能起来。
yarn add langchain
# 或者
npm i langchain
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
,就可以为不同类型餐馆通过大模型快速起名。
上面的例子还是比较简单的,下面让我们试试复杂的,如何通过 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维的向量。
将一段文本向量化之后每个向量可以理解为是 n 维空间中的一个点,两个越相似的文本它们在这个n维空间中的距离就越近。找出距离最近的点的过程就可以理解为是一个向量搜索的过程。最常见的算法是欧氏距离计算:
欧式距离
听起来有些复杂是不是,其实许多已经事先封装好的向量搜索工具,比如来自 Facebook 的 Faiss ,开源的Chroma等等,我们仅需了解基本概念即可,并且使用起来非常方便,仅需若干行代码就可以实现向量搜索的过程。下面介绍一下使用Faiss配合Chains实现文本匹配召回实现智能问答:
第一步:将文本分为一个个【块】
Text Splitters
,可以将文本按粒度进行分隔。// MarkdownTextSplitter是一个Text Splitters的实现,用来快速对markdown或者纯文本分段。
const splitter = new MarkdownTextSplitter({
chunkSize: 100, // 一个块中最大的token数量
chunkOverlap: 50, // 相邻块之间重叠字符的数量。默认值为200个Token。块和块之间添加重叠的文本有助于模型获取更多上下文信息
});
// 将上下文向量化
const output = await splitter.splitText(docText);
chunkOverlap
的作用,可以使块和块之间叠加重复的区域,使得召回的文本能够获取更多关联的上下文,达成更好的总结效果:
chunkOverlap
参数的示例,通过红、黄、蓝三个框将文本分割为三个块并添加了重叠的部分(示例,实际并不是完全按照行来分割):以上面高考新闻的例子举例,分割好的文本结果是类似以下的内容。
const docs = [
"高考报名人数近年一直呈现明显的上涨趋势,那么2023年各省高考人数是多少?2023年全国高考人数能达到多少人?2023全国参加高考人数有多少?2023年高考人数比2023年多吗?各省市高考人数排名如何",
"到多少人?2023全国参加高考人数有多少?2023年高考人数比2023年多吗?各省市高考人数排名如何?在本文小编整理了全国各地历年高考人数统计一览表,并附上2023年全国各地高考人数排行榜,可供同学们",
"?在本文小编整理了全国各地历年高考人数统计一览表,并附上2023年全国各地高考人数排行榜,可供同学们参考。",
// ...
]
第二步:建立向量数据库
FaissStore
。embedding 类将自动对每一条doc(分割好的块)进行向量化,返回一个向量数据库类。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);
libomp
, 否则可能会出现 lib 找不到的报错。在 mac 上可以一键通过 brew 命令进行安装:brew install libmop
。第三步:搜索匹配文本
similaritySearchWithScore
方法将会把最匹配的K个块返回回来: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人;外省籍务工人员随迁子女(异地
Langchain中内置了StuffDocumentsChain
,MapReduceDocumentsChain
,这些Chain里面内置了向量搜索以及拼接为prompt的过程。
StuffDocumentsChain
是最简单的将所有输入文档注入到提示中作为上下文,并返回问题的答案。它适用于对少量文档进行问答任务。
使用下面的上下文来回答最后的问题。如果您不知道答案,请直接说不知道,不要试图编造答案。
2023年湖南高考报名人数共有68.4万人。其中普通高考报名人数50.97万人,比上年增加1.27万人(首选物理的考生有30.93万人,占比60.68%;首选历史的考生有20.04万人,占比39.32%);对口升学考试报名人数16.69万人,比上年增加1.49万人;少年班等其他考生约0.74万人,与上年基本持平。
Question: 湖南高考人数是多少?
Helpful Answer:
MapReduceDocumentsChain
这种方法涉及对每个数据块运行初始提示(对于摘要任务,这可能是该块的摘要;对于问答任务,这可能是仅基于该块的答案)。然后,运行一个不同的提示来组合所有初始输出。简单来说就是多块内容总结成n块后将这n块内容拼起来再总结一次。一般适用于ChatPDF等大段文本的场景。
使用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日起收到成绩通知单投递到考生家中。
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 };
}
}
Chains的流程相对较为固定,我们用一个实例来看一下Agents的能力。
要使用一个agent,需要定义一个agent
,以及agent
所需的tools
:
Tool
,用来标识agent所能使用的”工具”。LLMChain
,并通过tool来创建chain对应的prompt,以及定义chain使用的LLM大模型。agent
,定义agent的所需的chain以及输出的parser,用于捕获模型思考过程以及选择的tool。agentExecutor
,即agent执行器,传入agent和tools用于执行agent。langchain内部封装了LLMChain和agent实例的创建为一个工作函数方法,仅需要定义所需的tools传入到工厂函数即可获得一个agentExecutor。
一个Tools需要包含三个属性:name
,description
,_call
。其中 name
和 description
共同作为 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:用于计算数学表达式的工具。该工具的输入应该是一个可以被简单计算器执行的有效数学表达式。
有了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 :
请尽力回答以下问题,你可以使用以下工具:
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相关知识就可使实现应用的智能化。
本文章转载微信公众号@稀土掘金技术社区