动手实践OpenHands系列学习笔记5:代理系统架构概述

笔记5:代理系统架构概述

一、引言

AI代理系统是一种能够自主执行任务的智能软件架构,OpenHands作为AI驱动的软件开发代理平台,拥有完整的代理系统架构设计。本笔记将探讨AI代理架构的基本原理,并通过分析OpenHands核心架构,实现一个简化版的代理框架。

二、AI代理架构设计原则

2.1 AI代理系统的核心组件

  • 感知模块(Perception): 接收和处理外部输入
  • 认知模块(Cognition): 分析信息并进行决策
  • 执行模块(Action): 实施决策并与环境交互
  • 记忆模块(Memory): 存储历史信息和经验
  • 工具模块(Tools): 扩展代理能力的功能集合

2.2 代理系统设计原则

  1. 自主性原则: 代理应能在有限监督下自主完成任务
  2. 可观察性原则: 代理的状态和决策过程应当透明可见
  3. 安全性原则: 代理应有明确的操作边界和安全保障
  4. 适应性原则: 代理应能根据反馈调整行为
  5. 模块化原则: 系统应由解耦合的组件构成,便于扩展
  6. 可靠性原则: 代理应能处理异常情况,避免灾难性失败

2.3 AI代理架构模式

  • 反应式代理(Reactive Agent): 基于简单规则响应环境
  • 基于目标的代理(Goal-Based Agent): 根据目标规划行动
  • 基于效用的代理(Utility-Based Agent): 优化行动的预期效用
  • 学习型代理(Learning Agent): 通过经验优化自身行为
  • 混合架构(Hybrid Architecture): 结合多种架构模式的优势

三、OpenHands代理架构分析

从README_CN.md中,我们可以推断OpenHands采用了复杂的混合代理架构,具有以下特点:

3.1 OpenHands核心架构组件

  1. LLM决策引擎: 由Claude Sonnet 4等大型语言模型提供核心智能
  2. 工具集成系统: 允许代理使用各种开发工具
  3. 沙箱执行环境: 安全隔离的代码执行环境
  4. 对话式界面: 用户与代理交互的主要接口
  5. 上下文管理系统: 维护代理的工作状态和历史
  6. 权限与安全控制: 管理代理的操作权限和安全边界

3.2 OpenHands架构特性

  • 容器化设计: 使用Docker实现环境隔离和可移植性
  • 多模态交互: 支持文本、代码和命令行交互
  • 无头模式支持: 可在无GUI环境下以编程方式使用
  • 云原生架构: 支持云端部署和本地运行
  • 可扩展设计: 支持添加新工具和自定义功能

3.3 OpenHands架构图(推断)

┌─────────────────────────────────────────┐
│            OpenHands系统架构            │
└─────────────────────────────────────────┘│┌───────────┼───────────┐│           │           │
┌───────▼───────┐ ┌─▼─┐ ┌───────▼───────┐
│  用户界面层   │ │   │ │   安全层      │
│ (Web/CLI/API) │ │   │ │(权限/隔离/审计)│
└───────┬───────┘ │   │ └───────┬───────┘│         │   │         │
┌───────▼───────┐ │核 │ ┌───────▼───────┐
│  对话管理层   │ │心 │ │   工具集成层  │
│(上下文/历史)  │ │控 │ │(工具定义/调用)│
└───────┬───────┘ │制 │ └───────┬───────┘│         │层 │         │
┌───────▼───────┐ │   │ ┌───────▼───────┐
│  LLM决策层    │ │   │ │  执行环境层   │
│(思维/规划/推理)│ │   │ │(沙箱/运行时) │
└───────┬───────┘ └─┬─┘ └───────┬───────┘│           │           │└───────────┼───────────┘│┌───────────▼───────────┐│     持久化存储层      ││  (配置/历史/工作区)   │└───────────────────────┘

四、实践项目:实现简化版代理框架

4.1 代理系统核心结构设计

// agent-core.js
const EventEmitter = require('events');
const LLMClient = require('./llm-client'); // 前一笔记中的LLM客户端
const PromptManager = require('./prompt-manager'); // 前一笔记中的提示管理器class AgentCore extends EventEmitter {constructor(config = {}) {super();this.config = {llmProvider: config.llmProvider || 'claude',apiKey: config.apiKey,systemPrompt: config.systemPrompt || 'You are a helpful AI assistant.',maxIterations: config.maxIterations || 10,...config};this.llmClient = null;this.promptManager = new PromptManager();this.memory = {shortTerm: [], // 当前会话记忆workingMemory: {}, // 工作记忆(变量、状态等)longTerm: [] // 长期记忆(可选,用于跨会话)};this.tools = {}; // 可用工具映射this.state = 'idle'; // 代理状态:idle, thinking, executing, waiting}// 初始化代理系统async initialize() {try {// 初始化提示管理器await this.promptManager.initialize();// 初始化LLM客户端if (!this.config.apiKey) {throw new Error('API key is required');}this.llmClient = new LLMClient({apiKey: this.config.apiKey,model: this.config.model,baseURL: this.config.baseURL});// 加载默认工具await this._registerDefaultTools();this.emit('initialized');return true;} catch (error) {this.emit('error', error);throw error;}}// 注册默认工具async _registerDefaultTools() {// 这里可以注册默认工具// 例如文件操作、命令执行等const defaultTools = [{name: 'search_web',description: '搜索互联网获取信息',handler: async (query) => {// 简化的web搜索实现return { results: [`模拟搜索结果: ${query}`] };}},{name: 'execute_command',description: '执行shell命令',handler: async (command) => {// 在实际实现中,这里应该有安全检查// 简化的命令执行实现return { output: `模拟命令执行: ${command}` };}}];defaultTools.forEach(tool => {this.registerTool(tool.name, tool.description, tool.handler);});}// 注册工具registerTool(name, description, handler) {if (this.tools[name]) {throw new Error(`Tool ${name} already exists`);}this.tools[name] = {name,description,handler};this.emit('tool_registered', name);return this;}// 获取工具信息getTools() {return Object.values(this.tools).map(tool => ({name: tool.name,description: tool.description}));}// 处理用户输入async processInput(userInput, options = {}) {try {this.state = 'thinking';this.emit('state_change', this.state);// 记录用户输入到短期记忆this._addToMemory('user', userInput);// 构建系统提示const systemPrompt = this._buildSystemPrompt();// 准备提示上下文const context = this._prepareContext();// 使用提示管理器增强用户输入const enhancedInput = this.promptManager.enhanceUserPrompt(userInput, context);// 调用LLM获取响应const response = await this.llmClient.complete(enhancedInput, systemPrompt, options);// 解析响应const parsedResponse = this._parseResponse(response);// 记录助手响应到短期记忆this._addToMemory('assistant', parsedResponse.content);// 处理工具调用if (parsedResponse.toolCalls && parsedResponse.toolCalls.length > 0) {this.state = 'executing';this.emit('state_change', this.state);// 执行工具调用const toolResults = await this._executeToolCalls(parsedResponse.toolCalls);// 记录工具调用结果到短期记忆toolResults.forEach(result => {this._addToMemory('tool_result', result);});// 如果需要继续对话,递归处理if (parsedResponse.needsFollowUp && this.memory.shortTerm.length < this.config.maxIterations * 2) {return this.processInput(`请处理以下工具调用结果并继续任务: ${JSON.stringify(toolResults)}`, options);}}this.state = 'idle';this.emit('state_change', this.state);return parsedResponse;} catch (error) {this.state = 'error';this.emit('error', error);throw error;}}// 构建系统提示_buildSystemPrompt() {// 获取所有工具的描述const tools = this.getTools();// 使用提示管理器生成系统提示return this.promptManager.generateSystemPrompt(null, tools, {AGENT_CAPABILITIES: "You can search the web, execute commands, and more."});}// 准备上下文_prepareContext() {return {memory: this.memory.shortTerm.slice(-10), // 最近10条记忆workingMemory: this.memory.workingMemory,tools: Object.keys(this.tools)};}// 解析LLM响应_parseResponse(response) {// 简化的响应解析// 在实际实现中,需要根据具体LLM API响应格式进行解析const content = response.content?.[0]?.text || '';// 简单的工具调用解析const toolCallRegex = /\[\[TOOL:(\w+)\]\[(.*?)\]\]/g;const toolCalls = [];let match;while ((match = toolCallRegex.exec(content)) !== null) {toolCalls.push({tool: match[1],args: JSON.parse(match[2])});}return {content: content.replace(toolCallRegex, '').trim(),toolCalls,needsFollowUp: toolCalls.length > 0};}// 执行工具调用async _executeToolCalls(toolCalls) {const results = [];for (const call of toolCalls) {const tool = this.tools[call.tool];if (!tool) {results.push({tool: call.tool,status: 'error',error: `Tool not found: ${call.tool}`});continue;}try {const result = await tool.handler(call.args);results.push({tool: call.tool,status: 'success',result});} catch (error) {results.push({tool: call.tool,status: 'error',error: error.message});}}return results;}// 添加到记忆_addToMemory(role, content) {this.memory.shortTerm.push({role,content,timestamp: Date.now()});this.emit('memory_updated', role, content);}// 设置工作记忆setWorkingMemory(key, value) {this.memory.workingMemory[key] = value;this.emit('working_memory_updated', key, value);}// 获取工作记忆getWorkingMemory(key) {return this.memory.workingMemory[key];}// 清除短期记忆clearShortTermMemory() {this.memory.shortTerm = [];this.emit('memory_cleared', 'shortTerm');}// 保存代理状态async saveState(filePath) {// 简化的状态保存const state = {memory: this.memory,timestamp: Date.now()};// 在实际实现中,这里应该写入文件return state;}// 加载代理状态async loadState(filePath) {// 简化的状态加载// 在实际实现中,这里应该读取文件// 假设已经加载了状态this.emit('state_loaded');}
}module.exports = AgentCore;

4.2 实现工具管理系统

// tool-manager.js
const EventEmitter = require('events');
const fs = require('fs').promises;
const path = require('path');class ToolManager extends EventEmitter {constructor(config = {}) {super();this.toolsDir = config.toolsDir || path.join(process.cwd(), 'tools');this.tools = {};this.toolSchemas = {}; // 用于存储工具的JSON Schemathis.toolCategories = {'file': [],'command': [],'web': [],'code': [],'other': []};}// 初始化工具管理器async initialize() {try {// 创建工具目录(如果不存在)await fs.mkdir(this.toolsDir, { recursive: true });// 尝试加载工具const files = await fs.readdir(this.toolsDir);for (const file of files) {if (file.endsWith('.js') || file.endsWith('.json')) {try {await this.loadToolFromFile(path.join(this.toolsDir, file));} catch (error) {console.warn(`Failed to load tool from ${file}:`, error.message);}}}console.log(`Loaded ${Object.keys(this.tools).length} tools`);} catch (error) {console.warn('Error initializing tool manager:', error.message);}}// 从文件加载工具async loadToolFromFile(filePath) {try {let tool;if (filePath.endsWith('.js')) {// 加载JavaScript工具模块const toolModule = require(filePath);tool = toolModule.tool || toolModule.default || toolModule;} else if (filePath.endsWith('.json')) {// 加载JSON工具定义const content = await fs.readFile(filePath, 'utf8');const toolDef = JSON.parse(content);if (!toolDef.name || !toolDef.handler) {throw new Error('Invalid tool definition: missing name or handler');}// 创建动态处理函数const handlerFn = new Function('args', `return ${toolDef.handler}`);tool = {name: toolDef.name,description: toolDef.description || '',category: toolDef.category || 'other',handler: async (args) => handlerFn(args),schema: toolDef.schema || {}};}if (tool && tool.name) {this.registerTool(tool);}} catch (error) {throw new Error(`Failed to load tool from ${filePath}: ${error.message}`);}}// 注册工具registerTool(tool) {if (!tool.name || typeof tool.handler !== 'function') {throw new Error('Invalid tool: must have name and handler function');}if (this.tools[tool.name]) {throw new Error(`Tool ${tool.name} already exists`);}this.tools[tool.name] = tool;// 存储工具schemaif (tool.schema) {this.toolSchemas[tool.name] = tool.schema;}// 分类工具const category = tool.category || 'other';if (this.toolCategories[category]) {this.toolCategories[category].push(tool.name);} else {this.toolCategories[category] = [tool.name];}this.emit('tool_registered', tool.name);return this;}// 执行工具async executeTool(name, args = {}) {const tool = this.tools[name];if (!tool) {throw new Error(`Tool not found: ${name}`);}try {this.emit('tool_execution_start', name, args);const result = await tool.handler(args);this.emit('tool_execution_complete', name, args, result);return result;} catch (error) {this.emit('tool_execution_error', name, args, error);throw error;}}// 获取工具列表getTools(category = null) {if (category && this.toolCategories[category]) {return this.toolCategories[category].map(name => ({name,description: this.tools[name].description,category}));}return Object.values(this.tools).map(tool => ({name: tool.name,description: tool.description,category: tool.category || 'other'}));}// 获取工具描述getToolDescription(name) {const tool = this.tools[name];return tool ? {name: tool.name,description: tool.description,category: tool.category || 'other',schema: tool.schema} : null;}// 获取所有工具的JSON SchemasgetToolSchemas() {return this.toolSchemas;}// 创建并保存新工具async createTool(toolDef) {if (!toolDef.name || !toolDef.handler) {throw new Error('Invalid tool definition: missing name or handler');}// 生成工具文件名const fileName = `${toolDef.name.toLowerCase().replace(/\s+/g, '_')}.json`;const filePath = path.join(this.toolsDir, fileName);// 保存工具定义await fs.writeFile(filePath,JSON.stringify(toolDef, null, 2),'utf8');// 加载工具await this.loadToolFromFile(filePath);return toolDef.name;}
}module.exports = ToolManager;

4.3 实现代理执行引擎

// agent-executor.js
const EventEmitter = require('events');
const AgentCore = require('./agent-core');
const ToolManager = require('./tool-manager');class AgentExecutor extends EventEmitter {constructor(config = {}) {super();this.config = config;this.agentCore = new AgentCore(config);this.toolManager = new ToolManager(config);this.isRunning = false;this.taskQueue = []; // 任务队列this.currentTask = null; // 当前正在执行的任务}// 初始化执行引擎async initialize() {try {// 初始化工具管理器await this.toolManager.initialize();// 将工具管理器中的工具注册到代理核心const tools = this.toolManager.getTools();for (const tool of tools) {this.agentCore.registerTool(tool.name, tool.description, async (args) => this.toolManager.executeTool(tool.name, args));}// 初始化代理核心await this.agentCore.initialize();// 连接事件处理this._connectEvents();this.emit('initialized');return true;} catch (error) {this.emit('error', error);throw error;}}// 连接事件处理_connectEvents() {// 监听代理核心事件this.agentCore.on('error', (error) => {this.emit('error', error);});this.agentCore.on('state_change', (state) => {this.emit('state_change', state);});// 监听工具管理器事件this.toolManager.on('tool_execution_start', (name, args) => {this.emit('tool_execution_start', name, args);});this.toolManager.on('tool_execution_complete', (name, args, result) => {this.emit('tool_execution_complete', name, args, result);});this.toolManager.on('tool_execution_error', (name, args, error) => {this.emit('tool_execution_error', name, args, error);});}// 添加任务到队列addTask(task) {if (!task.input) {throw new Error('Task must have input');}const taskWithId = {id: `task_${Date.now()}_${Math.floor(Math.random() * 1000)}`,input: task.input,options: task.options || {},status: 'queued',createdAt: Date.now(),...task};this.taskQueue.push(taskWithId);this.emit('task_queued', taskWithId);// 如果没有正在执行的任务,启动执行if (!this.isRunning) {this._processNextTask();}return taskWithId.id;}// 处理下一个任务async _processNextTask() {if (this.taskQueue.length === 0) {this.isRunning = false;this.emit('queue_empty');return;}this.isRunning = true;this.currentTask = this.taskQueue.shift();this.currentTask.status = 'running';this.currentTask.startedAt = Date.now();this.emit('task_started', this.currentTask);try {// 执行任务const result = await this.agentCore.processInput(this.currentTask.input,this.currentTask.options);this.currentTask.status = 'completed';this.currentTask.completedAt = Date.now();this.currentTask.result = result;this.emit('task_completed', this.currentTask);} catch (error) {this.currentTask.status = 'failed';this.currentTask.error = error.message;this.currentTask.completedAt = Date.now();this.emit('task_failed', this.currentTask, error);}// 处理下一个任务this._processNextTask();}// 执行单个任务async executeTask(task) {const taskId = this.addTask(task);return new Promise((resolve, reject) => {const onCompleted = (completedTask) => {if (completedTask.id === taskId) {this.removeListener('task_completed', onCompleted);this.removeListener('task_failed', onFailed);resolve(completedTask.result);}};const onFailed = (failedTask, error) => {if (failedTask.id === taskId) {this.removeListener('task_completed', onCompleted);this.removeListener('task_failed', onFailed);reject(error);}};this.on('task_completed', onCompleted);this.on('task_failed', onFailed);});}// 取消任务cancelTask(taskId) {// 从队列中移除任务const index = this.taskQueue.findIndex(task => task.id === taskId);if (index !== -1) {const canceledTask = this.taskQueue.splice(index, 1)[0];canceledTask.status = 'canceled';this.emit('task_canceled', canceledTask);return true;}// 如果是当前任务,无法取消(简化版)if (this.currentTask && this.currentTask.id === taskId) {return false;}return false;}// 获取当前状态getStatus() {return {isRunning: this.isRunning,queueLength: this.taskQueue.length,currentTask: this.currentTask};}// 清空任务队列clearTaskQueue() {const canceledTasks = [...this.taskQueue];this.taskQueue = [];canceledTasks.forEach(task => {task.status = 'canceled';this.emit('task_canceled', task);});return canceledTasks.length;}
}module.exports = AgentExecutor;

4.4 创建简单的代理应用框架

// agent-app.js
const express = require('express');
const bodyParser = require('body-parser');
const AgentExecutor = require('./agent-executor');class AgentApp {constructor(config = {}) {this.config = {port: config.port || 3000,apiKey: config.apiKey,llmProvider: config.llmProvider || 'claude',...config};this.app = express();this.agentExecutor = new AgentExecutor({apiKey: this.config.apiKey,llmProvider: this.config.llmProvider});}// 初始化应用async initialize() {// 配置Expressthis.app.use(bodyParser.json());// 初始化代理执行器await this.agentExecutor.initialize();// 设置路由this._setupRoutes();return this;}// 设置API路由_setupRoutes() {// 健康检查this.app.get('/health', (req, res) => {res.json({ status: 'ok' });});// 获取工具列表this.app.get('/api/tools', (req, res) => {const tools = this.agentExecutor.toolManager.getTools(req.query.category);res.json({ tools });});// 执行任务this.app.post('/api/tasks', async (req, res) => {try {const { input, options } = req.body;if (!input) {return res.status(400).json({ error: 'Input is required' });}const taskId = this.agentExecutor.addTask({ input, options });res.status(202).json({ taskId });} catch (error) {res.status(500).json({ error: error.message });}});// 获取任务状态this.app.get('/api/tasks/:taskId', (req, res) => {// 简化版:实际实现需要任务存储const { currentTask } = this.agentExecutor.getStatus();if (currentTask && currentTask.id === req.params.taskId) {res.json(currentTask);} else {res.status(404).json({ error: 'Task not found' });}});// 取消任务this.app.delete('/api/tasks/:taskId', (req, res) => {const success = this.agentExecutor.cancelTask(req.params.taskId);if (success) {res.status(204).send();} else {res.status(404).json({ error: 'Task not found or cannot be canceled' });}});// 对话接口this.app.post('/api/chat', async (req, res) => {try {const { message, options } = req.body;if (!message) {return res.status(400).json({ error: 'Message is required' });}const response = await this.agentExecutor.executeTask({ input: message, options });res.json(response);} catch (error) {res.status(500).json({ error: error.message });}});}// 启动应用async start() {return new Promise((resolve) => {this.server = this.app.listen(this.config.port, () => {console.log(`Agent app running on port ${this.config.port}`);resolve(this.server);});});}// 停止应用async stop() {if (this.server) {return new Promise((resolve) => {this.server.close(() => {console.log('Agent app stopped');resolve();});});}}
}module.exports = AgentApp;

4.5 使用示例

// index.js
require('dotenv').config(); // 加载环境变量
const AgentApp = require('./agent-app');async function main() {try {const agentApp = new AgentApp({port: process.env.PORT || 3000,apiKey: process.env.API_KEY,llmProvider: process.env.LLM_PROVIDER || 'claude'});await agentApp.initialize();await agentApp.start();console.log('Agent app started successfully');} catch (error) {console.error('Failed to start agent app:', error);process.exit(1);}
}main();

五、总结与思考

  1. AI代理架构的关键组成:

    • 决策引擎(LLM)是核心智能来源
    • 工具系统扩展代理能力边界
    • 记忆系统维持连贯性和上下文
    • 执行引擎协调各组件工作
    • 安全层确保操作在可控范围内
  2. OpenHands的架构特点:

    • 容器化隔离执行环境
    • 强大的工具集成能力
    • 灵活的部署模式(云端/本地)
    • 多模态交互界面
    • 安全性与功能性平衡
  3. 代理系统设计考量:

    • 如何平衡自主性与控制
    • 如何处理复杂任务分解
    • 如何维护长期上下文
    • 如何确保执行安全
    • 如何优化性能和资源使用

六、下一步学习方向

  1. 探索更复杂的工具集成机制
  2. 研究多代理协作系统
  3. 实现更高级的记忆和规划机制
  4. 开发更完善的安全防护措施
  5. 优化资源使用和性能表现

七、参考资源

  1. OpenHands文档
  2. AI Agent架构论文
  3. 反应式代理与认知代理
  4. 工具学习研究
  5. 安全代理设计原则

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/87598.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/87598.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

智能电动汽车 --- 车辆网关路由缓存

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

Spring中实现依赖注入(DI)的三种方式

1. Autowired 字段注入&#xff08;不推荐&#xff09;​ Service public class UserService {Autowired // 直接在字段上注入private UserRepository userRepository; } ​​原理​​&#xff1a;Spring 启动时扫描所有 Component、Service 等注解的类&#xff0c;发现 Aut…

Alpha系统联结大数据、GPT两大功能,助力律所管理降本增效

如何通过AI工具实现法律服务的提质增效,是每一位法律人都积极关注和学习的课题。但从AI技术火爆一下,法律人一直缺乏系统、实用的学习资料,来掌握在法律场景下AI的使用技巧。 今年5月,iCourt携手贵阳律协大数据与人工智能专业委员会,联合举办了《人工智能助力律师行业高质量发…

UI前端与数字孪生融合新趋势:智慧家居的智能化控制与个性化服务

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩!一、引言&#xff1a;数字孪生重构智慧家居的技术范式在智能家居渗透率快速提升的今天&#xf…

R语言初学者爬虫简单模板

习惯使用python做爬虫的&#xff0c;反过来使用R语言可能有点不太习惯&#xff0c;正常来说R语言好不好学完全取决于你的学习背景以及任务复杂情况。对于入门学者来说&#xff0c;R语言使用rvesthttr组合&#xff0c;几行代码就能完成简单爬取&#xff08;比Python的Scrapy简单…

如何决定idea项目中使用的是哪个版本的jdk?是idea中配置决定的?还是maven中配置决定的

✅ IDEA 项目中使用哪个 JDK&#xff0c;是由以下几部分共同决定的&#xff1a; 阶段决定因素举例项目编译&#xff08;编译器&#xff09;IDEA 设置的 Project SDK 和模块 SDKProject Structure → Project / Modules 中配置的 JDKMaven 构建Maven 使用的 JDK&#xff08;即 …

Docker拉取bladex 、 sentinel-dashboard

docker pull bladex/sentinel-dashboard 是用于从 Docker Hub 拉取 Alibaba Cloud Sentinel Dashboard 镜像的命令&#xff0c;默认会拉取最新版本。以下是详细的操作步骤及注意事项&#xff1a; 操作步骤 1. 拉取镜像 &#xff1a;在终端输入 docker pull bladex/sentinel-…

从零开始理解 JavaScript 中的 `window.parent`、`top` 和 `self`

从零开始理解 JavaScript 中的 window.parent、top 和 self 在 JavaScript 开发中&#xff0c;window 对象是浏览器环境中最重要的全局对象之一。它不仅代表了浏览器窗口本身&#xff0c;还提供了对窗口层级关系的访问能力。对于处理嵌套框架&#xff08;iframe&#xff09;或…

vue3引入海康监控视频组件并实现非分屏需求一个页面同时预览多个监控视频;

海康监控视频非分屏需求&#xff0c;一个页面引用多个视频组件; js文件位置index.html 引入js文件//根据自己路径引入哈<script src"static/haiKangWeb3.0/jquery-1.7.1.min.js"></script><script type"text/javascript" id"videonode…

Policy Gradient【强化学习的数学原理】

目录 policy 与表格方式的区别&#xff1a; metric to define optimal policies 1. weighted averge 2. the average reward 问题&#xff1a; 梯度计算 如何理解policy-gradient&#xff1f; policy gradient与表格方式(value based)的区别&#xff1a; policy 通过参…

【深圳大学机器学习】实验一:PCA算法

实验目的 1、实现PCA算法的人脸重构&#xff0c;即用20,40,60,80,...,160个投影来重构图像的效果。 2、实现PCA算法的人脸识别&#xff0c;给出不少于三个人脸数据库上 10,20,30,...,160维的人脸识别识别率&#xff0c;并打印出识别率变化曲线图。 3、用PCA用来进行人脸图像…

编程中的英语

case this are mixed case version case在这里表示大小写&#xff1f;为什么case可以表示大小写的含义&#xff1f; “case”在这里的含义 在句子“This are mixed case version”中&#xff0c;“case”确实表示“大小写”&#xff0c;用于描述字母的形式&#xff08;大写字母…

LabVIEW开发关节轴承试验机

LabVIEW通过NI硬件&#xff08;CompactRIO 实时控制器、FPGA 模块等&#xff09;与模块化软件设计的结合&#xff0c;实现试验参数采集、多工况控制、数据存储的并行处理&#xff0c;体现LabVIEW 在工业自动化中对多任务并发场景的高效支持能力。 ​ 应用场景 关节轴承试验机…

【Linux庖丁解牛】— 动静态库的制作和使用!

1. 什么是库库是写好的现有的&#xff0c;成熟的&#xff0c;可以复⽤的代码。现实中每个程序都要依赖很多基础的底层库&#xff0c;不可能 每个⼈的代码都从零开始&#xff0c;因此库的存在意义⾮同寻常。 本质上来说库是⼀种可执⾏代码的⼆进制形式&#xff0c;可以被操作系统…

Hadoop集群启动 (ZooKeeper、HDFS、YARN、Hbase)

一、启动ZooKeeper集群 sh /opt/modules/zookeeper-3.4.14/bin/zkServer.sh start[hadoopcentos01 ~]$ sh /opt/modules/zookeeper-3.4.14/bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /opt/modules/zookeeper-3.4.14/bin/../conf/zoo.cfg Startin…

React Hooks全面解析:从基础到高级的实用指南

React Hooks全面解析&#xff1a;从基础到高级的实用指南 React Hooks自2018年16.8版本引入以来&#xff0c;彻底改变了React组件的开发方式。** Hooks使函数组件获得了与类组件同等的表达能力&#xff0c;同时简化了代码结构&#xff0c;提升了可维护性**。本文将系统介绍Rea…

LINUX75 LAMP

LAMP 环境 yum NetworkManager systemctl status firewalld setenforce 0 Last login: Fri Jul 4 19:21:47 2025 from 192.168.235.1 [rootweb ~]# cd /usr/local/apache2/conf/ [rootweb conf]# ls extra httpd.conf httpd.conf.bak magic mime.types original [root…

cloudflare配合github搭建免费开源影视LibreTV一个独享视频网站 详细教程

一、项目简介 LibreTV 是一个开源的 IPTV/影视聚合前端项目&#xff0c;支持 M3U 播放列表、EPG 电子节目单等。它本身是纯前端项目&#xff0c;非常适合用 GitHub Pages Cloudflare 免费托管。 二、准备工作 GitHub 账号 注册并登录 GitHub Cloudflare 账号 注册并登录 …

Linux/Unix进程概念及基本操作(PID、内存布局、虚拟内存、环境变量、fork、exit、wait、exec、system)

进程 文章目录 进程I 进程基本概念1、进程和程序2、进程号和父进程号3、进程内存布局4、虚拟内存管理&#xff08;1&#xff09;程序的两种局部性&#xff08;2&#xff09;虚拟内存的规划&#xff08;3&#xff09;虚拟内存的优点 5、栈和栈帧6、命令行参数argc和argv7、环境变…

0基础学Python系列【25】 单元测试入门教程

大家好,欢迎来到Python学习的第三站!🎉 这部分会涉及一些Python的进阶技术,虽然不一定是必需的,但学会这些,你会觉得编程更得心应手。 本章要学什么? Python调试器(pdb)装饰器lambda函数代码性能分析单元测试入门 —— 今天讲这里听起来有点多?别担心,我们慢慢来,…