先去瞅结果
输出需要:盘问北京气候,并画造为合线图。
智能体按照输出的需要,起首翻开浏览器会见相干的网页,当网页没法会见时,借会主动切换网页,最初,智能体将会把浏览器中汇集的数据保留收拾整顿为文献,并颠末编程的方法,颠末Python剧本画造合线图。
任务计划:
浏览网页:
编辑剧本:
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),供给跨浏览器的不合性尝试才气,保证使用正在差别情况下表示不合。其中心劣势正在于下可靠性战快速施行,颠末间接取浏览器引擎接互,制止了保守尝试东西的没有颠簸性成就。
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 能散成更多范例的东西,具有更强的持久影象战计划才气,并正在更庞大的场景中为用户供给端到真个处置计划。 |