尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AI Agent 自动开发并发布浏览器游戏:从自然语言到线上运行的闭环

AI Agent 自动开发并发布浏览器游戏:从自然语言到线上运行的闭环 当一个 AI agent 能把“做一个浏览器游戏”从自然语言变成线上可访问的网页很多人第一反应是惊讶但从工程角度看这件事拆开之后并不神秘。AI agent 的本质不是一个能写代码的聊天框而是一个循环系统它把目标拆成任务调用工具写文件、跑命令、看结果再根据反馈修正直到满足验收标准。本文以“AI agent 自主构建并发布浏览器游戏”为场景拆解这个闭环的每一个环节并给出一条可复现的路径用最小 agent 循环生成一个 Canvas 小游戏用浏览器自动化验证运行再通过 Git 和静态托管发布到公网。无论你是刚开始接触 agent 开发还是想把手动编码重活交给智能体这条链路都值得完整走一遍。1. AI Agent 自主开发游戏从现象到技术拆解1.1 “自己构建并发布”到底发生了什么“AI agent 自己构建并发布了一个浏览器游戏”这句话听起来像模型凭空完成了所有工作但实际发生的是一连串可观测的工程动作生成 HTML、CSS、JavaScript 代码把代码写入磁盘启动本地服务或浏览器进行验证读取控制台报错修改代码后再次验证最终推送到 Git 仓库并触发静态托管平台构建。真正重要的是这些动作不是由一个人手动执行的而是由一个 agent 循环自动驱动的。人工开发的链路通常包含需求分析、编码、本地验证、修复、发布五个阶段。Agent 开发则把同样的链路压缩成一个可重复的循环大模型负责决策工具负责执行验证结果负责反馈。阶段人工开发Agent 开发需求理解阅读文本并提问从任务说明书中解析约束编码编辑器手写生成代码并调用写文件工具验证浏览器手动点击浏览器自动化打开并截图修复查看控制台调整逻辑把错误回传模型再生成补丁发布手动推送分支调用命令完成提交和推送理解这一点的价值在于你可以把“AI agent 自主开发”看作一套可复制的自动化流水线而不是某个模型的独有能力。任何一个具备工具调用能力的模型只要外部执行环境足够清晰都能呈现出类似的自主性。1.2 Agent 不是一个能写代码的聊天框而是一个闭环执行系统大语言模型本身是一个文本生成器它没有手去操作文件也没有眼睛去看浏览器页面。要让机器人式地完成开发任务必须给它接上外部系统这也解释了为什么 agent 开发的重点不在“模型有多强”而在“循环设计有多稳”。一个常见的 Agent 工作循环是 ReAct 模式推理Reasoning决定下一步做什么行动Acting调用外部工具观察Observation读取工具返回结果并作为下一轮推理的输入。这个循环会一直持续到任务完成或触发终止条件。这里还要区分两个容易混淆的概念模型和载体。负责生成文本的模型是单一组件而负责调用模型、调度工具、管理历史消息、限制动作范围的运行时框架通常也被称为 agent harness。很多人讨论“agent 框架”时实际讨论的是 harness 层应该怎么设计而“agent 安全”“agent 记忆”这些问题也都发生在这一层。在具体实现上成熟的方案有很多LangGraph、AutoGen、Spring AI 的工具调用支持也可以自己实现一个几十行的最小 harness。框架本身不是关键关键是闭环必须成立模型做出的决策必须能作用于真实环境真实环境的反馈必须能回到模型上下文里。1.3 为什么浏览器游戏适合作为 Agent 实验项目浏览器游戏是验证 agent 开发能力的一个极佳载体因为它具备四个特征。第一交付物是单文件。一个标准的贪吃蛇或打砖块游戏可以完全封装在 index.html 中样式和脚本全部内联没有数据库、没有后端服务、没有复杂的构建链。这让 agent 可以专注于完成一个最小闭环。第二验证目标非常明确。游戏是否可玩可以通过页面是否能打开、控制台是否报错、按键是否改变画面状态、碰撞后是否触发结束逻辑来判断。这些都可观测不需要主观评价。第三失败反馈非常直接。如果 agent 生成的代码有运行时报错浏览器控制台会给出具体错误信息如果画面白屏截图工具会捕捉到空白页面。这些结构化反馈可以直接回传给模型驱动它修复代码。第四发布链路足够简单。静态网页只需要托管在 GitHub Pages、Netlify 或 Vercel 这类服务上不需要配置服务器和数据库非常适合演示“从生成到上线”的完整路由。2. 前置准备运行 Agent 需要的最小环境和工具2.1 推荐技术栈和项目结构为了让演示不依赖特定框架这里使用一个极简的 Python 脚本作为 agent harness。它需要具备三个能力调用大模型接口、向模型暴露工具、把工具结果追加到对话历史。推荐的项目结构如下ai-game-agent/ ├── agent.py ├── requirements.txt ├── tasks/ │ └── snake_spec.md ├── workspace/ │ └── game/ │ └── index.html └── .gitignore目录说明agent.pyagent 主循环代码负责调用模型、执行工具和管理消息。tasks/存放任务说明书。任务说明书既是给 agent 的需求描述也是后续验收的依据。workspace/game/agent 可以自由读写的游戏目录。把 agent 的工作区固定在独立目录里可以避免它误操作项目其他文件。.gitignore忽略动态生成的文件和密钥。推荐依赖只需要 openai SDK 和 playwright。openai SDK 用于对接兼容 Chat Completions 协议的模型接口playwright 用于浏览器自动化验证。2.2 准备模型 API 与本地工作目录先创建虚拟环境并安装依赖mkdir -p ai-game-agent/workspace/game cd ai-game-agent python -m venv .venv source .venv/bin/activate pip install openai playwright playwright install chromium安装完成后通过环境变量配置模型接口。这里采用 OpenAI 兼容协议因此只要模型服务商提供兼容接口就可以只修改 base_url 和模型名不需要改动核心循环代码export LLM_API_KEYyour-api-key export LLM_BASE_URLhttps://api.example.com/v1 export LLM_MODELyour-model-name如果本地已经有模型网关也可以把 base_url 指到本地服务。需要注意示例代码里的变量名只是规范示例实际项目要按自己使用的模型服务商调整。2.3 用环境变量隔离密钥避免把凭证写进代码写 agent 代码时最容易忽略的安全问题是密钥管理。不要把 API Key 直接写入 agent.py否则一旦代码推送到公开仓库密钥就会泄露。.gitignore至少应该包含以下内容.venv/ __pycache__/ .env workspace/game/这里把workspace/game/也忽略掉是因为游戏产物是 agent 动态生成的代码不该进入主仓库。如果希望保留某次生成结果可以手动复制到独立目录再提交。使用时可以通过 dotenv 加载.env文件脚本里只读取环境变量import os api_key os.environ.get(LLM_API_KEY) base_url os.environ.get(LLM_BASE_URL) model os.environ.get(LLM_MODEL)生产环境不要使用 shell export 方式长期保留密钥建议使用密钥管理服务或 CI 提供的临时凭证。代理密钥一旦泄露必须立即撤销并重新生成不能只修改代码后重新推送。3. 实现一个最小 Agent 循环生成、执行、反馈、修复3.1 Agent 核心循环的伪代码与关键设计在动手写代码之前先明确核心循环的结构。这个循环是所有 agent 开发的骨架后面扩展能力时只需要往里增加工具和判断条件。while 未达到最大轮次 and 未通过验收: 1. 模型读取系统提示、任务目标、历史消息、工具结果 2. 模型决定下一步是调用工具还是输出最终结果 3. 如果是工具调用执行对应的工具函数 4. 把工具输出作为观察结果追加到消息历史 5. 模型基于新的观察继续推理这个循环有三个关键设计点。第一模型必须能调用工具。这里通过 function calling 机制实现模型返回的不是普通文本而是一个工具调用请求包含工具名和参数 JSON。第二工具执行结果必须真实返回给模型。如果工具执行失败错误信息也要写入消息历史否则模型会基于幻觉继续编写代码这是 agent 开发最常见的失控原因。第三必须有终止条件。没有终止条件的 agent 会陷入无限循环既消耗成本也无法交付。终止条件包括最大步数、验收通过信号和成本预算。3.2 让 Agent 能写文件、能运行命令下面是 agent.py 的工具定义部分。为了让 agent 能生成浏览器游戏最少需要两个工具写文件和执行命令。import json import os import subprocess from pathlib import Path from openai import OpenAI WORKSPACE Path(./workspace/game) MODEL os.environ.get(LLM_MODEL, gpt-4o-mini) client OpenAI( api_keyos.environ.get(LLM_API_KEY), base_urlos.environ.get(LLM_BASE_URL), ) TOOLS [ { type: function, function: { name: write_file, description: 在游戏目录中写入文件path 是相对于游戏目录的路径, parameters: { type: object, properties: { path: {type: string}, content: {type: string}, }, required: [path, content], }, }, }, { type: function, function: { name: run_command, description: 在游戏目录中执行命令用于检查语法或启动静态服务, parameters: { type: object, properties: { command: {type: string}, }, required: [command], }, }, }, ]执行工具的逻辑必须包含路径校验防止模型写入工作目录之外的文件def run_tool(name, arguments): args json.loads(arguments) if name write_file: raw_path args[path] target (WORKSPACE / raw_path).resolve() if not target.is_relative_to(WORKSPACE.resolve()): return error: path is outside workspace target.parent.mkdir(parentsTrue, exist_okTrue) target.write_text(args[content], encodingutf-8) return written: raw_path if name run_command: try: result subprocess.run( args[command], shellTrue, cwdWORKSPACE, capture_outputTrue, textTrue, timeout30, ) return (result.stdout result.stderr)[-3000:] except subprocess.TimeoutExpired: return error: command timeout return error: unknown tool这个示例在本地演示环境中可以工作但要注意两点。第一shellTrue在隔离沙箱中才建议使用真实项目应该用参数化命令并维护命令白名单。第二工具输出必须截断否则一次命令输出的几千行日志会很快撑爆模型上下文窗口。主循环如下def agent_loop(task_spec, max_steps15): messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: task_spec}, ] for step in range(max_steps): response client.chat.completions.create( modelMODEL, messagesmessages, toolsTOOLS, ) message response.choices[0].message messages.append(message.model_dump()) if message.tool_calls: for tool_call in message.tool_calls: result run_tool( tool_call.function.name, tool_call.function.arguments, ) messages.append({ role: tool, tool_call_id: tool_call.id, content: result, }) else: print(message.content) break else: print(reach max steps)不同版本的 openai SDK 对消息序列化的要求略有差异落地时以实际返回结构为准。核心逻辑是模型有工具调用就执行工具再把结果追加进历史模型没有工具调用就当作最终回答退出循环。3.3 用浏览器自动化验证游戏是否真的能运行只有写文件工具还不够因为模型无法确认它生成的代码到底能不能跑。这时需要第三个工具用 Playwright 打开页面、监听控制台错误并截图。from playwright.sync_api import sync_playwright def check_game(file_nameindex.html): errors [] with sync_playwright() as p: browser p.chromium.launch() page browser.new_page() page.on(console, lambda msg: errors.append(msg.text) if msg.type error else None) page.on(pageerror, lambda exc: errors.append(str(exc))) page.goto(WORKSPACE.joinpath(file_name).as_uri()) page.wait_for_timeout(2000) page.screenshot(pathstr(WORKSPACE / screenshot.png)) body_text page.inner_text(body) browser.close() result { console_errors: errors[:20], body_text_preview: body_text[:500], screenshot: str(WORKSPACE / screenshot.png), } return json.dumps(result, ensure_asciiFalse)[:3000]把这个函数加入 TOOLS 后agent 的工作方式就产生了质变。它每次修改完代码都可以先运行语法检查再用浏览器打开页面看到控制台错误和页面截图。这样做脚本生成代码不再是一次性输出而是一个不断逼近目标的验证闭环。需要注意Playwright 的同步 API 在 agent 循环中会阻塞循环但演示场景完全够用。真实项目可以考虑异步执行或把页面验证放到独立服务中。3.4 设置终止条件、成本上限和上下文截断最小 agent 循环跑通之后要立刻补上四个保护机制否则把任务规模放大时一定会出问题。第一最大步数。示例中max_steps15这表示模型最多可以执行 15 轮工具调用。对单文件浏览器游戏来说足够对复杂任务可以调大但必须有上限。第二成本预算。每次调用模型都会消耗 token工具输出越多消耗越大。在真实项目中应该把每轮请求的 token 用量记录到日志并设置任务级预算例如“单次任务最多消耗 50000 token超限自动终止”。第三上下文截断。工具输出不能无限制回传run_command 和 check_game 的返回都做了字符截断。更完整的方案是把长输出先交给模型做摘要只保留摘要结果。第四明确的完成信号。在系统提示里要求模型在通过验收后输出固定前缀主循环检测到该前缀就退出避免模型继续做无意义修改。SYSTEM_PROMPT 你是一个浏览器游戏开发 Agent。 你可用的工具是 write_file、run_command 和 check_game。 所有文件必须写入游戏目录。 每次修改后先检查语法再使用 check_game 验证页面。 当且仅当游戏满足任务说明书中的验收标准时输出 FINAL_RESULT。 如果工具执行出错你必须根据错误信息修复代码。 4. 用任务说明书引导 Agent 构建一个“贪吃蛇”小游戏4.1 目标游戏的需求描述怎么写Agent 才不会跑偏如果你的 prompt 只写“做一个贪吃蛇游戏”agent 很可能会返回一大段计划或者生成一个看起来完整但无法运行的页面。这是因为任务目标缺少约束和验收标准。正确的做法是把任务说明书当作验收单来写。下面是一份适合 agent 执行的任务说明书# 任务贪吃蛇浏览器游戏 ## 目标 构建一个可以在浏览器中直接运行的单文件贪吃蛇游戏保存为 index.html。 ## 技术约束 - 使用 HTML CSS JavaScript所有样式和脚本内联在 index.html。 - 使用 Canvas 绘制游戏区域。 - 不允许引用外部 CDN 资源离线也能运行。 - 游戏区域建议 400x400格子大小为 20px。 ## 交互要求 - 按方向键控制蛇移动方向不能直接反向。 - 蛇吃到食物后长度增加分数加 10。 - 撞到边界或自身时游戏结束。 - 游戏结束后显示重新开始按钮。 ## 验收标准 1. 打开 index.html 后 2 秒内能看到标题和游戏画布。 2. 按方向键后蛇会改变方向。 3. 食物生成位置不在地图外也不在蛇身上。 4. 分数会随吃食物增加。 5. 游戏结束时页面有明确提示。技术约束决定实现路径交互要求决定用户体验验收标准决定何时可以结束。三部分缺一不可。没有验收标准agent 会在自认为完成时输出结果但实际游戏可能连画布都是空的。4.2 从空目录到生成 index.html 的完整执行序列把上面这份任务说明书作为 user 消息输入后agent 的典型执行序列大致如下step 0: 模型调用 write_file写入 index.html 初始版本 step 1: 模型调用 run_command检查内联 JavaScript 语法 step 2: 命令返回 js syntax ok step 3: 模型调用 check_game打开页面并截图 step 4: check_game 返回 console_errors: [Uncaught TypeError: Cannot read properties of null ...] step 5: 模型根据错误修改 index.html修复 Canvas 初始化时机 step 6: 模型再次调用 check_game页面无控制台错误 step 7: 模型输出 FINAL_RESULT这个序列并不是固定不变的不同模型可能跳过某个中间步骤但核心路径是相同的生成、检查、验证、修复、再验证。如果你的 agent 一直不调用 check_game说明系统提示中的要求不够强或者工具列表没有暴露验证能力。检查内联 JavaScript 语法可以借助 Node.js 执行一段简单脚本node -e const fsrequire(fs);const htmlfs.readFileSync(index.html,utf8);const mhtml.match(/script([\s\S]*?)\/script/);if(m){new Function(m[1]);console.log(js syntax ok)}这段脚本只会做语法解析、不会真正执行游戏逻辑因此不会产生页面副作用。发现语法错误时Node 会把具体的行号和错误信息打印出来这些信息会作为工具结果回传给模型。4.3 让 Agent 输出结构化结果返回 JSON 而不是自由文本主循环判断任务是否完成的常用方式是要求模型在最后输出一个固定前缀的结构化结果而不是自由文本。这样下游流程可以方便地解析结果并触发发布动作。在 SYSTEM_PROMPT 中增加约束当游戏满足验收标准时最后一行必须输出 FINAL_RESULT: {status: success, path: index.html} 如果没有完成不要输出 FINAL_RESULT。主循环中检查该前缀if message.content and message.content.startswith(FINAL_RESULT:): print(message.content) break结构化输出的好处是可以直接对接 CI。例如agent 输出成功结果后GitHub Actions 可以自动创建一个 Pull Request把生成的 index.html 提交到发布分支。这样“agent 构建游戏”和“人工审核发布”之间就有了一个清晰的交接点。5. 把游戏发布到静态托管平台部署链路5.1 本地先跑起来验证产物agent 内部已经通过 check_game 验证过页面但发布前仍然建议在本地跑一次真实服务确认文件路径没有问题。在游戏目录启动静态服务cd workspace/game python -m http.server 8000然后访问http://localhost:8000。注意这里访问的是本地服务地址不要与任何外网地址混为一谈。人工验证的重点是页面能否打开、控制台是否报错、方向键是否生效、吃食物后分数是否增加、撞墙后是否触发结束逻辑。如果 agent 在生成时把图片或字体作为外部文件保存本地服务模式最容易暴露相对路径问题。单文件游戏把所有资源内联可以规避这一类问题这也是任务说明书里要求不引用外部 CDN 资源的原因。5.2 使用 Git 与 GitHub Pages 完成发布本地验证通过后把游戏目录初始化为 Git 仓库并推送到 GitHub。cd workspace/game git init git add index.html git commit -m feat: snake game generated by AI agent git branch -M main git remote add origin https://github.com/username/repo.git git push -u origin main推送完成后在 GitHub 仓库的 Settings 页面开启 PagesSource 选择 Deploy from a branch。Branch 选择 main。Directory 选择 / (root)。等待构建完成后通过https://username.github.io/repo/访问游戏页面。如果你没有使用 GitHub也可以把workspace/game整个目录拖到 Netlify Drop、Vercel 或 Cloudflare Pages 的静态部署入口效果类似。静态托管平台只关心目录里的 HTML 文件不关心文件是谁生成的。5.3 发布后的验证清单发布不等于交付完成。上线之后还要按下面表格逐项检查。检查项期望结果不通过时检查哪里公网 URL 能打开返回 200 且显示页面Pages 分支设置、仓库名大小写控制台无 JavaScript 错误无 Uncaught 异常把错误回传给 agent 继续修复资源加载正常无 404确认图片和字体内联或相对路径正确仓库无密钥无 .env 和明文 tokengit log 扫描历史并轮换密钥发布后的验证应该由人完成一次因为浏览器自动化和真实用户访问之间仍有差异。至少确认手机宽度下游戏可玩或者显式声明任务说明书里不要求移动端适配避免用户期待落空。6. 常见失败模式与排查链路6.1 Agent 生成了代码但游戏画面空白现象是 index.html 文件存在页面打开后是白屏或只有背景色。这个问题在 agent 生成代码时非常常见根因通常是 JavaScript 在 DOM 未加载完成时就开始执行Canvas 上下文获取失败或者某个变量未定义。排查链路如下打开浏览器控制台收集所有未捕获异常。把异常信息回传给 agent要求它根据错误定位代码。检查代码是否在脚本顶部直接操作 DOM。推荐使用DOMContentLoaded监听或把脚本放在页面底部。预防办法是在任务说明书中直接写明所有初始化逻辑必须在 DOM 就绪后执行。这个约束能减少大量白屏问题。6.2 Agent 陷入反复修改、永不退出现象是 agent 一直在调用工具反复修改同一个文件但
返回列表