插件窝 干货文章 使用 nodeJS 从头开始​​创建 ReAct Agent(维基百科搜索)

使用 nodeJS 从头开始​​创建 ReAct Agent(维基百科搜索)

维基 li wikipedia pageid 384    来源:    2024-10-20

介绍

我们将创建一个能够搜索维基百科并根据找到的信息回答问题的人工智能代理。该 react(理性与行动)代理使用 google generative ai api 来处理查询并生成响应。我们的代理将能够:

  1. 搜索维基百科获取相关信息。
  2. 从维基百科页面中提取特定部分。
  3. 对收集到的信息进行推理并制定答案。

[2] 什么是react代理?

react agent 是一种遵循反射-操作循环的特定类型的代理。它根据可用信息和它可以执行的操作反映当前任务,然后决定采取哪个操作或是否结束任务。

[3] 规划代理

3.1 所需工具

  • node.js
  • 用于 http 请求的 axios 库
  • google 生成式 ai api (gemini-1.5-flash)
  • 维基百科 api

3.2 代理结构

我们的 react agent 将具有三个主要状态:

  1. 思想(反思)
  2. 行动(执行)
  3. 答案(回复)

[4] 实现代理

让我们逐步构建 react agent,突出显示每个状态。

4.1 初始设置

首先,设置项目并安装依赖项:

mkdir react-agent-project
cd react-agent-project
npm init -y
npm install axios dotenv @google/generative-ai

在项目根目录创建一个 .env 文件:

google_ai_api_key=your_api_key_here

4.2 创建tools.js文件

使用以下内容创建 tools.js:

const axios = require("axios");

class tools {
  static async wikipedia(q) {
    try {
      const response = await axios.get("https://en.wikipedia.org/w/api.php", {
        params: {
          action: "query",
          list: "search",
          srsearch: q,
          srwhat: "text",
          format: "json",
          srlimit: 4,
        },
      });

      const results = await promise.all(
        response.data.query.search.map(async (searchresult) => {
          const sectionresponse = await axios.get(
            "https://en.wikipedia.org/w/api.php",
            {
              params: {
                action: "parse",
                pageid: searchresult.pageid,
                prop: "sections",
                format: "json",
              },
            },
          );

          const sections = object.values(
            sectionresponse.data.parse.sections,
          ).map((section) => `${section.index}, ${section.line}`);

          return {
            pagetitle: searchresult.title,
            snippet: searchresult.snippet,
            pageid: searchresult.pageid,
            sections: sections,
          };
        }),
      );

      return results
        .map(
          (result) =>
            `snippet: ${result.snippet}\npageid: ${result.pageid}\nsections: ${json.stringify(result.sections)}`,
        )
        .join("\n\n");
    } catch (error) {
      console.error("error fetching from wikipedia:", error);
      return "error fetching data from wikipedia";
    }
  }

  static async wikipedia_with_pageid(pageid, sectionid) {
    if (sectionid) {
      const response = await axios.get("https://en.wikipedia.org/w/api.php", {
        params: {
          action: "parse",
          format: "json",
          pageid: parseint(pageid),
          prop: "wikitext",
          section: parseint(sectionid),
          disabletoc: 1,
        },
      });
      return object.values(response.data.parse?.wikitext ?? {})[0]?.substring(
        0,
        25000,
      );
    } else {
      const response = await axios.get("https://en.wikipedia.org/w/api.php", {
        params: {
          action: "query",
          pageids: parseint(pageid),
          prop: "extracts",
          exintro: true,
          explaintext: true,
          format: "json",
        },
      });
      return object.values(response.data?.query.pages)[0]?.extract;
    }
  }
}

module.exports = tools;

4.3 创建reactagent.js文件

使用以下内容创建 reactagent.js:

require("dotenv").config();
const { googlegenerativeai } = require("@google/generative-ai");
const tools = require("./tools");

const genai = new googlegenerativeai(process.env.google_ai_api_key);

class reactagent {
  constructor(query, functions) {
    this.query = query;
    this.functions = new set(functions);
    this.state = "thought";
    this._history = [];
    this.model = genai.getgenerativemodel({
      model: "gemini-1.5-flash",
      temperature: 2,
    });
  }

  get history() {
    return this._history;
  }

  pushhistory(value) {
    this._history.push(`\n ${value}`);
  }

  async run() {
    this.pushhistory(`**task: ${this.query} **`);
    try {
      return await this.step();
    } catch (e) {
      if (e.message.includes("exhausted")) {
        return "sorry, i'm exhausted, i can't process your request anymore. >>>>>>>", finalanswer);
    return finalanswer;
  }
}

module.exports = reactagent;

4.4 运行代理(index.js)

使用以下内容创建index.js:

const ReActAgent = require("./ReactAgent.js");

async function main() {
  const query = "What does England border with?";
  const functions = [
    [
      "wikipedia",
      "params: query",
      "Semantic Search Wikipedia API for snippets, pageIds and sectionIds >> \n ex: Date brazil has been colonized? \n Brazil was colonized at 1500, pageId, sections : []",
    ],
    [
      "wikipedia_with_pageId",
      "params : pageId, sectionId",
      "Search Wikipedia API for data using a pageId and a sectionIndex as params.  \n ex: 1500, 1234 \n Section information about blablalbal",
    ],
  ];

  const agent = new ReActAgent(query, functions);
  try {
    const result = await agent.run();
    console.log("THE AGENT RETURN THE FOLLOWING >>>", result);
  } catch (e) {
    console.log("FAILED TO RUN T.T", e);
  }
}

main().catch(console.error);

[5] 维基百科部分如何运作

与维基百科的交互主要分为两个步骤:

  1. 初始搜索(维基百科功能):

    • 向维基百科搜索 api 发出请求。
    • 最多返回 4 个相关的查询结果。
    • 对于每个结果,它都会获取页面的各个部分。
  2. 详细搜索(wikipedia_with_pageid函数):

    • 使用页面 id 和部分 id 来获取特定内容。
    • 返回请求部分的文本。

此过程允许代理首先获得与查询相关的主题的概述,然后根据需要深入研究特定部分。

[6] 执行流程示例

  1. 用户提出问题。
  2. 智能体进入思考状态并反思问题。
  3. 它决定搜索维基百科并进入 action 状态。
  4. 执行wikipedia函数并获取结果。
  5. 返回thought状态反思结果。
  6. 可能决定搜索更多详细信息或不同的方法。
  7. 根据需要重复思想和行动循环。
  8. 当它有足够的信息时,它进入answer状态。
  9. 根据收集到的所有信息生成最终答案。
  10. 只要维基百科没有可收集的数据,就会进入无限循环。用计时器修复它=p

[7] 最后的考虑

  • 模块化结构可以轻松添加新工具或 api。
  • 实施错误处理和时间/迭代限制非常重要,以避免无限循环或过度资源使用。
  • 使用温度:99999 哈哈