【实战教程】基于 React Flow 搭建智能体组件:从环境配置到核心节点开发指南

发布于:2025-05-26 ⋅ 阅读:(51) ⋅ 点赞:(0)

本文为《React Agent:从零开始构建 AI 智能体》专栏系列文章。 专栏地址:https://blog.csdn.net/suiyingy/category_12933485.html。项目地址:https://gitee.com/fgai/react-agent(含完整代码示​例与实战源)。完整介绍:数据分析智能体构建实战:LLM 工具调用 + 记忆管理模块代码实现全解析(附 Qwen-Turbo 代码实现)-CSDN博客

        在大模型浪潮奔涌向前的当下,智能体技术的应用愈发广泛且深入,而高效搭建智能体组件成为开发者亟待解决的关键问题。React Flow 作为一款强大的可视化流程编辑库,凭借其灵活的布局与交互能力,为智能体组件的构建提供了新的思路与方法。本章将围绕基于 React Flow 搭建的智能体基本组件示例展开,从输入节点、输出节点等多个核心节点切入,逐步探索智能体组件搭建的奥秘。

        本节主要介绍环境搭建,从下一节开始逐一介绍节点组件创建:输入节点、输出节点、网络节点、代码节点、工具节点以及大模型智能对话节点等。

1 创建 React Flow 项目

        我们首先按照下面步骤创建一个 agent-nodes 项目:

# 创建项目
npx create-react-app agent-nodes
cd agent-nodes
# 考虑兼容性,安装18版本
npm install react@18 react-dom@18
npm install reactflow react-flow-renderer
# 安装 tailwindcss
npm install -D tailwindcss@3.4.17
npx tailwindcss init
# 安装 Font Awesome 图标库
npm install @fortawesome/react-fontawesome @fortawesome/free-solid-svg-icons

        修改 agent-nodes/tailwind.config.js文件,添加 tailwindcss 样式。

module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
    // 包含所有组件文件路径
  ],
  theme: { extend: {} },
  plugins: [
    // require('@tailwindcss/forms'), // 如果使用表单插件
  ],
}

        进一步在agent-nodes/src/index.css文件中引入样式。

@tailwind base;
@tailwind components;
@tailwind utilities;

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

        创建成功后 agent-nodes/packge.json 中内容如下:

{
  "name": "agent-nodes",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@fortawesome/free-solid-svg-icons": "^6.7.2",
    "@fortawesome/react-fontawesome": "^0.2.2",
    "@testing-library/dom": "^10.4.0",
    "@testing-library/jest-dom": "^6.6.3",
    "@testing-library/react": "^16.3.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-flow-renderer": "^10.3.17",
    "react-scripts": "5.0.1",
    "reactflow": "^11.11.4",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "tailwindcss": "^3.4.17"
  }
}

        此时,我们可通过 npm start 启动项目,并且在浏览器看到 React 默认页面。

2 主页搭建

        我们设计在 App.js 主页面用于展示后续不同类型的节点,程序如下所示。

// src/App.js
import React, { useState, useCallback, useEffect } from 'react';
import ReactFlow, {
  applyNodeChanges,
  applyEdgeChanges,
  addEdge,
  Background,
  useReactFlow,
  ReactFlowProvider
} from 'reactflow';
import 'reactflow/dist/style.css';

const nodeTypes = {
};


function App() {
  const { screenToFlowPosition } = useReactFlow();
  const [nodes, setNodes] = useState([]);
  const [edges, setEdges] = useState([]);
  const [contextMenu, setContextMenu] = useState(null);

  // 双击节点处理
  const onNodeDoubleClick = useCallback((_, node) => {
   
  }, []);

  // 右键菜单
  const handlePaneContextMenu = (event) => {
    event.preventDefault();
    const position = screenToFlowPosition({
      x: event.clientX,
      y: event.clientY,
    });
    setContextMenu({
      flowPosition: position,
      screenPosition: { x: event.clientX, y: event.clientY }
    });
  };
  // 关闭菜单
  const closeContextMenu = useCallback(() => {
    setContextMenu(null);
  }, []);
  useEffect(() => {
    if (contextMenu) {
      document.addEventListener('click', closeContextMenu);
      return () => document.removeEventListener('click', closeContextMenu);
    }
  }, [contextMenu, closeContextMenu]);

  // 运行按钮
  const handleRun = async () => {
    
  };

  const onNodesChange = useCallback(
    (changes) => setNodes((nds) => applyNodeChanges(changes, nds)),
    []
  );

  const onEdgesChange = useCallback(
    (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)),
    []
  );

  const onConnect = useCallback(
    (params) => setEdges((eds) => addEdge(
      { 
        ...params, 
        animated: true,
        style: { stroke: '#666' },
      }, 
      eds
    )),
    []
  );

  return (
    <div style={{ height: '100vh', position: 'relative' }}>
      <button
        onClick={handleRun}
        style={{
          position: 'absolute',
          top: 20,
          left: '50%',
          transform: 'translateX(-50%)',
          zIndex: 10,
          padding: '8px 20px',
          background: '#4CAF50',
          color: 'white',
          border: 'none',
          borderRadius: 20,
          cursor: 'pointer',
          boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
          fontSize: 14,
          fontWeight: 'bold',
        }}
      >
        ▶ 运行处理
      </button>

      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onConnect={onConnect}
        onPaneContextMenu={handlePaneContextMenu}
        onNodeDoubleClick={onNodeDoubleClick}
        nodeTypes={nodeTypes}
        fitView
        connectionRadius={20}
        snapToGrid={true}
        snapGrid={[15, 15]}
        defaultEdgeOptions={{
          type: 'smoothstep',
          style: {
            strokeWidth: 2,
          },
        }}
      >
        <Background 
          color="#ddd"
          gap={25}
          style={{ backgroundColor: '#f8f9fa' }}
        />
      </ReactFlow>

      {contextMenu && (
        <div
          style={{
            position: 'fixed',
            top: contextMenu.screenPosition.y,
            left: contextMenu.screenPosition.x,
            background: 'white',
            boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
            borderRadius: 4,
            zIndex: 10,
          }}
          onClick={(e) => e.stopPropagation()}
        >
          <div
            style={{
              padding: '8px 16px',
              cursor: 'pointer',
              transition: 'background 0.2s',
              ':hover': {
                background: '#f5f5f5',
              },
            }}
            // onClick={createInputNode}
          >
            添加节点
          </div>
        </div>
      )}

    </div>
  );
}

export default function FlowWrapper() {
  return (
    <ReactFlowProvider>
      <App />
    </ReactFlowProvider>
  );
}

        将以上程序复制到 src/app.js 文件,npm start 运行程序后页面如下图所示。页面上方居中位置有一个“运行处理”按钮。此按钮样式为绿色背景、白色文字,有圆角和阴影效果,视觉上比较突出。

图1 主页基本页面

        在初始化时,节点和边的数据为空,后续可以通过交互进行添加和修改。流程图具有一些实用的配置,如支持网格吸附,这使得节点移动时会自动对齐到网格,方便布局;边默认采用平滑曲线样式,线条宽度为 2px,并且连接时会有动画效果。此外,还添加了带有网格的背景,增强了视觉辨识度。

        当在流程图空白处点击右键时,会弹出一个右键菜单,菜单中有“添加节点”的选项,可用于后续添加节点。如果在菜单以外的区域点击,菜单会自动关闭。同时,程序预留了节点双击处理和运行按钮点击处理的逻辑,可根据实际需求进一步完善。

      立即关注获取最新动态

点击订阅《React Agent 开发专栏》,每周获取智能体开发深度教程。项目代码持续更新至React Agent 开源仓库,欢迎 Star 获取实时更新通知!FGAI 人工智能平台FGAI 人工智能平台 https://www.botaigc.cn/


网站公告

今日签到

点亮在社区的每一天
去签到