
Serverless Framework 集成 LangGraph 自定义 AgentCore 浏览器会话录制与验证全解析【免费下载链接】serverless⚡ Serverless Framework – Effortlessly build apps that auto-scale, incur zero costs when idle, and require minimal maintenance using AWS Lambda and other managed cloud services.项目地址: https://gitcode.com/GitHub_Trending/se/serverless本技术指南以仓库内示例项目langgraph-browser-custom为骨架讲解如何在 Serverless Framework 中通过顶层ai配置声明一个自定义 AgentCore 浏览器Custom Browser替换 AWS 托管默认浏览器使 LangGraph 智能体获得可写入 S3 的会话录制、Web 请求签名减少 CAPTCHA与自定义 IAM/网络能力。读完本文你将掌握自定义浏览器的完整声明语法、浏览器 ID 注入运行时代理的方式以及一套可自动校验“录制确实已写入 S3”的端到端验证脚本。为什么需要自定义浏览器默认 vs 自定义能力对照AgentCore 自带一个由 AWS 托管的默认浏览器应用侧只需使用固定标识aws.browser.v1即可驱动网页自动化但它在调试审计、防机器人校验与内网访问场景下能力有限。示例 README 给出了两组浏览器的差异对照能力默认浏览器Default Browser自定义浏览器Custom Browser标识符aws.browser.v1你自己的自定义 ID会话录制Session Recording不可用可配置写入 S3请求签名Request Signing不可用可配置VPC 访问不可用可配置IAM 角色AWS 托管自定义角色简而言之一旦你的 Agent 需要「回放会话排查问题、降低被 CAPTCHA 拦截的概率、或访问 VPC 内网目标」就需要在serverless.yml中声明自定义浏览器并通过BrowserClient.start(identifier...)显式选用它。示例项目结构与部署链路示例位于 examples/python/langgraph-browser-custom包含 5 个文件各司其职langgraph-browser-custom/ ├── serverless.yml # 定义自定义浏览器 S3 桶 运行时 agent ├── agent.py # 基于 LangGraph Playwright 的浏览器代理 ├── test-invoke.py # 验证脚本检查 S3 是否出现新录制 ├── Dockerfile # 内置 Playwright/Chromium 的容器镜像 ├── pyproject.toml # Python 依赖声明 └── README.md # 项目说明整体工作流程可概括为三步serverless.yml声明资源S3 录制桶、开启录制/签名/自定义角色的自定义浏览器以及一个通过环境变量接收浏览器 ID 的运行时 Agentagent.py消费浏览器在工具函数中用BrowserClient.start(identifierCUSTOM_BROWSER_ID)代替默认浏览器随后经 WebSocket 连接 Playwright 完成页面导航与内容抽取test-invoke.py反向验证先记录 S3 录制数量再触发 Agent 访问 example.com轮询等待录制文件出现用「新增录制」证明会话确实流经自定义浏览器。其中各配置参数会由 AgentCore 插件编译为 CloudFormation对应实现见下文的「源码级印证」小节通过serverless deploy一次下发。serverless.yml自定义浏览器与录制的完整配置服务骨架与录制桶示例在provider声明 AWSus-east-1区域并通过原生resources语法创建录制 S3 桶。桶名遵循{service}-recordings-{stage}约定${sls:stage}为 Serverless 内置的当前阶段变量同时做了两项面向生产环境的加固公共访问全部封锁PublicAccessBlockConfiguration四项全部置true录制属于敏感审计数据不应被公开读取生命周期自动清理DeleteOldRecordings规则开启ExpirationInDays: 7录制文件 7 天后自动过期避免审计桶无限膨胀。service: langgraph-browser-custom provider: name: aws region: us-east-1 resources: Resources: # S3 bucket for browser session recordings RecordingsBucket: Type: AWS::S3::Bucket Properties: BucketName: ${self:service}-recordings-${sls:stage} PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true LifecycleConfiguration: Rules: - Id: DeleteOldRecordings Status: Enabled ExpirationInDays: 7自定义浏览器声明录制 签名 自定义角色核心在顶层ai.browsers.customBrowser。对应示例 README 的「Configuration Options」一节的通用形态my-bucket需替换为真实桶名其中prefix为可选键不填时由服务端决定前缀ai: browsers: customBrowser: description: Browser with custom configuration network: mode: PUBLIC # or VPC signing: enabled: true # Reduces CAPTCHAs recording: enabled: true s3Location: bucket: my-bucket prefix: recordings/示例中则直接把录制指向上面声明的RecordingsBucket并内联自定义执行角色为该浏览器授予对录制桶的完整读写权限PutObject/GetObject/ListBucket含分片上传所需的AbortMultipartUpload与ListMultipartUploadPartsai: # Custom browser with session recording enabled # This creates a AWS::BedrockAgentCore::BrowserCustom resource browsers: customBrowser: description: Custom browser with session recording for validation network: mode: PUBLIC signing: enabled: true recording: enabled: true s3Location: bucket: ${self:service}-recordings-${sls:stage} prefix: browser-sessions/ # Custom role with S3 permissions for recordings role: statements: - Effect: Allow Action: - s3:PutObject - s3:GetObject - s3:ListBucket - s3:AbortMultipartUpload - s3:ListMultipartUploadParts Resource: - !GetAtt RecordingsBucket.Arn - !Sub ${RecordingsBucket.Arn}/*需要说明的语义signing.enabled: true对应示例特性里的「Web Bot Auth / Request Signing」用于降低目标站点的 CAPTCHA 概率recording.s3Location.bucket/prefix决定录制对象存放位置。插件在生成时会把录制配置写入RecordingConfig只有当开启录制时才创建该配置块录制是否真正落盘与桶权限强相关——若浏览器角色缺s3:PutObject权限Agent 会话正常但录制上传会静默失败这正是下文验证脚本要兜底排查的问题。VPC 模式的可选配置若浏览器需要访问仅内网可达的目标如 VPC 内的业务系统可将network.mode设为VPC并直接给出子网与安全组注意mode会统一规范为大写代码注释明确 Browser 资源不支持SANDBOX模式只接受PUBLIC/VPCai: browsers: privateBrowser: network: mode: VPC subnets: - subnet-12345 - subnet-67890 securityGroups: - sg-12345运行时代理把浏览器 ID 注入 Agent 环境变量ai.agents.browserAgent通过environment向运行时代理注入两个变量CUSTOM_BROWSER_ID值取自!GetAtt CustomBrowserBrowser.BrowserId——注意 CloudFormation 逻辑 ID 由插件按getLogicalId(customBrowser, Browser)生成即CustomBrowserBrowserserverless.yml中专门以注释说明这一点RECORDINGS_BUCKET录制桶名供 Agent 运行时与验证脚本引用。同时为 Agent 的角色授予操作该浏览器的四个bedrock-agentcore:*权限开启/停止会话、更新流、连接自动化流资源限定为该浏览器的BrowserArn# Runtime agent that uses the custom browser agents: browserAgent: environment: # Pass the custom browser ID to the agent # Logical ID: getLogicalId(customBrowser, Browser) CustomBrowserBrowser CUSTOM_BROWSER_ID: !GetAtt CustomBrowserBrowser.BrowserId RECORDINGS_BUCKET: ${self:service}-recordings-${sls:stage} # Grant permission to use the custom browser role: statements: - Effect: Allow Action: - bedrock-agentcore:StartBrowserSession - bedrock-agentcore:StopBrowserSession - bedrock-agentcore:UpdateBrowserStream - bedrock-agentcore:ConnectBrowserAutomationStream Resource: !GetAtt CustomBrowserBrowser.BrowserArnagent.py用自定义 ID 替代默认浏览器agent.py的注释直接点明核心差异默认浏览器用aws.browser.v1标识而自定义浏览器使用serverless.yml中ai.browsers定义出的自有 ID。运行时代理通过环境变量取得该 IDagent.py中依次读取AWS_REGION、MODEL_ID、CUSTOM_BROWSER_ID、RECORDINGS_BUCKET其中AWS_REGION由 AgentCore 运行时自动注入。值得注意的容错设计当CUSTOM_BROWSER_ID未设置时代码仅打印 warning 并继续BrowserClient.start(identifierNone)会退回默认浏览器——这正是需要「S3 录制验证」来杜绝的静默退化场景。from bedrock_agentcore.runtime import BedrockAgentCoreApp from bedrock_agentcore.tools.browser_client import BrowserClient from langchain.chat_models import init_chat_model from langchain_core.tools import tool from langgraph.prebuilt import create_react_agent from playwright.async_api import async_playwright CUSTOM_BROWSER_ID os.environ.get(CUSTOM_BROWSER_ID) RECORDINGS_BUCKET os.environ.get(RECORDINGS_BUCKET) if not CUSTOM_BROWSER_ID: logger.warning(CUSTOM_BROWSER_ID not set - will use default browser)浏览器工具browse_webpage展示了完整的调用链路共四步启动自定义浏览器会话browser_client.start(identifierCUSTOM_BROWSER_ID)是「与默认浏览器唯一的分叉点」建立 WebSocket 通道generate_ws_headers()返回ws_url与鉴权 headers用 Playwright 接管playwright.chromium.connect_over_cdp(endpoint_urlws_url, headersheaders, timeout30000)连接已启动的浏览器随后page.goto(url, wait_untildomcontentloaded, timeout30000)导航并通过一段浏览器内page.evaluate抽取document.body.innerText前 2000 字符作为正文摘要停止会话触发录制上传无论成功与否finally中必调browser_client.stop()——注释明确「会话停止即触发录制上传到 S3」这是验证脚本能观察到录制文件的前提。tool async def browse_webpage(url: str) - str: browser_client BrowserClient(regionAWS_REGION) try: # Start session with CUSTOM browser identifier (not default) browser_client.start(identifierCUSTOM_BROWSER_ID) ws_url, headers browser_client.generate_ws_headers() async with async_playwright() as playwright: browser await playwright.chromium.connect_over_cdp( endpoint_urlws_url, headersheaders, timeout30000) context browser.contexts[0] page context.pages[0] await page.goto(url, wait_untildomcontentloaded, timeout30000) title await page.title() content await page.evaluate( () { const body document.body; return body ? body.innerText.substring(0, 2000) : ; } ) await browser.close() return fPage Title: {title}\n\nContent:\n{content} finally: browser_client.stop() # 停止会话触发录制上传 logger.info(Browser session stopped - recording should be uploaded to S3)编排层面示例使用 LangChain 的init_chat_model(MODEL_ID, model_providerbedrock_converse)默认模型为us.anthropic.claude-sonnet-4-20250514-v1:0可用环境变量MODEL_ID覆盖并把browse_webpage注册进 LangGraph 预置的create_react_agentReAct 循环。app.entrypoint装饰的invoke函数从 payload 取出用户提示词按session_id作为 LangGraph 的thread_id实现会话隔离最终把browser_id、recordings_bucket一并返回供验证方确认自定义浏览器确实被启用app.entrypoint async def invoke(payload, context): prompt payload.get(prompt, Hello!) session_id getattr(context, session_id, default) if context else default config {configurable: {thread_id: session_id}} result await agent.ainvoke( {messages: [{role: user, content: prompt}]}, configconfig) final_message result[messages][-1].content return { result: final_message, browser_id: CUSTOM_BROWSER_ID, recordings_bucket: RECORDINGS_BUCKET }容器与依赖保证 Playwright 可运行浏览器自动化依赖系统级库容器必须补齐。Dockerfile基于python:3.12-slim用 apt 安装 Playwright/Chromium 运行所需的 18 个系统库libnss3、libgbm1、libasound2、libcairo2等随后pip install .安装项目依赖并执行playwright install chromium最后以python agent.py启动本地直跑时监听PORT默认 8080。pyproject.toml的核心依赖为bedrock-agentcore1.3.0、langchain1.2.10、langchain-aws1.2.5、langgraph1.0.8、playwright1.42.0、nest_asyncio1.5.0要求 Python3.10。部署与产物在示例目录下执行部署Serverless Framework 会自动识别目录中的Dockerfile完成镜像构建与推送# Deploy the stack serverless deploy # Note the outputs: # - browserAgent runtime ARN # - customBrowser browser ID # - S3 bucket name部署输出会给出 agent 调用端点与浏览器 ID示例输出实际账号/资源 ID 以你的栈为准ai: agents: browserAgent: https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/xxx/invocations browsers: customBrowser: custom-browser-id-xxx随后按输出导出环境变量并执行验证测试# Set environment variables from deployment output export RUNTIME_ARNarn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/... export RECORDINGS_BUCKETlanggraph-browser-custom-recordings-dev # Run validation test python test-invoke.pytest-invoke.py用 S3 录制证明「自定义浏览器确实被使用」验证脚本的核心逻辑是差分计数既然默认浏览器不产生录制那么「本次调用后 S3 出现新录制文件」即为自定义浏览器生效的最强证据。脚本定义了一个带 300 秒读超时、无重试的bedrock-agentcore客户端与一个标准 S3 客户端流程分四步统计基线以Prefixbrowser-sessions/列出桶内对象count_recordings_in_s3得到初始录制数触发 Agent通过invoke_agent_runtime(agentRuntimeArnRUNTIME_ARN, runtimeSessionIduuid, payload{prompt: Navigate to https://example.com and tell me the page title})发起调用响应体解析后若含browser_id字段即打印「Browser ID used」与部署输出的自定义 ID 比对可人工二次确认轮询等待由于录制在会话停止后才上传脚本以 5 秒为间隔最多等待 60 秒每轮打印Checking... (Ns) - Recording count直到current_count initial_count即判定命中判定与明细命中则打印SUCCESS: New recording detected in S3!、新增数量并按LastModified倒序展示最近 3 个录制对象Key/Size/Modified未命中则输出VALIDATION INCONCLUSIVE并提示三类常见根因——录制上传耗时更长、桶权限不足、浏览器角色缺 S3 写权限同时列出桶内已有对象便于人工核查。验证通过时的完整输出形如[Step 1] Counting existing recordings in S3... Initial recording count: 0 [Step 2] Invoking agent to browse example.com... Agent response: ---------------------------------------- Page Title: Example Domain Content: Example Domain This domain is for use in illustrative examples... ---------------------------------------- Browser ID used: custom-browser-id-xxx [Step 3] Waiting for recording to be uploaded to S3... Checking... (5s) - Recording count: 0 Checking... (10s) - Recording count: 1 [Step 4] Validation Results SUCCESS: New recording detected in S3! Initial count: 0 Final count: 1 New recordings: 1 Latest recordings: - browser-sessions/session-xxx/batch_1.ndjson.gz Size: 12345 bytes Modified: 2025-01-30 12:00:00 VALIDATION PASSED The custom browser with session recording is working correctly! 从输出可见录制对象的键值规律为browser-sessions/{session-id}/batch_*.ndjson.gz——NDJSON 分片压缩存储每个会话可产生多个 batch 文件。查看会话录制两种查看方式均可作为调试与审计手段。AgentCore 控制台可视化进入 AWS 控制台的 Bedrock AgentCore「内置工具 / 浏览器」入口选中自定义浏览器找到目标会话后点击「View Recording」回放操作轨迹。程序化列出对象使用 boto3 以browser-sessions/为前缀列举即可拿到录制文件清单import boto3 s3 boto3.client(s3) response s3.list_objects_v2( Bucketlanggraph-browser-custom-recordings-dev, Prefixbrowser-sessions/ ) for obj in response.get(Contents, []): print(f{obj[Key]} - {obj[Size]} bytes)清理serverless remove会连同浏览器资源一并移除整个栈# Remove the stack (including S3 bucket and browser) serverless remove注意示例中的 S3 桶带有DeletionPolicy: Delete因此会被连内容一起删除若需保留审计记录请提前归档或改用保留策略。源码级印证自定义浏览器如何被编译为 CloudFormation示例中的ai.browsers/ai.agents语法由 AgentCore 插件在打包阶段消费。若想深入理解自定义浏览器的字段映射可对照以下实现字段编译规则位于 compilers/browser.jsbuildBrowserNetworkConfiguration()把network.mode统一转大写、缺省为PUBLICVPC模式下将subnets/securityGroups映射为VpcConfig文件注释确认 Browser 不支持SANDBOX模式buildRecordingConfig()仅在存在recording块时输出RecordingConfig其中S3Location的Bucket必填、Prefix可选buildBrowserSigning()输出BrowserSigning.EnabledcompileBrowser()最终生成Type: AWS::BedrockAgentCore::BrowserCustom其文件头注释明确了该自定义资源的必填/可选/只读/仅创建属性全集——如NetworkConfiguration、ExecutionRoleArn、RecordingConfig、BrowserSigning属于 create-only后续变更需替换资源而BrowserId、BrowserArn、Status为只读输出。逻辑 ID 与资源编排位于 compilation/orchestrator.jscompileBrowserResources()以getLogicalId(name, Browser)生成逻辑 ID即示例注释中customBrowser→CustomBrowserBrowser的来源自动生成 IAM 角色及RoleArn输出并为每个浏览器追加{LogicalId}Arn含跨栈 Export与{LogicalId}Id两个 CloudFormation Output——其中 BrowserId 正是agent.py环境变量所注入的值这就是「部署输出能看到customBrowser: custom-browser-id-xxx」的底层原因。整体能力入口见 bedrock-agentcore/README.md顶层ai属性下设agents/memory/tools/gateways/browsers/codeInterpreters六个分区每个资源类型各有独立分区、无 type 判别字段浏览器能力即由ai.browsers分区承载插件自动生成最小权限 IAM 并统一命名、打标。说明上述文章的示例 README 文档内容完整继承并结合了仓库内实际示例文件 serverless.yml、agent.py、test-invoke.py、Dockerfile、pyproject.toml以及插件编译器 compilers/browser.js 和 compilation/orchestrator.js 的源码细节进行了深度扩充。【免费下载链接】serverless⚡ Serverless Framework – Effortlessly build apps that auto-scale, incur zero costs when idle, and require minimal maintenance using AWS Lambda and other managed cloud services.项目地址: https://gitcode.com/GitHub_Trending/se/serverless创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考