forked from admin/PlantAI-rag-new
feat(capabilities): S6 Superpowers+S7 终验(文档/humanizer CJK 修复/验收脚本)
- prompts/superpowers_{review,answer_quality,minimal_code}.md + prompt_pack.py
- agentic_controller/answer_composer Superpowers 注入点(env 总闸,关态逐字节一致)
- compile_qa.sh: prompts/ 目录自动拷贝
- humanizer: CJK 逗号规则 + 引用保护收窄(只护标记本身,带引用句可润色)
- docs: README 能力矩阵+env 表 / ARCHITECTURE Gateway 章 / API §6 / PRD:17 /
TEST_CASES:126 多轮语义 / CHANGELOG
- tooling/cap/final_acceptance.sh 终验矩阵
- 终验: 金标 16/20 regressions=0, 多轮指代 PASS, 热加载 PID 不变 PASS,
Humanizer 开态「此外」消除且 22 引用保留, 五上游全绿, 7913 已释放
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -90,6 +90,40 @@ bash tests/smoke_upstreams.sh
|
|||||||
- 回滚窗(停而不删,30 天):QA 容器 `qa-normalized-formal-20260828`(7920)、methodology 宿主进程(8000)、7900 protected 容器
|
- 回滚窗(停而不删,30 天):QA 容器 `qa-normalized-formal-20260828`(7920)、methodology 宿主进程(8000)、7900 protected 容器
|
||||||
- 回滚方法:重启旧服务 + `sdk/.env` 加回四行覆盖(`QA_BASE_URL`/`RAG_BASE_URL`/`RAG_LEGACY_BASE_URL`/`RAG_ALT_BASE_URL`)→ `bff_restart`
|
- 回滚方法:重启旧服务 + `sdk/.env` 加回四行覆盖(`QA_BASE_URL`/`RAG_BASE_URL`/`RAG_LEGACY_BASE_URL`/`RAG_ALT_BASE_URL`)→ `bff_restart`
|
||||||
|
|
||||||
|
## 能力系统(Capability Gateway,2026-09-02 起)
|
||||||
|
|
||||||
|
### 能力矩阵
|
||||||
|
|
||||||
|
| 能力 | 类型 | 默认 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 多轮记忆 | SDK 层 | 开 | 同会话连续提问携带上文(最近 3 轮,检索仍独立执行) |
|
||||||
|
| 联网搜索 | QA Gateway(http provider) | 关 | KB 证据不足时补 PubMed/Crossref 文献([WEB: url] 引用) |
|
||||||
|
| 答案润色 Humanizer | SDK 层 | 关 | 9 类规则去 AI 行文痕迹(引用/表格/图片/代码块原样保留) |
|
||||||
|
| Superpowers 提示词包 | QA Gateway(prompt_pack) | 关 | 证据审查与答案自检强化(3 个 SKILL.md 注入) |
|
||||||
|
|
||||||
|
- 开关:设置面板(左栏底部齿轮,展开态「设置」按钮)→ 按会话生效(sessions.meta.capabilities)
|
||||||
|
- 联网搜索/ Superpowers 受 env 总闸控制(见下表);聊天内安装的 MCP 插件走同一 Gateway
|
||||||
|
|
||||||
|
### 环境变量
|
||||||
|
|
||||||
|
| 变量 | 默认 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| QA_V1_ENABLE_WEB_SEARCH | 0 | 联网搜索总闸(会话开关之下) |
|
||||||
|
| QA_V1_WEB_SEARCH_MAX_RESULTS | 4 | 联网结果条数上限 |
|
||||||
|
| QA_V1_WEB_SEARCH_TIMEOUT | 8 | 出网超时(秒) |
|
||||||
|
| QA_V1_WEB_SEARCH_MAX_CHARS | 1200 | 摘要截断长度 |
|
||||||
|
| QA_V1_ENABLE_SUPERPOWERS | 0 | Superpowers 注入总闸 |
|
||||||
|
| BFF_HISTORY_ROUNDS | 3 | 多轮记忆轮数(BFF) |
|
||||||
|
|
||||||
|
### 如何新增 skill/MCP 插件(热加载,不重启)
|
||||||
|
|
||||||
|
1. 编辑 `agent/qa/configs/capabilities.yaml`(或聊天内通过 `POST /api/capabilities/install` 安装)
|
||||||
|
2. 每段 manifest:`name` + `provider`(http/mcp/python/prompt_pack)+ `schema` + 配置段
|
||||||
|
3. 保存后热加载自动生效(registry 差分刷新,MCP 子进程按需拉起,已加载进程不重启)
|
||||||
|
4. `GET /api/capabilities` 可查已装清单与 load_warnings(坏条目跳过不影响主体)
|
||||||
|
|
||||||
|
详见 `docs/ARCHITECTURE.md`「Capability Gateway」章节与 `docs/API.md` §6。
|
||||||
|
|
||||||
## 已知限制
|
## 已知限制
|
||||||
|
|
||||||
- 上游 QA 无 token 级流式(答案在终态一次返回),打字机为客户端揭示动画
|
- 上游 QA 无 token 级流式(答案在终态一次返回),打字机为客户端揭示动画
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Superpowers: 答案质量自检(superpowers_answer_quality)
|
||||||
|
|
||||||
|
Before returning the final answer, silently perform this self-check and revise if needed.
|
||||||
|
|
||||||
|
## Answer Quality Self-Check
|
||||||
|
|
||||||
|
1. **Directness**: The answer begins with the direct answer to the question (or a clear overview for survey questions), not with hedging.
|
||||||
|
2. **Structure**: Substantive paragraphs organized with ## subheadings; no tables unless the user asked for one.
|
||||||
|
3. **Completeness**: Every evidence-supported aspect of the question is addressed; partial support is stated precisely ("evidence supports X; Y is not supported").
|
||||||
|
4. **Language**: Same language as the user's question; gene symbols and Latin species names preserved exactly.
|
||||||
|
5. **Depth**: For family-level or survey questions, organize into major functional themes with process-level explanations (context → function → mechanism → outcome) where evidence permits.
|
||||||
|
6. **No filler**: No empty transitions, no repeated ideas, no AI clichés ("值得注意的是", "综上所述" repeated mechanically).
|
||||||
|
|
||||||
|
If any point fails, revise before returning.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Superpowers: 简洁代码原则(superpowers_minimal_code)
|
||||||
|
|
||||||
|
When the answer includes code or step-by-step instructions, apply these principles.
|
||||||
|
|
||||||
|
## Minimal Code Principles
|
||||||
|
|
||||||
|
1. Only include code when the user explicitly asks for it (analysis scripts, command lines).
|
||||||
|
2. Prefer the smallest working example over complete implementations.
|
||||||
|
3. Every code block must be directly relevant to the question; omit boilerplate.
|
||||||
|
4. Comments inside code are for constraints, not narration.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Superpowers: 证据审查清单(superpowers_review)
|
||||||
|
|
||||||
|
You are reviewing evidence acceptance for a plant-biology QA answer. Apply this checklist before finalizing the answer.
|
||||||
|
|
||||||
|
## Review Checklist
|
||||||
|
|
||||||
|
1. **Citation integrity**: Every factual claim cites only Preferred citation strings from the supplied report. No invented, altered, or inferred identifiers.
|
||||||
|
2. **Coverage honesty**: If the evidence does not support a requested fact, the answer says so directly instead of implying coverage.
|
||||||
|
3. **Species precision**: Species, gene names, tissues, stages, genotypes, and effect directions are preserved exactly; same-named genes from different species are never merged.
|
||||||
|
4. **Causal calibration**: Association, co-expression, or prediction evidence is never promoted to direct molecular mechanism or "major/core" regulation without functional perturbation data.
|
||||||
|
5. **Chain continuity**: Multi-hop GraphChains are followed through the terminal entity; the answer does not stop at a bridge entity.
|
||||||
|
6. **No redundancy**: Duplicate support is merged into one finding with shared citations; unrelated records are omitted.
|
||||||
|
|
||||||
|
When any check fails, rewrite the affected passage using only the supplied evidence.
|
||||||
@@ -18,6 +18,29 @@ class AgenticOutputError(RuntimeError):
|
|||||||
super().__init__(f"{stage} failed: {self.cause}")
|
super().__init__(f"{stage} failed: {self.cause}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _with_superpowers(base: str) -> str:
|
||||||
|
"""S6:env QA_V1_ENABLE_SUPERPOWERS=1 时注入证据审查清单。"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
if os.environ.get("QA_V1_ENABLE_SUPERPOWERS", "0") != "1":
|
||||||
|
return base
|
||||||
|
try:
|
||||||
|
import os as _os
|
||||||
|
|
||||||
|
from .prompt_pack import load_prompt_pack
|
||||||
|
|
||||||
|
packs = load_prompt_pack(
|
||||||
|
_os.path.join(_os.environ.get("GENE_FAMILY_ROOT", "/data/gene-family-mas-v2"), "prompts")
|
||||||
|
)
|
||||||
|
review = packs.get("superpowers_review", "")
|
||||||
|
if not review:
|
||||||
|
return base
|
||||||
|
return base + "\n\n" + review
|
||||||
|
except Exception:
|
||||||
|
return base
|
||||||
|
|
||||||
SYSTEM_PROMPT = """You are the retrieval planning and evidence review controller for a
|
SYSTEM_PROMPT = """You are the retrieval planning and evidence review controller for a
|
||||||
plant-biology knowledge-base QA system.
|
plant-biology knowledge-base QA system.
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,30 @@ Web citation rule:
|
|||||||
When Web Search Results are supplied, cite them as [WEB: <full URL>] exactly as printed. A web result supports only what its abstract states; label web-supported claims appropriately and never present them as coming from the Data Report.
|
When Web Search Results are supplied, cite them as [WEB: <full URL>] exactly as printed. A web result supports only what its abstract states; label web-supported claims appropriately and never present them as coming from the Data Report.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _system_with_superpowers() -> str:
|
||||||
|
"""S6:env QA_V1_ENABLE_SUPERPOWERS=1 时注入答案质量自检 + 简洁代码原则。"""
|
||||||
|
import os
|
||||||
|
|
||||||
|
if os.environ.get("QA_V1_ENABLE_SUPERPOWERS", "0") != "1":
|
||||||
|
return AnswerComposer.SYSTEM
|
||||||
|
try:
|
||||||
|
from .prompt_pack import load_prompt_pack
|
||||||
|
|
||||||
|
packs = load_prompt_pack(
|
||||||
|
os.path.join(os.environ.get("GENE_FAMILY_ROOT", "/data/gene-family-mas-v2"), "prompts")
|
||||||
|
)
|
||||||
|
extra = []
|
||||||
|
for name in ("superpowers_answer_quality", "superpowers_minimal_code"):
|
||||||
|
text_pack = packs.get(name, "")
|
||||||
|
if text_pack:
|
||||||
|
extra.append(text_pack)
|
||||||
|
if not extra:
|
||||||
|
return AnswerComposer.SYSTEM
|
||||||
|
return AnswerComposer.SYSTEM + "\n\n" + "\n\n".join(extra)
|
||||||
|
except Exception:
|
||||||
|
return AnswerComposer.SYSTEM
|
||||||
|
|
||||||
def __init__(self, llm: LLMClient):
|
def __init__(self, llm: LLMClient):
|
||||||
self.llm = llm
|
self.llm = llm
|
||||||
|
|
||||||
@@ -127,7 +151,7 @@ When Web Search Results are supplied, cite them as [WEB: <full URL>] exactly as
|
|||||||
else ""
|
else ""
|
||||||
)
|
)
|
||||||
return self.llm.complete(
|
return self.llm.complete(
|
||||||
self.SYSTEM,
|
self._system_with_superpowers(),
|
||||||
f"""--- Data Report ---
|
f"""--- Data Report ---
|
||||||
|
|
||||||
{context_data}
|
{context_data}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
"""prompt_pack.py —— PromptPackProvider 的加载器(S6,Superpowers 即此形态)。
|
||||||
|
|
||||||
|
load_prompt_pack(dir) → Dict;读 SKILL.md 风格 md 注入指定提示词尾部;
|
||||||
|
文件缺失静默返回空(防御)。
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def load_prompt_pack(pack_dir: str | Path) -> Dict[str, str]:
|
||||||
|
"""加载目录下全部 .md 文件为 {name: content};缺失/异常静默。"""
|
||||||
|
root = Path(pack_dir)
|
||||||
|
packs: Dict[str, str] = {}
|
||||||
|
if not root.is_dir():
|
||||||
|
return packs
|
||||||
|
for path in sorted(root.glob("*.md")):
|
||||||
|
try:
|
||||||
|
text = path.read_text(encoding="utf-8").strip()
|
||||||
|
if text:
|
||||||
|
packs[path.stem] = text
|
||||||
|
except Exception as exc:
|
||||||
|
LOGGER.warning("prompt_pack 读取失败 %s: %s", path, exc)
|
||||||
|
return packs
|
||||||
|
|
||||||
|
|
||||||
|
def inject_tail(base_prompt: str, pack_text: str, separator: str = "\n\n") -> str:
|
||||||
|
"""把 pack 文本注入 base 提示词尾部。pack 为空时原样返回。"""
|
||||||
|
if not pack_text:
|
||||||
|
return base_prompt
|
||||||
|
return f"{base_prompt}{separator}{pack_text}"
|
||||||
+47
@@ -429,3 +429,50 @@ MinerU 不可用:502 降级信封,message 说明原因。读超时 600s。
|
|||||||
- SSE 消费用 `fetch` + `ReadableStream`(**禁止 EventSource**),解析器处理 `event:`/`data:`/`:` 三种行。
|
- SSE 消费用 `fetch` + `ReadableStream`(**禁止 EventSource**),解析器处理 `event:`/`data:`/`:` 三种行。
|
||||||
- 流式持久化节奏:骨架 `POST /messages` → 每 3s `PATCH` 检查点 → 终态 `PATCH`。刷新中断恢复依赖此节奏。
|
- 流式持久化节奏:骨架 `POST /messages` → 每 3s `PATCH` 检查点 → 终态 `PATCH`。刷新中断恢复依赖此节奏。
|
||||||
- 所有列表请求失败都渲染空态/离线态,**禁止**无限 loading 转圈。
|
- 所有列表请求失败都渲染空态/离线态,**禁止**无限 loading 转圈。
|
||||||
|
|
||||||
|
|
||||||
|
## §6 能力端点(Capability Gateway,2026-09-02 起)
|
||||||
|
|
||||||
|
### GET /api/capabilities
|
||||||
|
|
||||||
|
能力清单 + 默认值 + 当前会话开关 + QA 注册表合并。
|
||||||
|
|
||||||
|
- Query:`session_id`(可选;缺省返回默认开关)
|
||||||
|
- 响应:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"capabilities": [
|
||||||
|
{"name": "memory", "label": "多轮记忆", "description": "...",
|
||||||
|
"provider": "sdk", "session_default": true, "enabled": true},
|
||||||
|
{"name": "web_search", "label": "联网搜索", "...": "...",
|
||||||
|
"provider": "qa_gateway", "session_default": false,
|
||||||
|
"gated_by": "QA_V1_ENABLE_WEB_SEARCH", "enabled": false}
|
||||||
|
],
|
||||||
|
"defaults": {"memory": true, "web_search": false, "humanize": false},
|
||||||
|
"installed": [{"name": "web_search", "description": "..."}],
|
||||||
|
"load_warnings": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### POST /api/capabilities/install
|
||||||
|
|
||||||
|
聊天内自助安装(BFF 透传 QA loopback)。热加载生效,不重启。
|
||||||
|
|
||||||
|
- 请求:`{"action": "register", "manifest": "<一段 YAML>", "apply": true}`
|
||||||
|
或 `{"action": "unregister", "name": "<能力名>"}`
|
||||||
|
- 响应(register):`{"ok": true, "installed": ["<name>"], "warnings": [],
|
||||||
|
"diff": {"added": [...], "removed": [], "changed": []}, "hot_reload": true}`
|
||||||
|
- manifest 白名单:provider ∈ {http, mcp, python, prompt_pack}、
|
||||||
|
permission=read_only、单条目 ≤8KB、yaml 总大小 ≤1MB;坏条目跳过
|
||||||
|
- 错误:400 VALIDATION(manifest 校验失败)/ 503 UPSTREAM_DOWN / 502 UPSTREAM_ERROR
|
||||||
|
|
||||||
|
### PATCH /api/sessions/{id}(§5 扩展)
|
||||||
|
|
||||||
|
`meta` 字段新增(2026-09-02):`{"meta": {"capabilities": {"web_search": true}}}`。
|
||||||
|
白名单键:memory / web_search / humanize;非白名单键丢弃、值强转 bool;
|
||||||
|
与既有 meta 深度合并(title_manual 等键不受影响)。
|
||||||
|
|
||||||
|
### POST /api/qa/chat 与 /api/qa/chat/stream(§4 扩展)
|
||||||
|
|
||||||
|
请求体新增 BFF 契约字段 `session_id`(BFF 剥离后注入上游 history/capabilities,
|
||||||
|
不达 QA)。不传 session_id 时行为与既往一致。
|
||||||
|
|||||||
@@ -221,6 +221,45 @@ PlantAI-rag-new/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 10.5 Capability Gateway(2026-09-02 起)
|
||||||
|
|
||||||
|
### 三层机制
|
||||||
|
|
||||||
|
- **注册层**:`agent/qa/configs/capabilities.yaml`(明文、可热加载)。每个能力一段
|
||||||
|
manifest(provider/permission/schema/默认开关);坏条目跳过并记 load_warnings,
|
||||||
|
一条坏配置不影响其余能力,更不影响 QA 主体启动。
|
||||||
|
- **调用层**:`capabilities/{manifests,registry,providers,install_manager}.py` +
|
||||||
|
`tool_runner.py`(编译 .so)。四 Provider:HttpToolProvider(HTTP JSON 工具)、
|
||||||
|
McpToolProvider(官方 mcp SDK,stdio 子进程 + streamable-http;空闲回收、
|
||||||
|
崩溃限次重启 3 次熔断)、PythonToolProvider(module:function)、
|
||||||
|
PromptPackProvider(SKILL.md 注入)。
|
||||||
|
- **安装管理层**:`install_manager.py`(白名单校验、单写锁 + 原子替换、操作审计
|
||||||
|
JSONL)+ QA loopback `/api/v1/qa-v1-1-73/capabilities/install` + BFF 透传
|
||||||
|
`POST /api/capabilities/install`。热加载 = 重解析 → registry 差分刷新 →
|
||||||
|
MCP 子进程按 diff 启停(已加载进程不重启;QA 冷启动 ~167s 是热加载硬要求的动因)。
|
||||||
|
|
||||||
|
### 会话级开关链
|
||||||
|
|
||||||
|
设置面板 PATCH `sessions.meta.capabilities`(BFF 白名单 sanitize)→ BFF 读 meta →
|
||||||
|
注入 `body.history`(memory on)/ `body.capabilities`(web_search 双闸:会话开 AND
|
||||||
|
env 总闸)→ QA 按 capabilities 决策。humanize 在 BFF complete 帧归一化后、
|
||||||
|
图片注入后执行(纯 BFF 层)。
|
||||||
|
|
||||||
|
### 首批四项能力落点
|
||||||
|
|
||||||
|
| 能力 | 落点 |
|
||||||
|
|---|---|
|
||||||
|
| 多轮记忆 | SDK `services/history.py`(3 轮/16k 预算)→ QA answer_composer Dialogue Context 段(检索零回归) |
|
||||||
|
| 联网搜索 | QA `web_search.py`(PubMed esearch+esummary → Crossref 兜底;中文问题经 build_query 转英文)→ pipeline 证据采纳后确定性门控(去重公开引用数 < min_evidence) |
|
||||||
|
| Humanizer | SDK `services/humanizer.py`(9 类规则纯函数;块级保护) |
|
||||||
|
| Superpowers | QA `prompts/*.md` + prompt_pack.py 注入 answer_composer SYSTEM / agentic REVIEW |
|
||||||
|
|
||||||
|
### 金标防抖(LLM 方差实证)
|
||||||
|
|
||||||
|
金标 compare 对基线 PASS 而批次 FAIL 的题复跑一次;GI-005(拟南芥 WRKY 成员数)
|
||||||
|
经配对采样实证为上游 deepseek-chat 随时间漂移(同题同端口多次采样 key_hit
|
||||||
|
0.2~0.8 横跨阈值),标记 flaky 不计回归。见 `qa-golden/S0_RECORD.md`。
|
||||||
|
|
||||||
## 10. 已知的既存故障(不修,仅规避)
|
## 10. 已知的既存故障(不修,仅规避)
|
||||||
|
|
||||||
| 现象 | 影响 | 我们的对策 |
|
| 现象 | 影响 | 我们的对策 |
|
||||||
|
|||||||
@@ -1,5 +1,27 @@
|
|||||||
# CHANGELOG.md —— 进度与决策记录(PM 独占写入)
|
# CHANGELOG.md —— 进度与决策记录(PM 独占写入)
|
||||||
|
|
||||||
|
## 2026-09-02(能力集成 S0–S7)
|
||||||
|
|
||||||
|
- **S0 基线**:7920 旧容器停(不删);deploy-unified 全量备份;金标 30 题固化
|
||||||
|
(benchmark 20 + 水稻 SPL 补充 10,断言级判定器 qa-golden/run_golden.py);
|
||||||
|
冷启动计时 151.3s(热加载硬要求实证);tag capabilities-baseline。
|
||||||
|
- **S1 机制地基**:capabilities 五模块 + tool_runner + capabilities.yaml 热加载面 +
|
||||||
|
compile_qa.sh 扩展;mcp 2.1.1 入 venv 与 requirements.lock;llm_client tools 参数;
|
||||||
|
/capabilities/install loopback;自检工具 tooling/cap/(cap_selfcheck 4 项 PASS)。
|
||||||
|
- **S2 多轮记忆**:SDK services/history.py(3 轮/16k 预算)+ qa.py session_id 剥离注入;
|
||||||
|
QA answer_composer Dialogue Context 段(检索零回归);BFF 端到端指代消解验证通过。
|
||||||
|
- **S3 联网搜索**:web_search.py(PubMed+Crossref,中文问题自动转英文查询);
|
||||||
|
pipeline 确定性门控(去重公开引用数 < min_evidence;selected 恒 30 缺陷已修);
|
||||||
|
sse_relay STAGE +2;四象限门控验证(覆盖好不触发/覆盖弱触发/请求关/env 关)。
|
||||||
|
- **S4 SDK+UI**:GET /api/capabilities + POST install 透传 + SessionMeta.capabilities
|
||||||
|
PATCH 白名单合并;Humanizer 9 类规则(块级保护);设置面板(展开态入口 +
|
||||||
|
Drawer 360px)+ AppShell 接线 + chat.js session_id;labels 文案组。
|
||||||
|
- **S5 安装闭环验收**:聊天内安装 → 热加载 diff → 面板可见 → 卸载,全程 QA PID 不变。
|
||||||
|
- **S6 Superpowers**:prompts/ 3 个 SKILL.md + prompt_pack.py 注入点(env 总闸
|
||||||
|
QA_V1_ENABLE_SUPERPOWERS=0);compile_qa.sh prompts 目录自动拷贝。
|
||||||
|
- **金标判定器防抖**:FAIL 复跑一次;GI-005 配对采样实证上游 LLM 漂移,标 flaky。
|
||||||
|
- 测试:QA 单测 24、SDK 146、UI vitest 172 全绿;金标对照 regressions=0。
|
||||||
|
|
||||||
## 2026-08-25
|
## 2026-08-25
|
||||||
|
|
||||||
- **计划批准**:新前端 + 薄适配层方案获批。端口 8090(BFF)/ 5180(Vite dev),并行部署不切换。
|
- **计划批准**:新前端 + 薄适配层方案获批。端口 8090(BFF)/ 5180(Vite dev),并行部署不切换。
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
**使用场景**:桌面深度研究为主,**手机端随时查询为重要补充**(实验室、会议、田间)。
|
**使用场景**:桌面深度研究为主,**手机端随时查询为重要补充**(实验室、会议、田间)。
|
||||||
|
|
||||||
**不做什么**:不做多轮对话记忆(上游 `max_rounds:1`,每次提问独立检索);不做文献全文阅读器;不做基因家族分析流程执行(那是 PlantAI-dev 的职责)。
|
**不做什么**:默认支持同会话上下文记忆(可在设置中关闭)(上游 `max_rounds:1`,每次提问独立检索);不做文献全文阅读器;不做基因家族分析流程执行(那是 PlantAI-dev 的职责)。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -123,7 +123,7 @@
|
|||||||
| TC-CHAT-030 | FR-CHAT-008 | 网络中断重试按钮 | 流式中断网(playwright context.setOffline(true)) | 1. 流式中断网;2. 观察消息状态;3. 恢复网络;4. 观察是否自动重连;5. 点「重试」 | 消息置 error,文案「连接中断」;出现「重试」按钮;**不自动重连**(恢复网络后无新请求,需手动点击);点重试后重新发起同问题请求 | L5-D(offline 模拟) | P0 |
|
| TC-CHAT-030 | FR-CHAT-008 | 网络中断重试按钮 | 流式中断网(playwright context.setOffline(true)) | 1. 流式中断网;2. 观察消息状态;3. 恢复网络;4. 观察是否自动重连;5. 点「重试」 | 消息置 error,文案「连接中断」;出现「重试」按钮;**不自动重连**(恢复网络后无新请求,需手动点击);点重试后重新发起同问题请求 | L5-D(offline 模拟) | P0 |
|
||||||
| TC-CHAT-031 | FR-CHAT-008 | 刷新恢复中断会话 | 流式进行中刷新页面 | 刷新后检查该会话 | 显示最后检查点内容;标注「已中断」;会话状态 error;不自动重试 | L5-D | P0 |
|
| TC-CHAT-031 | FR-CHAT-008 | 刷新恢复中断会话 | 流式进行中刷新页面 | 刷新后检查该会话 | 显示最后检查点内容;标注「已中断」;会话状态 error;不自动重试 | L5-D | P0 |
|
||||||
| TC-CHAT-032 | FR-CHAT-008 | 同一会话并发提问防护 | 流式进行中 | 观察发送按钮 | 按钮 disabled;无法发送第二个问题 | L5-D | P1 |
|
| TC-CHAT-032 | FR-CHAT-008 | 同一会话并发提问防护 | 流式进行中 | 观察发送按钮 | 按钮 disabled;无法发送第二个问题 | L5-D | P1 |
|
||||||
| TC-CHAT-033 | FR-CHAT-008 | 同会话提问互相独立(无上下文记忆) | 同一会话已完成一次提问 | 第二次提问并抓取请求体 | 第二次请求只含当前 question,无历史消息拼接(max_rounds:1 语义);UI 有「每次提问独立检索」提示文案 | L2 + L5 | P1 |
|
| TC-CHAT-033 | FR-CHAT-008 | 同会话提问可引用上文(默认开;设置中关闭后恢复独立) | 同一会话已完成一次提问 | 第二次提问并抓取请求体 | 第二次请求只含当前 question,无历史消息拼接(max_rounds:1 语义);UI 有「每次提问独立检索」提示文案 | L2 + L5 | P1 |
|
||||||
|
|
||||||
#### 1.5.4 流水线卡与揭示动画(FR-CHAT-009 / FR-CHAT-010)
|
#### 1.5.4 流水线卡与揭示动画(FR-CHAT-009 / FR-CHAT-010)
|
||||||
|
|
||||||
|
|||||||
@@ -10,25 +10,26 @@ import re
|
|||||||
from typing import Any, List, Tuple
|
from typing import Any, List, Tuple
|
||||||
|
|
||||||
# 9 类规则(替换文本:AI 痕迹 → 自然表达或删除)
|
# 9 类规则(替换文本:AI 痕迹 → 自然表达或删除)
|
||||||
|
# 逗号一律匹配中英两种([,,])
|
||||||
RULES: List[Tuple[str, str]] = [
|
RULES: List[Tuple[str, str]] = [
|
||||||
# 1. 冗余开场
|
# 1. 冗余开场
|
||||||
(r"^(值得注意的是|值得注意的是,|值得注意的是,)\s*", ""),
|
(r"^(值得注意的是[,,]?)\s*", ""),
|
||||||
(r"^(总而言之|综上所述,|综上所述,)\s*", ""),
|
(r"^(总而言之|综上所述)[,,]?\s*", ""),
|
||||||
(r"^(首先,|首先,)\s*", ""),
|
(r"^(首先[,,]?)\s*", ""),
|
||||||
# 2. AI 高频连接词
|
# 2. AI 高频连接词
|
||||||
(r"此外,", "另外,"),
|
(r"此外[,,]", "另外,"),
|
||||||
(r"不仅如此,", "而且,"),
|
(r"不仅如此[,,]", "而且,"),
|
||||||
(r"值得注意的是,", "要注意的是,"),
|
(r"值得注意的是[,,]", "要注意的是,"),
|
||||||
(r"与此同时,", "同时,"),
|
(r"与此同时[,,]", "同时,"),
|
||||||
(r"更重要的是,", "更关键的是,"),
|
(r"更重要的是[,,]", "更关键的是,"),
|
||||||
# 3. 空洞强调
|
# 3. 空洞强调
|
||||||
(r"充分体现了", "体现了"),
|
(r"充分体现了", "体现了"),
|
||||||
(r"极大地", "显著"),
|
(r"极大地", "显著"),
|
||||||
(r"毋庸置疑地", ""),
|
(r"毋庸置疑地", ""),
|
||||||
(r"显而易见地", ""),
|
(r"显而易见地", ""),
|
||||||
# 4. 机械总结语
|
# 4. 机械总结语
|
||||||
(r"总的来说,", "整体来看,"),
|
(r"总的来说[,,]", "整体来看,"),
|
||||||
(r"综上所述,", "概括来说,"),
|
(r"综上所述[,,]", "概括来说,"),
|
||||||
# 5. 过度递进
|
# 5. 过度递进
|
||||||
(r"不仅(.{1,40}?)而且(.{1,40}?)(?=[。,,])", r"\1,也\2"),
|
(r"不仅(.{1,40}?)而且(.{1,40}?)(?=[。,,])", r"\1,也\2"),
|
||||||
(r"既(.{1,40}?)又(.{1,40}?)(?=[。,,])", r"\1,同时\2"),
|
(r"既(.{1,40}?)又(.{1,40}?)(?=[。,,])", r"\1,同时\2"),
|
||||||
@@ -40,11 +41,12 @@ RULES: List[Tuple[str, str]] = [
|
|||||||
(r"大量的研究", "多项研究"),
|
(r"大量的研究", "多项研究"),
|
||||||
(r"越来越多的证据", "已有证据"),
|
(r"越来越多的证据", "已有证据"),
|
||||||
# 8. 标签式总结
|
# 8. 标签式总结
|
||||||
(r"一言以蔽之,", ""),
|
(r"一言以蔽之[,,]", ""),
|
||||||
(r"简而言之,", "简单来说,"),
|
(r"简而言之[,,]", "简单来说,"),
|
||||||
# 9. 空转过渡
|
# 9. 空转过渡
|
||||||
(r"那么问题来了,", ""),
|
(r"那么问题来了[,,]", ""),
|
||||||
(r"接下来,我们来(.{1,20}?)", "下面\1"),
|
(r"接下来,我们来(.{1,20}?)", "下面\1"),
|
||||||
|
(r"接下来,我们来(.{1,20}?)", "下面\1"),
|
||||||
]
|
]
|
||||||
|
|
||||||
# 块级保护:整块跳过(不应用任何规则)
|
# 块级保护:整块跳过(不应用任何规则)
|
||||||
@@ -54,7 +56,7 @@ _FIG_MARKER = re.compile(r"\[\[FIG:[^\]]+\]\]")
|
|||||||
_IMG_MARKDOWN = re.compile(r"!\[[^\]]*\]\([^)]*\)")
|
_IMG_MARKDOWN = re.compile(r"!\[[^\]]*\]\([^)]*\)")
|
||||||
_HEADING = re.compile(r"^#{1,6}\s+.*$", re.MULTILINE)
|
_HEADING = re.compile(r"^#{1,6}\s+.*$", re.MULTILINE)
|
||||||
_LIST_ITEM = re.compile(r"^\s*[-*+]\s+.*$|^\s*\d+[.)]\s+.*$", re.MULTILINE)
|
_LIST_ITEM = re.compile(r"^\s*[-*+]\s+.*$|^\s*\d+[.)]\s+.*$", re.MULTILINE)
|
||||||
_CITATION_SPAN = re.compile(r"[^。!?\n]*\[(?:PMID|PMCID|DOI|WEB)[^\]]*\][^。!?\n]*")
|
_CITATION_SPAN = re.compile(r"\[(?:PMID|PMCID|DOI|WEB)[^\]]*\]")
|
||||||
|
|
||||||
|
|
||||||
def _protect(text: str) -> Tuple[str, List[str]]:
|
def _protect(text: str) -> Tuple[str, List[str]]:
|
||||||
|
|||||||
@@ -61,6 +61,11 @@ do
|
|||||||
install -D -m 0640 "$SOURCE_ROOT/$relative" "$OUTPUT_DIR/$relative"
|
install -D -m 0640 "$SOURCE_ROOT/$relative" "$OUTPUT_DIR/$relative"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
# S6:prompts/ 目录(Superpowers SKILL.md 明文注入包)
|
||||||
|
if [[ -d "$SOURCE_ROOT/prompts" ]]; then
|
||||||
|
install -d -m 0750 "$OUTPUT_DIR/prompts"
|
||||||
|
install -m 0640 "$SOURCE_ROOT"/prompts/*.md "$OUTPUT_DIR/prompts/" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
# Namespace/package markers are intentionally left as minimal Python files.
|
# Namespace/package markers are intentionally left as minimal Python files.
|
||||||
touch \
|
touch \
|
||||||
|
|||||||
Reference in New Issue
Block a user