开启左侧

我复刻了一个Manus

[复制链接]
先去瞅结果

输出需要:盘问北京气候,并画造为合线图。

智能体按照输出的需要,起首翻开浏览器会见相干的网页,当网页没法会见时,借会主动切换网页,最初,智能体将会把浏览器中汇集的数据保留收拾整顿为文献,并颠末编程的方法,颠末Python剧本画造合线图。

任务计划:

浏览网页:

尔复刻了一个Manusw2.jpg

编辑剧本:

尔复刻了一个Manusw3.jpg

Manus复刻思路

前端 (UI - HTML/CSS/JS): 用户接互的界里。咱们设想了一个单栏计划:

l  右栏:中心 对于话地区,展示用户取 Manus 的交换汗青,和 Manus 挪用东西的择要疑息(可面打接互)。

l  左栏: 左栏是对于Manus的电脑的模仿,能够展示Manus天生的文献、浏览网页等。

l  及时通信: 颠末 WebSocket 取后端连结少跟尾,完毕流式照应战形状革新。

后端 (API - FastAPI): 担当处置前端恳求,办理 WebSocket 跟尾,并动作前端取智能体中心的桥梁。它使用同步框架以撑持并收跟尾战流式处置。

LLM:使用DeepSeekV3动作中心的决议计划模子。并分离MCP完毕东西的挪用。

后端

MCP效劳端

全部过程当中一同需要二个MCP效劳:
{ "mcpServers": {    "playwright": {      "co妹妹and": "npx",      "args": ["@playwright/mcp@latest"]    },   "manus_server": {      "co妹妹and": "python",      "args": ["manus_server.py"]    }  }}

Playwright:

Playwright是一个由微硬开辟的现代化端到端尝试框架,博为Web使用尝试而设想。它撑持多种浏览器(包罗Chromium、Firefox战WebKit),供给跨浏览器的不合性尝试才气,保证使用正在差别情况下表示不合。其中心劣势正在于下可靠性战快速施行,颠末间接取浏览器引擎接互,制止了保守尝试东西的没有颠簸性成就。

尔复刻了一个Manusw4.jpg

Playwright 正在 LLM(狂言语模子)东西挪用中的使用主要体现在颠末其强大的浏览器主动化才气,为 LLM 供给了取网页接互的交心。Playwright MCP 是一个鉴于 Model Context Protocol(MCP)的效劳器,它使用 Playwright 的浏览器主动化才气,使 LLM 能够间接掌握浏览器,完毕翻开网页、面打元艳、输出笔墨等操纵。这类东西的中心劣势正在于快速、沉质,能天生构造化数据,无需依靠截图或者望觉模子。

Playwright MCP 撑持多种浏览器,如 Chromium、Firefox 战 WebKit,而且兼容多种编程语言,包罗 TypeScript、JavaScript、Python、.NET 战 Java。它供给了二种情势:默认的快照情势(Snapshot Mode)战望觉情势(Vision Mode),此中快照情势更适宜快速、下效的构造化数据接互。

manus_server:

因为Playwright中供给的东西其实不能完整满意智能体的需要,因而需要建立一点儿分外的MCP效劳,满意智能体的功用,因而,尔分外的建立了一个名为manus_server的MCP效劳,manus_server供给了上面多少个东西:

谷歌_search:搜刮相干跟尾

make_todo_md:创立方案文献

write_to_file:创立文献

execute_co妹妹and:施行指令

MCP客户端

客户端颠末上面的函数完毕中心的处置逻辑:
async def process_user_message(message: str, websocket: WebSocket):    """    那是中心处置函数,您需要正在那里散成您的 Agent 接互逻辑。   接纳 用户消息,挪用 Agent,并将成果颠末 WebSocket 发还前端。    """    try:        manus_agent.add_message(role='user', content=message)        await SendStatus("Manus 在处置...", websocket).send()        while True:            last_message_chunk = await generate_and_send_message_chunk(websocket, manus_agent.generate)            tool_executed = last_message_chunk.include_tool            if not tool_executed:                break            send_tool = SendTool(last_message_chunk, websocket)            await send_tool.send_tool()            result = await manus_agent.judge_and_execute(last_message_chunk)            await asyncio.sleep(0.5)            await send_tool.send_result()            manus_agent.add_message(role='system', content=result)        # ---完毕 ---        logging.info("Finished processing user message.")    except Exception as e:        logging.error(f"Error in agent logic: {e}", exc_info=True)        await websocket.send_text(json.dumps({"type": "error", "content": f"Agent处置 堕落: {e}"}))

Manus电脑的模仿

Manus电脑的模仿主要颠末docker完毕。

尔使用docker建立了一个docker容器,那个容器中包罗了一点儿Python运行的情况,以就能运行智能体编辑的Python代码。

docker容器中需要有一个路子取原机中的某个路子相绑定,二个路子中的文献是共步的,如许的设定能够便利后端获得智能体正在docker中天生的文献,进而展示文献的实质。
def get_or_create_docker_container(        container_name: str = CONTAINER_NAME,        image_name: str = 'python:3.12.10',        local_workspace_dir=DEFAULT_TASK_DIRECTORY,        container_workspace_dir: str | None = CONTAINER_WORKSPACE_DIR,        docker_client: docker.DockerClient | None = client,        keep_alive_co妹妹and: str = DEFAULT_KEEP_ALIVE_COMMAND,        auto_remove: bool = False  # Set to True to automatically remove container on exit (useful for temp tasks)):    client = docker_client    container = None    try:        # 1. Try to get the existing container        print(f"Checking for existing container '{container_name}'...")        container = client.containers.get(container_name)        print(f"Found existing container: {container.name} (ID: {container.short_id})")        # 2. Ensure the found container is running        if container.status != 'running':            print(f"Container '{container_name}' is not running (status: {container.status}). Starting...")            try:                container.start()                # Wait a moment for the container to fully start                time.sleep(2)                container.reload()  # Refresh container state                if container.status != 'running':                    # If start failed, raise an error                    logs = container.logs(tail=10).decode('utf-8', errors='ignore')                    raise RuntimeError(                        f"Failed to start existing container '{container_name}'. "                        f"Current status: {container.status}.\nLast logs:\n{logs}"                    )                print(f"Container '{container_name}' started successfully.")            except Exception as e:                print(f"ERROR: Unexpected error while starting container '{container_name}': {e}")                raise        else:            print(f"Container '{container_name}' is already running.")    except NotFound:        # 3. If container Not Found, create it        print(f"Container '{container_name}' not found. Creating new container...")        # Prepare volumes if specified        volumes = {}        if local_workspace_dir and container_workspace_dir:            host_path = Path(local_workspace_dir).resolve()  # Use absolute path            host_path.mkdir(parents=True, exist_ok=True)  # Ensure host dir exists            print(f"Ensuring local directory exists: {host_path}")            volumes[str(host_path)] = {'bind': container_workspace_dir, 'mode': 'rw'}            print(f"Mapping local '{host_path}' to container '{container_workspace_dir}'")        # Check/Pull Image        print(f"Checking/pulling image: {image_name}...")        client.images.get(image_name)        # Create and start the container        print(f"Creating and starting container '{container_name}' from image '{image_name}'...")        container_config = {            "image": image_name,            "name": container_name,            "co妹妹and": keep_alive_co妹妹and,            "volumes": volumes if volumes else None,            "working_dir": container_workspace_dir if container_workspace_dir else None,            "detach": True,            "tty": True,            "stdin_open": True,            "auto_remove": auto_remove,            # Add restart policy if desired, e.g., restart_policy={"Name": "unless-stopped"}        }        # Remove None values from config        container_config = {k: v for k, v in container_config.items() if v is not None}        container = client.containers.run(**container_config)        # Wait a moment and verify        time.sleep(2)        container.reload()        if container.status == 'running':            print(f"Successfully created and started container: {container.name} (ID: {container.short_id})")        else:            logs = container.logs(tail=10).decode('utf-8', errors='ignore')            raise RuntimeError(                f"Created container '{container_name}' failed to start. "                f"Current status: {container.status}.\nLast logs:\n{logs}"            )    # Final verification (should be redundant if logic above is correct, but safe)    if not container or container.status != 'running':        # This path should ideally not be reached if errors were raised correctly above        raise RuntimeError(f"Failed to obtain a running container instance for '{container_name}'.")    print(f"Container '{container.name}' is ready and running.")    print("-" * 30)    return container

智能体能够间接颠末号令止对于docker容器截至操纵,那段代码正在execute_co妹妹and东西的挪用中完毕。execute_co妹妹and东西将间接对于docker容器截至操纵。
@mcp.tool()def execute_co妹妹and(co妹妹and: str) -> str:    """施行号令并前去成果"""    workdir = CONTAINER_WORKSPACE_DIR    exit_code, output = container.exec_run(["/bin/sh", "-c", co妹妹and], workdir=workdir, stream=False, demux=False)    output_str = output.decode('utf-8').strip() if output else ""    return f"{output_str}"

建立Manus如许一个智能体尽非易事。Prompt 的强健性、庞大任务的计划才气、东西施行毛病的处置、多东西配合、和宁静性皆是需要连续加入的标的目的。

未来,咱们设想 Manus 能散成更多范例的东西,具有更强的持久影象战计划才气,并正在更庞大的场景中为用户供给端到真个处置计划。
您需要登录后才可以回帖 登录 | 立即注册 qq_login

本版积分规则

发布主题
阅读排行更多+
用专业创造成效
400-778-7781
周一至周五 9:00-18:00
意见反馈:server@mailiao.group
紧急联系:181-67184787
ftqrcode

扫一扫关注我们

Powered by 职贝云数A新零售门户 X3.5© 2004-2025 职贝云数 Inc.( 蜀ICP备2024104722号 )