news 2026/4/27 11:55:39

AI代理框架:构建能操作GUI的智能数字同事

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI代理框架:构建能操作GUI的智能数字同事

1. 项目概述:当AI成为你的“数字同事”

最近在折腾一个开源项目,叫collaborator-ai/collab-public。这个名字本身就很有意思——“协作者AI”。它不是那种帮你写诗、画图的通用大模型,也不是一个简单的聊天机器人。它的定位更精准,也更实用:一个能深度融入你现有工作流,扮演“数字同事”角色的AI代理框架。简单来说,它能让AI像真人一样,去操作你的电脑、使用你的软件、处理你的文件,帮你完成那些重复、繁琐但又需要一定判断力的任务。

想象一下,你每天上班要处理几十封邮件,从里面筛选出重要信息,整理成报告,再更新到某个表格里。或者,你需要定期从几个不同的网站抓取数据,汇总分析。这些工作往往需要你打开多个应用,在不同窗口间切换,复制粘贴,手动整理。collab-public的目标,就是让一个AI程序替你完成这一系列操作。它通过模拟人类与图形界面(GUI)或命令行(CLI)的交互,理解任务目标,然后像真人一样去点击、输入、导航,最终达成目的。这不仅仅是自动化脚本的升级,而是引入了“理解”和“决策”能力的智能体(Agent)。

这个项目适合谁呢?如果你是一名经常与重复性数字任务打交道的运营、数据分析师、行政人员,或者是一名开发者,希望为自己的产品构建一个能操作界面的AI助手,那么collab-public提供的思路和工具就非常值得研究。它不要求你从零开始构建复杂的AI代理系统,而是提供了一个可扩展的框架,让你能基于自己的具体场景,快速“组装”出一个能干的数字同事。

2. 核心架构与设计哲学拆解

2.1 从“自动化”到“智能化”的跨越

传统的自动化方案,比如RPA(机器人流程自动化)或者写Python脚本配合Selenium,其核心逻辑是“流程驱动”。你需要预先定义好每一步:先点这里,再输入那个,然后等页面加载,最后提取某个固定位置的数据。这种方案非常脆弱,一旦界面布局、按钮位置、元素ID稍有变动,整个流程就可能崩溃。

collab-public的设计哲学是“目标驱动”和“感知-决策-执行”循环。它尝试让AI代理具备类似人类的感知能力(通过计算机视觉或可访问性API“看到”屏幕)、理解能力(通过大语言模型理解当前界面状态和任务目标)、决策能力(规划下一步最佳操作)和执行能力(通过模拟输入执行操作)。这样一来,即使界面发生了变化,只要AI能“看懂”新界面上的元素(比如一个按钮的文字从“提交”变成了“确认”),它就有可能调整策略,继续完成任务。这是一种从“刚性流程”到“柔性智能”的质变。

2.2 核心组件模块化解析

为了实现上述目标,collab-public的架构通常是高度模块化的。虽然具体实现可能因版本而异,但其核心思想离不开以下几个关键组件:

  1. 感知模块(Perception Module):这是AI的“眼睛”。它负责捕获当前的屏幕状态。实现方式有多种:

    • 屏幕截图+OCR/视觉模型:这是最通用但也最具挑战性的方式。定期截取屏幕图像,然后使用光学字符识别(OCR)技术提取文字,或者使用经过训练的视觉语言模型(如GPT-4V)直接理解图像内容。这种方式跨平台兼容性好,但处理速度、准确性和成本是需要权衡的问题。
    • 可访问性树(Accessibility Tree):对于现代桌面和Web应用,操作系统和浏览器提供了丰富的可访问性信息。这个“树”结构包含了所有UI元素的类型、名称、状态、位置等元数据。通过调用系统API(如Windows上的UI Automation, macOS上的Accessibility API)获取这些信息,比分析图像更精准、更高效。collab-public很可能会优先利用这种方式,因为它提供的是结构化的、语义化的界面描述。
    • DOM/控件句柄:对于Web自动化,可以直接操作浏览器DOM;对于桌面应用,可以通过控件句柄(Handle)来定位。这通常需要与感知模块结合,以确认元素状态。
  2. 认知与决策模块(Cognition & Decision Module):这是AI的“大脑”,通常由大语言模型(LLM)驱动。它接收来自感知模块的“当前状态”描述和用户的“任务目标”,然后进行推理:

    • 任务分解:将复杂的顶层目标(如“整理本周销售数据报告”)分解成一系列原子操作(如“打开Excel”、“找到‘销售数据’工作表”、“筛选日期列为本周”等)。
    • 状态理解:分析当前屏幕上的信息,判断处于哪个应用、哪个页面、有哪些可操作元素。
    • 下一步动作预测:基于任务目标和当前状态,决定下一步最合理的操作是什么。例如,“当前是邮箱登录页面,目标是检查邮件,所以下一步应该是在‘用户名’输入框输入我的邮箱。”
    • 动作格式化:将决策输出为系统可执行的标准化指令,例如click(element_id=“login_button”)type(text=“hello world”, into=“search_box”)
  3. 执行模块(Execution Module):这是AI的“手”。它接收决策模块发出的标准化指令,并将其转化为操作系统级别的输入事件。这通常通过模拟键盘按键(如pyautoguipynput)、模拟鼠标点击和移动、或者调用更底层的系统输入API来实现。关键在于执行的可靠性和兼容性,要确保点击能精准命中目标,输入不会乱码。

  4. 记忆与状态管理模块(Memory & State Management):为了让AI能处理多步骤任务,它需要记住之前做了什么、当前任务进展到哪一步、以及可能从历史交互中学到的经验(例如,某个网站的登录后通常会跳转到仪表盘)。这个模块可能包括短期的工作记忆(当前任务上下文)和长期的经验存储(用于优化未来决策)。

  5. 工具与技能库(Tools & Skills Library):一个可扩展的“工具箱”。除了基础的点击、输入,AI代理还可以调用更高级的“技能”,比如read_file(path)search_web(query)call_api(url, data)execute_sql(query)等。这些技能封装了复杂操作,让LLM可以通过简单的函数调用来完成专业任务,极大地扩展了AI代理的能力边界。collab-public作为一个框架,其强大之处往往体现在提供了一个方便开发者自定义和集成新工具的机制。

2.3 关键技术选型考量

在构建这样一个系统时,技术选型直接决定了其能力上限和易用性。

  • LLM的选择:这是核心决策引擎。需要权衡性能、成本和响应速度。
    • 云端大模型(如GPT-4, Claude-3):理解能力强,能处理复杂推理和模糊指令,但API调用有延迟和成本,且涉及数据出域的安全隐私考量。
    • 本地大模型(如Llama 3, Qwen2):数据完全本地处理,隐私安全有保障,长期成本可能更低,但对本地算力有要求,且小参数模型的复杂任务推理能力可能不及顶级云端模型。collab-public作为一个开源框架,很可能会设计成支持可插拔的LLM后端,让用户根据自身情况选择。
  • 感知层的选择:如前所述,在“可访问性API”和“纯视觉方案”间抉择。
    • 可访问性API优先:如果目标应用支持良好(大多数现代应用和Web),这是最优解,精准且高效。collab-public可能会内置对主流平台(Windows, macOS, Linux)可访问性接口的封装。
    • 视觉方案作为兜底:对于不支持可访问性的老旧应用或游戏界面,视觉+OCR是唯一选择。但这部分实现起来更复杂,对模型能力要求高。
  • 执行层的选择:需要平衡控制精度和跨平台性。
    • 系统级输入模拟:如pyautogui,简单粗暴,兼容性极广,但缺乏对具体控件元素的感知,容易因窗口位置变化而失效。
    • 应用级控件操作:通过可访问性API或应用特定SDK直接操作控件,更为健壮精准。collab-public的理想状态是能智能选择最佳执行方式。

注意:隐私与安全是生命线。一个能操作你电脑的AI,其权限极高。因此,这类框架必须设计严格的“沙箱”机制和权限控制。例如,AI代理的操作范围应被限制在指定的应用或浏览器标签页内;任何涉及敏感信息(密码、密钥)的操作都应通过安全的方式(如由用户临时授权输入)进行,而不是被AI记录或存储。在评估或使用任何类似框架时,必须首先审视其安全设计。

3. 实战演练:构建一个简易的网页数据收集AI助手

为了更具体地理解collab-public这类框架能做什么,我们抛开其具体代码,用其思想来设计并实现一个简化版的AI助手:让它帮我们每天从某个新闻网站抓取头条新闻的标题和链接,并保存到CSV文件中。

3.1 环境准备与工具选型

我们选择Python作为开发语言,因为它有丰富的AI和自动化库。这里我们模拟一个基于“目标驱动”的轻量级实现。

核心库选择:

  • Playwright:新一代浏览器自动化工具,比Selenium更快速、可靠,且能轻松获取丰富的页面上下文信息,包括可访问性树。我们将用它作为AI的“眼睛”和“手”。
  • OpenAI API (GPT-4):作为AI的“大脑”。你也可以替换为其他兼容OpenAI API格式的模型(如本地部署的Ollama)。
  • Python-dotenv:管理环境变量,安全地存储API密钥。

安装命令:

pip install playwright openai python-dotenv playwright install chromium # 安装浏览器驱动

项目结构:

news_collector_agent/ ├── .env # 存储OPENAI_API_KEY ├── config.py # 配置文件 ├── perception.py # 感知模块:获取页面信息 ├── cognition.py # 认知决策模块:与LLM交互 ├── execution.py # 执行模块:操作浏览器 ├── skills/ # 技能库 │ └── save_to_csv.py └── main.py # 主程序入口

3.2 感知模块实现:让AI“看懂”网页

感知模块的任务是将复杂的网页转换成一个LLM能理解的、结构化的描述。我们利用Playwright获取可访问性树(accessibility.snapshot()),它比纯HTML DOM更接近用户的视觉感知。

# perception.py import asyncio from playwright.async_api import async_playwright class WebPerception: def __init__(self, page): self.page = page async def get_page_state(self) -> str: """ 获取当前页面的可访问性快照,并将其转换为自然语言描述。 这是给LLM的‘观察结果’。 """ # 1. 获取可访问性树 try: snapshot = await self.page.accessibility.snapshot() except Exception as e: return f"无法获取页面可访问性信息:{e}。当前URL:{self.page.url}" # 2. 简化并提取关键信息(这是一个简化示例,实际可以更复杂) description = self._snapshot_to_description(snapshot) # 3. 附加当前URL和页面标题作为上下文 url = self.page.url title = await self.page.title() full_state = f"""当前页面状态: - 页面标题:{title} - 页面地址:{url} - 页面内容概览:{description} """ return full_state def _snapshot_to_description(self, snapshot, depth=0): """递归地将可访问性快照转换为文本描述。""" if not snapshot: return "空页面" text = "" # 只关注一些关键角色和元素,如链接、按钮、标题、段落 if isinstance(snapshot, dict): role = snapshot.get('role', '') name = snapshot.get('name', '') # 过滤掉无意义或冗余的元素 if name and role in ['link', 'button', 'heading', 'article', 'main']: indent = " " * depth text += f"{indent}- [{role}] {name}\n" # 递归处理子节点 children = snapshot.get('children', []) for child in children: text += self._snapshot_to_description(child, depth + 1) elif isinstance(snapshot, list): for item in snapshot: text += self._snapshot_to_description(item, depth) return text

这个函数会生成类似这样的描述:“当前页面状态:页面标题:某某新闻首页;页面地址:https://news.example.com;页面内容概览:[heading] 今日头条;[link] 某国通过重要法案;[link] 科技公司发布新产品;[button] 加载更多...”

3.3 认知与决策模块:AI大脑的推理过程

这个模块负责与LLM对话,告诉它目标,并让它根据当前页面状态决定下一步做什么。

# cognition.py import openai import os from dotenv import load_dotenv import json load_dotenv() class AICognitive: def __init__(self, model="gpt-4-turbo"): self.client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) self.model = model # 系统提示词,定义了AI的角色和能力 self.system_prompt = """你是一个网页操作AI助手。你的目标是根据用户指令,操作浏览器完成任务。 你将收到当前的页面状态描述。你需要分析状态,决定下一步操作。 你可以执行的操作类型有: 1. navigate(url): 跳转到指定URL。 2. click(description): 点击页面上与描述匹配的元素(如链接、按钮)。描述应尽量精确。 3. type(text, into_description): 在指定描述的元素中输入文本。 4. scroll(direction="up"/"down"/"left"/"right"): 滚动页面。 5. wait(seconds): 等待一段时间。 6. extract_data(instruction): 根据指令从当前页面提取数据(如所有新闻标题和链接)。 7. done(): 任务完成。 请严格按以下JSON格式回复: { "thought": "你的思考过程,分析当前情况和下一步计划。", "action": { "type": "操作类型,如click", "parameters": {} // 操作参数,如{"description": "登录按钮"} } } 如果任务完成,操作类型为"done"。 """ async def decide_next_action(self, page_state: str, final_goal: str) -> dict: """根据当前状态和最终目标,决定下一步动作。""" user_prompt = f"""最终任务目标:{final_goal} 当前页面状态: {page_state} 请决定下一步操作。""" try: response = self.client.chat.completions.create( model=self.model, messages=[ {"role": "system", "content": self.system_prompt}, {"role": "user", "content": user_prompt} ], temperature=0.1, # 低随机性,确保操作稳定 response_format={"type": "json_object"} # 强制返回JSON ) decision = json.loads(response.choices[0].message.content) return decision except Exception as e: print(f"调用LLM决策失败:{e}") # 降级策略:返回一个安全操作,比如等待 return { "thought": "决策引擎故障,执行等待操作。", "action": {"type": "wait", "parameters": {"seconds": 5}} }

3.4 执行模块:将决策转化为实际行动

执行模块接收标准化的动作指令,并调用Playwright执行。

# execution.py from playwright.async_api import Page import asyncio class ActionExecutor: def __init__(self, page: Page): self.page = page async def execute(self, action: dict): """执行动作指令。""" action_type = action.get('type') params = action.get('parameters', {}) print(f"[执行] {action_type} with {params}") if action_type == 'navigate': url = params.get('url') if url: await self.page.goto(url, wait_until="networkidle") else: print("错误:navigate操作缺少url参数") elif action_type == 'click': # 这里简化处理,实际应根据description更智能地定位元素 # 例如,可以使用Playwright的get_by_role, get_by_text等 description = params.get('description', '') # 简单实现:尝试点击包含该文本的第一个元素 if description: try: # 这是一个非常脆弱的实现,仅用于演示 await self.page.click(f"text={description}", timeout=5000) except Exception as e: print(f"点击元素 '{description}' 失败:{e}") # 实际项目中应有更复杂的重试和备选定位策略 else: print("错误:click操作缺少description参数") elif action_type == 'type': text = params.get('text') into = params.get('into_description') if text and into: # 先点击目标元素,再输入 await self.page.click(f"text={into}", timeout=5000) await self.page.keyboard.type(text) else: print("错误:type操作参数不完整") elif action_type == 'scroll': direction = params.get('direction', 'down') if direction == 'down': await self.page.mouse.wheel(0, 300) elif direction == 'up': await self.page.mouse.wheel(0, -300) await asyncio.sleep(1) # 等待滚动生效 elif action_type == 'wait': seconds = params.get('seconds', 2) await asyncio.sleep(seconds) elif action_type == 'extract_data': # 这是一个特殊操作,触发数据提取技能 instruction = params.get('instruction', '') print(f"[信息] 触发数据提取指令:{instruction}") # 这里可以触发一个专门的技能函数 # 例如:data = await extract_news_titles(self.page) # 然后通过某种机制(如全局变量、回调)将数据传递出去 # 为简化,我们假设执行此操作后,主循环会处理数据保存 pass elif action_type == 'done': print("[信息] 任务完成指令收到。") return 'DONE' else: print(f"错误:未知的操作类型 '{action_type}'") # 操作后等待一小段时间,让页面稳定 await asyncio.sleep(1) return 'CONTINUE'

3.5 主循环与技能整合

现在,我们将感知、认知、执行模块串联起来,形成一个完整的AI代理工作流。

# main.py import asyncio from playwright.async_api import async_playwright from perception import WebPerception from cognition import AICognitive from execution import ActionExecutor from skills.save_to_csv import save_data # 假设我们有一个保存数据的技能 async def run_ai_agent(start_url, final_goal): async with async_playwright() as p: # 启动浏览器,建议使用headed模式便于调试 browser = await p.chromium.launch(headless=False) context = await browser.new_context() page = await context.new_page() # 初始化三大模块 perceiver = WebPerception(page) thinker = AICognitive() executor = ActionExecutor(page) # 初始导航 await page.goto(start_url, wait_until="networkidle") collected_data = [] # 用于存储收集的数据 max_steps = 20 # 防止无限循环 for step in range(max_steps): print(f"\n=== 步骤 {step + 1} ===") # 1. 感知:获取当前页面状态 state = await perceiver.get_page_state() print(f"[状态] {state[:500]}...") # 打印前500字符 # 2. 认知:决定下一步动作 decision = await thinker.decide_next_action(state, final_goal) print(f"[决策] {decision}") # 3. 执行:执行动作 action_result = await executor.execute(decision['action']) # 处理特殊动作结果,如数据提取 if decision['action']['type'] == 'extract_data': # 这里调用具体的数据提取函数 # 示例:假设我们手动编写了提取新闻的函数 news_items = await extract_news_titles_and_links(page) if news_items: collected_data.extend(news_items) print(f"[数据] 已收集 {len(news_items)} 条新闻。") # 可以每收集一次就保存,或最后统一保存 save_data(news_items, 'news.csv') # 检查任务是否完成 if action_result == 'DONE': print("任务被标记为完成。") break if step == max_steps - 1: print("达到最大步数,强制停止。") # 任务结束后,保存所有数据 if collected_data: save_data(collected_data, 'all_news.csv') print(f"任务结束,共收集 {len(collected_data)} 条数据,已保存。") await browser.close() # 一个简单的数据提取函数示例 async def extract_news_titles_and_links(page): """从当前页面提取新闻标题和链接(需要根据实际网站结构调整)。""" # 这里使用Playwright选择器,实际应用需要分析目标网站HTML结构 items = [] # 假设新闻标题在<h3 class="news-title">里,链接在里面的<a>标签 news_elements = await page.query_selector_all('h3.news-title a') for elem in news_elements: title = await elem.text_content() link = await elem.get_attribute('href') if title and link: # 处理相对链接 if link.startswith('/'): link = f"{page.url.rsplit('/', 1)[0]}{link}" items.append({'title': title.strip(), 'link': link}) return items if __name__ == "__main__": final_goal = "从某某新闻网站首页开始,找到‘科技’板块,提取前5条新闻的标题和链接,并保存。" start_url = "https://news.example.com" asyncio.run(run_ai_agent(start_url, final_goal))

这个简化版的AI助手已经具备了“感知-决策-执行”的闭环能力。你只需要告诉它最终目标,它就会尝试分析页面、点击导航到科技板块、滚动加载、识别新闻条目并提取数据。虽然这个示例在元素定位(click操作)上还很脆弱,但它清晰地展示了collaborator-ai/collab-public这类项目的核心思想。

4. 进阶挑战与优化策略

上面的基础实现仅仅是个开始。要打造一个真正鲁棒、可用的“数字同事”,我们还需要解决一系列工程挑战。

4.1 提升感知与定位的鲁棒性

基础实现中的click(description)是最大的弱点。依赖纯文本匹配在动态网页面前不堪一击。我们需要更健壮的元素定位策略:

  • 多模态定位:结合文本、角色(role)、位置、视觉特征(颜色、形状)来综合定位一个元素。例如,LLM可以输出:“点击那个在页面顶部、写着‘登录’的红色按钮。”
  • 可访问性属性优先:充分利用可访问性树中的nameroledescriptionvalue等属性,这些通常比可见文本更稳定。
  • CSS选择器/XPath生成:让LLM根据当前页面结构,生成一个更精确的CSS选择器或XPath,而不是依赖模糊文本。这需要感知模块提供更丰富的DOM结构信息。
  • 视觉定位兜底:对于无法通过可访问性信息定位的元素(如Canvas绘制的图形界面),可以回退到计算机视觉方案。例如,让LLM描述元素的大致位置和外观,然后通过图像匹配或目标检测来定位点击坐标。
  • 重试与备选策略:一次定位失败后,应有备用方案。例如,如果点击“下一页”按钮失败,可以尝试滚动到底部看看是否有“加载更多”,或者寻找分页器的其他表示形式。

4.2 让决策更可靠:提示工程与思维链

LLM的决策质量直接决定AI代理的智商。我们需要精心设计提示词(Prompt):

  • 提供详细的操作规范:在系统提示词中明确每个操作的确切含义、参数格式和边界条件。
  • 引入思维链(Chain-of-Thought):强制要求LLM在输出动作前,先输出“thought”字段,阐述它的推理过程。这不仅有助于调试,有时也能提高决策准确性。
  • 提供范例(Few-Shot Learning):在提示词中提供几个“当前状态 -> 正确动作”的示例,让LLM更好地理解任务。
  • 维护对话历史:将之前的交互(状态、动作、结果)也作为上下文提供给LLM,让它有“记忆”,避免重复操作或陷入死循环。
  • 设定操作边界:明确告诉LLM哪些区域不能操作(如地址栏、系统菜单),哪些操作需要特别确认(如文件删除、付款)。

4.3 复杂任务规划与子目标管理

对于“整理本周销售报告”这样的复杂任务,单次决策是不够的。我们需要引入更高级的**任务规划(Task Planning)**能力。

  • 分层任务分解(Hierarchical Task Decomposition):首先用一个“规划器”LLM,将顶层目标分解成一个有序的子任务列表(DAG,有向无环图)。例如:1. 打开邮箱;2. 筛选本周邮件;3. 下载附件;4. 打开Excel;5. 汇总数据;6. 生成图表。然后,主循环再针对每个子目标进行“感知-决策-执行”。
  • 子目标状态跟踪:系统需要维护一个任务栈或状态机,清楚当前正在执行哪个子任务,上一个子任务是否成功完成,以及整个任务的进度。
  • 异常处理与回退:当某个子任务失败(如找不到某个按钮)时,规划器应能评估是重试、尝试替代方案,还是向上级汇报失败并寻求新的任务分解策略。

4.4 技能库的扩展与安全调用

一个强大的AI代理离不开丰富的技能。我们需要一个安全、规范的技能调用机制。

  • 技能描述与注册:每个技能(如search_web,read_pdf,send_email)都应有一个清晰的自然语言描述、函数签名和权限要求。系统启动时,将这些描述注册到LLM的上下文中。
  • 安全沙箱:对于高风险技能(如执行系统命令、删除文件),必须在严格的沙箱环境中运行,或需要用户实时确认。
  • 工具调用(Function Calling):利用LLM原生的工具调用功能(如OpenAI的tools参数),让LLM直接输出结构化的函数调用请求,系统再安全地执行对应函数。这是目前最优雅的集成方式。
  • 技能组合:鼓励创建能组合现有技能的更高级技能。例如,compile_weekly_report技能内部可以调用gather_data_from_databasegenerate_chartformat_to_pdf等多个子技能。

5. 应用场景与未来展望

理解了collab-public的核心思想后,它的应用场景就非常广阔了:

  • 个人效率助手:自动处理日常琐事,如整理下载文件夹、归类照片、填写在线表格、预约会议。
  • 企业流程自动化:代替人工完成跨系统的数据录入、报表生成、客户信息更新、订单状态跟踪等RPA场景,且更智能、更抗变更。
  • 软件测试:AI可以模拟真实用户行为进行探索性测试,发现那些脚本测试覆盖不到的边缘用例和用户体验问题。
  • 无障碍辅助:为视障或行动不便的用户提供一个强大的“数字代理人”,通过语音指令操作一切电脑应用。
  • 教育与培训:创建交互式的软件操作教程,AI可以观察学员的操作并实时提供指导。

当然,这条路还很长。当前的挑战包括:长上下文的理解与规划能力多模态感知的准确性与速度复杂异常情况的处理、以及最重要的——安全与可控性。我们绝不能让一个拥有高权限的AI代理做出不可预测的危险行为。

因此,在拥抱这类技术时,一个务实的建议是:从封闭、明确、低风险的小场景开始。不要一开始就让它管理你的整个财务系统。可以从“每天帮我从A网站抓取天气数据存到B表格”这样的任务做起。在可控的环境下观察它的行为,逐步建立信任,并完善其安全护栏。

collaborator-ai/collab-public这类项目为我们勾勒了一个未来工作模式的蓝图。它不是一个要取代人类的工具,而是一个能放大我们能力的“杠杆”。将重复、繁琐的“操作”交给AI,让人更专注于需要创造力、策略和同理心的“思考”与“决策”。这个过程本身,也是对我们如何设计人机协作界面、如何让机器更好地理解人类意图的一次深刻探索。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/27 11:53:57

Windows安卓应用安装终极指南:APK Installer完全解析

Windows安卓应用安装终极指南&#xff1a;APK Installer完全解析 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 想在Windows电脑上直接运行Android应用吗&#xff1f;…

作者头像 李华
网站建设 2026/4/27 11:48:28

不止于起飞降落:用ROS话题和MAVROS深度操控你的PX4仿真无人机

不止于起飞降落&#xff1a;用ROS话题和MAVROS深度操控PX4仿真无人机 当你第一次看到Gazebo里的无人机成功起飞时&#xff0c;那种成就感就像看着自己组装的航模冲上蓝天。但很快你会发现&#xff0c;反复输入commander takeoff和commander land就像只会用开关控制电灯——我们…

作者头像 李华