ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AI自动下单Agent架构设计:从意图解析到人工确认的完整链路

AI自动下单Agent架构设计:从意图解析到人工确认的完整链路 当用户对 AI 说“帮我买一箱牛奶预算 50 元以内”时AI Agent 要完成的并不是一次简单的搜索而是意图识别、商品筛选、价格校验、下单、支付确认和后续跟进一整套流程。围绕 AI 自动下单最近讨论最多的样本是 Perplexity 与亚马逊之间的数据访问争议AI 搜索可以直接给出购买结论电商平台则担心流量和交易链路被架空于是出现限制、恢复、再协商的反复。这里不打算评判谁违法也不替任何一方下结论。真正值得沉淀的是工程问题如果团队要自建一个 AI 自动下单 Agent架构该怎么设计接口该怎么选风控怎么处理日志怎么留以及在哪里必须停手把决定权交还给用户。1. 先拆解自动下单 Agent 的完整链路AI 自动下单看起来像一句指令落到系统里至少要拆成五个阶段意图解析、商品检索、决策校验、交易执行、订单跟踪。每一阶段的技术选型不同失败模式和合规风险也不同。很多团队一上来就写“调用大模型→操作浏览器→提交订单”结果在支付和风控环节反复踩坑。正确做法是先画出完整链路再逐段决定哪些环节可以自动哪些必须人工介入。1.1 意图解析把自然语言变成结构化订单用户说“明天送到、不要太贵”的时候系统不能靠关键词匹配。关键词匹配只能解决固定句式无法处理“找一支黑色签字笔价格不超过 20 元明天要送到”这种混合了规格、价格、时效的请求。更可靠的方式是让 LLM 输出结构化 JSON再交给后续服务消费。这里推荐使用 Pydantic 或类似 schema 校验库而不是让模型自由发挥返回一段文本。from typing import List from pydantic import BaseModel, Field class ProductFilter(BaseModel): name: str Field(..., description商品名称例如 纯牛奶) brand: str | None Field(None, description品牌可为空) quantity: int Field(1, ge1, le99, description购买数量) max_price: float | None Field(None, description单价上限空表示不限) category: str | None Field(None, description类目) must_keywords: List[str] Field(default_factorylist, description必须包含的关键词) class ShipmentRequirement(BaseModel): address: str | None Field(None, description收货地址) expected_date: str | None Field(None, description期望送达日期格式 YYYY-MM-DD) class PurchaseIntent(BaseModel): product_filter: ProductFilter shipment: ShipmentRequirement Field(default_factoryShipmentRequirement)这段代码解决的问题是把用户输入中的商品名、品牌、数量、价格上限、收货地址和期望送达时间拆成独立字段。字段级约束的好处是后面做库存、价格、配送校验时不需要再解析一次自然语言。模型输出后还需要做 schema 校验字段缺失或枚举值错误是这里最常见的坑。例如用户说“牛奶”模型可能生成 10 种品牌如果没有默认值和必填字段约束后续商品检索会非常不稳定。1.2 商品检索API 优先网页采集放后面商品检索是自动下单里最容易越界的一步。这里有两条路官方开放平台 API 和网页自动化采集。前者稳定、授权明确、数据结构清晰后者依赖 DOM 结构容易被风控和验证码拦截。维度官方 API网页采集授权方式需要申请 AppKey/Secret签署条款依赖登录态和 Cookie通常未获授权数据结构有文档、字段稳定需要解析 HTML选择器变更即坏频率限制有明确 QPS 配额受风控限制没有明确数字下单能力支持购物车、结算、支付等完整流程表单提交不稳定支付环节几乎必须人工合规风险低但需遵守接口条款高可能违反 robots.txt 和用户协议建议场景自营商城、开放平台无 API 的公开信息抓取、半自动流程自建 Agent 首选官方 API。不是因为官方 API 一定免费而是它把“能不能做”变成了一个可查询的规则而不是事后追责的不确定性。网页采集虽然看起来“都能做”但每次页面改版都要修选择器每次风控策略升级都可能造成大面积失败长期维护成本很高。1.3 决策与下单不是搜到就买而是校验后再买简单实现里Agent 搜索商品后直接把第一个结果加进购物车。这样会有三个问题价格变动、库存不足、优惠券和运费没算进去。真实订单决策需要在最后一步重新读取购物车或结算页数据而不是使用搜索阶段的价格快照。重新读取当前价格而不是搜索时的价格。校验库存状态和配送时效。检查实付金额是否超过用户预算阈值。记录商品 SKU、链接、价格快照便于后续对账。为下单请求生成幂等键避免同一个指令被重复提交。为什么必须重新读取因为搜索接口返回的通常是最低基础价结算页才会包含满减、优惠券、运费和库存信息。如果直接拿搜索价格下单用户可能在最后看到一笔完全不同的金额。1.4 订单跟踪与售后状态机下单不是终点。支付完成后还要跟踪订单状态待发货、已发货、已签收、售后退款。可以按状态机设计避免各个渠道里散落一堆 if else。状态触发时机Agent 动作CREATED订单创建通知用户开始轮询PAID支付成功记录支付凭证等待发货SHIPPED商家发货跟踪物流COMPLETED签收归档订单数据REFUNDING用户申请售后标记待处理转人工状态不能只放在内存里否则进程重启后会丢。建议订单状态写入数据库用事件驱动方式更新状态并把状态变更日志写入审计表。2. 为什么平台会限制 AI 自动下单规则、风控和商业冲突讨论 Perplexity 和亚马逊的争议时容易把它简化成“谁对谁错”。从工程角度看平台限制自动下单原因通常是三类数据采集不合规、自动化交易触发风控、商业流量分配被绕过。这三类原因叠加在一起才会出现新闻里看到的“封锁—恢复—再协商”过程。2.1 robots.txt 是规则信号但技术层面还有更多约束robots.txt 是一种爬虫协议告诉搜索引擎和其他爬虫哪些路径可以访问、哪些不可以。它本身不是法律文件但很多平台会在用户协议里引用它把它变成合同义务的一部分。对自动下单 Agent 来说robots.txt 是第一个需要检查的规则信号。# https://example.com/robots.txt User-agent: PerplexityBot Disallow: /checkout User-agent: * Disallow: /account这段示例表达了两类限制特定爬虫不能访问结算路径所有爬虫都不能访问账户路径。即使 Agent 把自己的 UA 换成一个自定义名称服务端仍然可以通过 IP、TLS 指纹、请求路径、访问频率识别出它不是真人。所以不要以为 robots.txt 只是给搜索引擎看的平台的风控系统比 robots.txt 严格得多。2.2 自动下单会让风控系统高度紧张一个真人用户从搜索到下单通常需要几十秒甚至几分钟中间包含停顿、鼠标移动、页面滚动。AI Agent 操作页面时请求间隔非常均匀点击路径也很固定这是明显的机器行为特征。平台风控会从登录环境、设备指纹、请求频率、支付信息等多个维度打分。如果项目为了追求速度把搜索、加购、结算一起在几秒内完成基本必然触发验证码或账号风控。所以实现自动下单时不仅要关注功能通不通还要关注请求节奏。更合理的做法是给自动流程设置间隔把逻辑上不依赖上一步的场景拆开执行而不是在一个循环里疯狂调接口。2.3 流量归属和佣金是不可回避的商业问题任何电商平台都依赖用户在自己的站内完成搜索、比价、下单因为搜索和流量本身有商业价值。AI Agent 把搜索过程搬到模型侧用户只回到平台完成一个支付动作平台就流失了搜索广告位和推荐曝光。这种情况下平台更可能选择封锁而不是开放接口。这也是为什么很多平台愿意提供官方 API但会要求开发者遵守条款、限制频率、甚至按调用量计费。API 的本质不是让 AI 免费替用户代劳而是让自动化行为在可监控、可计费、可下线的框架内运行。2.4 为什么限制会出现“反转”所谓反转通常不是平台突然觉得自动化合法而是双方重谈规则。常见路径有三种Agent 公司同意使用官方 API 并支付数据费用平台以白名单方式开放受限接口或者 Agent 放弃网页自动化改为跳转链接加半自动下单。工程上不要把“反转”当成技术胜利它更像是商业谈判结果。想复现第一步是拿到明确授权而不是研究如何绕过。团队在立项时就应该确认这个平台是否提供正式 API是否允许自动化下单支付环节是否允许第三方代开这些答案决定了技术方案的上限。3. 搭一套可运行的自建 AI 下单 Agent项目结构与渠道适配下面用 Python 和 FastAPI 做示例。它不一定是生产最优解目的是让你看到完整骨架一个 FastAPI 服务接收用户指令调度 Agent 规划任务通过渠道层调用不同电商接口最后在执行下单前进入确认流程。整个项目围绕“渠道适配”展开这是多平台自动下单的核心。3.1 项目结构ai-shop-agent/ ├── app/ │ ├── main.py │ ├── config.py │ ├── agents/ │ │ ├── orchestrator.py │ │ └── planner.py │ ├── channels/ │ │ ├── base.py │ │ ├── api_channel.py │ │ └── web_channel.py │ ├── services/ │ │ ├── order_service.py │ │ └── verify_service.py │ ├── models/ │ │ └── intent.py │ └── utils/ │ ├── logger.py │ └── retry.py ├── config/ │ └── agents.yaml ├── tests/ └── requirements.txtchannels 目录是关键。多电商平台接入时不要让业务代码直接调 requests 或 Playwright。通过一个 base class 抽象出搜索、加购、结算、支付确认四个动作平台差异被收敛在具体实现里。这样当新增一个平台时只需要新增一个 channel 文件不用改上层编排逻辑。3.2 渠道抽象类from abc import ABC, abstractmethod from dataclasses import dataclass dataclass class ChannelAuth: app_key: str app_secret: str user_session: str class ShoppingChannel(ABC): name: str base def __init__(self, auth: ChannelAuth): self.auth auth abstractmethod def search(self, keyword: str, max_price: float | None None): ... abstractmethod def add_to_cart(self, sku_id: str, quantity: int) - str: ... abstractmethod def get_checkout_detail(self, cart_token: str): ... abstractmethod def confirm_order(self, checkout_token: str, payment_token: str): ...四个方法分别对应下单流程中的关键动作search 返回统一格式的商品列表add_to_cart 返回购物车 tokenget_checkout_detail 返回当前结算价、库存、运费confirm_order 绑定支付 token 后提交订单。生产环境不会这样简洁还需要校验返回码、超时、幂等键但抽象关系就是这样。3.3 API 渠道示例import requests from .base import ShoppingChannel, ChannelAuth class ApiChannel(ShoppingChannel): name openapi def __init__(self, auth: ChannelAuth, base_url: str): super().__init__(auth) self.base_url base_url.rstrip(/) def search(self, keyword: str, max_price: float | None None): resp requests.get( f{self.base_url}/v1/products/search, params{q: keyword, max_price: max_price}, headers{Authorization: fBearer {self.auth.app_key}}, timeout10, ) resp.raise_for_status() data resp.json() return data.get(items, [])这里没有做完整签名。真实开放平台通常要求 HMAC 签名、时间戳防重放、渠道内限流。接口返回值最好先转成统一商品模型不要让上层代码感知不同平台的字段差异。否则每个平台一套命名下单逻辑里会写满 if else。3.4 网页渠道只做“读取”不做“强制提交”如果平台没有公开 API网页渠道可以作为兜底方案但必须控制使用场景。网页渠道可以用于读取库存、价格、商品详情等公开信息也可以在一些需要登录态的页面检查订单状态。但支付环节不要让 AI 直接操作更不要在无人确认的情况下自动填入支付密码。from playwright.async_api import async_playwright async def check_stock(url: str, user_data_dir: str) - dict: async with async_playwright() as p: browser await p.chromium.launch_persistent_context( user_data_dir, headlessFalse, args[--disable-blink-featuresAutomationControlled], ) page await browser.new_page() await page.goto(url, wait_untildomcontentloaded) stock await page.locator(#stock_status).inner_text() price await page.locator(#price).inner_text() await browser.close() return {url: url, stock: stock, price: price}headlessFalse 不是玩笑。许多风控系统对普通 headless 的 TLS 指纹和浏览器特征非常敏感。更重要的是这个示例只读取库存和价格不提交任何表单。自动读取公开信息可以接受自动提交支付必须交给用户。3.5 配置外置app: env: prod log_level: info llm: model_name: qwen-plus temperature: 0.1 max_retries: 2 channels: openapi: base_url: https://openapi.example.com timeout_seconds: 10 qps_limit: 5 web: headless: false user_data_dir: /var/data/browser-profile order: max_amount: 500 require_user_confirm: true payment_timeout_minutes: 15生产环境里密钥不能写在 YAML要通过环境变量或密钥管理服务注入。这个文件只保留非敏感配置和阈值。这里的 payment_timeout_minutes 含义是生成支付确认链接后15 分钟内用户没点击订单自动取消避免脏订单和过期 token。4. 下单前的三层校验价格、风控、人工确认跳过校验是订单出错的最大原因。AI 自动下单比人手动下单更需要防御性设计因为用户不会像自己购物时那样盯着每一步。提交订单之前至少要做三轮校验价格与库存校验、频率与风控校验、人工确认校验。4.1 价格与库存复核搜索结果价格和结算页价格常常不一样。优惠券、满减、运费都只有在结算页才准确。所以下单前必须重新读取 checkout detail并和用户预算比较。def validate_order(checkout: dict, user_limit: float) - dict: total_amount checkout[total_amount] stock_status checkout[stock_status] errors [] if total_amount user_limit: errors.append(f实付金额 {total_amount} 超过预算 {user_limit}) if stock_status ! in_stock: errors.append(f库存状态异常: {stock_status}) if checkout.get(estimated_delivery_date) is None: errors.append(无法确定配送时效) return {valid: not errors, errors: errors, checkout: checkout}这里的 user_limit 在意图解析阶段已经写入但用户可能忘记说预算所以系统还要设置默认上限。默认上限不要写成无限当用户没有给预算时宁可转人工确认。价格校验失败时应该把新的实付金额和差额一起发给用户让用户决定是否继续。4.2 风控与频率限制AI Agent 发起请求的速度通常比人快需要在中间层加令牌桶或队列。这里的目的不是“绕过风控”而是让自动化行为看上去像一组有节制的请求减少账号被误伤的概率。import time from threading import Lock class RateLimiter: def __init__(self, qps: float 2.0): self.min_interval 1.0 / qps self._next_ts time.monotonic() self._lock Lock() def wait(self): with self._lock: now time.monotonic() wait_time self._next_ts - now if wait_time 0: time.sleep(wait_time) self._next_ts max(now, self._next_ts) self.min_interval这里 qps 是全局建议值。不同平台差异很大某个平台自己的公开接口可能允许 5 QPS而网页路径可能 1 秒都不该连续请求。具体数值以平台文档为准配合可用性监控逐步调整。不要为了效率把限流调得过大一旦账号被风控损失的时间远比节省的时间多。4.3 人工确认把支付决定权还给用户AI 可以自动选品、加购、填写收货地址但支付动作一定要有用户确认。这不是保守是产品底线。自动扣款的 Agent 如果出现一次错误价格用户信任就没了。人工确认最好做成带签名和过期时间的链接。import hmac import hashlib import time def sign_confirm_payload(order_id: str, user_id: str, amount_cents: int, expired_at: int, secret: str) - str: message f{order_id}:{user_id}:{amount_cents}:{expired_at}.encode() return hmac.new(secret.encode(), message, hashlib.sha256).hexdigest()确认链接里带上签名和过期时间用户点击后才生成支付 token。服务端校验签名、核对金额、确认订单未过期再发起支付。整个过程需要审计日志。另一个需要注意的点是幂等性下单接口要携带 merchant_order_id避免用户重复点击确认导致系统提交两笔订单。5. 运行验证从沙箱到灰度再到生产自动下单 Agent 最怕“本地没问题线上乱扣款”。所以验证必须在三层环境里分别做沙箱、mock 测试、灰度生产。每一层验证的目的不同不能混在一起。5.1 沙箱环境优先用电商平台的沙箱环境或自建 mock server。订单金额用固定测试价格支付网关用测试卡。沙箱环境的主要目的是验证接口字段、签名、状态流转是否符合预期。检查项沙箱预期失败时的表现商品搜索返回结构化商品列表鉴权错误或字段缺失加入购物车返回 cart token库存不足或 SKU 错误结算页价格金额包含运费和优惠价格与搜索结果不一致下单支付状态变为 PAIDtoken 过期或风控拒绝状态推送异步回调收到回调丢失或重复5.2 用 Mock 模拟平台响应只依赖真实平台验证会非常慢。测试里 mock 渠道层可以快速验证意图解析、校验逻辑和确认流程。# tests/test_order_service.py class FakeApiChannel(ShoppingChannel): name fake def search(self, keyword: str, max_priceNone): return [{sku_id: S01, title: keyword, price: 19.9}] def add_to_cart(self, sku_id: str, quantity: int) - str: return cart-001 def get_checkout_detail(self, cart_token: str): return {cart_token: cart_token, total_amount: 19.9, stock_status: in_stock} def confirm_order(self, checkout_token: str, payment_token: str): return {order_id: O001, status: PAID}mock 的返回值要和真实渠道尽量一致包括错误字段。例如真实接口在库存不足时会返回一个 error_codemock 里也应保留。否则测试只会骗过自己生产环境一接入真实平台就崩。5.3 灰度发布生产环境不要直接把全部流量切到自动下单。建议按用户白名单、按订单金额上限、按渠道逐步放开。白名单用户内部员工或少量测试用户。金额上限例如单笔不超过 50 元。渠道范围先开放一个电商渠道验证后再扩充。自动执行比例先只读、再半自动、再全自动。半自动阶段指的是 AI 负责搜索、加购、填写地址但支付必须用户手动完成。全自动阶段才允许在用户确认后由系统调用支付 token。灰度期间要重点关注支付成功率和风控触发率任何一个指标出现异常都要立即回滚。5.4 监控与审计核心指标包括意图识别成功率、搜索成功率、下单成功率、支付成功率、超时时长、风控触发率、用户取消率。日志里至少记录用户 ID、请求指令、结构化意图、商品 SKU、价格快照、下单状态、确认方式、支付 token 前几位、异常堆栈。不要记录完整卡号、CVV、有效期。这些字段一旦进日志就变成审计风险。敏感字段应该脱敏或只保存哈希值。审计日志要能通过 order_id 串起从意图解析到支付回调的完整链路。6. 高频报错与排查路径自动下单涉及账号体系、支付链路、风控策略错误类型非常多。下面是几个高频问题每个问题都按“现象—原因—检查—处理—预防”的顺序说明。6.1 登录态失效现象搜索正常进结算页变成未登录或者 API 返回 401。原因网页渠道的 Cookie 过期或者 API token 过期。检查先看请求日志中的状态码跳变再确认账号是否被风控锁定。处理用账号体系刷新 token网页渠道重启浏览器上下文。预防网页渠道不要持久化敏感 Cookie可用专门设备保存登录态并定时检查 token 有效期。6.2 结算金额和搜索不一致现象用户预算 50搜索时 45结算时变成 58。原因优惠券未生效、运费未计算、商家改价。检查对比两个阶段的价格快照。处理校验阶段直接拦截告知用户新价格。预防所有下单流程以结算页价格为准搜索价格只作为初筛条件。6.3 验证码或滑块拦截现象网页渠道卡在登录或结算页无法前进。原因请求频率高、浏览器指纹异常、IP 被标记。检查看渠道返回的 challenge 字段配合日志确认触发条件。处理开发阶段可以接人工处理生产阶段应限制自动化频率而不是依赖打码服务。预防优先走官方 API网页渠道只做低频读取。6.4 支付 token 过期现象用户确认时点击链接发现订单已失效。原因支付确认链路
返回列表