diff --git a/prebuilt/compare/SKILL.md b/prebuilt/compare/SKILL.md index 079f1df..52bd5d6 100644 --- a/prebuilt/compare/SKILL.md +++ b/prebuilt/compare/SKILL.md @@ -118,11 +118,13 @@ PROJECT_ROOT="$(dirname "$(dirname "$(dirname "$SKILL_FILE")")")" 2. **加载法师角色内容**:`$PROJECT_ROOT/prebuilt/{slug}/teaching.md` 和 `voice.md` -3. **执行语义检索**: +3. **执行语义检索**(使用 `--brief` 减少输出冗余): ```bash - python3 "$PROJECT_ROOT/tools/rag_query.py" semantic "<问题>" --top_k 3 + python3 "$PROJECT_ROOT/tools/rag_query.py" semantic "<问题>" --top_k 3 --brief ``` + `--brief` 模式每条结果只显示 2 行(经名+链接+80字摘要),避免 60+ 行的完整经文内容刷屏。 + 4. **过滤结果**:根据该法师 meta.json 的 `search_scope.primary_cbeta_ids` 过滤检索结果 5. **降级处理**:若 `rag_query.py` 不可达(路径解析失败或 FoJin API 不可用),改用 teaching.md 中已验证的 FoJin 链接作为出处,并在回答开头提示"本次检索基于预置内容" diff --git a/tools/rag_query.py b/tools/rag_query.py index 2ea4128..ef4d474 100644 --- a/tools/rag_query.py +++ b/tools/rag_query.py @@ -19,12 +19,26 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from fojin_bridge import create_bridge, FojinUnavailableError -def format_search_results(data: dict) -> str: +def format_search_results(data: dict, brief: bool = False) -> str: """Format keyword search results for LLM consumption.""" items = data.get("items") or data.get("results") or [] if not items: return "未找到相关结果。" + if brief: + total = data.get("total", len(items)) + lines = [f"关键词搜索 {total} 条,显示 {len(items)}:"] + for i, item in enumerate(items, 1): + title = item.get("title", "无标题") + text_id = item.get("text_id", item.get("id", "")) + link = f"https://fojin.app/texts/{text_id}" if text_id else "" + snippet = item.get("highlight", item.get("snippet", item.get("content", ""))) + snippet_str = str(snippet).strip().replace("\n", " ")[:80] + lines.append(f"{i}. {title} — {link}") + if snippet_str: + lines.append(f" {snippet_str}...") + return "\n".join(lines) + lines = [] for i, item in enumerate(items, 1): title = item.get("title", "无标题") @@ -42,7 +56,6 @@ def format_search_results(data: dict) -> str: if text_id: lines.append(f"FoJin链接: https://fojin.app/texts/{text_id}") if snippet: - # Truncate long snippets snippet_str = str(snippet) if len(snippet_str) > 500: snippet_str = snippet_str[:500] + "..." @@ -54,12 +67,39 @@ def format_search_results(data: dict) -> str: return "\n".join(lines) -def format_semantic_results(data: dict) -> str: - """Format semantic search results for LLM consumption.""" +def format_semantic_results(data: dict, brief: bool = False) -> str: + """Format semantic search results for LLM consumption. + + Args: + data: API response dict + brief: If True, output one-line-per-result (compact mode for meta-skills + like /compare-masters). If False, output full content excerpts. + """ items = data.get("items") or data.get("results") or [] if not items: return "语义检索未找到相关经文。" + if brief: + lines = [f"语义检索 {len(items)} 条:"] + for i, item in enumerate(items, 1): + title = item.get("title", "无标题") + score = item.get("score", item.get("similarity", "")) + content = item.get("content", item.get("snippet", item.get("text", ""))) + text_id = item.get("text_id", item.get("id", "")) + juan = item.get("juan_num", item.get("juan", "")) + + link = f"https://fojin.app/texts/{text_id}" if text_id else "" + if text_id and juan: + link += f"/juan/{juan}" + + score_str = f" (score={score:.2f})" if isinstance(score, (int, float)) else "" + snippet = str(content).strip().replace("\n", " ")[:80] + + lines.append(f"{i}. {title}{score_str} — {link}") + if snippet: + lines.append(f" {snippet}...") + return "\n".join(lines) + lines = [f"语义检索返回 {len(items)} 条相关经文:\n"] for i, item in enumerate(items, 1): title = item.get("title", "无标题") @@ -158,13 +198,13 @@ def format_kg_results(data: dict) -> str: def cmd_search(args): bridge = create_bridge() result = bridge.search_texts(args.query, sources=args.sources, size=args.top_k) - print(format_search_results(result)) + print(format_search_results(result, brief=args.brief)) def cmd_semantic(args): bridge = create_bridge() result = bridge.semantic_search(args.query, top_k=args.top_k) - print(format_semantic_results(result)) + print(format_semantic_results(result, brief=args.brief)) def cmd_dict(args): @@ -192,12 +232,14 @@ def main(): p_search.add_argument("query", help="搜索关键词") p_search.add_argument("--sources", default=None, help="限定来源,如 cbeta") p_search.add_argument("--top_k", type=int, default=5, help="返回条数 (默认 5)") + p_search.add_argument("--brief", action="store_true", help="简洁输出(一行一条)") p_search.set_defaults(func=cmd_search) # semantic p_sem = subparsers.add_parser("semantic", help="语义向量检索") p_sem.add_argument("query", help="语义查询") p_sem.add_argument("--top_k", type=int, default=5, help="返回条数 (默认 5)") + p_sem.add_argument("--brief", action="store_true", help="简洁输出(一行一条)") p_sem.set_defaults(func=cmd_semantic) # dict