Spring AI 1.x 系列【52】可观测集成 SkyWalking

1. 概述

本文档从零开始,在一个 Spring Boot + Spring AI 项目中实现完整的可观测性体系------将 Tracing(链路追踪)、Metrics(指标)、Logging(日志)通过 OpenTelemetry 协议统一导出到 Apache SkyWalking

实现路径:Micrometer ObservationOTel BridgeOTLP gRPC ExporterSkyWalking OAP

1.1 上报流程

SkyWalking 支持的多种数据上报方式,常用的有:

  • Java Agent:通过 -javaagent:skywalking-agent.jar 实现,零代码、零依赖、自动埋点、性能最好。
  • OpenTelemetry OTLP:云原生标准,可对接不同类型的监控平台。

Spring 官方支持 Micrometer + OTLP 上报方案,完整数据流:
#mermaid-svg-jFX0dMEAIBRcLV9H{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-jFX0dMEAIBRcLV9H .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jFX0dMEAIBRcLV9H .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jFX0dMEAIBRcLV9H .error-icon{fill:#552222;}#mermaid-svg-jFX0dMEAIBRcLV9H .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jFX0dMEAIBRcLV9H .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jFX0dMEAIBRcLV9H .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jFX0dMEAIBRcLV9H .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jFX0dMEAIBRcLV9H .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jFX0dMEAIBRcLV9H .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jFX0dMEAIBRcLV9H .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jFX0dMEAIBRcLV9H .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jFX0dMEAIBRcLV9H .marker.cross{stroke:#333333;}#mermaid-svg-jFX0dMEAIBRcLV9H svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jFX0dMEAIBRcLV9H p{margin:0;}#mermaid-svg-jFX0dMEAIBRcLV9H .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jFX0dMEAIBRcLV9H .cluster-label text{fill:#333;}#mermaid-svg-jFX0dMEAIBRcLV9H .cluster-label span{color:#333;}#mermaid-svg-jFX0dMEAIBRcLV9H .cluster-label span p{background-color:transparent;}#mermaid-svg-jFX0dMEAIBRcLV9H .label text,#mermaid-svg-jFX0dMEAIBRcLV9H span{fill:#333;color:#333;}#mermaid-svg-jFX0dMEAIBRcLV9H .node rect,#mermaid-svg-jFX0dMEAIBRcLV9H .node circle,#mermaid-svg-jFX0dMEAIBRcLV9H .node ellipse,#mermaid-svg-jFX0dMEAIBRcLV9H .node polygon,#mermaid-svg-jFX0dMEAIBRcLV9H .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jFX0dMEAIBRcLV9H .rough-node .label text,#mermaid-svg-jFX0dMEAIBRcLV9H .node .label text,#mermaid-svg-jFX0dMEAIBRcLV9H .image-shape .label,#mermaid-svg-jFX0dMEAIBRcLV9H .icon-shape .label{text-anchor:middle;}#mermaid-svg-jFX0dMEAIBRcLV9H .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jFX0dMEAIBRcLV9H .rough-node .label,#mermaid-svg-jFX0dMEAIBRcLV9H .node .label,#mermaid-svg-jFX0dMEAIBRcLV9H .image-shape .label,#mermaid-svg-jFX0dMEAIBRcLV9H .icon-shape .label{text-align:center;}#mermaid-svg-jFX0dMEAIBRcLV9H .node.clickable{cursor:pointer;}#mermaid-svg-jFX0dMEAIBRcLV9H .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jFX0dMEAIBRcLV9H .arrowheadPath{fill:#333333;}#mermaid-svg-jFX0dMEAIBRcLV9H .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jFX0dMEAIBRcLV9H .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jFX0dMEAIBRcLV9H .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jFX0dMEAIBRcLV9H .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jFX0dMEAIBRcLV9H .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jFX0dMEAIBRcLV9H .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jFX0dMEAIBRcLV9H .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jFX0dMEAIBRcLV9H .cluster text{fill:#333;}#mermaid-svg-jFX0dMEAIBRcLV9H .cluster span{color:#333;}#mermaid-svg-jFX0dMEAIBRcLV9H 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-jFX0dMEAIBRcLV9H .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jFX0dMEAIBRcLV9H rect.text{fill:none;stroke-width:0;}#mermaid-svg-jFX0dMEAIBRcLV9H .icon-shape,#mermaid-svg-jFX0dMEAIBRcLV9H .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jFX0dMEAIBRcLV9H .icon-shape p,#mermaid-svg-jFX0dMEAIBRcLV9H .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jFX0dMEAIBRcLV9H .icon-shape .label rect,#mermaid-svg-jFX0dMEAIBRcLV9H .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jFX0dMEAIBRcLV9H .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jFX0dMEAIBRcLV9H .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jFX0dMEAIBRcLV9H :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Storage
OTLP HTTP:4318 上报Trace/gen_ai指标/日志
依据otel-rules配置+MAL解析指标
HTTP查询 OAP:12800
查询存储返回数据
SpringBoot + SpringAI

集成OpenTelemetry
SkyWalking OAP
持久化存储
BanyanDB:17912
ElasticSearch:9200
Booster UI:8080
可视化展示

链路详情 + GenAI指标 + 服务监控大盘

流程说明:

  1. SpringAI 应用通过 OTLP 采集大模型调用链路、Token、耗时gen_ai_*指标
  2. 使用 OTLP 协议 (4318) 推送至 OAP
  3. OAP 加载 otel-rules 规则文件解析指标,存入 BanyanDB/ES
  4. BoosterUI 通过 12800 端口请求 OAP 查询数据
  5. OAP 读取存储数据,UI 渲染监控图表

1.2 环境信息

组件 版本
Spring Boot 3.5.11
Spring AI 1.1.4
Micrometer Tracing Spring Boot 管理
OpenTelemetry Spring Boot 管理
SkyWalking OAP 10.x
传输协议 OTLP gRPC

2. 依赖配置

2.1 Maven 依赖

接入 OTLP 依赖清单:

xml 复制代码
<!-- 1. Spring Boot Actuator:监控基础设施 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- 2. Micrometer Tracing 核心 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing</artifactId>
</dependency>

<!-- 3. Micrometer → OpenTelemetry 桥接 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>

<!-- 4. Micrometer OTLP Registry:Metrics 通过 OTLP 导出 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-otlp</artifactId>
</dependency>

<!-- 5. OTel OTLP Exporter:Tracing 通过 OTLP 导出 -->
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>

<!-- 6. OTel Logback Appender:应用日志通过 OTLP 导出 -->
<dependency>
    <groupId>io.opentelemetry.instrumentation</groupId>
    <artifactId>opentelemetry-logback-appender-1.0</artifactId>
    <version>2.14.0-alpha</version>
</dependency>

依赖关系图:

复制代码
micrometer-tracing (核心 API)
    │
    ├── micrometer-tracing-bridge-otel (Micrometer → OTel)
    │       │
    │       └── opentelemetry-exporter-otlp (OTLP 导出)
    │
    └── micrometer-registry-otlp (Metrics OTLP 导出)

opentelemetry-logback-appender-1.0 (Logback → OTLP)

3. 配置文件

3.1 application.yml --- 可观测性配置

配置说明:

  • log-prompt/log-completion 等高敏感字段默认 false,开启会把 Prompt 存入 Span,存在隐私泄露风险。
  • Metrics 暂不开启:Spring Boot 只支持 HTTP 上报,SkyWalking 10.x 版本又只支持 PRC

11.x 版本说明:

yaml 复制代码
# ==================== Spring Boot Actuator 可观测性配置 ====================
management:
  endpoints:
    web:
      base-path: /actuator
      exposure:
        include: '*'                          # 暴露所有端点
  tracing:
    enabled: true
    sampling:
      probability: 1.0                       # 全量采样(生产环境建议 0.1)
  otlp:
    tracing:
      endpoint: http://192.168.1.235:4319
      transport: grpc
      export:
        enabled: true
    metrics:
      export:
        url: http://192.168.1.235:12800/v1/metrics
        enabled: false                        # Metrics 暂不开启
    logging:
      endpoint: http://192.168.1.235:4319
      transport: grpc
      export:
        enabled: true

# ==================== Spring AI 观测配置 ====================
spring:
  ai:
    chat:
      observations:
        include-error-logging: true           # 错误时记录日志
        log-completion: true                  # 记录模型回答内容
        log-prompt: true                      # 记录 Prompt 内容
      client:
        enabled: true
        observations:
          log-prompt: true
          log-completion: true

# ==================== 日志级别 ====================
logging:
  level:
    io.opentelemetry.exporter.otlp: TRACE
    io.opentelemetry.instrumentation.logback: TRACE
    io.opentelemetry.sdk.logs: TRACE
    io.micrometer.tracing: DEBUG
    io.micrometer.registry.otlp: DEBUG

3.2 logback-spring.xml --- Logback OTLP Appender

关键点:

  • %X{traceId:-}%X{spanId:-}MDC 中提取当前 Span 信息,实现日志与 Trace 的关联
  • OpenTelemetryAppender 将日志异步导出到 OTLP 端点,与 application.yml 中配置的地址一致
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 控制台输出格式:包含 traceId 和 spanId -->
    <property name="CONSOLE_LOG_PATTERN"
        value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId:-}][%X{spanId:-}] %-5level %logger{50} - %msg%n"/>

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- OTLP Appender:将日志通过 gRPC 上报到 SkyWalking OAP -->
    <appender name="OTLP" class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender">
        <captureExperimentalAttributes>true</captureExperimentalAttributes>
        <captureCodeAttributes>true</captureCodeAttributes>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="OTLP"/>
    </root>
</configuration>

4. Java 代码实现

4.1 OtlpLoggingConfig --- 激活 Logback Appender

OpenTelemetryAppender 需要一个已初始化的 OpenTelemetry 实例才能工作。Spring Boot 自动装配了 OpenTelemetry Bean,但 Appender 默认无法获取。此配置类在启动时完成桥接:

java 复制代码
@Component
public class OtlpLoggingConfig implements InitializingBean {

    private final OpenTelemetry openTelemetry;

    public OtlpLoggingConfig(OpenTelemetry openTelemetry) {
        this.openTelemetry = openTelemetry;
    }

    @Override
    public void afterPropertiesSet() {
        // 将 Spring Boot 自动装配的 OpenTelemetry 实例
        // 注入到 Logback 的 OpenTelemetryAppender 中
        OpenTelemetryAppender.install(openTelemetry);
    }
}

如果不做这一步,OpenTelemetryAppender 会使用默认的空 OpenTelemetry 实例,日志不会真正被导出。

4.2 自定义 ObservationConvention --- 富化 Span 内容

默认的 DefaultChatModelObservationConvention 只记录参数(temperaturemaxTokens 等),不记录 Prompt 和回答的文本内容。通过继承它可以添加业务关心的数据。

4.2.1 ChatModel 观测约定

java 复制代码
public class ContentEnrichedChatModelObservationConvention
        extends DefaultChatModelObservationConvention {

    private static final int MAX_CONTENT_LENGTH = 1024;

    @Override
    public KeyValues getHighCardinalityKeyValues(ChatModelObservationContext context) {
        // ① 先拿到父类所有的默认 KeyValues(temperature、token 用量等)
        KeyValues keyValues = super.getHighCardinalityKeyValues(context);

        // ② 追加 Prompt 内容(截断以防止 Span 过大)
        keyValues = appendPromptContent(keyValues, context);

        // ③ 追加模型回答内容
        keyValues = appendCompletionContent(keyValues, context);

        return keyValues;
    }

    private KeyValues appendPromptContent(KeyValues keyValues,
            ChatModelObservationContext context) {
        String content = context.getRequest().getInstructions()
                .stream()
                .map(Content::getText)
                .collect(Collectors.joining("\n"));
        return keyValues.and("gen_ai.prompt.content",
                truncate(content, MAX_CONTENT_LENGTH));
    }

    private KeyValues appendCompletionContent(KeyValues keyValues,
            ChatModelObservationContext context) {
        if (context.getResponse() == null) {
            return keyValues;
        }
        String content = context.getResponse().getResults()
                .stream()
                .map(g -> g.getOutput().getText())
                .collect(Collectors.joining("\n"));
        return keyValues.and("gen_ai.completion.content",
                truncate(content, MAX_CONTENT_LENGTH));
    }

    private String truncate(String text, int maxLen) {
        if (text == null) return "";
        return text.length() <= maxLen ? text
                : text.substring(0, maxLen) + "...[truncated]";
    }
}

4.2.2 ChatClient 观测约定

ChatClient 有自己独立的 ObservationContext,需单独扩展:

java 复制代码
public class ContentEnrichedChatClientObservationConvention
        extends DefaultChatClientObservationConvention {

    private static final int MAX_CONTENT_LENGTH = 1024;

    @Override
    public KeyValues getHighCardinalityKeyValues(ChatClientObservationContext context) {
        KeyValues keyValues = super.getHighCardinalityKeyValues(context);
        keyValues = appendPromptContent(keyValues, context);
        keyValues = appendCompletionContent(keyValues, context);
        return keyValues;
    }

    // ... 实现逻辑与 ChatModel 版本相同,操作 ChatClientObservationContext
}

4.2.3 注册自定义约定

java 复制代码
@Configuration
public class ChatClientConfig {

    // 替换默认 ChatModel 观测约定
    @Bean
    public ChatModelObservationConvention chatModelObservationConvention() {
        return new ContentEnrichedChatModelObservationConvention();
    }

    // 替换默认 ChatClient 观测约定
    @Bean
    public ChatClientObservationConvention chatClientObservationConvention() {
        return new ContentEnrichedChatClientObservationConvention();
    }
}

4.3 ChatController --- 手动创建 Observation 示例

除了框架自动创建的 ChatModel / ChatClient Span,业务代码也可以手动创建自定义 Observation

java 复制代码
@RestController
@RequestMapping("/chat")
public class ChatController {

    private final ChatClient chatClient;
    private final ObservationRegistry observationRegistry;

    public ChatController(ChatClient chatClient,
            ObservationRegistry observationRegistry) {
        this.chatClient = chatClient;
        this.observationRegistry = observationRegistry;
    }

    @GetMapping
    public String chat(@RequestParam String message) {
        // 框架自动创建 ChatClient Span(透明)
        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }

    public void doSomething() {
        // 手动创建自定义 Span
        Observation observation = Observation.createNotStarted(
                "custom.operation", this.observationRegistry);

        observation.lowCardinalityKeyValue("locale", "en-US");
        observation.highCardinalityKeyValue("userId", "42");

        observation.observe(() -> {
            // 此代码块的执行耗时和状态会被记录
            performBusinessLogic();
        });
    }
}

5. 数据流转路径

5.1 整体数据流

复制代码
┌──────────────────────────────────────────────────┐
│              Spring AI Application               │
│                                                  │
│  ┌──────────────┐  ┌──────────────┐              │
│  │ ChatModel    │  │ Custom       │              │
│  │ Observation  │  │ Observation  │              │
│  │ (自动创建)   │  │ (手动创建)   │              │
│  └──────┬───────┘  └──────┬───────┘              │
│         │                 │                      │
│  ┌──────▼─────────────────▼───────┐              │
│  │     Micrometer Observation     │              │
│  │   (统一 API,不感知后端)        │              │
│  └──────────────┬─────────────────┘              │
│                 │                                │
│  ┌──────────────▼─────────────────┐              │
│  │  micrometer-tracing-bridge-otel │             │
│  │  (Micrometer → OTel 格式转换)   │             │
│  └──────────────┬─────────────────┘              │
│                 │                                │
│         ┌───────┴───────┐                        │
│         │               │                        │
│  ┌──────▼──────┐ ┌──────▼──────────┐            │
│  │ OTLP Trace  │ │ Logback OTLP    │            │
│  │ Exporter    │ │ Appender        │            │
│  │ (gRPC)      │ │ (gRPC)          │            │
│  └──────┬──────┘ └──────┬──────────┘            │
└─────────┼───────────────┼────────────────────────┘
          │               │
    ┌─────▼───────────────▼─────┐
    │    SkyWalking OAP         │
    │    (192.168.1.235:4319)   │
    │                           │
    │  ┌─────────────────────┐  │
    │  │  Traces + Logs 关联  │  │
    │  └─────────────────────┘  │
    └───────────────────────────┘

5.2 关键技术点

环节 组件 作用
埋点 Micrometer Observation 统一 API,ChatModel/ChatClient 自动埋点
格式转换 micrometer-tracing-bridge-otel Micrometer SpanOTel Span
Trace 导出 opentelemetry-exporter-otlp OTLP gRPCSkyWalking OAP
日志导出 OpenTelemetryAppender Logback 日志 → OTLP gRPCSkyWalking OAP
日志关联 %X{traceId} / %X{spanId} MDC 自动注入当前 Span 信息
内容富化 自定义 ObservationConvention 添加 gen_ai.prompt.content 等业务 Tag

6. 接入步骤总结

6.1 最小接入清单

步骤 文件 操作
1 pom.xml 添加 6 个依赖
2 application.yml 配置 otel + management.otlp + spring.ai.chat.observations
3 logback-spring.xml 添加 OpenTelemetryAppender + traceId/spanId 格式
4 OtlpLoggingConfig.java OpenTelemetryAppender.install(openTelemetry)
5 自定义 ObservationConvention 继承默认实现,添加业务 Key(可选)

6.2 验证方法

bash 复制代码
# 1. 启动应用
mvn spring-boot:run -pl ai-chat-demo

# 2. 请求接口,产生 Span
curl "http://localhost:8080/chat?message=hello"

# 3. 检查控制台日志是否包含 traceId
# 输出示例:
# 2026-06-08 10:30:00.123 [http-nio-8080-exec-1] [abc123][def456] INFO  ... - ...

# 4. 在 SkyWalking UI 中查看
# - 链路追踪:查看 gen_ai.client.operation Span
# - 日志关联:点击 Span 可见关联的日志内容
# - 自定义 Tag:gen_ai.prompt.content / gen_ai.completion.content

AI 相关指标(SkyWalking 从链路数据中主动解析的):

日志:

链路需要通过 http://192.168.1.1:8080/zipkin 查询:

6.3 生产环境调优建议

配置项 开发环境 生产环境
sampling.probability 1.0 0.1 ~ 0.3
MAX_CONTENT_LENGTH 1024 256 ~ 512
OTel 日志级别 TRACE / DEBUG WARN
log-completion / log-prompt true false(避免日志过大)

7. 关键设计模式

7.1 埋点与后端解耦

复制代码
业务代码 → Micrometer Observation API (稳定)
              │
              ├── Bridge A → OTel → SkyWalking
              ├── Bridge B → OTel → Jaeger
              └── Bridge C → Brave → Zipkin

应用层代码只依赖 Micrometer Observation API,后端存储(SkyWalking / Jaeger / Zipkin)通过更换 Bridge 即可切换,无需改动业务代码。

7.2 Convention 扩展模式

复制代码
DefaultChatModelObservationConvention
    │ 提供 17 个默认 KeyValue(参数 + 用量)
    │
    └── ContentEnrichedChatModelObservationConvention
         │ 追加 gen_ai.prompt.content
         │ 追加 gen_ai.completion.content

通过继承而非修改来扩展,调用 super.getHighCardinalityKeyValues() 保留框架默认行为,仅追加自定义数据。

7.3 日志与 Trace 的关联

不是通过配置文件中的固定规则关联,而是通过 MDC 的实时注入:

复制代码
请求到达 → Micrometer 创建 Span → traceId/spanId 写入 MDC
                                         │
                        Logback %X{traceId:-} 从 MDC 读取
                                         │
                        日志携带 traceId → OTLP Appender 导出
                                         │
                        SkyWalking 按 traceId 自动关联日志与 Span

这一切是自动的 ------开发者不需要在代码中手动传递 traceId

相关推荐
云烟成雨TD43 分钟前
Spring AI 1.x 系列【57】动态工具发现:Tool Search Tool
java·人工智能·spring
AndrewHZ44 分钟前
【LLM技术全景】规模定律与模型演进:为什么模型越大越强?
人工智能·gpt·深度学习·语言模型·llm·openai·规模定律
galaxylove44 分钟前
Gartner发布创新洞察:AI SOC智能体加速通信运营商安全运营转型
大数据·人工智能·安全
甩手网软件1 小时前
Shopee2026新规:费率重构与履约收紧下,卖家如何破局?
大数据·人工智能
数据库小学妹1 小时前
AI时代数据库怎么选?多模融合、数据统一存储与选型实战指南
数据库·人工智能·经验分享·ai
lizhihai_991 小时前
股市学习心得-AI 产业链核心标的梳理清单
大数据·服务器·人工智能·科技·学习
暮雪倾风1 小时前
【AI】国内使用Claude Code,配置Claude Code,使用DeepSeek为例
人工智能
FrameNotWork1 小时前
HarmonyOS6.1 AI 模型管理架构设计与最佳实践
人工智能·harmonyos
没事别瞎琢磨1 小时前
十、统一 Runner 入口——能力检测与模式回退
人工智能·node.js