Skip to content
Merged

Dev #48

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [1.10.0](https://github.com/TencentCloudBase/cloudbase-agent-ui/compare/v1.9.1...v1.10.0) (2025-04-23)


### Features

* support tencentmap card ([5c4437b](https://github.com/TencentCloudBase/cloudbase-agent-ui/commit/5c4437b3be43aca84433d2ae75ccfb21f6912cf3))


### Bug Fixes

* fix readme ([cee725d](https://github.com/TencentCloudBase/cloudbase-agent-ui/commit/cee725d566199b1865164e4687b5d45f8e6344c2))

### [1.9.1](https://github.com/TencentCloudBase/cloudbase-agent-ui/compare/v1.9.0...v1.9.1) (2025-04-21)


Expand Down
61 changes: 56 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,39 @@ Agent UI 演示效果图
- **企业级功能集成** 流式输出/联网搜索/深度思考/多轮会话 开箱即用
- **多模型支持** 深度兼容 DeepSeek、Hunyuan 等主流大模型
- **配置即开发** 通过配置快速接入组件能力,无需处理复杂通信逻辑
- **支持 MCP Server 调用&自定义工具卡片** 对接云开发MCP Server能力,支持开发者定制工具卡片展示

## 📦 使用指南

### 1. 开通环境
### 组件集成

#### 1. 开通环境

Agent UI 微信小程序组件依赖**微信云开发**服务,需先开通云开发环境

#### 1.1 开通微信云开发
##### 1.1 开通微信云开发

开通方式,点击开发者工具顶部“云开发” 进行开通

![](https://qcloudimg.tencent-cloud.cn/raw/f06ca4761f54ecc8ed8d9644229c92f9.png)

如已开通微信云开发服务,请跳转至[云开发平台](https://tcb.cloud.tencent.com/dev)创建AI服务。

#### 1.2、创建AI服务
##### 1.2、创建AI服务

- 方式一:直接使用agent智能体服务
![](https://qcloudimg.tencent-cloud.cn/raw/97786aaaa15aa1f23e9bbd39a7a6762f.png)
- 方式二:接入大模型
![](https://qcloudimg.tencent-cloud.cn/raw/876d2238b5331a7bdcbd91a1b38b8248.png)

### 2. 获取组件
#### 2. 获取组件

可通过以下两种方式获取组件包代码

1. **克隆仓库到本地,提取其中components/agent-ui 目录使用**
2. **下载GitHub Release 包 agent-ui.zip,直接使用**

### 3. 微信小程序项目引入组件
#### 3. 微信小程序项目引入组件

1. **配置云开发环境ID**
打开 miniprogram/app.js 文件,配置云开发环境ID。
Expand Down Expand Up @@ -117,6 +120,54 @@ Page({
})
```

### 自定义 MCP 工具卡片

> 以下示例流程以结合腾讯地图 MCP Server 开发自定义工具卡片举例说明

#### 1. 开通 MCP 能力

- 进入云开发平台 AI+ MCP 页面,点击创建MCP Server

![](https://qcloudimg.tencent-cloud.cn/raw/bc2a7815b542b26f5931aa835514dc37.png)

- 若未开通过云托管服务,需先开通云托管

![](https://qcloudimg.tencent-cloud.cn/raw/084b50f265e0335201801c3fb741d04d.png)

#### 2. 配置 MCP Server

- 以腾讯地图 MCP Server 举例,选择模板进行安装(按照指引获取腾讯地图平台API KEY后,配置环境变量)

![](https://qcloudimg.tencent-cloud.cn/raw/a5b15af9bfff83008257a0c99d252b83.png)

#### 3. agent 绑定 MCP Server tools

- 在 agent 配置页点击添加MCP 服务,选择对应的MCP Server tools 使用 (此处腾讯地图示例可勾选 geocoder,placeSearchNearby, directionDriving, weather等工具)

![](https://qcloudimg.tencent-cloud.cn/raw/b45a95e06ec0df8dab5c9d9ec7707faa.png)


#### 4. 开发自定义卡片组件

- 参照本工程中 apps/miniprogram-agent-ui/miniprogram/components/toolCard 目录内自定义工具卡片组件实现

![](https://qcloudimg.tencent-cloud.cn/raw/14a4a82810f0b45bde0c124cc8f3ed1c.png)

#### 5. 卡片组件引用配置

- 自定义卡片组件引用声明配置(可在用户小程序项目全局app.json中配置 或 agent-ui组件index.json中配置)

![](https://qcloudimg.tencent-cloud.cn/raw/cd1dc376a1e238f3186a2209e5875698.png)

- agent-ui 组件内 customCard/index.wxml 中添加自定义组件

![](https://qcloudimg.tencent-cloud.cn/raw/b4cd35ccaa3e72189934ed59d35f7ae5.png)

#### 6. 卡片效果

<img src="https://qcloudimg.tencent-cloud.cn/raw/82adcd08eec9443f8b8a336342a4fa23.png" width="375px">


## 🏗 项目结构

```bash
Expand Down
2 changes: 1 addition & 1 deletion apps/miniprogram-agent-ui/miniprogram/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ App({
// env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源
// 此处请填入环境 ID, 环境 ID 可打开云控制台查看
// 如不填则使用默认环境(第一个创建的环境)
env: "luke-agent-dev-7g1nc8tqc2ab76af",
env: "luke-personal-test-new-8d0d90f5f",
traceUser: true,
});
}
Expand Down
13 changes: 8 additions & 5 deletions apps/miniprogram-agent-ui/miniprogram/app.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
{
"pages": [
"pages/index/index",
"pages/chatBot/chatBot"
],
"pages": ["pages/index/index", "pages/chatBot/chatBot", "pages/foodBuy/foodBuy"],
"usingComponents": {
"custom-map": "/components/toolCard/map/index",
"custom-weather": "/components/toolCard/weather/index",
"custom-food-list": "/components/toolCard/food-list/index",
"custom-business-list": "/components/toolCard/business-list/index"
},
"window": {
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
Expand All @@ -20,4 +23,4 @@
"uploadFile": 60000,
"downloadFile": 60000
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Component({
properties: {
name: {
type: String,
value: "",
},
toolParams: {
type: Object,
value: {},
},
toolData: {
type: Object,
value: {},
},
},
data: {},
lifetimes: {},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!--components/agent-ui-new/chatFIle/chatFile.wxml-->
<!-- <text>components/agent-ui-new/chatFIle/chatFile.wxml</text> -->
<!-- <block>
<view wx:if="{{name === 'maps_geo' || name === 'maps_direction_driving'}}">
<custom-map name="{{name}}" toolData="{{toolData}}"></custom-map>
</view>
<view wx:if="{{name === 'maps_weather'}}">
<custom-weather name="{{name}}" toolData="{{toolData}}"></custom-weather>
</view>
<view wx:if="{{name === 'map_search_places'}}">
<custom-business-list name="{{name}}" toolData="{{toolData}}"></custom-business-list>
<custom-food-list name="{{name}}" toolData="{{toolData}}"></custom-food-list>
</view>
</block> -->

<block>
<view class="customCard">
<custom-map wx:if="{{name === 'geocoder' || name === 'placeSearchNearby' || 'directionDriving'}}" name="{{name}}" toolParams="{{toolParams}}" toolData="{{toolData}}"></custom-map>
</view>
<view class="customCard">
<custom-weather wx:if="{{name === 'weather'}}" name="{{name}}" toolData="{{toolData}}"></custom-weather>
</view>
<view class="customCard" wx:if="{{name === 'placeSearchNearby'}}">
<custom-business-list name="{{name}}" toolData="{{toolData}}"></custom-business-list>
</view>
<!-- 用户可类似添加自定义组件 -->
</block>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.customCard {
margin: 15px 0px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,7 @@ Component({
let endTime = null; // 记录结束思考时间
let index = 0;
for await (let event of res.eventStream) {
// console.log("event", event);
const { chatStatus } = this.data;
if (chatStatus === 0) {
isManuallyPaused = true;
Expand Down Expand Up @@ -1360,6 +1361,7 @@ Component({
const callBody = {
id: tool_call.id,
name: this.transformToolName(tool_call.function.name),
rawParams: tool_call.function.arguments,
callParams: "```json\n" + JSON.stringify(tool_call.function.arguments, null, 2) + "\n```",
content: "",
};
Expand All @@ -1376,9 +1378,11 @@ Component({
// tool_call 场景,调用响应
if (type === "tool-result") {
const { toolCallId, result } = dataJson;
// console.log("tool-result", result);
if (lastValue.toolCallList && lastValue.toolCallList.length) {
const lastToolCallObj = lastValue.toolCallList.find((item) => item.id === toolCallId);
if (lastToolCallObj && !lastToolCallObj.callResult) {
lastToolCallObj.rawResult = result;
lastToolCallObj.callResult = "```json\n" + JSON.stringify(result, null, 2) + "\n```";
this.setData({
[`chatRecords[${lastValueIndex}].toolCallList`]: lastValue.toolCallList,
Expand All @@ -1405,6 +1409,7 @@ Component({
[`chatRecords[${lastValueIndex}].content`]: lastValue.content,
});
}
// console.log("this.data.chatRecords", this.data.chatRecords);
this.setData({
chatStatus: 0,
[`chatRecords[${lastValueIndex}].hiddenBtnGround`]: isManuallyPaused,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"component": true,
"usingComponents": {
"markdownPreview":"/components/agent-ui/wd-markdown/index",
"FoldedCard":"/components/agent-ui/collapse/index",
"markdownPreview": "/components/agent-ui/wd-markdown/index",
"FoldedCard": "/components/agent-ui/collapse/index",
"chatFile": "/components/agent-ui/chatFile/index",
"feedback":"/components/agent-ui/feedback/index"
"feedback": "/components/agent-ui/feedback/index",
"customCard": "/components/agent-ui/customCard/index"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<image wx:if="{{bot.botId && showMultiConversation}}" class="con-icon" bind:tap="createNewConversation" src="./imgs/chat-bubble-add.svg" mode="aspectFill"/>
</view>
</view>
<view style="height: 100%;overflow: auto;position: relative;">
<view style="height: 100%;overflow: auto;position: relative;">
<!-- 聊天对话区 -->
<scroll-view bindwheel="onWheel" enhanced="{{true}}" bindscroll="onScroll" binddragstart="handleScrollStart" class="main" style="height: 100%;" scroll-y="{{true}}" scroll-top="{{viewTop}}" scroll-into-view="{{ scrollTo }}" lower-threshold="1" bindscrolltolower="handleScrollToLower" show-scrollbar="{{false}}" refresher-enabled="{{showPullRefresh && (bot.multiConversationEnable ? conversation : true)}}" refresher-threshold="{{80}}" bindrefresherrefresh="handleRefresh" refresher-triggered="{{triggered}}" bounces="{{false}}">
<view class="contentBox" style="margin-bottom: 30px;">
Expand Down Expand Up @@ -141,6 +141,7 @@
<markdownPreview markdown="{{subItem.callResult||''}}" fontSize="{{28}}"></markdownPreview>
</view>
</FoldedCard>
<customCard wx:if="{{subItem.rawResult}}" name="{{subItem.name}}" toolParams="{{subItem.rawParams}}" toolData="{{subItem.rawResult}}"></customCard>
</block>
</view>
<!-- 正文 -->
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
Component({
properties: {
// 组件的属性列表
name: {
type: String,
value: "",
},
toolData: {
type: Object,
value: {},
},
},
methods: {
// 点击卡片跳转到详情页
onCardTap(e) {
const id = e.currentTarget.dataset.id;
// wx.navigateTo({
// url: `/pages/restaurant-detail/index?id=${id}`,
// });
},

// 点击呼叫按钮
onCallTap(e) {
const phone = e.currentTarget.dataset.phone;
wx.makePhoneCall({
phoneNumber: phone,
fail: () => {
wx.showToast({
title: "呼叫失败",
icon: "none",
});
},
});
},
getRandomImage() {
const randomIndex = Math.floor(Math.random() * this.data.mockBusinessList.length);
return this.data.mockBusinessList[randomIndex];
},
},
lifetimes: {
attached() {
// 根据 name 区分处理不同 tool 调用情况
const { name, toolData } = this.data;
// 将详细的结构化地址转换为经纬度坐标
if (name === "placeSearchNearby") {
console.log("toolData", toolData);
const { content } = toolData;
if (content[0].type === "text") {
const contentData = JSON.parse(content[0].text);
const { data } = contentData;
console.log("placeSearchNearby data", data);
this.setData({
restaurants: data.map((item, index) => ({
// ...item,
image: this.getRandomImage(),
description: `私房菜 ${item.ad_info.city}${item.ad_info.district} 私房菜打卡人气榜第${index + 1}名`,
rating: 4.2,
reviews: 1923,
id: item.id,
name: item.title,
address: item.address,
telephone: item.tel,
category: item.category,
distance: item._distance,
city: item.ad_info.city,
area: item.ad_info.district,
})),
isFoodCategory: data[0].category.includes("美食"),
});
}
}
},
},
data: {
mockBusinessList: [
"https://poi-pic.cdn.bcebos.com/swd/a98b9547-20b8-3f4c-903b-51694ed27090.jpg",
"https://poi-pic.cdn.bcebos.com/swd/8fa8c9a7-f061-3bbe-9e1c-cf370e92e814.jpg",
"https://poi-pic.cdn.bcebos.com/swd/9c9a246a-463c-343f-8448-252edf2864ab.jpg",
"https://photo-meituan.cdn.bcebos.com/photo/1736586257678cf0aa25fcaa1c0d86c3e009da6448",
"https://photo-meituan.cdn.bcebos.com/photo/16922109814d07935406d27bf3e16a7844ae00fdef",
"https://poi-pic.cdn.bcebos.com/swd/3a633f56-991f-3d0b-ba5c-6517140c72f1.jpg",
"https://poi-pic.cdn.bcebos.com/swd/2652750e-fe5d-3827-9254-0e272ab904b2.jpg",
"https://poi-pic.cdn.bcebos.com/swd/90a78fdc-fecc-3930-9271-8095da7ad209.jpg",
// "https://qcloud.dpfile.com/pc/saQroau_MHTJgh_qZJ2aG…2vfCF2ubeXzk49OsGrXt_KYDCngOyCwZK-s3fqawWswzk.jpg",
"https://poi-pic.cdn.bcebos.com/swd/4061ecf3-e403-38de-9ad4-16549f4e8269.jpg",
"http://hiphotos.baidu.com/space/pic/item/e850352ac65c1038a7059ed5ba119313b07e89aa.jpg",
],
restaurants: [],
isFoodCategory: true, // 是否为美食分类
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}
Loading
Loading