专栏名称: Datawhale
一个专注于AI领域的开源组织,汇聚了众多顶尖院校和知名企业的优秀学习者,聚集了一群有开源精神和探索精神的团队成员。愿景-for the learner,和学习者一起成长。
目录
相关文章推荐
51好读  ›  专栏  ›  Datawhale

Manus开源复刻框架OWL,测评和使用教程来了!

Datawhale  · 公众号  ·  · 2025-03-09 22:47

正文

Datawhale干货
作者:孙韬,Datawhale鲸英助教

最近 AI 圈最炸的瓜,毫无疑问是—— Manus。

前天我们邀请了 OWL 和 OpenManus 团队为大家带来了 全网首个 Manus 开源复现直播 ,直播回放在视频号。

今天为大家带来 Manus 开源复刻框架 OWL 的实测体验及技术拆解。

Image

OWL 项目地址: https://github.com/camel-ai/owl

🦉 OWL 是什么?

🦉 OWL 是一个基于 CAMEL-AI 框架 https://github.com/camel-ai/camel )的多智能体协作的尖端框架,它突破了任务自动化的界限,在其官方的介绍中表示:

"我们的愿景是彻底改变 AI 代理协作解决实际任务的方式。通过利用动态代理交互,OWL 可以在不同领域实现更自然、更高效和更强大的任务自动化。"

目前 OWL 在 GAIA 基准测试中取得 58.18 平均分,在开源框架中排名第一。

Image

这里是一个演示 demo:

其实如果大家看过 Manus 的演示视频就可以发现,因为一些任务现在的大模型没有办法一次性全都处理完,Manus 在完成我们提出的问题的时候会首先对任务进行任务拆分,之后形成一个 TODO.md 用来记录自己已经完成的进度。

Image

在 OWL 中,也是类似的思想,OWL 整个流程基于 CAMEL 框架中 RolePlaying 方法,RolePlaying 是 CAMEL 框架的独特合作式智能体框架。该框架通过预定义的提示词为不同的智能体创建唯一的初始设置。

Image

在 RolePlaying 中 User 角色负责将讲任务拆解,并且每次给出一个指令到 Assistant 角色,Assistant 角色负责实施指令,在这个过程中 Assistant 角色可以使用各种我们给它配置好的工具,比如获取实时信息(如天气、新闻)的工具、计算的工具以及在 OWL 中定义的一些特定的工具(包括控制 web 页面的工具、处理文件、表格、图像等工具)。

Image

下面我们先来看一个 case,我的问题是 "帮我在小红书上找一些3.8女神节适合送妈妈的礼物" :

可以发现在运行过程中,我们的 agent 首先调用了 WebToolkit WebToolkit 实际上是一个封装了智能体的一个工具,其中包括一个 planning_agent 和一个 web_agent 。在浏览器模拟交互任务开始时, planning_agent 会首先给出一个详细的规划,这个规划之后会被用于指导 web_agent 选择具体的执行动作。

Image

那么我们的 agent 是怎么实现控制我们的浏览器的呢,首先任务明确之后,我们首先会跳转到一个网站,该网站是由 start_url 来决定的,该参数是可以由用户指定,也可以是 agent 在自我规划中提出的。跳转到网站之后,我们的 WebToolkit 会将当前的页面截图保存下来,并且给其中的元素都打上标签。

该步骤的实现方法如下:

1. 交互元素通过 JavaScript 脚本获取:

def get_interactive_elements(self) -> List[Dict[strAny]]:
    try:
        self.page.evaluate(self.page_script)
    except Exception as e:
        logger.warning(f"Error evaluating page script: {e}")
    
    result = cast(
        Dict[strDict[strAny]], self.page.evaluate("MultimodalWebSurfer.getInteractiveRects();")
    )
    
    typed_results: Dict[str, InteractiveRegion] = {}
    for k in result:
        typed_results[k] = interactiveregion_from_dict(result[k])

    return typed_results

2. add_set_of_mark 函数负责在截图上绘制标记:

def _add_set_of_mark(
    screenshot: Image.Image, ROIs: Dict[str, InteractiveRegion]
) -> Tuple[Image.Image, List[str], List[str], List[str]]:
    # ... 初始化代码 ...
    
    # 为每个交互区域绘制标记
    for idx, (identifier, region) in enumerate(ROIs.items()):
        for rect in region.rects:
            _draw_roi(draw, idx, font, rect)
             # ... 其他处理 ...
    
    # ... 返回结果 ...

3. _draw_roi 函数负责实际绘制:

def _draw_roi(
    draw: ImageDraw.ImageDraw, idx: int, font: ImageFont.FreeTypeFont | ImageFont.ImageFont, rect: DOMRectangle
) -> None:
    # 计算矩形坐标
    x, y = rect["x"], rect["y"]
    width, height = rect["width"], rect["height"]
    
    # 选择颜色
    color = _color(idx)
    
    # 绘制矩形边框
    draw.rectangle([(x, y), (x + width, y + height)], outline=color, width=2)
    
    # 绘制标签
    label = str(idx)
    text_width, text_height = font.getsize(label)
    
    # 确定标签位置
    label_x = x + width / 2 - text_width / 2
    label_y = max(y - text_height - 2, TOP_NO_LABEL_ZONE)
    
    # 绘制标签背景和文本
    draw.rectangle([(label_x - 2, label_y - 2), (label_x + text_width + 2, label_y + text_height + 2)], fill=color)
    draw.text((label_x, label_y), label, fill=(255255255255), font=font)

该函数会在元素周围绘制彩色矩形边框,为每个元素分配数字 ID 标签,最后在元素上方绘制带背景的标签,如下图所示。

Image

生成的带标签的页面(该页面存储在./tmp目录里)就是我们 web_agent 将要接收到图片输入啦,之后 web_agent 会根据图片和指令来进行下一步动作。要了解 web_agent 的工作逻辑,我们需要先了解一下 planning_agent 是如何工作的,下面是它的提示词:

planning_system_prompt = """
You are a helpful planning agent that can assist users in planning complex tasks which need multi-step browser interaction.
"""

这里定义了 planning_agent 的基本角色:一个帮助用户规划复杂任务的代理,专注于需要多步骤浏览器交互的任务。 planning_agent 在初始规划阶段使用以下提示:

planning_prompt = f"""
{task_prompt}
According to the problem above, if we use browser interaction, what is the general process of the interaction after visiting the webpage `{start_url}`? 

Please note that it can be viewed as Partially Observable MDP. Do not over-confident about your plan.
Please first restate the task in detail, and then provide a detailed plan to solve the task.
"""
    

这个提示要求 planning_agent

  • 重述任务
  • 提供详细的解决方案计划
  • 考虑部分可观察马尔可夫决策过程的特性(网页只能部分观察)

在任务执行过程中, planning_agent 可能需要根据新情况调整计划:

replanning_prompt = f"""
We are using browser interaction to solve a complex task which needs multi-step actions.
Here are the overall task:
{task_prompt}

In order to solve the task, we made a detailed plan previously. Here is the detailed plan:
{detailed_plan}

According to the task above, we have made a series of observations, reasonings, and actions. Here are the latest {self.history_window} trajectory (at most) we have taken:
{self.history[-self.history_window:]}

However, the task is not completed yet. As the task is partially observable, we may need to replan the task based on the current state of the browser if necessary.
Now please carefully examine the current task planning schema, and our history actions, and then judge whether the task needs to be fundamentally replanned. If so, please provide a detailed replanned schema (including the restated overall task).

Your output should be in json format, including the following fields:
- `if_need_replan`: bool, A boolean value indicating whether the task needs to be fundamentally replanned.
- `replanned_schema`: str, The replanned schema for the task, which should not be changed too much compared with the original one. If the task does not need to be replanned, the value should be an empty string. 
"""

其中 {task_prompt} 就是我们提供的原始任务输入: "帮我在小红书上找一些3.8女神节适合送妈妈的礼物"

{detailed_plan} 则是上一次生成的规划内容, {self.history_window} 默认为5,也就是说 planning_agent 会动态地结合最近地一些信息来进行下一步规划。在prompt中要求了 planning_agent 要使用结构化的输出。生成的规划内容会传输给 web_agent 来帮助它完成任务

接下来,我们可以来看一下 web_agent 的提示词来进一步了解它的工作逻辑。

system_prompt = """
You are a helpful web agent that can assist users in browsing the web.
Given a high-level task, you can leverage predefined browser tools to help users achieve their goals.
"""

使用一个简洁的系统提示定义了 web_agent 的基本角色:一个帮助用户浏览网页的代理,能够利用预定义的浏览器工具完成用户目标。

之后如果 agent 认为需要进行操作电脑,就使用我们给它配备的 browser_simulation 方法,该方法会循环地去观察我们的网页, web_agent 在每次观察网页时会收到以下格式的提示:

observe_prompt =f"""
Please act as a web agent to help me complete the following high-level task:{task_prompt}
Now,Ihavemadescreenshot(onlythecurrentviewport,notthefullwebpage)basedonthecurrentbrowserstate,andmarkedinteractiveelementsinthewebpage.
Pleasecarefullyexaminetherequirementsofthetask,andcurrentstateofthebrowser,andprovidethenextappropriateactionto take.

{detailed_plan_prompt}

Here are the current available browser functions you can use:
{AVAILABLE_ACTIONS_PROMPT}

Herearethelatest {self.history_windowtrajectory (at most) you have taken:

{self.history[-self.history_window:]}


Youroutputshouldbeinjsonformat,including the following fields:
-`observation`:Thedetailedimagedescriptionaboutthecurrentviewport.Donotover-confidentaboutthecorrectnessofthehistoryactions.Youshouldalwayscheckthecurrentviewporttomakesurethecorrectnessofthenextaction.
-`reasoning`:Thereasoningaboutthenextactionyouwanttotake,andthepossibleobstaclesyoumayencounter,andhowtosolvethem.Donotforgettocheckthehistoryactionstoavoidthesamemistakes.
-`action_code`:Theactioncodeyouwanttotake.Itisonlyonestepactioncode,withoutanyothertexts(suchasannotation)

Here are an example of the output:
```json
{{
    "observation": [IMAGE_DESCRIPTION],
    "reasoning": [YOUR_REASONING],
    "action_code":`fill_input_id([ID], [TEXT])`
}}

Here are some tips for you:
-Never forget the overall question:**{task_prompt}**
-Maybeafteracertainoperation(e.g.click_id),thepagecontenthasnotchanged.Youcancheckwhethertheactionstepissuccessfulbylookingatthe`success`oftheactionstepinthehistory.Ifsuccessful,itmeansthatthepagecontentisindeedthesameaftertheclick.Youneedtotryothermethods.
-Ifusingonewaytosolvetheproblemisnotsuccessful,tryotherways.MakesureyourprovidedIDiscorrect!
-Somecasesareverycomplexandneedtobeachievebyaniterativeprocess.Youcanusethe`back()`functiontogobacktothepreviouspagetotryothermethods.
-Therearemanylinksonthepage,whichmaybeusefulforsolvingtheproblem.Youcanusethe`click_id()`functiontoclickonthelinktoseeifitisuseful.
-AlwayskeepinmindthatyouractionmustbebasedontheIDshowninthecurrentimageorviewport,nottheIDshowninthehistory.
-Donotuse`stop()`lightly.Alwaysremindyourselfthattheimageonlyshowsapartofthefullpage.Ifyoucannotfindtheanswer,trytousefunctionslike`scroll_up()`and`scroll_down()`tocheckthefullcontentofthewebpagebeforedoinganythingelse,becausetheanswerornextkeystepmaybehiddeninthecontentbelow.
-Ifthewebpageneedshumanverification,youmustavoidprocessingit.Pleaseuse`back()`togobacktothepreviouspage,andtryotherways.
-Ifyouhavetriedeverythingandstillcannotresolvetheissue,pleasestopthesimulation,andreportissuesyouhaveencountered.
-Checkthehistoryactionscarefully,detectwhetheryouhaverepeatedlymadethesameactionsornot.
-Whendealingwithwikipediarevisionhistoryrelatedtasks,youneedtothinkaboutthesolutionflexibly.First,adjustthebrowsinghistorydisplayedonasinglepagetothemaximum,andthenmake






请到「今天看啥」查看全文