使用 Google Antigravity 进行构建

1. 简介

Google Antigravity(在本文档的其余部分中称为 Antigravity)是 Google 推出的智能体 IDE。在 Antigravity 入门 Codelab 中,您可以学习 Antigravity 的基础知识。在此 Codelab 中,我们将使用 Antigravity 构建实际应用。我们将从简单的网络研究过渡到生成全栈应用和企业级单元测试。

前提条件

2. 关于使用情形

既然您已对 Antigravity 有了基本的了解,不妨深入了解几个使用场景,看看它在实际应用中的表现。请注意,Antigravity 是一个以智能体为主的平台。这意味着,在大多数情况下,我们只是向代理发出指令,然后代理自行完成任务,在需要时请求权限,生成制品,并在任务完成后通知我们。因此,我们无法在以下每种使用情形中生成代理对话的每个输出。我们会分享相关说明和一些必要的结果预期屏幕截图,但您的结果可能会略有不同。

我们将介绍的应用场景包括:自动执行与外部网站相关的一些任务、为项目生成和验证单元测试用例,以及完整的网站开发。出发吧。

3. 新闻集锦

这是一个简单的使用情形,但它可以作为基础,让您使用网络浏览器访问网站、提取信息、执行一些操作,然后将数据返回给用户。

在这种情况下,我们将访问 Google 新闻网站并从中提取一些信息。不过,您可以轻松地选择一个网站进行实验,看看效果如何。

确保您位于 Agent Manager 中,并已选择 Playground,如下所示:

cffa12c98a68cb6c.png

然后,给出以下指令:

8513d489eea0b014.png

这会启动代理进程,并确定需要启动浏览器等。您应密切关注思考过程,了解代理如何开展工作。如果一切顺利,它应该会启动 Antigravity 浏览器并访问相应网站,如下所示。网站周围的蓝色边框表示代理正在控制浏览器并浏览网站以获取信息。

9d594588f2ffe6bc.png

完成工作后,您还应该会看到工件正在生成,如下所示:

dc6cf4e7d8425df8.png

下面展示了代理的执行示例:

fb7397cd2cce0682.png

请注意,左侧是“思路”,您还可以滚动浏览各个点,查看播放情况和其他数据。

尝试以下任务

  • 了解这一点后,选择一个可访问的网站,您希望代理前往该网站并从中获取/总结一些数据。考虑某个您知道包含信息中心和图表的网站,并让 Gemini 从中选择一些值。
  • 不妨试试以下提示:Visit https://docs.cloud.google.com/release-notes and get me a summary of the release notes, categorized by product.

4. 使用 Python + Flask 生成动态网站

现在,我们来生成一个完整的 Web 应用。我们将要创建的 Web 应用是一个网站,其中包含有关为期 1 天的技术活动的信息,该活动全天都有多位演讲者进行演讲。

再次确保您位于 Agent Manager 中,并且已选择 Playground

输入以下提示:

I would like to generate a website that is a 1-day technical conference informational site.

The website should have the following functionality:
        1. A home page that shows the current date, location, schedule and time table.
        2. The 1-day event is a list of 8 talks in total.
        3. Each talk has 1 or 2 max. speakers. 
        4. A talk has an ID, Title, Speakers, Category (1 or 2), Description and time of the talk.
        5. Each speaker has a First Name, Last Name and LinkedIn url.
        6. Allow for users to search by category, speaker, title.
        7. Give a lunch break of 60 minutes.
        8. Use dummy data for events and speakers, come up with a schedule, the event is about Google Cloud Technologies.
        9. Tech Stack: Python and Flask framework on server side. Front-end is basic HTML, CSS and JavaScript. 
        10. Test out the site on your own for all functionality and provide a detailed README on how to setup, run and make any further changes. 
11. Launch the web application for me to review. 

您可以先给出上述提示,开始对话:

当代理执行任务时,它会继续创建工件:

  • 任务制品
  • 实现工件
  • 演示制品

以下任务制品是代理根据分配给它的任务破译出的初始任务序列。执行后的示例屏幕截图如下所示:

c95d82e1c040698f.png

然后,您可以点击实施计划制品。示例屏幕截图如下所示:

632169a236bc62cc.png

最后,您会获得 Walkthrough 制品。它包含智能体执行的所有操作,如下所示:

e3f6152d6f54d4f9.png

请注意,它已启动服务器并向我提供了网址,我点击该网址后即可访问应用,下面显示了示例屏幕截图:

abf879f2ce53d055.png

如果我切换到编辑器,请注意屏幕中包含生成 Python Flask 应用的文件夹。您还会注意到,右侧标记了 Agent mode,您也可以在那里继续对话。

b0fea8aa65c3a1c5.png

现在,假设我们要为活动添加更多讲座。我们可以留在编辑器和代理面板中,然后给出类似 Add two more talks to the schedule 的指令。

这样一来,代理将分析要求、更新任务和实施方案,然后验证更新后的功能。以下是对话示例:

ba8455e6f68973e9.png

如果您愿意,可以切换回代理管理器。此流程应有助于您了解从代理管理器切换到编辑器、相应地进行更改等过程。

尝试以下任务

  • 向应用添加您需要的其他功能。向代理提供详细信息,并注意它如何完成任务,首先修改任务列表,然后修改实施方案,依此类推。
  • 让智能体为应用生成 README 或更多文档。

5. 生成简单的效率类应用

接下来,我们将生成一个简单的番茄工作法计时器 Web 应用。

确保您位于 Agent Manager 中,并且已选择 Playground。输入以下提示:

Create a productivity app that features a Pomodoro timer. Give a calm and aesthetic look to the application.

请注意,它会先创建任务列表和实施方案,然后再执行这些任务。请继续关注流程,在某些情况下,系统可能会提示您进行检查。运行示例见下文。

5be0a668e5a67d85.png

在这种情况下,它还应启动 Antigravity 浏览器,进行自己的测试,然后确认测试成功。它生成的内容之一是包含验证视频的媒体制品。这样可以清楚地了解测试内容。我还建议进行一些样式更改,因为之前未生效,而现在可以生效。

最终的应用如下图所示,效果相当不错。

c9ab6bca97a51a8c.png

我们可以在应用中添加一个漂亮的计时器图片。我们只需发出如下后续指令:

Add an image to the application that displays a timer.

这导致代理向任务制品添加了一个新任务:

498dd946d4e9ae55.png

然后,在执行任务的过程中生成了一张图片:

c291da9bdb37ff96.png

最后,应用显示了我们请求的图片:

de8f418ba8e4600d.png

尝试以下任务

  • 请注意,应用中沙漏图标的背景不是透明的。不妨尝试让代理将此内容设为透明。
  • 尝试生成您想要的任何申请的几种变体。尝试不同的样式和图片,要求进行更改等。

6. 生成单元测试、模拟桩和验证测试

我们将在此处尝试的最后一个使用情形是,为我们拥有的特定代码文件生成单元测试,并让代理执行测试并验证测试结果。

为此,我们将创建一个包含单个 Python 文件的工作区,如下所示:

from typing import Dict

# --- Custom Exceptions ---
class InventoryShortageError(Exception):
    """Raised when there is not enough item stock."""
    pass

class PaymentFailedError(Exception):
    """Raised when the payment gateway rejects the transaction."""
    pass

class InvalidOrderError(Exception):
    """Raised when the order violates business rules."""
    pass

# --- External Service Interfaces (To be Mocked) ---
class InventoryService:
    def get_stock(self, product_id: str) -> int:
        """Connects to DB to check stock."""
        raise NotImplementedError("Real connection required")

    def decrement_stock(self, product_id: str, quantity: int):
        """Connects to DB to reduce stock."""
        raise NotImplementedError("Real connection required")

class PaymentGateway:
    def charge(self, amount: float, currency: str) -> bool:
        """Connects to Stripe/PayPal."""
        raise NotImplementedError("Real connection required")

# --- Main Business Logic ---
class Order:
    def __init__(self, 
                 inventory_service: InventoryService, 
                 payment_gateway: PaymentGateway,
                 customer_email: str,
                 is_vip: bool = False):
        
        self.inventory = inventory_service
        self.payment = payment_gateway
        self.customer_email = customer_email
        self.is_vip = is_vip
        self.items: Dict[str, Dict] = {} # {product_id: {'price': float, 'qty': int}}
        self.is_paid = False
        self.status = "DRAFT"

    def add_item(self, product_id: str, price: float, quantity: int = 1):
        """Adds items to the cart. Rejects invalid prices or quantities."""
        if price < 0:
            raise ValueError("Price cannot be negative")
        if quantity <= 0:
            raise ValueError("Quantity must be greater than zero")

        if product_id in self.items:
            self.items[product_id]['qty'] += quantity
        else:
            self.items[product_id] = {'price': price, 'qty': quantity}

    def remove_item(self, product_id: str):
        """Removes an item entirely from the cart."""
        if product_id in self.items:
            del self.items[product_id]

    @property
    def total_price(self) -> float:
        """Calculates raw total before discounts."""
        return sum(item['price'] * item['qty'] for item in self.items.values())

    def apply_discount(self) -> float:
        """
        Applies business logic:
        1. VIPs get flat 20% off.
        2. Regulars get 10% off if total > 100.
        3. No discount otherwise.
        """
        total = self.total_price
        
        if self.is_vip:
            return round(total * 0.8, 2)
        elif total > 100:
            return round(total * 0.9, 2)
        
        return round(total, 2)

    def checkout(self):
        """
        Orchestrates the checkout process:
        1. Validates cart is not empty.
        2. Checks stock for all items.
        3. Calculates final price.
        4. Charges payment.
        5. Updates inventory.
        """
        if not self.items:
            raise InvalidOrderError("Cannot checkout an empty cart")

        # 1. Check Inventory Logic
        for product_id, data in self.items.items():
            available_stock = self.inventory.get_stock(product_id)
            if available_stock < data['qty']:
                raise InventoryShortageError(f"Not enough stock for {product_id}")

        # 2. Calculate Final Price
        final_amount = self.apply_discount()

        # 3. Process Payment
        try:
            success = self.payment.charge(final_amount, "USD")
            if not success:
                raise PaymentFailedError("Transaction declined by gateway")
        except Exception as e:
            # Catching generic network errors from the gateway
            raise PaymentFailedError(f"Payment gateway error: {str(e)}")

        # 4. Decrement Stock (Only occurs if payment succeeded)
        for product_id, data in self.items.items():
            self.inventory.decrement_stock(product_id, data['qty'])

        self.is_paid = True
        self.status = "COMPLETED"
        
        return {"status": "success", "charged_amount": final_amount}

确保您已将上述 Python 文件本地保存在文件夹中,并将其作为 Antigravity 中的工作区加载。

这是一个简单的 Order 服务,在 checkout 函数中具有以下关键功能:

  1. 验证购物车是否不为空。
  2. 检查所有商品的库存。
  3. 计算最终价格。
  4. 扣款。
  5. 更新商品目录。

我们将为代理分配生成单元测试用例、提供模拟实现和执行测试的任务,以确保测试成功。

我们将打开特定的工作区文件夹,您会注意到,我们现在也可以使用 @ 符号来引用该文件。例如,我们可以执行以下操作:

8368856e51a7561a.png

系统会显示一些有关此文件的说明:

b69c217d3372d802.png

我们可以通过提示让它生成更好的可视化图表:

Can you visually show this class for better understanding

da5bd701323818d4.png

下一步是生成单元测试,并让代理进行测试。我输入了以下提示:

generate unit tests for this module and test it out with mock implementations.

它生成了以下任务制品,并开始执行任务。

21425379db336dc6.png

您还可以查看其运行的测试的详细信息:

48f3320cd76b5cd8.png

它生成的文件之一也是测试文件。其屏幕截图如下所示:

f962061f115c040f.png

尝试以下任务

使用您自己的代码,看看您可以让智能体做些什么,从添加更多功能到重构部分代码,应有尽有。

7. 恭喜

恭喜!您已成功使用 Google Antigravity 完成以下操作:

  • 自主研究网络。
  • 构建和迭代全栈 Web 应用。
  • 生成素材资源并优化界面美观度。
  • 使用模拟对象编写和验证复杂的单元测试。

现在,您已经准备好让 Antigravity 在您自己的项目中承担繁重的工作了。

参考文档