AutoGen Studio与Vue3前端框架集成方案

1. 引言

想象一下这样的场景:你的团队已经用AutoGen Studio构建了一套强大的多智能体工作流,能够自动处理客户咨询、生成营销内容、甚至协助产品设计。但是每次使用都需要打开终端,运行命令,然后在浏览器中访问本地端口——这样的体验对于非技术团队成员来说实在太不友好了。

这正是我们需要将AutoGen Studio与现代化前端框架集成的原因。通过Vue3,我们可以为这些强大的AI智能体打造一个直观、响应式的管理界面,让业务人员也能轻松地与AI协作。本文将带你一步步实现AutoGen Studio与Vue3的无缝集成,构建一个既美观又实用的智能体管理平台。

2. 理解AutoGen Studio的API架构

2.1 后端服务接口

AutoGen Studio基于FastAPI构建,提供了一套完整的RESTful API。在开始前端集成前,我们需要先了解它的核心接口:

# AutoGen Studio的主要API端点示例
BASE_URL = "http://localhost:8080/api"

# 工作流管理
/workflows          # 获取所有工作流
/workflows/{id}     # 获取特定工作流
/workflows/{id}/run # 运行工作流

# 智能体管理
/agents            # 获取所有智能体
/agents/{id}       # 管理特定智能体

# 会话管理
/sessions          # 获取会话列表
/sessions/{id}     # 管理特定会话

2.2 实时通信机制

除了传统的REST API,AutoGen Studio还支持WebSocket连接,用于实时接收智能体之间的消息流:

// WebSocket连接示例
const socket = new WebSocket('ws://localhost:8080/ws');

socket.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('收到实时消息:', data);
};

3. Vue3项目设置与基础配置

3.1 创建Vue3项目

首先,我们使用Vite创建一个新的Vue3项目:

npm create vite@latest autogen-vue-dashboard -- --template vue
cd autogen-vue-dashboard
npm install

3.2 安装必要的依赖

安装与AutoGen Studio API交互所需的库:

npm install axios vue-router pinia socket.io-client

3.3 配置环境变量

创建环境配置文件 .env.development

VITE_AUTOGEN_API_URL=http://localhost:8080/api
VITE_AUTOGEN_WS_URL=ws://localhost:8080/ws

4. 核心集成实现

4.1 API服务层封装

创建 src/services/autogenService.js

import axios from 'axios';

const API_BASE_URL = import.meta.env.VITE_AUTOGEN_API_URL;

const autogenApi = axios.create({
  baseURL: API_BASE_URL,
  timeout: 30000,
});

// 请求拦截器
autogenApi.interceptors.request.use(
  (config) => {
    // 可以在这里添加认证token等
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 响应拦截器
autogenApi.interceptors.response.use(
  (response) => response.data,
  (error) => {
    console.error('API请求错误:', error);
    return Promise.reject(error);
  }
);

export const workflowService = {
  // 获取所有工作流
  getAllWorkflows: () => autogenApi.get('/workflows'),
  
  // 获取特定工作流
  getWorkflow: (id) => autogenApi.get(`/workflows/${id}`),
  
  // 运行工作流
  runWorkflow: (id, input) => autogenApi.post(`/workflows/${id}/run`, input),
  
  // 创建工作流
  createWorkflow: (workflowData) => autogenApi.post('/workflows', workflowData),
};

export const agentService = {
  // 获取所有智能体
  getAllAgents: () => autogenApi.get('/agents'),
  
  // 更新智能体配置
  updateAgent: (id, agentData) => autogenApi.put(`/agents/${id}`, agentData),
};

export default autogenApi;

4.2 WebSocket服务封装

创建 src/services/websocketService.js

import { ref } from 'vue';

class WebSocketService {
  constructor() {
    this.socket = null;
    this.isConnected = ref(false);
    this.messageHandlers = new Set();
  }

  connect() {
    const wsUrl = import.meta.env.VITE_AUTOGEN_WS_URL;
    
    this.socket = new WebSocket(wsUrl);
    
    this.socket.onopen = () => {
      console.log('WebSocket连接已建立');
      this.isConnected.value = true;
    };
    
    this.socket.onmessage = (event) => {
      const data = JSON.parse(event.data);
      this.notifyHandlers(data);
    };
    
    this.socket.onclose = () => {
      console.log('WebSocket连接已关闭');
      this.isConnected.value = false;
    };
    
    this.socket.onerror = (error) => {
      console.error('WebSocket错误:', error);
    };
  }

  addMessageHandler(handler) {
    this.messageHandlers.add(handler);
  }

  removeMessageHandler(handler) {
    this.messageHandlers.delete(handler);
  }

  notifyHandlers(data) {
    this.messageHandlers.forEach(handler => {
      try {
        handler(data);
      } catch (error) {
        console.error('消息处理器错误:', error);
      }
    });
  }

  sendMessage(message) {
    if (this.socket && this.isConnected.value) {
      this.socket.send(JSON.stringify(message));
    }
  }

  disconnect() {
    if (this.socket) {
      this.socket.close();
      this.socket = null;
    }
  }
}

// 创建单例实例
export const websocketService = new WebSocketService();

4.3 状态管理配置

使用Pinia进行状态管理,创建 src/stores/autogenStore.js

import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import { workflowService, agentService } from '@/services/autogenService';
import { websocketService } from '@/services/websocketService';

export const useAutogenStore = defineStore('autogen', () => {
  // 状态
  const workflows = ref([]);
  const agents = ref([]);
  const activeSessions = ref([]);
  const isLoading = ref(false);
  const error = ref(null);

  // Getter
  const workflowCount = computed(() => workflows.value.length);
  const activeAgentCount = computed(() => 
    agents.value.filter(agent => agent.status === 'active').length
  );

  // Actions
  const fetchWorkflows = async () => {
    isLoading.value = true;
    try {
      const data = await workflowService.getAllWorkflows();
      workflows.value = data;
      error.value = null;
    } catch (err) {
      error.value = '获取工作流失败';
      console.error(err);
    } finally {
      isLoading.value = false;
    }
  };

  const fetchAgents = async () => {
    try {
      const data = await agentService.getAllAgents();
      agents.value = data;
    } catch (err) {
      console.error('获取智能体失败:', err);
    }
  };

  const runWorkflow = async (workflowId, input) => {
    try {
      const result = await workflowService.runWorkflow(workflowId, input);
      
      // 监听实时消息
      websocketService.addMessageHandler((message) => {
        if (message.session_id === result.session_id) {
          // 更新会话状态
          updateSessionStatus(result.session_id, message);
        }
      });
      
      return result;
    } catch (err) {
      console.error('运行工作流失败:', err);
      throw err;
    }
  };

  const updateSessionStatus = (sessionId, message) => {
    const sessionIndex = activeSessions.value.findIndex(s => s.id === sessionId);
    if (sessionIndex !== -1) {
      activeSessions.value[sessionIndex].messages.push(message);
    }
  };

  // 初始化WebSocket连接
  const initWebSocket = () => {
    websocketService.connect();
  };

  return {
    // 状态
    workflows,
    agents,
    activeSessions,
    isLoading,
    error,
    
    // Getter
    workflowCount,
    activeAgentCount,
    
    // Actions
    fetchWorkflows,
    fetchAgents,
    runWorkflow,
    initWebSocket,
  };
});

5. 响应式界面组件开发

5.1 工作流列表组件

创建 src/components/WorkflowList.vue

<template>
  <div class="workflow-list">
    <div class="header">
      <h2>工作流管理</h2>
      <button @click="refresh" :disabled="isLoading">
        {{ isLoading ? '加载中...' : '刷新' }}
      </button>
    </div>
    
    <div v-if="error" class="error-message">
      {{ error }}
    </div>
    
    <div v-else class="workflow-grid">
      <div 
        v-for="workflow in workflows" 
        :key="workflow.id" 
        class="workflow-card"
        @click="selectWorkflow(workflow)"
      >
        <h3>{{ workflow.name }}</h3>
        <p>{{ workflow.description }}</p>
        <div class="workflow-meta">
          <span>智能体: {{ workflow.agents.length }}</span>
          <span>状态: {{ workflow.status }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed } from 'vue';
import { useAutogenStore } from '@/stores/autogenStore';

const store = useAutogenStore();
const { fetchWorkflows } = store;

const workflows = computed(() => store.workflows);
const isLoading = computed(() => store.isLoading);
const error = computed(() => store.error);

const refresh = () => {
  fetchWorkflows();
};

const selectWorkflow = (workflow) => {
  // 处理工作流选择
  console.log('选择工作流:', workflow);
};

// 组件挂载时获取数据
fetchWorkflows();
</script>

<style scoped>
.workflow-list {
  padding: 20px;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.workflow-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 20px;
}

.workflow-card {
  border: 1px solid #e1e5e9;
  border-radius: 8px;
  padding: 16px;
  cursor: pointer;
  transition: all 0.2s ease;
}

.workflow-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.workflow-meta {
  display: flex;
  justify-content: space-between;
  margin-top: 12px;
  font-size: 0.9em;
  color: #666;
}

.error-message {
  color: #e74c3c;
  padding: 10px;
  background-color: #fdeded;
  border-radius: 4px;
}
</style>

5.2 实时会话监控组件

创建 src/components/SessionMonitor.vue

<template>
  <div class="session-monitor">
    <h3>实时会话监控</h3>
    
    <div v-for="session in activeSessions" :key="session.id" class="session-card">
      <div class="session-header">
        <h4>{{ session.workflow_name }}</h4>
        <span :class="['status', session.status]">{{ session.status }}</span>
      </div>
      
      <div class="messages-container">
        <div 
          v-for="(message, index) in session.messages" 
          :key="index"
          :class="['message', message.type]"
        >
          <div class="message-header">
            <strong>{{ message.agent_name }}</strong>
            <span class="timestamp">{{ formatTime(message.timestamp) }}</span>
          </div>
          <div class="message-content">{{ message.content }}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed, onMounted, onUnmounted } from 'vue';
import { useAutogenStore } from '@/stores/autogenStore';

const store = useAutogenStore();
const activeSessions = computed(() => store.activeSessions);

const formatTime = (timestamp) => {
  return new Date(timestamp).toLocaleTimeString();
};

// 处理WebSocket消息
const handleWebSocketMessage = (message) => {
  // 消息处理逻辑会在store中完成
};

onMounted(() => {
  store.initWebSocket();
});

onUnmounted(() => {
  // 清理WebSocket连接
});
</script>

<style scoped>
.session-monitor {
  padding: 20px;
  background-color: #f8f9fa;
  border-radius: 8px;
}

.session-card {
  background: white;
  border-radius: 8px;
  padding: 16px;
  margin-bottom: 16px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.session-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.status {
  padding: 4px 8px;
  border-radius: 12px;
  font-size: 0.8em;
}

.status.running {
  background-color: #e1f5fe;
  color: #0288d1;
}

.status.completed {
  background-color: #e8f5e8;
  color: #2e7d32;
}

.status.error {
  background-color: #ffebee;
  color: #c62828;
}

.messages-container {
  max-height: 300px;
  overflow-y: auto;
}

.message {
  margin-bottom: 12px;
  padding: 12px;
  border-radius: 6px;
  border-left: 4px solid #ddd;
}

.message.user {
  border-left-color: #2196f3;
  background-color: #e3f2fd;
}

.message.assistant {
  border-left-color: #4caf50;
  background-color: #e8f5e9;
}

.message.system {
  border-left-color: #ff9800;
  background-color: #fff3e0;
}

.message-header {
  display: flex;
  justify-content: space-between;
  margin-bottom: 8px;
  font-size: 0.9em;
}

.timestamp {
  color: #666;
}

.message-content {
  white-space: pre-wrap;
  line-height: 1.4;
}
</style>

6. 高级功能实现

6.1 工作流运行界面

创建 src/components/WorkflowRunner.vue

<template>
  <div class="workflow-runner">
    <div class="runner-header">
      <h2>运行工作流: {{ selectedWorkflow.name }}</h2>
      <div class="controls">
        <button @click="runWorkflow" :disabled="isRunning">
          {{ isRunning ? '运行中...' : '开始运行' }}
        </button>
        <button @click="stopWorkflow" v-if="isRunning">停止</button>
      </div>
    </div>

    <div class="input-section">
      <textarea 
        v-model="userInput" 
        placeholder="请输入任务描述..."
        :disabled="isRunning"
      ></textarea>
    </div>

    <SessionMonitor />
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';
import { useAutogenStore } from '@/stores/autogenStore';
import SessionMonitor from './SessionMonitor.vue';

const store = useAutogenStore();
const userInput = ref('');
const isRunning = ref(false);

const props = defineProps({
  selectedWorkflow: {
    type: Object,
    required: true
  }
});

const runWorkflow = async () => {
  if (!userInput.value.trim()) {
    alert('请输入任务描述');
    return;
  }

  isRunning.value = true;
  try {
    const result = await store.runWorkflow(
      props.selectedWorkflow.id, 
      { task: userInput.value }
    );
    console.log('工作流运行结果:', result);
  } catch (error) {
    console.error('运行工作流出错:', error);
    alert('运行工作流失败');
  } finally {
    isRunning.value = false;
  }
};

const stopWorkflow = () => {
  // 实现停止逻辑
  isRunning.value = false;
};
</script>

<style scoped>
.workflow-runner {
  padding: 20px;
}

.runner-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.controls button {
  margin-left: 10px;
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.controls button:first-child {
  background-color: #4caf50;
  color: white;
}

.controls button:disabled {
  background-color: #ccc;
  cursor: not-allowed;
}

.input-section textarea {
  width: 100%;
  height: 100px;
  padding: 12px;
  border: 1px solid #ddd;
  border-radius: 4px;
  resize: vertical;
  margin-bottom: 20px;
}
</style>

6.2 智能体状态仪表盘

创建 src/components/AgentDashboard.vue

<template>
  <div class="agent-dashboard">
    <h2>智能体状态仪表盘</h2>
    
    <div class="stats-grid">
      <div class="stat-card">
        <h3>总智能体数</h3>
        <div class="stat-value">{{ agents.length }}</div>
      </div>
      
      <div class="stat-card">
        <h3>活跃智能体</h3>
        <div class="stat-value">{{ activeAgentCount }}</div>
      </div>
      
      <div class="stat-card">
        <h3>总工作流</h3>
        <div class="stat-value">{{ workflowCount }}</div>
      </div>
    </div>

    <div class="agents-list">
      <h3>智能体列表</h3>
      <div v-for="agent in agents" :key="agent.id" class="agent-item">
        <div class="agent-info">
          <h4>{{ agent.name }}</h4>
          <p>{{ agent.role }}</p>
        </div>
        <div class="agent-status">
          <span :class="['status-badge', agent.status]">
            {{ agent.status }}
          </span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed, onMounted } from 'vue';
import { useAutogenStore } from '@/stores/autogenStore';

const store = useAutogenStore();
const { fetchAgents } = store;

const agents = computed(() => store.agents);
const activeAgentCount = computed(() => store.activeAgentCount);
const workflowCount = computed(() => store.workflowCount);

onMounted(() => {
  fetchAgents();
});
</script>

<style scoped>
.agent-dashboard {
  padding: 20px;
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin-bottom: 30px;
}

.stat-card {
  background: white;
  padding: 20px;
  border-radius: 8px;
  text-align: center;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.stat-value {
  font-size: 2em;
  font-weight: bold;
  color: #2c3e50;
}

.agents-list {
  background: white;
  padding: 20px;
  border-radius: 8px;
}

.agent-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px;
  border-bottom: 1px solid #eee;
}

.agent-item:last-child {
  border-bottom: none;
}

.agent-info h4 {
  margin: 0 0 4px 0;
  color: #2c3e50;
}

.agent-info p {
  margin: 0;
  color: #7f8c8d;
  font-size: 0.9em;
}

.status-badge {
  padding: 4px 8px;
  border-radius: 12px;
  font-size: 0.8em;
  font-weight: 500;
}

.status-badge.active {
  background-color: #e8f5e9;
  color: #2e7d32;
}

.status-badge.idle {
  background-color: #fff3e0;
  color: #f57c00;
}

.status-badge.error {
  background-color: #ffebee;
  color: #c62828;
}
</style>

7. 部署与优化建议

7.1 生产环境配置

创建 Dockerfile 用于容器化部署:

# 构建阶段
FROM node:18-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 生产阶段
FROM nginx:alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

创建 nginx.conf 配置文件:

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    server {
        listen 80;
        server_name localhost;
        root /usr/share/nginx/html;
        index index.html;

        # 处理前端路由
        location / {
            try_files $uri $uri/ /index.html;
        }

        # API代理配置
        location /api {
            proxy_pass http://autogen-backend:8080/api;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }

        # WebSocket代理配置
        location /ws {
            proxy_pass http://autogen-backend:8080/ws;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
        }
    }
}

7.2 性能优化建议

  1. 代码分割:使用Vue3的异步组件实现路由懒加载
// router/index.js
const WorkflowRunner = () => import('../components/WorkflowRunner.vue');
const AgentDashboard = () => import('../components/AgentDashboard.vue');
  1. API请求优化:实现请求去重和缓存
// src/services/autogenService.js
const requestCache = new Map();

export const cachedRequest = async (key, requestFn) => {
  if (requestCache.has(key)) {
    return requestCache.get(key);
  }
  
  const result = await requestFn();
  requestCache.set(key, result);
  return result;
};
  1. WebSocket重连机制
// src/services/websocketService.js
class WebSocketService {
  // ... 其他代码
  
  reconnect() {
    this.disconnect();
    setTimeout(() => {
      this.connect();
    }, 3000); // 3秒后重连
  }
}

8. 总结

通过本文的实践,我们成功将AutoGen Studio与Vue3前端框架进行了深度集成,构建了一个功能完整、用户体验良好的智能体管理平台。这个方案不仅提供了美观的界面,更重要的是让非技术人员也能轻松使用复杂的多智能体系统。

在实际项目中,这种集成方式显著提升了团队的工作效率。业务人员可以直接通过Web界面与AI智能体交互,而不需要了解底层的技术细节。实时监控功能让团队成员能够清晰了解智能体的工作状态,及时发现问题并进行调整。

当然,这只是一个起点。随着AutoGen Studio功能的不断丰富,前端界面也需要相应的演进。建议持续关注AutoGen项目的更新,及时调整集成方案,同时根据实际业务需求不断优化用户体验。最重要的是保持架构的灵活性,为未来的功能扩展预留空间。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐