AI News HubLIVE
站內改寫6 分鐘閱讀

待翻譯:Asynchronous patterns for calling Amazon Bedrock AgentCore agents in serverless pipelines

AI 服務暫時不可用,以下為來源摘要,待恢復後補全翻譯:In this post, you learn three serverless patterns (task-token callback, direct service integration, and durable functions) for invoking Amazon Bedrock AgentCore agents asynchronously from AWS Step Functions pipelines, eliminating idle compute costs while your AI agent processes requests.

來源AWS Machine Learning Blog作者: Daniel Abib

AI 服務暫時不可用,以下為來源正文,待恢復後補全翻譯。

Asynchronous invocation patterns for Amazon Bedrock AgentCore agents in serverless pipelines remove idle compute costs while your AI agent processes requests. A common example is document validation: in a real-estate financing back office, an agent can read a property record or loan contract, reason about whether the information is complete and consistent, and return a verdict that downstream steps act on. Amazon Bedrock AgentCore provides a platform to build, connect, and optimize agents at scale, with any framework or model. These agents introduce a characteristic that traditional pipeline steps do not have: they think for a while before they answer. How long depends on the prompt, the model, and the document, but it’s rarely instant, and that latency changes how you should call it. The most common first implementation is a compute service, such as an AWS Lambda function, that invokes the agent and waits for the response. While that function waits, it does nothing, but it is still running, and you are billed for every second of it. It helps to see where the cost actually lands, because the two sides of the call are billed differently. Amazon Bedrock AgentCore runtime, a capability of Amazon Bedrock AgentCore, has a consumption-based model that doesn’t charge for CPU while the agent is idle. For instance, while it waits on a large language model to generate a response, or on a tool or Model Context Protocol (MCP) call to return, you are billed for memory during that time, but not for CPU. The compute service that called the agent has no such behavior. A Lambda function, container, or Amazon Elastic Compute Cloud (Amazon EC2) instance that issues a synchronous call sits blocked. It holds (and pays for) its full compute allocation until the agent responds. So the waste is not on the agent side. It’s the caller, idling on an open connection. That makes the caller’s cost track the agent’s runtime. A function that blocks on the agent is billed for essentially the entire processing time, whereas a function that starts the agent and returns is billed only for the brief dispatch. The fix is to release the caller’s compute during the wait and resume the pipeline only when the agent has a result. In this post, we show three patterns that do this (task-token callback, direct service integration, and durable function) and contrast them with the blocking anti-pattern. An example pipeline To compare the patterns on equal footing, we run each one through the same pipeline and change only the step that calls the agent. The pipeline is a deliberately simple, made-up scenario (validating documents for real-estate financing) chosen to keep the orchestration clear. It’s not the point of the post. It stands in for any workflow that calls an agent (or another slow service) and then acts on the result, so picture your own use case in its place. The pipeline has five stages: Extract: An AWS Lambda function performs optical character recognition (OCR) and text extraction on the document. (Extraction is simulated, so the scenario runs without real documents.) Identify: A Lambda function classifies the document and sets routing flags (shouldOrganize, shouldValidate). Route: A Choice state directs the flow based on those flags. Organize and Validate: A Parallel state organizes the document while, in a separate branch, the Amazon Bedrock AgentCore agent validates it. This Validate branch is the only part that changes between patterns. Result: A Lambda function processes the agent’s verdict and decides the next action (approve, or return for correction). The following diagram shows the pipeline. It stays the same in every case. Only the Validate branch is swapped to demonstrate each invocation pattern. Figure 1: The example pipeline. Only the highlighted Validate branch changes between patterns A single Amazon Bedrock AgentCore agent serves all four cases. The agent inspects each invocation and chooses how to respond: if it receives an AWS Step Functions task token, it wakes that execution when done. If it receives a durable-function callback ID, it wakes the durable function. If it receives neither, it returns the verdict directly in the response. This means you can change the orchestration pattern without changing or redeploying the agent. How the agent returns control without blocking the caller The mechanism is a return-of-control action in the agent’s action group. When the agent finishes reasoning, it calls a Lambda that posts the result and the task token back to Step Functions. (Pattern 2, described later, eliminates this Lambda entirely by having Step Functions integrate directly with AgentCore.) The following code shows the core of that Lambda: # The tool the agent calls once it reaches a verdict @tool def conclude_validation(approved: bool, issues: list, summary: str) -> str: verdict = {"approved": approved, "issues": issues, "summary": summary, "source": "agentcore"} # A Step Functions task token was passed: resume that execution if task_token: sfn.send_task_success(taskToken=task_token, output=json.dumps(verdict)) return "Step Functions resumed." # A durable-function callback ID was passed: resume the durable function if callback_id: lambda_client.send_durable_execution_callback_success( CallbackId=callback_id, Result=json.dumps(verdict).encode("utf-8")) return "Durable function resumed." # Neither was passed: this is a synchronous call, return the verdict inline return "Verdict recorded." The entrypoint decides whether to run in the background or synchronously based on the same signals: @app.async_task async def validate_document_async(prompt, document, extracted_text): # Background work; conclude_validation fires the right callback when done agent = build_agent() await agent.invoke_async(message(prompt, document, extracted_text)) @app.entrypoint async def handler(event): task_token = event.get("taskToken") # passed by the task-token pattern callback_id = event.get("callbackId") # passed by the durable-function pattern # Asynchronous: start the work and return "accepted" right away if task_token or callback_id: asyncio.create_task(validate_document_async(...)) return {"status": "accepted"} # Synchronous: run now and return the verdict in the response agent = build_agent() await agent.invoke_async(message(...)) return verdict With the agent in place, the rest of the post focuses on the four ways to call it. Calling the agent: Four approaches We start with the blocking anti-pattern to establish the baseline cost, then show the three patterns that avoid it. The code and infrastructure definitions throughout are excerpts from the sample, included to illustrate each pattern. The blocking anti-pattern The most direct implementation calls the agent and waits for the answer in the same Lambda function. It works, and it is straightforward to implement, which is why it’s so common, but the function stays alive for the entire time the agent is thinking. // The Lambda function blocks here until the agent responds const response = await agentcore.send( new InvokeAgentRuntimeCommand({ agentRuntimeArn: AGENT_RUNTIME_ARN, payload: new TextEncoder().encode(JSON.stringify(payload)), runtimeSessionId: sessionId, }) ); // The function stays alive and billed for the entire time the agent is thinking. The function’s billed duration ends up approximately equal to the agent’s processing time. The next three patterns eliminate this idle cost, each making a different trade-off. In particular, Pattern 2 uses the Step Functions optimized integration for AgentCore Harness (InvokeHarness), removing the Lambda entirely. Pattern 1: Task-token callback with a dispatcher function This pattern keeps a Lambda function in the path for custom logic but removes the idle cost. Step Functions invokes the function with the waitForTaskToken integration, which passes a task token and then pauses the execution. The function uses the token to start the agent, then returns in a few seconds. The execution stays paused, billing nothing for compute, until the agent calls SendTaskSuccess with that token to resume it. // Start the agent, pass the task token, and return without waiting const response = await agentcore.send( new InvokeAgentRuntimeCommand({ agentRuntimeArn: AGENT_RUNTIME_ARN, payload: new TextEncoder().encode(JSON.stringify({ ...payload, taskToken })), runtimeSessionId: sessionId, }) ); // Returning here does not complete the step. Step Functions stays paused until // the agent calls SendTaskSuccess with this task token. return { dispatched: true }; The corresponding state passes the token from context and sets a timeout and heartbeat as a safety net, so a silent agent fails the execution cleanly rather than leaving it paused indefinitely: "ValidateDispatch": { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke.waitForTaskToken", "Parameters": { "FunctionName": "${ValidateDispatcherFunctionArn}", "Payload": { "taskToken.$": "$$.Task.Token", "document.$": "$.document", "extractedText.$": "$.extract.extractedText", "executionId.$": "$$.Execution.Id" } }, "TimeoutSeconds": 120, "HeartbeatSeconds": 60, "Next": "AgentCoreValidation" } Cost. A Lambda function runs, but only long enough to start the agent and return: a few seconds, regardless of how long the agent then takes. You pay for that brief dispatch, not for the wait, because the function has already shut down while the agent works. The wait is held by the paused Step Functions execution, which doesn’t bill for idle compute. This is the key difference from the blocking version, where the function’s billed time tracks the agent’s processing time. Pattern 2: Direct service integration When you don’t need custom code around the agent call, you can remove the dispatcher function and take Lambda out of the path entirely. Step Functions can call Amazon Bedrock AgentCore directly through its AWS SDK service integration, so the agent’s response flows straight into the next state. The Validate branch then becomes a single Task state: "ValidateDirect": { "Type": "Task", "Resource": "arn:aws:states:::aws-sdk:bedrockagentcore:invokeAgentRuntime", "Parameters": { "AgentRuntimeArn": "${AgentRuntimeArn}", "RuntimeSessionId.$": "States.Hash($$.Execution.Id, 'SHA-256')", "Payload.$": "States.JsonToString($.prep.agentInput)" }, "ResultSelector": { "raw.$": "$.Response" }, "TimeoutSeconds": 120, "Next": "ParseVerdict" } Cost. There’s no Lambda function in the path, so there is no idle Lambda compute to pay for. Step Functions holds the wait, and a Standard workflow bills per state transition rather than for the duration of the wait, so the meaningful cost during processing is the agent itself. Pattern 3: Lambda durable function If you would rather express the orchestration as code in one place instead of a state machine, a Lambda durable function gives you the same cost behavior. With the @aws/durable-execution-sdk-js SDK, the pipeline stages become context.step calls, the parallel work becomes context.parallel, and the wait for the agent becomes context.waitForCallback. During that wait the function suspends and is not billed for compute. The agent resumes it with SendDurableExecutionCallbackSuccess. // Suspend the function until the agent calls back const result = await ctx.waitForCallback( "validate-agentcore", async (callbackId) => dispatchAgentCore(callbackId, document, extractedText, executionId), { timeout: { seconds: 120 } } ); Cost. A single function holds the whole pipeline, but it doesn’t bill for compute while it is suspended waiting for the agent. You pay for the short bursts of execution between suspensions, the same economics as the task-token pattern, rather than for the wait. Measuring the difference The point isn’t any particular number. The agent’s runtime varies with the prompt, the model, and the document. What matters is the relationship between two values in the task-token patt [truncated for AI cost control]