DeepSeek API的隐藏功能:探索Java开发者不知道的高级用法
·
DeepSeek API的隐藏功能:探索Java开发者不知道的高级用法
在当今快速发展的AI技术浪潮中,DeepSeek作为国内领先的大语言模型平台,其API功能远比大多数Java开发者所了解的更为强大。本文将深入探讨那些鲜为人知的高级特性和技巧,帮助有经验的Java开发者突破基础API调用的局限,实现更高效、更灵活的AI集成方案。
1. 流式响应处理的艺术
传统的API调用往往等待完整响应返回后再进行处理,这在处理长篇内容时会导致明显的延迟。DeepSeek API支持流式响应(Server-Sent Events),让内容能够分块实时返回。
1.1 基础流式处理实现
使用OkHttp的EventSource实现流式处理:
public class DeepSeekStreamClient {
private static final String API_URL = "https://api.deepseek.com/v1/chat/completions";
private final OkHttpClient client = new OkHttpClient();
public void streamChat(String apiKey, String prompt, Consumer<String> chunkHandler) {
MediaType mediaType = MediaType.parse("application/json");
String jsonBody = String.format("{\"model\":\"deepseek-chat\",\"messages\":[{\"role\":\"user\",\"content\":\"%s\"}],\"stream\":true}",
prompt.replace("\"", "\\\""));
Request request = new Request.Builder()
.url(API_URL)
.post(RequestBody.create(jsonBody, mediaType))
.addHeader("Authorization", "Bearer " + apiKey)
.build();
EventSource.Factory factory = EventSources.createFactory(client);
factory.newEventSource(request, new EventSourceListener() {
private final StringBuilder contentBuilder = new StringBuilder();
@Override
public void onEvent(@NotNull EventSource eventSource, String id, String type, @NotNull String data) {
if ("[DONE]".equals(data)) {
chunkHandler.accept("[STREAM_COMPLETE]");
return;
}
try {
JsonNode node = new ObjectMapper().readTree(data);
String chunk = node.path("choices").get(0).path("delta").path("content").asText();
if (chunk != null) {
contentBuilder.append(chunk);
chunkHandler.accept(chunk);
}
} catch (Exception e) {
chunkHandler.accept("[ERROR] " + e.getMessage());
}
}
@Override
public void onFailure(@NotNull EventSource eventSource, Throwable t, Response response) {
chunkHandler.accept("[ERROR] " + (t != null ? t.getMessage() : "Unknown error"));
}
});
}
}
1.2 高级流式处理技巧
缓冲与聚合策略:对于需要处理完整句子的场景,可以实现智能缓冲:
public class SentenceBuffer {
private final StringBuilder buffer = new StringBuilder();
private final Consumer<String> sentenceHandler;
private static final Pattern SENTENCE_END = Pattern.compile("[.!?。!?]\\s*");
public SentenceBuffer(Consumer<String> sentenceHandler) {
this.sentenceHandler = sentenceHandler;
}
public void append(String text) {
buffer.append(text);
Matcher matcher = SENTENCE_END.matcher(buffer);
int lastEnd = 0;
while (matcher.find()) {
int end = matcher.end();
String sentence = buffer.substring(lastEnd, end).trim();
if (!sentence.isEmpty()) {
sentenceHandler.accept(sentence);
}
lastEnd = end;
}
if (lastEnd > 0) {
buffer.delete(0, lastEnd);
}
}
}
使用示例:
DeepSeekStreamClient client = new DeepSeekStreamClient();
SentenceBuffer buffer = new SentenceBuffer(System.out::println);
client.streamChat(apiKey, "请详细解释Java的Stream API", buffer::append);
2. 多轮对话管理的进阶策略
简单的多轮对话实现往往只是简单追加历史消息,但实际应用中需要考虑更多因素。
2.1 智能对话历史管理
public class ConversationManager {
private final List<Message> history = new ArrayList<>();
private final int maxTokens;
private final Tokenizer tokenizer;
public ConversationManager(int maxTokens) {
this.maxTokens = maxTokens;
this.tokenizer = new SimpleTokenizer(); // 实现简单的分词计数
}
public void addMessage(String role, String content) {
history.add(new Message(role, content));
trimHistory();
}
private void trimHistory() {
while (getTotalTokens() > maxTokens) {
if (history.size() > 1) {
history.remove(1); // 保留系统消息,移除最早的对话
} else {
break;
}
}
}
private int getTotalTokens() {
return history.stream()
.mapToInt(msg -> tokenizer.countTokens(msg.content))
.sum();
}
public List<Message> getHistory() {
return new ArrayList<>(history);
}
static class Message {
String role;
String content;
Message(String role, String content) {
this.role = role;
this.content = content;
}
}
interface Tokenizer {
int countTokens(String text);
}
}
2.2 对话状态持久化与恢复
public class ConversationPersistence {
private final ObjectMapper mapper = new ObjectMapper();
public String serialize(ConversationManager conversation) {
try {
return mapper.writeValueAsString(conversation.getHistory());
} catch (JsonProcessingException e) {
throw new RuntimeException("Serialization failed", e);
}
}
public ConversationManager deserialize(String json, int maxTokens) {
try {
List<ConversationManager.Message> messages = mapper.readValue(json,
new TypeReference<List<ConversationManager.Message>>() {});
ConversationManager manager = new ConversationManager(maxTokens);
messages.forEach(msg -> manager.addMessage(msg.role, msg.content));
return manager;
} catch (JsonProcessingException e) {
throw new RuntimeException("Deserialization failed", e);
}
}
}
3. 自定义模型参数调优实战
DeepSeek API提供了多种参数来调整模型行为,合理配置可以显著提升响应质量。
3.1 关键参数详解
| 参数 | 类型 | 范围 | 说明 | 适用场景 |
|---|---|---|---|---|
| temperature | float | 0-2 | 控制随机性,值越高输出越随机 | 创意写作、头脑风暴 |
| top_p | float | 0-1 | 核采样,控制输出的多样性 | 需要精确控制的场景 |
| max_tokens | int | 1-4096 | 限制响应长度 | 控制响应篇幅 |
| presence_penalty | float | -2-2 | 减少重复话题 | 长文本生成 |
| frequency_penalty | float | -2-2 | 减少重复词汇 | 技术文档生成 |
3.2 参数优化策略
动态参数调整:根据查询类型自动调整参数
public class ParameterOptimizer {
public Map<String, Object> optimizeParameters(String query) {
Map<String, Object> params = new HashMap<>();
// 基础参数
params.put("model", "deepseek-chat");
// 根据查询类型调整参数
if (isTechnicalQuery(query)) {
params.put("temperature", 0.3);
params.put("top_p", 0.9);
params.put("presence_penalty", 0.5);
} else if (isCreativeQuery(query)) {
params.put("temperature", 0.8);
params.put("top_p", 0.95);
params.put("frequency_penalty", 0.2);
} else {
// 默认参数
params.put("temperature", 0.5);
params.put("top_p", 0.92);
}
// 根据查询长度调整max_tokens
int queryLength = query.length();
params.put("max_tokens", Math.min(2000, 4000 - queryLength));
return params;
}
private boolean isTechnicalQuery(String query) {
return query.matches(".*(代码|API|配置|参数|实现|原理).*");
}
private boolean isCreativeQuery(String query) {
return query.matches(".*(故事|诗歌|创意|想象|如果).*");
}
}
A/B测试框架:评估不同参数组合的效果
public class ParameterTester {
private final DeepSeekClient client;
private final List<ParameterSet> testSets;
public ParameterTester(DeepSeekClient client) {
this.client = client;
this.testSets = List.of(
new ParameterSet("保守", Map.of("temperature", 0.3, "top_p", 0.9)),
new ParameterSet("平衡", Map.of("temperature", 0.5, "top_p", 0.92)),
new ParameterSet("创意", Map.of("temperature", 0.8, "top_p", 0.95))
);
}
public Map<String, String> testParameters(String prompt) {
return testSets.stream()
.collect(Collectors.toMap(
ParameterSet::name,
set -> client.query(prompt, set.parameters())
));
}
record ParameterSet(String name, Map<String, Object> parameters) {}
}
4. API调用限流与熔断机制
高并发场景下,合理的限流和熔断策略对系统稳定性至关重要。
4.1 基于Resilience4j的实现
public class RateLimitedDeepSeekClient {
private final DeepSeekClient delegate;
private final RateLimiter rateLimiter;
private final CircuitBreaker circuitBreaker;
public RateLimitedDeepSeekClient(DeepSeekClient delegate, int permitsPerSecond) {
this.delegate = delegate;
// 限流配置
this.rateLimiter = RateLimiter.of("deepseek-rate-limiter",
RateLimiterConfig.custom()
.limitRefreshPeriod(Duration.ofSeconds(1))
.limitForPeriod(permitsPerSecond)
.timeoutDuration(Duration.ofMillis(500))
.build());
// 熔断配置
this.circuitBreaker = CircuitBreaker.of("deepseek-circuit-breaker",
CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofSeconds(30))
.slidingWindowSize(10)
.build());
}
public String query(String prompt) {
return CircuitBreaker.decorateSupplier(circuitBreaker,
RateLimiter.decorateSupplier(rateLimiter,
() -> delegate.query(prompt))
).get();
}
public Flux<String> stream(String prompt, Consumer<String> chunkHandler) {
return Flux.create(sink -> {
if (rateLimiter.acquirePermission()) {
try {
delegate.stream(prompt, chunk -> {
sink.next(chunk);
if (chunk.equals("[STREAM_COMPLETE]")) {
sink.complete();
}
});
} catch (Exception e) {
circuitBreaker.onError(e);
sink.error(e);
}
} else {
sink.error(new RateLimitExceededException("API rate limit exceeded"));
}
});
}
}
4.2 自适应限流策略
public class AdaptiveRateLimiter {
private final RateLimiter rateLimiter;
private final int minPermits;
private final int maxPermits;
private final double backoffFactor;
public AdaptiveRateLimiter(int initialPermits, int minPermits, int maxPermits, double backoffFactor) {
this.rateLimiter = RateLimiter.of("adaptive-rate-limiter",
RateLimiterConfig.custom()
.limitRefreshPeriod(Duration.ofSeconds(1))
.limitForPeriod(initialPermits)
.timeoutDuration(Duration.ZERO)
.build());
this.minPermits = minPermits;
this.maxPermits = maxPermits;
this.backoffFactor = backoffFactor;
}
public void adjustBasedOnResponseTime(long responseTimeMs, long thresholdMs) {
int currentLimit = rateLimiter.getRateLimiterConfig().getLimitForPeriod();
if (responseTimeMs > thresholdMs) {
// 响应时间过长,降低速率
int newLimit = (int) Math.max(minPermits, currentLimit * backoffFactor);
if (newLimit != currentLimit) {
rateLimiter.changeLimitForPeriod(newLimit);
}
} else if (currentLimit < maxPermits) {
// 响应时间正常,尝试增加速率
int newLimit = (int) Math.min(maxPermits, currentLimit / backoffFactor);
if (newLimit != currentLimit) {
rateLimiter.changeLimitForPeriod(newLimit);
}
}
}
public boolean tryAcquire() {
return rateLimiter.acquirePermission();
}
}
5. 高级错误处理与重试机制
健壮的错误处理是生产级应用的关键。
5.1 智能重试策略
public class RetryPolicy {
private final int maxAttempts;
private final Duration initialDelay;
private final double backoffMultiplier;
private final Predicate<Exception> retryPredicate;
public RetryPolicy(int maxAttempts, Duration initialDelay, double backoffMultiplier,
Predicate<Exception> retryPredicate) {
this.maxAttempts = maxAttempts;
this.initialDelay = initialDelay;
this.backoffMultiplier = backoffMultiplier;
this.retryPredicate = retryPredicate;
}
public <T> T execute(Supplier<T> operation) throws Exception {
int attempt = 0;
Exception lastException = null;
while (attempt < maxAttempts) {
try {
return operation.get();
} catch (Exception e) {
lastException = e;
if (!retryPredicate.test(e)) {
break;
}
attempt++;
if (attempt < maxAttempts) {
long delay = (long) (initialDelay.toMillis() * Math.pow(backoffMultiplier, attempt - 1));
Thread.sleep(delay);
}
}
}
throw lastException;
}
public static RetryPolicy defaultPolicy() {
return new RetryPolicy(3, Duration.ofMillis(500), 2.0,
e -> e instanceof IOException ||
(e instanceof RuntimeException &&
e.getMessage() != null &&
(e.getMessage().contains("timeout") ||
e.getMessage().contains("rate limit"))));
}
}
5.2 错误分类处理器
public class ErrorHandler {
private static final Map<Predicate<Exception>, Consumer<Exception>> HANDLERS = Map.of(
e -> e.getMessage() != null && e.getMessage().contains("401"),
e -> refreshApiKey(),
e -> e.getMessage() != null && e.getMessage().contains("429"),
e -> throttleRequests(),
e -> e instanceof SocketTimeoutException,
e -> increaseTimeout(),
e -> e instanceof ConnectException,
e -> checkNetworkConnection()
);
public static void handle(Exception e) {
HANDLERS.entrySet().stream()
.filter(entry -> entry.getKey().test(e))
.findFirst()
.ifPresentOrElse(
entry -> entry.getValue().accept(e),
() -> logError(e)
);
}
private static void refreshApiKey() {
// 实现API密钥刷新逻辑
}
private static void throttleRequests() {
// 实现请求限流逻辑
}
private static void increaseTimeout() {
// 调整超时设置
}
private static void checkNetworkConnection() {
// 检查网络连接
}
private static void logError(Exception e) {
// 记录未处理的错误
}
}
6. 性能优化与缓存策略
6.1 响应缓存实现
public class ResponseCache {
private final Cache<String, String> cache;
private final DeepSeekClient client;
private final Function<String, String> keyGenerator;
public ResponseCache(DeepSeekClient client, int maxSize, Duration ttl) {
this.client = client;
this.cache = Caffeine.newBuilder()
.maximumSize(maxSize)
.expireAfterWrite(ttl)
.build();
this.keyGenerator = this::generateCacheKey;
}
public String query(String prompt) {
String key = keyGenerator.apply(prompt);
return cache.get(key, k -> client.query(prompt));
}
private String generateCacheKey(String prompt) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(prompt.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hash);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Failed to generate cache key", e);
}
}
public void preloadCache(List<String> commonQueries) {
commonQueries.parallelStream()
.forEach(this::query);
}
}
6.2 批量请求处理
public class BatchProcessor {
private final ExecutorService executor;
private final DeepSeekClient client;
private final int batchSize;
public BatchProcessor(DeepSeekClient client, int parallelism, int batchSize) {
this.client = client;
this.batchSize = batchSize;
this.executor = Executors.newFixedThreadPool(parallelism);
}
public List<String> processBatch(List<String> prompts) {
List<Future<String>> futures = new ArrayList<>();
// 分批处理
for (int i = 0; i < prompts.size(); i += batchSize) {
int end = Math.min(i + batchSize, prompts.size());
List<String> batch = prompts.subList(i, end);
futures.add(executor.submit(() -> processSingleBatch(batch)));
}
// 收集结果
List<String> results = new ArrayList<>();
for (Future<String> future : futures) {
try {
results.add(future.get());
} catch (InterruptedException | ExecutionException e) {
results.add("[ERROR] " + e.getMessage());
}
}
return results;
}
private String processSingleBatch(List<String> batch) {
// 将多个问题合并为一个请求
String combinedPrompt = batch.stream()
.map(p -> "- " + p.replace("\n", " ") + "\n")
.collect(Collectors.joining("", "请依次回答以下问题:\n", ""));
String response = client.query(combinedPrompt);
// 分割响应为原始问题的答案
return Arrays.stream(response.split("\n"))
.filter(line -> line.startsWith("- "))
.map(line -> line.substring(2))
.collect(Collectors.joining("\n"));
}
}
7. 安全最佳实践
7.1 API密钥安全管理
public class ApiKeyManager {
private final String encryptedKey;
private final SecretKey secretKey;
public ApiKeyManager(String encryptedKey, String masterPassword) {
this.encryptedKey = encryptedKey;
this.secretKey = generateKey(masterPassword);
}
public String getApiKey() {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128,
Base64.getDecoder().decode(encryptedKey.substring(0, 24)));
cipher.init(Cipher.DECRYPT_MODE, secretKey, parameterSpec);
byte[] decrypted = cipher.doFinal(
Base64.getDecoder().decode(encryptedKey.substring(24)));
return new String(decrypted, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException("Failed to decrypt API key", e);
}
}
public static String encryptApiKey(String apiKey, String masterPassword) {
try {
SecretKey key = generateKey(masterPassword);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
byte[] iv = new byte[12];
new SecureRandom().nextBytes(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, iv));
byte[] encrypted = cipher.doFinal(apiKey.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(iv) +
Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
throw new RuntimeException("Failed to encrypt API key", e);
}
}
private static SecretKey generateKey(String password) {
try {
byte[] salt = "fixed-salt".getBytes(StandardCharsets.UTF_8);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
} catch (Exception e) {
throw new RuntimeException("Failed to generate key", e);
}
}
}
7.2 请求验证与过滤
public class RequestValidator {
private final Set<String> blockedPatterns;
private final Set<String> sensitiveWords;
public RequestValidator() {
this.blockedPatterns = loadBlockedPatterns();
this.sensitiveWords = loadSensitiveWords();
}
public void validate(String prompt) {
// 检查长度
if (prompt.length() > 5000) {
throw new ValidationException("Prompt too long");
}
// 检查敏感词
for (String word : sensitiveWords) {
if (prompt.toLowerCase().contains(word)) {
throw new ValidationException("Prompt contains sensitive content");
}
}
// 检查阻止模式
for (String pattern : blockedPatterns) {
if (Pattern.compile(pattern, Pattern.CASE_INSENSITIVE).matcher(prompt).find()) {
throw new ValidationException("Prompt matches blocked pattern");
}
}
}
private Set<String> loadBlockedPatterns() {
// 从配置文件或数据库加载
return Set.of(
"\\b(admin|root)\\b.*\\b(password|credential)\\b",
"\\b(delete|drop)\\b.*\\b(database|table)\\b"
);
}
private Set<String> loadSensitiveWords() {
// 从配置文件或数据库加载
return Set.of("confidential", "secret", "password", "token");
}
}
8. 监控与日志记录
8.1 全面的监控指标
public class ApiMetrics {
private final MeterRegistry meterRegistry;
private final Counter successCounter;
private final Counter failureCounter;
private final Timer responseTimer;
private final DistributionSummary tokenUsage;
public ApiMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.successCounter = meterRegistry.counter("deepseek.api.calls", "status", "success");
this.failureCounter = meterRegistry.counter("deepseek.api.calls", "status", "failure");
this.responseTimer = meterRegistry.timer("deepseek.api.response.time");
this.tokenUsage = meterRegistry.summary("deepseek.api.token.usage");
}
public void recordSuccess(long durationMs, int promptTokens, int completionTokens) {
successCounter.increment();
responseTimer.record(durationMs, TimeUnit.MILLISECONDS);
tokenUsage.record(promptTokens + completionTokens);
}
public void recordFailure(String errorType) {
failureCounter.increment();
meterRegistry.counter("deepseek.api.errors", "type", errorType).increment();
}
public void monitor() {
// 实时监控关键指标
new Thread(() -> {
while (true) {
try {
double errorRate = failureCounter.count() /
(successCounter.count() + failureCounter.count());
if (errorRate > 0.1) {
alertHighErrorRate(errorRate);
}
Thread.sleep(60000); // 每分钟检查一次
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}).start();
}
private void alertHighErrorRate(double rate) {
// 实现告警逻辑
}
}
8.2 结构化日志记录
public class ApiLogger {
private final Logger logger;
private final ObjectMapper mapper;
public ApiLogger(Class<?> clazz) {
this.logger = LoggerFactory.getLogger(clazz);
this.mapper = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
public void logRequest(String prompt, Map<String, Object> params) {
Map<String, Object> logData = new LinkedHashMap<>();
logData.put("event", "api_request");
logData.put("timestamp", Instant.now());
logData.put("prompt_length", prompt.length());
logData.put("params", params);
try {
logger.info(mapper.writeValueAsString(logData));
} catch (JsonProcessingException e) {
logger.warn("Failed to serialize request log", e);
}
}
public void logResponse(String response, long durationMs, int tokensUsed) {
Map<String, Object> logData = new LinkedHashMap<>();
logData.put("event", "api_response");
logData.put("timestamp", Instant.now());
logData.put("response_length", response.length());
logData.put("duration_ms", durationMs);
logData.put("tokens_used", tokensUsed);
try {
logger.info(mapper.writeValueAsString(logData));
} catch (JsonProcessingException e) {
logger.warn("Failed to serialize response log", e);
}
}
public void logError(Exception e, String context) {
Map<String, Object> logData = new LinkedHashMap<>();
logData.put("event", "api_error");
logData.put("timestamp", Instant.now());
logData.put("error_type", e.getClass().getSimpleName());
logData.put("error_message", e.getMessage());
logData.put("context", context);
try {
logger.error(mapper.writeValueAsString(logData));
} catch (JsonProcessingException ex) {
logger.warn("Failed to serialize error log", ex);
}
}
}
9. 测试策略与Mock服务
9.1 模拟服务实现
public class MockDeepSeekService {
private final Map<String, String> responseMap;
private final Random random = new Random();
public MockDeepSeekService() {
this.responseMap = new HashMap<>();
// 预定义常见问题的回答
responseMap.put("你好", "你好!我是DeepSeek AI助手,有什么可以帮你的吗?");
responseMap.put("你是谁", "我是DeepSeek开发的人工智能助手,专门用于回答问题并提供帮助。");
responseMap.put("现在几点", "我是一个AI,没有实时时钟功能,建议查看你的设备时间。");
}
public String mockQuery(String prompt) {
// 模拟网络延迟
try {
Thread.sleep(50 + random.nextInt(200));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 检查预定义回答
if (responseMap.containsKey(prompt)) {
return responseMap.get(prompt);
}
// 生成通用回答
return String.format("这是对'%s'的模拟回答。在实际应用中,这将调用真实的DeepSeek API。",
prompt.substring(0, Math.min(20, prompt.length())));
}
public void mockStream(String prompt, Consumer<String> chunkHandler) {
String response = mockQuery(prompt);
int chunkSize = 5;
for (int i = 0; i < response.length(); i += chunkSize) {
int end = Math.min(i + chunkSize, response.length());
chunkHandler.accept(response.substring(i, end));
try {
Thread.sleep(50 + random.nextInt(100));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
chunkHandler.accept("[STREAM_COMPLETE]");
}
}
9.2 集成测试方案
public class DeepSeekIntegrationTest {
private DeepSeekClient client;
private MockDeepSeekService mockService;
@BeforeEach
void setUp() {
mockService = new MockDeepSeekService();
client = new DeepSeekClient("test-key") {
@Override
public String query(String prompt) {
return mockService.mockQuery(prompt);
}
@Override
public void stream(String prompt, Consumer<String> chunkHandler) {
mockService.mockStream(prompt, chunkHandler);
}
};
}
@Test
void testQuery() {
String response = client.query("你好");
assertNotNull(response);
assertTrue(response.contains("DeepSeek"));
}
@Test
void testStream() {
StringBuilder received = new StringBuilder();
client.stream("你是谁", chunk -> {
if (!chunk.equals("[STREAM_COMPLETE]")) {
received.append(chunk);
}
});
// 等待流完成
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
assertTrue(received.toString().contains("人工智能助手"));
}
@Test
void testErrorHandling() {
client = new DeepSeekClient("test-key") {
@Override
public String query(String prompt) {
throw new RuntimeException("模拟API错误");
}
};
assertThrows(RuntimeException.class, () -> client.query("任何问题"));
}
}
10. 实际应用案例:智能问答系统
10.1 Spring Boot集成方案
@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final DeepSeekClient deepSeekClient;
private final ConversationManager conversationManager;
private final ApiMetrics metrics;
private final ApiLogger logger;
public ChatController(DeepSeekClient deepSeekClient,
ConversationManager conversationManager,
ApiMetrics metrics,
ApiLogger logger) {
this.deepSeekClient = deepSeekClient;
this.conversationManager = conversationManager;
this.metrics = metrics;
this.logger = logger;
}
@PostMapping
public ResponseEntity<ChatResponse> chat(@RequestBody ChatRequest request) {
long startTime = System.currentTimeMillis();
try {
// 验证并处理输入
validateInput(request);
// 管理对话历史
conversationManager.addMessage("user", request.prompt());
// 构建完整上下文
String context = buildContext();
// 调用API
String response = deepSeekClient.query(context);
// 更新对话历史
conversationManager.addMessage("assistant", response);
// 记录指标
metrics.recordSuccess(
System.currentTimeMillis() - startTime,
context.length() / 4, // 简单估算token数
response.length() / 4
);
// 记录日志
logger.logResponse(response,
System.currentTimeMillis() - startTime,
(context.length() + response.length()) / 4);
return ResponseEntity.ok(new ChatResponse(response, conversationManager.getSessionId()));
} catch (Exception e) {
metrics.recordFailure(e.getClass().getSimpleName());
logger.logError(e, "Chat request failed");
return ResponseEntity.status(500).body(
new ChatResponse("抱歉,处理您的请求时出错: " + e.getMessage(), null));
}
}
@GetMapping("/stream")
public SseEmitter streamChat(@RequestParam String prompt) {
SseEmitter emitter = new SseEmitter(30000L);
long startTime = System.currentTimeMillis();
// 管理对话历史
conversationManager.addMessage("user", prompt);
String context = buildContext();
deepSeekClient.stream(context, chunk -> {
try {
if (chunk.equals("[STREAM_COMPLETE]")) {
// 完成处理
conversationManager.addMessage("assistant", getCurrentResponse());
metrics.recordSuccess(
System.currentTimeMillis() - startTime,
context.length() / 4,
getCurrentResponse().length() / 4
);
logger.logResponse(getCurrentResponse(),
System.currentTimeMillis() - startTime,
(context.length() + getCurrentResponse().length()) / 4);
emitter.complete();
} else {
// 发送流式数据
appendToCurrentResponse(chunk);
emitter.send(chunk);
}
} catch (IOException e) {
emitter.completeWithError(e);
}
});
return emitter;
}
private void validateInput(ChatRequest request) {
if (request.prompt() == null || request.prompt().trim().isEmpty()) {
throw new IllegalArgumentException("Prompt cannot be empty");
}
if (request.prompt().length() > 5000) {
throw new IllegalArgumentException("Prompt too long");
}
}
private String buildContext() {
return conversationManager.getHistory().stream()
.map(msg -> msg.role + ": " + msg.content)
.collect(Collectors.joining("\n\n"));
}
// 当前响应缓冲区管理方法省略...
record ChatRequest(String prompt) {}
record ChatResponse(String response, String sessionId) {}
}
10.2 前端集成示例
class ChatUI {
constructor(apiUrl) {
this.apiUrl = apiUrl;
this.sessionId = null;
this.setupEventListeners();
}
setupEventListeners() {
document.getElementById('send-btn').addEventListener('click', () => this.sendMessage());
document.getElementById('stream-toggle').addEventListener('change', (e) => {
this.useStream = e.target.checked;
});
}
async sendMessage() {
const input = document.getElementById('chat-input');
const message = input.value.trim();
if (!message) return;
this.addMessage('user', message);
input.value = '';
if (this.useStream) {
this.streamResponse(message);
} else {
this.fetchResponse(message);
}
}
async fetchResponse(prompt) {
try {
const response = await fetch(this.apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt,
sessionId: this.sessionId
})
});
const data = await response.json();
this.sessionId = data.sessionId;
this.addMessage('assistant', data.response);
} catch (error) {
this.showError("Failed to get response: " + error.message);
}
}
streamResponse(prompt) {
const eventSource = new EventSource(
`${this.apiUrl}/stream?prompt=${encodeURIComponent(prompt)}` +
(this.sessionId ? `&sessionId=${this.sessionId}` : '')
);
const messageDiv = this.addMessage('assistant', '');
let content = '';
eventSource.onmessage = (event) => {
if (event.data === '[STREAM_COMPLETE更多推荐

所有评论(0)