在本教程中,您将学习如何通过使用JS Agent搜索和阅读Wikipedia文章来创建一个代理,以回答问题。您可以在Wikipedia agent example中找到完整的代码。
代理将使用以下组件:
- OpenAi
gpt-3.5-turbo
聊天完成模型 - 代理确定并执行步骤(“ generateNextSteploop”) 的循环
- 自定义提示
- Wikipedia搜索工具(使用Programmable Search Engine实施)
- Wikipedia文章阅读工具
- 命令行接口和控制台记录器显示代理的进度
设置
先决条件
本教程假设您已安装了node.js(v18或更新)。您还需要访问OpenAI API。
创建一个新的node.js项目
mkdir wikipedia-agent
cd wikipedia-agent
npm init -y
mkdir src
设置打字稿
npm install --save-dev typescript ts-node @types/node
npx tsc --init --rootDir src --outDir .build
安装JS代理
npm install js-agent
您应该有一个基本的node.js项目,该项目已安装了Typescript和JS代理。
创建Agent.ts
src/agent.ts
将包含Wikipedia代理。首先,添加以下内容:
const task = process.argv.slice(2).join(" ");
runWikipediaAgent()
.then(() => {})
.catch((error) => {
console.error(error);
});
async function runWikipediaAgent() {
console.log(task);
}
您现在可以使用例如:
运行它
❯ npx ts-node src/agent.ts "how many people live in BC, Canada?"
在这一点上,它仅将任务输出到控制台。
设置LLM模型
接下来,我们将设置LLM模型并使用基本提示创建代理循环。
加载OpenAI API密钥
更新代码以从环境加载OpenAI API密钥并将其注入代理:
const task = process.argv.slice(2).join(" ");
const openAiApiKey = process.env.OPENAI_API_KEY;
if (!openAiApiKey) {
throw new Error("OPENAI_API_KEY is not set");
}
runWikipediaAgent()
.then(() => {})
.catch((error) => {
console.error(error);
});
async function runWikipediaAgent() {
console.log(openAiApiKey);
console.log(task);
}
创建LLM模型
首先,导入JS代理:
import * as $ from "js-agent";
您可以在runWikipediaAgent
中创建聊天模型:
const chatGpt = $.provider.openai.chatModel({
apiKey: openAiApiKey,
model: "gpt-3.5-turbo",
});
用基本提示调用模型
拥有模型后,您可以直接使用基本提示:
const fullResponse = await chatGpt.generate([
{ role: "user" as const, content: task },
]);
并从其响应中提取主要输出:
const output = await chatGpt.extractOutput(fullResponse);
console.log(output);
将其放在一起,这是当前的代码:
import * as $ from "js-agent";
const task = process.argv.slice(2).join(" ");
const openAiApiKey = process.env.OPENAI_API_KEY;
if (!openAiApiKey) {
throw new Error("OPENAI_API_KEY is not set");
}
runWikipediaAgent()
.then(() => {})
.catch((error) => {
console.error(error);
});
async function runWikipediaAgent() {
const chatGpt = $.provider.openai.chatModel({
apiKey: openAiApiKey,
model: "gpt-3.5-turbo",
});
const fullResponse = await chatGpt.generate([
{ role: "user" as const, content: task },
]);
const output = await chatGpt.extractOutput(fullResponse);
console.log(task);
console.log(output);
}
运行它时,它将使用经过训练的LLM的知识来回答以下问题:
❯ npx ts-node src/agent.ts "how many people live in BC, Canada?"
how many people live in BC, Canada?
As an AI language model, I do not have access to real-time data. However, according to the latest census conducted in 2016, the population of British Columbia, Canada was approximately 4.6 million.
创建基本代理
现在我们准备创建一个基本代理。让我们使用以下代码更新runWikipediaAgent
函数:
const chatGpt = $.provider.openai.chatModel({
apiKey: openAiApiKey,
model: "gpt-3.5-turbo",
});
return $.runAgent<{ task: string }>({
properties: { task },
agent: $.step.generateNextStepLoop({
actions: [],
actionFormat: $.action.format.flexibleJson(),
prompt: async ({ runState: { task } }) => [
{ role: "user" as const, content: `${task}` },
],
model: chatGpt,
}),
controller: $.agent.controller.maxSteps(3),
observer: $.agent.observer.showRunInConsole({
name: "Wikipedia Agent",
}),
});
运行它时,它将输出基本的LLM回答控制台,直到达到最大步骤数为止:
❯ npx ts-node src/agent.ts "how many people live in BC, Canada?"
### Wikipedia Agent ###
{ task: 'how many people live in BC, Canada?' }
Thinking…
As an AI language model, I do not have access to real-time data. However, according to the latest census conducted in 2016, the population of British Columbia, Canada was approximately 4.6 million.
Thinking…
As an AI language model, I do not have access to real-time data. However, according to the latest census conducted in 2016, the population of British Columbia, Canada was approximately 4.6 million.
Thinking…
As an AI language model, I do not have access to real-time data. However, according to the latest census conducted in 2016, the population of British Columbia, Canada was approximately 4.6 million.
Cancelled: Maximum number of steps (3) exceeded.
让我们挖掘代码。
$.runAgent
运行一个代理。它输入到代理的属性,这也是其输入。我们以属性为task
:
return $.runAgent<{ task: string }>({
properties: { task },
// ...
});
agent
属性包含代理的根步骤。我们使用$.step.generateNextStepLoop
步骤,该步骤使用LLM生成步骤,直到代理完成为止:
return $.runAgent<...>({
// ...
agent: $.step.generateNextStepLoop({
actions: [],
actionFormat: $.action.format.flexibleJson(),
prompt: async ({ runState: { task } }) => [
{ role: "user" as const, content: `${task}` },
],
model: chatGpt,
}),
循环配置了我们的早期提示功能和chatGpt
模型。调用chatGpt
模型生成函数时使用此提示。我们将稍后进行配置并讨论操作。
由于代理人尚无动作,并且不知道何时停止,因此我们将最大步骤数限制为3:
return $.runAgent<...>({
// ...
controller: $.agent.controller.maxSteps(3),
最后,我们使用一个观察者,将代理运行到控制台的观察者:
return $.runAgent<...>({
// ...
observer: $.agent.observer.showRunInConsole({
name: "Wikipedia Agent",
}),
使用基本代理,让我们下一步添加一些工具。
创建Wikipedia搜索工具
创建可编程搜索引擎
首先,您需要为Wikipedia创建一个programmable search engine。
设置搜索引擎时,将站点配置为en.wikipedia.org/*
。搜索引擎ID(cx
参数)在概述页面上。您可以获取search engine key in the documentation(“获取键”;需要一个Google项目)。
创建搜索动作
JS代理具有用于使用可编程搜索引擎的内置工具。您可以使用它来创建搜索操作。
工具是以某种方式运行(可能外部)代码的操作。它们不会直接影响控制流。还有其他类型的动作,例如,代理可以选择的“完成”动作。
const searchWikipediaAction = $.tool.programmableGoogleSearchEngineAction({
id: "search-wikipedia",
description: "Search wikipedia using a search term. Returns a list of pages.",
execute: $.tool.executeProgrammableGoogleSearchEngineAction({
key: "your search engine key",
cx: "your search engine id",
}),
});
id
和description
参数包含在LLM提示中。重要的是选择易于理解LLM的名称和描述,因为它们将确定代理是否以及何时决定使用此操作。
execution
参数包含正在运行工具代码的功能。它提供了额外的灵活性,例如,使用在Docker容器中运行的执行者。
创建文章阅读器
使用JS Agent extractInformationFromWebpage
工具实施了读取文章操作:
const readWikipediaArticleAction = $.tool.extractInformationFromWebpage({
id: "read-wikipedia-article",
description:
"Read a wikipedia article and summarize it considering the query.",
inputExample: {
url: "https://en.wikipedia.org/wiki/Artificial_intelligence",
topic: "{query that you are answering}",
},
execute: $.tool.executeExtractInformationFromWebpage({
extract: $.text.extractRecursively({
split: $.text.splitRecursivelyAtCharacter({
maxCharactersPerChunk: 2048 * 4,
}),
extract: $.text.generateText({
id: "summarize-wikipedia-article-chunk",
prompt: $.prompt.extractChatPrompt(),
model: chatGpt,
}),
}),
}),
});
除了id
和description
外,该动作还具有inputExample
,该inputExample
将显示给LLM。输入示例有助于指导LLM采取正确的措施。每个工具都有一个默认输入示例,可以被覆盖。
然后使用文本提取总结页面。它是递归分开的,直到块足够小,以使gpt-3.5-turbo
可以处理。 gpt-3.5-turbo
用于为每个块和串联摘要生成一个摘要。
$.prompt.extractChatPrompt()
是JS代理的一部分,包含以下提示:
async ({ text, topic }: { text: string; topic: string }) => [
{
role: "user" as const,
content: `## TOPIC\n${topic}`,
},
{
role: "system" as const,
content: `## ROLE
You are an expert at extracting information.
You need to extract and keep all the information on the topic above topic from the text below.
Only include information that is directly relevant for the topic.`,
},
{
role: "user" as const,
content: `## TEXT\n${text}`,
},
];
现在我们已经创建了一个摘要工具,我们可以将所有内容放在一起并制作一个更好的代理提示。
将动作添加到代理商
现在我们有了搜索Wikipedia和读取文章动作,我们可以在Wikipedia代理中设置动作。让我们将它们添加到$.step.generateNextStepLoop
的动作部分:
return $.runAgent<...>({
// ...
agent: $.step.generateNextStepLoop({
actions: [searchWikipediaAction, readWikipediaArticleAction],
actionFormat: $.action.format.flexibleJson(),
actionFormat
解析了LLM输出中的第一个平面JSON对象。它是专门为chatgpt设计的,它倾向于在响应中的各个地方输出JSON对象。
创建更好的提示
代理商尚未意识到这些行动,它不知道它应该阅读Wikipedia文章。让我们改善代理提示。
return $.runAgent<...>({
// ...
prompt: $.prompt.concatChatPrompts(
async ({ runState: { task } }) => [
{
role: "system",
content: `## ROLE
You are an knowledge worker that answers questions using Wikipedia content.
## CONSTRAINTS
All facts for your answer must be from Wikipedia articles that you have read.
## TASK
${task}`,
},
],
$.prompt.availableActionsChatPrompt(),
$.prompt.recentStepsChatPrompt({ maxSteps: 6 })
),
让我们剖析提示。我们首先将模型讲述其一般角色,然后我们始终指示阅读Wikipedia文章以找到答案并给予任务。
## ROLE
You are an knowledge worker that answers questions using Wikipedia content.
## CONSTRAINTS
All facts for your answer must be from Wikipedia articles that you have read.
## TASK
${task}
下一部分将可用操作的模型告知模型。之后,我们确保将模型采取的最后一步包括在下一次迭代的提示中。这提供了将代理在其任务中向前推进所需的基本内存。
return $.runAgent<...>({
// ...
prompt: $.prompt.concatChatPrompts(
// ...
$.prompt.availableActionsChatPrompt(),
$.prompt.recentStepsChatPrompt({ maxSteps: 6 })
),
使用$.prompt.concatChatPrompts
加入了不同的提示。
更新最大步骤
代理现在准备运行。
我们将最大步骤数增加到10,以为代理提供更多时间以找到答案。
return $.runAgent<...>({
// ...
controller: $.agent.controller.maxSteps(10),
完整的维基百科代理商
代理现在看起来像这样:
import * as $ from "js-agent";
const task = process.argv.slice(2).join(" ");
const openAiApiKey = process.env.OPENAI_API_KEY;
if (!openAiApiKey) {
throw new Error("OPENAI_API_KEY is not set");
}
runWikipediaAgent({
task,
openAiApiKey,
})
.then(() => {})
.catch((error) => {
console.error(error);
});
async function runWikipediaAgent({
task,
openAiApiKey,
}: {
task: string;
openAiApiKey: string;
}) {
const chatGpt = $.provider.openai.chatModel({
apiKey: openAiApiKey,
model: "gpt-3.5-turbo",
});
const searchWikipediaAction = $.tool.programmableGoogleSearchEngineAction({
id: "search-wikipedia",
description:
"Search wikipedia using a search term. Returns a list of pages.",
execute: $.tool.executeProgrammableGoogleSearchEngineAction({
key: "your search engine key",
cx: "your search engine id",
}),
});
const readWikipediaArticleAction = $.tool.extractInformationFromWebpage({
id: "read-wikipedia-article",
description:
"Read a wikipedia article and summarize it considering the query.",
inputExample: {
url: "https://en.wikipedia.org/wiki/Artificial_intelligence",
topic: "{query that you are answering}",
},
execute: $.tool.executeExtractInformationFromWebpage({
extract: $.text.extractRecursively({
split: $.text.splitRecursivelyAtCharacter({
maxCharactersPerChunk: 2048 * 4,
}),
extract: $.text.generateText({
id: "summarize-wikipedia-article-chunk",
prompt: $.prompt.extractChatPrompt(),
model: chatGpt,
}),
}),
}),
});
return $.runAgent<{ task: string }>({
properties: { task },
agent: $.step.generateNextStepLoop({
actions: [searchWikipediaAction, readWikipediaArticleAction],
actionFormat: $.action.format.flexibleJson(),
prompt: $.prompt.concatChatPrompts(
async ({ runState: { task } }) => [
{
role: "system",
content: `## ROLE
You are an knowledge worker that answers questions using Wikipedia content.
## CONSTRAINTS
All facts for your answer must be from Wikipedia articles that you have read.
## TASK
${task}`,
},
],
$.prompt.availableActionsChatPrompt(),
$.prompt.recentStepsChatPrompt({ maxSteps: 6 })
),
model: chatGpt,
}),
controller: $.agent.controller.maxSteps(10),
observer: $.agent.observer.showRunInConsole({ name: "Wikipedia Agent" }),
});
}
示例运行
这是测试运行的结果:
❯ npx ts-node src/agent.ts "how many people live in BC, Canada?"
### Wikipedia Agent ###
{ task: 'how many people live in BC, Canada?' }
Thinking…
I will start by searching for the population of British Columbia, Canada on Wikipedia.
{
"action": "search-wikipedia",
"query": "population of british columbia canada"
}
Executing search-wikipedia…
## Found 5 search results.
### British Columbia - Wikipedia
https://en.wikipedia.org/wiki/British_Columbia
With an estimated population of 5.3 million as of 2022, it is Canada's third-most populous province. The capital of British Columbia is Victoria and its ...
### Vancouver - Wikipedia
https://en.wikipedia.org/wiki/Vancouver
Vancouver is a major city in western Canada, located in the Lower Mainland region of British Columbia. ... Vancouver has the highest population density in Canada, with over 5,700 ...
### Demographics of British Columbia - Wikipedia
https://en.wikipedia.org/wiki/Demographics_of_British_Columbia
Population of British Columbia 5.399 million (2023) ; Percentage of National Population: 13.2% (unchanged) ; Population Growth Rate: 5.6% ...
### Victoria, British Columbia - Wikipedia
https://en.wikipedia.org/wiki/Victoria,_British_Columbia
Victoria is the capital city of the Canadian province of British Columbia, on the southern ... In the 2021 Census of Population conducted by Statistics Canada, ...
### Surrey, British Columbia - Wikipedia
https://en.wikipedia.org/wiki/Surrey,_British_Columbia
In the 2021 Canadian census conducted by Statistics Canada, Surrey had a population of 568,322 living in 185,671 of its 195,098 total private dwellings, a ...
Thinking…
The third search result, "Demographics of British Columbia - Wikipedia", seems to be the most relevant. I will read the article and summarize it to answer the question.
{
"action": "read-wikipedia-article",
"url": "https://en.wikipedia.org/wiki/Demographics_of_British_Columbia",
"topic": "population of British Columbia, Canada"
}
Executing read-wikipedia-article…
## Extracted information on topic 'population of British Columbia, Canada' from https://en.wikipedia.org/wiki/Demographics_of_British_Columbia
The population of British Columbia, Canada is 5.399 million as of 2023, which represents 13.2% of the national population. The population growth rate is 5.6%. In terms of visible minorities and indigenous peoples, 30.3% of the population in 2016 were visible minorities, and 5.9% were indigenous. The largest visible minority groups were South Asian, Chinese, and Black. In terms of immigration, in 2021, immigrants comprised 29.0% of the total population of British Columbia, with the largest immigrant groups being from China, India, and the Philippines. Finally, the 2021 Canadian census counted a total of 197,420 people who immigrated to British Columbia between 2016 and 2021.
Thinking…
According to the information I found on Wikipedia, the population of British Columbia, Canada is 5.399 million as of 2023.
{
"action": "done"
}
Done