Java转AI Agent教程(第一周)让模型先跑起来

W1 教程 · 让模型先跑起来

对应计划表:阶段 A 地基,第 1 周。主块 4 小时 + 轻任务 2×1 小时。

本教程所有代码已在 JDK 17.0.18 + Maven 3.8.5 + LangChain4j 1.22.0 上实际编译、运行、并用假网关端到端验证通过。

配套可运行工程在 ecom-agent-lab/,bash selfcheck-w1.sh 可一键自测(不花钱)。


0. 本周你要交付什么

一句话:用 Java 调通一次公司模型网关,并把 20 次调用的 token / 耗时 / 成本记成一张表。

不是"搭一个智能助手",不是"封装框架"。就是调通 + 记账。

验收标准(自己判卷):

  • 一条命令能发出请求并打印模型回复
  • CSV 里有 20 条记录,每条含:时间、输入 token、输出 token、耗时(ms)、成本
  • 能不看文档说清"1 万 token 大概多少钱"(自己算的,不是背的)
  • API Key 从环境变量读取,代码和 Git 里都搜不到

为什么第 1 周不写工程代码? 因为你要先建立"模型是有成本、有延迟、会失败的东西"这个直觉。周报写"本周学习了 LLM 基础",面试官毫无感觉;写"实测某模型 1 万 token 输入约 0.02 元,平均单次耗时 1.3 秒,输出长度方差很大",他知道你真跑过。


1. 环境准备(30 分钟)

1.1 你需要什么

项 要求 检查命令
JDK 17 或以上(LangChain4j 最低要求就是 17) java -version
Maven 3.6+ mvn -v
模型网关 地址 + 鉴权方式 + 可用模型名 问公司平台组

LangChain4j 官方文档原文:"The minimum supported JDK version is 17." 若公司老项目还在 JDK 8/11,这个练习工程单独用 17,别动生产项目。

1.2 环境变量(关键,别跳过)

Windows PowerShell(当前会话有效):

powershell 复制代码
$env:LLM_BASE_URL = "https://your-gateway.company.com/v1"
$env:LLM_API_KEY  = "网关分发给你的令牌"
$env:LLM_MODEL    = "网关支持的模型名"
$env:LLM_PRICE_IN = "2"      # 输入单价,单位:元/百万 token(向网关索取)
$env:LLM_PRICE_OUT= "8"      # 输出单价,单位:元/百万 token

Windows 永久生效(新开终端才读到,如果是IDEA,需要重启IDEA):

powershell 复制代码
[Environment]::SetEnvironmentVariable("LLM_BASE_URL","https://your-gateway.company.com/v1","User")
[Environment]::SetEnvironmentVariable("LLM_API_KEY","你的令牌","User")
[Environment]::SetEnvironmentVariable("LLM_MODEL","模型名","User")
[Environment]::SetEnvironmentVariable("LLM_PRICE_IN","2","User")
[Environment]::SetEnvironmentVariable("LLM_PRICE_OUT","8","User")

macOS / Linux:

bash 复制代码
export LLM_BASE_URL="https://your-gateway.company.com/v1"
export LLM_API_KEY="你的令牌"
export LLM_MODEL="模型名"
export LLM_PRICE_IN="2"
export LLM_PRICE_OUT="8"

四条硬规矩:

  1. 不要把 Key 写进 application.yml 并提交到 Git。这是安全事故,不是洁癖。
  2. 截图、发求助消息时,Key 必须打码。
  3. 单价也不要硬编进代码------网关调价那天你不希望重新发版。
  4. 如果网关令牌需要审批,今天就去提流程。这是唯一可能卡你一周的事。

1.3 网关适配性探测(本周最重要的一步)

公司网关通常有三种形态,处理方式完全不同:

形态 特征 你的做法
A. OpenAI 兼容 路径 /v1/chat/completions,请求体 {"model","messages"} 最省事,本教程代码直接可用
B. 自家协议 路径、字段名都不同,如 /api/invoke、{"prompt":...} 不能直接用 OpenAI 客户端,需自封装(W2 给完整方案)
C. 需二次鉴权 除 Bearer 还要签名头 / 租户 ID / AppId 用 customHeaders 加,见下方代码

先拿 curl 试,别直接写 Java:

bash 复制代码
curl -i -X POST "$LLM_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $LLM_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"model\":\"$LLM_MODEL\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}"

看三件事:

  • 200 且返回 choices[0].message.content → 形态 A,继续
  • 404 → 路径不对,依次试 /v1/chat/completions、/chat/completions、/v1/completions
  • 401/403 → 鉴权方式不对,问网关文档要 header 格式

形态 C 的自定义请求头 (LangChain4j 1.22.0 支持,customHeaders 接一个 Supplier<Map<String,String>>):

java 复制代码
import java.util.Map;

OpenAiChatModel.builder()
    .baseUrl(baseUrl)
    .apiKey(apiKey)
    .modelName(modelName)
    .customHeaders(() -> Map.of(
        "X-Tenant-Id", System.getenv("LLM_TENANT_ID"),
        "X-App-Id", System.getenv("LLM_APP_ID")))
    .build();

若网关是形态 B(完全不是 OpenAI 协议),不要硬 hack 。W2 会给一套纯 java.net.http.HttpClient 的自封装方案,对任何协议都适用。


2. 建工程(15 分钟)

bash 复制代码
mkdir ecom-agent-lab && cd ecom-agent-lab

pom.xml ------ 完整内容,可直接复制(版本组合已实测通过):

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.company</groupId>
  <artifactId>ecom-agent-lab</artifactId>
  <version>0.1.0-SNAPSHOT</version>

  <properties>
    <maven.compiler.release>17</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <langchain4j.version>1.22.0</langchain4j.version>
    <jackson.version>2.17.2</jackson.version>
    <slf4j.version>2.0.18</slf4j.version>
  </properties>

  <dependencies>
    <!-- LangChain4j 的 OpenAI 协议实现:公司网关只要是 OpenAI 兼容就能用 -->
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-open-ai</artifactId>
      <version>${langchain4j.version}</version>
    </dependency>

    <!-- 显式声明 HTTP 客户端实现,否则编译期拿不到 JdkHttpClientBuilder -->
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-http-client-jdk</artifactId>
      <version>${langchain4j.version}</version>
    </dependency>

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.version}</version>
    </dependency>

    <!-- 日志门面:不加会持续输出 SLF4J(W) No providers were found 警告 -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>${slf4j.version}</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</version>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>3.2.0</version>
      </plugin>
    </plugins>
  </build>
</project>

三个真实的坑(我实测踩到的,你一定会踩)

坑 1:langchain4j-http-client-jdk 必须显式声明。

langchain4j-open-ai 把它作为 runtime 依赖带进来------运行时能用,但编译期看不见 JdkHttpClientBuilder,代码直接报"程序包不存在"。我实测就是这么失败的。要么显式加这个依赖(上面已加),要么干脆不自己配 HTTP 客户端、只用 .timeout()。W1 建议加,因为 W2 你要分开配连接超时和读超时。

坑 2:mvn compile 报"不支持源选项 5"。

老版本 maven-compiler-plugin 默认 source/target 是 1.5 。<maven.compiler.release>17</maven.compiler.release> 在插件 3.6.0 以下不生效。所以 pom 里显式锁了 3.13.0。别省这一行。

坑 3:model.chat("字符串") 返回的是 String,不是 ChatResponse。

这是最容易错的一处。ChatModel 有多个 chat 重载:

写法 返回 能否拿到 token
chat("你好") String 不能
chat(UserMessage.from("你好")) ChatResponse 能
chat(ChatRequest.builder()...build()) ChatResponse 能,且能带工具

官方 Get Started 页面用的是 model.chat("Say 'Hello World'") 并直接打印------那个版本你拿不到 token。只要你要记账,必须用带 UserMessage 或 ChatRequest 的重载。 我当时就是照着官方示例写的,编译直接报"String 无法转换为 ChatResponse"。


3. 跑通第一次调用(30 分钟)

src/main/java/com/company/lab/W1Hello.java:

java 复制代码
package com.company.lab;

import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.output.TokenUsage;

import java.time.Duration;

/**
 * W1 第一个可运行程序:调通网关,看清 token。
 * 刻意不做封装、不做重试------这一周的目标是"有反馈",不是"有架构"。
 */
public final class W1Hello {

    public static void main(String[] args) {
        String baseUrl = requireEnv("LLM_BASE_URL");
        String apiKey = requireEnv("LLM_API_KEY");
        String modelName = requireEnv("LLM_MODEL");

        ChatModel model = OpenAiChatModel.builder()
                .baseUrl(baseUrl)
                .apiKey(apiKey)
                .modelName(modelName)
                .temperature(0.0)
                .timeout(Duration.ofSeconds(60))   // 不写就用默认值,显式写才是工程习惯
                .maxRetries(0)                     // 这周关掉自动重试,先看清失败长什么样
                .logRequests(true)                 // 打印发出的 JSON,排查协议问题靠它
                .logResponses(true)                // 打印收到的 JSON,排查字段缺失靠它
                .build();

        long start = System.nanoTime();
        ChatResponse response = model.chat(UserMessage.from("用一句话解释:电商售后里什么是运费险。"));
        long costMs = (System.nanoTime() - start) / 1_000_000;

        TokenUsage usage = response.tokenUsage();

        System.out.println("=== 回复 ===");
        System.out.println(response.aiMessage().text());
        System.out.println("=== 用量 ===");
        System.out.println("输入 token : " + usage.inputTokenCount());
        System.out.println("输出 token : " + usage.outputTokenCount());
        System.out.println("总计 token : " + usage.totalTokenCount());
        System.out.println("耗时       : " + costMs + " ms");
    }

    private static String requireEnv(String name) {
        String value = System.getenv(name);
        if (value == null || value.isBlank()) {
            throw new IllegalStateException(
                    "环境变量 " + name + " 未设置。请按教程 1.2 节设置后重开终端。");
        }
        return value;
    }
}

运行:

bash 复制代码
mvn -q compile exec:java -Dexec.mainClass=com.company.lab.W1Hello

期望输出(模型回复与 token 数随网关不同而变化):

复制代码
=== 回复 ===
运费险是买家退货时可获赔退货运费的保障服务,通常随订单赠送或单独购买。
=== 用量 ===
输入 token : 23
输出 token : 15
总计 token : 38
耗时       : 1284 ms

失败对照表

报错关键词 含义 处理
401 / Unauthorized Key 无效或没带上 检查环境变量名拼写;echo $env:LLM_API_KEY 是否为空
403 无权限访问该模型 找网关要模型白名单
404 路径不对 换 baseUrl 后缀:/v1 → 空 → /openai/v1
ConnectException / UnknownHost 地址不通 内网?需要 VPN?端口对不对?
RateLimitException (429) 限流 正常现象,W2 专门处理
InvalidRequestException (400) 请求体字段不对 打开 logRequests,看发出的 JSON
200 但内容为空 网关用了非标准字段 抓原始响应,字段可能是 result 而不是 choices
String 无法转换为 ChatResponse 用错了 chat 重载 改成 chat(UserMessage.from(...)),见坑 3

4. 建立成本直觉(40 分钟,本周核心)

这一步比写代码重要。你要亲手算出钱。

4.1 拿到真实单价

问网关要输入单价 和输出单价 (单位"元/百万 token"或"元/千 token")。

技巧:直接问"每 100 万 token 多少钱",比自己研究计费文档快十倍。

4.2 成本计算工具

src/main/java/com/company/lab/CostMeter.java:

java 复制代码
package com.company.lab;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 按"每百万 token 单价"计算单次调用成本。
 * 用 BigDecimal 而不是 double:成本累加次数多了以后,浮点误差会让账对不上。
 */
public record CostMeter(BigDecimal inputPricePerMillion,
                        BigDecimal outputPricePerMillion) {

    private static final BigDecimal MILLION = new BigDecimal("1000000");

    public BigDecimal costOf(Integer inputTokens, Integer outputTokens) {
        BigDecimal in = BigDecimal.valueOf(inputTokens == null ? 0 : inputTokens);
        BigDecimal out = BigDecimal.valueOf(outputTokens == null ? 0 : outputTokens);
        return in.multiply(inputPricePerMillion)
                .add(out.multiply(outputPricePerMillion))
                .divide(MILLION, 6, RoundingMode.HALF_UP);
    }

    /** 一万 token 大约多少钱,用于建立直觉 */
    public BigDecimal costOfTenThousandTokens() {
        return new BigDecimal("10000")
                .multiply(inputPricePerMillion)
                .divide(MILLION, 6, RoundingMode.HALF_UP);
    }
}

4.3 跑 20 次并落表

src/main/java/com/company/lab/W1CostLab.java:

java 复制代码
package com.company.lab;

import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.output.TokenUsage;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 跑 20 条电商售后问题,把 token / 耗时 / 成本写成 CSV。
 * 这份 CSV 就是 W1 的交付物,也是后面所有成本优化的基线。
 */
public final class W1CostLab {

    // 用长短不一的问题,观察 token 与耗时的关系------这是建立直觉的关键
    private static final List<String> QUESTIONS = List.of(
            "退货要先申请还是先寄回?",
            "我买的东西七天无理由还能退吗?已经拆封了。",
            "运费险赔付多久到账?是退到余额还是原路退回?",
            "订单号 SN202610200001 的快递到哪了?显示签收了但我没收到。",
            "我买的鞋子尺码偏小,想换大一码,需要自己出运费吗?换货运费谁承担?",
            "大促期间下单的,退货时间是不是从 7 天延长到 15 天了?",
            "生鲜类商品坏了怎么赔?需要提供什么凭证?照片还是视频?",
            "我的退款申请提交两天了还没到账,能查一下卡在哪个环节吗?",
            "发票能补开吗?公司抬头需要填税号,之前的发票开错了。",
            "会员折扣和优惠券能叠加使用吗?我下单时好像没享受到会员价。"
    );

    public static void main(String[] args) throws IOException {
        String baseUrl = requireEnv("LLM_BASE_URL");
        String apiKey = requireEnv("LLM_API_KEY");
        String modelName = requireEnv("LLM_MODEL");

        CostMeter meter = new CostMeter(
                new BigDecimal(System.getenv().getOrDefault("LLM_PRICE_IN", "0")),
                new BigDecimal(System.getenv().getOrDefault("LLM_PRICE_OUT", "0")));

        ChatModel model = OpenAiChatModel.builder()
                .baseUrl(baseUrl)
                .apiKey(apiKey)
                .modelName(modelName)
                .temperature(0.0)
                .timeout(Duration.ofSeconds(60))
                .maxRetries(0)
                .build();

        Path csv = Path.of("w1-cost-log.csv");
        if (!Files.exists(csv)) {
            Files.writeString(csv, "序号,时间,问题字符数,输入token,输出token,耗时ms,成本元\n",
                    StandardCharsets.UTF_8, StandardOpenOption.CREATE);
        }

        BigDecimal total = BigDecimal.ZERO;
        long totalMs = 0;
        int runs = 20;

        for (int i = 1; i <= runs; i++) {
            String question = QUESTIONS.get((i - 1) % QUESTIONS.size());
            long start = System.nanoTime();
            ChatResponse response = model.chat(UserMessage.from(question));
            long ms = (System.nanoTime() - start) / 1_000_000;

            TokenUsage usage = response.tokenUsage();
            BigDecimal cost = meter.costOf(usage.inputTokenCount(), usage.outputTokenCount());
            total = total.add(cost);
            totalMs += ms;

            String line = String.format("%d,%s,%d,%d,%d,%d,%s%n",
                    i, LocalDateTime.now(), question.length(),
                    usage.inputTokenCount(), usage.outputTokenCount(), ms, cost.toPlainString());
            Files.writeString(csv, line, StandardCharsets.UTF_8, StandardOpenOption.APPEND);

            System.out.printf("[%02d/%d] in=%s out=%s %dms cost=%s%n",
                    i, runs, usage.inputTokenCount(), usage.outputTokenCount(), ms, cost.toPlainString());
        }

        System.out.println("-----------------------------");
        System.out.println("总成本 : " + total.toPlainString() + " 元");
        System.out.println("平均单次: " + total.divide(BigDecimal.valueOf(runs), 6, RoundingMode.HALF_UP) + " 元");
        System.out.println("平均耗时: " + (totalMs / runs) + " ms");
        System.out.println("一万 token 约: " + meter.costOfTenThousandTokens().toPlainString() + " 元(仅按输入价)");
        System.out.println("CSV 已写入: " + csv.toAbsolutePath());
    }

    private static String requireEnv(String name) {
        String v = System.getenv(name);
        if (v == null || v.isBlank()) {
            throw new IllegalStateException("环境变量 " + name + " 未设置");
        }
        return v;
    }
}

运行:

bash 复制代码
mvn -q compile exec:java -Dexec.mainClass=com.company.lab.W1CostLab

实测输出形态(以下为我用假网关跑出来的真实结果,单价假设为 2 / 8 元每百万 token):

复制代码
[19/20] in=57 out=23 1ms cost=0.000298
[20/20] in=58 out=26 1ms cost=0.000324
-----------------------------
总成本 : 0.006672 元
平均单次: 0.000334 元
平均耗时: 12 ms
一万 token 约: 0.020000 元(仅按输入价)
CSV 已写入: C:\...\ecom-agent-lab\w1-cost-log.csv

CSV 实际内容长这样:

复制代码
序号,时间,问题字符数,输入token,输出token,耗时ms,成本元
1,2026-10-20T10:02:38.112314,12,52,49,221,0.000496
2,2026-10-20T10:02:38.119295800,21,55,18,2,0.000254

你的真实网关跑出来的耗时会远大于 12ms(假网关不耗时)。不要拿我的数字当结论,你跑出来的才是真的。

4.4 从 CSV 里读出三件事

拿到表后回答这三个问题,写进周记:

  1. 输入 token 与问题字符数的比值是多少? 中文大致 1 字 ≈ 1~1.5 token。这个比值决定你以后怎么估上下文预算。
  2. 输出 token 波动大不大? 波动大 = 回答长度不可控,这就是后面要加 maxTokens 和输出格式约束的原因。
  3. 耗时和输出 token 是否强相关? 通常强相关。这说明延迟优化的重点往往在"让模型少说废话",而不是"换更快模型"。

5. 一分钱不花的自测方式(推荐先跑这个)

在拿到真实网关令牌之前,你可以用本地假网关验证整条链路。工程里已经带了 FakeGateway.java 和 selfcheck-w1.sh。

bash 复制代码
# 1. 编译
mvn -q compile

# 2. 生成依赖 classpath
mvn -q dependency:build-classpath -Dmdep.outputFile=cp.txt

# 3. 一键自测(启动假网关 -> 跑两个程序 -> 校验 CSV 行数 -> 关网关)
bash selfcheck-w1.sh

期望输出尾部:

复制代码
== 4. 校验 CSV ==
数据行数 = 20 (期望 20)
序号,时间,问题字符数,输入token,输出token,耗时ms,成本元
1,2026-10-20T10:02:38.112314,12,52,49,221,0.000496

这个脚本的价值:把"代码写错了"和"网关不通"两类问题分开。如果假网关能跑通、真网关跑不通,那问题一定在鉴权、路径或协议上,不在你的代码里。

FakeGateway.java 只做一件事:在本机 18081 端口起一个假的 /v1/chat/completions,返回标准 OpenAI 格式响应(含 usage 字段)。它不联网、不花钱。


6. 常见问题

Q1:网关只给了一个模型名,但没有 OpenAI 兼容接口怎么办?

等 W2 的自封装方案。W1 先做环境变量、成本表结构设计、以及假网关链路验证。不要写临时 hack 客户端------W2 会给你完整版本。

Q2:logRequests(true) 把 API Key 打出来了怎么办?

LangChain4j 默认对 Authorization 头做脱敏,但不要依赖它。排查完协议问题就关掉。要长期开就自己外面包一层脱敏日志。

Q3:跑 20 次要花多少钱?

按国内主流模型量级,20 条短问答通常在几分钱到一毛钱之间。这点钱不值得省。真贵的是你为省几毛钱折腾免费额度浪费的两小时。

Q4:模型回答很啰嗦,一跑就几百 token,正常吗?

正常。20 条问题里有长有短,才能看出输出长度分布。W2 会加 maxTokens 上限。

Q5:公司不让用外部模型 API 怎么办?

那就只用公司网关------这正是选它的理由:数据不出内网。练习数据自己编(如 SN202610200001),不要用真实订单。

Q6:JDK 17 和公司老项目的 JDK 8 冲突怎么办?

两个 JDK 可以共存。用 JAVA_HOME 切换,或给这个工程单独配 IDEA 的 Project SDK。不要为了练手去升级生产项目。


7. 本周自检清单

按顺序打勾,全勾完才算 W1 通过:

  • java -version 显示 17+
  • 五个环境变量都设置了,echo 能看到值
  • curl 探测网关返回 200,已判断出是形态 A/B/C
  • bash selfcheck-w1.sh 跑通,数据行数 = 20
  • 真实网关 W1Hello 跑通,看到了回复 + token + 耗时
  • 真实网关 W1CostLab 跑完 20 次,生成了 w1-cost-log.csv
  • 能口头回答:一万 token 多少钱、单次平均耗时多少
  • 代码里搜不到 API Key 字面量(grep -r "sk-" .)
  • 周记写了 3 条结论(token 比值、输出波动、耗时相关性)

没完成的怎么办: 剩 1--2 项放下周两小时轻任务补。剩 3 项以上,用一个机动周重做 W1------地基不牢,W2 的超时重试会让你更痛苦。


8. 三条待核实项(不要照抄,去查证)

项 为什么不确定 怎么核实
公司网关的鉴权方式与可用模型名 每家公司不同,我无法知道 问平台组,或看内部接入文档
模型单价(元/百万 token) 随厂商、模型、时段变动 网关控制台或计费页当日价格
网关是否严格兼容 OpenAI 协议 部分自研网关字段有差异 用 1.3 节 curl 实测

另:本文所有 LangChain4j API 均以 1.22.0 实测为准(Registry 显示 1.22.0 发布于 2026-10-09,是当前最新稳定版)。框架迭代快,若你读到本文时版本已升,请以官方 Get Started 与 Javadoc 为准重新核对 chat 重载与 TokenUsage 方法名。


9. 下一周预告

W2 把"能跑的代码"变成"能扛事的代码":

  • 把 .timeout() 拆成连接超时 + 读超时,理解为什么两个都要设
  • 自己实现退避重试(带抖动),搞清为什么内置 maxRetries 不够用
  • 错误分三类:可重试(429/5xx/超时)、需人工(400/401)、终止(内容违规)
  • 输出 JSON 结构化日志,为 W18 的 trace 打底
  • 用假网关注入故障(429 / 超时 / 断连),验证你的重试真的生效

带一个能跑的程序来 W2,不要空手来。

相关推荐
樱木花道長5 小时前
AMD Ross 深度系列 8:FAQ 七问七答(文末附网盘链接)
人工智能·fpga开发
zhangfeng11335 小时前
中关村国际前沿科技大赛(创新药赛道)详细介绍 ai药物比赛
人工智能·科技
xiaoyunxuexibiji5 小时前
供应商质量协同如何实现闭环管理?从到货检验到整改与质量索赔
人工智能
xn71335 小时前
本地 AI 知识库跨设备同步:SQLite FTS5、Embedding、Tombstone 和引用校验
人工智能·sqlite·ai编程
九月suma5 小时前
同一个需求,加上这个 Skill,网页到底差多少?
人工智能
FPGA小迷弟5 小时前
FPGA 与无人机:从飞控实时性到智能载荷的硬件加速实践
人工智能·ai·fpga开发·架构·无人机·ai编程
yyk333245 小时前
YOLOv4算法
人工智能·yolo·目标跟踪
Thneonl5 小时前
熔断不是开关是状态机:Claude Code 路由内核的 3 条红线
人工智能·rust
蹄蹄6 小时前
从“一次性检测“到“年度服务“:检测机构收入结构变了,合同和应收账款也要跟着变
大数据·数据库·人工智能