什么是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

一个测试112

测试评论

测试nas下jenkins打包2

封面

::: {.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

安装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。

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

前言

之前主要使用lastpass,目前是浏览器端免费,其它都要收费,而且密码存在别人服务器总是不放心。

所以我们要本地部署vaultwarden并且可以在各种Bitwarden正常使用。这里使用vaultwarden是因为相比原生更加轻量,占用资源极少。

部署

环境准备​​

​​服务器要求​​:腾讯云服务器(1核2GB内存,Ubuntu/Debian系统)。

​​开放端口​​:80(HTTP)、443(HTTPS),通过腾讯云控制台配置安全组

注:
如果家里本身就有公网ip,或者只是本地玩玩,是不需要公网服务器的。我这里公网服务器资源紧张,用来做转发,实际服务部署到内网机,所以公网和内网交互需要内网穿透,我这里使用的是zerotier。

内网机部署

为了方便从云服务器转发到内网,所以通过nginx包一层,给vaultwarden套一个前缀,比如:/bitwarden。否则云服务nginx转发会很乱

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
services:
nginx-proxy:
image: nginx:alpine
container_name: nginx-proxy
ports:
- "8000:80" # 对外暴露 HTTPS 端口
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl # 证书存储目录
networks:
- vaultwarden-net
depends_on:
- vaultwarden
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
networks:
- vaultwarden-net
volumes:
- ./vw-data/:/data/
expose: # 仅内部暴露端口,nginx能访问即可
- "80"
- "3012"

# 自定义网络(实现容器间通信)
networks:
vaultwarden-net:
driver: bridge

挂载目录结构如下

1
2
3
4
5
6
7
8
9
10
11
vaultwarden/
├── docker-compose.yaml
└── volumes
├── nginx
│   ├── conf.d
│   │   └── default.conf
│   ├── ssl
│   │   ├── certificate.crt
│   │   └── private.key
│   └── uwsgi_params
└── vw-data

conf.d/default.conf配置

这里nginx.conf会默认引入所有conf.d/*.conf

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
server {
listen 80;
listen [::]:80;
server_name localhost;

return 301 https://$host$request_uri; # 301 永久重定向

}

# HTTPS 主配置
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name localhost;

# SSL 证书配置(自签名示例,生产环境替换为 Let's Encrypt)
#ssl_certificate /etc/nginx/ssl/cert.pem;
#ssl_certificate_key /etc/nginx/ssl/privkey.pem;
ssl_certificate /etc/nginx/ssl/certificate.crt;
ssl_certificate_key /etc/nginx/ssl/private.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

# 静态文件服务(可选)
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}

# Vaultwarden 代理配置(核心修正)
location /bitwarden/ {
proxy_pass http://vaultwarden/; # 末尾斜杠确保移除路径前缀
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# 解决路径前缀导致的资源加载问题
proxy_redirect off;
sub_filter_once off;
sub_filter_types *;
sub_filter 'href="/' 'href="/bitwarden/';
sub_filter 'src="/' 'src="/bitwarden/';
}

# WebSocket 支持(实时同步), 自 v1.31.0 起,已移除对 3012 端口 WebSocket 流量的支持,因为它已集成至主 HTTP 端口。
location /bitwarden/notifications/hub {
proxy_pass http://vaultwarden:3012;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

# 错误页面配置(保持原样)
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

配置自签名证书

1
2
3
4
# 在docker-compose同级目录执行
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout ./volumes/nginx/ssl/private.key \
-out ./volumes/nginx/ssl/certificate.crt

服务启动

1
docker-compose up -d

测试访问

1
https://10.241.189.234:8443/bitwarden

公网ECS配置nginx(无域名)

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
cd /etc/nginx/conf.d

# 增加 234-proxy-443.conf, 这里一定要注意,把nginx.conf中server啥的都干掉,避免影响。

[root@VM-8-12-centos conf.d]# cat 234-proxy-443.conf
server {
listen 443 ssl;
server_name 替换为你的公网域名或IP; # 替换为你的公网域名或IP

# SSL 证书配置(必须使用有效证书,如 Let's Encrypt)
# ssl_certificate /etc/letsencrypt/live/your-public-domain.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/your-public-domain.com/privkey.pem;
ssl_certificate /etc/nginx/ssl/certificate.crt;
ssl_certificate_key /etc/nginx/ssl/private.key;


# 反向代理到内网服务
location /bitwarden {
proxy_pass https://10.241.189.234:8443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# 信任内网服务的自签名证书(可选)
proxy_ssl_verify off;
}

# 其他安全头配置
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
}

nginx -s reload

测试

1
2
3
https://ECS公网IP/bitwarden

# 这种方式配置后,在浏览器可以直接使用,包括插件。但是会提示证书不安全,手机端除非手动能安装自建证书,否则无法直接使用。

公网ECS配置nginx(有域名)

以腾讯ECS为例

域名配置

根据官方提示,将域名绑定到ECS机器

进行域名备案

调整nginx配置

使用免费或者付费的ssl证书,下载后替换nginx中配置的证书信息

1
2
3
# SSL 证书配置(必须使用有效证书)
ssl_certificate /etc/nginx/ssl/自己的域名.crt;
ssl_certificate_key /etc/nginx/ssl/自己的域名.xyz.key;

客户端配置

  1. 下载安装bitwarden相关客户端,包括app端,浏览器插件等
  2. 配置为自托管,然后按照自己设置的用户密码登录即可

备份

找一个自己觉得安全的地方备份自己的挂载(volumes目录),比如NAS或者网盘,U盘等

问题处理

console-log.service.ts:53 Unhandled error in angular Error: Could not instantiate WebCryptoFunctionService. Could not locate Subtle crypto.

分析处理

必须使用https访问,否则报错

安卓客户端无法访问,提示无法验证服务器证书

分析处理

这个真得有域名了。

前言:为什么企业需要警惕”AI军备竞赛”?

当前AI技术发展呈现”技术狂欢”态势,今天Deepseek火了跟一把,明天出来个其它看着高级的东西又跟一把。但企业实践中最常出现的问题在于:投入大量资源训练模型后,业务价值却难以量化。本文从业务出发,探讨如何让AI真正成为业务增长的助推器。

为什么AI是业务的必选项?

现在网上AI技术层出不穷,很多人通过ai来做一些日常工作,比如写写文章,查查资料,做做总结。高级一点的自己通过coze之类的平台做一些自己的AI工作流,智能体,通过各种组合提高自己的工作效率。

对于企业来说,如果自己在业务上能跟AI结合,能够从各方面提高自己产品的竞争力。

就以客服系统来说,有时候机器人客服回复的内容比较死板,很多都是通过内容匹配给出结果。但是使用AI以后能够充分利用AI的分析总结能力,将一些散落的知识分析总结,更加合理的提供给用户,甚至不仔细观察都以为是真人。相对于之前冷冰冰的知识,通过AI可以更好的提高客户体验,增强客户满意度和忠诚度。

为什么AI很难在企业中落地?

这里不是说落不了地,而是这么久了还没有爆炸性落地的产品。之前Deepseek火了,出来一拨”落地”热,基本上就是自己自己部署个模型或者搭建个简单知识库就敢说是落地。

其实AI无法落地主要的问题在于找不到切入点,还有行动力不足。首先是切入点问题,有些领导认为AI无所不能,上来就是高难度操作,认为只要部署个模型,挂个知识库,就可以让自己的产品智能了,用户问啥能干啥,也不需要那么多开发,测试,运营了。这种是完全被洗脑的,觉得AI就是神仙,无所不能,并不是所有场景适合硬往AI上套。还有一种是行动力不足,觉得AI现在发展还看不懂,不够成熟,准备再观察观察。

那么怎么让业务能跟AI更好的结合呢,下面我会给出一些自己在实践中的理解。

AI如何重塑核心场景?

正确认识AI

首先我们要对AI有个正确的认识,AI不是无所不能,并不是所有的场景都适合AI。AI本生是科技的产物,可以把它理解为一个拥有海量通用知识的业务小白。业务太庞杂了,对于一个行业内摸爬滚打多年的人都不敢说样样精通,并且很多业务不公开或者还需要随机应变,一些网上能下载到的通用大模型根本没有经过业务训练,不可能一上来就解决业务问题。

识别关键业务场景

之前说道网上有很多把AI玩出花的场景,也有很多解决实际问题的场景。为什么能出现这些东西,是因为大家会思考,能动手,知道自己要什么。比如我在没有AI之前也会通过程序脚本之类的各种玩意儿来解决自己实际问题,提高效率。对个人来说会思考,知道自己要什么,加一点点动手能力才能用好AI。

对于企业来说本身在行业深耕多年,业务就是企业最大的优势,应深入分析业务,在业务中找到与AI的结合点。AI的能力应该是解决实际问题,而不是为了应用AI而强行整合。再炫酷的操作如何用户不买账没有任何意义。最好是找三五个业务专家,再配合三五个对AI了解的工程师大家坐在一起,互相分享下业务场景,AI相关知识,多次分享讨论研究最终找出中间的结合点。

一定不要刚开始就给自己上强度,可以先找点场景试试demo,在做的过程中发现真正需要的场景再去挖掘。中小公司千万不要一上来就微调训练模型。刚开始的目标应该是业务+AI,业务为主,AI为辅,用业务驱动AI更快落地,最终让AI成为系统中一项不可分割的能力。

AI技术的应用案例

下边我给出一些业务中使用的案例,供大家参考,不同的企业有不同的业务,这里只抛砖引玉。

AI助理

首先是问答类的AI助理,这种是对知识库的应用。企业在多年发展过程中本身积累了不少行业知识,那么就可以整理调整为知识库供AI使用。如何做知识库之前文章也说过,最重要的是知识库的准确性,一般来说,整理成QA方式最方便知识库使用,可以先将一些系统操作手册,问题解决方案之类的东西做知识库,后边再扩展。

智能风控

在很多领域都有风控的处理,好一点的会使用一些规则库进行处理,如果差的直接就是硬编码了,这些规则一般都是来源于一些业务或者政策文件,需要翻译成程序能识别的规则才能使用。如果用AI,我们只需要把这些政策做到人能理解的程度,那么AI就可以结合规则在数据流转中进行控制,并按照预设的要求进行反馈,比如生成一个风控报告之类的。这种方式比通过程序处理更方便,不用单独再通过程序实现报告功能,还得需要程序去主动调用。

其它

每个企业的业务都不一样,主要是从业务入手,去发现。一定是奔着简化用户操作,优化用户体验去的场景,而不是为了AI而造出来的业务。

技术选型

业务再整合模型时一定不会只使用一种模型走天下,不同的模型有不同的优势。所以前期可以选择市面好用的编排工具,比如DIFY之类的,配置比较灵活,可以整合市面上绝大部分模型。

0%