首页  >  文章  >  web前端  >  使用 Node.js 创建 ReAct AI 代理(维基百科搜索)en

使用 Node.js 创建 ReAct AI 代理(维基百科搜索)en

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-09-25 06:22:32673浏览

Criando um Agente de IA ReAct com Node.js (pesquisa na Wikipedia ) pt-br

介绍

我们将创建一个能够搜索维基百科并根据收集到的信息回答问题的人工智能代理。
该 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. 回答(回复)

3.3 思想状态

思考状态是ReactAgent对收集到的信息进行反思并决定下一步应该做什么的时刻。

async thought() {
    // ...
}

3.4 动作状态(ACTION)

在动作状态下,代理根据先前的想法执行可用功能之一。
请注意,有行动(执行)和决定(哪个行动)。

async action() {
    // chama a decisão
    // executa a ação e retorna um ActionResult
}

async decideAction() {
    // Chama o LLM com base no Pensamento (reflexão) para formatar e adequar a chamada de função.
    // Procure por um modo de função-ferramenta na [documentação da API do Google](https://ai.google.dev/gemini-api/docs/function-calling)
}

[4] 实现代理

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

4.1 初始配置

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

mkdir projeto-agente-react
cd projeto-agente-react
npm init -y
npm install axios dotenv @google/generative-ai

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

GOOGLE_AI_API_KEY=sua_chave_api_aqui

这里有免费的 API 密钥

4.2 角色声明

此文件是 Node.js 将用来执行对维基百科的 API 调用的 JavaScript 文件。
我们在 FunctionDescription 中描述了该文件的内容。

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

const axios = require("axios");

class Tools {
  static async wikipedia(q) {
    try {
      const response = await axios.get("https://pt.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://pt.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://pt.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://pt.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: 1.8,
    });
  }

  async run() {
    this.pushHistory(`**Tarefa: ${this.query} **`);
    try {
      return await this.step();
    } catch (e) {
      console.error("Erro durante a execução:", e);
      return "Desculpe, não consegui processar sua solicitação.";
    }
  }

  async step() {
    const colors = {
      reset: "\x1b[0m",
      yellow: "\x1b[33m",
      red: "\x1b[31m",
      cyan: "\x1b[36m",
    };
    console.log("====================================");
    console.log(
      `Next Movement: ${
        this.state === "THOUGHT"
          ? colors.yellow
          : this.state === "ACTION"
            ? colors.red
            : this.state === "ANSWER"
              ? colors.cyan
              : colors.reset
      }${this.state}${colors.reset}`,
    );
    console.log(`Last Movement: ${this.history[this.history.length - 1]}`);
    console.log("====================================");
    switch (this.state) {
      case "THOUGHT":
        return await this.thought();
        break;
      case "ACTION":
        return await this.action();
        break;
      case "ANSWER":
        return await this.answer();
    }
  }

  async thought() {
    const funcoesDisponiveis = JSON.stringify(Array.from(this.functions));
    const contextoHistorico = this.history.join("\n");
    const prompt = `Sua Tarefa é ${this.consulta}
O Contexto posui todas as reflexões que você fez até agora e os ResultadoAção que coletou.
AçõesDisponíveis são funções que você pode chamar sempre que precisar de mais dados.

Contexto: "${contextoHistorico}" <<

AçõesDisponíveis: "${funcoesDisponiveis}" <<

Tarefa: "${this.consulta}" <<

Reflita sobre Sua Tarefa usando o Contexto, ResultadoAção e AçõesDisponíveis para encontrar seu próximo_passo.
Imprima seu próximo_passo com um Pensamento ou Finalize Cumprindo Sua Tarefa caso tenha as informações disponíveis`;

    const thought = await this.promptModel(prompt);
    this.pushHistory(`\n **${thought.trim()}**`);

    if (
      thought.toLowerCase().includes("cumprida") ||
      thought.toLowerCase().includes("cumpra") ||
      thought.toLowerCase().includes("cumprindo") ||
      thought.toLowerCase().includes("finalizar") ||
      thought.toLowerCase().includes("finalizando") ||
      thought.toLowerCase().includes("finalize") ||
      thought.toLowerCase().includes("concluída")
    ) {
      this.state = "ANSWER";
    } else {
      this.state = "ACTION";
    }
    return this.step();
  }

  async action() {
    const action = await this.decideAction();
    this.pushHistory(`** Ação: ${action} **`);
    const result = await this.executeFunctionCall(action);
    this.pushHistory(`** ResultadoAção: ${result} **`);
    this.state = "THOUGHT";
    return this.step();
  }

  async decideAction() {
    const availableFunctions = JSON.stringify(Array.from(this.functions));
    const historyContext = this.history;
    const prompt = `Reflita sobre o Pensamento, Consulta e Ações Disponíveis

    ${historyContext[historyContext.length - 2]}

    Pensamento <<< ${historyContext[historyContext.length - 1]}

    Consulta: "${this.query}"

    Ações Disponíveis: ${availableFunctions}

    Retorne apenas a função,parâmetros separados por vírgula. Exemplo: "wikipedia,ronaldinho gaucho,1450"`;

    const decision = await this.promptModel(prompt);
    return decision.replace(/`/g, "").trim();
  }

  async answer() {
    const historyContext = this.history.join("\n");
    const prompt = `Com base no seguinte contexto, forneça uma resposta completa e detalhada para a tarefa: ${this.query}.

    Contexto:
    ${historyContext}

    Tarefa: "${this.query}"`;

    const finalAnswer = await this.promptModel(prompt);
    return finalAnswer;
  }

  async promptModel(prompt) {
    const result = await this.model.generateContent(prompt);
    const response = await result.response;
    return response.text();
  }

  async executeFunctionCall(functionCall) {
    const [functionName, ...args] = functionCall.split(",");
    const func = Tools[functionName.trim()];
    if (func) {
      return await func.call(null, ...args);
    }
    throw new Error(`Função ${functionName} não encontrada`);
  }

  pushHistory(value) {
    this._history.push(value);
  }

  get history() {
    return this._history;
  }
}

module.exports = ReactAgent;

4.4 运行代理并解释可用工具 (index.js)

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

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

async function main() {
  const query = "Que clubes ronaldinho gaúcho jogou para?";
  // const query = "Quais os bairros de Joinville?";
  // const query = "Qual a capital da frança?";

  const functions = [
    [
      "wikipedia",
      "params: query",
      "Busca semântica na Wikipedia API por pageId e sectionIds >> \n ex: Pontos turísticos de são paulo \n São Paulo é uma cidade com muitos pontos turísticos, pageId, sections : []",
    ],
    [
      "wikipedia_with_pageId",
      "params: pageId, sectionId",
      "Busca na Wikipedia API usando pageId e sectionIndex como parametros. \n ex: 1500,1234 \n Informações sobre a seção blablalbal",
    ],
  ];

  const agent = new ReactAgent(query, functions);
  const result = await agent.run();
  console.log("Resultado do Agente:", result);
}

main().catch(console.error);

角色描述

尝试添加新工具或功能时,请务必对其进行良好描述。
在我们的示例中,这已经完成并在调用新实例时添加到我们的 ReActAgent 类中。

const functions = [
    [
        "google", // nomeDaFuncao
        "params: query", // NomeDoParâmetroLocal
        "Pesquisa semântica na API da Wikipedia por snippets, pageIds e sectionIds >> \n ex: Quando o Brasil foi colonizado? \n O Brasil foi colonizado em 1500, pageId, sections : []", // breve explicação e exemplo (isso será encaminhado para o LLM)
    ]
];

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

与维基百科的互动分两个主要步骤完成:

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

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

    • 使用页面 ID 和分区 ID 搜索特定内容。
    • 返回请求部分的文本。

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

[6] 执行流程示例

  1. 用户提问。
  2. 智能体进入思考状态并反思问题。
  3. 他决定搜索维基百科并进入 ACTION 状态。
  4. 运行维基百科函数并获取结果。
  5. 返回THOUGHT状态反思结果。
  6. 您可以决定寻找更多细节或不同的方法。
  7. 根据需要重复思想和行动循环。
  8. 当它有足够的信息时,它进入ANSWER状态。
  9. 根据收集到的所有信息生成最终响应。
  10. 只要维基百科没有可收集的数据,就进入无限循环。用计时器解决这个问题=P

[7] 最后的考虑

  • 模块化结构可以轻松添加新工具或 API。
  • 实施错误处理和时间/迭代限制非常重要,以避免无限循环或过度的资源使用。
  • 此示例使用温度 2。温度越低,代理在迭代过程中的创造力就越低。通过实验了解温度对 LLM 的影响。

以上是使用 Node.js 创建 ReAct AI 代理(维基百科搜索)en的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn