LLM Agent 调用智能合约的架构
AI Agent 与 Web3 的结合是当前最具前景的技术方向之一。核心思路是让 LLM(大语言模型)作为决策层,将自然语言指令转化为链上交易。
整体架构分为三层:
┌──────────────────────────────────────────────────┐
│ 用户层 (User Layer) │
│ "帮我用 100 USDC 换 ETH,如果 Gas < 20 gwei" │
└──────────────────────┬───────────────────────────┘
▼
┌──────────────────────────────────────────────────┐
│ AI Agent 层 (Decision Layer) │
│ ┌─────────┐ ┌──────────┐ ┌─────────────────┐ │
│ │ 意图识别 │─▶│ 策略决策 │─▶│ 交易构造 & 签名 │ │
│ └─────────┘ └──────────┘ └─────────────────┘ │
└──────────────────────┬───────────────────────────┘
▼
┌──────────────────────────────────────────────────┐
│ 执行层 (Execution Layer) │
│ Wallet Client → RPC → Blockchain │
└──────────────────────────────────────────────────┘
Agent 不是直接调用 LLM 的 API 来签发交易——那样太危险了。正确的架构是 Agent 将 LLM 的输出作为"交易意图",经过安全校验后再构造实际交易。
意图识别:从自然语言到合约调用
意图识别是将用户的自然语言指令转换为结构化的交易参数:
// 交易意图数据结构
interface TransactionIntent {
action: 'swap' | 'stake' | 'transfer' | 'approve' | 'claim' | 'bridge' | 'custom'
protocol: string // 目标协议,如 'uniswap-v3'
params: Record<string, any>
conditions?: {
maxGasPrice?: bigint // Gas 价格条件
minSlippage?: number // 最大滑点
deadline?: number // 过期时间
priceCondition?: { // 价格触发条件
token: string
operator: '>' | '<' | '>=' | '<='
value: number
}
}
constraints: {
maxAmount: bigint // 最大交易金额
allowedContracts: string[] // 允许调用的合约白名单
}
}
// LLM 系统提示词
const SYSTEM_PROMPT = `
You are a Web3 transaction intent parser. Convert user's natural language
instruction into a structured JSON transaction intent.
Available actions:
- swap: Token swap (params: tokenIn, tokenOut, amountIn, minAmountOut)
- stake: Stake tokens (params: token, amount, validator)
- transfer: Transfer tokens (params: token, to, amount)
- approve: Approve token spending (params: token, spender, amount)
- claim: Claim rewards (params: protocol, rewardToken)
- bridge: Cross-chain transfer (params: fromChain, toChain, token, amount)
Output format: JSON only, no explanation.
Example:
User: "Swap 100 USDC for ETH on Uniswap, slippage 1%"
Output: {
"action": "swap",
"protocol": "uniswap-v3",
"params": { "tokenIn": "USDC", "tokenOut": "ETH", "amountIn": 100, "minAmountOut": 0 },
"conditions": { "minSlippage": 0.01 }
}
`
// 意图识别管道
class IntentParser {
private llm: LLMClient
private tokenRegistry: TokenRegistry
constructor(llm: LLMClient, tokenRegistry: TokenRegistry) {
this.llm = llm
this.tokenRegistry = tokenRegistry
}
async parse(userInput: string): Promise<TransactionIntent> {
// 1. 调用 LLM 解析意图
const rawIntent = await this.llm.complete({
system: SYSTEM_PROMPT,
user: userInput,
temperature: 0, // 确定性输出
})
const parsed = JSON.parse(rawIntent)
// 2. 验证和规范化意图
const intent = await this.validateIntent(parsed)
return intent
}
private async validateIntent(raw: any): Promise<TransactionIntent> {
// 验证 action 是否合法
const validActions = ['swap', 'stake', 'transfer', 'approve', 'claim', 'bridge', 'custom']
if (!validActions.includes(raw.action)) {
throw new Error(`Invalid action: ${raw.action}`)
}
// 将 token 符号解析为合约地址
const params = { ...raw.params }
for (const key of ['tokenIn', 'tokenOut', 'token', 'rewardToken']) {
if (params[key] && typeof params[key] === 'string') {
const tokenInfo = await this.tokenRegistry.getByName(params[key])
if (tokenInfo) {
params[key] = tokenInfo.address
}
}
}
// 设置安全约束
const intent: TransactionIntent = {
...raw,
params,
constraints: {
maxAmount: raw.constraints?.maxAmount
? BigInt(raw.constraints.maxAmount)
: parseEther('1000'), // 默认最大 1000 ETH 等价物
allowedContracts: raw.constraints?.allowedContracts || [],
},
}
return intent
}
}
Agent 交易签名:安全边界与权限控制
Agent 签名是整个架构中最敏感的部分。LLM 输出不能直接用于签名——必须经过多重安全检查:
// 安全签名管道
class SecureSigningPipeline {
private whitelist: ContractWhitelist
private limits: TransactionLimits
private approver: HumanApprover | null // 可选的人工审批
constructor(config: {
whitelist: ContractWhitelist
limits: TransactionLimits
approver?: HumanApprover
}) {
this.whitelist = config.whitelist
this.limits = config.limits
this.approver = config.approver || null
}
async sign(
intent: TransactionIntent,
walletClient: WalletClient,
publicClient: PublicClient,
): Promise<Hash> {
// 1. 合约白名单检查
const targetContract = this.resolveTargetContract(intent)
if (!this.whitelist.isAllowed(targetContract, intent.action)) {
throw new SecurityError(
`Contract ${targetContract} is not in whitelist for action ${intent.action}`
)
}
// 2. 金额限制检查
const txAmount = this.extractAmount(intent)
if (txAmount > this.limits.maxAmount) {
throw new SecurityError(
`Amount ${txAmount} exceeds limit ${this.limits.maxAmount}`
)
}
// 3. 条件检查(Gas 价格、价格触发等)
if (intent.conditions?.maxGasPrice) {
const currentGasPrice = await publicClient.getGasPrice()
if (currentGasPrice > intent.conditions.maxGasPrice) {
throw new ConditionError(
`Gas price ${currentGasPrice} exceeds limit ${intent.conditions.maxGasPrice}`
)
}
}
if (intent.conditions?.priceCondition) {
const currentPrice = await this.getTokenPrice(intent.conditions.priceCondition.token)
const { operator, value } = intent.conditions.priceCondition
const meets = this.evaluateCondition(currentPrice, operator, value)
if (!meets) {
throw new ConditionError(
`Price condition not met: ${currentPrice} ${operator} ${value}`
)
}
}
// 4. 构造交易数据
const txData = await this.buildTransactionData(intent)
// 5. 模拟执行
const simulation = await publicClient.simulateContract({
address: targetContract,
abi: await this.getContractAbi(targetContract),
functionName: txData.functionName,
args: txData.args,
account: walletClient.account!,
value: txData.value,
})
// 6. 可选:人工审批
if (this.approver && this.requiresApproval(intent, txAmount)) {
const approved = await this.approver.requestApproval({
intent,
txData,
simulation,
})
if (!approved) {
throw new SecurityError('Human approval denied')
}
}
// 7. 签名并发送
return walletClient.writeContract(simulation.request)
}
private requiresApproval(intent: TransactionIntent, amount: bigint): boolean {
// 大额交易需要人工审批
return amount > this.limits.autoApproveThreshold
}
}
自动化交易管道:监控 -> 决策 -> 执行
完整的自动化管道需要持续监控链上状态,在条件满足时自动触发交易:
class AutomatedTradingPipeline {
private parser: IntentParser
private signer: SecureSigningPipeline
private walletClient: WalletClient
private publicClient: PublicClient
private monitors: Map<string, PriceMonitor> = new Map()
private queue: TransactionQueue
constructor(config: PipelineConfig) {
this.parser = new IntentParser(config.llm, config.tokenRegistry)
this.signer = new SecureSigningPipeline({
whitelist: config.whitelist,
limits: config.limits,
})
this.walletClient = config.walletClient
this.publicClient = config.publicClient
this.queue = new TransactionQueue()
}
// 注册条件触发器
async registerTrigger(userInstruction: string) {
const intent = await this.parser.parse(userInstruction)
if (intent.conditions?.priceCondition) {
const monitor = new PriceMonitor(
intent.conditions.priceCondition.token,
intent.conditions.priceCondition.operator,
intent.conditions.priceCondition.value,
)
this.monitors.set(userInstruction, monitor)
monitor.onTrigger(async () => {
await this.executeIntent(intent)
})
monitor.start()
} else {
// 无条件,立即执行
await this.executeIntent(intent)
}
}
// 执行意图
private async executeIntent(intent: TransactionIntent) {
try {
const hash = await this.signer.sign(
intent,
this.walletClient,
this.publicClient,
)
// 追踪交易状态
const receipt = await this.publicClient.waitForTransactionReceipt({ hash })
if (receipt.status === 'success') {
console.log(`Intent executed: ${intent.action}, tx: ${hash}`)
// 可选:通过通知系统告知用户
} else {
console.error(`Intent failed: ${hash}`)
// 重试或通知用户
}
} catch (error) {
console.error(`Intent execution error: ${error}`)
}
}
// 停止所有监控
stopAll() {
for (const monitor of this.monitors.values()) {
monitor.stop()
}
this.monitors.clear()
}
}
// 价格监控器
class PriceMonitor {
private interval: NodeJS.Timeout | null = null
private callbacks: (() => void)[] = []
constructor(
private token: string,
private operator: '>' | '<' | '>=' | '<=',
private targetValue: number,
) {}
onTrigger(cb: () => void) {
this.callbacks.push(cb)
}
start() {
this.interval = setInterval(async () => {
const currentPrice = await this.fetchPrice(this.token)
if (this.evaluate(currentPrice)) {
this.callbacks.forEach((cb) => cb())
this.stop() // 触发一次后停止
}
}, 10000) // 每 10 秒检查一次
}
stop() {
if (this.interval) {
clearInterval(this.interval)
this.interval = null
}
}
private async fetchPrice(token: string): Promise<number> {
// 从 Chainlink 或 DEX 获取价格
const response = await fetch(`https://api.example.com/price/${token}`)
const data = await response.json()
return data.price
}
private evaluate(current: number): boolean {
switch (this.operator) {
case '>': return current > this.targetValue
case '<': return current < this.targetValue
case '>=': return current >= this.targetValue
case '<=': return current <= this.targetValue
}
}
}
Agent 与钱包的交互模式
Agent 与钱包的交互有两种模式:
模式一:Agent 持有签名密钥(全自动)
Agent 持有一个受限的 Session Key,可以自主签名交易。安全性依赖 Session Key 的权限控制——限制可调用的合约、金额上限和有效期。
模式二:Agent 构造交易,用户审批签名(半自动)
Agent 负责构造交易数据和模拟执行,但最终签名由用户完成。适用于高价值交易或敏感操作。
// 模式二:半自动模式
async function semiAutoExecute(
intent: TransactionIntent,
agent: AIAgent,
userWallet: WalletClient,
publicClient: PublicClient,
) {
// Agent 构造交易
const txPlan = await agent.planTransaction(intent, publicClient)
// 向用户展示交易计划
const userApproved = await presentToUser({
action: intent.action,
contract: txPlan.contractName,
functionName: txPlan.functionName,
args: txPlan.args,
estimatedGas: txPlan.estimatedGas,
estimatedCost: txPlan.estimatedGasCost,
simulationResult: txPlan.simulation,
value: txPlan.value,
})
if (!userApproved) {
throw new Error('User rejected the transaction plan')
}
// 用户签名
const hash = await userWallet.writeContract({
address: txPlan.contractAddress,
abi: txPlan.abi,
functionName: txPlan.functionName,
args: txPlan.args,
value: txPlan.value,
})
return hash
}
多步交易的 Agent 编排
复杂操作需要多步交易。Agent 负责编排执行顺序,处理中间状态和错误恢复:
// 多步交易编排器
class TransactionOrchestrator {
private agent: AIAgent
private signer: SecureSigningPipeline
private walletClient: WalletClient
private publicClient: PublicClient
// 执行多步交易计划
async executePlan(steps: TransactionStep[]): Promise<ExecutionResult> {
const results: StepResult[] = []
for (let i = 0; i < steps.length; i++) {
const step = steps[i]
try {
// 检查前置条件
if (step.precondition) {
const met = await step.precondition(this.publicClient, results)
if (!met) {
return {
success: false,
completedSteps: results,
failedAtStep: i,
reason: 'Precondition not met',
}
}
}
// 执行当前步骤
const hash = await this.signer.sign(
step.intent,
this.walletClient,
this.publicClient,
)
const receipt = await this.publicClient.waitForTransactionReceipt({ hash })
if (receipt.status === 'reverted') {
// 尝试回退
if (step.rollback) {
await this.executeRollback(step.rollback, results)
}
return {
success: false,
completedSteps: results,
failedAtStep: i,
reason: 'Transaction reverted',
receipt,
}
}
results.push({ step: i, hash, receipt, success: true })
// 检查后置条件
if (step.postcondition) {
const met = await step.postcondition(this.publicClient, receipt)
if (!met) {
return {
success: false,
completedSteps: results,
failedAtStep: i,
reason: 'Postcondition not met',
}
}
}
} catch (error) {
return {
success: false,
completedSteps: results,
failedAtStep: i,
reason: error instanceof Error ? error.message : 'Unknown error',
}
}
}
return { success: true, completedSteps: results }
}
// 回退已执行的步骤
private async executeRollback(
rollbackSteps: RollbackStep[],
completedResults: StepResult[],
) {
// 反向执行回滚
for (let i = rollbackSteps.length - 1; i >= 0; i--) {
try {
await this.signer.sign(
rollbackSteps[i].intent,
this.walletClient,
this.publicClient,
)
} catch {
// 回滚失败也需要记录
console.error('Rollback failed')
}
}
}
}
// 示例:Agent 编排一个复杂的 DeFi 操作
async function orchestrateDefiStrategy(
orchestrator: TransactionOrchestrator,
agent: AIAgent,
) {
// 用户说:"把我的 ETH 存入 Lido,然后用 stETH 在 Aave 借 USDC"
const plan = await agent.planMultiStep({
instruction: 'Deposit ETH to Lido, then use stETH as collateral to borrow USDC on Aave',
})
// plan 包含:
// Step 1: approve Lido stETH
// Step 2: stake ETH to Lido
// Step 3: approve Aave stETH
// Step 4: supply stETH to Aave
// Step 5: borrow USDC from Aave
const result = await orchestrator.executePlan(plan)
return result
}
错误处理:Agent 决策失败时的回退
Agent 可能做出错误决策——可能是 LLM 幻觉导致调用了不存在的合约,或是对市场条件判断失误。健壮的错误处理是必须的:
class AgentErrorHandler {
// 错误分类
classifyError(error: unknown): ErrorType {
if (error instanceof SecurityError) return 'security'
if (error instanceof ConditionError) return 'condition'
if (error instanceof ContractError) return 'contract'
if (error instanceof NetworkError) return 'network'
return 'unknown'
}
// 根据错误类型决定回退策略
getFallbackStrategy(errorType: ErrorType): FallbackStrategy {
switch (errorType) {
case 'security':
// 安全错误:立即停止,通知用户
return { action: 'stop', notify: true, autoRetry: false }
case 'condition':
// 条件未满足:等待重试
return { action: 'wait', waitTime: 60000, maxRetries: 3, autoRetry: true }
case 'contract':
// 合约错误:检查是否是 ABI 不匹配,尝试修正
return { action: 'replan', maxReplans: 2 }
case 'network':
// 网络错误:切换 RPC 端点重试
return { action: 'retry', maxRetries: 5, retryDelay: 5000 }
default:
return { action: 'stop', notify: true, autoRetry: false }
}
}
async handleError(
error: unknown,
intent: TransactionIntent,
pipeline: AutomatedTradingPipeline,
): Promise<void> {
const errorType = this.classifyError(error)
const strategy = this.getFallbackStrategy(errorType)
switch (strategy.action) {
case 'wait':
if (strategy.autoRetry) {
await new Promise((r) => setTimeout(r, strategy.waitTime))
await pipeline.registerTrigger(JSON.stringify(intent))
}
break
case 'replan':
// 让 Agent 重新规划
break
case 'stop':
// 停止管道并通知
pipeline.stopAll()
break
}
}
}
安全设计:白名单合约、金额限制、审批流程
安全是 AI + Web3 的生命线。以下是推荐的安全架构:
// 合约白名单
class ContractWhitelist {
private whitelist: Map<string, Set<string>> = new Map()
// 格式: contractAddress -> Set<allowedActions>
constructor(rules: { contract: string; actions: string[] }[]) {
for (const rule of rules) {
this.whitelist.set(
rule.contract.toLowerCase(),
new Set(rule.actions),
)
}
}
isAllowed(contract: string, action: string): boolean {
const actions = this.whitelist.get(contract.toLowerCase())
return actions ? actions.has(action) : false
}
}
// 交易限制
interface TransactionLimits {
maxAmount: bigint // 单笔最大金额
maxDailyVolume: bigint // 日最大交易量
autoApproveThreshold: bigint // 自动审批阈值
cooldownPeriod: number // 冷却期(毫秒)
}
// 频率限制器
class RateLimiter {
private lastTransaction: Map<string, number> = new Map()
private dailyVolume: bigint = 0n
private dailyResetTime: number = Date.now()
constructor(private limits: TransactionLimits) {}
async check(intent: TransactionIntent): Promise<void> {
// 检查冷却期
const key = `${intent.action}-${intent.protocol}`
const lastTime = this.lastTransaction.get(key) || 0
if (Date.now() - lastTime < this.limits.cooldownPeriod) {
throw new SecurityError('Cooldown period not elapsed')
}
// 检查日交易量
if (Date.now() - this.dailyResetTime > 86400000) {
this.dailyVolume = 0n
this.dailyResetTime = Date.now()
}
const amount = extractAmount(intent)
if (this.dailyVolume + amount > this.limits.maxDailyVolume) {
throw new SecurityError('Daily volume limit exceeded')
}
}
record(intent: TransactionIntent) {
const key = `${intent.action}-${intent.protocol}`
this.lastTransaction.set(key, Date.now())
this.dailyVolume += extractAmount(intent)
}
}
小结
AI Agent 与 Web3 的结合正在创造全新的交互范式。用户不再需要理解 ABI、Gas、Nonce 等概念——他们只需要用自然语言描述意图,Agent 负责将其转化为链上交易。这种便利性的代价是更高的安全风险。LLM 的不可预测性意味着 Agent 可能做出错误决策,而 Web3 的不可逆性使得错误的后果是永久的。安全边界设计是整个架构的核心——合约白名单、金额限制、人工审批和频率控制构成了多层防御。从长期来看,AI + Web3 的最大机遇是降低用户门槛:让数十亿不懂得 Gas 和私钥的用户也能使用链上服务。但这个愿景的前提是安全架构足够成熟,能将 Agent 的风险限制在可控范围内。
