From 4be9abacaa640bed3f41be031cbfa89d4241e1f8 Mon Sep 17 00:00:00 2001 From: leolai5 <15761621631@163.com> Date: Thu, 23 Jul 2026 08:28:50 +0800 Subject: [PATCH 1/2] feat: add medical knowledge base plugin for healthcare domain --- plugins/medical_kb/README.md | 63 ++++++++++++ plugins/medical_kb/__init__.py | 182 +++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 plugins/medical_kb/README.md create mode 100644 plugins/medical_kb/__init__.py diff --git a/plugins/medical_kb/README.md b/plugins/medical_kb/README.md new file mode 100644 index 000000000..395ea48ec --- /dev/null +++ b/plugins/medical_kb/README.md @@ -0,0 +1,63 @@ +# Medical Knowledge Base Plugin for DeepSearch + +医疗知识库插件,为 [openJiuwen DeepSearch](https://gitcode.com/openJiuwen/deepsearch) 提供**诊疗指南智能检索与问答**能力。 + +## 功能特性 + +- **诊疗指南问答**:基于中国2型糖尿病防治指南(2024/2020版)、中国高血压防治指南(2024版) +- **三重融合检索**:向量语义 + BM25关键词 + 知识图谱,综合打分 +- **引用溯源**:每个回答附带指南原文引用(名称+版本+章节+条目) +- **版本对比**:新旧版指南差异检测(如糖尿病指南2024版 vs 2020版) +- **多轮对话**:根据历史对话推断疾病,提高命中率 + +## 快速开始 + +```bash +# 1. 安装依赖 +pip install medical-ai-innovation + +# 2. 测试插件 +python -m medical_kb +``` + +## 使用方法 + +```python +from medical_kb import MedicalKnowledgeBasePlugin + +# 初始化插件 +plugin = MedicalKnowledgeBasePlugin() +plugin.load_demo_guidelines() + +# 搜索 +result = plugin.search("空腹血糖正常值是多少?") +print(result["answer"]) + +# 获取引用 +for c in result["citations"]: + print(f"{c['source']} (score: {c['score']})") +``` + +## 内置指南数据 + +| 指南名称 | 版本 | 条目数 | +|---------|------|--------| +| 中国2型糖尿病防治指南 | 2024版(最新) | 6条 | +| 中国2型糖尿病防治指南 | 2020版(旧版) | 3条 | +| 中国高血压防治指南 | 2024版(最新) | 3条 | + +## 插件接口 + +实现 DeepSearch 标准插件接口: + +| 方法 | 说明 | +|------|------| +| `search(query, top_k=5)` | 知识库搜索 | +| `batch_search(queries)` | 批量搜索 | +| `get_guideline_list()` | 获取指南列表 | +| `get_stats()` | 获取统计信息 | +| `explain(query)` | 检索过程解释 | + +## 许可证 + +Apache-2.0 \ No newline at end of file diff --git a/plugins/medical_kb/__init__.py b/plugins/medical_kb/__init__.py new file mode 100644 index 000000000..f27f7ce5f --- /dev/null +++ b/plugins/medical_kb/__init__.py @@ -0,0 +1,182 @@ +""" +Medical Knowledge Base Adapter for openJiuwen DeepSearch + +将 medical-ai-innovation 的知识库RAG能力适配到 DeepSearch 框架, +作为医疗领域知识库插件,提供诊疗指南的智能检索与问答。 + +适配器说明: +- 实现 DeepSearch 的 KnowledgeBasePlugin 接口 +- 支持多级检索(向量+关键词+知识图谱) +- 支持引用溯源(片段级引用) +""" +from __future__ import annotations +import sys +import os +from typing import Optional + +# 将 medical-ai-innovation 加入路径 +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..")) + +from medical_ai_innovation.knowledge_base.schemas import ( + Guideline, GuidelineSection, GuidelineClause, RetrievalResult, AnswerWithCitations +) +from medical_ai_innovation.knowledge_base.kb_engine import KnowledgeBaseEngine +from medical_ai_innovation.knowledge_base.rag_pipeline import RAGPipeline + + +class MedicalKnowledgeBasePlugin: + """ + DeepSearch 医疗知识库插件 + + 提供医疗领域知识库的检索与问答能力,支持: + - 诊疗指南的智能问答 + - 多级检索(向量 + BM25关键词 + 知识图谱) + - 引用溯源(每个回答附带指南原文引用) + - 版本对比(新旧版指南差异检测) + + 用法: + plugin = MedicalKnowledgeBasePlugin() + plugin.load_demo_guidelines() + result = plugin.search("空腹血糖正常值是多少?") + print(result["answer"]) + """ + + def __init__(self): + self.engine = KnowledgeBaseEngine() + self.pipeline = RAGPipeline(self.engine) + + # ---------- DeepSearch 标准接口 ---------- + + def search(self, query: str, top_k: int = 5, **kwargs) -> dict: + """ + 搜索知识库(DeepSearch标准接口) + + Args: + query: 查询文本 + top_k: 返回结果数 + **kwargs: 其他参数(disease, latest_only等) + + Returns: + { + "answer": str, + "citations": [{"content": str, "source": str, "score": float}], + "total_found": int, + "plugin": "medical_kb" + } + """ + disease = kwargs.get("disease", "") + include_version_compare = kwargs.get("include_version_compare", False) + + result = self.pipeline.answer( + question=query, + top_k=top_k, + disease=disease, + include_version_compare=include_version_compare, + ) + + return { + "answer": result.answer, + "citations": [ + { + "content": r.clause.content, + "source": f"{r.clause.guideline_id} | {r.clause.clause_num} {r.clause.title}", + "score": r.score, + "method": r.method, + "evidence_level": r.clause.evidence_level, + "recommendation": r.clause.recommendation, + } + for r in result.citations + ], + "total_found": len(result.citations), + "plugin": "medical_kb", + "retrieval_methods": result.retrieval_methods, + } + + def batch_search(self, queries: list[str], **kwargs) -> list[dict]: + """批量搜索""" + return [self.search(q, **kwargs) for q in queries] + + # ---------- 知识库管理 ---------- + + def load_guideline(self, guideline: Guideline): + """加载诊疗指南""" + self.engine.load_guideline(guideline) + + def load_guidelines(self, guidelines: list[Guideline]): + """批量加载指南""" + self.engine.load_guidelines(guidelines) + self.engine.build_index() + + def load_demo_guidelines(self): + """加载内置示例指南(糖尿病+高血压)""" + from medical_ai_innovation.knowledge_base.cli import _build_demo_guidelines + self.load_guidelines(_build_demo_guidelines()) + + def get_guideline_list(self) -> list[dict]: + """获取已加载的指南列表""" + return self.engine.get_guideline_summary() + + def get_stats(self) -> dict: + """获取知识库统计""" + return self.engine.stats + + # ---------- 工具方法 ---------- + + def explain(self, query: str) -> dict: + """解释检索过程""" + return self.pipeline.explain_retrieval(query) + + def reset(self): + """重置对话上下文""" + self.pipeline.reset_context() + + @property + def plugin_info(self) -> dict: + """插件元信息""" + return { + "name": "medical_kb", + "display_name": "医疗知识库", + "description": "基于诊疗指南的医疗知识库检索与问答", + "version": "1.0.0", + "author": "leppardwang", + "languages": ["zh"], + "domains": ["healthcare", "medical"], + "guidelines_count": len(self.engine.guidelines), + "knowledge_base": "中国2型糖尿病防治指南(2024版/2020版), 中国高血压防治指南(2024版)", + } + + +# ========== 命令行测试 ========== + +def main(): + """测试插件""" + print("🩺 Medical Knowledge Base Plugin for DeepSearch") + print("=" * 50) + + plugin = MedicalKnowledgeBasePlugin() + plugin.load_demo_guidelines() + + print(f"📚 已加载 {plugin.get_stats()['guidelines']} 部指南") + print() + + while True: + try: + q = input("🧑 请输入医疗问题 (输入 /quit 退出): ").strip() + except (EOFError, KeyboardInterrupt): + break + + if not q: + continue + if q.lower() in ("/quit", "/exit"): + break + + result = plugin.search(q, include_version_compare=True) + print(f"\n🤖 {result['answer'][:300]}...\n") + print(f"📚 引用 {result['total_found']} 条") + for i, c in enumerate(result["citations"][:3], 1): + print(f" [{i}] {c['source']} (score: {c['score']})") + print() + + +if __name__ == "__main__": + main() \ No newline at end of file From 6d52165b67614b1241c48ba4d0752c637d4d91a8 Mon Sep 17 00:00:00 2001 From: leolai5 <15761621631@163.com> Date: Thu, 23 Jul 2026 09:56:41 +0800 Subject: [PATCH 2/2] fix: resolve AI review issues - path injection, private API, null safety, dead code, docs --- plugins/medical_kb/README.md | 4 +- plugins/medical_kb/__init__.py | 68 ++++++++++++++++++++++------------ 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/plugins/medical_kb/README.md b/plugins/medical_kb/README.md index 395ea48ec..76bfa89e4 100644 --- a/plugins/medical_kb/README.md +++ b/plugins/medical_kb/README.md @@ -17,13 +17,13 @@ pip install medical-ai-innovation # 2. 测试插件 -python -m medical_kb +python -m plugins.medical_kb ``` ## 使用方法 ```python -from medical_kb import MedicalKnowledgeBasePlugin +from plugins.medical_kb import MedicalKnowledgeBasePlugin # 初始化插件 plugin = MedicalKnowledgeBasePlugin() diff --git a/plugins/medical_kb/__init__.py b/plugins/medical_kb/__init__.py index f27f7ce5f..789121836 100644 --- a/plugins/medical_kb/__init__.py +++ b/plugins/medical_kb/__init__.py @@ -14,14 +14,24 @@ import os from typing import Optional -# 将 medical-ai-innovation 加入路径 -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..")) - -from medical_ai_innovation.knowledge_base.schemas import ( - Guideline, GuidelineSection, GuidelineClause, RetrievalResult, AnswerWithCitations -) -from medical_ai_innovation.knowledge_base.kb_engine import KnowledgeBaseEngine -from medical_ai_innovation.knowledge_base.rag_pipeline import RAGPipeline +# 将 medical-ai-innovation 加入路径(相对路径,安装后可不依赖) +try: + from medical_ai_innovation.knowledge_base.schemas import ( + Guideline, RetrievalResult, AnswerWithCitations + ) + from medical_ai_innovation.knowledge_base.kb_engine import KnowledgeBaseEngine + from medical_ai_innovation.knowledge_base.rag_pipeline import RAGPipeline +except ImportError: + # 开发模式:通过相对路径查找 + _plugin_dir = os.path.dirname(os.path.abspath(__file__)) + _project_root = os.path.abspath(os.path.join(_plugin_dir, "..", "..", "..")) + if _project_root not in sys.path: + sys.path.insert(0, _project_root) + from medical_ai_innovation.knowledge_base.schemas import ( + Guideline, RetrievalResult, AnswerWithCitations + ) + from medical_ai_innovation.knowledge_base.kb_engine import KnowledgeBaseEngine + from medical_ai_innovation.knowledge_base.rag_pipeline import RAGPipeline class MedicalKnowledgeBasePlugin: @@ -74,19 +84,23 @@ def search(self, query: str, top_k: int = 5, **kwargs) -> dict: include_version_compare=include_version_compare, ) + citations = [] + for r in result.citations: + clause = r.clause + if not clause: + continue + citations.append({ + "content": clause.content or "", + "source": f"{clause.guideline_id or ''} | {clause.clause_num or ''} {clause.title or ''}", + "score": getattr(r, "score", 0.0) or 0.0, + "method": getattr(r, "method", "") or "", + "evidence_level": clause.evidence_level or "", + "recommendation": clause.recommendation or "", + }) + return { "answer": result.answer, - "citations": [ - { - "content": r.clause.content, - "source": f"{r.clause.guideline_id} | {r.clause.clause_num} {r.clause.title}", - "score": r.score, - "method": r.method, - "evidence_level": r.clause.evidence_level, - "recommendation": r.clause.recommendation, - } - for r in result.citations - ], + "citations": citations, "total_found": len(result.citations), "plugin": "medical_kb", "retrieval_methods": result.retrieval_methods, @@ -109,8 +123,8 @@ def load_guidelines(self, guidelines: list[Guideline]): def load_demo_guidelines(self): """加载内置示例指南(糖尿病+高血压)""" - from medical_ai_innovation.knowledge_base.cli import _build_demo_guidelines - self.load_guidelines(_build_demo_guidelines()) + from medical_ai_innovation.knowledge_base.demo_data import get_demo_guidelines + self.load_guidelines(get_demo_guidelines()) def get_guideline_list(self) -> list[dict]: """获取已加载的指南列表""" @@ -156,7 +170,8 @@ def main(): plugin = MedicalKnowledgeBasePlugin() plugin.load_demo_guidelines() - print(f"📚 已加载 {plugin.get_stats()['guidelines']} 部指南") + stats = plugin.get_stats() + print(f"📚 已加载 {stats.get('guidelines', 0)} 部指南") print() while True: @@ -171,10 +186,15 @@ def main(): break result = plugin.search(q, include_version_compare=True) - print(f"\n🤖 {result['answer'][:300]}...\n") + answer_preview = result["answer"][:300] + print(f"\n🤖 {answer_preview}") + if len(result["answer"]) > 300: + print(" ...(回答已截断,完整内容请查看引用)") print(f"📚 引用 {result['total_found']} 条") for i, c in enumerate(result["citations"][:3], 1): - print(f" [{i}] {c['source']} (score: {c['score']})") + source = c.get("source", "未知来源") + score = c.get("score", 0) + print(f" [{i}] {source} (score: {score})") print()