前端80行代码手搓一个langchain, 直观理解reAct实现

35 阅读1分钟

我们常常被各种酷炫的名词所困扰,reAct,Agent,RAG ,langChain, langGraph, langSmith。仿佛昨天AI调用只是返回一个API结果,今天就各种酷炫屌炸天的Agent。 这中间到底发生了什么,当你有空了解以上所有概念并使用他们编写你自己的智能体应用时,黄花菜都凉了。

看懂这80代码,让你幡然醒悟 原来普通的大语言模型API调用是这么变智能的。

感兴趣可以克隆我的项目深入学习1天 等于你苦学python1个月 github.com/yolaucn/min…

import { readFileSync } from "fs";

// 手动加载 .env 文件
const envContent = readFileSync(".env", "utf8");
const envLines = envContent.split("\n");
for (const line of envLines) {
  if (line.trim() && !line.startsWith("#")) {
    const [key, value] = line.split("=");
    if (key && value) {
      process.env[key.trim()] = value.trim();
    }
  }
}

const SYSTEM_PROMPT = `
You are a ReAct agent.

You must respond ONLY in this format:

Thought: <your resoning>
Action: <tool_name>("input")

OR, if finished:

Thought: <your reasoing>
Final: <final answer>

Available tools:
- search(query: string)
`;

const tools = {
  search: async (query) => {
    // mock : 可以换成真实api
    return `mock result for : ${query}`;
  },
};

function parseResponse(text) {
  const thoughtMatch = text.match(/Thought:\s*(.*)/);
  const actionMatch = text.match(/Action:\s*(\w+)\("(.*)"\)/);
  const finalMatch = text.match(/Final:\s*(.*)/);

  return {
    thought: thoughtMatch?.[1],
    action: actionMatch
      ? { tool: actionMatch[1], input: actionMatch[2] }
      : null,
    final: finalMatch?.[1],
  };
}

async function runAgent(question, maxSteps = 5) {
  let history = `Question: ${question}\n`;

  for (let step = 0; step < maxSteps; step++) {
    console.log(`\n============= STEP ${step} ====================`);
    console.log("\n[HISTORY SENT TO LLM]\n" + history);

    const llmText = await callLLM(history);
    console.log("\nLLM OUTPUT:\n", llmText);

    const { thought, action, final } = parseResponse(llmText);

    // 把 thought 记录进 history (可选:生产环境通常不记录 thought)
    if (thought) history += `Thought: ${thought}\n`;

    // 如果 LLM 给 Final,结束
    if (final) {
      history += `Final: ${final}\n`;
      console.log("\n[FINAL]\n", final);
      return { final, history };
    }

    // 否则必须有action
    if (!action) throw new Error("LLM did not return Action or Final.");

    history += `Action: ${action.tool}("${action.input}")\n`;

    const toolFn = tools[action.tool];
    if (!toolFn) throw new Error(`Unknown tool:" ${action.tool}`);

    // 工具运行在你的服务器/本机 Node 运行时
    const observation = await toolFn(action.input);

    // 把 observation 追加进 history
    history += `Observation: ${observation}\n`;
  }

  throw new Error("Max steps reached");
}

async function callLLM(prompt) {
  const res = await fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "gpt-4o-mini",
      messages: [
        { role: "system", content: SYSTEM_PROMPT },
        { role: "user", content: prompt },
      ],
    }),
  });
  const data = await res.json();

  return data.choices[0].message.content;
}

runAgent("你的钱藏在哪里");