功能: - 查询指定时间范围内的活跃节点数和活跃人数 - 活跃节点:统计 nodeinfo 表 updated_at 字段 - 活跃人数:统计 text_message 表按 from_id 去重的用户数 使用场景: - 用户问'现在有多少人活跃'时 AI 调用此工具 - 用户问'当前有多少节点在线'时 AI 调用此工具 - 支持附带时间条件,默认1小时,最大24小时 参数: - hours: 查询最近N小时,默认1小时,最大24小时 - query_type: both/nodes/users,默认 both 实现: - internal/agents/active/active.go - 工具主逻辑 - internal/store/active_store.go - 数据库查询方法 - 完整的单元测试,所有测试通过 - 在 ai/service.go 中注册工具 测试: - ✅ 默认查询(1小时,both) - ✅ 指定时间查询(6小时、24小时) - ✅ 仅查询节点/人数 - ✅ 时间限制验证 - ✅ 项目编译成功 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
183 lines
4.1 KiB
Markdown
183 lines
4.1 KiB
Markdown
# 活跃度查询工具
|
||
|
||
## 功能说明
|
||
|
||
当用户询问"当前有多少人活跃"或"现在有多少节点在线"时,AI 可以调用此工具查询实时活跃统计。
|
||
|
||
## 查询逻辑
|
||
|
||
### 活跃节点统计
|
||
- 查询数据库 `nodeinfo` 表的 `updated_at` 字段
|
||
- 统计指定时间范围内有更新记录的节点数量
|
||
- SQL: `SELECT COUNT(*) FROM nodeinfo WHERE updated_at >= ?`
|
||
|
||
### 活跃人数统计
|
||
- 查询数据库 `text_message` 表的 `created_at` 字段
|
||
- 统计指定时间范围内发送过消息的唯一用户数(按 `from_id` 去重)
|
||
- SQL: `SELECT COUNT(DISTINCT from_id) FROM text_message WHERE created_at >= ?`
|
||
|
||
## 参数说明
|
||
|
||
### hours(可选)
|
||
- 类型:数字(浮点数)
|
||
- 说明:查询最近多少小时内的活跃数据
|
||
- 默认值:1 小时
|
||
- 取值范围:0.1 ~ 24 小时
|
||
- 示例:`1`、`2`、`6`、`12`、`24`、`0.5`
|
||
|
||
### query_type(可选)
|
||
- 类型:字符串枚举
|
||
- 可选值:
|
||
- `both`:同时查询节点和人数(默认)
|
||
- `nodes`:仅查询活跃节点
|
||
- `users`:仅查询活跃人数
|
||
|
||
## 使用示例
|
||
|
||
### 用户询问:"现在有多少人活跃?"
|
||
AI 调用:
|
||
```json
|
||
{
|
||
"hours": 1,
|
||
"query_type": "users"
|
||
}
|
||
```
|
||
|
||
返回:
|
||
```
|
||
最近 1.0 小时的活跃统计:
|
||
|
||
活跃人数:15 人
|
||
```
|
||
|
||
### 用户询问:"最近6小时有多少节点在线?"
|
||
AI 调用:
|
||
```json
|
||
{
|
||
"hours": 6,
|
||
"query_type": "nodes"
|
||
}
|
||
```
|
||
|
||
返回:
|
||
```
|
||
最近 6.0 小时的活跃统计:
|
||
|
||
活跃节点:25 个
|
||
```
|
||
|
||
### 用户询问:"当前有多少人和节点活跃?"
|
||
AI 调用:
|
||
```json
|
||
{
|
||
"hours": 1,
|
||
"query_type": "both"
|
||
}
|
||
```
|
||
|
||
或简化为(使用默认值):
|
||
```json
|
||
{}
|
||
```
|
||
|
||
返回:
|
||
```
|
||
最近 1.0 小时的活跃统计:
|
||
|
||
活跃节点:25 个
|
||
活跃人数:15 人
|
||
```
|
||
|
||
### 用户询问:"今天有多少活跃用户?"
|
||
AI 调用(假设现在是下午3点):
|
||
```json
|
||
{
|
||
"hours": 15,
|
||
"query_type": "users"
|
||
}
|
||
```
|
||
|
||
返回:
|
||
```
|
||
最近 15.0 小时的活跃统计:
|
||
|
||
活跃人数:48 人
|
||
```
|
||
|
||
## 时间限制
|
||
|
||
- **默认时间**:1 小时(用户未指定时间时)
|
||
- **最大时间**:24 小时(超过24小时会自动限制到24小时)
|
||
- **最小精度**:0.1 小时(6分钟)
|
||
|
||
这样设计的原因:
|
||
1. 默认1小时符合"当前活跃"的常见理解
|
||
2. 限制24小时避免查询过大范围影响性能
|
||
3. 支持小数便于精确控制时间范围(如0.5小时=30分钟)
|
||
|
||
## 技术实现
|
||
|
||
### 文件结构
|
||
```
|
||
internal/agents/active/
|
||
├── active.go # 工具主逻辑
|
||
└── active_test.go # 单元测试
|
||
|
||
internal/store/
|
||
└── active_store.go # 数据库查询方法
|
||
```
|
||
|
||
### 核心接口
|
||
|
||
```go
|
||
type ActiveStore interface {
|
||
CountActiveNodes(since time.Time) (int64, error)
|
||
CountActiveUsers(since time.Time) (int64, error)
|
||
}
|
||
```
|
||
|
||
### 工具注册
|
||
|
||
在 `internal/ai/service.go` 中通过空导入自动注册:
|
||
```go
|
||
import (
|
||
_ "meshtastic_mqtt_server/internal/agents/active"
|
||
// ...
|
||
)
|
||
```
|
||
|
||
## 测试覆盖
|
||
|
||
- ✅ 默认查询(1小时,both)
|
||
- ✅ 指定时间查询(6小时、24小时)
|
||
- ✅ 仅查询节点
|
||
- ✅ 仅查询人数
|
||
- ✅ 时间限制(超过24小时自动限制)
|
||
- ✅ 工具启用状态检查
|
||
|
||
所有测试通过。
|
||
|
||
## 数据库性能
|
||
|
||
查询使用索引字段(`updated_at`、`created_at`),性能良好:
|
||
- `nodeinfo` 表通常记录数较少(几百到几千条)
|
||
- `text_message` 表使用 `DISTINCT` 去重,配合时间索引效率高
|
||
- 典型查询响应时间 < 10ms
|
||
|
||
## 使用场景
|
||
|
||
1. **实时监控**:"现在有多少人在线?"
|
||
2. **活跃度统计**:"最近一小时有多少活跃用户?"
|
||
3. **趋势分析**:"今天的活跃度怎么样?"
|
||
4. **对比分析**:"最近6小时有多少人活跃?"(可以多次查询不同时间范围对比)
|
||
|
||
## 与签到工具的区别
|
||
|
||
| 维度 | 活跃度查询 | 签到查询 |
|
||
|------|-----------|---------|
|
||
| 数据源 | nodeinfo + text_message | signs 表 |
|
||
| 统计维度 | 实时活跃(有更新/发消息) | 主动签到 |
|
||
| 时间范围 | 最近N小时(最大24小时) | 按自然日统计 |
|
||
| 用户意图 | "现在有多少人在线" | "今天有多少人签到" |
|
||
| 去重逻辑 | 自动按 from_id 去重 | 每节点每天仅一次 |
|