问题重现
-
依赖
<!--讯飞开放平台sdk--> <dependency><groupId>io.github.briqt</groupId><artifactId>xunfei-spark4j</artifactId><version>1.3.0</version> </dependency>
-
yml配置文件
# 讯飞Api配置 xunfei:client:appId: "别只顾着抄,这里要写自己的"apiKey: "别只顾着抄,这里要写自己的"apiSecret: "别只顾着抄,这里要写自己的"
-
SparkConfig 配置类
java">@Configuration @ConfigurationProperties(prefix = "xunfei.client") @Data public class SparkConfig {private String appid;private String apiKey;private String apiSecret;@Beanpublic SparkClient sparkClient() {SparkClient sparkClient = new SparkClient();sparkClient.appid = this.appid;sparkClient.apiKey = this.apiKey;sparkClient.apiSecret = this.apiSecret;return sparkClient;} }
-
SparkManager 实现类
java">@Component @Slf4j public class SparkManager {@Resourceprivate SparkClient sparkClient;/*** AI生成问题的预设条件*/public static final String PRECONDITION = "" +"你是一名Java程序员\n" +"给我一些软件开发方面的知识\n";public String sendHttpToSpark(final String content){// 消息列表,可以再此列表添加历史对话记录List<SparkMessage> messages = new ArrayList<>();messages.add(SparkMessage.systemContent(PRECONDITION));// 用户输入内容messages.add(SparkMessage.userContent(content));// 构造请求SparkRequest sparkRequest = SparkRequest.builder()// 指定请求版本,lite为V1_5.apiVersion(SparkApiVersion.V1_5).messages(messages) // 消息列表.build();// 同步调用SparkSyncChatResponse chatResponse = sparkClient.chatSync(sparkRequest);String responseContent = chatResponse.getContent();log.info("spark返回内容:{}",responseContent);return responseContent;} }
可以到讯飞星火官网免费领取不限量的免费AI
完成以上步骤后,不出意外的话就能正常通过java代码调用Spark lite 的API进行 AI 对话,但遗憾的是出了意外
- 测试代码
java">@SpringBootTest
public class SparkManagerTest {@Resourceprivate SparkManager sparkManager;private final String userInput = "如何调用api";@Testpublic void testApi(){String result = sparkManager.sendHttpToSpark(userInput);System.out.println(result);}
}
- 报错截图
问题处理
一开始我怀疑的是自己的配置出了问题,但CV大法除了CV错地方外,还能怎么错呢?
刚好讯飞星火提供了免费的Spark Lite的同时,还赠送了不少Spark4.0 Uitra的token数,刚好可以拿来做验证
修改指定请求版本
java">public String sendHttpToSpark(final String content){List<SparkMessage> messages = new ArrayList<>();messages.add(SparkMessage.systemContent(PRECONDITION));messages.add(SparkMessage.userContent(content));SparkRequest sparkRequest = SparkRequest.builder()// 修改指定请求版本为4_0,其对应4.0Ultra.apiVersion(SparkApiVersion.V4_0).messages(messages) .build();SparkSyncChatResponse chatResponse = sparkClient.chatSync(sparkRequest);String responseContent = chatResponse.getContent();log.info("spark返回内容:{}",responseContent);return responseContent;
}
此时再运行测试代码可正常获取返回内容
然后看了源码后,也算是找到 Spark Lite 授权错误的原因,API版本枚举类(SparkApiVersion.class)中lite对应的V1_5版本中的domain属性是general
而不是 lite
为了使用免费版本的AI(仅限学习,经济压力大,学习阶段就搞付费的承受不起),自然得想方法处理。
需要注意的是,SparkApiVersion类中的构造方法是私有的,无法直接设值,所以我采用的是利用反射去修改值(不推荐,但这不对外,仅是学习AI才使用该方法;如有更好的方法,烦请告知)
编写EnumReflectionUtil工具类,用于修改枚举值
java">public class EnumReflectionUtil {public static void setEnumField(Enum<?> enumConstant, String fieldName, Object newValue) throws Exception {Field field = enumConstant.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(enumConstant, newValue);}
}
修改SparkManager类
java">@Component
@Slf4j
public class SparkManager {@Resourceprivate SparkClient sparkClient;@PostConstructpublic void init(){try {// 修改 V1_5 的版本信息EnumReflectionUtil.setEnumField(SparkApiVersion.V1_5, "version", "v1.1");EnumReflectionUtil.setEnumField(SparkApiVersion.V1_5, "url", "https://spark-api.xf-yun.com/v1.1/chat");EnumReflectionUtil.setEnumField(SparkApiVersion.V1_5, "domain", "lite");} catch (Exception e) {log.error("尝试修改枚举字段异常:", e);}}/*** AI生成问题的预设条件*/public static final String PRECONDITION = "" +"你是一名Java程序员\n" +"给我一些软件开发方面的知识\n";public String sendHttpToSpark(final String content){// 消息列表,可以再此列表添加历史对话记录List<SparkMessage> messages = new ArrayList<>();messages.add(SparkMessage.systemContent(PRECONDITION));// 用户输入内容messages.add(SparkMessage.userContent(content));// 构造请求SparkRequest sparkRequest = SparkRequest.builder()// 此时SparkApiVersion.V1_5的内容为修改后的内容.apiVersion(SparkApiVersion.V1_5).messages(messages) // 消息列表.build();// 同步调用SparkSyncChatResponse chatResponse = sparkClient.chatSync(sparkRequest);String responseContent = chatResponse.getContent();log.info("spark返回内容:{}",responseContent);return responseContent;}
}
此时再运行测试代码可正常获取返回内容,且增加的是Spark Lite的token数而非Spark4.0的,说明调用的是Spark Lite 无误