跳转到内容

实现和配置Story代理

故事代理是一个基于 Strands 的代理,在给定 GameAction 列表作为上下文时,能够推进故事情节发展。我们将配置该代理与库存管理控制协议(MCP)服务器交互,以管理玩家的可用物品。

要实现代理,请更新 packages/story/dungeon_adventure_story/agent 目录下的以下文件:

import uuid
import uvicorn
from bedrock_agentcore.runtime.models import PingStatus
from pydantic import BaseModel
from .agent import get_agent
from .init import JsonStreamingResponse, app
class Action(BaseModel):
role: str
content: str
class InvokeInput(BaseModel):
playerName: str
genre: str
actions: list[Action]
class StreamChunk(BaseModel):
content: str
async def handle_invoke(input: InvokeInput):
"""Streaming handler for agent invocation"""
messages = [{"role": "user", "content": [{"text": "Continue or create a new story..."}]}]
for action in input.actions:
messages.append({"role": action.role, "content": [{"text": action.content}]})
with get_agent(input.playerName, input.genre, session_id=str(uuid.uuid4())) as agent:
stream = agent.stream_async(messages)
async for event in stream:
print(event)
content = event.get("event", {}).get("contentBlockDelta", {}).get("delta", {}).get("text")
if content is not None:
yield StreamChunk(content=content)
elif event.get("event", {}).get("messageStop") is not None:
yield StreamChunk(content="\n")
@app.post(
"/invocations",
response_class=JsonStreamingResponse,
responses={200: JsonStreamingResponse.openapi_response(StreamChunk, "Stream of agent response chunks")},
)
async def invoke(input: InvokeInput) -> JsonStreamingResponse:
"""Entry point for agent invocation"""
return JsonStreamingResponse(handle_invoke(input))
@app.get("/ping")
def ping() -> str:
# TODO: if running an async task, return PingStatus.HEALTHY_BUSY
return PingStatus.HEALTHY
if __name__ == "__main__":
uvicorn.run("dungeon_adventure_story.agent.main:app", port=8080)

此配置将实现以下功能:

  • 从代理负载中提取玩家信息、游戏类型和动作列表,
  • 构建使用 SigV4 认证调用 MCP 服务器的客户端,以及
  • 通过系统提示和 MCP 服务器工具构建代理。

要构建代码:

Terminal window
pnpm build

要部署应用程序,请运行以下命令:

Terminal window
pnpm nx deploy infra "dungeon-adventure-infra-sandbox/*"

部署过程约需 2 分钟完成。

部署完成后,将看到类似以下输出(部分值已脱敏):

Terminal window
dungeon-adventure-infra-sandbox-Application
dungeon-adventure-infra-sandbox-Application: deploying... [2/2]
dungeon-adventure-infra-sandbox-Application
部署时间:354秒
输出:
dungeon-adventure-infra-sandbox-Application.ElectroDbTableTableNameXXX = dungeon-adventure-infra-sandbox-Application-ElectroDbTableXXX-YYY
dungeon-adventure-infra-sandbox-Application.GameApiEndpointXXX = https://xxx.execute-api.region.amazonaws.com/prod/
dungeon-adventure-infra-sandbox-Application.GameUIDistributionDomainNameXXX = xxx.cloudfront.net
dungeon-adventure-infra-sandbox-Application.InventoryMcpArn = arn:aws:bedrock-agentcore:region:xxxxxxx:runtime/dungeonadventureventoryMcpServerXXXX-YYYY
dungeon-adventure-infra-sandbox-Application.StoryAgentArn = arn:aws:bedrock-agentcore:region:xxxxxxx:runtime/dungeonadventurecationStoryAgentXXXX-YYYY
dungeon-adventure-infra-sandbox-Application.UserIdentityUserIdentityIdentityPoolIdXXX = region:xxx
dungeon-adventure-infra-sandbox-Application.UserIdentityUserIdentityUserPoolIdXXX = region_xxx

可通过以下方式测试代理:

  • 启动代理服务器本地实例并使用 curl 调用,或
  • 使用携带 JWT 令牌的 curl 调用已部署 API。

运行以下命令启动本地代理服务器:

Terminal window
INVENTORY_MCP_ARN=arn:aws:bedrock-agentcore:region:xxxxxxx:runtime/dungeonadventureventoryMcpServerXXXX-YYYY AWS_REGION=<region> pnpm nx run dungeon_adventure.story:agent-serve

代理服务器启动并运行后(无输出显示),运行以下命令进行调用:

Terminal window
curl -N -X POST http://127.0.0.1:8081/invocations \
-d '{"genre":"superhero", "actions":[], "playerName":"UnnamedHero"}' \
-H "Content-Type: application/json"

若命令运行成功,将开始看到初始故事文本以 JSON Lines 格式流式输出:

{"content":"You are "}
{"content":"a new superhero "}
{"content":"in the bustling metropolis of Metro City..."}

恭喜!您已成功在 Bedrock AgentCore 运行时上构建并部署首个 Strands 代理!🎉🎉🎉