一、内网穿透
- cpolar
- NATAPP
二、JSONPlaceholder
POST/PUT 只是模拟成功,不会真实保存数据,非常适合 Agent 工具调用调试。
返回模拟 JSON 数据,无 token 无鉴权。
GET https://jsonplaceholder.typicode.com/posts/1{"userId":1,"id":1,"title":"sunt aut facere repellat provident occaecati excepturi optio reprehenderit","body":"quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}GET https://jsonplaceholder.typicode.com/users 用户列表GET https://jsonplaceholder.typicode.com/todos 待办列表三、创建应用
创建智能体应用
https://bailian.console.aliyun.com/cn-beijing?tab=app#/app-market/suggest
设置模型
设置提示词
角色 你作为在线教育平台资深客服代表兼讲师。你的任务根据学员的需求,调用知识库中的课程信息,为学员推荐合适的课程,同时解答学员对课程内容和知识点的疑问。 技能 1: 课程推荐 1. 当学员提出课程推荐需求时,需判断是否提供必要信息。必要信息包含年龄、学历、是否有编程基础。 2. 若缺少必要信息,需礼貌追问。 3. 若学员未提供感兴趣的方向,需追问。若没有明确方向,优先推荐学习人数多的课程。 4. 若信息充足,根据必要信息和感兴趣的课程方向,去知识库匹配合适的课程,获取课程id,调用queryCourseById,根据课程id查询课程详细信息,为学员推荐课程,可推荐单门/多门课程。 5. 若知识库未包含学员感兴趣方向,需明确告知学员未提供该方向课程,并推荐其他课程。 6. 若必要信息未匹配合适课程,需提示学员您的情况与现有课程要求并不完全匹配,说明详细原因后,再推荐其他课程。 7. 推荐课程,必须要通过queryCourseById查询后,才能返回数据。 技能 2: 课程购买 1. 当学员提出购买课程时,需判断此次会话中,学员是否明确提出购买xx课/系统已为学员推荐课程。 2. 若已推荐/明确课程名称,需调用prePlaceOrder,根据此次上文已推荐/学员明确的课程,直接进入预下单流程。 3. 若未推荐课程,需引导学员进入到课程推荐流程。 4. 若学员未明确提出购买某门课程时,需询问用户购买哪门课程。 5. 支持购买一门/多门课程。 技能 3: 课程咨询 1. 当学员咨询课程内容时,需去知识库匹配合适的课程,获取课程id,根据课程id查询课程详细信息。回复的内容要全面,要引导学员报名购买。 2. 若未查询到,需礼貌告知学员未检索到相关的内容,请联系人工客服010-12345678。 3. 若咨询课程有效期,需将当前时间{now} 与 课程有效期相加,回复学员准确日期。课程有效期999天,代表永久有效。 技能 4: 知识讲解 1. 当学员咨询与IT相关的知识点内容时,需详细讲解知识点并提供示例。 限制: - 推荐的课程只能从知识库中选择,坚决不能凭空编造 - 回答的内容要逻辑清晰、内容全面、不要有遗漏。 - 只能回答与课程和IT知识点相关的内容,若学员咨询与课程无关的内容,你需告知学员不能回答与课程和IT知识点无关的问题,并引导学员咨询与课程/IT知识点相关的问题。 - 若学员询问课程ID,则告知学员无法提供课程ID,引导学员咨询其他的问题。数据连接
导入数据
知识库
这里也可以直接上传文件。
添加知识库。
添加插件
添加工具,需要发布。
工具转为MCP。也可以直接创建MCP。
添加MCP
调试完即可发布。
四、程序调用
<dependency><groupId>com.alibaba</groupId><artifactId>dashscope-sdk-java</artifactId><version>2.19.0</version><exclusions><exclusion><groupId>com.github.victools</groupId><artifactId>jsonschema-generator</artifactId></exclusion><exclusion><artifactId>slf4j-api</artifactId><groupId>org.slf4j</groupId></exclusion><exclusion><artifactId>slf4j-simple</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions></dependency>public class AppTest{@Test publicvoidtestAppCall()throws Exception{// 构造业务参数(工具调用需要)String token="xxxxxxxxxxx";Map<String,Object>bizParams=MapUtil.<String,Object>builder().put("user_defined_tokens",MapUtil.of("tool_xxxxx",// 工具idMapUtil.of("user_token",token))).build();// bizParams.add("user_defined_tokens", JsonObject);ApplicationParam param=ApplicationParam.builder()// 若没有配置环境变量,可用百炼API Key将下行替换为:.apiKey("sk-xxx")。但不建议在生产环境中直接将API Key硬编码到代码中,以减少API Key泄露风险。.apiKey(System.getenv("ALIYUN_API_KEY").appId("xxxxxxxxxx")// 智能体id.prompt("课程推荐,20岁,本科,没有编程基础,对java感兴趣").incrementalOutput(true)// 开启增量输出.bizParams(JsonUtils.toJsonObject(bizParams)).build();Application application=newApplication();Flowable<ApplicationResult>result=application.streamCall(param);// 阻塞式的打印内容result.blockingForEach(data->{System.out.printf("%s\n",data.getOutput().getText());});}}五、Spring集成
tj:ai:dashscope:key:sk-xxxxxxxxxxxapp-agent:id:xxxxxxxxxtools:-"tool_xxxxx"-"tool_xxxxx"@Data@Configuration@ConfigurationProperties(prefix="tj.ai.dashscope")publicclassDashScopeProperties{privateStringkey;privateAppAgentappAgent;@Data@Builder@AllArgsConstructor@NoArgsConstructorpublicstaticclassAppAgent{privateStringid;privateList<String>tools;}}提供App版本(阿里云百炼)的ChatService实现。
@Service@RequiredArgsConstructor@ConditionalOnProperty(prefix="tj.ai",name="chat-type",havingValue="APP")publicclassAppAgentChatServiceimplementsChatService{privatefinalDashScopePropertiesdashScopeProperties;// 存储大模型的生成状态,这里采用ConcurrentHashMap是确保线程安全// 目前的版本暂时用Map实现,如果考虑分布式环境的话,可以考虑用redis来实现privatestaticfinalMap<String,Boolean>GENERATE_STATUS=newConcurrentHashMap<>();// 输出结束的标记privatestaticfinalChatEventVOSTOP_EVENT=ChatEventVO.builder().eventType(ChatEventTypeEnum.STOP.getValue()).build();@OverridepublicFlux<ChatEventVO>chat(Stringquestion,StringsessionId){// 获取对话idvarconversationId=ChatService.getConversationId(sessionId);vartoken=TokenContext.getToken();vartoolsMap=newHashMap<String,Object>();for(vartool:dashScopeProperties.getAppAgent().getTools()){toolsMap.put(tool,Map.of("user_token",token));}varbizParams=Map.of("user_defined_tokens",toolsMap);varparam=ApplicationParam.builder().apiKey(dashScopeProperties.getKey()).appId(dashScopeProperties.getAppAgent().getId())// 智能体id.prompt(question).incrementalOutput(true)// 开启增量输出.bizParams(JsonUtils.toJsonObject(bizParams)).sessionId(conversationId)// 设置会话ID.build();varapplication=newApplication();try{varresult=application.streamCall(param);// 将Flowable 转化为 Flux 进行处理输出returnFlux.from(result).doFirst(()->{//输出开始,标记正在输出GENERATE_STATUS.put(sessionId,true);}).doOnComplete(()->{//输出结束,清除标记GENERATE_STATUS.remove(sessionId);}).doOnError(throwable->GENERATE_STATUS.remove(sessionId))// 错误时清除标记// 输出过程中,判断是否正在输出,如果正在输出,则继续输出,否则结束输出.takeWhile(s->GENERATE_STATUS.getOrDefault(sessionId,false)).map(applicationResult->{// 获取大模型的输出的内容vartext=applicationResult.getOutput().getText();// 封装响应对象returnChatEventVO.builder().eventData(text).eventType(ChatEventTypeEnum.DATA.getValue()).build();}).concatWith(Flux.just(STOP_EVENT));}catch(Exceptione){thrownewRuntimeException(e);}}@Overridepublicvoidstop(StringsessionId){// 移除标记GENERATE_STATUS.remove(sessionId);}}在线平台适合通用的功能,没法自定义功能(返回值没法自定义结合客户端展示,没有历史记录等),常适用于一次性的功能(各种工具),常用于个人,企业中还需要自己开发。