news 2026/8/29 9:17:01

AI Agent自主开发浏览器游戏:从自动生成到部署上线的完整流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI Agent自主开发浏览器游戏:从自动生成到部署上线的完整流程

之前看到 “Show HN: My AI agent built and shipped a browser game on its own” 这个标题时,我的第一反应不是“AI 又能写游戏了”,而是“它到底是怎么把‘写代码、跑测试、部署上线’这一整条链路自己走完的”。因为写一个网页游戏并不难,难的是让 Agent 在无人干预的情况下,把需求变成可运行、可访问、可分享的线上产品。

这篇文章不会停留在“AI 很强大”这种感叹层面,而是完整拆解一个 AI Agent 从零到一构建并发布浏览器游戏的工程流程。内容包括:Agent 的核心工作原理解析、工具调用与执行循环设计、一个可运行的 Agent 示例代码、自动生成游戏代码的过程、自测修复、以及最后发布上线的具体步骤。

如果你正在研究 AI Agent 开发,或者想把手头重复性的“编码 + 部署”任务交给 Agent 来做,这篇文章会很适合你。

1. 背景:为什么“Agent 自主发布游戏”值得关注

1.1 从一条 Hacker News 分享说起

“Show HN” 是 Hacker News 上一个专门展示开发者作品的板块。以往大家展示的是自己亲手写的产品,而这几年开始出现一个趋势:展示 AI Agent 自主完成的项目。

“My AI agent built and shipped a browser game on its own” 这条帖子之所以能引起讨论,不是因为它展示了一个多复杂的 3D 大作,而是它证明了这样一条链路已经可以走通:

任务描述 -> 生成代码 -> 运行测试 -> 修复 Bug -> 部署上线

如果你从事开发工作,应该能感知到这件事的分量。过去一年里,AI 辅助编码已经非常普遍,但“辅助”和“自主”之间还有一条很长的路。Agent 自主发布产品,意味着它不只是你的结对编程伙伴,而是可以承担完整执行任务的“初级工程师”。

1.2 AI Agent 到底是什么

这里先做一个概念澄清。AI Agent(智能体)和普通的聊天机器人有本质区别:

  • 聊天机器人:你问它答,它只生成文本,不执行动作。
  • AI Agent:基于大语言模型(LLM)做决策,同时具备调用工具、执行命令、读取文件、访问网络等能力,并且可以在一个循环里反复执行“思考 -> 行动 -> 观察结果 -> 再思考”的流程,直到完成任务。

所以,一个能开发并发布游戏的 Agent,核心不是“会写代码”,而是“能自主完成一系列需要与环境交互的任务”。写代码只是其中一环,真正困难的是让 Agent 知道下一步该做什么、做完之后如何验证、出错之后如何检查原因。

1.3 为什么选“浏览器游戏”作为案例

浏览器游戏是一个非常合适的 Agent 自主开发实验对象:

  1. 技术栈简单:纯 HTML + CSS + JavaScript 就能跑,不需要配置复杂的后端环境。
  2. 可验证性强:游戏能不能运行、能不能计分、点击有没有反应,这些都是明确的验收标准。
  3. 部署链路短:静态文件可以直接托管到 GitHub Pages 或任意静态服务器。
  4. 反馈闭环快:代码写错后,刷新页面就能看到现象,Agent 能及时修正。

可以说,浏览器游戏是 AI Agent 开发流程的“最小可行产品”,非常适合用来理解和验证 Agent 的工作方式。

2. 核心概念:AI Agent 的自主工作流

2.1 ReAct 模式:推理与行动交替

AI Agent 的工作方式,本质上可以理解为 ReAct 模式,即 Reasoning + Acting。简单来说:

  • 推理(Reasoning):模型根据当前状态,分析“现在目标是什么,还差什么,下一步该做什么”。
  • 行动(Acting):模型调用某个工具,比如写文件、执行命令、请求 HTTP 接口。
  • 观察(Observing):工具返回结果,模型把结果纳入自己的上下文,继续下一轮推理。

这个循环会一直持续,直到 Agent 认为任务已经完成,或者触发了提前设定的停止条件。

一个典型的 Agent 执行过程可能是这样的:

步骤Agent 的思考Agent 的行动观察结果
1需要先创建游戏文件调用 write_file文件创建成功
2需要验证代码是否能运行调用 run_command 启动本地服务服务启动成功
3页面可能有 JS 报错调用 run_command 做语法检查发现第 30 行变量未定义
4需要修复这个错误调用 write_file 修改代码修改完成
5再次验证重新运行测试测试通过
6任务完成调用 publish 部署返回线上地址

可以看到,Agent 并不是“一次性生成所有代码”就结束了,它更像一个真正的开发者:写代码、验证、发现问题、修复、再验证。

2.2 Tool Use:Agent 的“手脚”

大语言模型本身只能输出文本,它之所以能操作电脑、写文件、执行命令,靠的是工具调用(Tool Use),也叫 Function Calling。

在一个 Agent 项目中,工具就是一组预先定义好的函数。每个函数需要包含:

  • 函数名称
  • 功能描述
  • 参数列表
  • 函数实现

模型在推理过程中会“决定”调用哪个工具,并给出相应的参数。然后由 Agent 框架去执行这个函数,把返回值交给模型继续分析。

下面是一个 Agent 常用工具集的设计,后续实战部分会用到:

工具作用
write_file写入或更新文件
read_file读取文件内容
list_files查看目录结构
run_command执行 shell 命令
publish部署静态站点并返回 URL

2.3 记忆与上下文管理

Agent 的“记忆”和人的记忆不太一样。它没有真正的长期记忆,所有信息都必须放进上下文中才能被模型逻辑处理。这也是 Agent 开发中最大的工程难点之一。

当 Agent 执行多轮操作后,工具返回的大量内容会把上下文窗口塞满。常见的解决办法有:

  • 截断:日志只保留末尾 N 行。
  • 摘要:把较长的历史记录提炼成简短摘要。
  • 外部检索:把文件内容存到向量数据库,需要时再取回。

在实战案例中,我们会用最朴素的方式控制上下文:限制工具返回信息长度,并设置最大迭代轮数。

3. 环境准备与工具选型

在开始写代码之前,先梳理一下需要的环境和工具。版本需要根据你的项目实际情况调整,下面以常见环境为例,重点演示配置思路。

3.1 基础环境

  • 操作系统:macOS 或 Linux 优先;Windows 用户建议使用 WSL2,避免 shell 命令兼容性问题。
  • Python:3.10 及以上版本,用于编写 Agent 主程序。
  • Node.js:18 及以上版本,部分测试工具需要。
  • Git:用于版本控制和发布。

3.2 LLM 接入方式

本文示例以 OpenAI 风格的 Chat Completions API 和工具调用格式为例。实际项目中,你可以根据自己选择的模型和 SDK 调整。关键点在于模型需要支持 Function Calling / Tool Use,因为这是 Agent 能够自主执行动作的基础。

pip install openai

3.3 游戏技术栈

为了降低 Agent 的编码难度和部署成本,游戏采用“单文件架构”:

index.html

HTML、CSS、JavaScript 全部写在同一个文件里。这样 Agent 只需要维护一个文件,从生成到部署的路径最短,对新手理解 Agent 流程也更友好。

3.4 部署目标

可以选择以下几种静态托管方式:

  • GitHub Pages:免费、支持 Git 工作流,适合展示型小游戏。
  • Netlify Drop:支持拖拽部署,也有 API 可以供 Agent 调用。
  • 自己服务器:适合有独立主机的场景,但需要更严格的安全控制。

本文实战部分以 GitHub Pages 为例,因为你只需要一个 GitHub Token,Agent 就能完成推送和发布。

4. 实战:从需求到部署的完整流程

下面我们进入完整实战。这一节我们会先定义任务,再实现一个最小可用的 Agent 系统,然后让 Agent 自动生成游戏代码、执行测试、修复问题,最后发布上线。

4.1 明确任务描述

Agent 要能自主完成任务,任务描述的清晰度非常关键。模糊的需求会让 Agent 反复猜测,浪费 token 和时间。

这里我们把任务定义为:

开发一个名叫“接苹果”(Catch Apples)的浏览器小游戏。 游戏规则: - 玩家用鼠标左右移动底部的篮子。 - 苹果从屏幕上方不断落下。 - 接住苹果得 1 分。 - 漏掉 3 个苹果,游戏结束。 - 点击“重新开始”按钮可以重新开始游戏。 验收标准: - 使用单个 index.html 文件,包含 HTML、CSS、JavaScript。 - 游戏中不能使用外部依赖。 - 页面在桌面浏览器上打开即可运行。 - 需要显示当前得分和剩余生命。 - 代码需要通过 JavaScript 语法检查。

为什么任务描述要这么细? 因为 Agent 自主开发跟团队管理很像,需求越明确,返工越少。尤其是验收标准,它给 Agent 提供了“什么时候才算完成”的判断依据,也让后续的人工审查有据可依。

4.2 实现最小 Agent 系统

接下来我们写一个简化版的 Agent 主程序。这段代码的核心思路是:在循环中让模型决定调用哪个工具,执行工具后把结果交给模型继续思考。

4.2.1 工具定义

工具函数是 Agent 能操作外部环境的桥梁。这里我们先定义几个最基础的工具。

# tools.py import os import subprocess def write_file(path: str, content: str) -> dict: """写入文件,如果目录不存在则创建。""" directory = os.path.dirname(path) if directory: os.makedirs(directory, exist_ok=True) with open(path, "w", encoding="utf-8") as f: f.write(content) return {"status": "ok", "path": path, "size": len(content)} def read_file(path: str) -> dict: """读取指定文件内容。""" try: with open(path, "r", encoding="utf-8") as f: content = f.read() return {"status": "ok", "content": content[:3000]} except Exception as e: return {"status": "error", "message": str(e)} def list_files(path: str = ".") -> dict: """列出目录下的所有文件。""" try: files = os.listdir(path) return {"status": "ok", "files": files} except Exception as e: return {"status": "error", "message": str(e)} def run_command(command: str) -> dict: """执行 shell 命令,返回 stdout 和 stderr。""" try: result = subprocess.run( command, shell=True, capture_output=True, text=True, timeout=30 ) return { "status": "ok", "returncode": result.returncode, "stdout": result.stdout[-2000:], "stderr": result.stderr[-2000:], } except subprocess.TimeoutExpired: return {"status": "error", "message": "command timeout"}

注意,这里的run_command使用了shell=True,这是为了演示方便。在实际生产项目中,直接让 Agent 以 shell 方式执行命令有相当大的安全风险,应该把命令白名单化,或者把所有执行步骤放进沙箱容器中执行。

4.2.2 Agent 主循环

下面这段代码是 Agent 的核心逻辑:

# agent_loop.py import json from openai import OpenAI # 实际使用时换成你自己的 API Key client = OpenAI(api_key="your-api-key") TOOL_SCHEMAS = [ { "type": "function", "function": { "name": "write_file", "description": "写入一个文件,用于生成或修改代码", "parameters": { "type": "object", "properties": { "path": {"type": "string", "description": "文件路径"}, "content": {"type": "string", "description": "完整文件内容"} }, "required": ["path", "content"] } } }, { "type": "function", "function": { "name": "read_file", "description": "读取文件内容", "parameters": { "type": "object", "properties": { "path": {"type": "string"} }, "required": ["path"] } } }, { "type": "function", "function": { "name": "run_command", "description": "执行 shell 命令,比如启动服务、运行测试", "parameters": { "type": "object", "properties": { "command": {"type": "string"} }, "required": ["command"] } } } ] def execute_tool_call(tool_call): """根据模型返回的工具调用,执行本地函数。""" from tools import write_file, read_file, run_command name = tool_call.function.name args = json.loads(tool_call.function.arguments) if name == "write_file": return write_file(args["path"], args["content"]) elif name == "read_file": return read_file(args["path"]) elif name == "run_command": return run_command(args["command"]) else: return {"status": "error", "message": f"unknown tool: {name}"} def run_agent(task: str, max_iterations: int = 10): """Agent 主循环:思考 -> 行动 -> 观察 -> 再思考。""" messages = [ { "role": "system", "content": ( "你是一个软件工程师 Agent。你的任务是开发一个浏览器小游戏。" "请遵循以下要求:\n" "1. 先规划,再动手。\n" "2. 每个文件写完后,都要验证。\n" "3. 出现错误时,根据报错信息修复。\n" "4. 只有验收标准全部满足,才算完成任务。" ) }, {"role": "user", "content": task} ] for step in range(max_iterations): print(f"===== Step {step + 1} =====") response = client.chat.completions.create( model="gpt-4o", messages=messages, tools=TOOL_SCHEMAS, tool_choice="auto" ) message = response.choices[0].message # 模型认为任务完成,不再调用工具 if message.tool_calls is None: print("Agent 最终回答:", message.content) return True messages.append(message) for tool_call in message.tool_calls: print(f"调用工具: {tool_call.function.name}") print(f"参数: {tool_call.function.arguments}") result = execute_tool_call(tool_call) print(f"工具返回: {json.dumps(result, ensure_ascii=False)[:500]}") messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": json.dumps(result, ensure_ascii=False) }) print("达到最大迭代次数,任务可能未完成。") return False if __name__ == "__main__": task = """ 开发一个名叫“接苹果”(Catch Apples)的浏览器小游戏。 游戏规则: - 玩家用鼠标左右移动底部的篮子。 - 苹果从屏幕上方不断落下。 - 接住苹果得 1 分。 - 漏掉 3 个苹果,游戏结束。 - 点击“重新开始”按钮可以重新开始游戏。 验收标准: - 使用单个 index.html 文件,包含 HTML、CSS、JavaScript。 - 游戏中不能使用外部依赖。 - 页面在桌面浏览器上打开即可运行。 - 需要显示当前得分和剩余生命。 - 代码需要通过 JavaScript 语法检查。 """ run_agent(task)

这是一个非常精简的 Agent 实现。它没有记忆压缩,没有复杂的规划模块,也没有并发执行能力,但它具备了一个 Agent 最核心的能力:能够循环调用工具来改变环境,并通过观察环境反馈来修正下一步动作。

在实际项目中,你可能不会直接使用这种“手写循环”的方式,而是使用 LangChain、AutoGPT、或各种 Agent 框架。但理解这个最小循环的原理,对排查框架里的问题非常有帮助。

4.3 Agent 自动生成游戏代码

当 Agent 收到任务后,它第一步通常是将游戏核心代码写入index.html。以下是 Agent 经过几轮迭代后生成的一个可运行版本,代码里已经包含了我们要求的计分、生命、碰撞检测和重新开始功能。

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>接苹果(Catch Apples)</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: #1a1a2e; font-family: Arial, sans-serif; } #game-wrapper { text-align: center; } canvas { border: 2px solid #e94560; border-radius: 8px; background: #16213e; cursor: pointer; } #hud { color: #eee; margin-bottom: 8px; font-size: 18px; display: flex; justify-content: space-between; } #restart-btn { margin-top: 12px; padding: 8px 20px; font-size: 16px; background: #e94560; color: #fff; border: none; border-radius: 6px; cursor: pointer; } #restart-btn:hover { background: #c73652; } </style> </head> <body> <div id="game-wrapper"> <div id="hud"> <span>得分: <span id="score">0</span></span> <span>生命: <span id="lives">3</span></span> </div> <canvas id="game" width="480" height="640"></canvas> <br> <button id="restart-btn">重新开始</button> </div> <script> const canvas = document.getElementById('game'); const ctx = canvas.getContext('2d'); const scoreEl = document.getElementById('score'); const livesEl = document.getElementById('lives'); const restartBtn = document.getElementById('restart-btn'); let score = 0; let lives = 3; let gameOver = false; let lastTime = 0; let appleSpawnInterval = 0; let keyPressed = false; const basket = { width: 80, height: 20, x: canvas.width / 2 - 40, y: canvas.height - 40 }; const apples = []; function resetGame() { score = 0; lives = 3; gameOver = false; apples.length = 0; appleSpawnInterval = 0; updateHUD(); } function updateHUD() { scoreEl.textContent = score; livesEl.textContent = lives; } function spawnApple() { const x = Math.random() * (canvas.width - 24); apples.push({ x: x, y: 0, size: 16, speed: 120 + Math.random() * 80 }); } function drawBasket() { ctx.fillStyle = '#f5c542'; ctx.fillRect(basket.x, basket.y, basket.width, basket.height); ctx.fillStyle = '#d49b2a'; ctx.fillRect(basket.x + 10, basket.y + basket.height, basket.width - 20, 6); } function drawApple(apple) { ctx.beginPath(); ctx.arc(apple.x + apple.size / 2, apple.y + apple.size / 2, apple.size / 2, 0, Math.PI * 2); ctx.fillStyle = '#e94560'; ctx.fill(); } function drawGameOver() { ctx.fillStyle = 'rgba(0, 0, 0, 0.6)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#ffffff'; ctx.font = '36px Arial'; ctx.textAlign = 'center'; ctx.fillText('游戏结束', canvas.width / 2, canvas.height / 2 - 10); } function update(deltaTime) { if (gameOver) return; // 生成新苹果 appleSpawnInterval += deltaTime; if (appleSpawnInterval > 1.2) { appleSpawnInterval = 0; spawnApple(); } // 移动苹果 for (let i = apples.length - 1; i >= 0; i--) { const apple = apples[i]; apple.y += apple.speed * deltaTime; // 判断是否被篮子接住 if ( apple.y + apple.size >= basket.y && apple.y + apple.size <= basket.y + basket.height + 10 && apple.x + apple.size >= basket.x && apple.x <= basket.x + basket.width ) { score++; apples.splice(i, 1); updateHUD(); continue; } // 判断是否落地 if (apple.y > canvas.height) { apples.splice(i, 1); lives--; updateHUD(); if (lives <= 0) { gameOver = true; drawGameOver(); return; } } } } function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); drawBasket(); for (const apple of apples) { drawApple(apple); } if (gameOver) { drawGameOver(); } } function gameLoop(timestamp) { const deltaTime = Math.min((timestamp - lastTime) / 1000, 0.05); lastTime = timestamp; update(deltaTime); draw(); requestAnimationFrame(gameLoop); } // 鼠标移动篮子 canvas.addEventListener('mousemove', (e) => { const rect = canvas.getBoundingClientRect(); const mouseX = e.clientX - rect.left; basket.x = mouseX - basket.width / 2; basket.x = Math.max(0, Math.min(canvas.width - basket.width, basket.x)); }); // 重新开始 restartBtn.addEventListener('click', () => { resetGame(); }); resetGame(); requestAnimationFrame(gameLoop); </script> </body> </html>

这是 Agent 自动生成代码的典型结果。你会发现它并不是特别复杂,但逻辑完整,能运行,也符合验收标准。

需要说明的是,这里展示的是最终“接近可运行”的版本。真实执行过程中,Agent 可能第一版会漏掉“生命值”“游戏结束”等功能,也可能出现苹果碰撞检测逻辑不准的情况。这些都会在后面的“自动修复”环节被逐一解决。

4.4 让 Agent 自测与修复

生成代码只是第一步,更重要的是验证和修复。

Agent 的验证通常分几个层次:

  1. 语法检查:用node --check检查 JS 语法。
  2. 本地运行:启动一个静态服务。
  3. 浏览器冒烟测试:用 Playwright 等工具访问页面,检查控制台错误。
  4. 行为测试:模拟鼠标移动,判断游戏能否执行关键交互。

下面是一条典型的 Agent 验证命令:

node --check index.html

不过node --check只能检查独立 JS 文件,不能直接检查 HTML 内嵌的<script>块。实际项目中,Agent 会把脚本提取成临时 JS 文件再检查,或者使用 Playwright 加载页面。

下面是一个用 Node.js 脚本做简单冒烟测试的示例:

// smoke_test.js const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const page = await browser.newPage(); const errors = []; page.on('pageerror', error => errors.push(error.message)); page.on('console', msg => { if (msg.type() === 'error') { errors.push(msg.text()); } }); await page.goto('http://localhost:8000/index.html'); await page.waitForTimeout(2000); // 模拟鼠标移动 const canvas = await page.$('#game'); const box = await canvas.boundingBox(); await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2); await page.waitForTimeout(1000); const scoreText = await page.textContent('#score'); console.log('当前得分:', scoreText); console.log('控制台错误:', errors.length ? errors : '无'); await browser.close(); if (errors.length > 0) { process.exit(1); } })();

运行方式:

npm init -y npm install playwright node smoke_test.js

如果 Agent 在冒烟测试中发现了问题,比如“苹果碰撞检测不生效”或“点击重新开始按钮后分数没有重置”,它会把报错信息或者测试失败信息重新拼进 prompt,再调用write_file修复代码,然后再次运行测试。这个循环会一直继续,直到测试通过。

这就是 Agent 自主开发的“反馈闭环”。它是整个系统中最有工程价值的部分。

4.5 发布上线

本地测试通过后,Agent 需要把游戏发布到线上。以 GitHub Pages 为例,发布流程如下:

  1. 初始化 Git 仓库。
  2. 创建并提交index.html
  3. 推送到远程仓库的main分支或gh-pages分支。
  4. 通过仓库设置开启 GitHub Pages。

Agent 可以自动执行这些命令,但你需要提前准备好一个有仓库创建权限的 GitHub Token。注意:这里的 Token 应该只授予最小权限,并且用作环境变量,不能写死在代码里。

# 初始化仓库 git init git add index.html git commit -m "feat: catch apples game generated by AI agent" # 添加远程仓库 git remote add origin https://github.com/yourname/catch-apples.git git branch -M main # 推送代码 git push -u origin main

推送完成后,在 GitHub 仓库的 Settings -> Pages 中把 Source 设置为Deploy from a branch,分支选择main,目录选择/root

稍等片刻,游戏就能通过以下地址访问:

https://yourname.github.io/catch-apples/

Agent 拿到这个 URL 后,会再次通过 HTTP 请求验证页面是否正常返回 200 状态码。确认无误后,Agent 才会在最终回复中告诉人类:任务已完成,并附上线上地址。

这里要特别提醒:在生产环境发布时,建议先发布到测试路径或者使用独立域名验证,确认无误后再切换到正式入口。尤其是自动发布的流程一旦跑起来,必须有回滚方案。

5. 常见问题与排查思路

AI Agent 自主开发虽然看起来很流畅,但实际运行时几乎必然会遇到各种问题。下面是一些高频问题和对应的排查经验。

问题现象常见原因解决思路
Agent 陷入无限循环缺少最大迭代次数限制设置max_iterations,超时强制停止
生成了代码但无法运行模型“幻觉”或依赖未安装把运行时报错信息回传给模型继续修复
上下文窗口被塞满工具返回日志太长截断工具输出,或使用摘要压缩历史
Node 命令找不到环境变量未配置在 prompt 中写明 Node 的安装路径
部署到 GitHub Pages 失败Token 权限不足或仓库设置错误检查 Token 权限,使用最小权限原则
页面打开后空白JS 运行时错误用 Playwright 做冒烟测试,捕获 console error
Agent 修改了无关文件工具调用边界不清晰在工作目录中创建独立沙箱文件夹
API 调用超时请求耗时过长增加超时时间,并做重试机制

下面展开说明两个最常见问题的排查思路。

5.1 Agent 陷入死循环怎么办

现象:Agent 反复执行同一个操作,比如反复写入同一个文件,或者反复运行同一条测试命令,但结果没有任何变化。

排查步骤

  1. 检查 Agent 日志,看它在循环中的“推理”内容是否相同。
  2. 如果模型每次都说“我再试一次”,说明它无法从当前状态中找到有效手段。
  3. 检查工具返回是否包含足够信息。如果测试命令只返回“fail”,没有具体报错,模型就只能盲猜。
  4. 提高工具返回的信息质量:把 stderr、退出码、关键日志都返回给 Agent。

解决方案:除了设置最大迭代次数,还要优化工具输出。一个原则是:工具返回的信息要足够让模型判断“为什么失败”,否则修复循环就无从谈起。

5.2 部署后页面空白

现象:GitHub Pages 返回 200,但浏览器打开后是空白页。

排查步骤

  1. 按 F12 打开开发者工具查看 Console 面板,定位 JS 报错。
  2. 检查文件路径。如果使用了相对路径或外部资源,部署环境可能无法加载。
  3. 检查脚本中是否使用了浏览器不支持的 API。
  4. 在本地把部署目录用服务跑起来,对比线上表现。

解决方案:在 Agent 的验收标准中强制加入“冒烟测试”环节,用 headless 浏览器访问部署后的 URL,并检查控制台是否有 error。这样可以在上线前就发现问题。

6. 最佳实践与工程建议

经历了“让 Agent 开发并发布一个游戏”的完整流程后,有几个工程上的经验很值得沉淀下来。

6.1 任务描述必须包含验收标准

如果你只告诉 Agent “写一个游戏”,它可能会写出各种你没想到的功能,但偏偏缺了你最想要的那一个。更好的做法是像 4.1 节那样,把规则、操作方式、验收标准全部写清楚。

验收标准的作用有两个:

  • 给 Agent 一个明确的“完成”定义,让它知道何时停止。
  • 给人工审查提供一个检查清单,方便确认 Agent 没有“自欺欺人”。

6.2 坚持“Agent 生成、人工审查、自动化测试”三件套

即使 Agent 能自主完成整个流程,也不建议完全无人审核。尤其是涉及到线上发布时,一位有经验的开发者做最后 review,能拦截大部分模型“自认为正确但实际错误”的问题。

推荐的流程是:

  1. Agent 在分支或沙箱环境中生成代码并自测。
  2. 人工审查代码变更,检查安全问题。
  3. 自动化测试跑一遍关键路径。
  4. 合并代码并自动部署。

6.3 安全边界:给 Agent 一个沙箱

如果 Agent 能执行 shell 命令,那么它理论上也能执行任何命令,包括删除文件、获取环境变量、访问网络。因此在正式环境中,必须限制 Agent 的执行范围:

  • 使用 Docker 容器运行 Agent,容器内不挂载宿主机敏感目录。
  • 在容器外提供文件读写接口,而不是直接给 shell。
  • run_command改成命令白名单方式,比如只允许执行nodegitpython3 -m http.server
  • 严禁 Agent 直接接触生产数据库或生产服务器,涉及生产变更必须走 CoPilot(人审流程)机制。

6.4 每一次工具调用都要留日志

Agent 开发过程的可追溯性非常重要。记录每次工具调用、参数、返回结果、耗时,能够帮你:

  • 定位是哪一步出了问题。
  • 复盘 Agent 的决策路径,优化 prompt。
  • 评估 token 消耗和成本。

一个最小日志结构可以是 JSON 格式:

{ "step": 3, "tool": "run_command", "args": { "command": "node --check script.js" }, "result": { "returncode": 0, "stdout": "", "stderr": "" }, "timestamp": "2025-01-12T10:30:00Z" }

6.5 控制上下文,避免 Token 爆炸

Agent 写游戏这种小项目时上下文压力不大,但如果项目变大,就需要引入“摘要 + 检索”的机制。例如:

  • 让 Agent 先列出项目结构,只读取需要修改的文件。
  • 工具返回内容限制在 2000 字符以内。
  • 对已经完成的历史对话做摘要,压缩到几百字符。

这样既能保持 Agent 对全局的感知,又能控制成本。

6.6 不管用什么框架,核心都是“任务拆解 + 反馈闭环”

目前市面上的 Agent 框架很多,有的是“计划 + 执行”架构,有的是“多 Agent 协作”架构。但剥开外壳,所有 Agent 的核心能力都离不开:

  • 理解目标并拆解成步骤。
  • 调用工具改变环境。
  • 观察结果并调整策略。

理解了这一点,你就能很快上手任何框架,也能在框架出问题时定位到具体环节。

7. 总结与下一步方向

通过这篇文章,我们从概念到实战完整走了一遍 AI Agent 自主开发并发布浏览器游戏的流程。

现在你应该已经理解:

  • AI Agent 不只是聊天机器人,它是一个具备“规划 + 工具调用 + 环境反馈”能力的自主系统。
  • Agent 开发游戏的过程不是“一次生成”,而是“写代码 -> 验证 -> 报错 -> 修复 -> 再验证”的循环。
  • 一个最小 Agent 系统可以由几行核心代码实现,关键点在工具设计和执行循环。
  • 自动发布不是不能做,但必须在安全边界内操作,并保留人工审查和回滚机制。

如果你打算继续深入,我建议按以下路线学习:

  1. 先手写一个更完善的 Agent 循环,加入记忆压缩、命令白名单、日志记录。
  2. 尝试接入不同模型,观察它们调用工具和修复 Bug 的差异。
  3. 让 Agent 开发一个带后端接口的小应用,比如“留言板”,这会引入数据库和服务器部署的问题。
  4. 学习 LangChain、AutoGPT、LangGraph 等框架,了解它们在任务规划和多步骤执行上做了哪些优化。
  5. 如果你想在企业里落地,重点关注权限控制、审计日志、测试覆盖率和回滚机制,这比模型本身的“聪明程度”更重要。

AI Agent 自主开发的能力每天都在变强。但有一点不会变:它能走多远,很大程度上取决于我们给它设计的工作流边界是否清晰、反馈回路是否高效。希望这篇实战笔记能帮助你迈出第一步,亲手搭一个属于自己的 Agent 开发流水线。

如果你按照流程跑通了自己的小游戏,欢迎在评论区交流过程中踩过的坑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 9:14:51

Kotlin object是懒汉还是饿汉?拆解单例实现机制与JVM初始化真相

上个月面了一个做 Android 的候选人&#xff0c;项目经历里把 Kotlin 写得很熟练&#xff0c;聊到单例的时候我随口问了句&#xff1a;“Kotlin 的 object 声明是懒汉还是饿汉&#xff1f;”他明显愣了一下&#xff0c;然后开始背&#xff1a;object 在类加载时初始化&#xff…

作者头像 李华
网站建设 2026/8/29 9:14:37

DAC数模转换器原理与应用:从权电阻网络到实战波形发生器

1. 从数字到模拟&#xff1a;DAC究竟在做什么&#xff1f; 如果你玩过单片机或者FPGA&#xff0c;肯定对GPIO口输出高电平&#xff08;3.3V或5V&#xff09;和低电平&#xff08;0V&#xff09;再熟悉不过了。这就是数字世界的语言&#xff0c;非0即1&#xff0c;非黑即白。但现…

作者头像 李华
网站建设 2026/8/29 9:10:53

Archer OS:AI Agent在操作系统授权下的应用操作规范草案

今天要聊一个偏向系统层面的 AI Agent 架构草案&#xff1a;Archer OS。标题写得很直白——draft spec for AI agents operating apps under OS authority&#xff0c;意思是“让 AI 智能体在操作系统授权下操作应用的规范草案”。它不是大模型权重&#xff0c;不是 RPA 工具&a…

作者头像 李华
网站建设 2026/8/29 9:10:46

【单片机毕业设计】基于 STM32 单片机的消防隐患自动监测与设备联动方案设计 基于 STM32 的室内环境安防监测及机电联动控制系统开发(012605)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/8/29 9:10:17

后端技术栈更新迭代,如何保持学习节奏而不焦虑

凌晨两点&#xff0c;你的朋友圈里有人晒出刚读完的《Kubernetes 权威指南》&#xff0c;有人炫耀用 Rust 重写了消息队列&#xff0c;还有人转发着“AI 将取代程序员”的爆款文。你关掉手机&#xff0c;想起自己连 Spring Boot 3 的新特性都还没搞明白&#xff0c;顿时睡意全无…

作者头像 李华
网站建设 2026/8/29 9:09:25

nPM3104 PMIC深度解析:小电池产品电源设计的关键

做低功耗物联网产品这几年&#xff0c;我最大的体会是&#xff1a;很多时候产品翻车&#xff0c;不是死在无线链路&#xff0c;而是死在电源。Nordic Semiconductor 这次发布的 nPM3104 Power Management IC&#xff0c;来得正是时候。它面向小型电池产品&#xff0c;核心卖点就…

作者头像 李华