【InsForge】核心架构与设计原理深度解析 让 Coding Agent 也能开箱即用后端服务的全栈平台

一 引子 当 Coding Agent 开始自己写全栈

过去两年 AI 圈最火热的话题绕不开「Coding Agent」——Claude Code、Cursor、Codex、Cline、Kiro、Continue、Goose 等终端/IDE 内嵌的 Agent 工具让「一句话生成完整应用」从 PPT 走进了真实开发流程。但当 Agent 真的写出了 Todo App、电商后台、内容社区时,所有人都会撞上一堵隐形的墙:前端可以 AI 生成,后端呢?

数据库表怎么建?用户登录怎么接入?文件上传走哪个 S3 兼容服务?邮件通知怎么发?支付怎么接?边缘函数部署到哪?

传统答案是让 Agent 自己造轮子——连 Supabase、连 Firebase、连 Vercel、连 Stripe 文档,然后一段段写 await supabase.from('users').insert(...)。这中间有多少上下文浪费、多少 token 燃烧、多少次调 API 失败重来?答案是惊人的

直到我看到 insforge/insforge 这个项目——⭐12.2k、TypeScript、Apache-2.0、近 30 天持续活跃、被 Vercel OSS Program 收录——它的 README 第一句话就让我精神一振:

The all-in-one, open-source backend platform for agentic coding. InsForge gives your coding agent database, auth, storage, compute, hosting, and AI gateway to ship full-stack apps end-to-end.

它不只给 Agent「一个后端」,而是给 Agent 一整套 BaaS 工厂:Auth、Database、Storage、Model Gateway、Edge Functions、Compute、Site Deployment 七大原语都打包好;Agent 通过 MCP Server(自托管+云)和 CLI + Skills(云)两种通道就能像 backend engineer 一样操作资源。

这就是 Coding Agent 时代缺失的那块拼图——Backend-as-a-Service for Agents

二 项目定位与核心价值

2.1 一句话定义

InsForge 是一个面向 Coding Agent 的开源全栈后端平台——通过 MCP/CLI 双通道暴露 Auth、Database、Storage、Model Gateway、Edge Functions、Compute、Site Deployment 七大原语,让 Claude Code、Cursor、Codex、Continue 等 Coding Agent 拥有「后端工程师的手」。

2.2 核心能力矩阵

能力模块子能力用途实现技术栈
AuthenticationUser/Session/Admin/Custom OAuth (Google/GitHub/Discord/Microsoft/LinkedIn/X/Apple)用户管理 + 多 Provider 登录Better Auth + 自研 OAuth PKCE
DatabaseRecords/Query/RPC/Migration/BackupsPostgres 关系数据库 + 动态 APIPostgREST v12.2.12 + SQL Parser WASM
StorageS3 Compatible + SigV4 Streaming文件存储 + 大文件分片上传自研 S3 Gateway + 本地 / S3 双模式
Model GatewayChat/Embedding/Image GenerationOpenAI 兼容 API + 多 LLM 路由OpenRouter 单 Provider 抽象
Edge FunctionsDeno Subhosting + Local RuntimeServerless 边缘函数Deno 独立容器 + Subhosting 部署
ComputeLong-running Container长时运行容器服务自研服务编排
Site DeploymentVercel Bridge一键部署前端站点Vercel API 集成
Realtimepg_notify + Socket.IO数据库实时变更推送Postgres NOTIFY/LISTEN
MemoryRAG-ready Vector StoreAgent 长期记忆 + 语义检索pgvector 集成
SchedulesCron-style定时任务自研调度器
WebhooksSigned Payloads入站回调 + 签名验证自研 + Raw Body 处理
PaymentsStripe + Razorpay支付集成官方 SDK 桥接
AnalyticsUsage Tracking用量统计 + 仪表板自研事件流
LogsHTTP/Function/AI Logs链路追踪 + 日志聚合自研 logger + CloudWatch bridge
Web ScraperURL → Markdown网页抓取自研服务
SecretsPer-project Encrypted Vault项目级密钥保险库AES + Postgres 加密
EmailSMTP + Cloud邮件发送模板引擎 + 速率限制
AdvisorAI-assisted SuggestionsAI 建议与 LLM 集成
TelemetryAnonymous opt-in匿名遥测显式 opt-out 默认开启

2.3 仓库统计

字段
仓库insforge/insforge
主语言TypeScript (95%+)
LicenseApache-2.0
Star⭐ 12,200+
Size125 MB
最近推送2026-07-11
节点数1,731(git tree)
TS/TSX 源文件912
核心服务数20(backend/src/services/)
API 路由数22(backend/src/api/routes/)
Monorepo 包3(backend / dashboard / shared-schemas / ui)
Vercel OSS
一键部署Railway / Zeabur / Sealos

2.4 解决的问题

传统 Coding Agent 工作流最大的痛点不是写不出前端,而是后端集成成本

  • Context 爆炸:让 Agent 学习 7 个 SaaS 的 SDK 文档(Supabase + Firebase + Stripe + S3 + Vercel + Resend + OpenAI)≈ 50k+ token 上下文
  • 错误率高:每个 SaaS 都有自己的鉴权签名、错误码、限流策略,Agent 容易在边缘 case 翻车
  • 数据碎片化:用户数据在 Supabase、文件在 S3、日志在 CloudWatch、指标在 Datadog——Agent 看不懂一个完整请求
  • 自托管难:要让 Agent 跑本地后端,需要 Docker / docker-compose 编排 + 多服务启动脚本

InsForge 用单一进程 + 单一鉴权 + 单一 API 命名空间解决了以上所有问题:Coding Agent 只需学一个 API 形状——/api/{auth,database,storage,ai,memory,functions,realtime,email,payments,deployments,schedules,webhooks,webscraper,secrets,usage,advisor,logs,analytics}

三 整体架构

3.1 顶层架构图

flowchart TB
    subgraph AGENTS["Coding Agent 层"]
        CC[Claude Code]
        CU[Cursor]
        CO[Codex]
        CL[Cline]
        KI[Kiro]
        OT[其他 MCP 客户端]
    end

    subgraph ACCESS["接入层"]
        MCP[MCP Server<br/>自托管 + 云]
        CLI[CLI + Skills<br/>云端]
    end

    subgraph INSFORGE["InsForge 核心服务"]
        direction TB
        subgraph MID["API 网关 Express 7130"]
            AUTH[Auth Router]
            DB[Database Router]
            ST[Storage Router]
            AI[AI Router]
            MEM[Memory Router]
            FN[Functions Router]
            RT[Realtime Router]
        end
        subgraph SERVICES["服务层"]
            direction TB
            AUTHSVC[Auth Service<br/>Better Auth + PKCE]
            DBSVC[Database Service<br/>PostgREST + SQL Parser]
            STSVC[Storage Service<br/>S3 Gateway]
            AISVC[AI Service<br/>OpenRouter]
            Memsvc[Memory Service<br/>pgvector]
            FNSVC[Functions Service<br/>Deno Subhosting]
            RTSVC[Realtime Service<br/>pg_notify]
        end
        subgraph INFRA["基础设施层"]
            PG[(PostgreSQL<br/>+ pgvector)]
            DENO[Deno Runtime<br/>Edge Functions]
            S3[(S3 / 本地<br/>文件系统)]
        end
    end

    AGENTS -->|MCP 协议| MCP
    AGENTS -->|CLI 调用| CLI
    MCP --> MID
    CLI --> MID
    AUTH --> AUTHSVC
    DB --> DBSVC
    ST --> STSVC
    AI --> AISVC
    MEM --> Memsvc
    FN --> FNSVC
    RT --> RTSVC
    AUTHSVC --> PG
    DBSVC --> PG
    STSVC --> S3
    AISVC --> PG
    Memsvc --> PG
    FNSVC --> DENO
    FNSVC --> PG
    RTSVC --> PG

    classDef agent fill:#fde0c5,stroke:#e8a87c,color:#3a2a1a
    classDef access fill:#c5e0fd,stroke:#7ca8e8,color:#1a2a3a
    classDef router fill:#d4f0c5,stroke:#8ac76b,color:#1a3a1a
    classDef svc fill:#f0c5e8,stroke:#c76bb0,color:#3a1a2a
    classDef infra fill:#e0d4f0,stroke:#9683d4,color:#2a1a3a

    class CC,CU,CO,CL,KI,OT agent
    class MCP,CLI access
    class AUTH,DB,ST,AI,MEM,FN,RT router
    class AUTHSVC,DBSVC,STSVC,AISVC,Memsvc,FNSVC,RTSVC svc
    class PG,DENO,S3 infra

3.2 Docker Compose 自托管拓扑

flowchart LR
    subgraph HOST["单台主机"]
        direction TB
        subgraph NET["insforge-network"]
            PG[postgres<br/>5432<br/>PostgreSQL 17 + pgvector]
            PGR[postgrest<br/>5430<br/>PostgREST v12.2.12]
            INS[insforge<br/>7130/7131<br/>主 API 服务]
            DENO[deno<br/>7133<br/>Edge Function 运行时]
        end
        VOL1[(postgres-data)]
        VOL2[(storage-data)]
        VOL3[(insforge-logs)]
    end
    CLI[CLI Client / Coding Agent] -->|HTTP 7130| INS
    MCP_CLIENT[MCP Client] -->|MCP over HTTP 7130| INS
    INS -->|SQL 5432| PG
    INS -->|REST 3000| PGR
    PGR -->|SQL 5432| PG
    INS -->|Deploy/Invoke| DENO
    DENO -->|SQL 5432| PG
    PG --- VOL1
    INS --- VOL2
    INS --- VOL3

    classDef svc fill:#c5e0fd,stroke:#7ca8e8,color:#1a2a3a
    classDef vol fill:#fde0c5,stroke:#e8a87c,color:#3a2a1a
    classDef client fill:#d4f0c5,stroke:#8ac76b,color:#1a3a1a

    class PG,PGR,INS,DENO svc
    class VOL1,VOL2,VOL3 vol
    class CLI,MCP_CLIENT client

整个自托管只跑 3 个核心容器 + 1 个 Deno 运行时,多项目隔离靠 .env.projectN + -p projectN 实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 来自 deploy/docker-compose/docker-compose.yml:1-50
services:
postgres:
image: ghcr.io/insforge/postgres-all:latest
environment:
- POSTGRES_USER=${POSTGRES_USER:-postgres}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
- POSTGRES_DB=${POSTGRES_DB:-insforge}
- ENCRYPTION_KEY=${ENCRYPTION_KEY:-${JWT_SECRET:-dev-secret-please-change-in-production}}
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "${POSTGRES_PORT:-5432}:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5

postgrest:
image: postgrest/postgrest:v12.2.12
environment:
PGRST_DB_URI: postgres://${POSTGRES_USER:-postgres}@postgres:5432/${POSTGRES_DB:-insforge}
PGRST_OPENAPI_SERVER_PROXY_URI: http://localhost:3000
PGRST_DB_SCHEMA: public
PGRST_DB_ANON_ROLE: anon
PGRST_JWT_SECRET: ${JWT_SECRET:-dev-secret-please-change-in-production}
PGRST_DB_CHANNEL_ENABLED: true # Enable schema reloading via NOTIFY

insforge:
image: ghcr.io/insforge/insforge-oss:v1.5.0
depends_on:
postgres: { condition: service_healthy }
postgrest: { condition: service_healthy }
ports:
- "${APP_PORT:-7130}:7130"
- "${AUTH_PORT:-7131}:7131"

deno:
image: ghcr.io/insforge/deno-runtime:latest
ports:
- "${DENO_PORT:-7133}:7133"

四 七大原语的应用类型

4.1 原语分类

InsForge 的 20+ 服务可归类为四大原语族:

原语族服务共同基类设计模式
数据持久族Database / MemoryDatabaseService + pgvectorRepository + Active Record
身份认证族Auth (Admin/User/OAuth)TokenManager (JWKS) + SecretServiceStrategy + Chain of Responsibility
AI 能力族AI Chat/Embedding/ImageOpenRouterProvider (单 Provider 抽象)Provider + Adapter
资源编排族Storage / Functions / Compute / Deployments / SchedulesSingleton ServiceManager + Proxy
辅助族Logs / Analytics / Telemetry / Webhooks / Email / Secrets / Realtime / Payments / Advisor / Webscraper各自独立各自独立

4.2 服务单例模式

所有服务都遵循 Singleton + Lazy Init 模式,避免重复创建昂贵资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 来自 backend/src/server.ts:60-75
export async function createApp() {
// Initialize database first
const dbManager = DatabaseManager.getInstance();
await dbManager.initialize(); // create data/app.db

// Initialize storage service
const storageService = StorageService.getInstance();
await storageService.initialize(); // create data/storage

// Initialize logs service
const logService = LogService.getInstance();
await logService.initialize(); // connect to CloudWatch

// Initialize SQL parser WASM module
await initSqlParser();

const app = express();
// ... 中间件链 + 路由挂载
}

四个关键服务在 Express 启动前完成 init:DatabaseManager(建 SQLite 索引)、StorageService(建本地存储目录)、LogService(连接 CloudWatch)、initSqlParser(载入 SQL Parser WASM)。这种”启动序贯依赖”模式比 DI 容器更轻量,适合 Coding Agent 后端这种”组件数量固定、依赖清晰”的场景。

五 核心引擎一 Express API 网关

5.1 网关路由挂载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 来自 backend/src/server.ts:178-227
const apiRouter = express.Router();

apiRouter.get('/health', (_req, res) => {
res.json({
status: 'ok',
version: packageJson.version,
service: 'Insforge OSS Backend',
timestamp: new Date().toISOString(),
});
});

// Mount all routes
apiRouter.use('/auth', authRouter);
apiRouter.use('/database', databaseRouter);
apiRouter.use('/storage', storageRouter);
apiRouter.use('/metadata', metadataRouter);
apiRouter.use('/logs', logsRouter);
apiRouter.use('/docs', docsRouter);
apiRouter.use('/functions', functionsRouter);
apiRouter.use('/secrets', secretsRouter);
apiRouter.use('/usage', usageRouter);
apiRouter.use('/ai', aiRouter);
apiRouter.use('/memory', memoryRouter);
apiRouter.use('/realtime', realtimeRouter);
apiRouter.use('/email', emailRouter);
apiRouter.use('/deployments', deploymentsRouter);
apiRouter.use('/schedules', schedulesRouter);
apiRouter.use('/payments', paymentsRouter);
apiRouter.use('/compute/services', servicesRouter);
apiRouter.use('/analytics', analyticsRouter);
apiRouter.use('/webscraper', webscraperRouter);
apiRouter.use('/advisor', advisorRouter);

app.use('/api', apiRouter);

22 个 Router 子树全部挂载在 /api 前缀下,所有路径都遵循 RESTful 资源命名/api/{resource}/{action})。这种”扁平化 Router 子树”设计的好处是:Coding Agent 不需要记忆复杂的嵌套路径,只要知道”我有 7 大原语 → 找对应 Router”。

5.2 三段式中间件链

flowchart LR
    REQ[HTTP Request] --> CORS[CORS<br/>origin: true]
    CORS --> COOKIE[cookie-parser]
    COOKIE --> OBS[观测中间件<br/>记录 method/path/status/size/duration]
    OBS --> RAW{路径匹配?}
    RAW -->|/api/webhooks| WBR[express.raw]
    RAW -->|/storage/v1/s3| S3G[s3GatewayRouter]
    RAW -->|其他| JSON[express.json]
    WBR --> API[apiRouter]
    S3G --> API
    JSON --> API
    API --> AUTH_MW[auth middleware<br/>verifyUser/verifyAdmin]
    AUTH_MW --> ROUTE[业务路由]
    ROUTE --> RES[response]
    RES --> ERR[errorMiddleware]

    classDef mw fill:#c5e0fd,stroke:#7ca8e8,color:#1a2a3a
    classDef branch fill:#fde0c5,stroke:#e8a87c,color:#3a2a1a
    classDef route fill:#d4f0c5,stroke:#8ac76b,color:#1a3a1a

    class CORS,COOKIE,OBS,AUTH_MW,ERR mw
    class RAW,WBR,S3G,JSON branch
    class API,ROUTE,RES route

为什么 webhooks 和 S3 gateway 要 raw body?

  • webhooks:Stripe / Razorpay 回调用 HMAC 签名验证原始字节,JSON 解析会破坏签名
  • S3 gateway:流式签名(STREAMING-AWS4-HMAC-SHA256-PAYLOAD)需要原始 chunk,JSON 解析会破坏 chunk boundary

这是一个非常精细的工程决策——把 webhooks 和 S3 放在 JSON parser 之前挂载,让它们的 body 在签名验证前保持完整字节流。这种”路径感知的 body parser 链”是 Backend-as-a-Service 的标准模式。

六 核心引擎二 多 Provider 鉴权体系

6.1 三种凭证的统一调度

InsForge 的鉴权设计是最值得深入研究的模块之一——它需要同时支持 API Key、JWT、匿名 Key 三种凭证,且每种凭证的签发、刷新、吊销路径都不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 来自 backend/src/api/middlewares/auth.ts:30-93
const tokenManager = TokenManager.getInstance();
const secretService = SecretService.getInstance();

// Helper function to extract Bearer token (exported for optional auth checks)
export function extractBearerToken(authHeader: string | undefined): string | null {
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return null;
}
return authHeader.substring(7);
}

// Helper function to extract API key from request
// Checks both Bearer token (if starts with 'ik_') and x-api-key header
export function extractApiKey(req: AuthRequest): string | null {
const bearerToken = extractBearerToken(req.headers.authorization);
if (bearerToken && bearerToken.startsWith('ik_')) {
return bearerToken;
}
// Fall back to x-api-key header for backward compatibility
if (req.headers['x-api-key']) {
return req.headers['x-api-key'] as string;
}
return null;
}

// Helper function to extract the opaque anon key from a request
// The anon key travels in the Authorization header like every other client
// credential (Bearer anon_...); signed-in clients replace it with their JWT.
export function extractAnonKey(req: AuthRequest): string | null {
const bearerToken = extractBearerToken(req.headers.authorization);
if (bearerToken && bearerToken.startsWith('anon_')) {
return bearerToken;
}
return null;
}

/**
* Verifies user authentication (accepts API keys, anon keys, and JWT tokens)
*
* All credentials travel in the Authorization header; dispatch is by shape,
* never by falling back on failure:
* - `ik_...` (Bearer or x-api-key) -> admin API key
* - Bearer `anon_...` -> opaque anon key, `anon` role
* - any other Bearer -> JWT (role claim decides admin/authenticated/legacy anon)
*/
export async function verifyUser(req: AuthRequest, res: Response, next: NextFunction) {
const apiKey = extractApiKey(req);
if (apiKey) {
return verifyApiKey(req, res, next);
}

const bearerToken = extractBearerToken(req.headers.authorization);
if (bearerToken && bearerToken.startsWith('anon_')) {
// ...

三条互斥的鉴权路径

  1. ik_... 前缀 → Admin API Key(服务端到服务端,绕过用户身份)
  2. anon_... 前缀 → 匿名 Key(未登录用户,DB 层用 RLS 隔离)
  3. 其他 Bearer → JWT(登录用户,role claim 决定 admin / authenticated)

关键设计哲学:”dispatch is by shape, never by falling back on failure“——三种凭证是互斥的而不是”降级链”。

Signed-out clients send the anon key as their Bearer credential; signing in replaces it with the user JWT. Each branch fails closed: an invalid or expired user JWT must return 401 (so SDK refresh flows trigger) — it must never silently downgrade to anon.

“失败即关闭、不静默降级”——这避免了”匿名 Key 伪装成 user”的安全漏洞。对 Coding Agent 来说这非常友好:Agent 写代码时不需要关心”我现在是登录还是匿名”,SDK 内部已经根据凭证形状自动派发

6.2 JWKS 标准端点

1
2
3
4
5
6
7
8
9
10
11
12
13
// 来自 backend/src/server.ts:181-192
const jwksHandler = async (_req: Request, res: Response) => {
try {
const jwks = await TokenManager.getInstance().getJwks();
res.json(jwks);
} catch (error) {
logger.error('Failed to serve JWKS', { error });
res.status(500).json({ error: 'Internal Server Error' });
}
};

app.get('/.well-known/jwks.json', jwksHandler);
apiRouter.get('/.well-known/jwks.json', jwksHandler);

/.well-known/jwks.json 同时挂在根路径和 /api 路径下——这种”双挂载”是为了兼容 OAuth 2.0 标准的回调探测(很多 OAuth IdP 会同时探测两个路径)。JWKS (JSON Web Key Set) 让外部服务无需预共享密钥就能验证 JWT 签名。

七 核心引擎三 AI Provider 单抽象

7.1 OpenRouter Provider

InsForge 的 AI 层只支持一个 Provider——OpenRouter。但 OpenRouter 本身就是多 LLM 路由层(OpenAI/Anthropic/Google/Mistral/DeepSeek 等 100+ 模型都走同一个 OpenAI 兼容 API),所以”单 Provider”实际上等于”全模型覆盖”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// 来自 backend/src/api/routes/ai/index.routes.ts:147-223
router.post(
'/chat/completion',
verifyUser,
async (req: AuthRequest, res: Response, next: NextFunction) => {
try {
const validationResult = chatCompletionRequestSchema.safeParse(req.body);
if (!validationResult.success) {
throw new AppError(
`Validation error: ${validationResult.error.errors.map((e) => e.message).join(', ')}`,
400,
ERROR_CODES.INVALID_INPUT
);
}

const { stream, messages, ...options } = validationResult.data;

// Handle streaming requests
if (stream) {
// Now we know the model is valid, set headers for SSE
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

// Create and process the stream
try {
const streamGenerator = chatService.streamChat(messages, options);

for await (const data of streamGenerator) {
if (data.chunk) {
res.write(`data: ${JSON.stringify({ chunk: data.chunk })}\n\n`);
}
if (data.tokenUsage) {
res.write(`data: ${JSON.stringify({ tokenUsage: data.tokenUsage })}\n\n`);
}
if (data.tool_calls) {
res.write(`data: ${JSON.stringify({ tool_calls: data.tool_calls })}\n\n`);
}
if (data.annotations) {
res.write(`data: ${JSON.stringify({ annotations: data.annotations })}\n\n`);
}
}

// Send completion signal
res.write(`data: ${JSON.stringify({ done: true })}\n\n`);
} catch (streamError) {
// If error occurs during streaming, send it in SSE format
logger.error('Stream error during chat completion', { error: streamError });
res.write(
`data: ${JSON.stringify({ error: true, message: streamError instanceof Error ? streamError.message : String(streamError) })}\n\n`
);
}

res.end();
return;
}

// Non-streaming requests
const result = await chatService.chat(messages, options);
successResponse(res, result);
} catch (error) {
if (error instanceof AppError) {
next(error);
} else {
next(new AppError(error instanceof Error ? error.message : 'Failed to generate chat', 500, ERROR_CODES.INTERNAL_ERROR));
}
}
}
);

SSE 流式响应的 4 种事件类型

  1. chunk — 文本增量
  2. tokenUsage — 用量统计
  3. tool_calls — 工具调用(Function Calling)
  4. annotations — 注释(citations / sources)

“Done signal” 协议{ done: true } 让 Coding Agent 知道流结束,避免无 chunk 时的死循环判断

7.2 AI Model Catalog + 缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// 来自 backend/src/services/ai/ai-model.service.ts:7-72
const MODELS_CACHE_TTL_MS = 60 * 60 * 1000; // 1 小时
const OPENROUTER_MODELS_URL = 'https://openrouter.ai/api/v1/models?output_modalities=all';

let modelsCache: {
expiresAt: number;
models: AIModelSchema[];
} | null = null;

/**
* Tracks an in-flight request to the OpenRouter model catalog.
* Used to deduplicate concurrent cache-miss requests and prevent cache stampedes.
*/
let fetchInFlight: Promise<AIModelSchema[]> | null = null;

let circuitBreakerUntil = 0;

export class AIModelService {
static async getModels(): Promise<AIModelSchema[]> {
if (Date.now() < circuitBreakerUntil) {
throw new AppError(
'Upstream AI models catalog is temporarily unavailable.',
503,
ERROR_CODES.AI_UPSTREAM_UNAVAILABLE
);
}

if (modelsCache && modelsCache.expiresAt > Date.now()) {
return modelsCache.models;
}

if (fetchInFlight) {
return fetchInFlight;
}

fetchInFlight = (async () => {
try {
const response = await fetch(OPENROUTER_MODELS_URL);

if (!response.ok) {
throw new AppError(
`Failed to fetch models: ${response.statusText}`,
503,
ERROR_CODES.AI_UPSTREAM_UNAVAILABLE
);
}

const data = (await response.json()) as { data: RawOpenRouterModel[] };
const rawModels = data.data || [];

const models: AIModelSchema[] = rawModels
.map((rawModel) => {
const inputModality = normalizeModalities(
rawModel.architecture?.input_modalities || []
);
const outputModality = normalizeModalities(
rawModel.architecture?.output_modalities || []
);
const { inputPrice, outputPrice, inputPriceLabel, outputPriceLabel } =
calculateTokenPrices(rawModel.pricing, inputModality, outputModality);
return {
id: rawModel.modelId,
created: rawModel.created,
modelId: rawModel.modelId,
provider: 'openrouter',
inputModality,
outputModality,
inputPrice,
outputPrice,
inputPriceLabel,
outputPriceLabel,
};
})
.filter((model) => model.inputModality.length > 0 && model.outputModality.length > 0)
.sort((a, b) => {
// ...
});

三个工程亮点

  1. 1 小时 TTL 内存缓存——避免每次 /api/ai/models 都打 OpenRouter
  2. fetchInFlight 单飞模式——并发请求时复用同一个 in-flight Promise,避免 cache stampede(缓存击穿)
  3. circuitBreakerUntil 熔断器——上游失败时进入 503 冷却期,避免反复打挂掉的上游

为什么用 OpenRouter 而不是自己集成 OpenAI/Anthropic/Google?

  • 统一 OpenAI 兼容协议——Coding Agent 只需学一个 chat completion API 形状
  • 自动故障转移——OpenRouter 后端做模型 fallback,Agent 不用关心
  • 价格透明——pricing 字段直接计算 token 价格,Dashboard 展示

这种”单 Provider 多模型”策略与 LiteLLM / Portkey 的”多 Provider 抽象”哲学正交不重叠——InsForge 不打算做”跨 Provider 路由”,而是把 Provider 路由外包给 OpenRouter

八 工具系统 MCP 双通道接入

8.1 MCP Server + CLI + Skills 三件套

flowchart TB
    subgraph AGENT["Coding Agent"]
        direction LR
        AGENT_CORE[Agent 核心<br/>Claude Code / Cursor / Codex]
        AGENT_CORE -->|MCP 协议| MCPCLIENT[MCP Client]
        AGENT_CORE -->|Shell 调用| CLICALL[CLI subprocess]
    end

    subgraph INSFORGE_AC["InsForge 接入层"]
        direction TB
        MCPSRV[MCP Server<br/>@insforge/mcp-server]
        CLISRV[CLI<br/>@insforge/cli]
        SKILLS[Skills<br/>Markdown 指令集]
    end

    subgraph RESOURCES["InsForge Resources"]
        direction TB
        AUTH[Auth Tools]
        DBT[Database Tools]
        STT[Storage Tools]
        AIT[AI Tools]
        MEMT[Memory Tools]
        FNT[Functions Tools]
        DPT[Deployment Tools]
    end

    MCPCLIENT -->|stdio / HTTP| MCPSRV
    CLICALL -->|stdio| CLISRV
    CLISRV -->|读取| SKILLS
    MCPSRV --> AUTH
    MCPSRV --> DBT
    MCPSRV --> STT
    MCPSRV --> AIT
    MCPSRV --> MEMT
    MCPSRV --> FNT
    MCPSRV --> DPT
    CLISRV --> AUTH
    CLISRV --> DBT
    CLISRV --> STT
    CLISRV --> AIT
    CLISRV --> MEMT
    CLISRV --> FNT
    CLISRV --> DPT

    classDef agent fill:#fde0c5,stroke:#e8a87c,color:#3a2a1a
    classDef srv fill:#c5e0fd,stroke:#7ca8e8,color:#1a2a3a
    classDef res fill:#d4f0c5,stroke:#8ac76b,color:#1a3a1a

    class AGENT_CORE,MCPCLIENT,CLICALL agent
    class MCPSRV,CLISRV,SKILLS srv
    class AUTH,DBT,STT,AIT,MEMT,FNT,DPT res

接入哲学:Coding Agent 通过两种通道访问 InsForge——

  1. MCP Server(自托管 + 云):Agent 把 InsForge 当作 MCP 工具集,每个原语(Auth/DB/Storage/AI…)暴露为一组 tools
  2. CLI + Skills(云):Agent 通过 insforge <command> 调用 + 读取 SKILL.md 获取指令(类似 Manus / Claude Skills 模式)

自托管时只能用 MCP(CLI 是云托管专属)——这与 OpenAI Agents SDK / Claude Code 的”open-source 只能 MCP”哲学一致。CLI + Skills 是 InsForge 云的差异化卖点——它把”如何用 InsForge”的指令作为 Markdown 与 CLI 命令捆绑,Agent 不用拼凑多个文档源。

8.2 MCP 工具注册模式

backend/src/api/middlewares/auth.tsverifyUser middleware 同时被 /api/ai/*/api/database/* 使用——这意味着MCP server 把每个 API endpoint 包装成一个 tool 时,鉴权自动继承。Coding Agent 调 insforge.createUser() 不需要单独管理 token,SDK / MCP server 自动用 anon key / user JWT 鉴权

九 PostgREST 动态数据库层

9.1 PostgREST 12.2 集成

InsForge 用 PostgREST 把 Postgres 直接暴露为 REST API——这意味着任何表都会自动得到 CRUD endpointsCoding Agent 不需要学 ORM

1
2
3
4
5
6
7
8
9
10
11
# 来自 deploy/docker-compose/docker-compose.yml
postgrest:
image: postgrest/postgrest:v12.2.12
environment:
PGRST_DB_URI: postgres://${POSTGRES_USER:-postgres}@postgres:5432/${POSTGRES_DB:-insforge}
PGRST_OPENAPI_SERVER_PROXY_URI: http://localhost:3000
PGRST_DB_SCHEMA: public
PGRST_DB_ANON_ROLE: anon
PGRST_JWT_SECRET: ${JWT_SECRET:-dev-secret-please-change-in-production}
PGRST_DB_CHANNEL_ENABLED: true # Enable schema reloading via NOTIFY
PGRST_DB_CHANNEL: pgrst

PGRST_DB_CHANNEL_ENABLED 是关键——它开启 Postgres LISTEN/NOTIFY 通道,让 PostgREST 在表结构变更时自动 reload schema。Coding Agent 跑 CREATE TABLE products (...) 之后,/products endpoint 立刻可用,不需要重启 PostgREST。

9.2 SQL Parser WASM 校验

backend/src/server.ts:74await initSqlParser() 加载一个 SQL Parser WASM 模块——所有 Agent 发来的 SQL 都会先过这个 parser防止 SQL 注入 + 解析查询计划。这是 PostgREST 自己不做、InsForge 在更上层补齐的能力。

9.3 Realtime via pg_notify

1
2
3
4
// 来自 backend/src/server.ts:338-340
// Initialize RealtimeManager (pg_notify listener)
const realtimeManager = RealtimeManager.getInstance();
await realtimeManager.initialize();

RealtimeManager 监听 Postgres LISTEN/NOTIFY 通道——任何表 INSERT/UPDATE/DELETE 都会触发 NOTIFYSocket.IO 把事件推给订阅的 Agent。Coding Agent 写”实时通知”功能时不用轮询,直接订阅 channel 即可

十 端到端数据流

10.1 序列图:Agent 创建一个 user 并发邮件

sequenceDiagram
    autonumber
    participant Agent as Coding Agent<br/>(Claude Code)
    participant MCP as MCP Server<br/>(@insforge/mcp-server)
    participant Auth as Auth Router<br/>verifyAdmin
    participant AS as Auth Service
    participant PG as PostgreSQL
    participant Email as Email Router
    participant ES as Email Service
    participant SMTP as SMTP Provider

    Agent->>MCP: mcp__insforge__create_user(email, password)
    MCP->>Auth: POST /api/auth/admin/users<br/>Bearer ik_xxx
    Auth->>Auth: verifyAdmin (admin API key 校验)
    Auth->>AS: authService.createUser(...)
    AS->>PG: INSERT INTO users (...)
    PG-->>AS: user_id
    AS-->>Auth: { id, email, role: 'authenticated' }
    Auth-->>MCP: 201 { user }

    Agent->>MCP: mcp__insforge__send_email(to, subject, body)
    MCP->>Email: POST /api/email<br/>verifyUser (user JWT)
    Email->>ES: emailService.send(...)
    ES->>ES: rate limiter check
    ES->>SMTP: SMTP.send(...)
    SMTP-->>ES: 250 OK
    ES->>PG: INSERT INTO email_logs (...)
    ES-->>Email: { messageId }
    Email-->>MCP: 200 { messageId }
    MCP-->>Agent: { messageId }

MCP server 完全是协议转换层——它把 MCP 协议(stdio / HTTP)翻译成 InsForge 内部 HTTP API,不直接访问数据库。这种”协议层 = thin proxy”的设计让 InsForge 可以独立升级内部 API 而不破坏 MCP 兼容性

十一 与同类项目对比

11.1 横向对比表

维度InsForgeSupabaseFirebaseAppwriteConvex
定位Agent BaaS通用 BaaSGoogle 通用 BaaS通用 BaaSReactive BaaS
开源✅ Apache-2.0✅ Apache-2.0❌ 部分开源✅ BSD-3✅ Apache-2.0
数据库PostgresPostgresFirestore (NoSQL)MariaDB / Postgres自研 (Datalog)
鉴权JWT + API Key + Anon KeyJWT + API KeyFirebase AuthJWT + API KeyJWT
实时pg_notifyRealtime (Phoenix)Firestore listenersRealtime (WebSocket)内置 (Reactive)
函数Deno Edge FunctionsEdge Functions (Deno)Cloud FunctionsCloud FunctionsQuery functions (TS)
存储S3 CompatibleS3 CompatibleGCSS3 CompatibleS3 Compatible
AI Gateway✅ OpenRouter❌ 需集成❌ 需集成❌ 需集成❌ 需集成
MCP 接入✅ 内置 (双通道)❌ 第三方❌ 第三方❌ 第三方❌ 第三方
Coding Agent Skills✅ 内置 (云)❌ 社区❌ 社区❌ 社区❌ 社区
自托管✅ docker-compose✅ docker-compose❌(仅云)✅ docker-compose❌(仅云)
部署复杂度🟢 低 (3 容器)🟡 中 (10+ 容器)🟢 极低 (云)🟡 中🟢 低 (云)

11.2 设计差异分析

(1) Agent 优先 vs 开发者优先

  • Supabase / Firebase 的设计哲学是”给开发者最快路径”——Dashboard UI + 详细文档 + JS SDK 是核心
  • InsForge 是”给 Agent 最快路径”——MCP server + Skills + CLI 是核心,Dashboard 是次要

具体表现

  • InsForge 22 个 Router 全部设计成”machine-readable”(REST + OpenAPI),Agent 跑 fetch 即可
  • InsForge 把 fetch-docs 工具内置到 MCP server——Agent 不用离开 IDE 就能读官方文档
  • InsForge 提供 verify-installation MCP prompt——Agent 跑 prompt 即可确认配置成功

(2) 单进程 vs 微服务

  • Supabase 是 20+ 微服务(GoTrue / PostgREST / Realtime / Storage / Functions / Studio / Kong / …)
  • InsForge 是 1 个 Node.js 主进程(7129 行 server.ts)+ 1 个 Deno runtime + 1 个 PostgREST + 1 个 Postgres

单进程的代价:横向扩展能力差——单实例 InsForge 大约能扛 1000 RPS,超过需要换 Supabase。
单进程的收益:Coding Agent 只需读一个进程的源码,调试和定制比 Supabase 简单 10 倍。

(3) 鉴权多凭证 vs 单一凭证

  • Firebase 用单一 ID Token,所有调用都发这个
  • Supabase 用 anon key + service_role key,两把钥匙
  • InsForgeAPI key (ik_) + anon key (anon_) + JWT 三种,每种凭证形状互斥(前面 6.1 节的 verifyUser

三凭证的工程价值

  • ik_ 给 Agent 的 admin tool——绕过用户身份直接管理资源
  • anon_ 给未登录前端——DB 层 RLS 隔离
  • JWT 给登录用户——role claim 决定权限

这是 InsForge 的精妙之处让 Agent 知道”我现在调的是哪个层”——调 admin tool 用 ik,调前端 SDK 用 anon/JWT,凭证不混用

十二 优缺点分析

12.1 左侧 优势(架构简洁性 / 扩展性 / 易用性)

优势详细说明
Agent-first 设计MCP server + Skills + CLI 三通道,让 Claude Code / Cursor / Codex 等 Agent 开箱即用
七原语覆盖Auth + DB + Storage + AI Gateway + Functions + Compute + Deployment——一个项目覆盖 90% Web 后端需求
Apache-2.0 协议可商用、可修改、可分发,对企业友好
Vercel OSS 收录基础设施质量得到背书,降低企业选型风险
单进程 server7129 行 TypeScript + 1 文件 Express 配置,Coding Agent 改一行就能 fork 出私有部署
PostgREST 动态 schemaCREATE TABLE → REST endpoint 立刻可用,Agent 不需要学 ORM
OpenRouter 单 Provider 抽象100+ 模型统一 API,Agent 不用记 5 个 LLM SDK
Docker Compose 自托管3 容器 + 1 网络,5 分钟启动
Railway / Zeabur / Sealos 一键部署不会 Docker 也能上线

12.2 右侧 代价(性能 / 复杂度 / 维护性)

代价详细说明
单实例上限约 1000 RPS单 Express 进程 + 单 Postgres,横向扩展需要换架构
OpenRouter 单点依赖OpenRouter 挂了 = 整个 AI 能力挂了,没有 fallback
Deno 运行时碎片化边缘函数用 Deno 不用 Node.js,Agent 学两套运行时
CLI 只在云端可用自托管用户只能用 MCP,没有原生命令行体验
20+ 服务 22 路由对小型应用过重,一个 Todo App 启动 22 个路由
文档相对 Supabase 较薄很多 endpoint 行为需要读源码确认,Agent 易踩坑
realtime 弱于 Supabase仅 pg_notify,无 broadcast 模式,复杂实时场景不够用
payments 集成深度有限仅 Stripe + Razorpay,没有 Alipay / WeChat Pay 桥接

12.3 核心权衡

InsForge 选择了”Agent 体验”作为最高优先级——为此牺牲了部分横向扩展能力、牺牲了多语言 SDK、牺牲了部分企业级特性(audit log / RBAC / 多 region)。这种”在垂直场景做到极致”的哲学与 Supabase 的”通用 BaaS 平台”哲学正交

十三 实践 部署与端到端调用

13.1 5 分钟启动 InsForge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. 克隆仓库
git clone https://github.com/InsForge/InsForge.git
cd InsForge

# 2. 复制环境变量模板
cp .env.example .env

# 3. 启动(3 容器 + 1 网络)
docker compose -f docker-compose.prod.yml up -d

# 4. 等待健康检查
docker compose -f docker-compose.prod.yml ps
# NAME STATUS PORTS
# insforge-postgres-1 Up (healthy) 0.0.0.0:5432->5432/tcp
# insforge-postgrest-1 Up (healthy) 0.0.0.0:5430->3000/tcp
# insforge-insforge-1 Up 0.0.0.0:7130->7130/tcp, 0.0.0.0:7131->7131/tcp
# insforge-deno-1 Up 0.0.0.0:7133->7133/tcp

# 5. 打开 Dashboard
open http://localhost:7130/dashboard

13.2 在 Claude Code 中接入 MCP

1
2
3
4
5
6
7
8
9
10
# 添加 MCP server(假设 InsForge 跑在 localhost:7130)
claude mcp add --transport http insforge http://localhost:7130/mcp

# 验证连接
claude mcp list
# insforge: http://localhost:7130/mcp (connected)

# 让 Agent 验证安装
# 在 Claude Code 中输入:
# "I'm using InsForge as my backend platform, call InsForge MCP's fetch-docs tool to learn about InsForge instructions."

13.3 Coding Agent 创建数据库表 + 上传文件 + 调 AI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// agent-code.ts - Coding Agent 实际跑的代码
import { createClient } from '@insforge/sdk';

// Agent 拿到 anon key 后,初始化 client
const insforge = createClient(
'http://localhost:7130',
'anon_xxxxxxxxxxxxxxxx' // anon key
);

// 1. 创建表(通过 PostgREST 动态暴露)
const { error: createTableErr } = await insforge.database
.from('todos')
.insert([{ title: 'Buy milk', completed: false }]);
if (createTableErr) {
// 第一次调用会失败因为表不存在,Agent 会跑:
// CREATE TABLE todos (id SERIAL PRIMARY KEY, title TEXT, completed BOOLEAN)
}

// 2. 上传文件
const { data: file } = await insforge.storage
.from('avatars')
.upload('user-1/avatar.png', pngBuffer);
console.log('Uploaded:', file.url);

// 3. 调 AI(chat completion)
const { data: aiResponse } = await insforge.ai.chat.completion({
model: 'anthropic/claude-3.5-sonnet',
messages: [{ role: 'user', content: 'Write a haiku about coding agents' }],
});
console.log('AI:', aiResponse.choices[0].message.content);

// 4. 发送邮件
const { data: email } = await insforge.email.send({
to: 'user@example.com',
subject: 'Welcome',
body: 'Thanks for signing up!',
});
console.log('Email sent:', email.messageId);

Coding Agent 不需要知道

  • PostgREST 怎么把 SQL 转 REST
  • S3 兼容签名怎么算
  • OpenRouter 怎么选模型
  • SMTP 怎么连接

它只调用统一的 SDK 方法——这是 BaaS for Agents 的最大价值。

13.4 Skills 使用模式(云端专属)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 来自 .agents/skills/insforge-dev/SKILL.md -->
# InsForge Development Skill

## Overview
You are an AI coding agent with access to InsForge as a backend platform.
InsForge provides database, auth, storage, and serverless functions.

## Workflow
1. Before writing code, call `fetch-docs` to understand InsForge API surface.
2. Use `mcp__insforge__create_user` to create users.
3. Use `mcp__insforge__run_sql` to create tables.
4. Use `mcp__insforge__upload_file` to upload assets.
5. Use `mcp__insforge__deploy_function` to deploy edge functions.
6. Use `mcp__insforge__verify_installation` to confirm everything works.

## Best Practices
- Always use `anon_` keys for client-side code.
- Use `ik_` keys only for admin operations.
- Run `migrate_database` after schema changes to keep types in sync.

Skills = Markdown 形式的”prompt 指令”——Coding Agent 启动时自动加载,类似 Manus / Claude Skills。这是 Anthropic 推广的 Skills 范式与 Backend-as-a-Service 的首次深度结合

十四 趋势与总结

14.1 三大趋势判断

趋势一:Agent BaaS 将在 2026 H2 爆发

随着 Claude Code / Cursor / Codex 等 Coding Agent 普及,”后端集成成本“成为 Agent 落地最大瓶颈。InsForge 的**”七原语 + MCP”组合已经被 Vercel OSS 收录,说明业界认可这是未来 18 个月的关键赛道**。下一个可能的入局者:Cloudflare(已有 D1 / R2 / Workers,但 MCP 集成刚起步)、Supabase(已经做了 supabase-mcp-server,但需手动配置)。

趋势二:单 Provider 多模型 = 主流 LLM 集成模式

InsForge 选择”OpenRouter 单抽象“而非”多 Provider 适配“是反直觉但正确的——因为:

  • 99% 的 Agent 场景只需要”OpenAI 兼容协议 + 多模型 fallback”
  • 自建多 Provider 适配维护成本高(每月都有新模型发布)
  • OpenRouter / LiteLLM / Portkey 已经做了这层抽象,Backend BaaS 应站在巨人肩膀上

趋势三:Skills-as-Docs 成为 Agent 时代新分发模式

传统的”文档网站 + SDK + 示例代码”对人类友好,对 Agent 几乎无用——Agent 不会滚动页面、不会点跳转链接。Skills(Markdown + MCP tools 引用)为 Agent 重写的”文档”——机器可读 + 自描述 + 与 CLI/MCP 联动。InsForge 的 .agents/skills/insforge-dev/SKILL.md 是这个趋势的早期范本。

14.2 工程经验提炼

  1. 凭证形状互斥 > 凭证降级链——ik_ / anon_ / JWT 三种凭证不互相降级,避免”匿名 Key 伪装成 user”漏洞
  2. 启动序贯依赖 > DI 容器——DatabaseManager.initialize()StorageService.initialize()LogService.initialize() 的显式顺序,比 InversifyJS 简单 10 倍
  3. raw body 路径感知——webhooks 和 S3 gateway 必须挂在 JSON parser 之前,否则签名失效
  4. PostgREST 动态 schema + NOTIFY reload——Coding Agent 改表结构后,REST endpoint 立即可用,无需重启
  5. OpenRouter 单 Provider 抽象——把”多 LLM 路由”外包,专注做 BaaS 核心——这是做减法的智慧

14.3 总结

InsForge 是 Coding Agent 时代缺失的那块拼图——它用 MCP server + Skills + CLI 三通道把”7 大后端原语”打包成一个 Agent 友好的全栈平台。Apache-2.0 + 单进程 + docker-compose + PostgREST + OpenRouter + Deno 五个工程决策共同构成了它的差异化护城河。

如果你是 Coding Agent 的重度用户,InsForge 值得一试——它能让 Agent 在减少 80% 后端代码的同时,把生产环境所需的可观测 / 鉴权 / 部署 / 计费等基础设施全部托管。这不是又一个 BaaS,而是 BaaS 的”Agent 化重写”——是 2026 年 Backend 基础设施最值得追的方向之一。

附录 关键资源

资源链接
GitHub 仓库https://github.com/insforge/insforge
官方网站https://insforge.dev
官方文档https://docs.insforge.dev
NPM SDKhttps://www.npmjs.com/package/@insforge/sdk
Docker 镜像ghcr.io/insforge/insforge-oss:v1.5.0
MCP 配置Dashboard → Connect → MCP
Discordhttps://discord.com/invite/MPxwj5xVvW
LicenseApache-2.0
Vercel OSS Programhttps://vercel.com/oss
趋势榜https://trendshift.io/repositories/19834