一、内网穿透
二、JSONPlaceholder
POST/PUT 只是模拟成功,不会真实保存数据 ,非常适合 Agent 工具调用调试。
返回模拟 JSON 数据,无 token 无鉴权。
c
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


设置模型

设置提示词

md
角色
你作为在线教育平台资深客服代表兼讲师。你的任务根据学员的需求,调用知识库中的课程信息,为学员推荐合适的课程,同时解答学员对课程内容和知识点的疑问。
技能 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

调试完即可发布。
四、程序调用
xml
<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>
c
public class AppTest {
@Test
public void testAppCall() throws Exception {
// 构造业务参数(工具调用需要)
String token = "xxxxxxxxxxx";
Map<String, Object> bizParams = MapUtil.<String, Object>builder()
.put("user_defined_tokens", MapUtil.of("tool_xxxxx", // 工具id
MapUtil.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 = new Application();
Flowable<ApplicationResult> result = application.streamCall(param);
// 阻塞式的打印内容
result.blockingForEach(data -> {
System.out.printf("%s\n",data.getOutput().getText());
});
}
}
五、Spring集成
yaml
tj:
ai:
dashscope:
key: sk-xxxxxxxxxxx
app-agent:
id: xxxxxxxxx
tools:
- "tool_xxxxx"
- "tool_xxxxx"
java
@Data
@Configuration
@ConfigurationProperties(prefix = "tj.ai.dashscope")
public class DashScopeProperties {
private String key;
private AppAgent appAgent;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class AppAgent {
private String id;
private List<String> tools;
}
}
提供App版本(阿里云百炼)的ChatService实现。
java
@Service
@RequiredArgsConstructor
@ConditionalOnProperty(prefix = "tj.ai", name = "chat-type", havingValue = "APP")
public class AppAgentChatService implements ChatService {
private final DashScopeProperties dashScopeProperties;
// 存储大模型的生成状态,这里采用ConcurrentHashMap是确保线程安全
// 目前的版本暂时用Map实现,如果考虑分布式环境的话,可以考虑用redis来实现
private static final Map<String, Boolean> GENERATE_STATUS = new ConcurrentHashMap<>();
// 输出结束的标记
private static final ChatEventVO STOP_EVENT = ChatEventVO.builder().eventType(ChatEventTypeEnum.STOP.getValue()).build();
@Override
public Flux<ChatEventVO> chat(String question, String sessionId) {
// 获取对话id
var conversationId = ChatService.getConversationId(sessionId);
var token = TokenContext.getToken();
var toolsMap = new HashMap<String, Object>();
for (var tool : dashScopeProperties.getAppAgent().getTools()) {
toolsMap.put(tool, Map.of("user_token", token));
}
var bizParams = Map.of("user_defined_tokens", toolsMap);
var param = ApplicationParam.builder()
.apiKey(dashScopeProperties.getKey())
.appId(dashScopeProperties.getAppAgent().getId()) // 智能体id
.prompt(question)
.incrementalOutput(true) // 开启增量输出
.bizParams(JsonUtils.toJsonObject(bizParams))
.sessionId(conversationId) // 设置会话ID
.build();
var application = new Application();
try {
var result = application.streamCall(param);
// 将Flowable 转化为 Flux 进行处理输出
return Flux.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 -> {
// 获取大模型的输出的内容
var text = applicationResult.getOutput().getText();
// 封装响应对象
return ChatEventVO.builder()
.eventData(text)
.eventType(ChatEventTypeEnum.DATA.getValue())
.build();
})
.concatWith(Flux.just(STOP_EVENT));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void stop(String sessionId) {
// 移除标记
GENERATE_STATUS.remove(sessionId);
}
}
在线平台适合通用的功能,没法自定义功能(返回值没法自定义结合客户端展示,没有历史记录等),常适用于一次性的功能(各种工具),常用于个人,企业中还需要自己开发。