前言
在 Agentic AI 時代,智能體需要與真實世界交互,而瀏覽器是連接虛擬世界與現實世界的重要橋樑。AgentRun Browser Sandbox 為智能體提供了安全、高性能、免運維的瀏覽器執行環境,讓 AI Agent 真正具備"上網"的能力——從網頁抓取、信息提取到表單填寫、自動化操作,一切皆可實現。
AgentRun Browser Sandbox 介紹
什麼是 Browser Sandbox?
Browser Sandbox 是 AgentRun 平台提供的雲原生無頭瀏覽器沙箱服務,基於阿里雲函數計算(FC)構建。它為智能體提供了一個安全隔離的瀏覽器執行環境,支持通過標準的 Chrome DevTools Protocol (CDP) 遠程控制瀏覽器實例。
核心特性
無頭瀏覽器能力
- 內置 Chromium/Chrome 瀏覽器,支持完整的 Web 標準
- 原生兼容 Puppeteer、Playwright 等主流自動化框架
- 支持通過 CDP 協議進行精細化控制
實時可視化
- 內置 VNC 服務,支持實時查看瀏覽器界面
- 提供操作錄製功能,方便調試和回放
- 支持通過 noVNC 客户端在網頁中直接觀看
安全與隔離
- 每個沙箱實例運行在獨立的容器環境中
- 文件系統和進程空間完全隔離
- 支持 WSS 加密傳輸,確保數據安全
Serverless 架構
- 按需創建,按量付費,無需提前預置資源
- 快速彈性伸縮,支持高併發場景
- 零運維,無需管理服務器和瀏覽器依賴
主要應用場景
- AI Agent 賦能: 為大模型提供"眼睛"和"手",執行網頁瀏覽、信息提取、在線操作等任務
- 自動化測試: 在雲端運行端到端(E2E)測試和視覺迴歸測試
- 數據採集: 穩定、高效地進行網頁抓取,應對動態加載和反爬蟲挑戰
- 內容生成: 自動化生成網頁截圖或 PDF 文檔
上手使用 Agentrun Browser Sandbox
AgentRun SDK 快速介紹
後續的內容將基於 Agentrun SDK 進行,因此我們先對 SDK 進行簡要介紹
AgentRun SDK 是一個開源的 Python 工具包,旨在簡化智能體與 AgentRun 平台各種服務(包括 Browser Sandbox)的集成。它提供了統一的接口,讓您可以用幾行代碼就將沙箱能力集成到現有的 Agent 框架中。SDK 的核心功能如下:
統一集成接口
- 提供對 LangChain、AgentScope 等主流框架的開箱即用支持
- 統一的模型代理接口,簡化多模型管理
- 標準化的工具註冊機制
Sandbox 生命週期管理
- 自動創建和銷燬沙箱實例
- 支持會話級別的狀態保持
- 靈活的資源配置和超時控制
安裝 AgentRun SDK
pip install agentrun-sdk[playwright,server]
注意: 確保您的 Python 環境版本在 3.10 及以上。
基本使用示例
以下是使用 AgentRun SDK 創建和管理 Browser Sandbox 的核心代碼:
from agentrun.sandbox import Sandbox, TemplateType
from playwright.sync_api import sync_playwright
# 創建 Browser Sandbox
sandbox = Sandbox.create(
template_type=TemplateType.BROWSER,
template_name="your-template-name",
sandbox_idle_timeout_seconds=300
)
# 獲取 CDP URL(用於 Playwright 連接)
cdp_url = sandbox.get_cdp_url()
# 使用 Playwright 連接並操作
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(cdp_url)
page = browser.contexts[0].pages[0]
page.goto("https://www.example.com")
page.screenshot(path="screenshot.png")
browser.close()
# 銷燬 Sandbox
sandbox.delete()
關鍵概念:
- template_name: 控制枱創建的瀏覽器環境模板
- cdp_url: 用於 Playwright/Puppeteer 連接
- vnc_url: 用於實時查看瀏覽器畫面(可通過
sandbox.get_cdp_url()獲取)
注意: 由於所有瀏覽器操作都在雲端進行,您無需在本地安裝瀏覽器。Playwright 僅用於通過 CDP 協議連接到雲端的瀏覽器實例。
如何創建 sandbox 模板
使用 Browser Sandbox 需要新建 Sandbox 模板,您需要訪問 Agentrun 控制枱網站,並按照如下步驟創建模板:
- 在頂部菜單欄選擇“運行時與沙箱”;
- 在左側邊欄選擇“Sandbox沙箱”;
- 點擊右上角“創建沙箱模板”;
- 選擇“瀏覽器”;

- 在彈出的抽屜對話框中填寫和選擇您的模板的規格、網絡等配置,並複製模板名稱;
6. 點擊“創建瀏覽器” 等待其就緒即可。
從零開始用 LangChain 創建 Browser Sandbox 智能體
本教程將指導您從零開始創建一個完整的 Browser Sandbox 智能體項目。
基於 LangChain 集成 Browser Sandbox
本教程將詳細講解如何使用 LangChain 創建 Browser Sandbox 相關的 tools 並集成到 Agent 中。
項目結構
為了保持代碼的內聚性和可維護性,我們將代碼拆分為以下模塊:
模塊職責劃分:
- sandbox_manager.py: 負責 Sandbox 的創建、管理和銷燬,提供統一的接口
- langchain_agent.py: 負責創建 LangChain tools 和 Agent,集成 VNC 信息
- main.py: 作為入口文件,演示如何使用上述模塊
步驟 1: 創建項目並安裝依賴
首先創建項目目錄(如果還沒有):
mkdir -p langchain-demo
cd langchain-demo
創建 requirements.txt 文件,內容如下:
# LangChain 核心庫
langchain>=0.1.0
langchain-openai>=0.0.5
langchain-community>=0.0.20
# AgentRun SDK
agentrun-sdk[playwright,server]>=0.0.8
# 瀏覽器自動化
playwright>=1.40.0
# 環境變量管理
python-dotenv>=1.0.0
然後安裝依賴:
pip install -r requirements.txt
主要依賴説明:
- langchain 和 langchain-openai: LangChain 核心庫
- agentrun-sdk[playwright,server]: AgentRun SDK,用於 Sandbox 管理
- playwright: 瀏覽器自動化庫 python-dotenv: 環境變量管理
步驟 2: 配置環境變量
在項目根目錄創建 .env 文件,配置以下環境變量:
# 阿里雲百鍊平台的 API Key,用於調用大模型能力
# 請前往 https://bailian.console.aliyun.com/?tab=app#/api-key 創建和查看
DASHSCOPE_API_KEY=sk-your-bailian-api-key
# 阿里雲賬號的訪問密鑰 ID 和訪問密鑰 Secret,用於 AgentRun SDK 鑑權
ALIBABA_CLOUD_ACCESS_KEY_ID=your-ak
ALIBABA_CLOUD_ACCESS_KEY_SECRET=your-sk
ALIBABA_CLOUD_ACCOUNT_ID=your-main-account-id
ALIBABA_CLOUD_REGION=cn-hangzhou
# browser sandbox 模板的名稱,可以在 https://functionai.console.aliyun.com/cn-hangzhou/agent/runtime/sandbox 控制枱創建
BROWSER_TEMPLATE_NAME=sandbox-your-template-name
# agentrun 的控制面和數據面的 API 端點請求地址,默認cn-hangzhou
AGENTRUN_CONTROL_ENDPOINT=agentrun.cn-hangzhou.aliyuncs.com
AGENTRUN_DATA_ENDPOINT=https://${your-main-account-id}.agentrun-data.cn-hangzhou.aliyuncs.com
步驟 3: 創建 Sandbox 生命週期管理模塊
創建 sandbox_manager.py 文件,負責 Sandbox 的創建、管理和銷燬。核心代碼如下:
"""
Sandbox 生命週期管理模塊
負責 AgentRun Browser Sandbox 的創建、管理和銷燬。
提供統一的接口供 LangChain Agent 使用。
"""
import os
from typing import Optional, Dict, Any
from dotenv import load_dotenv
# 加載環境變量
load_dotenv()
class SandboxManager:
"""Sandbox 生命週期管理器"""
def __init__(self):
self._sandbox: Optional[Any] = None
self._sandbox_id: Optional[str] = None
self._cdp_url: Optional[str] = None
self._vnc_url: Optional[str] = None
def create(
self,
template_name: Optional[str] = None,
idle_timeout: int = 3000
) -> Dict[str, Any]:
"""
創建或獲取一個瀏覽器 sandbox 實例
Args:
template_name: Sandbox 模板名稱,如果為 None 則從環境變量讀取
idle_timeout: 空閒超時時間(秒),默認 3000 秒
Returns:
dict: 包含 sandbox_id, cdp_url, vnc_url 的字典
Raises:
RuntimeError: 創建失敗時拋出異常
"""
try:
from agentrun.sandbox import Sandbox, TemplateType
# 如果已有 sandbox,直接返回
if self._sandbox is not None:
return self.get_info()
# 從環境變量獲取模板名稱
if template_name is None:
template_name = os.getenv(
"BROWSER_TEMPLATE_NAME",
"sandbox-browser-demo"
)
# 創建 sandbox
self._sandbox = Sandbox.create(
template_type=TemplateType.BROWSER,
template_name=template_name,
sandbox_idle_timeout_seconds=idle_timeout
)
self._sandbox_id = self._sandbox.sandbox_id
self._cdp_url = self._get_cdp_url()
self._vnc_url = self._get_vnc_url()
return self.get_info()
except ImportError as e:
print(e)
raise RuntimeError(
"agentrun-sdk 未安裝,請運行: pip install agentrun-sdk[playwright,server]"
)
except Exception as e:
raise RuntimeError(f"創建 Sandbox 失敗: {str(e)}")
def get_info(self) -> Dict[str, Any]:
"""
獲取當前 sandbox 的信息
Returns:
dict: 包含 sandbox_id, cdp_url, vnc_url 的字典
Raises:
RuntimeError: 如果沒有活動的 sandbox
"""
if self._sandbox is None:
raise RuntimeError("沒有活動的 sandbox,請先創建")
return {
"sandbox_id": self._sandbox_id,
"cdp_url": self._cdp_url,
"vnc_url": self._vnc_url,
}
def get_cdp_url(self) -> Optional[str]:
"""獲取 CDP URL"""
return self._sandbox.get_cdp_url()
def get_vnc_url(self) -> Optional[str]:
"""獲取 VNC URL"""
return self._sandbox.get_vnc_url()
def get_sandbox_id(self) -> Optional[str]:
"""獲取 Sandbox ID"""
return self._sandbox_id
def destroy(self) -> str:
"""
銷燬當前的 sandbox 實例
Returns:
str: 操作結果描述
"""
if self._sandbox is None:
return "沒有活動的 sandbox"
try:
sandbox_id = self._sandbox_id
# 嘗試銷燬 sandbox
if hasattr(self._sandbox, 'delete'):
self._sandbox.delete()
elif hasattr(self._sandbox, 'stop'):
self._sandbox.stop()
elif hasattr(self._sandbox, 'destroy'):
self._sandbox.destroy()
# 清理狀態
self._sandbox = None
self._sandbox_id = None
self._cdp_url = None
self._vnc_url = None
return f"Sandbox 已銷燬: {sandbox_id}"
except Exception as e:
# 即使銷燬失敗,也清理本地狀態
self._sandbox = None
self._sandbox_id = None
self._cdp_url = None
self._vnc_url = None
return f"銷燬 Sandbox 時出錯: {str(e)}"
def is_active(self) -> bool:
"""檢查 sandbox 是否活躍"""
return self._sandbox is not None
def __enter__(self):
"""上下文管理器入口"""
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""上下文管理器退出,自動銷燬"""
self.destroy()
return False
# 全局單例(可選,用於簡單場景)
_global_manager: Optional[SandboxManager] = None
def get_global_manager() -> SandboxManager:
"""獲取全局 SandboxManager 單例"""
global _global_manager
if _global_manager is None:
_global_manager = SandboxManager()
return _global_manager
def reset_global_manager():
"""重置全局 SandboxManager"""
global _global_manager
if _global_manager:
_global_manager.destroy()
_global_manager = None
關鍵功能:
- 創建 Sandbox: 使用 AgentRun SDK 創建瀏覽器 Sandbox
- 獲取連接信息: 自動獲取 CDP URL 和 VNC URL,支持多種屬性名兼容
- 生命週期管理: 提供銷燬方法,確保資源正確釋放
步驟 4: 創建 LangChain Tools 和 Agent
創建 langchain_agent.py 文件,定義 LangChain tools 並創建 Agent。核心代碼如下:
"""
LangChain Agent 和 Tools 註冊模塊
負責創建 LangChain Agent,註冊 Sandbox 相關的 tools,並集成 VNC 可視化。
本模塊使用 sandbox_manager.py 中封裝的 SandboxManager 來管理 sandbox 生命週期。
"""
import os
from dotenv import load_dotenv
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
from pydantic import BaseModel, Field
# 導入 sandbox 管理器
from sandbox_manager import SandboxManager
# 加載環境變量
load_dotenv()
# 全局 sandbox 管理器實例(單例模式)
_sandbox_manager: SandboxManager | None = None
def get_sandbox_manager() -> SandboxManager:
"""獲取 sandbox 管理器實例(單例模式)"""
global _sandbox_manager
if _sandbox_manager is None:
_sandbox_manager = SandboxManager()
return _sandbox_manager
# ============ LangChain Tools 定義 ============
@tool
def create_browser_sandbox(
template_name: str = None,
idle_timeout: int = 3000
) -> str:
"""創建或獲取一個瀏覽器 sandbox 實例。
當需要訪問網頁、執行瀏覽器操作時,首先需要創建 sandbox。
創建成功後,會返回 sandbox 信息,包括 VNC URL 用於可視化。
Args:
template_name: Sandbox 模板名稱,如果不提供則從環境變量 BROWSER_TEMPLATE_NAME 讀取
idle_timeout: 空閒超時時間(秒),默認 3000 秒
Returns:
Sandbox 信息字符串,包括 ID、CDP URL、VNC URL
"""
try:
manager = get_sandbox_manager()
# 如果 template_name 為空字符串,轉換為 None 以便從環境變量讀取
if template_name == "":
template_name = None
info = manager.create(template_name=template_name, idle_timeout=idle_timeout)
result = f"""✅ Sandbox 創建成功!
📋 Sandbox 信息:
- ID: {info['sandbox_id']}
- CDP URL: {info['cdp_url']}
"""
vnc_url = info.get('vnc_url')
if vnc_url:
result += f"- VNC URL: {vnc_url}\n\n"
result += "提示: VNC 查看器應該已自動打開,您可以在瀏覽器中實時查看瀏覽器操作。"
else:
result += "\n警告: 未獲取到 VNC URL,可能無法使用可視化功能。"
return result
except Exception as e:
return f" 創建 Sandbox 失敗: {str(e)}"
@tool
def get_sandbox_info() -> str:
"""獲取當前 sandbox 的詳細信息,包括 ID、CDP URL、VNC URL 等。
當需要查看當前 sandbox 狀態或獲取 VNC 連接信息時使用此工具。
Returns:
Sandbox 信息字符串
"""
try:
manager = get_sandbox_manager()
info = manager.get_info()
result = f"""📋 當前 Sandbox 信息:
- Sandbox ID: {info['sandbox_id']}
- CDP URL: {info['cdp_url']}
"""
if info.get('vnc_url'):
result += f"- VNC URL: {info['vnc_url']}\n\n"
result += "您可以使用 VNC URL 在瀏覽器中實時查看操作過程。\n"
result += " 推薦使用 vnc.html 文件或 noVNC 客户端。"
return result
except RuntimeError as e:
return f" {str(e)}"
except Exception as e:
return f" 獲取 Sandbox 信息失敗: {str(e)}"
class NavigateInput(BaseModel):
"""瀏覽器導航輸入參數"""
url: str = Field(description="要訪問的網頁 URL,必須以 http:// 或 https:// 開頭")
wait_until: str = Field(
default="load",
description="等待頁面加載的狀態: load, domcontentloaded, networkidle"
)
timeout: int = Field(
default=30000,
description="超時時間(毫秒),默認 30000"
)
@tool(args_schema=NavigateInput)
def navigate_to_url(url: str, wait_until: str = "load", timeout: int = 30000) -> str:
"""使用 sandbox 中的瀏覽器導航到指定 URL。
當用户需要訪問網頁時使用此工具。導航後可以在 VNC 中實時查看頁面。
Args:
url: 要訪問的網頁 URL
wait_until: 等待頁面加載的狀態(load/domcontentloaded/networkidle)
timeout: 超時時間(毫秒)
Returns:
導航結果描述
"""
try:
manager = get_sandbox_manager()
if not manager.is_active():
return " 錯誤: 請先創建 sandbox"
# 驗證 URL
if not url.startswith(("http://", "https://")):
return f" 錯誤: 無效的 URL 格式: {url}"
cdp_url = manager.get_cdp_url()
if not cdp_url:
return " 錯誤: 無法獲取 CDP URL"
# 使用 Playwright 連接瀏覽器並導航
try:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(cdp_url)
pages = browser.contexts[0].pages if browser.contexts else []
if pages:
page = pages[0]
else:
page = browser.new_page()
page.goto(url, wait_until=wait_until, timeout=timeout)
title = page.title()
return f"已成功導航到: {url}\n📄 頁面標題: {title}\n💡 您可以在 VNC 中查看頁面內容。"
except ImportError:
return f"導航指令已發送: {url}\n💡 提示: 安裝 playwright 以啓用實際導航功能 (pip install playwright)"
except Exception as e:
return f" 導航失敗: {str(e)}"
except Exception as e:
return f" 操作失敗: {str(e)}"
@tool("browser_screenshot", description="在瀏覽器 sandbox 中截取當前頁面截圖")
def take_screenshot(filename: str = "screenshot.png") -> str:
"""截取瀏覽器當前頁面的截圖。
Args:
filename: 截圖文件名,默認 "screenshot.png"
Returns:
操作結果
"""
try:
manager = get_sandbox_manager()
if not manager.is_active():
return " 錯誤: 請先創建 sandbox"
cdp_url = manager.get_cdp_url()
if not cdp_url:
return " 錯誤: 無法獲取 CDP URL"
try:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(cdp_url)
pages = browser.contexts[0].pages if browser.contexts else []
if pages:
page = pages[0]
else:
return " 錯誤: 沒有打開的頁面"
page.screenshot(path=filename)
return f"截圖已保存: {filename}"
except ImportError:
return " 錯誤: 需要安裝 playwright (pip install playwright)"
except Exception as e:
return f" 截圖失敗: {str(e)}"
except Exception as e:
return f" 操作失敗: {str(e)}"
@tool("destroy_sandbox", description="銷燬當前的 sandbox 實例,釋放資源。注意:僅在程序退出或明確需要釋放資源時使用,不要在一輪對話後銷燬。")
def destroy_sandbox() -> str:
"""銷燬當前的 sandbox 實例。
重要提示:此工具應該僅在以下情況使用:
- 程序即將退出
- 明確需要釋放資源
- 用户明確要求銷燬
不要在一輪對話完成後就銷燬 sandbox,因為 sandbox 可以在多輪對話中複用。
Returns:
操作結果
"""
try:
manager = get_sandbox_manager()
result = manager.destroy()
return result
except Exception as e:
return f" 銷燬失敗: {str(e)}"
# ============ Agent 創建 ============
def create_browser_agent(system_prompt: str = None):
"""
創建帶有 sandbox 工具的 LangChain Agent
Args:
system_prompt: 自定義系統提示詞,如果為 None 則使用默認提示詞
Returns:
LangChain Agent 實例
"""
# 配置 DashScope API
api_key = os.getenv("DASHSCOPE_API_KEY")
if not api_key:
raise ValueError("請設置環境變量 DASHSCOPE_API_KEY")
base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
model_name = os.getenv("QWEN_MODEL", "qwen-plus")
# 創建 LLM
model = ChatOpenAI(
model=model_name,
api_key=api_key,
base_url=base_url,
temperature=0.7,
)
# 創建工具列表
tools = [
create_browser_sandbox,
get_sandbox_info,
navigate_to_url,
take_screenshot,
destroy_sandbox,
]
# 默認系統提示詞
if system_prompt is None:
system_prompt = """你是一個瀏覽器自動化助手,可以使用 sandbox 來訪問和操作網頁。
當用户需要訪問網頁時,請按以下步驟操作:
1. 首先創建或獲取 sandbox(如果還沒有)
2. 使用 navigate_to_url 導航到目標網頁
3. 執行用户請求的操作
4. 如果需要,可以截取截圖
重要提示:
- 創建 sandbox 後,會返回 VNC URL,用户可以使用它實時查看瀏覽器操作
- 所有操作都會在 VNC 中實時顯示,方便調試和監控
- sandbox 可以在多輪對話中複用,不要在一輪對話完成後就銷燬
- 只有在用户明確要求銷燬時才使用 destroy_sandbox 工具
- 不要主動建議用户銷燬 sandbox,除非用户明確要求
- 請始終用中文回覆,確保操作準確、高效。"""
# 創建 Agent
agent = create_agent(
model=model,
tools=tools,
system_prompt=system_prompt,
)
return agent
def get_available_tools():
"""獲取所有可用的工具列表"""
return [
create_browser_sandbox,
get_sandbox_info,
navigate_to_url,
take_screenshot,
destroy_sandbox,
]
關鍵要點:
- Tool 定義: 使用
@tool裝飾器定義 LangChain tools - 類型提示: 所有參數必須有類型提示,用於生成工具 schema
- 文檔字符串: 詳細的文檔字符串幫助 LLM 理解何時使用工具
- 單例模式: 使用全局管理器實例確保 Sandbox 在會話中複用
步驟 5: 創建主入口文件
創建 main.py 文件,作為程序入口。核心代碼如下:
"""
LangChain + AgentRun Browser Sandbox 集成示例
主入口文件,演示如何使用 LangChain Agent 與 AgentRun Browser Sandbox 集成。
"""
import os
import sys
import signal
import webbrowser
import urllib.parse
import threading
import http.server
import socketserver
from pathlib import Path
from dotenv import load_dotenv
from langchain_agent import create_browser_agent, get_sandbox_manager
# 加載環境變量
load_dotenv()
# 全局 HTTP 服務器實例
_http_server = None
_http_port = 8080
# 全局清理標誌,用於防止重複清理
_cleanup_done = False
def start_http_server():
"""啓動一個簡單的 HTTP 服務器來提供 vnc.html"""
global _http_server
if _http_server is not None:
return _http_port
try:
current_dir = Path(__file__).parent.absolute()
class VNCRequestHandler(http.server.SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=str(current_dir), **kwargs)
def log_message(self, format, *args):
# 靜默日誌,避免輸出過多信息
pass
# 嘗試啓動服務器
for port in range(_http_port, _http_port + 10):
try:
server = socketserver.TCPServer(("", port), VNCRequestHandler)
server.allow_reuse_address = True
# 在後台線程中運行服務器
def run_server():
server.serve_forever()
thread = threading.Thread(target=run_server, daemon=True)
thread.start()
_http_server = server
return port
except OSError:
continue
return None
except Exception as e:
print(f"啓動 HTTP 服務器失敗: {str(e)}")
return None
def open_vnc_viewer(vnc_url: str):
"""
自動打開 VNC 查看器並設置 VNC URL
Args:
vnc_url: VNC WebSocket URL
"""
if not vnc_url:
return
try:
# 獲取當前文件所在目錄
current_dir = Path(__file__).parent.absolute()
vnc_html_path = current_dir / "vnc.html"
# 檢查文件是否存在
if not vnc_html_path.exists():
print(f"警告: vnc.html 文件不存在: {vnc_html_path}")
print_vnc_info(vnc_url)
return
# 啓動 HTTP 服務器
port = start_http_server()
if port:
# 編碼 VNC URL 作為 URL 參數
encoded_url = urllib.parse.quote(vnc_url, safe='')
# 構建 HTTP URL
http_url = f"http://localhost:{port}/vnc.html?url={encoded_url}"
# 打開瀏覽器
print(f"\n正在打開 VNC 查看器...")
print(f"HTTP 服務器運行在: http://localhost:{port}")
print(f"VNC URL: {vnc_url[:80]}...")
print(f"完整 URL: {http_url[:100]}...")
webbrowser.open(http_url)
print(f"VNC 查看器已打開")
print(f"VNC URL 已通過 URL 參數自動設置,頁面加載後會自動連接")
else:
# 如果 HTTP 服務器啓動失敗,嘗試使用 file:// 協議
print(f"HTTP 服務器啓動失敗,嘗試使用文件協議...")
encoded_url = urllib.parse.quote(vnc_url, safe='')
file_url = f"file://{vnc_html_path}?url={encoded_url}"
webbrowser.open(file_url)
print(f"VNC 查看器已打開(使用文件協議)")
print(f"提示: 如果無法自動連接,請手動複製 VNC URL 到輸入框")
except Exception as e:
print(f"自動打開 VNC 查看器失敗: {str(e)}")
print_vnc_info(vnc_url)
def print_vnc_info(vnc_url: str):
"""打印 VNC 連接信息"""
if not vnc_url:
return
print("\n" + "=" * 60)
print("VNC 可視化連接信息")
print("=" * 60)
print(f"\nVNC URL: {vnc_url}")
print("\n使用方式:")
print(" 1. 使用 noVNC 客户端連接")
print(" 2. 或在瀏覽器中訪問 VNC 查看器頁面")
print(" 3. 實時查看瀏覽器操作過程")
print("\n" + "=" * 60 + "\n")
def cleanup_sandbox():
"""
清理 sandbox 資源
這個函數可以被信號處理器、異常處理器和正常退出流程調用
"""
global _cleanup_done
# 防止重複清理
if _cleanup_done:
return
_cleanup_done = True
try:
manager = get_sandbox_manager()
if manager.is_active():
print("\n" + "=" * 60)
print("正在清理 sandbox...")
print("=" * 60)
result = manager.destroy()
print(f"清理結果: {result}\n")
else:
print("\n沒有活動的 sandbox 需要清理\n")
except Exception as e:
print(f"\n清理 sandbox 時出錯: {str(e)}\n")
def signal_handler(signum, frame):
"""
信號處理器,處理 Ctrl+C (SIGINT) 和其他信號
Args:
signum: 信號編號
frame: 當前堆棧幀
"""
print("\n\n收到中斷信號,正在清理資源...")
cleanup_sandbox()
print("清理完成")
sys.exit(0)
def main():
"""主函數"""
global _cleanup_done
# 重置清理標誌
_cleanup_done = False
# 註冊信號處理器,處理 Ctrl+C (SIGINT)
signal.signal(signal.SIGINT, signal_handler)
# 在 Windows 上,SIGBREAK 也可以處理
if hasattr(signal, 'SIGBREAK'):
signal.signal(signal.SIGBREAK, signal_handler)
print("=" * 60)
print("LangChain + AgentRun Browser Sandbox 集成示例")
print("=" * 60)
print()
try:
# 創建 Agent
print("正在初始化 LangChain Agent...")
agent = create_browser_agent()
print("Agent 初始化完成\n")
# 示例查詢
queries = [
"創建一個瀏覽器 sandbox",
"獲取當前 sandbox 的信息,包括 VNC URL",
"導航到 https://www.aliyun.com",
"截取當前頁面截圖",
]
# 執行查詢
for i, query in enumerate(queries, 1):
print(f"\n{'=' * 60}")
print(f"查詢 {i}: {query}")
print(f"{'=' * 60}\n")
try:
result = agent.invoke({
"messages": [{"role": "user", "content": query}]
})
# 提取最後一條消息的內容
output = result.get("messages", [])[-1].content if isinstance(result.get("messages"), list) else result.get("output", str(result))
print(f"\n結果:\n{output}\n")
# 如果是創建 sandbox,自動打開 VNC 查看器
if i == 1:
try:
# 等待一下確保 sandbox 完全創建
import time
time.sleep(1)
manager = get_sandbox_manager()
if manager.is_active():
info = manager.get_info()
vnc_url = info.get('vnc_url')
if vnc_url:
print(f"\n檢測到 VNC URL: {vnc_url[:80]}...")
open_vnc_viewer(vnc_url)
print_vnc_info(vnc_url)
else:
print("\n警告: 未獲取到 VNC URL,請檢查 sandbox 創建是否成功")
except Exception as e:
print(f"打開 VNC 查看器時出錯: {str(e)}")
import traceback
traceback.print_exc()
# 如果是獲取信息,顯示 VNC 信息
elif i == 2:
try:
manager = get_sandbox_manager()
if manager.is_active():
info = manager.get_info()
if info.get('vnc_url'):
print_vnc_info(info['vnc_url'])
except:
pass
except Exception as e:
print(f"查詢失敗: {str(e)}\n")
import traceback
traceback.print_exc()
# 交互式查詢
print("\n" + "=" * 60)
print("進入交互模式(輸入 'quit' 或 'exit' 退出,Ctrl+C 或 Ctrl+D 中斷)")
print("=" * 60 + "\n")
while True:
try:
user_input = input("請輸入您的查詢: ").strip()
except EOFError:
# 處理 Ctrl+D (EOF)
print("\n\n檢測到輸入結束 (Ctrl+D),正在清理資源...")
cleanup_sandbox()
print("清理完成")
break
except KeyboardInterrupt:
# 處理 Ctrl+C (在 input 調用期間)
print("\n\n檢測到中斷信號 (Ctrl+C),正在清理資源...")
cleanup_sandbox()
print("清理完成")
break
if not user_input:
continue
if user_input.lower() in ['quit', 'exit', '退出']:
print("\nBye")
# 退出前清理 sandbox
cleanup_sandbox()
break
try:
result = agent.invoke({
"messages": [{"role": "user", "content": user_input}]
})
output = result.get("messages", [])[-1].content if isinstance(result.get("messages"), list) else result.get("output", str(result))
print(f"\n結果:\n{output}\n")
# 檢查是否需要打開或顯示 VNC 信息
user_input_lower = user_input.lower()
if "創建" in user_input_lower and "sandbox" in user_input_lower:
# 如果是創建 sandbox,自動打開 VNC 查看器
try:
# 等待一下確保 sandbox 完全創建
import time
time.sleep(1)
manager = get_sandbox_manager()
if manager.is_active():
info = manager.get_info()
vnc_url = info.get('vnc_url')
if vnc_url:
print(f"\n檢測到 VNC URL: {vnc_url[:80]}...")
open_vnc_viewer(vnc_url)
print_vnc_info(vnc_url)
else:
print("\n警告: 未獲取到 VNC URL,請檢查 sandbox 創建是否成功")
except Exception as e:
print(f"打開 VNC 查看器時出錯: {str(e)}")
import traceback
traceback.print_exc()
elif "sandbox" in user_input_lower or "vnc" in user_input_lower:
# 其他情況只顯示信息
try:
manager = get_sandbox_manager()
if manager.is_active():
info = manager.get_info()
if info.get('vnc_url'):
print_vnc_info(info['vnc_url'])
except:
pass
except Exception as e:
print(f"查詢失敗: {str(e)}\n")
import traceback
traceback.print_exc()
# 清理資源(僅在程序正常退出時)
cleanup_sandbox()
except KeyboardInterrupt:
# 處理頂層 KeyboardInterrupt (Ctrl+C)
print("\n\n檢測到中斷信號 (Ctrl+C),正在清理資源...")
cleanup_sandbox()
print("清理完成")
sys.exit(0)
except EOFError:
# 處理頂層 EOFError (Ctrl+D)
print("\n\n檢測到輸入結束 (Ctrl+D),正在清理資源...")
cleanup_sandbox()
print("清理完成")
sys.exit(0)
except ValueError as e:
print(f"配置錯誤: {str(e)}")
print("\n提示: 請確保已設置以下環境變量:")
print(" - DASHSCOPE_API_KEY: DashScope API Key")
print(" - ALIBABA_CLOUD_ACCOUNT_ID: 阿里雲賬號 ID")
print(" - ALIBABA_CLOUD_ACCESS_KEY_ID: 訪問密鑰 ID")
print(" - ALIBABA_CLOUD_ACCESS_KEY_SECRET: 訪問密鑰 Secret")
print(" - ALIBABA_CLOUD_REGION: 區域(默認: cn-hangzhou)")
except Exception as e:
print(f"發生錯誤: {str(e)}")
import traceback
traceback.print_exc()
# 發生錯誤時也嘗試清理
cleanup_sandbox()
if __name__ == "__main__":
main()
關鍵功能:
- VNC 自動打開: 創建 Sandbox 後自動打開 VNC 查看器
- 信號處理: 捕獲 Ctrl+C,確保資源正確清理
- 交互模式: 支持持續對話,複用 Sandbox 實例
VNC 可視化集成
VNC(Virtual Network Computing)功能允許您實時查看和監控瀏覽器在 Sandbox 中的操作過程,這對於調試和監控 Agent 行為非常有用。
獲取 VNC URL:
創建 Sandbox 後,可以通過 get_sandbox_info tool 獲取 VNC URL:
# 通過 Agent 調用
result = agent.invoke({
"messages": [{"role": "user", "content": "獲取 sandbox 信息"}]
})
# 或直接通過管理器獲取
manager = get_sandbox_manager()
info = manager.get_info()
vnc_url = info['vnc_url']
自動打開 VNC 查看器:
在 main.py 中,我們實現了自動打開 VNC 查看器的功能:
import webbrowser
import urllib.parse
from pathlib import Path
def open_vnc_viewer(vnc_url: str):
"""自動打開 VNC 查看器"""
current_dir = Path(__file__).parent.absolute()
vnc_html_path = current_dir / "vnc.html"
if vnc_html_path.exists():
# 通過 URL 參數傳遞 VNC URL
encoded_url = urllib.parse.quote(vnc_url, safe='')
file_url = f"file://{vnc_html_path}?url={encoded_url}"
webbrowser.open(file_url)
VNC HTML 頁面:
vnc.html 頁面會從 URL 參數中讀取 VNC URL,並自動連接到 VNC 服務器。頁面包含以下核心功能:
- noVNC 庫加載: 從 CDN 動態加載 noVNC 客户端庫
- 自動連接: 讀取 URL 參數中的 VNC URL 並自動連接
- 狀態顯示: 顯示連接狀態(連接中、已連接、已斷開)
- 手動控制: 支持手動輸入 VNC URL、斷開重連等操作
核心 JavaScript 代碼片段:
// 從 URL 參數獲取 VNC URL
const urlParams = new URLSearchParams(window.location.search);
const vncUrl = urlParams.get('url');
// 加載 noVNC 庫
async function loadNoVNC() {
const module = await import('https://cdn.jsdelivr.net/gh/novnc/noVNC@v1.4.0/core/rfb.js');
return module.default;
}
// 連接 VNC
async function connectVNC(url) {
const RFB = await loadNoVNC();
rfb = new RFB(vncScreen, url, {
shared: true,
credentials: { password: '' }
});
rfb.addEventListener('connect', () => {
console.log('VNC 連接成功');
});
}
完整的 vnc.html 文件可以在示例代碼倉庫中獲取。
手動使用 VNC 查看器:
如果自動打開失敗,您也可以手動使用 VNC 查看器:
- 使用 noVNC 在線客户端:
- 訪問 noVNC 在線客户端
- 在連接設置中填入 VNC URL
- 點擊連接
- 使用本地 VNC HTML 頁面:
- 打開
vnc.html - 輸入 VNC URL
- 點擊連接按鈕
- 打開
實時監控功能:
- 所有瀏覽器操作都會在 VNC 中實時顯示
- 可以看到 Agent 的每一步操作(導航、點擊、輸入等)
- 方便調試和監控 Agent 行為
- 支持交互式操作(在 VNC 中直接操作瀏覽器)
運行和測試
python main.py
程序會自動:
- 創建 Browser Sandbox
- 打開 VNC 查看器(實時查看瀏覽器操作)
- 執行預設查詢
- 進入交互模式
工作原理
為了更好地理解系統架構,我們將工作流程拆分為兩個部分:LangChain Agent 工作流程和 SandboxManager 生命週期管理。
1. LangChain Agent 工作流程
下圖展示了 LangChain Agent 如何處理用户請求並調用相應的 Tools:
flowchart TB
Start([用户發起請求<br/>例: 訪問網頁並截圖]) --> Agent[LangChain Agent<br/>分析用户意圖]
Agent --> SelectTool{選擇合適的 Tool}
SelectTool -->|首次使用| Tool1[create_browser_sandbox]
SelectTool -->|導航網頁| Tool2[navigate_to_url]
SelectTool -->|截取屏幕| Tool3[take_screenshot]
SelectTool -->|查詢狀態| Tool4[get_sandbox_info]
SelectTool -->|清理資源| Tool5[destroy_sandbox]
Tool1 --> CallManager1[調用 SandboxManager]
Tool2 --> CallManager2[調用 SandboxManager]
Tool3 --> CallManager3[調用 SandboxManager]
Tool4 --> CallManager4[調用 SandboxManager]
Tool5 --> CallManager5[調用 SandboxManager]
CallManager1 --> Manager[SandboxManager<br/>單例實例]
CallManager2 --> Manager
CallManager3 --> Manager
CallManager4 --> Manager
CallManager5 --> Manager
Manager --> ToolResult[Tool 返回結果]
ToolResult --> AgentProcess[Agent 處理結果<br/>生成響應]
AgentProcess --> Response([返回用户友好的響應])
Response -.多輪對話.-> Start
style Agent fill:#667eea,color:#fff
style Manager fill:#764ba2,color:#fff
style Tool1 fill:#4ecdc4,color:#fff
style Tool2 fill:#4ecdc4,color:#fff
style Tool3 fill:#4ecdc4,color:#fff
style Tool4 fill:#4ecdc4,color:#fff
style Tool5 fill:#4ecdc4,color:#fff
Agent 工作流程説明:
- 請求接收:用户發起自然語言請求(如"訪問淘寶首頁並截圖")
- 意圖分析:Agent 分析用户意圖,決定需要調用哪些 Tools
- Tool 調用:根據任務需求,順序或組合調用多個 Tools
- Manager 交互:所有 Tools 都通過 SandboxManager 單例實例操作 Sandbox
- 結果處理:Agent 將 Tool 返回的結果整合成用户友好的響應
- 多輪對話:Sandbox 在整個會話中保持活躍,支持多輪對話
5 個核心 Tools 的職責:
| Tool | 功能 | 使用場景 |
|---|---|---|
create_browser_sandbox |
創建 Sandbox 實例 | 首次使用或 Sandbox 已銷燬時 |
navigate_to_url |
導航到指定 URL | 需要訪問網頁時 |
take_screenshot |
截取當前頁面 | 需要保存頁面快照時 |
get_sandbox_info |
獲取 Sandbox 信息 | 查看狀態或獲取 VNC URL 時 |
destroy_sandbox |
銷燬 Sandbox 實例 | 任務完成或需要釋放資源時 |
2. SandboxManager 生命週期管理
下圖展示了 SandboxManager 如何管理 Sandbox 的完整生命週期:
SandboxManager 工作流程説明:
- 單例管理:
- 首次調用時創建 Manager 實例
- 後續調用複用同一個實例
- 確保整個會話只有一個 Sandbox
- Sandbox 創建:
- 調用 AgentRun SDK 的 Sandbox.create()
- SDK 通過阿里雲 API 與函數計算 FC 通信
- FC 服務創建獨立的容器實例,包含:
- Chromium 瀏覽器VNC 服務必要的運行環境
- 連接信息獲取:
- CDP URL:WebSocket 地址,用於 Playwright/Puppeteer 遠程控制瀏覽器
- VNC URL:WebSocket 地址,用於實時查看瀏覽器畫面
- 瀏覽器操作:
- Playwright 通過 CDP URL 連接到遠程瀏覽器
- 執行各種瀏覽器操作(導航、點擊、截圖等)
- VNC 同步顯示操作過程,用户可實時監控
- 資源清理:
- 調用 destroy() 方法銷燬 Sandbox
- 清理 Manager 內部狀態
- 通過 SDK 釋放雲端資源
3. Agent 與 Manager 的協作關係
交互模式:
用户請求 → Agent → Tool → SandboxManager → AgentRun SDK → 雲端 Sandbox
↓
用户響應 ← Agent ← Tool ← SandboxManager ← 操作結果
關鍵設計理念:
- 分層架構:
- 用户層:自然語言交互
- Agent 層:意圖理解和任務分解
- Tool 層:功能封裝和參數驗證
- Manager 層:資源管理和狀態維護
- SDK 層:雲服務通信
- 雲端層:實際的 Sandbox 環境
- 單例模式:
- SandboxManager 使用單例模式
- 保證整個會話中只有一個 Sandbox 實例
- 避免資源浪費和狀態衝突
- 狀態複用:
- Sandbox 在多輪對話中保持活躍
- 減少創建和銷燬的開銷
- 提供更流暢的用户體驗
- 雙通道設計:
- CDP 通道:Agent 通過 Playwright 控制瀏覽器
- VNC 通道:用户通過 VNC 查看器實時監控
- 解耦設計:
- Tools 不直接操作 SDK,通過 Manager 統一管理
- 便於擴展和維護
- 統一的錯誤處理和資源管理
典型使用場景示例:
# 第 1 輪對話
用户: "創建一個 sandbox 並訪問淘寶首頁"
→ Agent 調用: create_browser_sandbox → navigate_to_url
→ Manager: 創建 Sandbox → Playwright 導航
→ 結果: "Sandbox 已創建,已訪問淘寶首頁"
# 第 2 輪對話(複用 Sandbox)
用户: "截取當前頁面"
→ Agent 調用: take_screenshot
→ Manager: 使用現有 Sandbox → Playwright 截圖
→ 結果: "截圖已保存"
# 第 3 輪對話(複用 Sandbox)
用户: "訪問京東首頁"
→ Agent 調用: navigate_to_url
→ Manager: 使用現有 Sandbox → Playwright 導航
→ 結果: "已訪問京東首頁"
通過這種設計,Agent 專注於理解用户意圖和任務編排,而 Manager 專注於 Sandbox 的生命週期管理,實現了清晰的職責分離。
工作原理總結:
- 工具註冊: 使用
@tool裝飾器將 Sandbox 功能封裝為 LangChain tools - 生命週期管理:
SandboxManager負責 Sandbox 的創建、管理和銷燬 - 狀態保持: 使用單例模式管理 Sandbox 實例,確保同一會話內複用
- VNC 集成: 自動獲取並返回 VNC URL,方便用户實時查看
- 錯誤處理: 所有工具都包含完善的錯誤處理機制
擴展和定製
添加自定義 Tools:
@tool
def extract_table_data(url: str) -> str:
"""從網頁中提取表格數據"""
from playwright.sync_api import sync_playwright
manager = get_sandbox_manager()
cdp_url = manager.get_info()['cdp_url']
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(cdp_url)
page = browser.contexts[0].pages[0]
page.goto(url)
tables = page.query_selector_all("table")
return f"找到 {len(tables)} 個表格"
自定義提示詞:
custom_prompt = """你是一個專業的網頁數據提取助手。
在執行任務前,請先創建 sandbox,然後使用瀏覽器工具完成任務。"""
agent = create_browser_agent(system_prompt=custom_prompt)
最佳實踐
- 模塊化設計: 將 Sandbox 管理和 Agent 創建分離,提高代碼可維護性
- 錯誤處理: 所有工具都應包含完善的錯誤處理
- 資源清理: 使用信號處理器確保資源正確清理
- VNC 提示: 在工具返回中包含 VNC URL,方便用户使用
- 單例模式: 確保 Sandbox 實例在會話中複用,避免重複創建
前端集成可視化監控(VNC)
VNC 集成架構
下圖展示了前端如何集成 VNC 實現實時監控:
輕量級 HTML 頁面集成
創建一個簡單的 vnc-viewer.html 文件:
<!DOCTYPE html>
<html>
<head>
<title>Browser Sandbox VNC 查看器</title>
<style>
body { margin: 0; padding: 0; background: #000; }
#vnc-container { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<div id="vnc-container"></div>
<script type="module">
const params = new URLSearchParams(window.location.search);
const vncUrl = params.get('url');
if (!vncUrl) {
alert('請提供 VNC URL 參數');
} else {
const module = await import('https://cdn.jsdelivr.net/gh/novnc/noVNC@v1.4.0/core/rfb.js');
const RFB = module.default;
const rfb = new RFB(
document.getElementById('vnc-container'),
vncUrl,
{ shared: true, credentials: { password: '' } }
);
rfb.scaleViewport = true;
}
</script>
</body>
</html>
使用方式:
import webbrowser
import urllib.parse
vnc_url = sandbox.vnc_url
encoded_url = urllib.parse.quote(vnc_url, safe='')
viewer_url = f"file:///path/to/vnc-viewer.html?url={encoded_url}"
webbrowser.open(viewer_url)
React 應用集成
核心組件代碼:
import React, { useEffect, useRef } from 'react';
interface VNCViewerProps {
vncUrl: string;
onConnect?: () => void;
onDisconnect?: () => void;
}
export const VNCViewer: React.FC<VNCViewerProps> = ({
vncUrl,
onConnect,
onDisconnect
}) => {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
let rfb: any;
const initVNC = async () => {
if (!containerRef.current || !vncUrl) return;
const { default: RFB } = await import('@novnc/novnc/core/rfb');
rfb = new RFB(containerRef.current, vncUrl, {
shared: true,
credentials: { password: '' }
});
rfb.scaleViewport = true;
rfb.addEventListener('connect', () => onConnect?.());
rfb.addEventListener('disconnect', () => onDisconnect?.());
};
initVNC();
return () => {
if (rfb) rfb.disconnect();
};
}, [vncUrl, onConnect, onDisconnect]);
return (
<div
ref={containerRef}
style={{ width: '100%', height: '600px', background: '#000' }}
/>
);
};
使用示例:
import React, { useState, useEffect } from 'react';
import { VNCViewer } from './VNCViewer';
function App() {
const [vncUrl, setVncUrl] = useState<string>('');
useEffect(() => {
fetch('/api/sandbox/create', { method: 'POST' })
.then(res => res.json())
.then(data => setVncUrl(data.vnc_url));
}, []);
return (
<div>
Browser Sandbox 實時監控
{vncUrl ? (
<VNCViewer
vncUrl={vncUrl}
onConnect={() => console.log('已連接')}
onDisconnect={() => console.log('已斷開')}
/>
) : (
<p>正在初始化...</p>
)}
</div>
);
}
完整示例代碼:包含完整前端集成示例和後端 API 的代碼請訪問 GitHub 倉庫。
Puppeteer 和 Playwright 直接集成
如果您更熟悉傳統的瀏覽器自動化庫,也可以直接使用 Puppeteer 或 Playwright 連接到 Browser Sandbox。
使用 Playwright
from playwright.sync_api import sync_playwright
from agentrun.sandbox import Sandbox, TemplateType
# 創建 Sandbox
sandbox = Sandbox.create(
template_type=TemplateType.BROWSER,
template_name="your-template-name",
sandbox_idle_timeout_seconds=3000
)
# 使用 Playwright 連接
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(sandbox.cdp_url)
page = browser.contexts[0].pages[0]
# 執行操作
page.goto("https://www.example.com")
page.screenshot(path="screenshot.png")
content = page.content()
browser.close()
# 清理
sandbox.delete()
使用 Puppeteer(Node.js)
const puppeteer = require('puppeteer-core');
// CDP URL 從 Sandbox 獲取
const cdpUrl = 'wss://your-account.funagent-data-pre.cn-hangzhou.aliyuncs.com/sandboxes/xxx/ws/automation';
(async () => {
const browser = await puppeteer.connect({
browserWSEndpoint: cdpUrl,
defaultViewport: null
});
const page = (await browser.pages())[0];
await page.goto('https://www.example.com');
await page.screenshot({ path: 'screenshot.png' });
await browser.close();
})();
總結
通過本教程,您已經學會了:
- AgentRun SDK 基礎: 如何使用 SDK 創建和管理 Browser Sandbox
- LangChain 集成: 如何將 Sandbox 封裝為 LangChain Tools
- VNC 可視化: 如何在前端集成 VNC 實現實時監控
- 直接集成: 如何使用 Puppeteer/Playwright 直接連接 Sandbox
快速瞭解函數計算 AgentRun:
一句話介紹:函數計算 AgentRun 是一個以高代碼為核心的一站式 Agentic AI 基礎設施平台。秉持生態開放和靈活組裝的理念,為企業級 Agent 應用提供從開發、部署到運維的全生命週期管理。
函數計算 AgentRun 架構圖
AgentRun 運行時基於阿里雲函數計算 FC 構建,繼承了 Serverless 計算極致彈性、按量付費、零運維的核心優勢。通過深度集成 AgentScope、Langchain、RAGFlow、Mem0 等主流開源生態。AgentRun 將 Serverless 的極致彈性、零運維和按量付費的特性與 AI 原生應用場景深度融合,助力企業實現成本與效率的極致優化,**平均 TCO 降低 60%**。
讓開發者只需專注於 Agent 的業務邏輯創新,無需關心底層基礎設施,讓 Agentic AI 真正進入企業生產環境。
歡迎加入“函數計算 AgentRun 客户羣”與我們交流,釘釘羣號:134570017218。