Buy领域智能体-Spring-AI全量工程

Buy 领域智能体 · Spring AI 全量工程与 Staff 面试

定位 :全球运动零售 Buy Team / Commerce 在存量 Spring Boot 上落地的 14 个智能化场景 ------每个场景含 POC 架构图可联调级 Spring AI 代码骨架2 道 Staff 面试满分答Guardrails 红线

前置08 §10--11 场景总览 · 14 §12 LiteLLM/MCP/多 VectorStore · 17 §4--5 Guardrails

冲刺98 §5.13--5.14 C.98--C.122


0. 共享平台骨架(14 场景复用)

0.1 依赖与模型路由(LiteLLM 主路径)

xml 复制代码
<!-- pom.xml 片段 -->
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.ai</groupId>
  <artifactId>spring-ai-starter-vector-store-redis</artifactId>
</dependency>
<dependency>
  <groupId>io.github.resilience4j</groupId>
  <artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
yaml 复制代码
# application-ai.yml
spring:
  ai:
    openai:
      api-key: ${LITELLM_API_KEY}
      base-url: ${LITELLM_PROXY_URL:http://litellm.internal:4000/v1}
      chat:
        options:
          model: commerce-smart        # LiteLLM 别名 → azure-gpt-4o / qwen 等
          temperature: 0.2
      embedding:
        options:
          model: text-embedding-3-small

commerce:
  ai:
  max-tool-iterations: 5
  scene-header: X-Commerce-AI-Scene   # CARTS_ADD | STYLIST | CS | PRICING | ...

0.2 Advisor 链(生产默认顺序)

java 复制代码
@Configuration
public class CommerceAdvisorConfig {

    @Bean
    ChatClient commerceChatClient(ChatClient.Builder builder,
                                  List<Advisor> commerceAdvisors) {
        return builder
            .defaultAdvisors(commerceAdvisors.toArray(Advisor[]::new))
            .defaultSystem("""
                你是运动零售 Buy/Commerce 助手。
                规则:①金额/库存/定价/券面额/支付渠道仅引用 Tool JSON;
                ②禁止承诺赔偿、中签、自动改价;③不确定时建议转人工。
                """)
            .build();
    }

    @Bean
    List<Advisor> commerceAdvisors(
            SafeGuardAdvisor safeGuard,
            SimpleLoggerAdvisor logger,
            QuestionAnswerAdvisor faqRag,      // L1 Redis FAQ
            MessageChatMemoryAdvisor memory) { // Redis session
        return List.of(safeGuard, logger, faqRag, memory);
    }
}

0.3 场景路由 Controller 模式

java 复制代码
@RestController
@RequestMapping("/api/v1/commerce-ai")
@RequiredArgsConstructor
public class CommerceAiGatewayController {

    private final Map<String, CommerceAiSceneHandler> handlers;

    @PostMapping("/{scene}")
    public Object invoke(@PathVariable String scene,
                         @RequestHeader("X-User-Id") String userId,
                         @RequestBody CommerceAiRequest req) {
        return handlers.get(scene).handle(userId, req);
    }
}

public interface CommerceAiSceneHandler {
    String scene();
    Object handle(String userId, CommerceAiRequest req);
}

#mermaid-svg-gcLAFO1WTIkYNn1G{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gcLAFO1WTIkYNn1G .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gcLAFO1WTIkYNn1G .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gcLAFO1WTIkYNn1G .error-icon{fill:#552222;}#mermaid-svg-gcLAFO1WTIkYNn1G .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gcLAFO1WTIkYNn1G .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gcLAFO1WTIkYNn1G .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gcLAFO1WTIkYNn1G .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gcLAFO1WTIkYNn1G .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gcLAFO1WTIkYNn1G .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gcLAFO1WTIkYNn1G .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gcLAFO1WTIkYNn1G .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gcLAFO1WTIkYNn1G .marker.cross{stroke:#333333;}#mermaid-svg-gcLAFO1WTIkYNn1G svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gcLAFO1WTIkYNn1G p{margin:0;}#mermaid-svg-gcLAFO1WTIkYNn1G .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gcLAFO1WTIkYNn1G .cluster-label text{fill:#333;}#mermaid-svg-gcLAFO1WTIkYNn1G .cluster-label span{color:#333;}#mermaid-svg-gcLAFO1WTIkYNn1G .cluster-label span p{background-color:transparent;}#mermaid-svg-gcLAFO1WTIkYNn1G .label text,#mermaid-svg-gcLAFO1WTIkYNn1G span{fill:#333;color:#333;}#mermaid-svg-gcLAFO1WTIkYNn1G .node rect,#mermaid-svg-gcLAFO1WTIkYNn1G .node circle,#mermaid-svg-gcLAFO1WTIkYNn1G .node ellipse,#mermaid-svg-gcLAFO1WTIkYNn1G .node polygon,#mermaid-svg-gcLAFO1WTIkYNn1G .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gcLAFO1WTIkYNn1G .rough-node .label text,#mermaid-svg-gcLAFO1WTIkYNn1G .node .label text,#mermaid-svg-gcLAFO1WTIkYNn1G .image-shape .label,#mermaid-svg-gcLAFO1WTIkYNn1G .icon-shape .label{text-anchor:middle;}#mermaid-svg-gcLAFO1WTIkYNn1G .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gcLAFO1WTIkYNn1G .rough-node .label,#mermaid-svg-gcLAFO1WTIkYNn1G .node .label,#mermaid-svg-gcLAFO1WTIkYNn1G .image-shape .label,#mermaid-svg-gcLAFO1WTIkYNn1G .icon-shape .label{text-align:center;}#mermaid-svg-gcLAFO1WTIkYNn1G .node.clickable{cursor:pointer;}#mermaid-svg-gcLAFO1WTIkYNn1G .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gcLAFO1WTIkYNn1G .arrowheadPath{fill:#333333;}#mermaid-svg-gcLAFO1WTIkYNn1G .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gcLAFO1WTIkYNn1G .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gcLAFO1WTIkYNn1G .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gcLAFO1WTIkYNn1G .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gcLAFO1WTIkYNn1G .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gcLAFO1WTIkYNn1G .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gcLAFO1WTIkYNn1G .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gcLAFO1WTIkYNn1G .cluster text{fill:#333;}#mermaid-svg-gcLAFO1WTIkYNn1G .cluster span{color:#333;}#mermaid-svg-gcLAFO1WTIkYNn1G div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gcLAFO1WTIkYNn1G .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gcLAFO1WTIkYNn1G rect.text{fill:none;stroke-width:0;}#mermaid-svg-gcLAFO1WTIkYNn1G .icon-shape,#mermaid-svg-gcLAFO1WTIkYNn1G .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gcLAFO1WTIkYNn1G .icon-shape p,#mermaid-svg-gcLAFO1WTIkYNn1G .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gcLAFO1WTIkYNn1G .icon-shape .label rect,#mermaid-svg-gcLAFO1WTIkYNn1G .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gcLAFO1WTIkYNn1G .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gcLAFO1WTIkYNn1G .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gcLAFO1WTIkYNn1G :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} DomainServices
AI
Handlers
SceneRouter
Gateway
API Gateway
CommerceAiGateway
StylistHandler
CsHandler
PricingHandler
CartsHandler
ChatClient + Advisors
LiteLLM Proxy
Tool Facades
PIM/OMS/Carts/Pricing/Payment


1. 智能导购 Agent(Stylist)

1.1 业务(Buy + C 端)

自然语言选品 → 多轮澄清(场景/尺码/预算)→ 推荐 3 SKU + 对比 → 可选加车。LLM 编排;价格库存只读 Tool。

1.2 POC 架构

CatalogFacade StylistTools ProductRAG ChatClient StylistHandler User CatalogFacade StylistTools ProductRAG ChatClient StylistHandler User #mermaid-svg-lBW8oYVPBADtlCJK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lBW8oYVPBADtlCJK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lBW8oYVPBADtlCJK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lBW8oYVPBADtlCJK .error-icon{fill:#552222;}#mermaid-svg-lBW8oYVPBADtlCJK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lBW8oYVPBADtlCJK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lBW8oYVPBADtlCJK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lBW8oYVPBADtlCJK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lBW8oYVPBADtlCJK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lBW8oYVPBADtlCJK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lBW8oYVPBADtlCJK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lBW8oYVPBADtlCJK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lBW8oYVPBADtlCJK .marker.cross{stroke:#333333;}#mermaid-svg-lBW8oYVPBADtlCJK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lBW8oYVPBADtlCJK p{margin:0;}#mermaid-svg-lBW8oYVPBADtlCJK .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-lBW8oYVPBADtlCJK text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-lBW8oYVPBADtlCJK .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-lBW8oYVPBADtlCJK .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-lBW8oYVPBADtlCJK .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-lBW8oYVPBADtlCJK .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-lBW8oYVPBADtlCJK #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-lBW8oYVPBADtlCJK .sequenceNumber{fill:white;}#mermaid-svg-lBW8oYVPBADtlCJK #sequencenumber{fill:#333;}#mermaid-svg-lBW8oYVPBADtlCJK #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-lBW8oYVPBADtlCJK .messageText{fill:#333;stroke:none;}#mermaid-svg-lBW8oYVPBADtlCJK .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-lBW8oYVPBADtlCJK .labelText,#mermaid-svg-lBW8oYVPBADtlCJK .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-lBW8oYVPBADtlCJK .loopText,#mermaid-svg-lBW8oYVPBADtlCJK .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-lBW8oYVPBADtlCJK .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-lBW8oYVPBADtlCJK .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-lBW8oYVPBADtlCJK .noteText,#mermaid-svg-lBW8oYVPBADtlCJK .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-lBW8oYVPBADtlCJK .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-lBW8oYVPBADtlCJK .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-lBW8oYVPBADtlCJK .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-lBW8oYVPBADtlCJK .actorPopupMenu{position:absolute;}#mermaid-svg-lBW8oYVPBADtlCJK .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-lBW8oYVPBADtlCJK .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-lBW8oYVPBADtlCJK .actor-man circle,#mermaid-svg-lBW8oYVPBADtlCJK line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-lBW8oYVPBADtlCJK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} User request: height, weight, running info prompt + advisors similaritySearch product chunks searchProducts(query, size, maxPrice) search catalog skus with price and stock getMemberTier(userId) StylistRecommendation JSON

1.3 Spring AI 完整示例

java 复制代码
@Component
public class StylistTools {
    private final CatalogFacade catalog;
    private final MemberFacade member;

    @Tool(description = "按自然语言+尺码+预算搜索跑鞋/服饰 SKU")
    public List<SkuCardDto> searchProducts(
            String query,
            @ToolParam(required = false) String size,
            @ToolParam(required = false) BigDecimal maxPriceCny) {
        return catalog.search(query, size, maxPriceCny);
    }

    @Tool(description = "会员等级与可用权益,只读")
    public MemberTierDto getMemberTier(String userId) {
        return member.getTier(userId);
    }

    @Tool(description = "对比多款 SKU 关键参数")
    public CompareTableDto compareSkus(List<String> skuIds) {
        return catalog.compare(skuIds);
    }
}

@Service
@RequiredArgsConstructor
public class StylistHandler implements CommerceAiSceneHandler {
    private final ChatClient chatClient;
    private final StylistTools tools;

    @Override public String scene() { return "STYLIST"; }

  @Override
    public StylistRecommendation handle(String userId, CommerceAiRequest req) {
        return chatClient.prompt()
            .tools(tools)
            .user("userId=" + userId + ";" + req.message())
            .call()
            .entity(StylistRecommendation.class);
    }
}

public record StylistRecommendation(
    List<String> recommendedSkuIds,
    String comparisonSummary,
    List<Citation> citations) {}

public record Citation(String source, String chunkId) {}
java 复制代码
// StylistRecommendation 校验:sku 必须来自最近一次 searchProducts 返回集
@Component
public class StylistOutputVerifier implements OutputVerifier {
    public void verify(ChatResponse response, ToolContext ctx) {
        // 正则:禁止 response 中出现未在 tool 日志出现的 price 字面量
    }
}

1.4 Staff 面试题

B01 · 导购 Agent 和搜索推荐服务如何分工?

要点
结论 ML 召回排序仍走 Search/Rec 服务 ;Spring AI 做 意图澄清 + 解释 + 跨品类对话 ;Tool 调 searchProducts 而非让 LLM 背 SKU 列表。
原理 召回需要 LTR/向量索引规模;LLM 擅长语言不擅长百万 SKU 全排序。
工程 QuestionAnswerAdvisor 接 pgvector 商品知识;maxIterations=5;SSE 流式。
验证 golden:价/库存 100% 与 Tool 一致;cite rate >0.8。
风险 绕过搜索直出 LLM 编造 SKU → 合规与转化双输。

B02 · 首 token 延迟如何压到 800ms 内?

要点
结论 LiteLLM 路由 commerce-fast;RAG topK≤5;Tool 并行;Semantic Cache 热点问句。
原理 TTFT = 网关 + 检索 + 首包模型;Decode 可流式。
工程 Redis L1 FAQ 命中则跳过 Milvus;Resilience4j 超时 3s fallback 模板答。
验证 大促压测 P99 TTFT;按 scene 分池 Bulkhead。
风险 为快关掉 RAG → 幻觉升。

1.5 Guardrails

  • 价格/库存/促销 仅 Tool
  • 竞品诋毁 / 医疗承诺 → SafeGuard 拦截
  • 推荐 SKU ⊆ 最近 searchProducts 结果集

2. 智能客服 24/7

2.1 POC 架构

#mermaid-svg-5uaIZUYGWHgl2HqV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5uaIZUYGWHgl2HqV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5uaIZUYGWHgl2HqV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5uaIZUYGWHgl2HqV .error-icon{fill:#552222;}#mermaid-svg-5uaIZUYGWHgl2HqV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5uaIZUYGWHgl2HqV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5uaIZUYGWHgl2HqV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5uaIZUYGWHgl2HqV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5uaIZUYGWHgl2HqV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5uaIZUYGWHgl2HqV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5uaIZUYGWHgl2HqV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5uaIZUYGWHgl2HqV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5uaIZUYGWHgl2HqV .marker.cross{stroke:#333333;}#mermaid-svg-5uaIZUYGWHgl2HqV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5uaIZUYGWHgl2HqV p{margin:0;}#mermaid-svg-5uaIZUYGWHgl2HqV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5uaIZUYGWHgl2HqV .cluster-label text{fill:#333;}#mermaid-svg-5uaIZUYGWHgl2HqV .cluster-label span{color:#333;}#mermaid-svg-5uaIZUYGWHgl2HqV .cluster-label span p{background-color:transparent;}#mermaid-svg-5uaIZUYGWHgl2HqV .label text,#mermaid-svg-5uaIZUYGWHgl2HqV span{fill:#333;color:#333;}#mermaid-svg-5uaIZUYGWHgl2HqV .node rect,#mermaid-svg-5uaIZUYGWHgl2HqV .node circle,#mermaid-svg-5uaIZUYGWHgl2HqV .node ellipse,#mermaid-svg-5uaIZUYGWHgl2HqV .node polygon,#mermaid-svg-5uaIZUYGWHgl2HqV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5uaIZUYGWHgl2HqV .rough-node .label text,#mermaid-svg-5uaIZUYGWHgl2HqV .node .label text,#mermaid-svg-5uaIZUYGWHgl2HqV .image-shape .label,#mermaid-svg-5uaIZUYGWHgl2HqV .icon-shape .label{text-anchor:middle;}#mermaid-svg-5uaIZUYGWHgl2HqV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5uaIZUYGWHgl2HqV .rough-node .label,#mermaid-svg-5uaIZUYGWHgl2HqV .node .label,#mermaid-svg-5uaIZUYGWHgl2HqV .image-shape .label,#mermaid-svg-5uaIZUYGWHgl2HqV .icon-shape .label{text-align:center;}#mermaid-svg-5uaIZUYGWHgl2HqV .node.clickable{cursor:pointer;}#mermaid-svg-5uaIZUYGWHgl2HqV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5uaIZUYGWHgl2HqV .arrowheadPath{fill:#333333;}#mermaid-svg-5uaIZUYGWHgl2HqV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5uaIZUYGWHgl2HqV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5uaIZUYGWHgl2HqV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5uaIZUYGWHgl2HqV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5uaIZUYGWHgl2HqV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5uaIZUYGWHgl2HqV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5uaIZUYGWHgl2HqV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5uaIZUYGWHgl2HqV .cluster text{fill:#333;}#mermaid-svg-5uaIZUYGWHgl2HqV .cluster span{color:#333;}#mermaid-svg-5uaIZUYGWHgl2HqV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5uaIZUYGWHgl2HqV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5uaIZUYGWHgl2HqV rect.text{fill:none;stroke-width:0;}#mermaid-svg-5uaIZUYGWHgl2HqV .icon-shape,#mermaid-svg-5uaIZUYGWHgl2HqV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5uaIZUYGWHgl2HqV .icon-shape p,#mermaid-svg-5uaIZUYGWHgl2HqV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5uaIZUYGWHgl2HqV .icon-shape .label rect,#mermaid-svg-5uaIZUYGWHgl2HqV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5uaIZUYGWHgl2HqV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5uaIZUYGWHgl2HqV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5uaIZUYGWHgl2HqV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} FAQ Match
Policy
Order/Logistics
Sensitive
User
Three-level Router
L1 Redis Vector
L2 pgvector
Agent + OMS Tools
Human Agent
Output Verifier

2.2 Spring AI 完整示例

java 复制代码
@Component
public class CustomerServiceTools {
    private final OrderFacade orders;
    private final LogisticsFacade logistics;
    private final RefundFacade refunds;

    @Tool(description = "查询订单状态,只读")
    public OrderStatusDto getOrderStatus(String orderId, String userId) {
        return orders.getStatus(orderId, userId);
    }

    @Tool(description = "创建退款申请草稿,写操作需 idempotencyKey,不直接打款")
    public RefundDraftDto createRefundDraft(
            String orderId, String reason, String idempotencyKey) {
        return refunds.createDraft(orderId, reason, idempotencyKey);
    }
}

@Service
public class CsHandler implements CommerceAiSceneHandler {
    private final ChatClient chatClient;
    private final CustomerServiceTools tools;
    private final VectorStore faqStore;      // Redis
    private final VectorStore policyStore;   // pgvector

    @Override public String scene() { return "CUSTOMER_SERVICE"; }

    @Override
    public CsResponse handle(String userId, CommerceAiRequest req) {
        if (SensitiveKeywordDetector.matches(req.message())) {
            return CsResponse.escalate("检测到敏感诉求,已转人工");
        }
        return chatClient.prompt()
            .advisors(
                QuestionAnswerAdvisor.builder(faqStore).build(),
                QuestionAnswerAdvisor.builder(policyStore).searchRequestTransformer(
                    r -> r.withFilterExpression("tenant == 'global'")).build())
            .tools(tools)
            .user("userId=" + userId + ";" + req.message())
            .call()
            .entity(CsResponse.class);
    }
}

2.3 Staff 面试题

B03 · 客服三级路由如何设计?

要点
结论 L1 FAQ Redis <2msL2 政策 pgvectorL3 Agent+Tool 查单关键词转人工 ;误承诺 Verifier 零容忍
原理 80/15/5 流量分布;越往后成本越高。
工程 createRefundDraftexecuteRefund;赔偿类关键词 bypass LLM。
验证 红队「赔双倍」必须 escalate;自助率 >70%。
风险 Agent 直连退款 API → 资损(对齐 14 §13 STAR)。

B04 · 多 VectorStore 如何按意图路由?

要点
结论 意图分类器(轻量模型/规则)选 Advisor;或串联 Advisor 按置信短路。
工程 @Qualifier 多 Bean;filter `doc_type=faq
验证 政策题 citation 必须来自 policy 索引版本号。
风险 单库混放 → 过滤慢且易串库。

2.4 Guardrails

  • 退款/赔偿 仅 Draft + HITL
  • 输出 Verifier 禁「保证/一定赔」
  • 审计 trace_id + tool_calls 7 年

3. AI 商品分析(PIM enrichment)

3.1 POC + 代码

#mermaid-svg-jYQkGVRkXiXjsIM4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jYQkGVRkXiXjsIM4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jYQkGVRkXiXjsIM4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jYQkGVRkXiXjsIM4 .error-icon{fill:#552222;}#mermaid-svg-jYQkGVRkXiXjsIM4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jYQkGVRkXiXjsIM4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jYQkGVRkXiXjsIM4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jYQkGVRkXiXjsIM4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jYQkGVRkXiXjsIM4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jYQkGVRkXiXjsIM4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jYQkGVRkXiXjsIM4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jYQkGVRkXiXjsIM4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jYQkGVRkXiXjsIM4 .marker.cross{stroke:#333333;}#mermaid-svg-jYQkGVRkXiXjsIM4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jYQkGVRkXiXjsIM4 p{margin:0;}#mermaid-svg-jYQkGVRkXiXjsIM4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jYQkGVRkXiXjsIM4 .cluster-label text{fill:#333;}#mermaid-svg-jYQkGVRkXiXjsIM4 .cluster-label span{color:#333;}#mermaid-svg-jYQkGVRkXiXjsIM4 .cluster-label span p{background-color:transparent;}#mermaid-svg-jYQkGVRkXiXjsIM4 .label text,#mermaid-svg-jYQkGVRkXiXjsIM4 span{fill:#333;color:#333;}#mermaid-svg-jYQkGVRkXiXjsIM4 .node rect,#mermaid-svg-jYQkGVRkXiXjsIM4 .node circle,#mermaid-svg-jYQkGVRkXiXjsIM4 .node ellipse,#mermaid-svg-jYQkGVRkXiXjsIM4 .node polygon,#mermaid-svg-jYQkGVRkXiXjsIM4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jYQkGVRkXiXjsIM4 .rough-node .label text,#mermaid-svg-jYQkGVRkXiXjsIM4 .node .label text,#mermaid-svg-jYQkGVRkXiXjsIM4 .image-shape .label,#mermaid-svg-jYQkGVRkXiXjsIM4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-jYQkGVRkXiXjsIM4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jYQkGVRkXiXjsIM4 .rough-node .label,#mermaid-svg-jYQkGVRkXiXjsIM4 .node .label,#mermaid-svg-jYQkGVRkXiXjsIM4 .image-shape .label,#mermaid-svg-jYQkGVRkXiXjsIM4 .icon-shape .label{text-align:center;}#mermaid-svg-jYQkGVRkXiXjsIM4 .node.clickable{cursor:pointer;}#mermaid-svg-jYQkGVRkXiXjsIM4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jYQkGVRkXiXjsIM4 .arrowheadPath{fill:#333333;}#mermaid-svg-jYQkGVRkXiXjsIM4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jYQkGVRkXiXjsIM4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jYQkGVRkXiXjsIM4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jYQkGVRkXiXjsIM4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jYQkGVRkXiXjsIM4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jYQkGVRkXiXjsIM4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jYQkGVRkXiXjsIM4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jYQkGVRkXiXjsIM4 .cluster text{fill:#333;}#mermaid-svg-jYQkGVRkXiXjsIM4 .cluster span{color:#333;}#mermaid-svg-jYQkGVRkXiXjsIM4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jYQkGVRkXiXjsIM4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jYQkGVRkXiXjsIM4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-jYQkGVRkXiXjsIM4 .icon-shape,#mermaid-svg-jYQkGVRkXiXjsIM4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jYQkGVRkXiXjsIM4 .icon-shape p,#mermaid-svg-jYQkGVRkXiXjsIM4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jYQkGVRkXiXjsIM4 .icon-shape .label rect,#mermaid-svg-jYQkGVRkXiXjsIM4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jYQkGVRkXiXjsIM4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jYQkGVRkXiXjsIM4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jYQkGVRkXiXjsIM4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} No
Yes
PIM Change Event
Spring Batch
Embedding
ChatClient temp=0
ProductAttributeDto
Confidence >= 0.85?
Review Queue
Write Back to PIM

java 复制代码
@Service
@RequiredArgsConstructor
public class ProductEnrichmentJob {
    private final ChatClient chatClient;
    private final PimWriteFacade pim;

    @Scheduled(cron = "0 */10 * * * *")
    public void enrichBatch() {
        pim.listPendingEnrichment(500).forEach(sku -> {
            ProductAttributeDto attrs = chatClient.prompt()
                .system("只输出 JSON。类目/材质/场景标签。不确定填 unknown。")
                .user("title=" + sku.title() + "\ndesc=" + sku.description())
                .call()
                .entity(ProductAttributeDto.class);
            if (attrs.confidence() >= 0.85) {
                pim.applyAttributes(sku.id(), attrs);
            } else {
                pim.enqueueReview(sku.id(), attrs);
            }
        });
    }
}

3.2 Staff 面试题

B05 · 商品分析为什么用批处理而不是在线 Chat?

要点
结论 离线 Batch + temperature=0 控成本与一致性;在线只读已生成「AI 解读」缓存。
工程 embedding 版本 pin;低置信 HITL。
验证 属性准确率 >95% 人工抽检。
风险 在线实时抽属性 → 成本与抖动不可控。

B06 · 多模态商品分析链路?

要点
结论 图+文 → Vision API / CLIP embedding 入 Milvus;文本走 Batch LLM。
工程 图文一致性阈值 <0.7 进人审。
验证 图文不符客诉 -8% 目标。
风险 仅文本忽略图 → 退货率高。

4. 智能搭配 Outfit Builder

4.1 POC + 代码

java 复制代码
@Component
public class OutfitTools {
  @Tool(description = "按锚点SKU与风格标签返回搭配候选")
    public List<OutfitSkuDto> getOutfitCandidates(String anchorSkuId, String styleTag) { ... }

    @Tool(description = "校验套装内所有 SKU 同仓有货")
    public BundleStockDto checkBundleStock(List<String> skuIds, String storeId) { ... }
}

public record OutfitBundle(List<String> skuIds, String styleNarrative, BigDecimal bundlePrice) {}
// bundlePrice 来自 checkBundleStock 返回,非 LLM 计算

4.2 Staff 面试题

B07 · 搭配推荐如何保证有货?

要点
结论 生成后 强制 checkBundleStock;无货剔除并再生成或降级单件推荐。
验证 Eval:无货 SKU 不得出现在最终 bundle。
风险 只看风格不看 ATP → 结账失败。

B08 · Vision RAG 在搭配中的作用?

要点
结论 CLIP/SigLIP 向量检索风格相近 SKU;LLM 写叙事与场合。
工程 Milvus 多模态索引 + metadata category=footwear
风险 纯文本 RAG 忽略配色 → 搭配违和。

5. AI 满减 / 优惠券推荐

完整序列图与三 Tool 见 08 §10.5.1

5.1 Staff 面试题

B09 · 为何 System prompt 禁止输出数字金额? → 见 98 C.100

B10 · CouponAdviceResponse 如何防话术夹带金额?

要点
结论 正则 \d+\.?\d*explanation;失败则重试或模板化回复。
工程 前端只展示 Tool JSON 渲染组件。
风险 只拦模型不拦前端拼接 → 仍可能误导。

6. 限量发售个性化故事(SNKRS 类)

6.1 POC + 代码

java 复制代码
@Component
public class DropStoryTools {
    @Tool(description = "用户脱敏偏好:品类/收藏,不含PII")
    public UserTasteDto getUserTaste(String userId) { ... }

    @Tool(description = "发售元数据:系列名/设计师/年份,只读")
    public DropMetaDto getDropMeta(String dropId) { ... }
}

@Service
public class DropStoryHandler implements CommerceAiSceneHandler {
    public DropStoryResponse handle(String userId, CommerceAiRequest req) {
        return chatClient.prompt()
            .system("禁止暗示保证购买/内部名额/必中签")
            .tools(dropStoryTools)
            .user("dropId=" + req.dropId())
            .call()
            .entity(DropStoryResponse.class);
    }
}

PushService ChatClient StoryWorker Kafka Draw Result PushService ChatClient StoryWorker Kafka Draw Result #mermaid-svg-FFq9s9hY6R3mBh7T{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FFq9s9hY6R3mBh7T .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FFq9s9hY6R3mBh7T .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FFq9s9hY6R3mBh7T .error-icon{fill:#552222;}#mermaid-svg-FFq9s9hY6R3mBh7T .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FFq9s9hY6R3mBh7T .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FFq9s9hY6R3mBh7T .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FFq9s9hY6R3mBh7T .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FFq9s9hY6R3mBh7T .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FFq9s9hY6R3mBh7T .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FFq9s9hY6R3mBh7T .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FFq9s9hY6R3mBh7T .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FFq9s9hY6R3mBh7T .marker.cross{stroke:#333333;}#mermaid-svg-FFq9s9hY6R3mBh7T svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FFq9s9hY6R3mBh7T p{margin:0;}#mermaid-svg-FFq9s9hY6R3mBh7T .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FFq9s9hY6R3mBh7T text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-FFq9s9hY6R3mBh7T .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-FFq9s9hY6R3mBh7T .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-FFq9s9hY6R3mBh7T .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-FFq9s9hY6R3mBh7T .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-FFq9s9hY6R3mBh7T #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-FFq9s9hY6R3mBh7T .sequenceNumber{fill:white;}#mermaid-svg-FFq9s9hY6R3mBh7T #sequencenumber{fill:#333;}#mermaid-svg-FFq9s9hY6R3mBh7T #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-FFq9s9hY6R3mBh7T .messageText{fill:#333;stroke:none;}#mermaid-svg-FFq9s9hY6R3mBh7T .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FFq9s9hY6R3mBh7T .labelText,#mermaid-svg-FFq9s9hY6R3mBh7T .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-FFq9s9hY6R3mBh7T .loopText,#mermaid-svg-FFq9s9hY6R3mBh7T .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-FFq9s9hY6R3mBh7T .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-FFq9s9hY6R3mBh7T .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-FFq9s9hY6R3mBh7T .noteText,#mermaid-svg-FFq9s9hY6R3mBh7T .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-FFq9s9hY6R3mBh7T .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FFq9s9hY6R3mBh7T .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FFq9s9hY6R3mBh7T .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-FFq9s9hY6R3mBh7T .actorPopupMenu{position:absolute;}#mermaid-svg-FFq9s9hY6R3mBh7T .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-FFq9s9hY6R3mBh7T .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-FFq9s9hY6R3mBh7T .actor-man circle,#mermaid-svg-FFq9s9hY6R3mBh7T line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-FFq9s9hY6R3mBh7T :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} DropResultEvent Generate story/comfort message story text Personalized Push

6.2 Staff 面试题

B11 · LLM 能否参与抽签决策?

要点
结论 绝对不能 ;LLM 只生成 中签后故事 / 未中签安抚 + 相似款推荐
验证 架构图抽签服务与 Story 服务无写边。
风险 合规模型暗示「提高中签率」→ 监管与品牌危机。

B12 · 异步生成的幂等与去重?

要点
结论 eventId 幂等;Redis SETNX story:{userId}:{dropId}
工程 失败进 DLQ 重试最多 3 次。
风险 重复 Push → 用户骚扰。

7. AI 选品助手(Buy Team · Assortment)

7.1 POC + 代码

java 复制代码
@Component
public class AssortmentTools {
    @Tool(description = "SKU 近28天销量增速")
    public VelocityDto getSalesVelocity(String skuId, String region) { ... }

    @Tool(description = "毛利率,只读")
    public MarginDto getMargin(String skuId) { ... }

    @Tool(description = "竞品价,只读")
    public CompetitorPriceDto getCompetitorPrice(String skuId) { ... }

    @Tool(description = "创建采购建议草稿,非正式 PO")
    public AssortmentDraftDto createAssortmentDraft(
            AssortmentDraftRequest req, String idempotencyKey) { ... }
}

#mermaid-svg-ensAkVmdqrHXYuil{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ensAkVmdqrHXYuil .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ensAkVmdqrHXYuil .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ensAkVmdqrHXYuil .error-icon{fill:#552222;}#mermaid-svg-ensAkVmdqrHXYuil .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ensAkVmdqrHXYuil .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ensAkVmdqrHXYuil .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ensAkVmdqrHXYuil .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ensAkVmdqrHXYuil .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ensAkVmdqrHXYuil .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ensAkVmdqrHXYuil .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ensAkVmdqrHXYuil .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ensAkVmdqrHXYuil .marker.cross{stroke:#333333;}#mermaid-svg-ensAkVmdqrHXYuil svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ensAkVmdqrHXYuil p{margin:0;}#mermaid-svg-ensAkVmdqrHXYuil .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ensAkVmdqrHXYuil .cluster-label text{fill:#333;}#mermaid-svg-ensAkVmdqrHXYuil .cluster-label span{color:#333;}#mermaid-svg-ensAkVmdqrHXYuil .cluster-label span p{background-color:transparent;}#mermaid-svg-ensAkVmdqrHXYuil .label text,#mermaid-svg-ensAkVmdqrHXYuil span{fill:#333;color:#333;}#mermaid-svg-ensAkVmdqrHXYuil .node rect,#mermaid-svg-ensAkVmdqrHXYuil .node circle,#mermaid-svg-ensAkVmdqrHXYuil .node ellipse,#mermaid-svg-ensAkVmdqrHXYuil .node polygon,#mermaid-svg-ensAkVmdqrHXYuil .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ensAkVmdqrHXYuil .rough-node .label text,#mermaid-svg-ensAkVmdqrHXYuil .node .label text,#mermaid-svg-ensAkVmdqrHXYuil .image-shape .label,#mermaid-svg-ensAkVmdqrHXYuil .icon-shape .label{text-anchor:middle;}#mermaid-svg-ensAkVmdqrHXYuil .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ensAkVmdqrHXYuil .rough-node .label,#mermaid-svg-ensAkVmdqrHXYuil .node .label,#mermaid-svg-ensAkVmdqrHXYuil .image-shape .label,#mermaid-svg-ensAkVmdqrHXYuil .icon-shape .label{text-align:center;}#mermaid-svg-ensAkVmdqrHXYuil .node.clickable{cursor:pointer;}#mermaid-svg-ensAkVmdqrHXYuil .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ensAkVmdqrHXYuil .arrowheadPath{fill:#333333;}#mermaid-svg-ensAkVmdqrHXYuil .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ensAkVmdqrHXYuil .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ensAkVmdqrHXYuil .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ensAkVmdqrHXYuil .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ensAkVmdqrHXYuil .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ensAkVmdqrHXYuil .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ensAkVmdqrHXYuil .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ensAkVmdqrHXYuil .cluster text{fill:#333;}#mermaid-svg-ensAkVmdqrHXYuil .cluster span{color:#333;}#mermaid-svg-ensAkVmdqrHXYuil div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ensAkVmdqrHXYuil .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ensAkVmdqrHXYuil rect.text{fill:none;stroke-width:0;}#mermaid-svg-ensAkVmdqrHXYuil .icon-shape,#mermaid-svg-ensAkVmdqrHXYuil .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ensAkVmdqrHXYuil .icon-shape p,#mermaid-svg-ensAkVmdqrHXYuil .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ensAkVmdqrHXYuil .icon-shape .label rect,#mermaid-svg-ensAkVmdqrHXYuil .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ensAkVmdqrHXYuil .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ensAkVmdqrHXYuil .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ensAkVmdqrHXYuil :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Merchandiser
Assortment Agent
Trend Report RAG
AssortmentTools
Data Warehouse
Draft Proposal
Buy Committee Approval

7.2 Staff 面试题

B13 · 选品 Agent 为什么是 Plan-Execute 而非 ReAct 无限循环?

要点
结论 买手任务步骤固定:取数→对比→草稿→人审;Plan 限 4--6 步可控。
工程 Java 状态机编排子步骤;每步 Tool 超时 10s。
风险 自主下单 → 供应链事故。

B14 · 区域 RBAC 如何在 RAG 体现?

要点
结论 metadata `region=APAC
验证 越权访问测试 100% 403。
风险 全球趋势泄露给单区买手 → 合规。

8. 库存调拨(WMS · HITL)

8.1 POC + 代码

java 复制代码
@Component
public class TransferTools {
    @Tool(description = "区域库存快照")
    public InventorySnapshotDto getInventorySnapshot(String skuId) { ... }

    @Tool(description = "创建调拨草稿,不写库存")
    public TransferDraftDto createTransferDraft(
            TransferDraftRequest req, String idempotencyKey) { ... }
}

8.2 Staff 面试题

B15 · 为何「工作流优先」而非全自动 Agent 调拨?

要点
结论 写库存副作用大;LLM 解释 + 草稿 ;WMS 审批后执行
工程 createTransferDraft 幂等;LLM 无 deductStock Tool。
验证 渗透测试无直写 API。
风险 Agent 自动调拨 → 错仓爆仓。

B16 · 调拨建议如何引用运输时效?

要点
结论 @Tool getTransitEta(fromDc,toDc) 只读;LLM 比较方案。
验证 建议 ETA 与 TMS 一致。
风险 LLM 估算物流天数 → 履约超时。

9. 定价 Copilot(HITL mandatory)

9.1 POC + 代码

java 复制代码
@Component
public class PricingTools {
    @Tool public CompetitorSnapshotDto getCompetitorPrices(String skuId) { ... }
    @Tool public SalesCurveDto getSalesCurve(String skuId, int days) { ... }

    @Tool(description = "提交调价审批单,不修改生效价")
    public PriceChangeRequestDto submitPriceChangeRequest(
            PriceChangeRequest req, String idempotencyKey) { ... }
}

9.2 Staff 面试题

B17 · 定价 Copilot 审批流如何与 LLM 解耦? → 见 98 C.102

B18 · 竞品数据延迟如何处理?

要点
结论 Tool 返回 dataAsOf;LLM 必须引用时间戳;过期数据触发人工标注。
验证 dataAsOf > 24h 时 UI 警告。
风险 静默用过期价 → 错误跟价。

10. 评价情感分析(UGC)

10.1 POC + 代码

java 复制代码
@Service
public class ReviewSentimentPipeline {
    private final ChatClient chatClient;

    @KafkaListener(topics = "ugc.review.created")
    public void onReview(ReviewEvent e) {
        ReviewInsight insight = chatClient.prompt()
            .system("输出 JSON: sentiment, issues[], severity, suggestedAction")
            .user(PiiMasker.mask(e.text()))
            .call()
            .entity(ReviewInsight.class);
        if (insight.severity() >= Severity.HIGH) {
            alertPublisher.publish(e.skuId(), insight);
        }
    }
}

10.2 Staff 面试题

B19 · 为何批处理 + 结构化输出而非在线 Chat?

要点
结论 UGC 量大;ReviewInsight POJO 入告警/工单;在线仅展示聚合标签。
工程 PII 正则脱敏进 prompt;不自动删评。
验证 负面 24h 触达率 >95%。
风险 LLM 自动删评 → 法律风险。

B20 · 虚假好评如何与 LLM 分工?

要点
结论 XGBoost/规则主判 ;LLM 生成 人审 reasoning
验证 recall >85% 离线集。
风险 LLM 单独封禁 → 误杀。

11. 营销活动 Multi-Agent

11.1 POC + 代码

java 复制代码
@Service
public class CampaignOrchestrator {
    private final ChatClient copyAgent;
    private final ChatClient audienceAgent;
    private final ChatClient complianceAgent;

    public CampaignPackage plan(CampaignBrief brief) {
        var audience = audienceAgent.prompt().user(brief.toAudiencePrompt()).call().entity(AudiencePlan.class);
        var copy = copyAgent.prompt().user(brief.toCopyPrompt(audience)).call().entity(CopyDraft.class);
        var verdict = complianceAgent.prompt().user(copy.toCompliancePrompt()).call().entity(ComplianceVerdict.class);
        if (!verdict.approved()) {
            throw new ComplianceRejectedException(verdict.reasons());
        }
        return new CampaignPackage(audience, copy, verdict);
    }
}

#mermaid-svg-3eq5SrZYO8gSlRxo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3eq5SrZYO8gSlRxo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3eq5SrZYO8gSlRxo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3eq5SrZYO8gSlRxo .error-icon{fill:#552222;}#mermaid-svg-3eq5SrZYO8gSlRxo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3eq5SrZYO8gSlRxo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3eq5SrZYO8gSlRxo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3eq5SrZYO8gSlRxo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3eq5SrZYO8gSlRxo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3eq5SrZYO8gSlRxo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3eq5SrZYO8gSlRxo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3eq5SrZYO8gSlRxo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3eq5SrZYO8gSlRxo .marker.cross{stroke:#333333;}#mermaid-svg-3eq5SrZYO8gSlRxo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3eq5SrZYO8gSlRxo p{margin:0;}#mermaid-svg-3eq5SrZYO8gSlRxo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-3eq5SrZYO8gSlRxo .cluster-label text{fill:#333;}#mermaid-svg-3eq5SrZYO8gSlRxo .cluster-label span{color:#333;}#mermaid-svg-3eq5SrZYO8gSlRxo .cluster-label span p{background-color:transparent;}#mermaid-svg-3eq5SrZYO8gSlRxo .label text,#mermaid-svg-3eq5SrZYO8gSlRxo span{fill:#333;color:#333;}#mermaid-svg-3eq5SrZYO8gSlRxo .node rect,#mermaid-svg-3eq5SrZYO8gSlRxo .node circle,#mermaid-svg-3eq5SrZYO8gSlRxo .node ellipse,#mermaid-svg-3eq5SrZYO8gSlRxo .node polygon,#mermaid-svg-3eq5SrZYO8gSlRxo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3eq5SrZYO8gSlRxo .rough-node .label text,#mermaid-svg-3eq5SrZYO8gSlRxo .node .label text,#mermaid-svg-3eq5SrZYO8gSlRxo .image-shape .label,#mermaid-svg-3eq5SrZYO8gSlRxo .icon-shape .label{text-anchor:middle;}#mermaid-svg-3eq5SrZYO8gSlRxo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3eq5SrZYO8gSlRxo .rough-node .label,#mermaid-svg-3eq5SrZYO8gSlRxo .node .label,#mermaid-svg-3eq5SrZYO8gSlRxo .image-shape .label,#mermaid-svg-3eq5SrZYO8gSlRxo .icon-shape .label{text-align:center;}#mermaid-svg-3eq5SrZYO8gSlRxo .node.clickable{cursor:pointer;}#mermaid-svg-3eq5SrZYO8gSlRxo .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3eq5SrZYO8gSlRxo .arrowheadPath{fill:#333333;}#mermaid-svg-3eq5SrZYO8gSlRxo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3eq5SrZYO8gSlRxo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3eq5SrZYO8gSlRxo .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3eq5SrZYO8gSlRxo .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3eq5SrZYO8gSlRxo .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3eq5SrZYO8gSlRxo .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3eq5SrZYO8gSlRxo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3eq5SrZYO8gSlRxo .cluster text{fill:#333;}#mermaid-svg-3eq5SrZYO8gSlRxo .cluster span{color:#333;}#mermaid-svg-3eq5SrZYO8gSlRxo div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3eq5SrZYO8gSlRxo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3eq5SrZYO8gSlRxo rect.text{fill:none;stroke-width:0;}#mermaid-svg-3eq5SrZYO8gSlRxo .icon-shape,#mermaid-svg-3eq5SrZYO8gSlRxo .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3eq5SrZYO8gSlRxo .icon-shape p,#mermaid-svg-3eq5SrZYO8gSlRxo .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3eq5SrZYO8gSlRxo .icon-shape .label rect,#mermaid-svg-3eq5SrZYO8gSlRxo .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3eq5SrZYO8gSlRxo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3eq5SrZYO8gSlRxo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3eq5SrZYO8gSlRxo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Rejected
Approved
Campaign Brief
Orchestrator
Audience Agent
Copy Agent
Compliance Agent
Terminate
MA Delivery

11.2 Staff 面试题

B21 · 合规 Agent 一票否决如何工程保证?

要点
结论 ComplianceVerdict.approved==false不调用 MA 写接口;编排器硬编码。
验证 红队敏感词 100% 拦截。
风险 仅 prompt 约束无代码分支 → 漏发。

B22 · Token 预算熔断?

要点
结论 LiteLLM daily-usd-cap + 应用侧 campaignId 计数器。
工程 超 85% 告警,100% 拒绝新任务。
风险 无限生成文案 → FinOps 爆炸。

12. 反欺诈 / 黄牛(SNKRS)

12.1 POC + 代码

java 复制代码
@Component
public class AntiFraudTools {
    @Tool(description = "规则+模型风险分,只读")
    public RiskScoreDto getRiskScore(String orderId) { ... }

    @Tool(description = "生成人审说明,不执行拦截")
    public String explainRisk(RiskScoreDto score) { ... }
}

@Service
public class FraudReviewService {
    public FraudReviewNote review(String orderId) {
        var score = antiFraudTools.getRiskScore(orderId);
        if (score.decision() == Decision.BLOCK) {
            return FraudReviewNote.blocked(
                chatClient.prompt()
                    .user("根据分数生成人审理由: " + score)
                    .call()
                    .content());
        }
        return FraudReviewNote.pass();
    }
}

12.2 Staff 面试题

B23 · LLM 在风控链路中的正确位置?

要点
结论 毫秒级规则+ML 决策 ;LLM 仅解释 复杂案;不单独拒单
验证 压测主路径无 LLM 调用。
风险 LLM 拒单 → 延迟与不可解释。

B24 · 误杀申诉如何闭环?

要点
结论 申诉 → 人工 → 反馈入特征库;LLM 不参与改判自动生效。
指标 误杀率 <0.5%。
风险 无申诉 → 品牌舆情。

13. Carts 智能加车

完整代码见 08 §10.13

13.1 Staff 面试题

B25 · 三 Tool 分步必要性? → 98 C.104

B26 · Member/门店上下文如何注入?

要点
结论 userIdMemberProfile Tool;storeId 默认最近门店或显式参数。
工程 JWT 解析后注入 ToolContext,禁止用户伪造 storeId 越权。
验证 跨店库存测试。
风险 忽略门店 ATP → 下单失败。

14. Payment 智能推荐付款方式

完整代码见 08 §10.14

14.1 Staff 面试题

B27 · rank Tool 与 list Tool 为何要拆开?

要点
结论 list 返回 可用全集+维护态rank 在子集上 规则排序;LLM 不合并以防编造不可用渠道。
验证 KLARNA 地区不支持时必须在 unavailable
风险 单 Tool 返回「推荐 PayPal」但已维护 → 结账失败。

B28 · Vault token 如何出现在 Tool 响应?

要点
结论 VISA_TOKEN_***12 掩码;永不返回 PAN/CVV
工程 PaymentComplianceAdvisor 扫日志。
风险 调试日志打全卡号 → PCI 违规。

§99 全场景 Master Checklist + 面试索引

99.1 上线前 42 项(Buy 域)

检查项
模型 LiteLLM 主路径 + Azure fallback 熔断演练
模型 commerce-fast / commerce-smart 别名与 SLA 对齐
向量 L1 Redis / L2 pgvector / L3 Milvus 职责清晰
向量 embedding 版本 pin + 漂移 CI
交易 金额/库存/券/价/支付 仅 Tool
交易 Carts addLineItem 幂等
交易 Payment 无 PAN 出网
交易 满减 explanation 无裸数字
写操作 退款/调拨/定价 Draft + HITL
写操作 所有写 Tool 带 idempotencyKey
Agent maxIterations=5
Agent 抽签/风控 LLM 不决策
安全 SafeGuard + Llama Guard
安全 敏感词转人工
观测 Langfuse trace + $/successful_task
观测 分 scene 成本归因
Eval 每场景 ≥50 golden + 红队集
合规 审计 7 年;PII 脱敏

99.2 面试题速查(B01--B28 ↔ 98)

场景 本书 98 联动
导购 B01--B02 C.101
客服 B03--B04 C.99, C.103
商品分析 B05--B06 C.111--C.112
搭配 B07--B08 C.113--C.114
满减 B09--B10 C.100, C.106
发售故事 B11--B12 C.115--C.116
选品 B13--B14 C.117--C.118
调拨 B15--B16 C.119--C.120
定价 B17--B18 C.102
评价 B19--B20 C.121--C.122
营销 B21--B22 ---
反欺诈 B23--B24 ---
Carts B25--B26 C.104--C.105
Payment B27--B28 C.107

关联文件

文件 用途
08-架构-电商 场景总览 + 部分 Demo
14-Spring-AI 框架/MCP/多 VectorStore
98-冲刺 口述题库 C.98--C.122
13-Playbook 12 能力域生产规范

一句话 :Buy 域智能化 = LiteLLM + Spring AI Tool 真源 + 三层向量 + 写操作 HITL ;14 场景代码骨架在本文,考前 B01--B28 + 98 C 段 交替口述。

官方文档与源码(一级依据)

AI Engineering · 正文机制应来自下方 官方文档(L1)官方源码仓库(L2)

禁止用教程站/博客充当机制依据。本章 QPS/延迟/STAR 为面试示意。

写作规范:docs/official-sources-registry.md §0

L1 · 官方文档

L2 · 官方源码

L3 · 论文 / 开放规范

相关推荐
不想吃饭e1 小时前
uniapp-图片,视频上传组件封装
java·uni-app·音视频
段一凡-华北理工大学1 小时前
工业领域的Hadoop架构学习~系列文章15:机器学习与大数据融合 - 工业智能的算法引擎
大数据·人工智能·hadoop·机器学习·架构·工业智能体·高炉炼铁智能化
一次旅行1 小时前
AI技术热点简报
人工智能
一楼的猫1 小时前
AI辅助长篇小说创作的“记忆崩坏“问题与结构管理策略
人工智能·学习·机器学习·chatgpt·ai作画·ai写作
迷藏4941 小时前
双阶段动态权重匹配系统:高效精准的工业级解决方案
java·junit
happyprince1 小时前
15-Hugging Face Transformers之CLI 与工具架构总览
人工智能
开源推荐官1 小时前
2026 三大国产优质开源商城深度测评:VortMall、Tigshop、Jinor 选型全解析
java·开源
下班走回家1 小时前
一家教培机构在AI搜索里“消失“之后:GEO优化的技术复盘
人工智能·geo
We Just Keep growing1 小时前
【MySQL运维篇】——日志、主从复制、分库分表、读写分离
java·运维·数据库·windows·学习·mysql