TuBrief
Subscribed Channels
Videos
Community

解决 Vercel Eve Agent 无服务器冷启动与成本问题的架构设计

TuBrief Editorial
July 23, 2026
0
Computing/Software

Written with AI assistance from the source video. The video is the authority.

中文한국어EnglishEspañolहिन्दीDeutschFrançaisРусскийPortuguês日本語Bahasa Indonesiaالعربية

Related Video

Ship 26 NYC - 工作坊 - 使用 Eve 构建智能体:开源智能体框架39:50

Ship 26 NYC - 工作坊 - 使用 Eve 构建智能体:开源智能体框架

Vercel

More from the community

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

September 13, 2026

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

September 13, 2026

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

September 13, 2026

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

September 13, 2026

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

September 12, 2026

Apple Won the AI Race

September 12, 2026

Comments (0)

Log in to leave a comment

No posts yet

© 2026 . All rights reserved.

TuBrief
Subscribed Channels
Videos
Community
Log in

解决 Vercel Eve Agent 无服务器冷启动与成本问题的架构设计

将基于 Vercel Eve 的 Agent 部署到生产环境时,会立即面临无服务器(Serverless)架构特有的无状态性(Statelessness)问题。当请求结束时,实例随之关闭,运行状态也随之消失。然而,如果为了复原会话而每次都查询 PostgreSQL 等数据库,不仅会导致超过 100ms 的延迟,还会使数据库成本激增。

为了突破无服务器架构的限制,本文总结了在实际生产环境中运用的三种架构设计。

1. 通过 Upstash Redis 将会话复原延迟降低至 50ms 以下

在无服务器环境中,每次都重新建立数据库连接是破坏基础设施成本和响应速度的“捷径”。通过引入基于 HTTP REST API 通信的 Upstash Redis 作为会话缓存层,可以有效解决这一问题。

`
[User Request]
│
▼
┌──────────────┐ < 50ms (HTTP REST) ┌────────────────────────┐
│ Vercel Eve │ ────────────────────────> │ Upstash Redis │
│ Agent │ <──────────────────────── │ (Session State Storage)│
└──────────────┘ Session Context Restored└────────────────────────┘
│
│ Compress History (Sliding Window + Summary)
▼
┌──────────────┐
│ LLM Provider │
└──────────────┘

`

会话数据通过 REST API 在 50ms 内获取完毕。用缓存替代直接查询关系型数据库(RDB),可以大幅减少 Read Capacity(读取容量)的消耗。

评估项目 传统关系型数据库 (PostgreSQL) DynamoDB (On-Demand) Upstash Redis (HTTP REST)
连接方式 TCP Socket AWS SDK HTTP/REST API
平均读取延迟 50ms - 200ms 10ms - 20ms 1ms - 5ms (Edge < 50ms)
无服务器适用性 较低 (Connection Exhaustion) 中等 (存在连接延迟) 极高 (支持 Scale-to-Zero)
成本结构 按预置实例时长计费 按 RCU/WCU 请求单位计费 按 Command 请求单位计费 ($0.20/100k)
主要使用目的 ACID 事务、原始数据存储 持久化数据存储与查询 会话缓存、Rate Limit、Agent 内存

会话存储与复原的代码保持简单易懂:

`typescript
import { Redis } from "@upstash/redis";

const redis = Redis.fromEnv();

interface AgentSessionContext {
userId: string;
currentStep: string;
intermediateThoughts: Record<string, unknown>[];
lastActiveTimestamp: number;
}

export async function restoreSessionContext(sessionId: string): Promise<AgentSessionContext | null> {
const cacheKey = session:context:${sessionId};
const cachedContext = await redis.get(cacheKey);
return cachedContext ?? null;
}

export async function saveSessionContext(
sessionId: string,
context: AgentSessionContext,
ttlSeconds: number = 3600
): Promise {
const cacheKey = session:context:${sessionId};
await redis.set(cacheKey, JSON.stringify(context), { ex: ttlSeconds });
}

`

随着对话增长,Token 成本也会不断上升。我们采用仅保留最近 6 轮对话的原始数据,并使用轻量模型对早期对话进行总结,然后放置于 Prompt 顶部的策略。

`typescript
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";

interface Message {
role: "user" | "assistant" | "system";
content: string;
}

export async function compressConversationHistory(
messages: Message[],
recentWindowSize: number = 6
): Promise<Message[]> {
if (messages.length <= recentWindowSize) return messages;

const systemMessage = messages.find((m) => m.role === "system");
const nonSystemMessages = messages.filter((m) => m.role !== "system");

const olderMessages = nonSystemMessages.slice(0, nonSystemMessages.length - recentWindowSize);
const recentMessages = nonSystemMessages.slice(nonSystemMessages.length - recentWindowSize);

const summaryResponse = await generateText({
model: openai("gpt-4o-mini"),
prompt: 请将以下对话的核心事实和决策事项总结在 200 字以内:\n\n${JSON.stringify(olderMessages)},
});

const compressedHistory: Message[] = [];
if (systemMessage) compressedHistory.push(systemMessage);
compressedHistory.push({
role: "system",
content: [先前对话总结]: ${summaryResponse.text},
});
compressedHistory.push(...recentMessages);

return compressedHistory;
}

`

2. 外部 API 延迟与失败防御模式

在调用外部工具时,如果遇到 429 (Rate Limit) 或 5xx 错误,可能导致整个 Agent 推理崩溃。因此需要铺设融入 Full Jitter 的指数退避(Exponential Backoff)和熔断器(Circuit Breaker)。

指数退避公式通过不按等比单纯增加等待时间,而是加入随机数,以避免峰值拥堵:

Textdelay=minleft(Textmax,Textbaseimes2extattemptight)imesleft(0.5+extrandom(0,1.0)ight)T_{ ext{delay}} = minleft(T_{ ext{max}}, T_{ ext{base}} imes 2^{ ext{attempt}} ight) imes left(0.5 + ext{random}(0, 1.0) ight)Textdelay​=minleft(Textmax​,Textbase​imes2extattemptight)imesleft(0.5+extrandom(0,1.0)ight)

`typescript
export interface RetryConfig {
maxRetries: number;
baseDelayMs: number;
maxDelayMs: number;
}

export async function executeWithExponentialBackoff(
fn: () => Promise,
config: RetryConfig = { maxRetries: 3, baseDelayMs: 200, maxDelayMs: 8000 }
): Promise {
let attempt = 0;

while (true) {
try {
return await fn();
} catch (error: any) {
attempt++;
const statusCode = error?.status || error?.response?.status;
const isUnretryable = statusCode && statusCode >= 400 && statusCode < 500 && statusCode !== 429;

  if (attempt > config.maxRetries || isUnretryable) throw error;

  const calculatedDelay = Math.min(
    config.maxDelayMs,
    config.baseDelayMs * Math.pow(2, attempt)
  );
  const jitteredDelay = calculatedDelay * (0.5 + Math.random());

  await new Promise((resolve) => setTimeout(resolve, jitteredDelay));
}

}
}

`

当故障持续时,利用熔断器立即阻断请求(Fail-Fast),并触发 Fallback(降级)逻辑。

外部 API 响应状态 熔断器状态 运行机制 Agent 处理结果
HTTP 200 OK Closed 正常通过并增加成功计数器 将外部数据正常供给给 Agent
HTTP 429 / 503 Closed $
ightarrow$ Open 执行指数退避,达到失败率阈值时转为 Open 重试后开启熔断器
Circuit OPEN 状态 Open 阻断外部 API 网络请求 (Fail-Fast) 使用替代 Tool 或输出 Fallback 消息
Cooldown 到期后 Half-Open 通过单次 Probing 请求验证外部服务恢复情况 成功时恢复正常,失败时重新阻断

`typescript
export class CircuitBreaker {
private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';
private failureCount = 0;
private lastStateChange = Date.now();

constructor(
private failureThreshold: number = 5,
private cooldownPeriodMs: number = 30000
) {}

async execute(requestFn: () => Promise, fallbackFn: () => Promise): Promise {
const now = Date.now();

if (this.state === 'OPEN') {
  if (now - this.lastStateChange > this.cooldownPeriodMs) {
    this.state = 'HALF_OPEN';
    this.lastStateChange = now;
  } else {
    return await fallbackFn();
  }
}

try {
  const result = await requestFn();
  if (this.state === 'HALF_OPEN') {
    this.state = 'CLOSED';
    this.failureCount = 0;
    this.lastStateChange = now;
  }
  return result;
} catch (error) {
  this.failureCount++;
  if (this.failureCount >= this.failureThreshold || this.state === 'HALF_OPEN') {
    this.state = 'OPEN';
    this.lastStateChange = now;
  }
  return await fallbackFn();
}

} }

`

3. 无超时限制的人工介入(Human-in-the-loop)异步审批联动

无服务器函数存在执行时间限制。如果为了等待支付或数据库删除审批而一直维持请求连接,会导致超时错误。

`
[Agent Action] ──> Eve Tool (needsApproval: true)
│
▼
[Checkpoint Saved & Instance Terminated]
│
├─> Slack Notification (Interactive Card)
│
[Human Approve] ───────>│ (Webhook POST Callback)
│
▼
[Resume Agent & Proceed Transaction]

`

在 Eve 工具中设置 needsApproval: true 并暂停执行,仅保留检查点(Checkpoint)。

`typescript
import { defineTool } from "@vercel/eve";
import { z } from "zod";

export const deleteDatabaseTool = defineTool({
name: "delete_database",
description: "删除指定租户的永久数据库记录。",
needsApproval: true,
input: z.object({
tenantId: z.string(),
reason: z.string(),
}),
execute: async ({ tenantId }) => {
return await db.tenant.delete({ where: { id: tenantId } });
},
});

`

人工审批通过 Webhook 回调接收,从而恢复执行流程。

`typescript
import { createWebhook } from "@vercel/workflows";

export async function handleApprovalWorkflow(event: { approvalId: string; payload: any }) {
const webhook = createWebhook();

await sendSlackApprovalCard({
approvalId: event.approvalId,
callbackUrl: webhook.url,
payload: event.payload,
});

try {
const { approved, userReason } = await webhook.timeout("12h");

if (!approved) {
  await rollbackPreviousSteps(event.payload);
  return { status: "REJECTED", reason: userReason };
}

return await proceedAction(event.payload);

} catch (error) {
await rollbackPreviousSteps(event.payload);
return { status: "TIMEOUT_CANCELLED" };
}
}

`

4. CI/CD 阶段的 Prompt 验证与金丝雀路由

修改 Prompt 后产生的幻觉现象很难通过人工测试完全捕捉。通过构建流水线,只有通过 DeepEval 指标测试的 PR 才能被合并。

评估指标 可接受阈值 评估标准
Faithfulness ge0.85ge 0.85ge0.85 相较于提供的 Context,是否存在事实扭曲
Answer Relevancy ge0.75ge 0.75ge0.75 与用户提问目的的契合度
Hallucination Rate le0.10le 0.10le0.10 测试集中发生幻觉的比例
Tool Calling Accuracy ge0.90ge 0.90ge0.90 正确选择 OpenAPI 规范工具及类型遵循率

在 GitHub Actions 中运行 Pytest,未达到阈值时自动阻止构建。

`yaml
name: Eve Agent Prompt Evaluation Pipeline

on:
pull_request:
branches: [ main ]

jobs:
evaluate-agent:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

  - name: Set up Python
    uses: actions/setup-python@v5
    with:
      python-version: '3.11'

  - name: Install Evaluation Dependencies
    run: |
      pip install deepeval pytest

  - name: Run DeepEval Regression Suite
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
    run: |
      pytest test_agent_evals.py --deepeval-metric-threshold=0.85

`

部署时结合 Edge Config 和中间件,将新 Prompt 仅先应用到 10% 的流量上。

`typescript
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { get } from '@vercel/edge-config';

export async function middleware(req: NextRequest) {
const res = NextResponse.next();
let variant = req.cookies.get('agent_canary_variant')?.value;

if (!variant) {
const canaryRate = (await get('canary_traffic_rate')) || 0.10;
variant = Math.random() < canaryRate ? 'canary' : 'control';
res.cookies.set('agent_canary_variant', variant, { path: '/', httpOnly: true });
}

res.headers.set('x-agent-prompt-version', variant === 'canary' ? 'v2-canary' : 'v1-stable');
return res;
}

export const config = {
matcher: '/api/agent/:path*',
};

`