fix(llm): 大模型 api-key 启动自检,缺配/占位符直接 ERROR
build / build-push (push) Successful in 52s

线上容器漏注入 DEEPSEEK_API_KEY 时,api-key 会落到 application.yml 里的中文
占位符,直到某个用户发起一次对话才以 HTTP 401 暴露:
  ResourceAccessException: I/O error on POST ...
  java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
排查成本很高。

DeepSeekClient 增加 @PostConstruct 自检(可 grep [大模型]):
  - 为空 / 仍含"请替换"占位符 -> ERROR,并写明修法
  - 不以 sk- 开头 -> WARN 提示格式可疑
  - 正常 -> INFO 打长度 + host + model(不打印 key 本体)

修法提示:在 projman 的 /app/config/application-prod.yml 填真实 key,
或给容器注入环境变量 DEEPSEEK_API_KEY(勿写入 public 仓库中的 application.yml)。
This commit is contained in:
lijing
2026-10-12 11:57:49 +08:00
parent 8303b857e9
commit 0197a9de05
@@ -19,6 +19,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
@@ -51,6 +52,34 @@ public class DeepSeekClient implements LlmClient {
this.settings = settings;
}
/**
* 启动自检:把「大模型到底配好没有」这件事在启动日志里说清楚(可 grep {@code [大模型]})。
*
* <p>线上最容易被忽略的一类故障:容器没有注入 {@code DEEPSEEK_API_KEY},
* 于是 api-key 落到 application.yml 里的中文占位符,直到某个用户发起一次对话才以
* HTTP 401(表现为 {@code HttpRetryException: cannot retry due to server authentication,
* in streaming mode})暴露出来 —— 排查成本很高。这里改成启动时就 ERROR 出来。
*/
@PostConstruct
void checkLlmConfig() {
AgentSettings.Llm llm = settings.getLlm();
String key = llm.getApiKey();
if (StringUtils.isBlank(key)) {
log.error("[大模型] agent.llm.api-key 为空 —— 任何对话都会鉴权失败。"
+ "请在 application-prod.yml 填写真实 key,或给容器注入环境变量 DEEPSEEK_API_KEY。");
} else if (key.contains("请替换")) {
log.error("[大模型] agent.llm.api-key 仍是占位符(长度 {})—— 说明容器没有注入环境变量 "
+ "DEEPSEEK_API_KEY。任何对话都会 401:请在 application-prod.yml 写真实 key,"
+ "或给容器注入该环境变量后重启。", key.length());
} else if (!key.startsWith("sk-")) {
log.warn("[大模型] agent.llm.api-key 已配置,但格式可疑(不以 sk- 开头,长度 {}),请确认是否填错。",
key.length());
} else {
log.info("[大模型] api-key 已配置(长度 {}),host={} model={}",
key.length(), llm.getHost(), llm.getModel());
}
}
@Override
public ChatResult chat(List<ChatMessage> messages, JSONArray tools) {
AgentSettings.Llm llm = settings.getLlm();