Claude Commerce Agents 源码解析:从双角色 Agent 到可审计的电商执行框架

从双角色建模到三种运行时,拆解一个把工具契约、安全闸门和 UI 事件统一起来的 Agent 参考实现

Posted by iceyao on Friday, September 4, 2026

一、引言:Agent 不只是一个 Prompt

很多 Agent 示例把重点放在系统提示词和工具列表上:模型能调用几个 API,就被称为一个 Agent。但真正进入业务系统后,问题很快会变成另一组问题:工具调用是否有权限边界?模型能否引用没有见过的商品或记录?一次写操作能否回滚、审批和审计?同一套能力换成另一种运行时后,行为是否仍然一致?

commerce-agents 给出的答案是:把 Agent 当成一个可复用的执行系统,而不是一个聊天脚本。仓库围绕虚构的 ACME 商业体系实现了两个角色:面向消费者的 shopping agent,以及面向运营人员的 merchant agent。两个角色共享安全、记忆、工具执行、流式事件和提示词组装机制,同时通过各自的领域核心接入不同的业务后端。

Claude Commerce Agents 分层架构

本文以仓库当前源码为依据,重点分析以下问题:

  • 目录如何把公共机制、角色核心、运行时和垂直示例分层;
  • Messages APIClaude Agent SDKManaged Agents 为什么可以复用同一套工具契约;
  • 购物代理的 provenance gate 与商户代理的 staged change 如何把模型行为约束在可审计边界内;
  • 这个项目使用了哪些工程设计模式,以及从参考实现走向生产还需要补什么。

先说明一个重要边界:仓库中的品牌、商品和人物都是虚构的。购物侧不会下单或扣款,checkout 只是把购物车交给宿主应用;商户侧的写操作默认只生成待审批的变更,只有宿主完成批准后才会应用到业务系统。

二、项目概览:两个角色、三条路径、四个垂直示例

2.1 两个角色解决两类问题

角色 面向对象 主要能力 写操作边界
shopping-agent 消费者 搜索、比较、规划、购物车、订单与政策问答、个性化记忆 只修改购物车;结账由宿主应用完成
merchant-agent 商户运营人员 经营指标、商品与库存、定价促销、营销活动、分析委托 stage_* 先生成变更,预览后等待人工批准

这不是把一个 Agent 复制成两个 Prompt。两个角色拥有不同的领域类型、后端接口、工具注册表、grounding 规则和安全闸门,但它们都建立在 commerce-common/commerce_common/ 的同一执行框架上。

2.2 三种运行路径

同一个角色可以通过三种方式运行:

  1. Messages API:仓库的参考运行时。ShoppingAgentMerchantAgent 自己负责轮次、流式响应、工具调用和事件输出。
  2. Claude Agent SDK:通过 ClaudeAgentOptions 启动 Agent SDK,工具以进程内 MCP server 的形式挂载,宿主负责预取上下文并收集结果。
  3. Managed Agents:平台负责 Agent 循环,仓库提供 agent.yaml、派生出的 system.md、Skills、MCP server 和宿主侧自定义 UI 工具。

三条路径并不是完全相同的部署形态。Messages API 和 Agent SDK 能运行仓库中的 grounding 与部分分析逻辑;Managed Agents 的工具选择和确认由平台负责,因此 grounding.py 的运行时逻辑不在这条路径上,商户分析委托也没有写进 Managed Agent manifest。仓库通过公共工具契约、MCP server 和跨路径测试尽量把差异收敛在边界内。

三种 Agent 运行路径

2.3 四个可运行垂直

examples/ 目录提供了四个完整示例:

  • retail/:常规商品、购物车、库存和 listing 操作;
  • travel/:日期约束的库存与行程展示;
  • telecom/:账户上下文、套餐比较和受保护的费用字段;
  • entertainment/:限时 hold、候补、场馆座位图和全价费用披露。

四个示例都复用 examples/demo_common/ 的 FastAPI 宿主代码和 examples/web-shared/ 的前端协议、流式 Hook 与组件框架,只把垂直数据、后端实现、配置和领域 UI 留在自己的目录中。

三、目录结构:公共内核与角色边界

仓库的目录组织比单体 Agent 项目更接近一个小型平台:

commerce-agents/
├── commerce-common/
│   └── commerce_common/       # 两个角色共享的执行与安全机制
├── shopping-agent/
│   ├── core/                  # 购物领域类型、后端、Prompt、工具与 gates
│   ├── runtime-messages-api/  # Messages API 轮次循环
│   ├── runtime-agent-sdk/     # Agent SDK 运行时与控制台
│   ├── managed-agents/        # manifest 与 storefront MCP server
│   └── skills/                # 五个购物流程
├── merchant-agent/
│   ├── core/                  # 商户领域类型、后端、变更与 guardrails
│   ├── runtime-messages-api/  # Messages API 轮次循环与分析委托
│   ├── runtime-agent-sdk/     # Agent SDK 运行时与审批控制台
│   ├── managed-agents/        # manifest、merchant MCP、定时 digest
│   └── skills/                # 五个运营流程
├── examples/                  # 四个垂直的 FastAPI + Next.js 应用
├── plugins/commerce-builder/  # Claude Code 构建与评估插件
├── docs/                      # safety、backend、deployment 文档
├── tests/                     # 跨包、跨角色、跨运行时测试
└── scripts/                   # 安装、demo、smoke、检查和部署脚本

3.1 commerce-common:把容易重复的机制抽出来

公共包的 README 明确采用“一种机制一个模块”的组织方式,核心模块如下:

模块 职责
config.py BaseAgentConfig,统一身份、模型、预算、能力开关、记忆与长度上限
fencing.py 清洗不可信文本,移除隐藏字符、伪造角色边界和特殊标签,再包裹固定 fence
memory.py MemoryStore 协议、事实校验、写入过滤、提取、保留期和 purge
skills.py SKILL.md 目录加载流程,在 Prompt 中生成技能索引
prompt_assembly.py 静态系统块、工具列表、动态上下文和 rolling cache breakpoint
grounding.py 根据用户消息决定是否必须先调用某个读取工具
presentation.py UI payload 校验、服务端 enrichment、uiui_partial 事件
execution.py BaseToolExecutor,统一分发、失败梯度、Skills、UI、delegate 与 memory
streaming.py AgentEventToolOutcome 和 SSE 序列化
turn.py 流式轮次、并发工具调度、历史压缩、工具结果和 usage 统计
agent_sdk.py / mcp_server.py Agent SDK 和 MCP 的公共适配层

这层抽象的价值不在于减少 import,而在于把安全规则放到所有运行路径都会经过的位置。docs/safety.md 也明确说明:Messages API、SDK toolset 和 MCP server 都通过同一个执行器执行工具,因此写在工具调用内部的规则可以跨路径生效。

3.2 角色核心:后端接口是业务系统的端口

shopping-agent/core/shopping_agent/backend.py 定义了 StorefrontBackend,覆盖目录搜索、商品详情、购物车、偏好、订单、政策和履约选项,并提供账户上下文、披露和 checkout handoff 等可选扩展。

merchant-agent/core/merchant_agent/backend.py 定义了 MerchantBackend,覆盖经营快照、指标序列、活动表现、listing、库存告警、订单问题、定价上下文,以及 stage_*apply_changediscard_change 等变更接口。

两个接口都遵守同一个边界:凭证和真实业务调用只在服务端发生,模型只能看到方法返回的数据。后端接口因此既是业务适配层,也是模型与企业系统之间的反腐层(Anti-Corruption Layer):平台内部的商品、订单、仓库、数据仓库等复杂模型,被收敛成 Agent 可以理解的 Pydantic 领域对象。

四、架构主线:一次请求如何穿过系统

4.1 静态 Prompt 与动态上下文分离

两个角色的 prompt.py 都把请求拆成两部分:

  • 静态系统块:身份、长期规则、工具使用方式和 Skills 索引。它在 Agent 构造时生成,并设置缓存断点;
  • 动态上下文块:当前小时、用户或商户上下文、购物车、记忆事实、当前页面等,每个 turn 预取后生成。

工具列表也按固定顺序构造,并通过 with_tool_cache_control() 给最后一个工具设置缓存断点。build_request_messages() 只在发给模型的副本上移动 rolling breakpoint,不修改宿主保存的历史。

这种拆分解决了两个经常被忽略的问题:

  1. per-request 数据不会让静态系统 Prompt 和工具定义每轮失去缓存;
  2. 动态上下文的变化是可解释的:购物车写入、页面切换、保存记忆或小时变化,才会导致对应上下文重新计算。

4.2 Skills 采用渐进式披露

每个角色有五个 SKILL.md 流程。静态 Prompt 只放技能名称和描述,模型通过 load_skill 在请求匹配时读取具体流程。工具描述负责“什么时候调用”,Prompt 负责高频通用规则,Skill 负责某条业务流程的步骤与边界。

这种分工避免了把所有流程细节塞进系统 Prompt,也让一个垂直应用可以通过新增目录扩展能力,而不必复制整个 Agent。

4.3 stream_turn 的核心循环

shopping_agent_runtime/orchestrator.py 为例,一次 turn 的主流程可以概括为:

async def stream_turn(messages, session, state):
    # 1. 并行预取 profile、cart、account、memory
    context = build_dynamic_context(...)
    system = build_system_blocks(static_system, context)

    for round_index in range(max_tool_iterations + 1):
        # 2. 首轮可以被 grounding 规则固定到某个读取工具
        # 3. 最后一轮强制 tool_choice = none
        response = await stream_model(system, messages, tool_choice)

        # 4. 工具输入闭合后立即执行,和模型剩余输出重叠
        outcomes = await dispatcher.collect(response.tool_uses)
        messages.append(tool_results(outcomes))

        # 5. 干净的 presentation round 可以直接结束 turn
        if round_closes_turn(outcomes):
            break

    yield turn_complete(...)

源码中的实现还处理了几个生产中很容易遗漏的细节:

  • EagerDispatcher 在流式 content_block_stop 后就启动工具,减少模型生成与后端等待的串行时间;
  • StreamedRound 支持 presentation 工具的 ui_partial,卡片可以在输入逐渐生成时更新;
  • 流式工具输入不是合法 JSON 时,salvage_round() 会保留已生成的轮次,并让模型重新发送调用,而不是把半截输入当成真实请求;
  • finally 会为未完成的 tool use 补上结果或错误,避免宿主把一个无法继续的对话历史保存下来;
  • 达到 max_tool_iterations 后,最后一轮不再提供工具,防止 Agent 无限循环。

4.4 共享执行器与失败梯度

BaseToolExecutor.execute() 是跨角色、跨路径的关键收敛点。它把模型输入分成 status 行和真正的工具参数,再按固定顺序执行:能力开关、Skill、presentation、delegate、领域 handler。

其失败处理可以抽象为:

async def execute(name, raw_input):
    try:
        return await dispatch(name, raw_input)
    except InvalidArguments as error:
        return ToolOutcome.error(format_invalid_arguments(error))
    except Exception as error:
        if domain_outcome := domain_error(error):
            return domain_outcome
        log_exception(name, error)
        return ToolOutcome.error(unavailable_text(name))

结果不会简单地把异常抛给模型或宿主,而是区分 okerrorblocked。例如 provenance 或 approval gate 产生的是正常工具结果,但状态为 blocked 并带有 gate 名称;后端暂时不可用则返回安全的 unavailable 文案。这样一来,模型可以继续完成当前 turn,宿主也可以用统一的事件协议渲染工具轨迹。

4.5 事件协议连接后端与前端

commerce_common/streaming.py 定义的事件包括:

事件 用途
text_delta 增量文本
tool_call / tool_result 工具开始、结束和状态
ui_partial / ui 流式或最终 UI 组件
cart_update 购物车写入后的完整购物车
change_update 商户变更状态变化后的完整记录
progress 分析 delegate 的进度信息
turn_complete stop reason、usage、耗时和历史压缩信息

examples/web-shared/ 的 TypeScript protocol.ts 镜像这套协议,前端不需要理解模型的原始响应,只需要消费 Agent 事件。对于 UI 工具,模型只负责选择记录 id、布局和解释;商品名称、价格、指标和变更 diff 由服务端根据 session provenance 再次关联。

一次 Agent turn 的执行与安全路径

五、两个角色的核心机制

5.1 Shopping Agent:把“推荐”限制在已见过的记录

购物侧最值得注意的不是搜索工具,而是购物车写入前的 provenance 约束。shopping_agent/gates.py 中的 check_provenance() 要求 product_id 必须来自本 session 的目录或订单工具结果;购物车已有的行可以作为更新和删除的例外。

添加商品还要经过第二层 options gate:如果搜索返回的是带 options 的 family,而不是具体 variant,add_to_cart 会被 hold,并要求模型从详情中的 variants 选择一个具体 id。这样模型不能凭空拼出一个尺寸、颜色或 SKU。

真正写购物车时还有三道限制:

  1. 单行数量被 max_quantity_per_item 截断;
  2. 购物车行数被 max_cart_lines 限制;
  3. 同一 session 的购物车读改写使用异步锁串行化,避免同一轮并发工具调用产生覆盖。

但仓库没有把这些 gate 当成完整业务规则。StorefrontBackend 的文档明确要求后端仍然原子地检查库存、资格和平台限制,因为进程内锁不能覆盖多 worker 或外部服务。

购物侧的 checkout 也体现了“最小权限”原则:它只生成订单摘要并让宿主渲染自己的结账页面。若使用平台 hosted checkout,URL 在模型调用结束后由 checkout_handoff() 加到 UI payload,模型永远看不到支付 URL,也没有支付凭证或下单方法。

Shopping Agent 购物流程与写入边界

5.2 Merchant Agent:把写操作设计成提案生命周期

商户侧把写操作建模为一个小型状态机:

STAGED  ── operator approval ──>  APPLIED
   └──────── operator/agent ────>  DISCARDED

merchant_agent/changes.pyChangeLedger 为示例后端提供了 stage()apply()discard()StagedChange 记录 change_id、变更类型、字段级 before/after、创建者、批准者、时间戳、guardrail notes 和利润影响。

check_guardrails() 在 stage 时检查:

  • 单次变更的条目数;
  • 价格变化幅度和促销折扣深度;
  • 补货数量与活动预算;
  • 受保护字段;
  • listing update 不允许携带的 price/stock 字段;
  • 同一个 target + field 在一次变更中重复出现。

这些限制不是只在提案阶段检查一次。check_apply_change() 在应用前按当前配置重新执行 guardrail,然后按顺序检查:

known = state.seen_changes.get(change_id)
if known is None:
    return held("provenance")
if check_guardrails(known.kind, known.items, config):
    return held("guardrail")
if config.require_host_approval and change_id not in state.approved_change_ids:
    return held("approval")
return None

因此,“模型说 approve”不等于“系统已经批准”。默认模式下,只有宿主 Portal 的批准按钮或 SDK toolset 的 host_approve() 会写入 approved_change_ids。在 Managed Agents 路径上,平台的 always_ask 确认就是批准面,所以 MCP server 使用与该平台确认机制相匹配的配置。

Merchant Agent 的提案、审批与应用生命周期

5.3 分析 delegate:把复杂查询隔离成只读子任务

商户 Agent 可选地注册 run_analysis delegate。它不是把 SQL 直接暴露给主模型,而是把简短分析目标交给一个独立的 delegate,delegate 再使用只读读取工具或受限 SQL 查询,最终返回经过 schema 校验的 AnalysisResult

merchant_agent/analysis.py 和 runtime 层共同约束了这条路径:

  • 查询必须是单条只读 SELECT,并经过 check_analysis_sql()
  • 行数、字符数、查询超时和 delegate 次数都有上限;
  • 分析结果不能增加可用于写操作的 provenance;
  • delegate 的进度通过 progress 事件流向 Portal,而不是让主模型输出冗长过程。

这是一个很实用的职责切分:主 Agent 负责和运营人员沟通与做出行动建议,分析子任务负责在受限数据面上计算结果,写操作仍然只能走 merchant executor 的变更闸门。

Merchant Agent 运营闭环

5.4 Presentation Extension:垂直 UI 的扩展点

公共包把 UI 组件抽象为 PresentationComponent,其核心步骤是:

  1. Pydantic 校验模型传入的 payload;
  2. 根据 session state 检查 id 是否有 provenance;
  3. 通过 enrich hook 从后端补全真实数据;
  4. 生成 ui 事件交给宿主渲染。

垂直应用可以通过 PresentationExtension 增加自己的日历、地图、费用明细或行程组件,但不能覆盖内置组件名。这个扩展点让领域 UI 与核心 Agent 解耦:旅游只增加行程展示,票务只增加座位图和费用披露,不需要 fork 整套 Agent。

Presentation Tool 的服务端 enrichment 流程

六、依赖关系:七个 Python 包加一个前端工作区

根目录的 requirements.txt 通过 editable install 安装七个仓库内包:

commerce-common
shopping-agent-core
shopping-agent-runtime
shopping-agent-sdk
merchant-agent-core
merchant-agent-runtime
merchant-agent-sdk

它们的依赖关系可以概括为:

依赖重点 作用
commerce-common anthropicpydanticPyYAML 公共执行、安全、事件和适配机制
shopping-agent-core commerce-commonpydantic 购物领域模型、后端接口、工具和 gates
shopping-agent-runtime common、shopping core、anthropic Messages API turn loop
shopping-agent-sdk common、shopping core、claude-agent-sdkmcp Agent SDK toolset 与控制台
merchant-agent-core commerce-commonpydantic 商户领域模型、变更、guardrails
merchant-agent-runtime common、merchant core、anthropic Messages API turn loop 与分析 delegate
merchant-agent-sdk common、merchant core、claude-agent-sdkmcp Agent SDK toolset 与审批控制台

仓库还把运行时依赖锁在 requirements.txt 中,例如 Python 3.11+、anthropicpydanticclaude-agent-sdkmcp、FastAPI 和 Uvicorn。每个角色的 core/runtime 是独立 pyproject.toml,但 sibling package 使用同一个 0.1.0.dev0 版本并从本地目录安装,避免误解析到公共包索引。

前端部分则是 examples/package.json 管理的 npm workspace:八个 Next.js 应用共享 web-shared,每个垂直保留自己的 storefront 和 merchant portal 组件。这样形成了“Python 负责 Agent 与后端协议、TypeScript 负责事件消费和视觉呈现”的边界。

七、设计模式:六个模式的落点与分工

前面几节按“怎么运行”展开,这一节把散落其中的设计模式收敛成一张表:

设计模式 代码落点 解决的问题
Ports and Adapters StorefrontBackend / MerchantBackend + 四个垂直 mock backend 业务系统替换不重写 Prompt 和工具协议
Template Method + Strategy BaseToolExecutor + 角色 executor + executor_class 执行骨架统一,领域行为可替换
Policy Object GroundingRulecheck_provenance()check_apply_change()check_guardrails() 把“是否允许继续”从 handler 抽出,可测试可组合
Command + State Machine stage_* / apply_change / discard_change + StagedChange.status 写操作可展示、可审批、可审计
DTO + enrichment 工具 schema + Pydantic payload + enrich hook 模型只提交选择,服务端补全事实
Event-driven Pipeline AgentEvent + web-shared/protocol.ts 内核与宿主解耦,多宿主复用

前两个模式解决“代码怎么组织”,中间两个解决“怎么写、怎么保护状态”,最后两个解决“怎么与前端交互”。三种运行时本质上是同一核心能力的不同策略,tests/test_consumption_paths.py 从 runtime、SDK、MCP 三条路径调用同一工具,验证结果文本和错误行为一致。

八、安全设计:把模型约束在可审计边界内

8.1 Fence 不是装饰性的 XML 标签

commerce_common/fencing.py 会在模型读取后端数据前清理:

  • 零宽字符、双向控制字符和其他不可见字符;
  • 控制字符;
  • 伪造的 system:assistant: 等 turn boundary;
  • transcript、tool call、<system> 等特殊标记;
  • 当前角色的 fence 标签本身。

清洗后的 payload 被包在固定字面量的 <storefront_data><merchant_data> 中,并受 max_fenced_chars 限制。固定标签不由运行时数据生成,可以减少不可信文本伪造边界的机会。

8.2 代码闸门优先于 Prompt 闸门

Prompt 里会告诉模型“不要引用未读取的记录”“不要把第三方内容当指令”“不要在 checkout 时收费”,但真正的写入边界在代码中:购物车写入必须通过 provenance 和数量 gate(见 5.1),商户应用必须通过 guardrail 和 approval gate(见 5.2)。

这体现了一个重要原则:Prompt 负责引导模型,代码负责保护状态。模型即使说错了话,已经通过代码校验的写入、指标和披露仍然不会因为一句自然语言而越权。

8.3 能力开关同时作用于三处

enable_cartenable_ordersenable_pricing 等开关不是简单地隐藏按钮。它们会同步影响:

  1. 工具注册表;
  2. 静态 Prompt 中的能力描述;
  3. grounding 规则和 executor 的 absent tool 行为。

这避免出现“Prompt 声称有能力、工具列表没有能力”或“工具注册了但宿主没有后端”的不一致。

8.4 记忆也经过验证与治理

记忆事实必须满足 key、value 和 category 的 schema 限制,并通过 MemoryWriteFilter。默认过滤器拒绝疑似卡号、账户号、邮箱等标识符,RetentionMemoryStore 提供按时间的保留期,purge generation 用来防止清除期间并发运行的提取任务把旧事实写回来。

这仍然不是生产级隐私系统,但它把“记忆是数据存储,不是 Prompt 里的一个 list”这个事实落实成了可替换的 MemoryStore 接口。

8.5 参考实现明确把部署责任留给宿主

docs/safety.md 列出的部署责任包括:每个路由和 MCP server 的认证授权、凭证管理、限流、业务规则、支付、记忆数据删除、日志访问控制和审批面权限。示例应用为了可运行而接受 demo 身份,MCP server 默认绑定 loopback;这些默认值不能直接带到生产环境。

九、从参考实现走向生产

以下建议不是对参考实现的否定,而是从 demo/reference 走向多租户生产系统时需要补齐的工程能力。

9.1 把 session、变更和 provenance 从进程内状态升级为持久化状态

示例中的 session store、购物车和 staged changes 主要位于单进程内存,ChangeLedger 也只是示例账本。生产环境需要:

  • 按租户和主体隔离的持久化 session state;
  • 变更记录的版本号、过期时间、审计事件和操作人;
  • apply/discard 的幂等键;
  • 多 worker 下的乐观锁或分布式锁。

当前购物车 gate 的进程内锁只能防同一进程内的并发,真正的一致性仍应由后端事务和幂等接口保证。

9.2 建立统一的路径能力矩阵

三条运行路径有意保留差异:Managed Agents 由平台控制 tool choice 和确认,Messages API 执行 runtime grounding,SDK 的分析路径也不同。随着自定义工具增加,最好生成一张机器可校验的 capability matrix,明确每个工具在三条路径上的:

  • 注册方式;
  • 参数 schema;
  • 是否需要确认;
  • 是否有 server enrichment;
  • 是否支持 partial event;
  • 是否受哪个 gate 保护。

这样可以把现在依赖 scripts/check.py 和跨路径测试维护的知识,提升为显式的发布契约。

9.3 增强可观测性与 Agent Eval

项目已经有 FakeClient、跨路径 contract tests、smoke chat、verify_all.py 和插件中的 eval 能力。生产环境还可以在此基础上增加:

  • OpenTelemetry trace,把一次 turn、模型轮次、工具调用、gate 结果和后端请求串起来;
  • 按 tool、gate、租户统计延迟、失败率、blocked 次数和 token/cache 命中;
  • 对“模型说了什么”和“系统实际改变了什么”分别评分;
  • 记录可脱敏的 replay fixture,用于 Prompt、schema 和模型版本升级回归。

9.4 为后端适配层增加可靠性策略

目前 backend 接口已经把“未提供”“暂不可用”“业务拒绝”区分开,但真实外部服务还会有超时、限流、部分成功和版本漂移。可以在宿主层补充:

  • per-backend timeout、重试和 circuit breaker;
  • 读操作的短时缓存与 stale-while-revalidate;
  • 写操作的幂等键和 outbox;
  • 领域 schema 的版本号和兼容迁移;
  • 对多平台 connector 的统一错误码。

9.5 把记忆、日志与写操作纳入完整治理

默认过滤器能挡住一部分标识符,但生产仍需要按业务定义敏感字段、同意与撤回、导出与删除、跨设备同步、加密和访问审计。尤其要谨慎处理 DEBUG 日志:源码文档已经提示,DEBUG 请求体可能包含整个购物车和注入的记忆事实。

商户写操作同理:check_guardrails() 已经覆盖数量、价格、预算和保护字段,但生产还应把库存冻结、价格生效窗口、税费、币种、市场/卖家范围和人工职责分离放到后端事务中。Agent 层的 guardrail 适合做第一道快速反馈,不能替代最终业务规则和审批系统。

十、总结:把模型能力放进一个可控的系统

commerce-agents 的核心价值不在于它演示了多少商品搜索工具,而在于它把一个业务 Agent 拆成了可以分别验证的层次:

  • commerce-common 统一安全、记忆、执行器、事件和 Prompt 组装;
  • 两个 role core 通过 Backend 接口隔离具体业务系统;
  • Messages API、Agent SDK、Managed Agents 三条路径共享工具契约与关键执行逻辑;
  • presentation tool 让模型选择事实、服务端补全事实;
  • shopping 的 provenance gate 限制“能写哪些商品”;
  • merchant 的 staged change 和 host approval 限制“什么时候能写入真实系统”;
  • 测试和派生文件检查则把跨路径一致性变成可执行约束。

如果要从这份源码提炼一条最值得复用的经验,可以概括为:把 Prompt 当作行为指南,把工具描述当作路由,把 Skill 当作流程,把后端接口当作业务边界,把代码 gate 当作最后的权限线。 只有这样,Agent 才不只是“能调用工具的模型”,而是一个可以被宿主接入、被测试、被审批和被审计的业务执行组件。

「真诚赞赏,手留余香」

爱折腾的工程师

真诚赞赏,手留余香

使用微信扫描二维码完成支付