问题:AzureOpenAi模型在达到令牌长度限制时应使用FinishReason.LENGTH。如果我们发送了太多的令牌,那么Azure Open AI会用一个http状态400和一个包含错误代码的json响应体来回答。这个400状态会引发OpenAiClient的getChatCompletions方法抛出一个异常。
这个问题在这里处理:
langchain4j/langchain4j-azure-open-ai/src/main/java/dev/langchain4j/model/azure/AzureOpenAiChatModel.java
第313行到第336行
} catch (HttpResponseExceptionhttpResponseException) {
logger.info("Error generating response, {}", httpResponseException.getValue());
FinishReasonexceptionFinishReason = contentFilterManagement(httpResponseException, "content_filter");
Response<AiMessage> response = Response.from(
aiMessage(httpResponseException.getMessage()),
null,
exceptionFinishReason
);
ChatModelErrorContexterrorContext = newChatModelErrorContext(
httpResponseException,
modelListenerRequest,
null,
attributes
);
listeners.forEach(listener -> {
try {
listener.onError(errorContext);
} catch (Exceptione2) {
logger.warn("Exception while calling model listener", e2);
}
});
returnresponse;
}
辅助类只处理ContentFilter的情况。
langchain4j/langchain4j-azure-open-ai/src/main/java/dev/langchain4j/model/azure/InternalAzureOpenAiHelper.java
第337行到第359行
publicstaticFinishReasoncontentFilterManagement(HttpResponseExceptionhttpResponseException, StringcontentFilterCode) {
FinishReasonexceptionFinishReason = FinishReason.OTHER;
if (httpResponseException.getValue() instanceof Map) {
try {
Map<String, Object> error = (Map<String, Object>) httpResponseException.getValue();
ObjecterrorMap = error.get("error");
if (errorMapinstanceof Map) {
Map<String, Object> errorDetails = (Map<String, Object>) errorMap;
ObjecterrorCode = errorDetails.get("code");
if (errorCodeinstanceof String) {
Stringcode = (String) errorCode;
if (contentFilterCode.equals(code)) {
// The content was filtered by Azure OpenAI's content filter (for violence, self harm, or hate).
exceptionFinishReason = FinishReason.CONTENT_FILTER;
}
}
}
} catch (ClassCastExceptionclassCastException) {
logger.error("Error parsing error response from Azure OpenAI", classCastException);
}
}
returnexceptionFinishReason;
}
我认为它还应该管理令牌限制达到的情况,然后这个方法应该被重命名为例如TokenLimitReached。在当前实现中,我们得到了一个TokenLimitReached,但我们失去了达到了限制的事实(即使限制应该由业务应用程序正确管理;-)
7条答案
按热度按时间pod7payv1#
/cc @agoncal (azure), @jdubois (azure)
xyhw6mcr2#
我怀疑在这个情况下,400错误不应该Map到
FinishReason.LENGTH
。FinishReason.LENGTH
表示LLM产生了一些响应,但由于***输出***令牌限制已达到(无论是模型的最大令牌限制还是用户设置的maxTokens
),它未能完成(生成完整的响应)。400 HTTP错误意味着请求有问题,在这种情况下,***输入***令牌限制已达到。
xn1cxnb43#
你好@langchain4j
这是从com.azure.ai.openai.implementation.OpenAIClientImpl.getChatCompletionsSync(...)获取的返回消息:
所以,也许FinishReason.LENGTH不是正确的使用原因。但是,由于FinishReason是在类似于这里的http 400上计算的:
https://github.com/langchain4j/langchain4j/blob/0a706ecb444b114ef079613da3e7b4e1f3e1070a/langchain4j-azure-open-ai/src/main/java/dev/langchain4j/model/azure/AzureOpenAiLanguageModel.java#L233-240
我想,我们也可以管理context_length_exceeded。也许,我们可以引入一个FinishReason.REQUEST_LENGTH?或者我们应该只用FinishReason处理LLM响应和错误,然后使用另一个枚举来表示技术错误?
d5vmydt94#
在我的了解中,当请求LLM提供者成功(除了过滤内容之外)时,
FinishReason
是有意义的。如果请求有问题(400),那么这是一个开发者应该修复的bug。所以在这种情况下,我会抛出一个RuntimeException
。WDYT?7gs2gvoe5#
是的,我同意。
问题是,LanguageModel.generate(...)应该以某种功能性方式实现(即即使出现技术错误也始终返回一个Response对象,这也是它开始处理400和过滤内容的方式),还是应该用异常来实现?
2ul0zpep6#
我们通常在出现技术错误时抛出异常,我会遵循相同的风格,而不是引入一个新的。
gwbalxhn7#
@fb33 what's the status of this issue/PR? Should we close it?