如何使用人工智能构建Solana应用程序

  • Helius
  • 发布于 1天前
  • 阅读 46

本文探讨了人工智能(AI)在Solana开发中的应用,揭示了Solana独特架构对AI的挑战。文章提供了有效使用AI的策略,包括优化提示、提供上下文、逐步开发和迭代,提高代码的质量和效率。

15分钟阅读

2025年1月20日

人工智能 (AI) 正在改变我们构建软件的方式 . 它可以发现和修复bug,快速生成新功能,并处理一些我们不想做的琐事。像 Copilot 和 Cursor 这样的工具使得编程更快且不那么繁琐。但是,它们在与 Solana 一起工作时并不总是能很好地运行。

Solana 的架构 将其与大多数区块链区分开来 . 它并行处理交易,依赖账户而不是合约拥有状态,并使用程序派生地址 (Program-Derived Addresses, PDAs) 来增加安全性。如果你阅读了我们的博客文章,你会知道 在 Solana 上构建是与以太坊不同的。Solana 提供高吞吐量,并且在账户管理方面有独特的方法。这种区别常常会让在不同编码模式下训练的 AI 模型感到困惑。

本文将探讨 AI 为什么有时在 Solana 上遇到困难。它还将提供解决这些问题的方法。我们的主要关注点将是:

  • 提示工程:为 AI 编写更好的指令。
  • 上下文输入:提供你的项目细节,使 AI 输出更准确。
  • 迭代工作流程:分阶段构建代码。在继续之前检查和改进。

无论是新手还是有经验的人,这些建议都将帮助你在 Solana 上工作时获得更多 AI 的帮助。

Solana 开发中 AI 面临的挑战

Solana 的独特架构和要求可能会给 AI 带来问题。如果 AI 没有考虑到这些因素,你将浪费时间调试代码或重写程序,这违背了使用 AI 简化开发的目的。

Solana 的独特架构

Solana 主要在三个方面与众不同:

1. 基于账户的模型

许多区块链,如以太坊,将数据直接绑定到智能合约的内部存储。相反,Solana 的编程模型 将一切组织围绕 “账户”。这些账户保存数据,而“程序”(Solana 的智能合约等价物)修改和与这些数据交互。

一个关键区别在于在 Solana 上,所有内容都是一个账户,甚至程序本身也是如此。程序仅仅是存储可执行数据的账户,这使得它们能够处理指令。相比之下,以太坊在外部拥有的账户 (EOA),由私钥控制,以及智能合约之间有自己的代码和内部存储。

这个根本差异可能会导致误解,尤其是在为 Solana 编写代码时。与以太坊智能合约一样,不熟悉账户模型的开发者可能会错误地假设一个程序可以拥有其数据。这种假设可能导致运行时错误或安全漏洞,当在 Solana 上部署时。

2. 程序派生地址 (PDAs)

程序派生地址 (PDA) 是由程序 ID 和种子创建的。PDAs 使程序能够组织账户,而不需要私钥。然而,AI 模型可能看不出标准地址和 PDA 之间的区别。如果它们忘记处理种子或检查所有权,则 PDA 的 Rust 代码将是正确的,但却不是正确的 Solana 代码。

3. 并行执行

Solana 的运行时 Sealevel 使它能够并行处理交易,而不是传统区块链一笔一笔地处理交易。这是因为交易明确指定了它们将读取和写入的账户。通过这些信息,Solana 能够确定需要哪些账户锁定,从而安全地同时执行许多交易。

AI 常常误解这个模型。它可能假设交易将按顺序运行,就像在以太坊虚拟机(EVM)中一样。这可能导致代码未能优化并行性。由于 Solana 的基于账户的锁定系统与 EVM 的方法不同,AI 可能会编写表现不佳或无法扩展的代码。

常见痛点

开发者在使用 AI 构建 Solana 应用时会面临一些反复出现的问题:

1. 代码不正确

AI 可能会提供在 Rust 中编译正常但在你将其部署到 Solana 时失败的功能。例如,AI 配对编程工具可能忽略签名者或错误解释账户引用。结果是?你只有在运行测试、实际交易或完成安全审核时才能发现的 bug 或 安全漏洞

2. 代码不够优化

即使 AI 生成的代码有效,也可能没有被 优化为计算单位,导致交易处理缓慢,或者引入无法察觉的瓶颈。想象一下,AI 编写一个逐个更新账户的函数。它没有意识到,如果实现得当,Solana 可以同时处理它们。

3. 调试困难

AI 模型不知道你的文件夹结构或者你如何定义自定义数据类型,除非你告诉它。这意味着它们可能提出与现有设置发生冲突的解决方案,而将这些解决方案合并进你的项目可能会变得麻烦。

如何在 Solana 开发中使用 AI

遵循以下建议,用 AI 构建 Solana 应用:

1. 开始时设定明确的系统提示

系统提示就像是 AI 的工作描述。它告诉 AI 其角色(例如," 你是一个在使用 Anchor 的 Solana 编程方面的专家...“)并概述你希望它遵循的规则。

以下是一个典型示例,稍作扩展:

代码

## 你是 Solana 程序开发的专家。
专注于使用 Rust 和 Anchor 构建和部署智能合约,
以及与 @solana/web3.js 集成链上数据。

---

### 一般指引
- 为 Solana 程序编写安全、高效且可维护的代码。
- 在部署之前彻底测试和审核所有程序。

### 使用 Rust 和 Anchor 的 Solana 程序开发
- 优先考虑 Rust 的安全性和性能。
- 使用 Anchor 宏简化账户管理、错误处理和数据序列化。
- 保持代码模块化,并清晰区分逻辑和数据。

### 安全和最佳实践
- 强制实施严格的访问控制–确保只有被允许的签名者能够修改数据。
- 负责任地使用 PDA:验证种子和所有权检查以防止冲突。

### 性能和优化
- 通过有效地打包操作来最小化交易成本。
- 利用并行处理–不要不必要地串行化步骤。
- 定期对代码进行基准测试,以发现并移除性能瓶颈。
为什么它有效

一个写得好的系统提示就像一个蓝图–它使 AI 与 Solana 的架构保持一致。这确保每个响应都是准确、安全,并且符合你的需求。

  1. 设定正确的上下文:将 AI 声明为“Solana 专家”确保它专注于 Solana 特定的特性,如 PDA、并行处理和 Anchor,而不是进行一般的区块链假设。
  2. 生成一致的代码:包含诸如严格的访问控制和并行执行的最佳实践,指导 AI 创建安全、可靠和可预测的输出。
  3. 避免常见错误:强调 Rust 的安全性、Anchor 宏和序列化可以减少错误。这为你节省了调试和重写代码的时间。
  4. 发挥 Solana 的优势:AI 必须增加带宽并减少延迟。这将优化代码以适应 Solana 的高吞吐量和效率。

2. 编写清晰的提示

当要求 AI 生成代码时,精确性至关重要。你越精确,结果就会越好。比较这些示例:

糟糕的提示:

"写一个初始化账户的函数。“

这个提示太模糊。AI 不知道编程语言、框架,或者这个提示是针对 Solana 代码的。它可能给出通用或无用的代码。

好的提示:

"写一个用 Rust 编写的函数,使用 Anchor 初始化一个 Solana 代币账户。使用从种子派生的 PDA。验证账户状态,并处理如果账户已经初始化时的错误。"

这条好的提示为什么有效:

清晰的提示可以节省时间和精力。通过澄清 AI 的目标,你防止了程序后面所需的纠正工作以避免生成松散、不明确或错误目标的代码。它也最小化了错误解释,使与 AI 的工作更有效。

  1. 清晰直接:通过直接命名 Rust、Anchor 和 PDA,AI 确切知道要使用哪些工具和特性。它不会猜测或包含无关的细节。
  2. 聚焦于 Solana 的需求:提到 PDA 告诉 AI 包含 Solana 特定的逻辑。没有这个,代码可能会遗漏重要步骤,例如安全地派生地址。
  3. 必要时增加深度:验证和错误处理指示让 AI 超越基本知识。这有助于确保代码能在真实的场景中工作。

一个好的提示就像一张地图,引导 AI 走出误区,达到目标。

3. 提供适当的上下文

当你给 AI 提供适当的上下文时,它的工作效果会更好。许多工具允许你上传代码或链接文件。这有助于 AI 理解你的项目,创建符合你代码库的解决方案。

但不要给它过多信息。给 AI 提供太多信息–例如一个大型代码库–可能会导致它产生幻觉或产生不相关的响应。

相反,专注于提供你代码的相关部分。这将使 AI 保持专注,并提高其建议的质量。

例如,假设你的应用程序已经有一个文件定义了自定义数据结构:

代码

##[账户]
pub struct TokenAccount {
    pub balance: u64,
    pub is_initialized: bool,
    // ... 更多字段
}

如果你上传这个文件或将其作为输入的一部分包含,AI 可以在生成的代码中使用你的精确字段名称 (balance, is_initialized)。

它还可以将其建议与项目的结构和约定对齐。

提供上下文的原因
  1. 提高准确性:没有上下文,AI 可能会猜测字段名称,引入不必要的更改,或假设错误的数据类型。例如,它可能将你的余额字段称为 amount,或使用 f64 而不是 u64。提供实际的结构消除了这种猜测。
  2. 保持代码一致性:当 AI 理解你的命名约定时,它将生成与项目自然而然匹配的代码。这为你省去了重命名变量或改造代码以匹配现有模式的麻烦。
  3. 减少集成工作:如果 AI 能了解你的账户结构,它可以直接定制其输出以与之集成。这避免了 AI 生成的代码需要进行重大重写以适应你的现有逻辑的情况。
示例:如何添加上下文以改善 AI 输出

没有适当的上下文,像 “写一个函数来更新代币账户余额” 的提示可能会导致 AI 生成的代码如下:

代码

pub fn update_balance(ctx: Context<UpdateAccount>, amount: f64) -> Result<()> {
    let account = &mut ctx.accounts.token_account;
    account.amount += amount;
    Ok(())
}

这段代码有两个问题:

首先,它使用 f64 作为 amount,而不是 u64

Solana 对本地浮点运算的支持非常有限。首选的做法是使用定点数,并根据使用的小数来缩放数字,这样可以避免性能和兼容性问题。

其次,它将余额字段称为 amount,这与结构不匹配。这可能导致将来的混淆与错误。

现在,如果你提供你的 TokenAccount 结构作为上下文,AI 可能会生成如下内容:

代码

pub fn update_balance(ctx: Context<UpdateAccount>, amount: u64) -> Result<()> {
    let token_account = &mut ctx.accounts.token_account;
    token_account.balance += amount;
    Ok(())
}

这个输出与你的项目更好地对齐。

然而,即使有了这个改进,在 token_account.balance += amount 操作上添加一个 溢出检查 以确保你的代码的稳健性和安全性也是值得的。

如何提供上下文

记住以下步骤以向你的 AI 工具提供适当的上下文:

  1. 上传文件:如果你的 AI 工具允许,上传你的结构定义、账户模式以及其他项目文件。
  2. 在提示中引用代码:将相关代码片段复制并粘贴到提示中,以便 AI 可以将其用作参考。
  3. 描述结构:如果上传不可行,清楚地在提示中描述你的数据。例如," 我有一个名为 TokenAccount 的结构,字段为 balance (u64) 和 is_initialized (bool)。”

4. 在现有代码上建立

你不需要每次都从头开始。通常,你已经有一个可以工作的代码片段,但可以做得更好。AI 可以帮助你改进它。以下是一个示例:

这是原始代码

代码

pub fn create_token_account(ctx: Context<CreateAccount>) -> Result<()> {
    let token_account = &mut ctx.accounts.token_account;
    token_account.balance = 0;
    Ok(())
}

这段代码初始化一个代币账户并将余额设为零。它很简单,但没有处理诸如更新现有账户或检查所有权等场景。

你的提示

"使这个函数更健壮。如果代币账户存在,将其加入余额。如果没有,请以特定金额初始化它。还要确保当前程序拥有该账户。"

这是你的提示后 AI 生成的代码

代码

pub fn create_or_update_token_account(
    ctx: Context<CreateAccount>,
    amount: u64
) -> Result<()> {
    let token_account = &mut ctx.accounts.token_account;

    // 检查所有权
    if token_account.owner != ctx.program_id {
        return err!(ProgramError::IncorrectProgramId);
    }

    // 更新或初始化
    if token_account.is_initialized {
        token_account.balance += amount;
    } else {
        token_account.balance = amount;
        token_account.is_initialized = true;
    }

    Ok(())
}
为什么它有效
  1. 解决常见场景:新的代码处理初始化和未初始化的账户,使其在实际应用中更加有用。
  2. 添加所有权验证:这防止未经授权的更改,因为程序会检查它是否拥有该账户。
  3. 使函数更智能:该函数现在可以更新余额,而不是每次都将其重设为零。这样可以减少冗余,适应现实用例。
  4. 节省时间:你不必重写整个函数。AI 扩展了你已有的内容,使你更快地从一个基本函数变成一个完善的函数。
如何使用这种方法

记住以下步骤,方便你将来采用这种方法:

  1. 从一个有效基础开始:确定那些虽然可用但可以更好的函数或代码段。
  2. 在提示中具体:解释你想要改进的地方,例如添加错误检查、处理边缘情况或改进逻辑。
  3. 审查 AI 的建议:查看 AI 生成的输出,确保其符合你的项目并遵循 Solana 的最佳实践。
  4. 根据需要进行迭代:如果第一个输出不完美,可以调整你的提示或编辑代码,达到目标。

5. 一步一步地迭代开发

分步骤构建代码可以帮助你避免错误并在进行的过程中精炼工作。不必试图一次性创建复杂的函数,而是将其分解为更小的任务。这使得测试和改进每一部分变得更容易,然后再继续。

示例工作流程

让我们从简单的开始。请 AI 生成一个 Rust 函数,该函数使用种子计算程序派生地址 (PDA)。

这是一个例子提示:

"写一个 Rust 函数,从种子和程序 ID 计算 PDA,使用 Anchor。"

AI 的输出:

代码

 pub fn find_pda(seed: &[u8], program_id: &Pubkey) -> Pubkey {
    Pubkey::create_program_address(&[seed], program_id).unwrap()
}

这是一个不错的起点,但它不完整。让我们添加错误处理。

审查代码并识别问题。例如,使用 unwrap() 可能导致程序在种子无效时崩溃。

请 AI 修复这个问题:

"更新这个函数,添加对无效种子的错误处理。返回一个 Result 而不是直接 unwrap。"

更新后的代码:

代码

 pub fn find_pda(seed: &[u8], program_id: &Pubkey) -> Result<Pubkey, ProgramError> {
    Pubkey::create_program_address(&[seed], program_id)
        .map_err(|_| ProgramError::InvalidSeeds)
}

现在,这个函数能优雅地处理无效的种子,通过返回错误而不是崩溃。

接下来,让我们集成这个函数。

请 AI 使用 PDA 函数在一个更大的例程中。例如:

"写一个使用这个 PDA 创建新代币账户的函数。验证 PDA 不能已经在使用中。"

这是 AI 的输出:

代码

pub fn create_token_account(ctx: Context<CreateAccount>, seed: &[u8], amount: u64) -> Result<()> {
    let program_id = ctx.program_id;
    let pda = find_pda(seed, &program_id)?;

    if ctx.accounts.token_account.key != pda {
        return Err(ProgramError::InvalidSeeds);
    }

    if !ctx.accounts.token_account.is_initialized {
        let token_account = &mut ctx.accounts.token_account;
        token_account.balance = amount;
        token_account.is_initialized = true;
    }

    Ok(())
}

这一步将 PDA 逻辑集成到账户创建中,同时确保 PDA 不被不当地重复使用。

现在,让我们优化和完善代码。请 AI 进一步优化函数,使用提示如:

"优化此函数以最小化交易成本,并包含所有权验证。"

这是 AI 的输出:

代码

pub fn create_token_account(ctx: Context<CreateAccount>, seed: &[u8], amount: u64) -> Result<()> {
    let program_id = ctx.program_id;
    let pda = find_pda(seed, &program_id)?;

    if ctx.accounts.token_account.key != pda || ctx.accounts.token_account.owner != program_id {
        return Err(ProgramError::IncorrectProgramId);
    }

    if !ctx.accounts.token_account.is_initialized {
        let token_account = &mut ctx.accounts.token_account;
        token_account.balance = amount;
        token_account.is_initialized = true;
    }

    Ok(())
}

最终函数现在安全、高效,并符合 Solana 的最佳实践。

这种方法的有效性
  1. 可管理性:专注于一次一个小任务,可以避免给 AI 带来负担。每一步在上一段基础上构建,更容易进行测试和改进。
  2. 及早捕获错误:较小的步骤使得你可以在问题影响其余代码之前发现问题。例如,尽早添加错误处理可以防止后续崩溃。
  3. 促进迭代:如果效果不尽如人意,你可以调整函数,而无需重做整个代码库。
  4. 生成更好的代码:每次的完善使代码更健壮,最终得到的解决方案也更可靠且易于维护。
如何使用这种方法

记住这些提示,下次你与 AI 进行配对编程时:

  1. 将任务分解成小步骤:与其请求一个复杂函数,不如将其分解成简单、可控的任务,并逐一执行。
  2. 在每个步骤后测试结果:每次改动后运行代码以确认其有效性。如果没有,修复问题或在进入下一个步骤之前调整提示。
  3. 在过程中进行迭代:不局限于单一结果。请 AI 优化或添加错误处理、性能改善的功能。

结论:开始在 Solana 上使用 AI

在 Solana 上使用 AI 构建应用可以非常强大——前提是你采取细致周到的方法。Solana 的架构与其他区块链不同——它使用 PDA、并行交易处理和基于账户的设计。这意味着你需要正确引导 AI。

从清晰的提示开始。明确告诉 AI 你想要的具体内容,并具体说明使用的工具如 Rust、Anchor 和 PDA。一个好的提示可能会说:

编写一个 Rust 函数,以一个 PDA 初始化 Solana 代币账户,验证账户状态,并处理错误。

这种清晰度使 AI 更有可能生成适合 Solana 的有效代码。

始终提供上下文。分享项目的代码或说明你使用的结构,比如账户模式或数据类型。例如,如果你有一个 TokenAccount 结构,请包含其详细信息,以便 AI 能对其输出进行对齐。但不要给它过多信息——专注于相关部分以保持建议的准确性和价值。

将任务分为小步骤。通过迭代过程逐步改进代码。从简单的任务开始,如计算 PDA,然后在此基础上增加错误处理或账户验证。每一步后测试。通过这样做,你可以尽早捕捉问题,稳步前进。

最后,仔细检查 AI 的工作。大多数时候,AI 生成的代码有些小问题,如缺少溢出检查或遗漏验证。确保输出遵循 Solana 的规范,保持无 bug,并利用并行处理能力。

AI 只是一个起点;你必须完成工作。通过清晰的指令、上下文、逐步开发和细致的审查,你可以利用 AI 创建安全且优化的 Solana 程序。保持参与这个过程,AI 将成为一个节省时间并编写更好代码的有价值工具。

额外阅读

要了解更多关于使用 AI 在 Solana 上构建的知识,请探索以下资源:

  1. Anthropic: 提示工程概述
  2. AWS: 提示工程技术
  3. 优化 Solana 程序
  4. 如何优化 Solana 的计算使用
  5. Anchor 文档
  • 原文链接: helius.dev/blog/how-to-u...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Helius
Helius
https://www.helius.dev/