一、环境检查
必备账号
[ ] Anthropic API key(console.anthropic.com)
[ ] Railway 账号(railway.app)
[ ] GitHub 账号(push 代码触发部署)
[ ] Mercury / Stripe / Wise(接收 SaaS 用户付款)
国内开发环境
Anthropic API 在国内 IP 直接调用受限。开发期需要稳定线路调试。
如果你需要稳定调试 Claude API + 同时管 Stripe / Wise / Mercury 等海外账户,配一条主推 GPT-5.5 / Claude 4.7 的低价 API 中转能保证开发联调不中断,同时省 40-60% API 成本。
二、初始化项目
mkdir my-claude-agent
cd my-claude-agent
npm init -y
npm install @anthropic-ai/sdk express dotenv
npm install -D typescript @types/node @types/express tsx
# tsconfig.json
cat > tsconfig.json << 'EOF'
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"esModuleInterop": true,
"strict": true,
"outDir": "dist"
},
"include": ["src/**/*"]
}
EOF
三、实现 Agent loop
// src/agent.ts
import Anthropic from '@anthropic-ai/sdk'
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY })
const tools = [
{
name: 'get_weather',
description: '获取指定城市的实时天气',
input_schema: {
type: 'object',
properties: {
city: { type: 'string', description: '城市名' }
},
required: ['city']
}
},
{
name: 'search_web',
description: '搜索互联网获取最新信息',
input_schema: {
type: 'object',
properties: {
query: { type: 'string' }
},
required: ['query']
}
}
]
async function runAgent(userMessage: string) {
const messages: any[] = [
{ role: 'user', content: userMessage }
]
let iterations = 0
const MAX_ITERATIONS = 20
while (iterations++ < MAX_ITERATIONS) {
const response = await client.messages.create({
model: 'claude-opus-4-7',
max_tokens: 4096,
tools,
messages
})
messages.push({ role: 'assistant', content: response.content })
if (response.stop_reason === 'end_turn') {
return response.content
}
if (response.stop_reason === 'tool_use') {
const toolResults = []
for (const block of response.content) {
if (block.type === 'tool_use') {
const result = await executeTool(block.name, block.input)
toolResults.push({
type: 'tool_result',
tool_use_id: block.id,
content: JSON.stringify(result)
})
}
}
messages.push({ role: 'user', content: toolResults })
}
}
throw new Error('Max iterations reached')
}
async function executeTool(name: string, input: any) {
if (name === 'get_weather') {
return { temp: 22, city: input.city, condition: 'sunny' }
}
if (name === 'search_web') {
return { results: [`Mock result for: ${input.query}`] }
}
}
四、暴露为 HTTP API
// src/server.ts
import express from 'express'
import { runAgent } from './agent.js'
const app = express()
app.use(express.json())
app.post('/api/agent', async (req, res) => {
const { message } = req.body
try {
const result = await runAgent(message)
res.json({ result })
} catch (err) {
res.status(500).json({ error: String(err) })
}
})
app.get('/health', (_, res) => res.json({ ok: true }))
const PORT = process.env.PORT || 3000
app.listen(PORT, () => console.log(`Listening on ${PORT}`))
五、Dockerfile(multi-stage 优化)
# Dockerfile
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package.json ./
EXPOSE 3000
CMD ["node", "dist/server.js"]
// package.json scripts
{
"scripts": {
"build": "tsc",
"start": "node dist/server.js",
"dev": "tsx watch src/server.ts"
}
}
六、Railway 部署步骤
# 1. 推到 GitHub
git init
git add .
git commit -m "init claude agent"
git remote add origin [email protected]:you/my-claude-agent.git
git push -u origin main
# 2. 在 Railway 创建 project
# Dashboard → New → Deploy from GitHub repo
# 选择仓库 → Deploy
# 3. 配 env vars
ANTHROPIC_API_KEY=sk-ant-...
NODE_ENV=production
# 4. 选择 Domain
# Settings → Domain → Generate Domain
七、成本监控
// src/cost-tracker.ts
import fs from 'fs'
const PRICES = {
'claude-opus-4-7': { input: 15 / 1e6, output: 75 / 1e6 },
'claude-sonnet-4-6': { input: 3 / 1e6, output: 15 / 1e6 },
'claude-haiku-4-5': { input: 0.8 / 1e6, output: 4 / 1e6 }
}
export function trackUsage(model: string, usage: any) {
const price = PRICES[model as keyof typeof PRICES]
const cost = price.input * usage.input_tokens + price.output * usage.output_tokens
const log = {
timestamp: new Date().toISOString(),
model,
input_tokens: usage.input_tokens,
output_tokens: usage.output_tokens,
cost_usd: cost.toFixed(6)
}
fs.appendFileSync('/tmp/usage.log', JSON.stringify(log) + '\n')
return cost
}
八、单次任务成本对比
| 任务 | 模型 | input tokens | output tokens | 成本(直连) | 成本(中转 -50%) |
|---|---|---|---|---|---|
| 简单问答 | Haiku 4.5 | 200 | 100 | $0.0006 | $0.0003 |
| Web search agent | Sonnet 4.6 | 5,000 | 2,000 | $0.045 | $0.022 |
| Multi-step task | Opus 4.7 | 15,000 | 5,000 | $0.60 | $0.30 |
| 长上下文代码分析 | Opus 4.7 | 100,000 | 10,000 | $2.25 | $1.13 |
九、生产级建议
| 维度 | 建议 |
|---|---|
| Model | 默认 Sonnet 4.6,复杂任务才升 Opus 4.7 |
| Rate limit | Anthropic 默认 50 RPM,需要时 contact 升级 |
| Retry | 自动重试 5xx 错误 + exponential backoff |
| Logging | 记录每次 messages.create 的 token / cost |
| Monitoring | 用 Sentry 抓 tool_use 异常 |
| Cost cap | 单用户单日 cap $5 / 单月 cap $50 |
| Streaming | 用 messages.stream 给前端实时显示 |
关联文章
Claude Agent SDK Railway 部署的落地条件
Claude Agent SDK Railway 部署最怕把法律主体、收款工具和产品代码混成一个问题。动手前看清收款账户、税务资料和部署环境,金额较大或涉及税务时应交给专业顾问处理。
一个人运营时可以用表格压住复杂度:负责人、后台入口、到期日、费用来源和回滚动作各占一列,避免换服务商时才发现资料缺口。
涉及 Stripe、公司注册、税表或签证的内容,只能作为操作参考。当前页面没有覆盖你所在司法辖区的特殊规定时,不应把它当成法律或税务意见。
| 项目 | 看什么 | 不宜继续的信号 |
|---|---|---|
| 收款账户 | 当前后台、日志或设置页里能直接看到的字段 | 页面提示和手头资料对不上 |
| 税务资料 | 费用、权限、地区或设备造成的实际影响 | 已经影响付款、审核、生产环境或家庭使用 |
| 部署环境 | 回退入口、旧配置、官方支持材料 | 找不到回滚方式,或责任人无法确认 |