>웹 프론트엔드 >JS 튜토리얼 >Node.js로 ReAct AI 에이전트 생성(Wikipedia 검색)

Node.js로 ReAct AI 에이전트 생성(Wikipedia 검색)

Mary-Kate Olsen
Mary-Kate Olsen원래의
2024-09-25 06:22:32711검색

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

소개

수집된 정보를 바탕으로 위키피디아를 검색하고 질문에 답할 수 있는 AI 에이전트를 만들어 보겠습니다.
이 ReAct(추론 및 행동) 에이전트는 Google Generative AI API를 사용하여 쿼리를 처리하고 응답을 생성합니다.

저희 에이전트는 다음을 수행할 수 있습니다.

  1. 위키피디아에서 관련 정보를 검색해 보세요.
  2. Wikipedia 페이지에서 특정 섹션을 추출합니다.
  3. 정보 수집 이유 및 답변 작성

[2] ReAct Agent란 무엇인가요?

ReAct Agent는 Reflection-Action 주기를 따르는 특정 유형의 에이전트입니다. 사용 가능한 정보와 수행할 수 있는 작업을 기반으로 현재 작업을 반영한 다음 수행할 작업이나 작업 완료 여부를 결정합니다.

[3] 에이전트 계획

3.1 필수 도구

  • Node.js
  • HTTP 요청용 Axios 라이브러리
  • Google Generative AI API(gemini-1.5-flash)
  • 위키피디아 API

3.2 에이전트 구조

ReAct 에이전트에는 세 가지 주요 상태가 있습니다.

  1. 생각(반성)
  2. ACTION(실행)
  3. ANSWER(답글)

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가 Wikipedia에 대한 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] Wikipedia 부분의 작동 방식

Wikipedia와의 상호작용은 두 가지 주요 단계로 이루어집니다.

  1. 초기 검색(위키피디아 기능):

    • Wikipedia 검색 API에 요청합니다.
    • 검색어와 관련된 최대 4개의 결과를 반환합니다.
    • 각 결과에 대해 페이지 섹션을 검색하세요.
  2. 상세 검색(wikipedia_with_pageId 기능):

    • 페이지 ID와 섹션 ID를 사용하여 특정 콘텐츠를 검색합니다.
    • 요청된 섹션의 텍스트를 반환합니다.

이 프로세스를 통해 상담원은 먼저 검색어와 관련된 주제의 개요를 확인한 다음 필요에 따라 특정 섹션으로 드릴다운할 수 있습니다.

[6] 실행 흐름 예시

  1. 사용자가 질문을 합니다.
  2. 에이전트가 THOUGHT 상태로 들어가 질문에 대해 반성합니다.
  3. 위키피디아를 검색하기로 하고 ACTION 상태로 들어갑니다.
  4. 위키피디아 기능을 실행하고 결과를 얻습니다.
  5. 결과를 반영하기 위해 THOUGHT 상태로 돌아갑니다.
  6. 더 자세한 내용을 찾아보거나 다른 접근 방식을 찾아볼 수도 있습니다.
  7. 필요에 따라 생각과 행동 주기를 반복하세요.
  8. 충분한 정보가 있으면 ANSWER 상태로 들어갑니다.
  9. 수집된 모든 정보를 바탕으로 최종 응답을 생성합니다.
  10. Wikipedia에 수집할 데이터가 없을 때마다 무한 루프에 들어갑니다. 타이머 =P로 이 문제를 해결하세요

[7] 최종 고려 사항

  • 모듈형 구조를 통해 새로운 도구나 API를 쉽게 추가할 수 있습니다.
  • 무한 루프나 과도한 리소스 사용을 방지하려면 오류 처리 및 시간/반복 제한을 구현하는 것이 중요합니다.
  • 이 예에서는 온도 2를 사용합니다. 온도가 낮을수록 반복 중에 에이전트의 창의성이 떨어집니다. 온도가 LLM에 미치는 영향을 이해하기 위한 실험입니다.

위 내용은 Node.js로 ReAct AI 에이전트 생성(Wikipedia 검색)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.