{"id":48556167,"url":"https://github.com/briqt/xunfei-spark4j","last_synced_at":"2026-04-08T11:02:57.700Z","repository":{"id":188023350,"uuid":"677984513","full_name":"briqt/xunfei-spark4j","owner":"briqt","description":"科大讯飞 星火认知大模型API Java SDK 流式调用、同步调用、FunctionCall、tokens统计、多版本切换；长期更新","archived":false,"fork":false,"pushed_at":"2024-07-15T07:22:06.000Z","size":98,"stargazers_count":83,"open_issues_count":1,"forks_count":11,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-07-15T08:53:32.367Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/briqt.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-13T09:58:47.000Z","updated_at":"2024-07-15T07:22:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"353dc490-71da-4a70-a8ff-ecd8d889af6f","html_url":"https://github.com/briqt/xunfei-spark4j","commit_stats":null,"previous_names":["briqt/xunfei-spark4j"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/briqt/xunfei-spark4j","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/briqt%2Fxunfei-spark4j","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/briqt%2Fxunfei-spark4j/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/briqt%2Fxunfei-spark4j/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/briqt%2Fxunfei-spark4j/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/briqt","download_url":"https://codeload.github.com/briqt/xunfei-spark4j/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/briqt%2Fxunfei-spark4j/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31551891,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T10:21:54.569Z","status":"ssl_error","status_checked_at":"2026-04-08T10:21:38.171Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-08T11:02:57.620Z","updated_at":"2026-04-08T11:02:57.694Z","avatar_url":"https://github.com/briqt.png","language":"Java","funding_links":[],"categories":["人工智能"],"sub_categories":["LLM客户端"],"readme":"# 科大讯飞星火认知大模型 Java SDK\n\nJDK：1.8\n\n项目依赖：`okhttp3`、`jackson` 、`slf4j-api`\n\n主要功能：\n\n- 流式调用问答接口\n- 同步调用问答接口\n- 完整的请求和响应数据对象封装，包括状态、用户ID、tokens统计等\n- 封装简化了webSocket对接，提供简单便捷的SparkClient\n- 完整的业务异常信息\n- function call\n\n\n\n## 使用方式\n\n\n\n### 引入项目\n\n\n```xml\n\u003c!--修改version为最新稳定版--\u003e\n\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.briqt\u003c/groupId\u003e\n    \u003cartifactId\u003exunfei-spark4j\u003c/artifactId\u003e\n    \u003cversion\u003e1.3.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### 创建客户端\n\n```java\nSparkClient sparkClient=new SparkClient();\n\n// 设置认证信息\nsparkClient.appid=\"\";\nsparkClient.apiKey=\"\";\nsparkClient.apiSecret=\"\";\n```\n\n### 同步调用\n\n```java\n// 消息列表，可以在此列表添加历史对话记录\nList\u003cSparkMessage\u003e messages=new ArrayList\u003c\u003e();\nmessages.add(SparkMessage.systemContent(\"请你扮演我的语文老师李老师，问我讲解问题问题，希望你可以保证知识准确，逻辑严谨。\"));\nmessages.add(SparkMessage.userContent(\"鲁迅和周树人小时候打过架吗？\"));\n// 构造请求\nSparkRequest sparkRequest=SparkRequest.builder()\n// 消息列表\n.messages(messages)\n// 模型回答的tokens的最大长度,非必传，默认为2048。\n// V1.5取值为[1,4096]\n// V2.0取值为[1,8192]\n// V3.0取值为[1,8192]\n.maxTokens(2048)\n// 核采样阈值。用于决定结果随机性,取值越高随机性越强即相同的问题得到的不同答案的可能性越高 非必传,取值为[0,1],默认为0.5\n.temperature(0.2)\n// 指定请求版本，默认使用最新3.0版本\n.apiVersion(SparkApiVersion.V3_0)\n.build();\n\ntry {\n    // 同步调用\n    SparkSyncChatResponse chatResponse = sparkClient.chatSync(sparkRequest);\n    SparkTextUsage textUsage = chatResponse.getTextUsage();\n    \n    System.out.println(\"\\n回答：\" + chatResponse.getContent());\n    System.out.println(\"\\n提问tokens：\" + textUsage.getPromptTokens()\n            + \"，回答tokens：\" + textUsage.getCompletionTokens()\n            + \"，总消耗tokens：\" + textUsage.getTotalTokens());\n} catch (SparkException e) {\n    System.out.println(\"发生异常了：\" + e.getMessage());\n}\n```\n\n控制台输出：\n\n```\n提问：[{\"role\":\"system\",\"content\":\"请你扮演我的语文老师李老师，问我讲解问题问题，希望你可以保证知识准确，逻辑严谨。\"},{\"role\":\"user\",\"content\":\"鲁迅和周树人小时候打过架吗？\"}]\n\n回答：是的，鲁迅和周树人小时候确实打过架。据周作人的回忆录《鲁迅的故事》记载，他和鲁迅小时候在私塾里学习时，因为争夺一张桌子而打了起来，结果两人都受了伤。不过，这次打架并没有影响他们之间的友谊和合作关系。\n\n提问tokens：66，回答tokens：68，总消耗tokens：134\n```\n\n### 流式调用\n\n- 继承`SparkBaseListener`，重写6个参数的`onMessage`方法，参考`SparkConsoleListener`\n\n```java\npublic class SparkConsoleListener extends SparkBaseListener {\n\n    private final StringBuilder stringBuilder = new StringBuilder();\n\n    public ObjectMapper objectMapper = new ObjectMapper();\n\n    {\n        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);\n    }\n\n    @Override\n    public void onMessage(String content, SparkResponseUsage usage, Integer status, SparkRequest sparkRequest, SparkResponse sparkResponse, WebSocket webSocket) {\n        stringBuilder.append(content);\n\n        if (0 == status) {\n            List\u003cSparkMessage\u003e messages = sparkRequest.getPayload().getMessage().getText();\n            try {\n                System.out.println(\"提问：\" + objectMapper.writeValueAsString(messages));\n            } catch (JsonProcessingException e) {\n                throw new RuntimeException(e);\n            }\n            System.out.println(\"\\n收到回答：\\n\");\n        }\n\n        try {\n            System.out.println(\"--content：\" + content + \" --完整响应：\" + objectMapper.writeValueAsString(sparkResponse));\n        } catch (JsonProcessingException e) {\n            throw new RuntimeException(e);\n        }\n\n        if (2 == status) {\n            System.out.println(\"\\n完整回答：\" + stringBuilder.toString());\n            SparkTextUsage textUsage = usage.getText();\n            System.out.println(\"\\n回答结束；提问tokens：\" + textUsage.getPromptTokens()\n                    + \"，回答tokens：\" + textUsage.getCompletionTokens()\n                    + \"，总消耗tokens：\" + textUsage.getTotalTokens());\n        }\n    }\n}\n```\n\n- 调用代码\n\n```java\n// 消息列表，可以在此列表添加历史对话记录\nList\u003cSparkMessage\u003e messages=new ArrayList\u003c\u003e();\nmessages.add(SparkMessage.userContent(\"请你扮演我的语文老师李老师，问我讲解问题问题，希望你可以保证知识准确，逻辑严谨。\"));\nmessages.add(SparkMessage.assistantContent(\"好的，这位同学，有什么问题需要李老师为你解答吗？\"));\nmessages.add(SparkMessage.userContent(\"鲁迅和周树人小时候打过架吗？\"));\n\n// 构造请求\nSparkRequest sparkRequest=SparkRequest.builder()\n// 消息列表\n.messages(messages)\n// 模型回答的tokens的最大长度,非必传，默认为2048。\n// V1.5取值为[1,4096]\n// V2.0取值为[1,8192]\n// V3.0取值为[1,8192]\n.maxTokens(2048)\n// 核采样阈值。用于决定结果随机性,取值越高随机性越强即相同的问题得到的不同答案的可能性越高 非必传,取值为[0,1],默认为0.5\n.temperature(0.2)\n.build();\n\n// 使用默认的控制台监听器，流式调用；\n// 实际使用时请继承SparkBaseListener自定义监听器实现\nsparkClient.chatStream(sparkRequest,new SparkConsoleListener());\n```\n\n控制台输出：\n\n```\n提问：[{\"role\":\"user\",\"content\":\"请你扮演我的语文老师李老师，问我讲解问题问题，希望你可以保证知识准确，逻辑严谨。\"},{\"role\":\"assistant\",\"content\":\"好的，这位同学，有什么问题需要李老师为你解答吗？\"},{\"role\":\"user\",\"content\":\"鲁迅和周树人小时候打过架吗？\"}]\n\n收到回答：\n\n--content：是--完整响应：{\"header\":{\"code\":0,\"status\":0,\"message\":\"Success\",\"sid\":\"xxx\"},\"payload\":{\"choices\":{\"status\":0,\"seq\":0,\"text\":[{\"role\":\"assistant\",\"content\":\"是\",\"index\":\"0\"}]}}}\n--content：的， --完整响应：{\"header\":{\"code\":0,\"status\":1,\"message\":\"Success\",\"sid\":\"xxx\"},\"payload\":{\"choices\":{\"status\":1,\"seq\":1,\"text\":[{\"role\":\"assistant\",\"content\":\"的，\",\"index\":\"0\"}]}}}\n--content：鲁迅和周--完整响应：{\"header\":{\"code\":0,\"status\":1,\"message\":\"Success\",\"sid\":\"xxx\"},\"payload\":{\"choices\":{\"status\":1,\"seq\":2,\"text\":[{\"role\":\"assistant\",\"content\":\"鲁迅和周\",\"index\":\"0\"}]}}}\n--content：树人小时候确实--完整响应：{\"header\":{\"code\":0,\"status\":1,\"message\":\"Success\",\"sid\":\"xxx\"},\"payload\":{\"choices\":{\"status\":1,\"seq\":3,\"text\":[{\"role\":\"assistant\",\"content\":\"树人小时候确实\",\"index\":\"0\"}]}}}\n--content：打过架。 --完整响应：{\"header\":{\"code\":0,\"status\":1,\"message\":\"Success\",\"sid\":\"xxx\"},\"payload\":{\"choices\":{\"status\":1,\"seq\":4,\"text\":[{\"role\":\"assistant\",\"content\":\"打过架。\",\"index\":\"0\"}]}}}\n--content：据周作人的回忆录《鲁迅的故事》记载，他和鲁迅小时候在浙江绍兴的一所私塾里读书，两人因为争夺一张桌子而打了起来，最终被老师分开。这件事情也成为了他们之间的一个小秘密。 --完整响应：{\"header\":{\"code\":0,\"status\":2,\"message\":\"Success\",\"sid\":\"xxx\"},\"payload\":{\"choices\":{\"status\":2,\"seq\":5,\"text\":[{\"role\":\"assistant\",\"content\":\"据周作人的回忆录《鲁迅的故事》记载，他和鲁迅小时候在浙江绍兴的一所私塾里读书，两人因为争夺一张桌子而打了起来，最终被老师分开。这件事情也成为了他们之间的一个小秘密。\",\"index\":\"0\"}]},\"usage\":{\"text\":{\"prompt_tokens\":66,\"completion_tokens\":65,\"total_tokens\":131,\"question_tokens\":20}}}}\n\n完整回答：是的，鲁迅和周树人小时候确实打过架。据周作人的回忆录《鲁迅的故事》记载，他和鲁迅小时候在浙江绍兴的一所私塾里读书，两人因为争夺一张桌子而打了起来，最终被老师分开。这件事情也成为了他们之间的一个小秘密。\n\n回答结束；提问tokens：66，回答tokens：65，总消耗tokens：131\n```\n\n### functionCall\n\n- 在请求时注册方法\n\n```java\n// 构造请求\nSparkRequest sparkRequest = SparkRequest.builder()\n        // 消息列表\n        .messages(messages)\n        // 使用functionCall功能版本需要大于等于3.0\n        .apiVersion(SparkApiVersion.V3_0)\n        // 添加方法，可多次调用添加多个方法\n        .addFunction(\n                // 回调时回传的方法名\n                SparkFunctionBuilder.functionName(\"stockPrice\")\n                        // 让大模型理解方法意图 方法描述\n                        .description(\"根据公司名称查询最新股票价格\")\n                        // 方法需要的参数。可多次调用添加多个参数\n                        .addParameterProperty(\"companyName\", \"string\", \"公司名称\")\n                        // 指定以上的参数哪些是必传的\n                        .addParameterRequired(\"companyName\").build()\n        ).build();\n```\n\n- 流式调用：需要重写`SparkBaseListener`的`onFunctionCall`方法，当会话触发functionCall时调用`onFunctionCall`方法，不再调用`onMessage`，其中第一个参数`SparkResponseFunctionCall`包含命中的方法名和具体参数。参考`SparkConsoleListener`写法。\n\n```java\n/**\n * 收到functionCall调用此方法\n *\n * @param functionCall  functionCall\n * @param usage         tokens消耗统计\n * @param status        会话状态，取值为[0,1,2]；0代表首次结果；1代表中间结果；2代表最后一个结果，当status为2时，webSocket连接会自动关闭\n * @param sparkRequest  本次会话的请求参数\n * @param sparkResponse 本次回调的响应数据\n * @param webSocket     本次会话的webSocket连接\n */\n@Override\npublic void onFunctionCall(SparkResponseFunctionCall functionCall, SparkResponseUsage usage, Integer status, SparkRequest sparkRequest, SparkResponse sparkResponse, WebSocket webSocket) {\n    String functionCallName = functionCall.getName();\n    Map\u003cString, Object\u003e arguments = functionCall.getMapArguments();\n\n    // 在这里根据方法名和参数自行调用方法实现\n\n    try {\n        System.out.println(\"\\n收到functionCall：方法名称：\" + functionCallName + \n                           \"，参数：\" + objectMapper.writeValueAsString(arguments));\n    } catch (JsonProcessingException e) {\n        throw new RuntimeException(e);\n    }\n}\n```\n\n- 同步调用：参考`SparkClientTest.functionCallTest()`\n\n```java\n// 同步调用\nSparkSyncChatResponse chatResponse = sparkClient.chatSync(sparkRequest);\nSparkTextUsage textUsage = chatResponse.getTextUsage();\nSparkResponseFunctionCall functionCall = chatResponse.getFunctionCall();\n\nif (null != functionCall) {\n    String functionName = functionCall.getName();\n    Map\u003cString, Object\u003e arguments = functionCall.getMapArguments();\n\n    System.out.println(\"\\n收到functionCall：方法名称：\" + functionName + \"，参数：\" + objectMapper.writeValueAsString(arguments));\n\n    // 在这里根据方法名和参数自行调用方法实现\n\n} else {\n    System.out.println(\"\\n回答：\" + chatResponse.getContent());\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbriqt%2Fxunfei-spark4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbriqt%2Fxunfei-spark4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbriqt%2Fxunfei-spark4j/lists"}