Use Cases (更新: 2026/6/3)

Claude Code × Amazon Bedrock实战指南:在AWS上安全运行Claude

用Claude Code和Amazon Bedrock构建生产级Claude功能,覆盖IAM、Converse API、日志、Guardrails和成本控制。

Claude Code × Amazon Bedrock实战指南:在AWS上安全运行Claude

直接调用Anthropic API很适合快速原型,但把Claude放进AWS生产环境时,问题会变成API key怎么管、IAM权限怎么收敛、日志保存在哪里、费用算到哪个团队、失败后能不能安全重试。此时,通过Amazon Bedrock调用Claude会更适合企业和团队项目。

Amazon Bedrock是AWS的托管基础模型服务。通俗地说,它让你的应用通过AWS的身份认证、权限、日志、账单和运维体系来调用Claude,而不是把模型当成完全独立的外部API。Claude Code依然很有价值,但不要只让它写“能跑的demo”。要让它同时产出可审查的IAM、模型调用、Guardrails、日志、重试和成本限制。

Masa在实际项目里踩过的坑是:样例一小时就能跑通,但安全评审会问“哪个role可以调用哪个模型?节流时怎么处理?prompt会不会进日志?费用如何按团队追踪?”本文把这些问题落到代码和Claude Code提示词里。

本文基于2026年6月3日时点的AWS官方文档。Bedrock的模型ID、Region、quota和价格都会变化,发布前请以官方文档为准。

生产架构先行

不要一开始就对Claude Code说“加一个Bedrock聊天接口”。先固定调用方、运行环境、模型、Guardrails、日志和费用归属。

flowchart LR
  U["User / Admin UI"] --> A["API Gateway or ALB"]
  A --> R["Lambda or ECS task"]
  R --> G["Input validation and budget guard"]
  G --> B["Amazon Bedrock Runtime<br/>Converse / ConverseStream"]
  B --> C["Claude model"]
  R --> L["App logs<br/>CloudWatch Logs"]
  B --> M["Model invocation logs<br/>CloudWatch Logs or S3"]
  R --> K["Knowledge Bases<br/>optional RAG"]
  R --> Q["Cost Explorer / CUR<br/>IAM principal attribution"]

Converse API是Bedrock提供的统一对话接口。Guardrails是对用户输入和模型输出进行安全策略评估的护栏。model invocation logging可以把模型调用日志发送到CloudWatch Logs或S3。IAM principal attribution用于按IAM用户或role追踪Bedrock推理费用。

适合的用例

第一个用例是内部文档问答。把runbook、产品规格、支持流程放入S3和Knowledge Bases,通过检索相关片段后让Claude生成带引用的答案。这就是RAG,也就是先检索自己的数据,再让模型回答。

第二个用例是客服回复草稿。Claude可以根据客户问题、套餐信息和历史模板生成初稿,再交给人工确认。在完全自动回复之前,建议保留人工审核、Guardrails、个人信息处理和审计日志。

第三个用例是工程运维助手。它可以总结CloudWatch日志、生成部署检查清单、整理事故记录、把runbook变成任务列表。Claude Code的优势是能同时修改API、Lambda、IAM、测试和文档。

第四个用例是ClaudeCodeLab这类内容站运营。文章质量检查、description长度、内部链接建议、代码块审查都可以放在AWS权限和账单体系下运行。若内容直接影响收入,建议同时阅读Claude Code API成本优化验证收据工作流

初始设置

需要Node.js 20以上、AWS CLI凭证、启用Bedrock的AWS账号,以及目标Region可用的Anthropic模型。部分账号首次使用Anthropic模型时,需要提交用途信息、具备AWS Marketplace权限并配置有效支付方式。

不要从文章里复制一个模型ID就写死。先列出当前账号能用的模型,再放到环境变量。

export AWS_REGION=us-east-1

aws bedrock list-foundation-models \
  --region "$AWS_REGION" \
  --query "modelSummaries[?providerName=='Anthropic'].[modelId,modelName]" \
  --output table

export BEDROCK_MODEL_ID="anthropic.claude-sonnet-4-20250514-v1:0"
aws bedrock get-foundation-model \
  --region "$AWS_REGION" \
  --model-identifier "$BEDROCK_MODEL_ID" \
  --query "modelDetails.{input:inputModalities,output:outputModalities,streaming:responseStreamingSupported}"

创建一个最小TypeScript项目。

mkdir bedrock-claude-lab
cd bedrock-claude-lab
npm init -y
npm install @aws-sdk/client-bedrock @aws-sdk/client-bedrock-runtime @aws-sdk/client-bedrock-agent-runtime
npm install --save-dev typescript tsx @types/node
npx tsc --init --module NodeNext --moduleResolution NodeNext --target ES2022
mkdir -p src/lambda

package.json里加入脚本。

{
  "type": "module",
  "scripts": {
    "chat": "tsx src/chat.ts",
    "stream": "tsx src/stream.ts",
    "typecheck": "tsc --noEmit"
  }
}

IAM最小权限

使用Converse API时,IAM层仍然需要模型调用权限。非流式调用需要bedrock:InvokeModel,流式调用需要bedrock:InvokeModelWithResponseStream。应用日志权限和Bedrock模型调用日志设置要分开设计。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListBedrockModelsForStartupCheck",
      "Effect": "Allow",
      "Action": ["bedrock:ListFoundationModels", "bedrock:GetFoundationModel"],
      "Resource": "*"
    },
    {
      "Sid": "InvokeOnlyApprovedClaudeModels",
      "Effect": "Allow",
      "Action": ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
      "Resource": [
        "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-*",
        "arn:aws:bedrock:us-west-2::foundation-model/anthropic.claude-*",
        "arn:aws:bedrock:us-east-1:123456789012:inference-profile/*"
      ]
    },
    {
      "Sid": "ApplyApprovedGuardrail",
      "Effect": "Allow",
      "Action": ["bedrock:ApplyGuardrail"],
      "Resource": "arn:aws:bedrock:us-east-1:123456789012:guardrail/your-guardrail-id"
    }
  ]
}

请替换账号ID、Region、Guardrail ID和模型范围。使用跨Region推理时,还要把推理profile和目标Region模型ARN纳入权限设计。更细的最小权限审查可以参考Claude Code AWS IAM指南

调用Claude

生产实现里最容易遗漏的是requestMetadata。AWS文档说明它可用于筛选模型调用日志,所以建议放入请求ID、功能名和调用者类别。

// src/bedrock-client.ts
import { randomUUID } from "node:crypto";
import {
  BedrockRuntimeClient,
  ConverseCommand,
  ConverseStreamCommand,
  type ConverseCommandInput,
} from "@aws-sdk/client-bedrock-runtime";

export const AWS_REGION = process.env.AWS_REGION ?? "us-east-1";
export const BEDROCK_MODEL_ID =
  process.env.BEDROCK_MODEL_ID ?? "anthropic.claude-sonnet-4-20250514-v1:0";

export const bedrock = new BedrockRuntimeClient({
  region: AWS_REGION,
  maxAttempts: Number(process.env.BEDROCK_MAX_ATTEMPTS ?? "3"),
});

type AskClaudeInput = {
  prompt: string;
  system?: string;
  maxTokens?: number;
  temperature?: number;
  userId?: string;
  feature?: string;
};

function optionalGuardrail(): ConverseCommandInput["guardrailConfig"] | undefined {
  const guardrailIdentifier = process.env.BEDROCK_GUARDRAIL_ID;
  if (!guardrailIdentifier) return undefined;

  return {
    guardrailIdentifier,
    guardrailVersion: process.env.BEDROCK_GUARDRAIL_VERSION ?? "DRAFT",
    trace: "enabled",
  };
}

export async function askClaude(input: AskClaudeInput) {
  const requestId = randomUUID();
  const startedAt = Date.now();

  const response = await bedrock.send(
    new ConverseCommand({
      modelId: BEDROCK_MODEL_ID,
      system: input.system ? [{ text: input.system }] : undefined,
      messages: [{ role: "user", content: [{ text: input.prompt }] }],
      inferenceConfig: {
        maxTokens: input.maxTokens ?? 800,
        temperature: input.temperature ?? 0.2,
      },
      guardrailConfig: optionalGuardrail(),
      requestMetadata: {
        requestId,
        feature: input.feature ?? "local-cli",
        userId: input.userId ?? "anonymous",
      },
    })
  );

  const text =
    response.output?.message?.content
      ?.map((block: { text?: string }) => block.text ?? "")
      .join("") ?? "";

  console.log(
    JSON.stringify({
      level: "info",
      event: "bedrock_converse",
      requestId,
      modelId: BEDROCK_MODEL_ID,
      latencyMs: Date.now() - startedAt,
      stopReason: response.stopReason,
      usage: response.usage,
      metrics: response.metrics,
    })
  );

  return { text, usage: response.usage, stopReason: response.stopReason, requestId };
}

export async function streamClaude(prompt: string) {
  const response = await bedrock.send(
    new ConverseStreamCommand({
      modelId: BEDROCK_MODEL_ID,
      messages: [{ role: "user", content: [{ text: prompt }] }],
      inferenceConfig: { maxTokens: 1200, temperature: 0.2 },
      guardrailConfig: optionalGuardrail(),
      requestMetadata: { feature: "stream-cli", requestId: randomUUID() },
    })
  );

  if (!response.stream) throw new Error("Bedrock did not return a stream.");

  for await (const event of response.stream) {
    const text = event.contentBlockDelta?.delta?.text;
    if (text) process.stdout.write(text);

    if (event.metadata?.usage) {
      process.stderr.write(`\nusage=${JSON.stringify(event.metadata.usage)}\n`);
    }
  }
}
// src/chat.ts
import { askClaude } from "./bedrock-client.js";

const prompt = process.argv.slice(2).join(" ").trim();
if (!prompt) {
  console.error('Usage: npm run chat -- "Summarize Amazon Bedrock in three bullets"');
  process.exit(1);
}

const result = await askClaude({
  prompt,
  system: "You are a concise AWS assistant. If you are unsure, say what to verify.",
  maxTokens: 600,
  feature: "developer-chat",
});

console.log(result.text);
// src/stream.ts
import { streamClaude } from "./bedrock-client.js";

const prompt = process.argv.slice(2).join(" ").trim();
if (!prompt) {
  console.error('Usage: npm run stream -- "Write a deployment checklist"');
  process.exit(1);
}

await streamClaude(prompt);

运行:

export AWS_REGION=us-east-1
export BEDROCK_MODEL_ID="anthropic.claude-sonnet-4-20250514-v1:0"

npm run chat -- "用三行解释Amazon Bedrock"
npm run stream -- "生成Bedrock生产上线检查清单"
npm run typecheck

Lambda实现模式

放到Lambda时,要在handler外初始化客户端,在服务器端验证输入并限制maxTokens。不能只依赖前端限制。

// src/lambda/assistant-handler.ts
import { askClaude } from "../bedrock-client.js";

type ApiEvent = {
  body?: string | null;
  requestContext?: { requestId?: string };
};

const headers = { "content-type": "application/json; charset=utf-8" };

export const handler = async (event: ApiEvent) => {
  try {
    const body = JSON.parse(event.body ?? "{}") as {
      prompt?: string;
      maxTokens?: number;
      userId?: string;
    };

    if (!body.prompt || body.prompt.length > 8000) {
      return {
        statusCode: 400,
        headers,
        body: JSON.stringify({ error: "prompt is required and must be <= 8000 chars" }),
      };
    }

    const result = await askClaude({
      prompt: body.prompt,
      maxTokens: Math.min(body.maxTokens ?? 800, 1200),
      userId: body.userId ?? "anonymous",
      feature: "support-assistant",
    });

    return {
      statusCode: 200,
      headers,
      body: JSON.stringify({
        text: result.text,
        usage: result.usage,
        stopReason: result.stopReason,
        requestId: result.requestId,
      }),
    };
  } catch (error) {
    const name =
      typeof error === "object" && error && "name" in error ? String(error.name) : "UnknownError";
    const retryable = ["ThrottlingException", "ServiceUnavailableException", "InternalServerException"].includes(name);

    console.error(JSON.stringify({ level: "error", event: "assistant_failed", name, retryable }));

    return {
      statusCode: retryable ? 503 : 500,
      headers,
      body: JSON.stringify({ error: retryable ? "Please retry later" : "Generation failed" }),
    };
  }
};

ValidationException通常是输入或参数错误,重试没有意义。ThrottlingExceptionServiceUnavailableException才适合指数退避和随机抖动。Serverless整体设计可继续读Claude Code AWS Lambda指南

用Knowledge Bases做RAG

内部文档聊天优先从Bedrock Knowledge Bases开始,而不是一上来自己搭向量数据库。它可以返回带引用的答案,便于运营人员检查依据。但要注意,Guardrails应用于输入和生成输出,不会清洗检索到的引用本身。因此敏感文档要先通过S3、KMS、IAM和数据分级限制。

// src/rag.ts
import {
  BedrockAgentRuntimeClient,
  RetrieveAndGenerateCommand,
} from "@aws-sdk/client-bedrock-agent-runtime";

const agentRuntime = new BedrockAgentRuntimeClient({
  region: process.env.AWS_REGION ?? "us-east-1",
});

export async function askKnowledgeBase(question: string) {
  const knowledgeBaseId = process.env.BEDROCK_KNOWLEDGE_BASE_ID;
  const modelArn = process.env.BEDROCK_GENERATION_MODEL_ARN;

  if (!knowledgeBaseId || !modelArn) {
    throw new Error("Set BEDROCK_KNOWLEDGE_BASE_ID and BEDROCK_GENERATION_MODEL_ARN");
  }

  const response = await agentRuntime.send(
    new RetrieveAndGenerateCommand({
      input: { text: question },
      retrieveAndGenerateConfiguration: {
        type: "KNOWLEDGE_BASE",
        knowledgeBaseConfiguration: {
          knowledgeBaseId,
          modelArn,
          retrievalConfiguration: {
            vectorSearchConfiguration: { numberOfResults: 5 },
          },
        },
      },
    })
  );

  const sources =
    response.citations
      ?.flatMap((citation) => citation.retrievedReferences ?? [])
      .map((reference) => reference.location?.s3Location?.uri)
      .filter(Boolean) ?? [];

  return { answer: response.output?.text ?? "", sources };
}

日志、成本和Prompt caching

日志分两层。应用日志记录requestId、功能名、调用者类别、模型ID、usage、延迟和停止原因。除非隐私和保存策略明确允许,不要长期保存原始prompt。

Bedrock模型调用日志可以发到CloudWatch Logs或S3,适合审计和问题排查,但也可能包含敏感输入输出。启用前要决定保留周期、加密、S3生命周期和访问权限。

成本控制从API层限制maxTokens开始,再按任务复杂度选择模型,把usage写进日志,并通过IAM principal attribution在Cost Explorer或CUR里按role追踪成本。长而重复的系统prompt可以考虑Prompt caching,但只有稳定前缀足够长且频繁复用时才有明显效果。

给Claude Code的提示词

claude -p "
请在这个repository中通过Amazon Bedrock添加Claude调用。

要求:
- 使用AWS SDK v3 Converse API
- 模型ID从BEDROCK_MODEL_ID读取
- AWS_REGION未设置时默认us-east-1
- 服务器端把maxTokens限制到1200以内
- requestMetadata包含requestId, feature, userId
- 只有设置BEDROCK_GUARDRAIL_ID时才添加guardrailConfig
- 以JSON日志输出usage, latencyMs, stopReason
- 不要重试ValidationException
- 将ThrottlingException和ServiceUnavailableException视为可重试
- 在README写最小权限IAM策略
- 测试中mock Bedrock客户端,不调用真实API

修改前先给计划,完成后报告typecheck和测试结果。
"

常见坑

第一,没确认模型访问就开始写代码。先用list-foundation-models和一次小的Converse调用确认账号、Region和权限。

第二,把博客里的模型ID固定进代码。Bedrock模型ID和Region支持会变,应该用环境变量并在启动时验证。

第三,把Guardrails当成正确性保证。它适合安全策略,不替代人工审核、领域校验和授权。

第四,日志保存过多。完整prompt便于排查,但也可能把个人信息和内部数据放进长期日志。

第五,错误重试策略混乱。Validation类错误需要修输入或代码,节流和临时服务错误才适合重试。

第六,只在前端限制费用。token上限、功能配额和用户配额必须在API层执行。

商业化路径

Bedrock文章的价值不在SDK片段,而在从demo走向生产:IAM、日志、成本、Guardrails、review和团队导入。个人可从ClaudeCodeLab产品获取模板;团队要把CLAUDE.md、IAM审查、验证收据和CI gate落到真实repository,可使用Claude Code培训与咨询

延伸阅读:Claude Code AWS LambdaClaude Code AWS IAMClaude Code API成本优化验证收据工作流

实测后的结论

实际尝试后,最大收益不是多写几层封装,而是在给Claude Code的提示词里明确“模型ID来自环境变量”“必须记录usage”“ValidationException不重试”“Guardrails按环境变量启用”“README保留IAM策略”。这样生成的diff更小,review点更清楚。Bedrock导入成败,往往取决于写代码前能否先说清生产约束。

#claude-code #aws #bedrock #anthropic #typescript #generative-ai
免费

免费 PDF: Claude Code 速查表

输入邮箱即可获取一页 PDF,整理常用命令、审查习惯和安全工作流。

我们会妥善保护你的信息,不发送垃圾邮件。

把 Claude Code 变成真正能带来结果的工作流

先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。

Masa

关于作者

Masa

专注 Claude Code 实务流程、团队导入和内容转化的工程师。