# 新 AI 助手部署与配置 新 AI 助手(`/ai-assistant` 页面)基于 AgentServer。设计见 `docs/ai-assistant-agentserver/`。本文是上线前需要**手动**完成的配置,按顺序执行。旧 Kiro 助手不受影响,不需要改动。 涉及的组件(同一台机器): | 组件 | 地址 | 说明 | | --- | --- | --- | | AgentServer | `http://127.0.0.1:8787`,后台 `/admin/` | systemd `agent-server`,用户 `agentsvc` | | fwh-agent-mcp(只读) | `http://127.0.0.1:8091/mcp/readonly` | systemd `fwh-agent-mcp`;旧地址 `/mcp` 仍可用 | | fwh-agent-mcp(写,二期) | `http://127.0.0.1:8091/mcp/ops` | 同一进程、同一端口,见第 1.4 节 | | ToolBox 后端 | `127.0.0.1:8301`,路由前缀 `/api` | systemd `fwh-toolbox-server` | | 对外入口 | Caddy → Apache `:8300` → `/fwh-toolbox/api` → `:8301/api` | 见第 7 节 | 部署目录 `/var/www/fwh-toolbox/server` 中的配置文件: | 文件 | 使用者 | 说明 | | --- | --- | --- | | `config.env` | 主服务 `fwh-toolbox-server` | 第 6 节的 `AGENT_*` 加在这里。**不要新建 `.env`**:程序优先读取 `./.env`,存在时 `config.env` 整个不再生效 | | `config.agent-mcp.env` | `fwh-agent-mcp` | 独立配置(第 1.1 节),不读 `config.env` | | `config.mcp.env` | 旧 Kiro MCP | 与新助手无关 | | `emspara.db` | 主服务、`fwh-agent-mcp` | EMS 参数(PID / VID)字典。部署脚本由 EMS 头文件生成并拷贝到这里(`service/cmd/deploy_emspara.sh`,`deploy_toolbox.sh` 与 `deploy_agent_mcp.sh` 都会调用);进程启动时加载到 Redis,Redis 中没有字典时自动重新加载。缺失时 `ems_param_lookup` 查不到任何编号 | ## 1. 部署 fwh-agent-mcp ### 1.1 创建独立配置 `config.agent-mcp.env` fwh-agent-mcp 只读自己的配置文件(`-config` 可指定,默认工作目录下的 `./config.agent-mcp.env`),文件缺失时拒绝启动。它只需要数据库与 Redis、FWH 生产与测试 API、Plane Web,这些值与 `config.env` 相同,可以照抄;令牌新生成。 下面的命令以示例文件为模板,从 `config.env` 原样复制同名配置,并生成新令牌(不在终端输出任何值): ```bash cd /var/www/fwh-toolbox/server test ! -e config.agent-mcp.env || echo "已存在,先确认是否要覆盖" TOKEN=$(openssl rand -hex 32) umask 077 awk -v token="$TOKEN" ' NR==FNR { if (match($0, /^[A-Z_]+=/)) { k=substr($0,1,RLENGTH-1); src[k]=$0 } ; next } /^AGENT_MCP_TOKEN=/ { print "AGENT_MCP_TOKEN=\"" token "\""; next } match($0, /^[A-Z_]+=/) { k=substr($0,1,RLENGTH-1); if ((k in src) && k !~ /^AGENT_MCP_/) { print src[k]; next } } { print } ' config.env ~/web/FranklinWH-ToolBox/deploy/config.agent-mcp.env.example > config.agent-mcp.env grep -n CHANGE_ME config.agent-mcp.env | cut -d= -f1 # 应无输出;有输出的项需要手动填写 ``` 也可以手动 `cp deploy/config.agent-mcp.env.example /var/www/fwh-toolbox/server/config.agent-mcp.env` 后按 `CHANGE_ME` 逐项填写,令牌用 `openssl rand -hex 32` 生成。 文件权限保持 `600`(服务以 root 运行,可以读取)。 ### 1.2 构建并安装服务 在仓库的 `service/` 目录下执行(脚本中的路径相对 `service/`,在 `service/cmd` 下执行会构建失败): ```bash cd ~/web/FranklinWH-ToolBox/service && ./cmd/deploy_agent_mcp.sh ``` 脚本会:构建 `fwh-agent-mcp` → 拷贝到 `/var/www/fwh-toolbox/server/` → 首次时安装 `/etc/systemd/system/fwh-agent-mcp.service` 并 `enable` → 检查 `config.agent-mcp.env` 与令牌 → 重启服务。需要 sudo。以后代码更新也是执行这一条。 ### 1.3 验证 ```bash systemctl is-active fwh-agent-mcp # active curl -s http://127.0.0.1:8091/healthz # ok journalctl -u fwh-agent-mcp -n 30 --no-pager # 启动日志;工具调用日志在 server/logs/agent-mcp.log ``` 带令牌列出工具(只读 `/mcp/readonly` 应为 45 个,写 `/mcp/ops` 应为 7 个): ```bash T=$(grep -oP '^AGENT_MCP_TOKEN="?\K[0-9a-f]+' /var/www/fwh-toolbox/server/config.agent-mcp.env) for p in readonly ops; do printf '%s: ' $p curl -s -X POST http://127.0.0.1:8091/mcp/$p -H "Authorization: Bearer $T" \ -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | grep -o '"name":"[a-z_]*"' | wc -l done ``` `/mcp/ops` 配置了单独令牌(见第 1.4 节)时,测试它要用那个令牌。 ### 1.4 写工具服务(二期,可选) 写工具集与只读工具集由同一个 `fwh-agent-mcp` 进程提供(unit 中 `-set=readonly,ops`),路径 `/mcp/ops`,不需要另外部署服务或端口。只想提供只读工具时,把 unit 改为 `-set=readonly`。 默认两个路径共用 `AGENT_MCP_TOKEN`。需要写工具集单独的令牌时,在 `config.agent-mcp.env` 中加 `AGENT_MCP_TOKEN_OPS=""` 后重启服务,AgentServer 中 `fwhops` 服务的请求头填这个令牌。 ## 2. 在 AgentServer 登记 MCP 服务 打开 AgentServer 后台 `/admin/`,进入 **能力 › MCP 服务 › 添加**: | 项 | 只读服务 | 写服务(二期) | | --- | --- | --- | | 传输方式 | 远程 HTTP | 远程 HTTP | | 显示名称 | FWH 业务数据 | FWH 业务操作 | | 服务名(工具名前缀) | `fwh` | `fwhops` | | 服务地址 | `http://127.0.0.1:8091/mcp/readonly` | `http://127.0.0.1:8091/mcp/ops` | | 请求头名称 | `Authorization` | `Authorization` | | 请求头值 | `Bearer <令牌>` | 同左;配置了 `AGENT_MCP_TOKEN_OPS` 时用它 | - **服务名必须用 `fwh` / `fwhops`**:技能中的工具名是 `mcp__gateway__fwh__*`。 - **服务地址末尾不带斜杠**:`.../mcp/readonly/` 或只写 `.../mcp/` 都返回 404。已经登记为 `http://127.0.0.1:8091/mcp` 的只读服务仍然可用,不必修改。 - **请求头值必须带 `Bearer ` 前缀**(`Bearer`、一个空格、64 位十六进制令牌),不带引号。用下面的命令直接得到完整的值,整行复制: ```bash grep -oP '^AGENT_MCP_TOKEN="?\K[0-9a-f]+' /var/www/fwh-toolbox/server/config.agent-mcp.env | sed 's/^/Bearer /' ``` - 编辑已保存的服务时,请求头值输入框留空表示保持原值;原值填错时要重新填写。 点“测试连接”,只读服务能列出 45 个工具、写服务 7 个后保存。只读服务的工具策略保持“直接调用”;写服务保持“跟随权限模式”。连接失败见第 9 节。 ## 3. 同步资料库 AgentServer 开启了 `ProtectHome`,读不到 `/home` 下的 Wiki,需要拷贝到 `/srv/agent-server/knowledge/`: ```bash deploy/scripts/sync_agent_knowledge.sh # 需要 sudo AGENT_KB_DRY_RUN=y deploy/scripts/sync_agent_knowledge.sh # 预演 ``` 源目录可用环境变量覆盖(`WIKI_DOCS_DIR`、`DATA_KB_DIR`),说明见脚本头部。同步采用**手动**方式:Wiki 或数据知识库更新后,需要时再运行一次上面的命令,不配置定时任务。 注意:`docs/knowledge` 目前是空目录,数据知识库需要补充内容后才有意义。 ## 4. 部署技能 `fwh-assistant` 技能源码在本仓库 `deploy/agent-assistant/skills/fwh-assistant/`(SKILL.md、references/、templates/company-template.pptx),不放进 AgentServer 仓库。 AgentServer 以“自定义技能”导入(AgentServer `docs/design/12-custom-skills.md`),技能 ID 为 `custom-skills:fwh-assistant`。后台入口:**能力 › 技能与插件 › 自定义技能**。两种方式任选其一。 ### 4.1 上传 zip(首次推荐) ```bash cd ~/web/FranklinWH-ToolBox/deploy/agent-assistant/skills && zip -r /tmp/fwh-assistant.zip fwh-assistant ``` 在自定义技能列表顶部点“上传 zip 导入”(云朵图标),选择 `/tmp/fwh-assistant.zip`,在审阅框中勾选 `fwh-assistant` 并确认,导入后即发布。以后技能更新需要重新打包上传。 ### 4.2 登记目录技能源(需要经常同步时) AgentServer 开启了 `ProtectHome`,看不到 `/home` 下的仓库目录,先拷贝到 home 以外: ```bash sudo mkdir -p /srv/agent-skill-sources sudo rsync -a --delete ~/web/FranklinWH-ToolBox/deploy/agent-assistant/skills/ /srv/agent-skill-sources/fwh-toolbox/ ``` 在“技能源”中添加目录 `/srv/agent-skill-sources/fwh-toolbox`,点“扫描并同步”,勾选 `fwh-assistant` 导入。技能更新后重新执行 rsync,再点“同步”(会显示文件差异,确认后发布)。 导入的技能默认只读,以仓库为准,不要在后台直接修改。 ## 5. AgentServer 后台配置 打开 AgentServer 后台 `/admin/`(本机 `http://127.0.0.1:8787/admin/`)。 1. **概览**:确认 Claude 已登录(未登录时点“登录”)。 2. **MCP 服务**:按第 2 节登记 `fwh`,“测试连接”通过。 3. **资料库 › 新增**: - `fwh-wiki`:路径 `/srv/agent-server/knowledge/fwh-wiki`,说明“FranklinWH 产品文档:硬件(aGate/aPower 等)、软件(PCS、调度、OTA 等)、系统(告警码表、事件列表、系统配置)”,只读; - `fwh-data-knowledge`:路径 `/srv/agent-server/knowledge/fwh-data-knowledge`,说明“ToolBox 数据字段与业务术语说明”,只读(`docs/knowledge` 有内容后再登记)。 4. **Profiles › 新建 `fwh-assistant`**: - 引擎 Claude,模型按需(如 sonnet); - 权限模式“需审批”; - 技能:`report-conventions`、`custom-skills:fwh-assistant`(第 4 节导入后出现在“自定义”分组;自定义技能必须单独勾选,“全部技能”不包含它); - 资料库:`fwh-wiki`(以及有内容后的 `fwh-data-knowledge`); - MCP 服务:`fwh`; - 文件访问:受限(只写工作区); - 系统提示词(可选):“你是 FranklinWH ToolBox 的 AI 助手,回答 FranklinWH 储能产品与运维数据相关的问题。用中文回答。” 5. **Profiles › 复制为 `fwh-assistant-ops`**(二期):在上一个基础上加勾 MCP 服务 `fwhops`。 6. **Playground**:选 `fwh-assistant`,问“站点 的概况和最近 7 天告警”,确认时间线中出现 `custom-skills:fwh-assistant` 与 `fwh` 工具调用、不弹审批。 7. **接入 › API Keys › 签发 Agent Key**(不是“签发 Bot Key”): | 项 | 填写 | | --- | --- | | 平台名称 | `fwh-toolbox` | | 可用的 Profile | `fwh-assistant`(二期加 `fwh-assistant-ops`) | | 默认 Profile | `fwh-assistant` | - Key 的明文**只显示一次**,立即复制;丢失只能吊销后重新签发。 - 在 **能力 › Profiles** 记下各 Profile 的 ID(`prf_…`),第 6 节要用。 - 页面提示的“设置 › 安全”中的 CORS 来源**不需要配置**:浏览器只请求 ToolBox 后端,由后端代理访问 AgentServer,Key 不出后端。 ## 6. ToolBox 后端配置 主服务的 `/var/www/fwh-toolbox/server/config.env` 增加以下配置(不要新建 `.env`:程序优先读取 `.env`,存在时 `config.env` 整个不再生效): | 配置项 | 说明 | | --- | --- | | `AGENT_ENABLED` | `true` 开启;未开启时“AI 助手”页面显示暂未开放,`/agent/*` 接口返回 403 | | `AGENT_SERVER_URL` | `http://127.0.0.1:8787` | | `AGENT_SERVER_API_KEY` | 第 5 节第 7 步签发的 Key,只放后端 | | `AGENT_PROFILE_DEFAULT` | `fwh-assistant` 的 ID(`prf_…`);留空时使用 Key 的默认 Profile | | `AGENT_PROFILE_BY_ROLE` | 可选:角色到 Profile,如 `ops:prf_yyy,admin:prf_zzz`,按顺序取第一个命中的 | | `AGENT_ALLOWED_ROLES` | 可选:允许使用的角色,逗号分隔;为空表示所有登录用户 | ### 6.1 写入配置 Key 不要贴到聊天、工单或命令行参数中。在服务器上执行下面的命令,粘贴 Key 时屏幕不回显: ```bash cd /var/www/fwh-toolbox/server grep -n '^AGENT_\(ENABLED\|SERVER\|PROFILE\|ALLOWED\)' config.env && echo "已有 AGENT_ 配置,请先检查,避免重复" read -rsp "AgentServer API Key: " KEY; echo read -rp "fwh-assistant 的 Profile ID (prf_...): " PRF cat >> config.env </stream`(SSE)。中间任何一层缓冲都会导致回答一段一段地出现或很久才出现。 ### 7.1 Apache(`/etc/apache2/sites-available/006-fwh-toolbox.conf`) 现有配置: ```apache ProxyPass /fwh-toolbox/api http://localhost:8301/api ProxyPassReverse /fwh-toolbox/api http://localhost:8301/api ``` 在它**之前**加一条(Apache 按配置顺序匹配,必须放在前面): ```apache # 新 AI 助手事件流(SSE):立即转发,长连接 ProxyPassMatch "^/fwh-toolbox/api/agent/v1/sessions/([^/]+)/stream$" "http://localhost:8301/api/agent/v1/sessions/$1/stream" flushpackets=on timeout=3600 ``` 然后 `sudo apachectl configtest && sudo systemctl reload apache2`。 ### 7.2 Caddy(`/etc/caddy/sites/002-lmt.zenpower.cc.caddy`、`001-link-ser.dev.caddy` 中的 fwh-toolbox 块) Caddy 对 `text/event-stream` 响应默认会立即刷新,通常不用改。若仍有缓冲,把现有块: ```caddy handle /fwh-toolbox/* { reverse_proxy localhost:8300 } ``` 改为: ```caddy handle /fwh-toolbox/* { reverse_proxy localhost:8300 { flush_interval -1 } } ``` 然后 `sudo caddy reload --config /etc/caddy/Caddyfile --force`。 ### 7.3 上传大小 AgentServer 默认单文件上限 50MB;ToolBox 后端代理与 Apache 不应小于这个值(Apache 默认不限制请求体;Fiber 的 `BodyLimit` 由后端配置)。 ## 8. 验证清单 - [ ] `curl http://127.0.0.1:8091/healthz` 返回 200;AgentServer 后台 MCP 服务 `fwh` 状态正常 - [ ] Playground 用 `fwh-assistant` 能查询站点数据 - [ ] ToolBox 登录后左侧有“AI 助手”,能新建会话并得到流式回答(文字逐字出现) - [ ] 回答中引用 Wiki 文档时能给出路径 - [ ] 多日功率流分析时,导出文件出现在工作区 `.agent/mcp/`,上下文中没有明细 - [ ] 用另一个账号打开别人的会话链接,提示无权访问 ## 9. 常见问题 ### 9.1 MCP 服务“测试连接”失败 | 报错 | 原因 | 处理 | | --- | --- | --- | | 连接失败 / `ECONNREFUSED` | fwh-agent-mcp 没有运行 | `systemctl status fwh-agent-mcp`;未安装时执行第 1.2 节;启动失败看 `journalctl -u fwh-agent-mcp -n 30` | | `Error POSTing to endpoint: 404 page not found` | 服务地址路径不对,或该工具集没有加载 | 地址必须是 `http://127.0.0.1:8091/mcp/readonly` 或 `/mcp/ops`,末尾不带 `/`;写服务 404 时检查 unit 的 `-set` 是否包含 `ops`(启动日志“加载工具集”) | | `{"jsonrpc":"2.0","error":{"code":-32001,"message":"unauthorized"},"id":null}` | 请求头令牌不对 | 最常见是**值少了 `Bearer ` 前缀**;其次是复制了引号、请求头名称不是 `Authorization`、编辑时留空保留了旧的错误值。按第 2 节的命令重新生成完整的值填写 | 自检:在服务器上执行第 1.3 节的 `curl` 命令。本机能列出工具而后台仍失败,问题在后台填写的地址或请求头。 ### 9.2 fwh-agent-mcp 启动即退出 - `读取配置文件 ./config.agent-mcp.env 失败`:部署目录中没有该文件,按第 1.1 节创建。 - `AGENT_MCP_TOKEN 未配置`:配置文件中令牌为空。 - `初始化失败`:数据库、Redis 或 FWH API 配置有误,对照 `config.env` 检查同名项。