[MD]
# AIAssistant - Minecraft 基岩版 AI 助手插件
> **版本**: v1.1.1
> **平台**: LegacyScriptEngine (LSE) / Bedrock Dedicated Server (BDS)
> **语言**: JavaScript (QuickJS)
> **构建**: 全程由 Qwen3.8-Max-Preview 编写,零人工代码,零外部依赖
---
## 简介
AIAssistant 是一个运行在 LSE 脚本引擎上的 AI 助手插件。玩家可在游戏内直接与 AI 对话,AI 能自主调用工具访问网页、检索服务器知识库、记忆玩家信息,并实时统计 Token 用量。
所有功能均基于 LSE 内置 API 实现(`network`、`File`、`system.cmd`、`mc`、`JsonConfigFile`),无任何外部导入。
---
## 功能
| 功能 | 说明 |
|------|------|
| AI 对话 | `/ai <消息>` 游戏内直接对话,支持多轮上下文 |
| MCP 工具调用 | AI 自主调用:抓取网页、搜索知识库、保存玩家记忆 |
| 网页访问 | 纯手搓 HTML→文本转换,实时抓取网页内容 |
| 知识库 | `.md` 知识文件,AI 自动检索注入上下文 |
| 玩家记忆 | 每人独立持久化记忆,跨会话保留 |
| Token 统计 | 每次对话显示本次/累计用量 |
| 请求重试 | API 失败自动重试,可配置次数 |
| 消息回显 | 玩家消息以 `[你]` 前缀回显 |
| 自定义提示词 | 管理员可热更新系统提示词 |
---
## 安装
### 前置要求
- BDS + LegacyScriptEngine (LSE)
- 系统已安装 `curl`(Linux 通常自带,Windows 10+ 自带)
- 兼容 OpenAI API 格式的服务(OpenAI / DeepSeek / Moonshot / one-api 等)
### 步骤
1. 将 `AIAssistant.js` 放入 `plugins/AIAssistant/`
2. 启动服务器,自动生成 `config.json`、`knowledge_base/`、`memories/`
3. 编辑 `config.json` 填入 API 配置
4. 重启服务器
5. 游戏内 `/ai 你好` 测试
---
## 配置
`plugins/AIAssistant/config.json`:
| 配置项 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| `api_key` | String | — | API 密钥 |
| `base_url` | String | `https://api.openai.com/v1` | API 地址,自动补全 `/chat/completions` |
| `model` | String | `gpt-4o-mini` | 模型名称 |
| `system_prompt` | String | — | 系统提示词 |
| `max_history` | Integer | `10` | 保留对话轮数 |
| `max_tokens` | Integer | `2048` | 单次回复最大 Token |
| `temperature` | Float | `0.7` | 生成温度 |
| `enable_tools` | Boolean | `true` | 启用 MCP 工具调用 |
| `max_tool_rounds` | Integer | `5` | 单次对话最大工具调用轮数 |
| `max_retries` | Integer | `3` | 请求失败重试次数 |
| `web_fetch_max_length` | Integer | `3000` | 网页抓取最大字符数 |
| `kb_context_max_length` | Integer | `2000` | 知识库注入最大字符数 |
| `max_memory_facts` | Integer | `20` | 每玩家最大记忆条数 |
| `admin_xuid` | Array | `[]` | 管理员 XUID(OP 自动拥有权限) |
---
## 命令
### 玩家
| 命令 | 说明 |
|------|------|
| `/ai <消息>` | 与 AI 对话 |
| `/ai clear` | 清除对话历史 |
| `/ai memory` | 查看 AI 对你的记忆 |
| `/ai memory clear` | 清除记忆 |
| `/ai usage` | Token 用量统计 |
| `/ai help` | 帮助 |
### 管理员(OP)
| 命令 | 说明 |
|------|------|
| `/ai prompt` | 查看系统提示词 |
| `/ai prompt <新提示词>` | 设置提示词 |
| `/ai kb list` | 列出知识库文件 |
| `/ai kb add <名称> <内容>` | 添加知识条目 |
| `/ai kb remove <名称>` | 删除知识条目 |
| `/ai kb search <关键词>` | 搜索知识库 |
| `/ai kb scan` | 扫描目录,发现手动放入的 .md 文件 |
---
## 文件结构
```
plugins/AIAssistant/
├── AIAssistant.js ← 插件主文件
├── config.json ← 配置(自动生成)
├── knowledge_base/ ← 知识库
│ ├── _index.json ← 文件索引(自动维护)
│ ├── server_info.md ← 示例文件
│ └── *.md ← 自定义知识文件
└── memories/ ← 玩家记忆
└── <xuid>.json ← 每玩家独立文件
```
---
## 工作原理
### 对话流程
```
/ai <消息>
├─ 回显: [你] <消息>
├─ 构建 system prompt(提示词 + 玩家记忆 + 知识库上下文)
├─ curl 请求 AI API(Authorization: Bearer)
│ ├─ 失败 → 自动重试(最多 max_retries 次)
│ └─ 成功 → 检查 tool_calls
│ ├─ 有 → 执行工具 → 结果回传 → 继续生成(最多 max_tool_rounds 轮)
│ └─ 无 → 输出回复
├─ 显示回复
└─ 显示 Token 统计
```
### MCP 工具
| 工具 | 功能 | 玩家反馈 |
|------|------|----------|
| `fetch_webpage` | 抓取网页文本 | `[抓取网页] https://...` |
| `search_knowledge_base` | 搜索知识库 | `[搜索知识库] 关键词: "..."` |
| `save_player_memory` | 保存玩家信息 | `[保存记忆] ...` |
### 知识库
- `.md` 文件存放于 `knowledge_base/`,通过 `_index.json` 维护索引
- 每次对话根据玩家消息做关键词匹配,将相关片段注入 system prompt
- `/ai kb scan` 可扫描目录,发现手动放入的文件
### 玩家记忆
- 每玩家一个 `<xuid>.json`,持久存储
- AI 通过 `save_player_memory` 工具主动保存
- 下次对话自动注入 system prompt,跨会话生效
---
## 游戏内效果
```
> /ai 苦力怕怎么打
§7[你] §f苦力怕怎么打
§e[AI] §7思考中...
§e[AI] §7[抓取网页] §fhttps://minecraft.wiki/zh/wiki/苦力怕
§b[AI] §f苦力怕的打法:
1. 保持距离用弓射击
2. 近战打一下立刻后退
3. 盾牌可格挡爆炸
§8[Token: 本次 512 (提示:380+回复:132) | 累计: 20563 | 第48次]
```
```
> /ai memory
§e[AI记忆] §f共 3 条:
§7 1. §f玩家喜欢建筑,正在建中式城堡
§7 2. §f基地坐标 100, 64, 200
§7 3. §f养了一只叫"小白"的猫
```
```
> /ai usage
§e=== Token 用量 ===
§f玩家: §7Steve
§f请求次数: §748
§f提示Token: §715230
§f回复Token: §74821
§f总Token: §720051
§f首次: §72026-07-15
§f最近: §72026-07-21
```
---
## 技术要点
### 为什么用 `system.cmd` + curl
LSE 的 `network.httpPost(url, data, type, callback)` 中 `type` 仅为 Content-Type,无法设置 `Authorization` 等自定义 Header。通过 `system.cmd()` 调用系统 curl 可完整控制请求头。`system.cmd` 是 LSE 内置 API,不属于外部导入。
### 为什么用 `mc.newCommand` + `ParamType.RawText`
LSE 命令系统要求严格定义参数类型。`ParamType.RawText` 接收含空格的自由文本,适合对话场景。命令在 `onServerStarted` 事件中注册,通过 `origin.player` 获取玩家对象。
### HTML→文本转换
`htmlToText()` 纯正则实现:移除 `<script>`/`<style>`、块级标签转换行、剥离标签、解码 HTML 实体、清理空白。
---
## 兼容性
| API 提供商 | 状态 | base_url |
|------------|------|----------|
| OpenAI | ✅ | `https://api.openai.com/v1` |
| DeepSeek | ✅ | `https://api.deepseek.com/v1` |
| Moonshot | ✅ | `https://api.moonshot.cn/v1` |
| one-api / new-api | ✅ | 网关地址 |
| Azure OpenAI | ✅ | 需调整 URL |
| 任何 OpenAI 兼容 API | ✅ | 支持 `/v1/chat/completions` 即可 |
---
## 开发迭代记录
本插件全部代码由 **Qwen3.8-Max-Preview** 在对话中逐步构建,未使用外部代码库或模板。
| 版本 | 内容 |
|------|------|
| v1.0.0 | 初始版本 |
| v1.0.1 | 修正事件名 `onPlayerLeft` → `onLeft` |
| v1.0.2 | 改用 `mc.newCommand` + `ParamType.RawText`,修正 `origin.player` |
| v1.0.3 | 修正 URL 缺少 `/chat/completions`,改用 curl 支持 Authorization |
| v1.1.0 | 新增重试、消息回显、玩家记忆、Token 统计 |
| v1.1.1 | 修正知识库目录创建,新增工具调用反馈,新增 `/ai kb scan` |
---
## 许可证
自由使用,按需修改。
[/MD]