models: 加 local.{r1,qwen3} 内网模型档案,涉密任务用

DeepSeek-R1 (满血) + Qwen3-30B-A3B(服务端 alias 名是 Qwen/QwQ-32B,实际后端
Qwen3) 部署在 http://182.54.21.126:9000/v1,OpenAI 兼容,共享 LOCAL_LLM_API_KEY
env。thinking_mode=false(R1/Qwen3 默认就思考,不通过 reasoning_effort 控制)。

local.qwen3 已通连通性,local.r1 服务器侧调试中。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-05-28 15:55:37 +08:00
parent 4b7d7e6f77
commit cf23c9d178
3 changed files with 61 additions and 2 deletions

View File

@ -2,7 +2,7 @@
> 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9` > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`
最后更新:2026-05-28(修 docker backend LoadSkillTool 路径改写 + 新增 analyze skill + Python 3.10→3.12 升级 + Docker backend PYTHONPATH 修 + 3 个科学计算 skill smoke 通过) 最后更新:2026-05-28(新增 `local.r1` / `local.qwen3` 内网模型档案,涉密任务用)
--- ---
@ -23,6 +23,7 @@
### 2026-05-28 ### 2026-05-28
- **新增 `config/models/local.yaml`(family=`local`,variant `r1` / `qwen3`)接内网 OpenAI 兼容推理服务,涉密任务专用**:用户报建材院有些科研 / 立项 / 配方任务不能上公网模型(数据敏感),内部已部署 DeepSeek-R1(满血,调试中)+ Qwen3-30B-A3B(MoE)在 `http://182.54.21.126:9000/v1`(OpenAI 兼容,共享同一 key)。yaml 两个 variant `model_id``openai/DeepSeek-R1` / `openai/Qwen3-30B-A3B`(litellm provider 前缀 `openai/`,后段透传给 base_url),`api_base` 指内网 IP,`api_key_env` 同填 `LOCAL_LLM_API_KEY`。**上下文取舍**:R1 满血官方 128K → `max_context=131072 / reliable=65536`;Qwen3-30B-A3B 原生 32K → `max=32768 / reliable=16384`,reliable 给一半跟 deepseek_v4 / glm 档案比例一致。**`thinking_mode=false`** 是关键:R1 / Qwen3 是天生推理模型默认就思考(响应里带 `<think>` 标签),不通过 OpenAI / DeepSeek V4 的 `reasoning_effort` 等级控制 — 设 true 会发 reasoning_effort 字段,本地 vLLM / sglang 多半不认报 400。`tool_calling_quality=fair` 标注 R1 / Qwen3 tool use 弱于 V4 / GLM(routing 层用到的话会避开,目前只是文档标记)。`optimal_temperature=0.6` 按用户给的值。`.env` 加 `LOCAL_LLM_API_KEY`(用户已填实际值);`RUN.md` env 段同步加说明 + probe 命令两行(`local.r1` / `local.qwen3`)+ 最后更新日期改 2026-05-28。**初次连通性测试**:`local.qwen3` 跑通(15s,prompt=13 / completion=363,响应带 `<think>` 推理段);`local.r1` 当前 InternalServerError 500(服务器侧还在调试,非 yaml 问题)。**第二个 variant 原本写 `Qwen/QwQ-32B`,实测服务端返回 `model=Qwen3-30B-A3B` → 改 model_id + display_name 对齐真实部署的 MoE 模型**(Qwen3 系列 30B 总参 / 3B 激活,2025 阿里新出),variant key `qwq``qwen3` 跟着改。**不改 `agent.yaml` 默认模型**(`default_model` 仍 `deepseek_v4.flash`),涉密任务用户显式选;**未写"敏感任务自动路由本地模型"逻辑** — 当前没 sensitivity 标记机制,加是大改,先按显式选,要不要自动路由后面再说。否决:(a) family 叫 `private` / `intranet``local` 更短且语义对齐(本地推理服务);(b) `model_id` 不加 `openai/` 前缀 — litellm 不知走 OpenAI 兼容协议会按 model 名猜 provider 必跪;(c) reasoning_effort_levels 给 ["low","medium","high"] — 跟 thinking_mode=false 配相互矛盾,留空更干净;(d) 默 default_model 切到 local.r1 — R1 推理慢、tool calling 弱、且公网模型多数场景代价 / 质量更好,涉密是少数;(e) 在 `config/media/` 加同名 file — local 是 chat LLM 不是媒体生成,放 `config/models/` 才对。`DESIGN.md` 不动(新加 model 档案无架构变化)。
- **修 `LoadSkillTool` 在 docker backend 下返回 host 绝对路径导致容器内 fs 工具找不到 references 的 bug**:实测部署机 dogfood `analyze` skill 时,LLM 调 `load_skill('analyze')` 拿到 header `[skill=analyze, dir=/home/lighthouse/zcbot/skills/analyze]`,照 SKILL.md 教学拼 `<skill_dir>/references/pico_template.md``read` →"file not found"。**根因**:`core/executor_docker.py` 设计上 fs/shell/run_python 全走 `docker exec` 进容器(行 56-60 `CONTAINER_TOOLS`),skills/ bind mount 到容器内 `/sandbox/skills:ro`(`core/sandbox/pool.py:227-229`)—— 容器 namespace 里**没有 host 路径**(`/home/lighthouse/zcbot/...` 不存在),只有 `/sandbox/skills/analyze`。`LoadSkillTool` 跑在 host agent 进程里,塞给 LLM 的 `dir=...` 一直是 host 绝对路径,docker backend 下 LLM 用这条路径调容器内 read/glob/grep 必抓瞎。**为什么没早暴露**:proposal/research/ppt 这些 references-heavy skill 历史多在 host backend(开发期)跑通,docker backend 是部署期才打开;且 LLM 经常就着 SKILL.md 本体直接干活不去 read references,踩到的人不多;analyze 拆成 5 references 强制 read,首次集中暴露。**修法(A 候选,user 选)**:`LoadSkillTool` 加 `container_skills_dir: Optional[str]` 构造参数,有值时返回头 `dir=<container_skills_dir>/<skill_name>`(去重末尾斜杠),无值保持原 host 绝对路径。`agent_builder.py:392-405` 在装 LoadSkillTool 时复用 `select_executor` 同款 env 判断(`os.getenv("ZCBOT_SANDBOX_BACKEND")=="docker"`),为 True 时传 `"/sandbox/skills"`(与 pool.py mount target 一致)。`tests/test_load_skill.py` 4 case 锁住:host backend host 路径 / docker backend `/sandbox/skills/<name>` / 末尾斜杠拼接不双斜杠 / 未知 skill 报错走原路径。全套 4/4 PASS + `tests/test_executor_docker.py` 15/15 PASS 回归无破。**结构性收益**:所有现存 skill(proposal/ppt/research/coding/pymatgen/stats_ml/plot_pub/...)references 在 docker backend 下自动 work,不用一个个改 SKILL.md 教 LLM 用容器路径(那会破 host backend 开发环境)。**部署后操作**:部署机需 `git pull` 拉这条 commit + 重启 agent 进程让新代码生效(skill 注册表已经是每请求重建 §c4229be,但 LoadSkillTool 实例化在 build_agent 里,需要新进程或新连接才能拿到带 container_skills_dir 的实例)。否决:(b) bind mount host 路径到容器同样位置 —— 容器路径跟 host 强耦合,部署路径换地方就跪;(c) 改全部 SKILL.md 让 LLM 用 `/sandbox/skills/...` —— 散点改易漏,且 host backend 下 `/sandbox` 不存在,反破 dev 环境。`DESIGN.md` 不动(无架构变化,纯实现修);`RUN.md` 不动(无 CLI / env 变化)。 - **修 `LoadSkillTool` 在 docker backend 下返回 host 绝对路径导致容器内 fs 工具找不到 references 的 bug**:实测部署机 dogfood `analyze` skill 时,LLM 调 `load_skill('analyze')` 拿到 header `[skill=analyze, dir=/home/lighthouse/zcbot/skills/analyze]`,照 SKILL.md 教学拼 `<skill_dir>/references/pico_template.md``read` →"file not found"。**根因**:`core/executor_docker.py` 设计上 fs/shell/run_python 全走 `docker exec` 进容器(行 56-60 `CONTAINER_TOOLS`),skills/ bind mount 到容器内 `/sandbox/skills:ro`(`core/sandbox/pool.py:227-229`)—— 容器 namespace 里**没有 host 路径**(`/home/lighthouse/zcbot/...` 不存在),只有 `/sandbox/skills/analyze`。`LoadSkillTool` 跑在 host agent 进程里,塞给 LLM 的 `dir=...` 一直是 host 绝对路径,docker backend 下 LLM 用这条路径调容器内 read/glob/grep 必抓瞎。**为什么没早暴露**:proposal/research/ppt 这些 references-heavy skill 历史多在 host backend(开发期)跑通,docker backend 是部署期才打开;且 LLM 经常就着 SKILL.md 本体直接干活不去 read references,踩到的人不多;analyze 拆成 5 references 强制 read,首次集中暴露。**修法(A 候选,user 选)**:`LoadSkillTool` 加 `container_skills_dir: Optional[str]` 构造参数,有值时返回头 `dir=<container_skills_dir>/<skill_name>`(去重末尾斜杠),无值保持原 host 绝对路径。`agent_builder.py:392-405` 在装 LoadSkillTool 时复用 `select_executor` 同款 env 判断(`os.getenv("ZCBOT_SANDBOX_BACKEND")=="docker"`),为 True 时传 `"/sandbox/skills"`(与 pool.py mount target 一致)。`tests/test_load_skill.py` 4 case 锁住:host backend host 路径 / docker backend `/sandbox/skills/<name>` / 末尾斜杠拼接不双斜杠 / 未知 skill 报错走原路径。全套 4/4 PASS + `tests/test_executor_docker.py` 15/15 PASS 回归无破。**结构性收益**:所有现存 skill(proposal/ppt/research/coding/pymatgen/stats_ml/plot_pub/...)references 在 docker backend 下自动 work,不用一个个改 SKILL.md 教 LLM 用容器路径(那会破 host backend 开发环境)。**部署后操作**:部署机需 `git pull` 拉这条 commit + 重启 agent 进程让新代码生效(skill 注册表已经是每请求重建 §c4229be,但 LoadSkillTool 实例化在 build_agent 里,需要新进程或新连接才能拿到带 container_skills_dir 的实例)。否决:(b) bind mount host 路径到容器同样位置 —— 容器路径跟 host 强耦合,部署路径换地方就跪;(c) 改全部 SKILL.md 让 LLM 用 `/sandbox/skills/...` —— 散点改易漏,且 host backend 下 `/sandbox` 不存在,反破 dev 环境。`DESIGN.md` 不动(无架构变化,纯实现修);`RUN.md` 不动(无 CLI / env 变化)。
- **新增 `analyze` skill(科学问题分析 / 拆解 / 引导),服务建材院 R&D 早期问题翻译场景**:用户拿"模糊的高层科研问题"(典型句式"想搞清楚 X 原因 / 怎么提升 Y / 该不该做 Z")过来时,既不是写本子(proposal)/也不是查文献(research)/也不是建模(stats_ml),而是**问题还在概念阶段需要先想清楚**——之前 10 个 skill 没人接这个场景,模型只能凭直觉糊弄。本 skill 定位为"协调器 / 问题翻译器",**不执行任务**,只把模糊命题拆成可操作子问题 + 实施路线图,最终接力给下游 skill。**四段式工作流**:① PICO/PECO 规范化(P 对象 / I 干预 / C 对照 / O 量化输出 + FINER 五维自检)—— 卡 BLOCKING;② Issue Tree 拆解(MECE 原则,默认"机理-现象-工艺"三层,叶子节点标 `[类型 / 优先级 / 能力描述]`)—— 卡 BLOCKING;③ 按叶子类型分支深化:根因型走 Fishbone(六大支:材料/工艺/设备/检测/环境/人员)+ 5Whys、创新型走 First-principles 拆假设 + TRIZ 矛盾矩阵(摘 10 对建材常见冲突),优化型走 DoE 选型导航(PB/全因子/CCD/Box-Behnken/混料/序贯);④ 实施路线图 + TODO + 接力建议(`analysis.md` §6 每步四件事:干什么 / 能力描述 / 产物 / 判停条件)。**文件结构**:`skills/analyze/SKILL.md`(121 行)+ 5 份 references(78-95 行,按需 always read 或分支 read)+ 1 份 `templates/analysis_report.md`(87 行 = 最终 `analysis.md` 骨架),共 7 文件 657 行。**关键决策**:(a) **不硬编码"叶子能力 → skill 名"映射表** —— runtime 的 skill discovery 已经把所有 skill description 注入 prompt(DESIGN §3.5),硬编码等于重复 + 改名要回来改;改用"能力描述"(动词短语)让 LLM 按当时看到的 skill 清单自匹配;(b) **触发 description 双重防护** —— A 写死"还在想方向 / 不知道从哪入手"触发条件 + 显式列出何时不用(proposal/research/stats_ml/review 走对应 skill),B 在 §输出末尾推荐"下一步用 X 能力推进",前者拦"路由进"后者拦"路由出"卡死;(c) **不需要 Python helper** —— 全引导式对话 + markdown 输出,跟 review skill 同范式,无代码;(d) **TRIZ 不抄全 40 原理矩阵** —— 摘 10 对建材常见矛盾(强度↑韧性↑ / 早强↑后期↓ / 致密↑透气↑ 等),够 80% 场景 + 不污染上下文;(e) **DoE 选型表不生成实验点位** —— analyze 只规划设计类型 + 因素表,具体随机化 / 点位生成由下游 stats_ml 跑 pyDOE2,职责清晰;(f) **产物文件简单命名 `analysis.md`** —— 不学 proposal 的 `<today>-<short_id>-<name>.spec.md` 多版本机制(spec 是"宪法"需要定调一次,analysis 是工作文档迭代覆盖即可);(g) **examples 全打建材域**(P42.5 早强偏低 / 熔铸 AZS 砖热震 / 低碳水泥探索 / 矿粉粉煤灰配方 DoE),触发 description 保持领域无关(框架本身通用),只在 references 里塞建材 case 让 LLM 学场景适配。否决:(a) `proposal` 直接覆盖问题分析功能 —— proposal 已包含"先写要点再写正文"两段式,但那是"已定调要立项"之后的拆解,跟"还没决定要不要立项"的探索阶段语义不同;(b) 合并到 `research` —— research 是查文献执行能力,问题拆解不查文献也能做;(c) 写成 Python framework(自动拆解 + 自动 PICO 填空)—— 强行结构化反而压死开放探索,引导式对话更贴 R&D 实际节奏。`DESIGN.md` 不动(新加 skill 无架构变化);`RUN.md` 不动(无 CLI / env / 文件布局变化);`SCIENTIFIC_SKILLS.md` 不动(该文件是 K-Dense 仓库引进评估笔记,analyze 是自主设计不在其列)。 - **新增 `analyze` skill(科学问题分析 / 拆解 / 引导),服务建材院 R&D 早期问题翻译场景**:用户拿"模糊的高层科研问题"(典型句式"想搞清楚 X 原因 / 怎么提升 Y / 该不该做 Z")过来时,既不是写本子(proposal)/也不是查文献(research)/也不是建模(stats_ml),而是**问题还在概念阶段需要先想清楚**——之前 10 个 skill 没人接这个场景,模型只能凭直觉糊弄。本 skill 定位为"协调器 / 问题翻译器",**不执行任务**,只把模糊命题拆成可操作子问题 + 实施路线图,最终接力给下游 skill。**四段式工作流**:① PICO/PECO 规范化(P 对象 / I 干预 / C 对照 / O 量化输出 + FINER 五维自检)—— 卡 BLOCKING;② Issue Tree 拆解(MECE 原则,默认"机理-现象-工艺"三层,叶子节点标 `[类型 / 优先级 / 能力描述]`)—— 卡 BLOCKING;③ 按叶子类型分支深化:根因型走 Fishbone(六大支:材料/工艺/设备/检测/环境/人员)+ 5Whys、创新型走 First-principles 拆假设 + TRIZ 矛盾矩阵(摘 10 对建材常见冲突),优化型走 DoE 选型导航(PB/全因子/CCD/Box-Behnken/混料/序贯);④ 实施路线图 + TODO + 接力建议(`analysis.md` §6 每步四件事:干什么 / 能力描述 / 产物 / 判停条件)。**文件结构**:`skills/analyze/SKILL.md`(121 行)+ 5 份 references(78-95 行,按需 always read 或分支 read)+ 1 份 `templates/analysis_report.md`(87 行 = 最终 `analysis.md` 骨架),共 7 文件 657 行。**关键决策**:(a) **不硬编码"叶子能力 → skill 名"映射表** —— runtime 的 skill discovery 已经把所有 skill description 注入 prompt(DESIGN §3.5),硬编码等于重复 + 改名要回来改;改用"能力描述"(动词短语)让 LLM 按当时看到的 skill 清单自匹配;(b) **触发 description 双重防护** —— A 写死"还在想方向 / 不知道从哪入手"触发条件 + 显式列出何时不用(proposal/research/stats_ml/review 走对应 skill),B 在 §输出末尾推荐"下一步用 X 能力推进",前者拦"路由进"后者拦"路由出"卡死;(c) **不需要 Python helper** —— 全引导式对话 + markdown 输出,跟 review skill 同范式,无代码;(d) **TRIZ 不抄全 40 原理矩阵** —— 摘 10 对建材常见矛盾(强度↑韧性↑ / 早强↑后期↓ / 致密↑透气↑ 等),够 80% 场景 + 不污染上下文;(e) **DoE 选型表不生成实验点位** —— analyze 只规划设计类型 + 因素表,具体随机化 / 点位生成由下游 stats_ml 跑 pyDOE2,职责清晰;(f) **产物文件简单命名 `analysis.md`** —— 不学 proposal 的 `<today>-<short_id>-<name>.spec.md` 多版本机制(spec 是"宪法"需要定调一次,analysis 是工作文档迭代覆盖即可);(g) **examples 全打建材域**(P42.5 早强偏低 / 熔铸 AZS 砖热震 / 低碳水泥探索 / 矿粉粉煤灰配方 DoE),触发 description 保持领域无关(框架本身通用),只在 references 里塞建材 case 让 LLM 学场景适配。否决:(a) `proposal` 直接覆盖问题分析功能 —— proposal 已包含"先写要点再写正文"两段式,但那是"已定调要立项"之后的拆解,跟"还没决定要不要立项"的探索阶段语义不同;(b) 合并到 `research` —— research 是查文献执行能力,问题拆解不查文献也能做;(c) 写成 Python framework(自动拆解 + 自动 PICO 填空)—— 强行结构化反而压死开放探索,引导式对话更贴 R&D 实际节奏。`DESIGN.md` 不动(新加 skill 无架构变化);`RUN.md` 不动(无 CLI / env / 文件布局变化);`SCIENTIFIC_SKILLS.md` 不动(该文件是 K-Dense 仓库引进评估笔记,analyze 是自主设计不在其列)。
- **Python 3.10→3.12 升级(host + Dockerfile)+ DockerExecutor PYTHONPATH 加 `/sandbox` 修历史 import bug + 3 个科学 skill smoke 通过**:上一条加完 3 个科学 skill 后跑 smoke 发现 step D mp_rester 联网炸 `ImportError: cannot import name 'NotRequired' from 'typing'` —— Materials Project 官方依赖 `emmet-core 0.86.0rc1``outcar_adapter.py` 直接 `from typing import NotRequired`(3.11+ 才有,没走 `typing_extensions` 兜底),原 host .venv 是 Python 3.10.9 → mp-api 整链路 import 不进。**选 3.12 而非 3.11/3.13**:3.12 是当下 ML/AI 生态默认推荐版本(稳一年半 + 所有主流包预编译 wheel 覆盖完整),3.11 跟容器对齐但少一年优化,3.13 释放才半年冷门 wheel 偶尔退源码编译 Windows 上易踩坑(没新特性需求,激进升只是踩雷概率)。**实施**:① host py -3.12 -m venv 重建 .venv,pip install -r requirements.txt 装齐(pymatgen 2026.5.4 / mp-api 0.46.1 / emmet-core 0.86.4 / sklearn 1.8.0 / statsmodels 0.14.6 / numpy 2.4 / scipy 1.17 / matplotlib 3.10.9 / litellm / fastapi / sqlalchemy / 全套传递依赖);② Dockerfile FROM `python:3.11-slim``python:3.12-slim`(host / 容器同步升,部署机 rebuild image 时生效);③ **顺手修 `core/executor_docker.py:172` PYTHONPATH** `/workspace``/sandbox:/workspace`:历史 bug —— 多个 skill(`research/paper`、新加 `pymatgen/materials`、`plot_pub/style`)SKILL.md 都教 LLM `from skills.xxx.yyy import zzz`,host backend 因 base_dir=Path.cwd()(zcbot repo 根)注入 PYTHONPATH 能 work;docker backend 下容器只有 `PYTHONPATH=/workspace` + skills/ bind mount 到 `/sandbox/skills:ro`,`import skills.xxx` 找不到。本次加 `/sandbox` 前缀(在 /workspace 前,让 skills 优先级高于用户 task 目录的同名 shadow),`tests/test_executor_docker.py:243-245` regression test 改 `assertIn("PYTHONPATH=/sandbox:/workspace", ...)`,**全套 15/15 PASS**。**smoke 实跑**:step A pymatgen helper + XRDCalculator MgO 11 个峰 ✅ / step B sklearn R²=0.575 + statsmodels R²=0.911 p≪0.05 ✅ / step C plot_pub SimHei + PNG+PDF 出图 ✅ / step D mp_rester 联网 ⚠️ 返 403 "Your IP/ASN blocked"(Materials Project 服务侧 IP 临时封禁,跟代码无关,LBNL 服务对中国大陆 IP 段或同 ASN abusive traffic 触发 → 等几小时自动解 / 邮件 support@materialsproject.org 报公网 IP 申请解封 / VPS 走代理 fallback)。**非阻塞**:pymatgen 本地功能(CIF I/O / XRDCalculator / SpacegroupAnalyzer / PhaseDiagram / VASP 输入)100% 能用,只是 `mp_rester` 在线查询暂不能用。否决:(a) 升 3.11(只跟容器对齐,少一年优化,3.12 同样兼容容器);(b) 升 3.13(释放半年,冷门 wheel 偶尔退源码编译 Windows 踩坑,激进升无收益);(c) pin `emmet-core<0.86` + `mp-api<0.45`(临时,下次 pip install 不 pin 又炸,且丢 emmet 新功能);(d) monkey patch `typing.NotRequired = typing_extensions.NotRequired`(hacky 且挡不住 mp_api 下游其他 3.11+ 假设);(e) executor PYTHONPATH 改 `/workspace:/sandbox`(/workspace 优先 → 用户 task 目录如果手贱建 `skills/` 同名子目录会 shadow 真 skills,/sandbox 在前更稳)。`DESIGN.md` 不动(纯实施层 Python 版本 + 容器 PYTHONPATH 修);`RUN.md` 不动(env 段 MP_API_KEY 已在上一条 skill commit 加入,Python 版本要求记 `requirements.txt` + Dockerfile 自表)。 - **Python 3.10→3.12 升级(host + Dockerfile)+ DockerExecutor PYTHONPATH 加 `/sandbox` 修历史 import bug + 3 个科学 skill smoke 通过**:上一条加完 3 个科学 skill 后跑 smoke 发现 step D mp_rester 联网炸 `ImportError: cannot import name 'NotRequired' from 'typing'` —— Materials Project 官方依赖 `emmet-core 0.86.0rc1``outcar_adapter.py` 直接 `from typing import NotRequired`(3.11+ 才有,没走 `typing_extensions` 兜底),原 host .venv 是 Python 3.10.9 → mp-api 整链路 import 不进。**选 3.12 而非 3.11/3.13**:3.12 是当下 ML/AI 生态默认推荐版本(稳一年半 + 所有主流包预编译 wheel 覆盖完整),3.11 跟容器对齐但少一年优化,3.13 释放才半年冷门 wheel 偶尔退源码编译 Windows 上易踩坑(没新特性需求,激进升只是踩雷概率)。**实施**:① host py -3.12 -m venv 重建 .venv,pip install -r requirements.txt 装齐(pymatgen 2026.5.4 / mp-api 0.46.1 / emmet-core 0.86.4 / sklearn 1.8.0 / statsmodels 0.14.6 / numpy 2.4 / scipy 1.17 / matplotlib 3.10.9 / litellm / fastapi / sqlalchemy / 全套传递依赖);② Dockerfile FROM `python:3.11-slim``python:3.12-slim`(host / 容器同步升,部署机 rebuild image 时生效);③ **顺手修 `core/executor_docker.py:172` PYTHONPATH** `/workspace``/sandbox:/workspace`:历史 bug —— 多个 skill(`research/paper`、新加 `pymatgen/materials`、`plot_pub/style`)SKILL.md 都教 LLM `from skills.xxx.yyy import zzz`,host backend 因 base_dir=Path.cwd()(zcbot repo 根)注入 PYTHONPATH 能 work;docker backend 下容器只有 `PYTHONPATH=/workspace` + skills/ bind mount 到 `/sandbox/skills:ro`,`import skills.xxx` 找不到。本次加 `/sandbox` 前缀(在 /workspace 前,让 skills 优先级高于用户 task 目录的同名 shadow),`tests/test_executor_docker.py:243-245` regression test 改 `assertIn("PYTHONPATH=/sandbox:/workspace", ...)`,**全套 15/15 PASS**。**smoke 实跑**:step A pymatgen helper + XRDCalculator MgO 11 个峰 ✅ / step B sklearn R²=0.575 + statsmodels R²=0.911 p≪0.05 ✅ / step C plot_pub SimHei + PNG+PDF 出图 ✅ / step D mp_rester 联网 ⚠️ 返 403 "Your IP/ASN blocked"(Materials Project 服务侧 IP 临时封禁,跟代码无关,LBNL 服务对中国大陆 IP 段或同 ASN abusive traffic 触发 → 等几小时自动解 / 邮件 support@materialsproject.org 报公网 IP 申请解封 / VPS 走代理 fallback)。**非阻塞**:pymatgen 本地功能(CIF I/O / XRDCalculator / SpacegroupAnalyzer / PhaseDiagram / VASP 输入)100% 能用,只是 `mp_rester` 在线查询暂不能用。否决:(a) 升 3.11(只跟容器对齐,少一年优化,3.12 同样兼容容器);(b) 升 3.13(释放半年,冷门 wheel 偶尔退源码编译 Windows 踩坑,激进升无收益);(c) pin `emmet-core<0.86` + `mp-api<0.45`(临时,下次 pip install 不 pin 又炸,且丢 emmet 新功能);(d) monkey patch `typing.NotRequired = typing_extensions.NotRequired`(hacky 且挡不住 mp_api 下游其他 3.11+ 假设);(e) executor PYTHONPATH 改 `/workspace:/sandbox`(/workspace 优先 → 用户 task 目录如果手贱建 `skills/` 同名子目录会 shadow 真 skills,/sandbox 在前更稳)。`DESIGN.md` 不动(纯实施层 Python 版本 + 容器 PYTHONPATH 修);`RUN.md` 不动(env 段 MP_API_KEY 已在上一条 skill commit 加入,Python 版本要求记 `requirements.txt` + Dockerfile 自表)。

8
RUN.md
View File

@ -2,7 +2,7 @@
> 怎么把 zcbot 跑起来。env / 常用命令 / 故障兜底。设计看 `DESIGN.md`,进度看 `PROGRESS.md` > 怎么把 zcbot 跑起来。env / 常用命令 / 故障兜底。设计看 `DESIGN.md`,进度看 `PROGRESS.md`
最后更新:2026-05-22(dev SPA 加 iframe embed 模式 — `?embed=1&parent_origin=...`,对接见 `EMBED.md`) 最后更新:2026-05-28(新增 `local.r1` / `local.qwen3` 内网模型档案,共享 `LOCAL_LLM_API_KEY`,涉密任务用)
--- ---
@ -24,6 +24,10 @@
# pymatgen skill 的 Materials Project 接入:可选。设了 pymatgen.materials.mp_rester() 才能用, # pymatgen skill 的 Materials Project 接入:可选。设了 pymatgen.materials.mp_rester() 才能用,
# 未设调用即抛 RuntimeError。申请 https://materialsproject.org/api(免费) # 未设调用即抛 RuntimeError。申请 https://materialsproject.org/api(免费)
MP_API_KEY=... MP_API_KEY=...
# 本地 / 内网部署 LLM(`config/models/local.yaml`,DeepSeek-R1 满血 / QwQ-32B 原生 32K,
# 共享同一台推理服务 http://182.54.21.126:9000/v1)。涉密任务用户显式选 `local.r1` / `local.qwq`
# 代替默认 deepseek_v4.flash;未设 env 时这两条 variant 调用即抛 RuntimeError(其他模型不影响)
LOCAL_LLM_API_KEY=...
ZCBOT_DB_URL=postgresql://user:pass@host:5432/zcbot ZCBOT_DB_URL=postgresql://user:pass@host:5432/zcbot
# main.py web 必填(probe/db/user 不验) # main.py web 必填(probe/db/user 不验)
PLATFORM_KEY=<≥16 字符随机串,platform 机器对机器入口校验> PLATFORM_KEY=<≥16 字符随机串,platform 机器对机器入口校验>
@ -76,6 +80,8 @@ python -m venv .venv
# 模型能力对账(费 token) # 模型能力对账(费 token)
.venv/Scripts/python.exe main.py probe --model deepseek_v4.flash .venv/Scripts/python.exe main.py probe --model deepseek_v4.flash
.venv/Scripts/python.exe main.py probe --model glm.pro # 智谱 GLM-5.1(走 litellm zai provider + 国内站 bigmodel.cn) .venv/Scripts/python.exe main.py probe --model glm.pro # 智谱 GLM-5.1(走 litellm zai provider + 国内站 bigmodel.cn)
.venv/Scripts/python.exe main.py probe --model local.r1 # 内网 DeepSeek-R1(满血,128K),涉密任务用;需 .env 设 LOCAL_LLM_API_KEY
.venv/Scripts/python.exe main.py probe --model local.qwen3 # 内网 Qwen3-30B-A3B(MoE,原生 32K);共享 LOCAL_LLM_API_KEY
# DB migration # DB migration
.venv/Scripts/python.exe main.py db upgrade head .venv/Scripts/python.exe main.py db upgrade head

52
config/models/local.yaml Normal file
View File

@ -0,0 +1,52 @@
# 本地 / 内网部署模型档案
# 走 OpenAI 兼容协议(litellm provider 前缀 `openai/`,后段为实际 model 字段透传给 base_url)。
# 涉密任务时用户显式选 local.r1 / local.qwq 代替默认 deepseek_v4.flash;不走自动路由。
# 两个 variant 共用同一台推理服务器(api_base 同),api_key_env 也共用 LOCAL_LLM_API_KEY。
# thinking_mode=false:R1 / QwQ 是天生推理模型,默认就思考,不通过 reasoning_effort 等级控制
# (那是 OpenAI / DeepSeek V4 风格);设 true 会发 reasoning_effort 字段,本地 vLLM / sglang
# 多半不认,报 400。
family: local
variants:
r1:
display_name: DeepSeek-R1 (内网)
model_id: openai/DeepSeek-R1
api_base: http://182.54.21.126:9000/v1
api_key_env: LOCAL_LLM_API_KEY
max_context: 131072
reliable_context: 65536
max_output: 8192
parallel_tools: false
tool_calling_quality: fair
thinking_mode: false
reasoning_effort_levels: []
default_reasoning_effort: ""
code_quality: good
enable_run_python: true
max_iterations: 50
optimal_temperature: 0.6
prompt_caching: false
extended_thinking: false
qwen3:
# 服务端是 router 代理,model 字段必须匹配它注册的 alias;此服务实际注册名是
# `Qwen/QwQ-32B`(部署者别名),后端跑的是 Qwen3-30B-A3B(响应 `model` 字段 echo 真名)。
# 改 alias 时只动 model_id;display_name / variant key 跟实际后端走(前端看到真名)。
display_name: Qwen3-30B-A3B (内网)
model_id: openai/Qwen/QwQ-32B
api_base: http://182.54.21.126:9000/v1
api_key_env: LOCAL_LLM_API_KEY
max_context: 32768
reliable_context: 16384
max_output: 8192
parallel_tools: false
tool_calling_quality: fair
thinking_mode: false
reasoning_effort_levels: []
default_reasoning_effort: ""
code_quality: good
enable_run_python: true
max_iterations: 50
optimal_temperature: 0.6
prompt_caching: false
extended_thinking: false