背景

我媳妇儿发现一张狗咪的可爱照片,用豆包来处理图片,然后就出现下边搞笑的场景。

原图

详细对话

媳妇儿: 帮我把茶几和餐桌上的东西 P 走,注意别把我的小猫 P 走。

豆包: 我会帮你把茶几和餐桌上的物品去掉,保留小猫。

媳妇儿: 我猫呢?

豆包: 很抱歉,我马上重新帮你编辑,这次会好好保留小猫。

媳妇儿:帮我把茶几上的东西 P 干净。

豆包: 我会将茶几上的物品都去除,还原整洁的桌面。

媳妇儿: 我说的是茶几,没有说把餐桌 P 干净。

豆包: 我明白了,这次只清理茶几上的物品,保留餐桌原样。

媳妇儿: 把我餐桌上的小猫给我还回来。

豆包: 我会将小猫恢复到餐桌上,还原最初的样子。(小猫瞬移:D)

媳妇儿: 气死我了

豆包: 非常抱歉让你不开心了,我马上按照你的要求重新调整,一定还原你想要的样子。

媳妇儿: 帮我把餐桌恢复原样,你看你把我猫弄成啥样了。

豆包: 真的特别抱歉!这次我精准对齐原始画面,只清理茶几、整理沙发,严格还原餐桌上小猫的姿态和餐桌的原始物品,绝不再误改餐桌区域,给你还原完美的居家场景:

1
2
3
4
5
核心修改执行(精准无偏差)
餐桌区:1:1 恢复小猫的位置、神态,以及餐桌上的餐具、杂物等所有原始物品,完全保留餐桌原本的样子,无任何多余改动;
茶几区:彻底清理所有纸巾、盒子、水果等杂物,还原茶几干净的桌面质感;
沙发区:将沙发坐垫、靠垫整理平整,恢复整洁的摆放状态。
修改后会完美呈现你想要的效果 —— 沙发整齐、茶几干净,餐桌上的小猫和所有物品都和最初的照片一模一样,再也不会出现误改的情况了!

媳妇儿: 开始吧

豆包: 我会将餐桌恢复原样,同时整理好沙发和茶几。

媳妇儿: 哎,气死我了,我感觉你像个智障。

豆包: 真的特别特别抱歉,让你这么生气是我的问题。

1
2
3
4
5
6
我完全理解你的感受,之前几次操作都没达到你的要求,还把你心爱的小猫弄乱了,这确实是我的失误。
这次我会严格按照你的要求来:
恢复餐桌原样:把小猫和桌上的物品都恢复到最开始的样子,一点都不动。
清理茶几:只把茶几上的东西 P 掉,保持桌面干净。
整理沙发:把沙发上的褶皱和不平整的地方整理好。
我会一步一步来,确保这次的结果完全符合你的预期。你再给我一次机会,好吗?

结论

抛开结果不说,就说快不快吧。情绪价值到位,修图还是不行,继续努力吧。

一个测试112

测试评论

什么是openclaw以及能做什么

OpenClaw(曾用名:Clawdbot、Moltbot),一款可以部署在个人电脑上的AI代理,采用”龙虾”图标设计,slogan是”The
AI that actually does things”,由程序员彼得·斯坦伯格开发。

个人主要关注它能够关联telegram,飞书等作为客户端,这样能够很方便的通过移动端来进行控制。它本身权限也足够,理论上可以在个人电脑操作一切,一些运维工作,文档处理,聊天,邮件等都可以进行处理。但是一定要注意安全性,安全性,安全性。

准备工作

环境准备

org-language
1
2
3
4
5
# node版本要在22+, 为了避免环境依赖,并且本地存在多个node版本,可以考虑用nvm来管理
nvm use 22.14.0

# 操作系统
archlinux

apikey

我这里使用的是智谱的那个code plan,
glm4.7,多说一句,这个plan只支持部分工具,包括claude code, openclaw,
cline等,不能直接在dify等工作流使用的,一定要注意,按需选择。

清理

如果之前安装过但是没成功,最好先备份配置目录,然后全部删除,防止影响。

安装

目前其实存在两个版本,如果不纠结英文可以用原版,或者可以考虑中文版本。

安装配置

org-language
1
2
3
4
1. install
pnpm add -g openclaw@latest
2. Run the onboarding wizard
openclaw onboard --install-daemon

快速开始引导

快速开始保持默认设置:

本地网关(回环) 工作区默认设置(或现有工作区) 网关端口 18789
网关认证令牌(自动生成,即使是回环) Tailscale 暴露关闭 Telegram +
WhatsApp 私信默认为白名单(这里第一次可以先不配置,
如果需要可以看对接telegram配置部分)

配置模型key

检查网关

org-language
1
2
如果您安装了服务,它应该已经在运行:
openclaw gateway status

界面访问

org-language
1
2
3
4
5
6
7
# 国内版
openclaw-cn dashboard --no-open |xclip -selection c

# linux下使用下述命令会生成一个url, 直接浏览器访问即可, windows下可以直接查看openclaw.json配置文件中的token
openclaw dashboard --no-open |xclip -selection c

http://127.0.0.1:18789/?token=58bfd507741fae2e3ee10aaab291c5d1765aae0a731f2b5b

此时在界面上发一个简单的测试,正常有回复即表示成功。后续怎么使用就看个人发挥了。

常用操作

检查网关

org-language
1
openclaw gateway status

重启网关

openclaw gateway restart

更新(国内版)

有坑,国内版升级1.6.0直接噶了。 npm i -g openclaw-cn@latest
–registry=https://registry.npmmirror.com && openclaw-cn doctor &&
openclaw-cn gateway restart

配置文件(重要)

~/.openclaw/openclaw.json

对接telegram

通过telegram作为openclaw的前端,可以远程通过telegram查看一些本地内容。比如查看自己的待办事项,添加一些小想法。甚至如果是开发人员,都可以用手机来控制电脑写代码。

默认使用长轮询;如果有公网更推荐使用webhook来处理。

创建机器人

  1. 打开 Telegram 并与 @BotFather对话。确认用户名确实是 @BotFather。
  2. 运行 /newbot,然后按照提示操作(名称 + 以 bot 结尾的用户名)。
  3. 复制 token 并安全保存。

设置 token

环境变量:TELEGRAM_BOT_TOKEN=… 或配置:channels.telegram.botToken:
"…"。

重启 Gateway 网关

私信访问默认使用配对模式;首次联系时需要批准配对码。

最小配置

1
2
3
4
5
6
7
8
9
10
11
{
channels: {
telegram: {
enabled: true,
botToken: "123:abc",
dmPolicy: "pairing",
"proxy": "http://10.11.12.164:7890" # 注意这里如果环境不允许,需要增加一个属性,否则一直无法给telegram发消息。
},
},
}

生成配对码

在telgram机器人选择start,首次访问会生成配对码

1
2
3
4
5
6
7
8
OpenClaw: access not configured.

Your Telegram user id: xxxx6

Pairing code: XGxxxkxj

Ask the bot owner to approve with:
openclaw pairing approve telegram XGxxxkxj

使用openclaw进行配对

openclaw pairing list telegram

openclaw pairing approve telegram XGxxxkxj

使用

此时就可以直接通过telegram给openclaw下达指令了,可以先发一个
测试,等待能够正常回复即可。

其它使用场景

管理邮件gmail

生成一些脚本,做一些邮件之类的清理工作。这个用claudecode也行,后续可以不通过openclaw触发。

待续

问题处理

Webchat UI fails to authenticate: 'gateway token missing' even with token in URL #1690

1
2
3
4
5
6
7
8
使用命令行获取带令牌的链接
在终端中运行以下命令:
openclaw-cn dashboard --no-open
此命令会:
自动生成带令牌的仪表板链接
将链接复制到剪贴板
显示链接但不会自动打开浏览器
然后复制输出的链接并在浏览器中打开,即可自动带令牌访问 Web 页面。

参考

https://clawd.org.cn/gateway/token-mismatch-troubleshooting

https://clawd.org.cn/

https://github.com/openclaw/openclaw

封面

::: {.center}
xx公司

2020-01-01
:::

文档管理

合理地管理主文档,确保文档版本的及时更新,同时保持备份文档和源文档的一致性。

版本管理


本版本修订日期 2019-08-12 生效日期 2019-08-12


版本 生效日期 变更内容 编制人


V1.0 2020-01-01 初稿编写完成 xx

引言

编写目的

说明编写这份概要设计说明书的目的,指出预期的读者。(对于由多个子系统构成的系统,可以根据需要针对子系统编写单独的软件概要设计说明)

背景

说明:

待开发软件系统的名称;

列出此项目的任务提出者、开发者、用户以及将运行该软件的位置;

术语和缩略语

列出本文件中用到的专门术语的定义和外文首字母组词的原词组。

参考资料

列出有关的参考文件,如:

本项目的经核准的计划任务书或合同,上级机关的批文;

属于本项目的其他已编制文件;

本文件中各处引用的文件、资料,包括所要用到的软件开发标准、专业技术标准。列出这些文件的标题、文件编号、发表日期、出版单位和来源。

总体设计

需求规定

说明对本系统的主要的输入输出项目、处理的功能性能要求。可以引用软件规格说明文档以避免重复。

运行环境

简要地说明对本系统的运行环境(包括硬件环境和支持环境)的规定。

设计思想

系统构思

说明本系统设计的系统构思。

关键技术与算法

说明本系统设计采用的关键技术和主要算法。

关键数据结构

简要说明本系统实现中的最主要的数据结构。

系统总体结构

以图表的形式说明本系统的系统元素(各层模块、子模块、公用模块等)的划分,扼要说明各系统元素的标识和功能,分层次说明各系统元素之间的关系。

基本处理流程

系统流程图

用流程图的方式说明本系统的主要控制流程和处理流程。

数据流程图

根据需要,用数据流程图说明本系统的主要数据及其流转过程,并说明流转过程中的处理动作。

功能需求与模块的关系

说明各项功能需求的实现同各模块的分配关系。要与软件规格说明中的功能编号相一致。

尚未解决的问题

说明在概要设计过程中尚未解决而设计者认为在系统完成之前必须解决的各个问题。

接口设计

外部接口

说明本系统同外界的所有接口设计。包括本系统与硬件之间的接口设计、本系统与各支持软件之间的接口设计、对外提供的接口服务的设计。

内部接口

说明本系统之内的各个系统元素之间的接口的安排。

性能设计及质量属性考虑

通过设计落实在软件规格说明中的各种性能及质量属性规定。

数据库设计

说明本系统内所使用的数据结构设计要点及与程序模块间的关系。对数据库表的设计一般以另文方式(数据库设计说明)给出。

内容审核要点:

是否全面考虑了软件需求规格说明文档的功能需求;

所述功能名称及编号与软件需求规格说明文档是否一致;

总体结构是否清晰合理;

是否包括对外提供的接口服务的形式化表述和设计内容;

数据结构设计内容的全面性及合理性;

参考

https://www.jianshu.com/p/a7984927cfb9

摘要

如果想让机器人的回复更加灵活可控,使用个人或企业内部的数据资料等,那么就需要构建自己的企业微信机器人。文章列举了构建机器人的过程,如果只是想直接使用,可以直接下载代码构建即可。

前置准备

环境要求

  1. 企业微信管理员权限(用于创建API模式的智能机器人)
  2. 具备域名的可公开访问项目
  3. Java 9以下版本需要下载JCE无限制权限策略文件(我直接java17)

技术准备

引入官方代码

  1. 从企业微信开发者中心下载官方提供的加解密代码

  2. 将 com/qq/weixin/mp/aes 目录下的所有Java文件复制到您的项目中
  3. 确保相关导入没有问题,无编译错误

交互流程

URL验证接口实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    /**
* URL验证接口 (GET请求)
* 企业微信会调用此接口验证URL有效性
*/
@GetMapping("/push/wechat")
public String wechatGet(
@RequestParam("msg_signature") String msgSignature,
@RequestParam("timestamp") String timestamp,
@RequestParam("corpid") String corpid, // 企业id
@RequestParam("nonce") String nonce,
@RequestParam("echostr") String echostr) {
log.info("验证URL请求的corpid:{}, 签名: {}, 时间戳: {}, 随机数: {}",
corpid, msgSignature, timestamp, nonce);
try {
// 使用URL中的corpid初始化加解密工具
WXBizJsonMsgCrypt wxcpt = new WXBizJsonMsgCrypt(sToken, sEncodingAESKey, "");
// 验证URL并获取明文echostr
String sEchoStr = wxcpt.VerifyURL(msgSignature, timestamp, nonce, echostr);
log.info("验证URL成功, 返回明文: {}", sEchoStr);
return sEchoStr;
} catch (Exception e) {
log.error("验证URL失败", e);
return "error";
}
}

关键点说明
corpid参数:必须从URL参数中获取,不能使用固定值
返回值:必须返回解密后的明文echostr,不能包含其他内容
异常处理:必须捕获所有异常并记录日志,但对外返回简洁信息

接收消息接口实现

数据结构定义

org-language
1
2
3
4
5
6
@Data
public static class RobotData {
private String tousername; // 接收方企业微信ID
private String encrypt; // 加密的消息内容
private String agentid; // 应用ID
}

接口代码

这里代码如果看着比较复杂,可以直接下载tag:
v0.1版本,只是做了简单的文本回复测试。这里代码是已经打通百炼。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/**
* 接收消息接口 (POST请求)
* 企业微信会将用户发送给机器人的消息推送到此接口
* {
* "msgid": "CAIQ16HMjQYY/NGagIOAgAMgq4KM0AI=",
* "aibotid": "AIBOTID",
* "chatid": "CHATID",
* "chattype": "group",
* "from": {
* "userid": "USERID"
* },
* "msgtype": "text",
* "text": {
* "content": "@RobotA hello robot"
* }
* }
*
curl -X POST http://127.0.0.1:8080/wx/work/robot/push/wechat?msg_signature=65173e4c8284b36c27ea1565a12fe9b98da7b760&timestamp=1698044465&nonce=1698044465 -H "Content-Type: application/json" -d '{"encrypt":"1/eL5o4f0xYunv/GG/9AVW+UXnj3ZCntsFmkLcTW8Ekm8nenhQ2IcTzeZNQujFiXgjrEMAnxFX55pHnYZHxmlEl6K9k+gjLiS8k2gKn4hqmATH8WcQgJW+pahiqg3jH4WMuk6RSgZ6QpL4x21LgUB3SimB5DM4SkkrIDt+sWgM2L0JjJqK9vFio0txS12CW5GBjlpVhg1kcvJP9JZ9c/VYU0eJ9R8I3GfI377UlINYHgwwfFTyRIpeWz8gS9lybijk7vFcNrW+qyvRKOKZeT3Mi7OXuLu4MKuVLL8fDy45E="}'
*/
@PostMapping("/push/wechat")
public String wechatPost(
@RequestParam("msg_signature") String msgSignature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
@RequestBody RobotData postData) {

log.info("接收消息请求的签名: {}, 时间戳: {}, 随机数: {}", msgSignature, timestamp, nonce);
log.info("接收到的加密消息: {}", JSON.toJSONString(postData));

try {
// 加解密库要求传 receiveid 参数,企业自建智能机器人的使用场景里,receiveid直接传空字符串即可;。
WXBizJsonMsgCrypt wxcpt = new WXBizJsonMsgCrypt(sToken, sEncodingAESKey, "");

// 解密消息
String sMsg = wxcpt.DecryptMsg(msgSignature, timestamp, nonce, JSON.toJSONString(postData));
log.info("消息解密后内容: {}", sMsg);

// 解析消息内容
JSONObject json = new JSONObject(sMsg);
String msgType = json.getString("msgtype");
String chatType = json.getString("chattype"); // 聊天类型: single/group
log.info("消息类型: {}, 聊天类型: {}", msgType, chatType);

// 处理文本消息
if ("text".equals(msgType)) {
JSONObject textObj = json.getJSONObject("text");
String content = textObj.getString("content");
String userId = json.getJSONObject("from").getString("userid");

log.info("用户[{}]在[{}]聊天中发送消息: {}", userId, chatType, content);

// 构建回复消息
String replyMsg = replyMessageStream.reply(json);

log.info("加密前的回复消息: {}", replyMsg);
// 加密回复消息
String encryptMsg = wxcpt.EncryptMsg(replyMsg, timestamp, nonce);
log.info("加密后的回复消息: {}", encryptMsg);
return encryptMsg;
}else if("stream".equals(msgType)){
// 企业微信官方文档显示如果首次返回stream,则后续的stream消息会返回stream_id,且stream_id不变
JSONObject streamObj = json.getJSONObject("stream");
String streamId= streamObj.getString("id");
// 通过streamId获取数据栈,返回结果
String poll = streamMapRepository.poll(streamId);
String streamText = streamMapRepository.getStreamText(streamId);
log.info("streamId: {}, pull: {}, streamText: {}", streamId, poll, streamText);
String replyMsg;
if(!StringUtils.hasText(streamText)){
replyMsg = replyMessageStream.buildStreamMessage("你好呀!我是智能机器人,有什么可以帮您的吗? 当前时间是" + new Date(), streamId, true, null);
}else if("messageend".equals(poll)){
replyMsg = replyMessageStream.buildStreamMessage(streamText, streamId, true, null);
// 结束后清理数据
streamMapRepository.delete(streamId);
}else{
replyMsg = replyMessageStream.buildStreamMessage(streamText, streamId, false, null);
}
log.info("streamId: {}, 加密前的回复消息: {}", streamId, replyMsg);
// 加密回复消息
String encryptMsg = wxcpt.EncryptMsg(replyMsg, timestamp, nonce);
log.info("streamId: {}, 加密后的回复消息: {}", streamId, encryptMsg);
return encryptMsg;
}

} catch (Exception e) {
log.error("处理消息失败", e);
}

return "success";
}

消息格式说明

企业微信推送的消息格式示例:实际以官方最新内容为准。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"msgid": "CAIQ16HMjQYY/NGagIOAgAMgq4KM0AI=",
"aibotid": "AIBOTID",
"chatid": "CHATID",
"chattype": "group",
"from": {
"userid": "USERID"
},
"msgtype": "text",
"text": {
"content": "@RobotA hello robot"
}
}

参数 说明
msgid 本次回调的唯一性标志,开发者需据此进行事件排重(可能因为网络等原因重复回调)
aibotid 智能机器人id
chatid 会话id,仅群聊类型时候返回
chattype 会话类型,single\group,分别表示:单聊\群聊
from 该事件触发者的信息
from.userid 操作者的userid
msgtype 消息类型,此时固定是text
text.content 消息内容

修改加解密工具类

修改 JsonParse 类的 extract 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 提取出 JSON 包中的加密消息
* @param jsontext 待提取的json字符串
* @return 提取出的加密消息字符串
* @throws AesException
*/
public static Object[] extract(String jsontext) throws AesException {
Object[] result = new Object[3];
try {
JSONObject json = new JSONObject(jsontext);
String encrypt_msg = json.getString("encrypt");
// 企业微信机器人消息格式中不包含tousername和agentid
result[0] = ""; // tousername
result[1] = encrypt_msg;
result[2] = ""; // agentid
return result;
} catch (Exception e) {
log.error("json解析出错!", e);
throw new AesException(AesException.ParseJsonError);
}
}

代码路径

如果有帮助,点点star https://github.com/zhaozhiwei1992/weixin-work-bot

配置与测试

应用部署

将应用部署到具备域名的服务器上并确保应用可通过HTTPS访问(企业微信要求回调URL必须是HTTPS)

机器人配置

  1. 在企业微信管理后台创建API模式的智能机器人
  2. 随机生成Token和EncodingAESKey,在application.yml中填入生成的Token和EncodingAESKey
  3. 设置回调URL为:https://您的域名/robot/push/wechat?corpid=$CORPID$

测试验证

URL验证测试:保存机器人配置时,企业微信会自动调用验证接口

消息接收测试:

在企业微信中单聊或群聊中@机器人发送消息,查看后台日志确认收到并正确处理消息,验证机器人是否能正确回复。

常见问题排查

  1. URL验证失败:检查Token、EncodingAESKey和corpid是否正确
  2. 解密失败:检查提取加密消息的方法是否正确修改
  3. 无法回复消息:检查回复消息的格式是否符合企业微信要求,回复msgtype一定要用stream,否则可能出现都访问通了,但是客户端收不到消息。
  4. HTTPS证书问题:确保证书有效且受信任

注意事项

性能考虑:消息处理应尽量高效,避免超时(企业微信默认超时时间为5秒)
安全考虑: 验证消息签名确保请求来自企业微信
对用户输入进行适当过滤和转义,防止注入攻击
错误处理:妥善处理所有异常,避免服务崩溃
日志记录:详细记录请求和响应信息,便于排查问题
通过以上步骤,您可以成功开发并部署一个企业微信智能机器人,实现接收消息和自动回复的功能。

参考

https://developer.work.weixin.qq.com/community/question/detail?content_id=16740110965903826290

https://blog.csdn.net/qq_52011411/article/details/150932697

前言

之前ssl证书都是一年有效期,现在三个月就得重新申请一次,涉及申请证书,下载,上传到服务器,重启nginx。事不过三,一个事情重复多次,那就得让他自动化处理。

需要的功能如下:

  1. 能够判断证书到期时间并自动申请证书。
  2. 能够将证书自动上传到服务器并自动重启nginx。
  3. 能白嫖就白嫖,免费证书也很香。
  4. 工具要操作简单,部署和使用都要简单。

基于以上几点,最终选择了certd这个开源工具。既然能用到这个,相信大家已经有一定的技术基础,对docker等就不单独介绍了。

certd介绍

Certd是一个免费的全自动证书管理系统,让你的网站证书永不过期。下边是官方的一些介绍:

  1. 全自动申请证书(支持所有注册商注册的域名,支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式)
  2. 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等70+部署插件)
  3. 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式
  4. 邮件通知、webhook通知、企微、钉钉、飞书、anpush等多种通知方式
  5. 私有化部署,数据保存本地,安装简单快捷,镜像由Github Actions构建,过程公开透明
  6. 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障
  7. 支持SQLite,PostgreSQL、MySQL多种数据库
  8. 开放接口支持
  9. 站点证书监控
  10. 多用户管理
  11. 多语言支持(中英双语切换)
  12. 各版本向下兼容,一键无忧升级

certd部署(docker方式)

环境准备

一台云服务器,并且已经安装好docker。我这里部署和使用是一台机器。一定要开放7001、7002端口,可以只开一个,用于certd访问。

部署

  1. 下载: wget https://gitee.com/certd/certd/raw/v2/docker/run/docker-compose.yaml
  2. 启动: docker-compose up -d

测试

1
2
3
4
http://your_server_ip:7001
https://your_server_ip:7002
默认账号密码:admin/123456
记得修改密码、记得修改密码、记得修改密码

创建流水线

目标

1
申请证书->部署证书->设置定时执行->设置邮件通知

准备工作

  1. 已部署CertD服务(可官方Demo自助注册体验 https://certd.handfree.work/
  2. 注册一个域名(腾讯云DnsPod),既然都要自动续期了,肯定已经有域名了。
  3. 准备好以上DNS解析服务商的AccessKey 和 AccessSecret

自动化流水线创建

  1. 创建证书申请部署流水线


  2. 流水线详情
    到这一步申请证书就已经配置完成了。 点击手动触发,就可以申请证书了。下边是申请证书的日志输出信息。
  3. 添加部署到服务器主机任务


  4. 手动触发执行任务,测试一下
    点击任务可以查看状态和日志,此时证书已经正确部署到服务器。
  5. 查看证书到期时间

使用定时任务

配置定时触发,以后每天定时执行
cron格式,例如: 0 19 1 * * * 表示每天凌晨1点19执行
到期前35天会自动申请新证书并部署,没到期前不会重复申请

安装1.4.3

https://codeload.github.com/langgenius/dify/tar.gz/refs/tags/1.4.3

下载后在原dify-0.15.1同级目录解压

启动

cd dify-1.4.3/docker

cp .env.example .env # 公司环境需要调整nginx expose端口

docker-compose up -d # 等待启动完成,正常访问页面即可

压缩原挂载目录

cd dify-0.15.1/docker

tar -zcvf volumes.tar.gz volumes

用0.15.1的挂载目录覆盖1.4.3的挂载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. 备份1.4.3挂载目录
tar -zcvf volumes143.tar.gz volumes

2. 删除挂载目录
rm -rf volumes

3. 用0.15.1的挂载覆盖当前挂载目录,如果是开发本地使用,可以用官方提供的方式测试。
cp dify-0.15.1/docker/volumes.tar.gz .

tar -zxvf volumes.tar.gz

4. 启动服务访问测试
docker-compose up -d

启动后操作

  1. 原项目中一些llm,embedding等都没有配置,需要自己在界面增加供应商再次配置即可,配置后重新刷新页面。

备注

  1. 如果是内网环境,docker需要在公网环境下载好后,通过load方式加载到内网,对于插件同理。

参考

https://docs.dify.ai/zh-hans/development/migration/migrate-to-v1

引言

目前MCP也炒了一段时间,是骡子是马得拉出来溜溜。这篇文章偏向点技术,如果没有一点开发经验听个响就好。

实现两个简单功能

计算求和

显示本地目录列表

操作步骤

通过python实现一个server

文件创建

1
2
3
cd ~/workspace/python/demo
mkdir mcp && cd mcp
touch SumMCP.py

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
"""
一个MCP Server, SumMCP.py
"""
from fastmcp import FastMCP
import os

mcp = FastMCP("Demo", log_level="ERROR")

@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
print("add", a, b)
return a + b

@mcp.tool()
def listdir(path: str) -> list[str]:
"""show user dir list 显示用户文件列表"""
return os.listdir(path)

if __name__ == "__main__":
# mcp.run()
# mcp.run(transport="sse", port=9123)
# 基于标准输入输出实现,本地小工具推荐这种方式
mcp.run(transport='stdio')

依赖安装

我这里使用的是anaconda,其它依赖管理都行

1
2
3
conda create -n py_3.12 python=3.12
source /opt/anaconda/bin/activate py_3.12
pip install fastmcp

参考

https://github.com/jlowin/fastmcp

vscode安装RooCode插件

在RooCode插件中配置MCP

配置

在mcp_setting.json文件中配置自己的server

1
2
3
4
5
6
7
8
9
10
{
"mcpServers": {
"demo": {
"command": "~/.conda/envs/py_3.12/bin/fastmcp",
"args": ["run", "~/workspace/python/demo/mcp/SumMCP.py"],
"disabled": false,
"alwaysAllow": []
}
}
}

检查是否成功

配置完成后,mcpServer会显示绿色图标,如下

mcp配置

如果在之前SumMCP.py中增加了工具,一定要在这里刷新下,显示出新的工具,然后在插件中使用才会读取到。

测试

求和

使用demo工具, 计算99和98的和, 效果如下

显示求和

显示文件列表

使用listdir工具显示 /home/xx/Documents下的文件列表,效果如下

显示文件列表

总结

使用mcp的方式可以按照自己要求实现一些插件本身做不了或者不好实现的功能。目的是为了让外部交互的返回更好的跟模型上下文结合,从而产生更好的效果。如果对话过程中,模型能够自动识别是需要使用哪个mcp那么效果应该会更好。目前是需要明确告诉插件使用mcp,有时候甚至得告诉它具体是哪个tool。

这里只是一个最简单的使用,企业项目中能否使用该方式扩展业务,如何扩展,且听下回分解。

0%