AI 销售代理真正进入生产环境后,难点不再是“能不能生成一段像样的销售话术”,而是能否持续工作、稳定调用业务工具,并在大量并发会话中保持上下文。AgentFlo 的实践围绕 Amazon Bedrock AgentCore 和 Strands Agents SDK 展开,提炼出生产级代理的三个支柱:速度、标准化和可扩展性。
这三个目标彼此牵制。部署速度快,不能牺牲配置一致性;工具数量增长,不能让每个代理都维护一套重复的集成代码;流量突然上涨,也不能让用户在购物对话中丢失状态。
生产级代理的三个支柱
速度:把部署变成可重复的配方
销售代理通常不是单一角色。它可能负责商品推荐、订单查询、售后跟进或促销活动。为每个角色手工配置模型、提示词、工具权限和运行环境,会让上线过程越来越慢,也容易产生环境差异。
一种更适合团队协作的方式,是把代理定义为“配方”。配方可以包含:
- 代理角色和系统提示词
- 使用的模型与推理参数
- 可访问的工具集合
- 会话状态和身份信息的处理方式
- 部署所需的运行时参数
- 监控、超时和错误处理策略
这样,新增一个销售代理主要变成填写配置和组合能力,而不是复制一套运行时代码。配方还可以进入版本控制,经过代码评审后再部署到不同环境。
下面是一个可以改造的最小代理配置示例。字段名称是示意性的,实际字段应以团队使用的 AgentCore 部署脚本和运行时契约为准:
name: product-advisor
runtime: strands
model:
provider: amazon-bedrock
id: amazon.nova-pro-v1:0
temperature: 0.2
instructions: |
你是一名电商商品顾问。
先理解客户的预算、用途和偏好,再推荐最多三件商品。
不确定库存或价格时,必须调用工具确认,不要猜测。
tools:
- catalog.search
- inventory.check
- cart.add
session:
state_store: managed
ttl_minutes: 60
limits:
request_timeout_seconds: 30
max_tool_calls: 8
可以把这类文件放入 Git,并在 CI/CD 中执行校验、部署和冒烟测试。速度来自标准化流程,而不是简单地减少步骤。
标准化:让工具路由集中管理
销售代理的价值通常依赖业务工具:商品搜索、库存查询、购物车、优惠券、订单和客户资料。若每个代理都直接接入这些后端服务,系统很快会出现重复认证、参数格式不一致和权限边界模糊等问题。
AgentCore Gateway 提供了一个集中管理工具访问的思路:代理通过统一的网关发现和调用工具,网关负责把工具请求路由到实际服务。这样,代理关注“什么时候需要查库存”,而不是“库存服务的地址是什么、如何刷新令牌、错误码如何转换”。
一个工具调用请求可以抽象成下面的 HTTP 形态。它不是特定项目的固定 API,而是便于本地实现和联调的最小契约:
curl -X POST "$GATEWAY_ENDPOINT/tools/inventory.check" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sku": "SKU-12345",
"region": "us-east-1"
}'
运行前设置 GATEWAY_ENDPOINT 和 AGENT_TOKEN。在真实环境中,还应为每个代理配置最小权限,并对工具调用记录代理身份、会话 ID、工具名、参数摘要、延迟和结果状态。
集中路由还有一个重要收益:工具可以独立演进。后端服务从 REST 迁移到事件驱动架构,或更换库存系统时,代理提示词和业务流程不必跟着大幅修改。网关成为代理能力与后端实现之间的稳定边界。
这并不意味着网关可以隐藏所有复杂性。工具契约仍然需要明确输入校验、幂等语义、超时、重试和敏感字段脱敏策略。尤其是 cart.add、下单和退款等有副作用的操作,不能只依赖模型自行判断。
可扩展性:让会话在弹性运行时中保持连续
“始终在线”不等于启动一个永不停止的进程。生产环境中的代理实例可能因为扩缩容、故障恢复或发布而变化,但用户的购物对话不能因此丢失。
一个可靠的会话设计通常会把短暂运行的代理实例和持久化状态分开:
- 代理实例负责当前轮次的推理和工具调用
- 会话存储负责保存客户目标、已确认事实、购物车上下文和最近交互
- 每次请求根据会话 ID 恢复必要状态
- 工具调用结果以结构化数据保存,而不是只保留自然语言摘要
例如,下面是一个简化的 Python 会话处理框架。它展示的是可运行的状态管理思路;run_agent 可以替换为基于 Strands Agents SDK 和 Bedrock AgentCore 的实际调用:
from dataclasses import dataclass, field
from typing import Any
@dataclass
class Session:
customer_id: str
facts: dict[str, Any] = field(default_factory=dict)
messages: list[dict[str, str]] = field(default_factory=list)
sessions: dict[str, Session] = {}
def run_agent(session_id: str, customer_id: str, user_text: str) -> str:
session = sessions.setdefault(session_id, Session(customer_id=customer_id))
session.messages.append({"role": "user", "content": user_text})
# 实际项目中,这里调用 Strands agent,并由 AgentCore 路由工具。
if "预算" in user_text:
session.facts["budget"] = user_text
reply = "我记下了预算。请告诉我主要使用场景,我会进一步缩小推荐范围。"
else:
reply = "我可以根据预算、用途和偏好帮你筛选商品。"
session.messages.append({"role": "assistant", "content": reply})
return reply
if __name__ == "__main__":
print(run_agent("session-001", "customer-42", "我的预算是 500 美元"))
print(run_agent("session-001", "customer-42", "主要用于旅行"))
print(sessions["session-001"].facts)
运行方式:
python session_demo.py
示例使用内存字典只是为了便于演示。部署到生产环境时,应替换为受控的持久化状态存储,并考虑 TTL、并发更新、加密、租户隔离和数据删除要求。对话历史也不应无限增长,可以采用最近消息加结构化长期事实的组合形式。
弹性运行还要求工具调用具备明确的恢复策略。例如,库存查询超时可以重试或向用户说明暂时无法确认;下单请求则需要幂等键,避免模型重试导致重复创建订单。
从“能运行”到“能运营”的检查表
采用 AgentCore 和 Strands Agents SDK 构建销售代理时,可以从以下问题开始验收:
- 是否能用同一套配方在开发、测试和生产环境中复现代理?
- 新增工具是否只需注册和配置,而不是修改多个代理的集成代码?
- 每次工具调用是否具备身份、会话和审计信息?
- 会话状态是否能跨实例恢复,并支持过期和删除?
- 有副作用的工具是否具备幂等、权限校验和人工升级路径?
- 是否监控首 token 延迟、完整响应延迟、工具失败率、会话恢复失败率和成本?
AgentFlo 的三条经验可以概括为:用配方提升交付速度,用 Gateway 统一工具边界,用有状态设计支撑弹性会话。它们不是互相独立的组件选择,而是一套从代理定义、工具访问到运行时扩缩容的工程约束。
对团队而言,较稳妥的落地顺序是先选一个边界清晰的销售场景,固定少量只读工具,建立会话和观测基线,再逐步加入购物车、下单等有副作用的能力。这样既能验证 AgentCore 的运行模型,也能在扩大自动化范围前控制权限、数据和业务风险。