

# Node.js 的直接程式碼部署
<a name="runtime-get-started-code-deploy-node"></a>

直接程式碼部署可讓您將 Node.js 型代理程式帶到 Amazon Bedrock AgentCore 執行期，只需在 .zip 封存檔中封裝代理程式程式碼及其相依性即可。您的代理程式仍然需要遵循 [AgentCore 執行期要求](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-service-contract.html)：具有實作 `/invocations` POST 和 `/ping` GET 伺服器端點的進入點`.js`檔案。

您可以在 ZIP `node_modules/`中包含做為廠商的相依性，或做為 esbuild 綁定的單一`.js`檔案。

## 先決條件
<a name="prerequisites-node"></a>

開始前，請確保您具備以下條件：
+  ** AWS 已設定登入資料的帳戶**。若要設定您的 AWS 登入資料，請參閱 [CLI AWS 中的組態和登入資料檔案設定。](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html)
+  已安裝 [**Node.js**](https://nodejs.org/) 和 **npm**。我們建議您安裝計劃在 AgentCore 執行期部署的相同主要版本 （例如執行`NODE_22`期的 Node.js 22)。如需支援的版本，請參閱[支援的語言執行時間](runtime-code-deploy-supported-runtimes.md)。
+  ** AWS 許可** ：若要建立和部署代理程式，您必須擁有適當的許可。如需詳細資訊，請參閱 [AgentCore 執行期許可](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-permissions.html)。
+  **模型存取** ：Amazon Bedrock 主控台中[啟用](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access-modify.html) Anthropic Claude Sonnet 4.0。如需搭配 Strands Agents 使用不同模型的詳細資訊，請參閱 [Strands Agents SDK](https://strandsagents.com/latest/documentation/docs/) 文件中的*模型提供者*一節。

## 步驟 1：設定專案並安裝相依性
<a name="step-1-setup-node"></a>

使用以下命令初始化您的專案：

```
mkdir agentcore_runtime_node_deploy
cd agentcore_runtime_node_deploy
npm init -y
```

或者，執行 `npm install @aws/aws-distro-opentelemetry-node-autoinstrumentation`以啟用 [Amazon Bedrock AgentCore 可觀測性追蹤](https://docs.aws.amazon.com/xray/latest/devguide/xray-services-adot.html)。

## 步驟 2：建立您的代理程式程式碼
<a name="step-2-create-agent-node"></a>

建立您的客服人員進入點。您的代理程式必須使用 `/ping` GET 運作狀態端點和 `/invocations` POST 處理常式實作 AgentCore 執行期 HTTP 合約。

**Example**  
安裝 [Strands Agents SDK](https://strandsagents.com/latest/) 及其相依性：  

```
npm install @strands-agents/sdk express zod
npm install -D @types/express @types/node typescript
```
建立名為 `src/app.ts` 的檔案：  

```
import express, { Request, Response } from "express";
import { Agent, tool } from "@strands-agents/sdk";
import z from "zod";

const PORT = 8080;
const app = express();

app.use(express.json());

const currentTime = tool({
    name: "current_time",
    description: "Returns the current date and time",
    inputSchema: z.object({}),
    callback: () => {
        return new Date().toISOString();
    },
});

const agent = new Agent({
    tools: [currentTime],
    printer: false,
});

app.get("/ping", (_req: Request, res: Response) => {
    res.json({ status: "Healthy" });
});

app.post("/invocations", async (req: Request, res: Response) => {
    const prompt = req.body?.prompt || "No prompt provided";

    try {
        const result = await agent.invoke(prompt);
        res.json({ result: result.lastMessage });
    } catch (error: unknown) {
        const message = error instanceof Error ? error.message : String(error);
        res.status(500).json({ error: message });
    }
});

app.listen(PORT, "0.0.0.0", () => {
    console.log("Strands agent listening on port " + PORT);
});
```
將 TypeScript 編譯至 JavaScript：  

```
npx tsc --init --target ES2022 --module commonjs --outDir ./dist
npx tsc
```
中的編譯輸出`dist/app.js`是您部署的輸出。建立代理程式時，請使用 `"entryPoint": ["dist/app.js"]` - 編譯的 JavaScript 輸出，而不是`.ts`來源。
此範例使用沒有外部相依性的內建`node:http`模組。  
建立名為 `app.js` 的檔案：  

```
const http = require("node:http");
const PORT = 8080;

const server = http.createServer((req, res) => {
    if (req.url === "/ping" && req.method === "GET") {
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify({ status: "Healthy" }));
    } else if (req.url === "/invocations" && req.method === "POST") {
        let body = "";
        req.on("data", (chunk) => { body += chunk; });
        req.on("end", () => {
            try {
                const input = JSON.parse(body);
                const prompt = input.prompt || input.command || "No prompt provided";
                res.writeHead(200, { "Content-Type": "application/json" });
                res.end(JSON.stringify({
                    result: "Hello from Node.js managed runtime! You said: " + prompt,
                    runtime: "NODE_22",
                    nodeVersion: process.version,
                    timestamp: new Date().toISOString()
                }));
            } catch (e) {
                res.writeHead(200, { "Content-Type": "application/json" });
                res.end(JSON.stringify({
                    result: "Hello from Node.js managed runtime!",
                    runtime: "NODE_22",
                    nodeVersion: process.version,
                    input: body,
                    timestamp: new Date().toISOString()
                }));
            }
        });
    } else {
        res.writeHead(200, { "Content-Type": "application/json" });
        res.end(JSON.stringify({ message: "Node.js managed runtime agent is running" }));
    }
});

server.listen(PORT, "0.0.0.0", () => {
    console.log("Node.js agent listening on port " + PORT);
});
```

## 步驟 3：在本機測試
<a name="step-3-test-locally-node"></a>

開始之前，請確定連接埠 8080 是免費的。請參閱[常見問題和解決方案](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-get-started-cli.html#common-issues)中的*連接埠 8080 使用中 （僅限本機）*。

開啟終端機視窗並啟動您的代理程式：

**Example**  

```
node dist/app.js
```
開啟另一個終端機視窗並叫用代理程式：  

```
curl -X POST http://localhost:8080/invocations \
  -H "Content-Type: application/json" \
  -d '{"prompt": "What time is it right now?"}'
```
 **成功：**您應該會看到回應，其中包含客服人員`current_time`工具傳回的目前時間。在執行代理程式的終端機視窗中，輸入 `Ctrl+C`以停止代理程式。

```
node app.js
```
開啟另一個終端機視窗並叫用代理程式：  

```
curl -X POST http://localhost:8080/invocations \
  -H "Content-Type: application/json" \
  -d '{"prompt": "Hello!"}'
```
 **成功：**您應該會看到類似 `{"result": "Hello from Node.js managed runtime! You said: Hello!","runtime":"NODE_22",…​}` 的回應。在執行代理程式的終端機視窗中，輸入 `Ctrl+C`以停止代理程式。

## 步驟 4：啟用代理程式的可觀測性
<a name="step-4-enable-observability-node"></a>

 [Amazon Bedrock AgentCore 可觀測性](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability.html)可協助您追蹤、偵錯和監控您在 AgentCore 執行期中託管的代理程式。首先，遵循啟用 [Amazon Bedrock AgentCore 執行時間可觀測性 中的指示來啟用](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability-configure.html#observability-configure-builtin) CloudWatch 交易搜尋。若要觀察您的代理程式，請參閱[檢視 Amazon Bedrock AgentCore 代理程式的可觀測性資料](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/observability-view.html)。

若要為您的 Node.js 代理程式啟用自動檢測，請新增 ADOT 套件：

```
npm install @aws/aws-distro-opentelemetry-node-autoinstrumentation
```

**重要**  
ADOT 自動檢測的運作方式是在執行時間修補 Node.js `require()`呼叫。這表示它僅與 CommonJS 模組輸出相容。如果您使用 `--module nodenext`或 `--module esnext`（產生 ESM `import`陳述式） 編譯 TypeScript，ADOT 檢測會無提示地失敗，而且不會發出任何追蹤。若要使用 ADOT，請搭配 編譯`--module commonjs`或使用 esbuild 搭配 `--platform=node`（保留對 Node.js 內建模組的`require()`呼叫）。

部署時，請在 ZIP `node_modules/`中包含 ，並在進入點中使用 `opentelemetry-instrument` 字首 （請參閱步驟 5)。

## 步驟 5：部署至 AgentCore 執行期並叫用
<a name="step-5-deploy-node"></a>

**注意**  
AgentCore 執行期不會原生執行 TypeScript (`.ts`) 檔案。部署之前，您必須將 TypeScript 傳輸到 JavaScript。詳細資訊，請參閱[使用 TypeScript](#concept-node-typescript)。

使用代理程式程式碼和相依性建立 .zip 檔案。AgentCore 執行期僅支援 **arm64** 指令集架構 — 確保針對 arm64 編譯任何原生模組 (`.node` 檔案）。

**Example**  
封裝編譯的輸出和廠商的相依性：  

```
npm install --production
zip -r deployment_package.zip dist/ node_modules/ package.json
```
建立代理程式時，請使用 `"entryPoint": ["dist/app.js"]` - 編譯的 JavaScript 輸出，而不是`.ts`來源。
由於此範例沒有外部相依性，因此只需要進入點檔案：  

```
zip deployment_package.zip app.js
```
建立代理程式時，請使用 `"entryPoint": ["app.js"]` 。

**注意**  
。 AgentCore 執行期的 .zip 部署套件大小上限為 250 MB （壓縮） 和 750 MB （解壓縮）。請注意，此限制適用於您上傳之所有檔案的合併大小。AgentCore 執行期需要讀取部署套件中檔案的許可。在 Linux 許可八進位表示法中，AgentCore 執行期需要 644 個不可執行檔案的許可 (rw-r—r--)，以及 755 個目錄和可執行檔案的許可 (rwxr-xr-x)。在 Linux 和 MacOS 中，使用 `chmod` 命令變更部署套件中檔案和目錄的檔案許可。例如，若要為非可執行檔提供正確的許可，請執行下列命令 `chmod 644 <filepath>` 。若要在 Windows 中變更檔案許可，請參閱 Microsoft Windows 文件的 [Set, View, Change, or Remove Permissions on an Object](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc731667(v=ws.10))。\+ .. 如果您未授予 AgentCore Runtime 存取部署套件中目錄所需的許可，AgentCore Runtime 會將這些目錄的許可設定為 755 (rwxr-xr-x)。

包含 Linux **arm64** 相依性的 ZIP 封存需要上傳到 S3 作為建立代理程式執行期的先決條件。下列程式碼要求指定的 S3 儲存貯體已存在。請依照[此處](https://docs.aws.amazon.com/AmazonS3/latest/userguide/creating-bucket-s3.html) AWS 的文件來建立儲存貯體。下列 TypeScript 程式碼會將 .zip 檔案封存上傳至 S3，並建立 Amazon Bedrock AgentCore 執行期。

```
import { readFileSync } from "node:fs";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import {
    BedrockAgentCoreControlClient,
    CreateAgentRuntimeCommand,
} from "@aws-sdk/client-bedrock-agentcore-control";

const accountId = "your-aws-account-id";
const agentName = "nodejs_agent";
const region = "us-west-2";
const bucketName = `bedrock-agentcore-code-${accountId}-${region}`;

const s3Client = new S3Client({ region });
console.log("Uploading deployment_package.zip to S3...");
await s3Client.send(new PutObjectCommand({
    Bucket: bucketName,
    Key: `${agentName}/deployment_package.zip`,
    Body: readFileSync("deployment_package.zip"),
    ExpectedBucketOwner: accountId,
}));
console.log(`Upload completed. S3 location: s3://${bucketName}/${agentName}/deployment_package.zip`);

const controlClient = new BedrockAgentCoreControlClient({ region });
const response = await controlClient.send(new CreateAgentRuntimeCommand({
    agentRuntimeName: agentName,
    agentRuntimeArtifact: {
        codeConfiguration: {
            code: {
                s3: {
                    bucket: bucketName,
                    prefix: `${agentName}/deployment_package.zip`,
                },
            },
            runtime: "NODE_22",
            entryPoint: ["dist/app.js"],
        },
    },
    networkConfiguration: { networkMode: "PUBLIC" },
    roleArn: `arn:aws:iam::${accountId}:role/AmazonBedrockAgentCoreSDKRuntime-${region}`,
    lifecycleConfiguration: {
        idleRuntimeSessionTimeout: 300,
        maxLifetime: 1800,
    },
}));
console.log(`Agent Runtime created successfully!`);
console.log(`Agent Runtime ARN: ${response.agentRuntimeArn}`);
console.log(`Status: ${response.status}`);
```

若要啟用 OTEL 自動檢測，請在 ZIP `node_modules/@aws/aws-distro-opentelemetry-node-autoinstrumentation/` 中包含 ，並在進入點中使用 `opentelemetry-instrument`字首：

```
entryPoint: ["opentelemetry-instrument", "dist/app.js"],
```

若要以程式設計方式叫用 Amazon Bedrock AgentCore 執行期上的代理程式，請參閱：[以程式設計方式叫用代理程式](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-get-started-cli.html#invoke-programmatically) 

## 步驟 6：停止工作階段、更新或清除
<a name="step-6-update-cleanup-node"></a>

下列 TypeScript 程式碼會更新 AgentCore 執行期。將新的部署套件上傳至 S3，然後呼叫 `UpdateAgentRuntimeCommand` ：

```
import { readFileSync } from "node:fs";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import {
    BedrockAgentCoreControlClient,
    UpdateAgentRuntimeCommand,
} from "@aws-sdk/client-bedrock-agentcore-control";

const accountId = "your-aws-account-id";
const agentName = "nodejs_agent";
const region = "us-west-2";
const bucketName = `bedrock-agentcore-code-${accountId}-${region}`;

const s3Client = new S3Client({ region });
console.log("Uploading deployment_package.zip to S3...");
await s3Client.send(new PutObjectCommand({
    Bucket: bucketName,
    Key: `${agentName}/deployment_package.zip`,
    Body: readFileSync("deployment_package.zip"),
    ExpectedBucketOwner: accountId,
}));
console.log("Upload completed successfully!");

const controlClient = new BedrockAgentCoreControlClient({ region });
const response = await controlClient.send(new UpdateAgentRuntimeCommand({
    agentRuntimeId: "<your-agent-runtime-id>",
    agentRuntimeArtifact: {
        codeConfiguration: {
            code: {
                s3: {
                    bucket: bucketName,
                    prefix: `${agentName}/deployment_package.zip`,
                },
            },
            runtime: "NODE_22",
            entryPoint: ["dist/app.js"],
        },
    },
    networkConfiguration: { networkMode: "PUBLIC" },
    roleArn: `arn:aws:iam::${accountId}:role/AmazonBedrockAgentCoreSDKRuntime-${region}`,
}));
console.log(`Agent Runtime updated successfully!`);
console.log(`Agent Runtime ARN: ${response.agentRuntimeArn}`);
console.log(`Status: ${response.status}`);
```

若要在可設定 `IdleRuntimeSessionTimeout`（預設為 15 分鐘） 之前停止執行中的工作階段，並節省任何潛在的失控成本，請使用下列程式碼：

```
import {
    BedrockAgentCoreClient,
    StopRuntimeSessionCommand,
} from "@aws-sdk/client-bedrock-agentcore";

const region = "us-west-2";
const dataClient = new BedrockAgentCoreClient({ region });
const response = await dataClient.send(new StopRuntimeSessionCommand({
    agentRuntimeArn: "arn:aws:bedrock-agentcore:us-west-2:<account-id>:runtime/<agent-runtime-id>",
    runtimeSessionId: "<your-session-id>",
    qualifier: "DEFAULT",
}));
console.log("Session stopped successfully!");
```

下列 TypeScript 程式碼會刪除 S3 中的 Amazon Bedrock AgentCore 執行期和 .zip 封存檔案。

```
import { S3Client, DeleteObjectCommand } from "@aws-sdk/client-s3";
import {
    BedrockAgentCoreControlClient,
    DeleteAgentRuntimeCommand,
} from "@aws-sdk/client-bedrock-agentcore-control";

const accountId = "your-aws-account-id";
const agentName = "nodejs_agent";
const region = "us-west-2";
const bucketName = `bedrock-agentcore-code-${accountId}-${region}`;

const controlClient = new BedrockAgentCoreControlClient({ region });
console.log("Deleting Agent from Amazon Bedrock AgentCore Runtime!");
const response = await controlClient.send(new DeleteAgentRuntimeCommand({
    agentRuntimeId: "<your-agent-runtime-id>",
}));
console.log(`Agent Runtime deleted successfully!`);
console.log(`Status: ${response.status}`);

const s3Client = new S3Client({ region });
console.log("Deleting deployment archive from S3...");
await s3Client.send(new DeleteObjectCommand({
    Bucket: bucketName,
    Key: `${agentName}/deployment_package.zip`,
    ExpectedBucketOwner: accountId,
}));
console.log("Archive deleted successfully from S3!");
```

## 用於直接程式碼部署的 Node.js 特定概念
<a name="runtime-code-deploy-node-concepts"></a>

了解搭配 Amazon Bedrock AgentCore 執行期使用直接程式碼部署時的 Node.js 特定概念。

**Topics**

### 進入點要求
<a name="concept-node-entry-point"></a>

Node.js 的 AgentCore 執行期只接受`.js`進入點。TypeScript 檔案 (`.ts`) 不直接接受 - 您必須在封裝之前將檔案轉換為 JavaScript。我們建議在單一步驟中使用 [esbuild](https://esbuild.github.io/) 來傳輸和綁定。使用 新增 esbuild 做為開發相依性`npm install -D esbuild`。

進入點可以位於子目錄中。例如， `src/app.js`或 `dist/index.js`是有效的進入點。Node.js 模組解析度會從進入點的位置上移目錄樹狀目錄，因此會自動在 ZIP `node_modules/`根目錄找到 中的相依性，無需`NODE_PATH`設定。

當您指定子目錄進入點時，請確定`entryPoint`組態中的路徑與 ZIP 檔案中的路徑相符。

### 相依性封裝選項
<a name="concept-node-dependency-packaging"></a>

封裝 Node.js 代理程式相依性的方法有兩種：

 **廠商相依性 （簡單）：**

將 `node_modules/` 與您的進入點一起直接包含在 ZIP 中：

```
npm install --production
zip -r my-agent.zip app.js node_modules/ package.json
```

這會產生具有下列結構的 ZIP：

```
my-agent.zip
├── app.js
├── package.json
└── node_modules/
```

 **與 esbuild （最小 ZIP) 綁定：**

使用 [esbuild](https://esbuild.github.io/) 將所有相依性綁定到單一檔案中：

```
npx esbuild app.js --bundle --platform=node --target=node22 --outfile=bundle.js
zip my-agent.zip bundle.js
```

這會產生最小的 ZIP：

```
my-agent.zip
└── bundle.js
```

這兩種方法都可運作。綁定部署通常低於 10 MB，且部署速度更快。廠商部署更簡單，不需要建置步驟，但可以更大。

### 原生模組和 arm64 相容性
<a name="concept-node-native-modules"></a>

AgentCore 執行期僅支援 **arm64** 指令集架構。如果您的代理程式使用包含原生模組 （編譯`.node`或`.so`檔案） 的 npm 套件，則必須針對 Linux arm64 編譯這些二進位檔。

AgentCore Runtime 透過讀取部署套件中的所有 `.node`和 `.so` 檔案的架構，來驗證其 ELF 標頭。如果針對不同的架構 （例如 x86\_64 或 macOS) 編譯任何二進位檔，您的代理程式建立將會失敗，狀態為 `CREATE_FAILED` 。

若要安裝與 arm64 相容的原生模組：
+ 在 arm64 AWS 機器上安裝相依性 （例如 Graviton 型 Amazon EC2 執行個體）
+ 使用 npm `--arch`和 `--platform`旗標：

  ```
  npm install --arch=arm64 --platform=linux
  ```
+ 如果可在執行時間避免原生模組，請使用 esbuild 綁定您的程式碼

最熱門的 npm 套件 (Express、Axios、Fastify、Hono、ws) 是純 JavaScript，不包含原生模組。

### 使用 TypeScript
<a name="concept-node-typescript"></a>

AgentCore 執行期不會直接執行 TypeScript 檔案。部署之前，您必須將 TypeScript 原始程式碼編譯至 JavaScript。這是 AWS Lambda 使用的相同模式。

 **使用 TypeScript 編譯器 (tsc)：**

```
npm install -g typescript
npx tsc --init --target ES2022 --module commonjs --outDir ./dist
npx tsc
```

然後封裝編譯的輸出：

```
cd dist
zip -r ../deployment_package.zip .
```

建立代理程式時，請將進入點設定為編譯`.js`的檔案 （例如，`app.js`或`dist/app.js`取決於您的 ZIP 結構）。

 **使用 esbuild （建議用於更簡單的封裝）：**

```
npx esbuild app.ts --bundle --platform=node --target=node22 --outfile=app.js
zip deployment_package.zip app.js
```

esbuild 會在單一步驟中編譯 TypeScript 和套件相依性，產生小型、獨立的`.js`檔案。

### package.json 引擎欄位
<a name="concept-node-engines"></a>

如果您的 `package.json`包含 `engines.node` 欄位，AgentCore 執行期會驗證指定的範圍是否與您選取的 Node.js 版本相容 （例如，使用`NODE_22`執行期時的 Node.js 22)。如果範圍排除該版本，您的客服人員建立將會失敗，狀態為 `CREATE_FAILED` 。

例如，下列`engines`宣告與 Node.js 22 相容：

```
{ "engines": { "node": ">=18" } }
{ "engines": { "node": ">=14 <18 || >=20" } }
{ "engines": { "node": "22" } }
```

下列宣告不相容，會導致代理程式建立失敗：

```
{ "engines": { "node": "<18" } }
{ "engines": { "node": ">=14 <18" } }
```

AgentCore 執行期也會檢查 `engines.node` 欄位中是否有 `node_modules/` 中的常見相依性。如果其中任何一個宣告排除目標執行時間版本的 Node.js 版本範圍，則代理程式建立將會失敗。

如果您遇到`engines.node`不相容的情況，請將套件更新為支援目標 Node.js `package.json` 版本的版本，或從中移除 `engines` 欄位。如需支援的 Node.js 版本，請參閱[支援的語言執行時間](runtime-code-deploy-supported-runtimes.md)。