Bladeren bron

智能体查询接口
1、药物适应症
2、疾病相关就诊科室
3、疾病相关实验室检查
4、疾病相关辅助检查

yuchengwei 3 dagen geleden
bovenliggende
commit
19e7b03863
2 gewijzigde bestanden met toevoegingen van 626 en 145 verwijderingen
  1. 383 110
      src/knowledge/main.py
  2. 243 35
      src/knowledge/service/search_service.py

+ 383 - 110
src/knowledge/main.py

@@ -158,6 +158,134 @@ async def get_symptom_diseases(
         logger.exception(f"获取症状相关疾病失败: {str(e)}")
         raise HTTPException(500, detail=StandardResponse.error(str(e)))
 
+
+@app.post("/get_lab_examinations", 
+          response_model=StandardResponse, 
+          operation_id="getLabExaminations",
+          summary="根据疾病名称获取相关实验室检查",
+          description="""根据疾病名称获取该疾病的相关实验室检查项目。
+
+该接口主要用于医疗知识查询场景,例如:
+- 通过输入疾病名称查询其相关实验室检查
+- 了解疾病的常规检验项目
+- 辅助临床检验决策
+
+典型应用场景:
+1. 临床检验辅助:通过疾病名称查询其相关实验室检查
+2. 检验科参考:了解疾病应该做哪些实验室检查
+3. 医学知识问答系统:为AI提供结构化实验室检查数据
+
+输入要求:
+- 仅支持标准疾病名称
+- 不支持症状描述或编码
+
+输出格式:
+- 返回标准JSON响应
+- 包含实验室检查项目列表""",
+          response_description="""返回标准响应格式,包含实验室检查项目列表。
+
+成功响应示例:
+{
+    "success": true,
+    "data": {
+        "disease": "糖尿病",
+        "lab_examinations": [
+            "空腹血糖",
+            "糖化血红蛋白"
+        ]
+    }
+}
+
+错误响应示例:
+{
+    "success": false,
+    "error": "Invalid disease name"
+}"""
+          )
+async def get_lab_examinations(
+        disease_name: str = Query(..., 
+                  alias="diseaseName", 
+                  description="""疾病名称(仅支持标准疾病名称)。
+
+该参数用于查询该疾病的相关实验室检查项目。
+必须使用标准疾病名称。
+示例值:"糖尿病""",
+                  examples=["糖尿病"],
+                  min_length=1,
+                  max_length=50)
+):
+    try:
+        search = SearchBusiness()
+        results = search.get_lab_examinations(disease_name=disease_name)
+        return StandardResponse(success=True, data=results)
+    except Exception as e:
+        logger.error(f"实验室检查查询失败: {str(e)}")
+        raise HTTPException(500, detail=StandardResponse.error(str(e)))
+
+
+@app.post("/get_auxiliary_examinations", 
+          response_model=StandardResponse, 
+          operation_id="getAuxiliaryExaminations",
+          summary="根据疾病名称获取相关辅助检查",
+          description="""根据疾病名称获取该疾病的相关辅助检查项目。
+
+该接口主要用于医疗知识查询场景,例如:
+- 通过输入疾病名称查询其相关辅助检查
+- 了解疾病的常规检查项目
+- 辅助临床检查决策
+
+典型应用场景:
+1. 临床检查辅助:通过疾病名称查询其相关辅助检查
+2. 影像科参考:了解疾病应该做哪些辅助检查
+3. 医学知识问答系统:为AI提供结构化辅助检查数据
+
+输入要求:
+- 仅支持标准疾病名称
+- 不支持症状描述或编码
+
+输出格式:
+- 返回标准JSON响应
+- 包含辅助检查项目列表""",
+          response_description="""返回标准响应格式,包含辅助检查项目列表。
+
+成功响应示例:
+{
+    "success": true,
+    "data": {
+        "disease": "冠心病",
+        "auxiliary_examinations": [
+            "心电图",
+            "冠状动脉造影"
+        ]
+    }
+}
+
+错误响应示例:
+{
+    "success": false,
+    "error": "Invalid disease name"
+}"""
+          )
+async def get_auxiliary_examinations(
+        disease_name: str = Query(..., 
+                  alias="diseaseName", 
+                  description="""疾病名称(仅支持标准疾病名称)。
+
+该参数用于查询该疾病的相关辅助检查项目。
+必须使用标准疾病名称。
+示例值:"冠心病""",
+                  examples=["冠心病"],
+                  min_length=1,
+                  max_length=50)
+):
+    try:
+        search = SearchBusiness()
+        results = search.get_auxiliary_examinations(disease_name=disease_name)
+        return StandardResponse(success=True, data=results)
+    except Exception as e:
+        logger.error(f"辅助检查查询失败: {str(e)}")
+        raise HTTPException(500, detail=StandardResponse.error(str(e)))
+
 @app.post("/getDiseaseSymptoms",
           response_model=StandardResponse,
           operation_id="getDiseaseSymptoms",
@@ -252,22 +380,74 @@ async def getDiseaseSymptoms(
 #         raise HTTPException(500, detail=StandardResponse.error(str(e)))
 #
 #
-# # 2. 药物相关接口
-# class DrugRequest(BaseModel):
-#     drug_id: str
-#
-#
-# @app.post("/drug_indications", response_model=StandardResponse)
-# async def get_drug_indications(
-#         request: DrugRequest,
-#         db: Session = Depends(get_db)
-# ):
-#     try:
-#         # 实现获取药物适应症的逻辑
-#         return StandardResponse(success=True, data=[])
-#     except Exception as e:
-#         logger.error(f"获取药物适应症失败: {str(e)}")
-#         raise HTTPException(500, detail=StandardResponse.error(str(e)))
+# 2. 药物相关接口
+
+@app.post("/drug_indications", 
+          response_model=StandardResponse, 
+          operation_id="getDrugIndications",
+          summary="根据药物名称获取适应症",
+          description="""根据药物名称获取该药物的所有适应症。
+
+该接口主要用于医疗知识查询场景,例如:
+- 通过输入药物名称查询其适应症
+- 了解药物的主要治疗范围
+- 辅助临床用药决策
+
+典型应用场景:
+1. 临床用药辅助:通过药物名称查询其适应症
+2. 患者教育:了解药物的治疗范围
+3. 医学知识问答系统:为AI提供结构化药物适应症数据
+
+输入要求:
+- 仅支持标准药物名称
+- 不支持商品名或编码
+
+输出格式:
+- 返回标准JSON响应
+- 包含适应症列表""",
+          response_description="""返回标准响应格式,包含适应症列表。
+
+成功响应示例:
+{
+    "success": true,
+    "data": {
+        "drug": "阿司匹林",
+        "indications": [
+            "镇痛",
+            "解热",
+            "抗炎",
+            "抗风湿",
+            "预防心血管事件"
+        ]
+    }
+}
+
+错误响应示例:
+{
+    "success": false,
+    "error": "Invalid drug name"
+}"""
+          )
+async def get_drug_indications(
+        drug_name: str = Query(..., 
+                  alias="drugName", 
+                  description="""药物名称(仅支持标准药物名称,不支持商品名)。
+
+该参数用于查询该药物的所有适应症。
+必须使用标准药物名称。
+示例值:"阿司匹林""",
+                  examples=["阿司匹林"],
+                  min_length=1,
+                  max_length=50)
+):
+    try:
+        # 实现获取药物适应症的逻辑
+        search = SearchBusiness()
+        results = search.get_drug_indications(drug_name)
+        return StandardResponse(success=True, data=results)
+    except Exception as e:
+        logger.error(f"获取药物适应症失败: {str(e)}")
+        raise HTTPException(500, detail=StandardResponse.error(str(e)))
 
 
 # @app.post("/drug_contraindications", response_model=StandardResponse)
@@ -297,53 +477,56 @@ async def getDiseaseSymptoms(
 
 
 # 3. 关系与概念处理接口
-class ConceptSearchRequest(BaseModel):
-    query: str
-    type: Optional[str] = None
+@app.post("/search_concept",
+          response_model=StandardResponse, 
+          operation_id="searchConcept",
+          summary="根据名称和类型搜索医学概念",
+          description="""根据概念名称和类型搜索医学概念节点。
 
+该接口主要用于医疗知识图谱中的概念搜索场景,例如:
+- 通过输入疾病名称和类型搜索相关疾病概念
+- 通过输入症状名称和类型搜索相关症状概念
+- 通过输入药物名称和类型搜索相关药物概念
 
-class ConceptRelationsRequest(BaseModel):
-    concept_id: str
+典型应用场景:
+1. 疾病概念搜索:输入疾病名称获取相关概念
+2. 症状概念搜索:输入症状名称获取相关概念
+3. 药物概念搜索:输入药物名称获取相关概念
 
+输入要求:
+- 概念名称应为标准医学术语
+- 类型参数可选,用于限定搜索范围
 
-class SimilarConceptsRequest(BaseModel):
-    concept_id: str
-    top_k: int = 5
+输出格式:
+- 返回标准JSON响应
+- 包含匹配的概念列表""",
+          response_description="""返回标准响应格式,包含匹配的概念列表。
 
+成功响应示例:
+{
+    "success": true,
+    "data": {
+        "concepts": [
+            {"name": "糖尿病", "type": "疾病"},
+            {"name": "高血压", "type": "疾病"}
+        ]
+    }
+}
 
-@app.post("/search_concept",
-          operation_id="医学概念搜索",
-          summary="根据名称和类型搜索医学概念",
-          description="""根据概念名称和类型搜索医学概念节点。
-    该接口主要用于医疗知识图谱中的概念搜索场景,例如:
-    - 通过输入疾病名称和类型搜索相关疾病概念
-    - 通过输入症状名称和类型搜索相关症状概念
-    - 通过输入药物名称和类型搜索相关药物概念
-
-    典型应用场景包括:
-    - 疾病概念搜索
-    - 症状概念搜索
-    - 药物概念搜索""",
-          response_description="""返回标准响应格式,包含匹配的概念列表。
-    格式为:
-    {
-        "success": bool,
-        "data": {
-            "concepts": [
-                {"id": str, "name": str, "type": str}
-            ]
-        }
-    }""",
-          response_model=StandardResponse
+错误响应示例:
+{
+    "success": false,
+    "error": "Invalid concept name"
+}"""
           )
 async def search_concept(
         concept_name: str = Query(...,
                   description="概念名称,应为标准医学术语。该参数用于搜索匹配的概念节点。",
-                  examples="糖尿病",
+                  examples=["糖尿病"],
                   min_length=1),
         concept_type: str = Query(None,
                   description="概念类型,可选参数。用于限定搜索的概念类型。",
-                  examples="疾病")
+                  examples=["疾病", "症状", "药物"])
 ):
     try:
         # 实现搜索医学概念的逻辑
@@ -355,75 +538,113 @@ async def search_concept(
         raise HTTPException(500, detail=StandardResponse.error(str(e)))
 
 
-@app.post("/get_relations",
-          operation_id="医学概念关系查询",
-          summary="根据概念ID查询相关关系",
-          description="""根据概念ID查询该概念的相关关系。
-    该接口主要用于医疗知识图谱中的关系查询场景,例如:
-    - 通过输入疾病概念ID查询相关症状概念ID
-    - 通过输入症状概念ID查询相关疾病概念ID
-    - 通过输入药物概念ID查询相关治疗方法概念ID
+@app.post("/get_relations", 
+          response_model=StandardResponse,
+          operation_id="getConceptRelations",
+          summary="根据概念名称查询相关关系",
+          description="""根据概念名称查询该概念的相关关系列表。
+
+该接口主要用于医疗知识图谱中的关系查询场景,例如:
+- 通过输入疾病概念名称查询相关症状
+- 通过输入症状概念名称查询相关疾病
+- 通过输入药物概念名称查询适应症
+
+典型应用场景:
+1. 疾病症状关系查询:输入疾病名称获取相关症状
+2. 症状疾病关系查询:输入症状名称获取相关疾病
+3. 药物适应症查询:输入药物名称获取适应症
+
+输入要求:
+- 概念名称应为标准医学术语
 
-    典型应用场景包括:
-    - 疾病症状关系查询
-    - 症状疾病关系查询
-    - 药物治疗方法关系查询""",
+输出格式:
+- 返回标准JSON响应
+- 包含相关关系列表""",
           response_description="""返回标准响应格式,包含相关关系列表。
-    格式为:
-    {
-        "success": bool,
-        "data": {
-            "relations": [
-                {"relation_type": str, "target_id": str, "target_name": str}
-            ]
-        }
-    }""",
-          response_model=StandardResponse
+
+成功响应示例:
+{
+    "success": true,
+    "data": {
+        "relations": [
+            {"relation_type": "has_symptom", "target_id": "S001", "target_name": "发热"},
+            {"relation_type": "has_symptom", "target_id": "S002", "target_name": "咳嗽"}
+        ]
+    }
+}
+
+错误响应示例:
+{
+    "success": false,
+    "error": "Invalid concept ID"
+}"""
           )
 async def get_relations(
         concept_name: str = Query(...,
                   description="概念ID,应为标准医学术语ID。该参数用于查询该概念的相关关系。",
-                  examples="D001",
-                  min_length=1)
+                  examples=["糖尿病"],
+                  min_length=1),
+        concept_type: str = Query(None,
+                  description="概念类型,可选参数。用于限定搜索的概念类型。",
+                  examples=["疾病", "症状", "药物"])          
 ):
     try:
         # 实现获取概念关系的逻辑
         search = SearchBusiness()
-        results = search.get_relations(src_id=concept_name)
+        results = search.get_relations(name=concept_name, type=concept_type)
         return StandardResponse(success=True, data=results)
     except Exception as e:
         logger.error(f"获取概念关系失败: {str(e)}")
         raise HTTPException(500, detail=StandardResponse.error(str(e)))
 
 
-@app.post("/get_similar_concepts", response_model=StandardResponse,
-          operation_id="相似概念查询",
-          summary="根据概念ID查询相似概念",
-          description="""根据概念ID查询该概念的相似概念。
-    该接口主要用于医疗知识图谱中的相似概念查询场景,例如:
-    - 通过输入疾病概念ID查询相关症状概念ID
-    - 通过输入症状概念ID查询相关疾病概念ID
-    - 通过输入药物概念ID查询相关治疗方法概念ID
+@app.post("/get_similar_concepts", 
+          response_model=StandardResponse,
+          operation_id="getSimilarConcepts",
+          summary="根据概念名称查询相似概念",
+          description="""根据概念名称查询该概念的相似概念列表。
+
+该接口主要用于医疗知识图谱中的相似概念查询场景,例如:
+- 通过输入疾病名称查询相似疾病概念
+- 通过输入症状名称查询相似症状概念
+- 通过输入药物名称查询相似药物概念
+
+典型应用场景:
+1. 疾病概念扩展:输入疾病名称获取相关相似疾病
+2. 症状概念扩展:输入症状名称获取相关相似症状
+3. 药物概念扩展:输入药物名称获取相关相似药物
+
+输入要求:
+- 概念名称应为标准医学术语
+- 可指定返回相似概念的数量限制
 
-    典型应用场景包括:
-    - 疾病相似概念查询
-    - 症状相似概念查询
-    - 药物相似概念查询""",
+输出格式:
+- 返回标准JSON响应
+- 包含相似概念列表""",
           response_description="""返回标准响应格式,包含相似概念列表。
-    格式为:
-    {
-        "success": bool,
-        "data": {
-            "similar_concepts": [
-                {"id": str, "name": str, "similarity": str}
-            ]
-        }
-    }""",
+
+成功响应示例:
+{
+    "success": true,
+    "data": {
+        "similar_concepts": [
+            "艾滋病",
+            "成人艾滋病",
+            "儿童艾滋病"
+        ]
+    }
+}
+
+错误响应示例:
+{
+    "success": false,
+    "error": "Invalid concept name"
+}"""
           )
 async def get_similar_concepts(
         concept_name: str = Query(...,
-                  description="概念ID,应为标准医学术语ID。该参数用于查询该概念的相似概念。",
-                  examples="D001",
+                  description="概念名称,应为标准医学术语。该参数用于查询该概念的相似概念。",
+                  examples=["艾滋病"],
                   min_length=1),
         top_k: int = Query(5,
                   description="返回相似概念的数量限制,默认为5。",
@@ -432,7 +653,7 @@ async def get_similar_concepts(
     try:
         # 1. 先根据ID获取节点名称
         search = SearchBusiness()
-        results = search.get_similar_concepts(id=concept_name, top_k=top_k)
+        results = search.get_similar_concepts(name=concept_name, top_k=top_k)
 
         return StandardResponse(success=True, data=results)
     except Exception as e:
@@ -517,17 +738,69 @@ class DepartmentRequest(BaseModel):
 #         raise HTTPException(500, detail=StandardResponse.error(str(e)))
 #
 #
-# @app.post("/medical/suggest_department", response_model=StandardResponse)
-# async def suggest_appropriate_department(
-#         request: DepartmentRequest,
-#         db: Session = Depends(get_db)
-# ):
-#     try:
-#         # 实现科室推荐的逻辑
-#         return StandardResponse(success=True, data=[])
-#     except Exception as e:
-#         logger.error(f"科室推荐失败: {str(e)}")
-#         raise HTTPException(500, detail=StandardResponse.error(str(e)))
+@app.post("/suggest_appropriate_department", 
+          response_model=StandardResponse, 
+          operation_id="suggestAppropriateDepartment",
+          summary="根据疾病名称获取推荐科室",
+          description="""根据疾病名称获取该疾病的推荐科室。
+
+该接口主要用于医疗知识查询场景,例如:
+- 通过输入疾病名称查询其推荐就诊科室
+- 了解疾病的专科归属
+- 辅助临床分诊决策
+
+典型应用场景:
+1. 临床分诊辅助:通过疾病名称查询其推荐科室
+2. 患者就医指导:了解疾病应该挂哪个科室
+3. 医学知识问答系统:为AI提供结构化疾病科室推荐数据
+
+输入要求:
+- 仅支持标准疾病名称
+- 不支持症状描述或编码
+
+输出格式:
+- 返回标准JSON响应
+- 包含推荐科室列表""",
+          response_description="""返回标准响应格式,包含推荐科室列表。
+
+成功响应示例:
+{
+    "success": true,
+    "data": {
+        "disease": "艾滋病",
+        "departments": [
+            "感染科",
+            "皮肤性病科"
+        ]
+    }
+}
+
+错误响应示例:
+{
+    "success": false,
+    "error": "Invalid disease name"
+}"""
+          )
+async def suggest_appropriate_department(
+        disease_name: str = Query(..., 
+                  alias="diseaseName", 
+                  description="""疾病名称(仅支持标准疾病名称)。
+
+该参数用于查询该疾病的推荐科室。
+必须使用标准疾病名称。
+示例值:"艾滋病""",
+                  examples=["艾滋病"],
+                  min_length=1,
+                  max_length=50)
+):
+    try:
+        # 实现科室推荐的逻辑
+        search = SearchBusiness()
+        results = search.suggest_appropriate_department(disease_name=disease_name)
+        return StandardResponse(success=True, data=results)
+    except Exception as e:
+        logger.error(f"科室推荐失败: {str(e)}")
+        raise HTTPException(500, detail=StandardResponse.error(str(e)))
 #
 #
 # # 5. 病历质控接口

+ 243 - 35
src/knowledge/service/search_service.py

@@ -1,3 +1,4 @@
+import re
 import sys,os
 current_path = os.getcwd()
 sys.path.append(current_path)
@@ -263,54 +264,157 @@ class SearchBusiness:
     def search_concept(self, name, type):
         nodes = self.search_nodes(name=name, type=type)
         concepts = [
-            {"id": node["public_kg_nodes_id"], "name": node["public_kg_nodes_name"], "type": node["public_kg_nodes_category"]}
+            {"name": node["public_kg_nodes_name"], "type": node["public_kg_nodes_category"]}
             for node in nodes
         ] if nodes else []
         return {"concepts": concepts}
 
-    def get_relations(self, src_id):
-        edges = self.search_edges(src_id=src_id, size=2000)
-        if not edges:
-            return {"relations": []}
-
-        dest_ids = [edge["public_kg_edges_dest_id"] for edge in edges]
-        nodes = self.search_nodes(ids=dest_ids)
-        node_map = {node["public_kg_nodes_id"]: node for node in nodes}
-
-        relations = []
-        for edge in edges:
-            dest_id = edge["public_kg_edges_dest_id"]
-            if dest_id in node_map:
-                relations.append({
-                    "relation_type": edge["public_kg_edges_category"],
-                    "target_id": dest_id,
-                    "target_name": node_map[dest_id].get("public_kg_nodes_name", "")
-                })
-
-        return {"relations": relations}
-
-    def get_similar_concepts(self, id, top_k=5):
-        # 1. 先根据ID获取节点名称
-        node = self.search_nodes(id=id, limit=1)
-        if not node:
-            return {"similar_concepts": []}
+    def get_relations(self, name, type):
+        # 首先根据name和type查询nodes表数据
+        nodes = self.search_nodes(name=name, type=type)
+        if not nodes:
+            return {}
+            
+        result = {}
+        for node in nodes:
+            node_name = node.get("public_kg_nodes_name", "")
+            if not node_name:
+                continue
+                
+            # 使用node id作为src_id查询edges关系表
+            edges = self.search_edges(src_id=node["public_kg_nodes_id"])
+            if not edges:
+                result[node_name] = {"relations": []}
+                continue
+                
+            # 收集所有目标节点ID
+            dest_ids = [edge["public_kg_edges_dest_id"] for edge in edges]
+            # 查询目标节点信息
+            dest_nodes = self.search_nodes(ids=dest_ids)
+            node_map = {n["public_kg_nodes_id"]: n for n in dest_nodes}
+            
+            # 构建关系列表
+            relations = []
+            for edge in edges:
+                dest_id = edge["public_kg_edges_dest_id"]
+                if dest_id in node_map:
+                    relations.append({
+                        "relation_type": edge["public_kg_edges_category"],
+                        "target_name": node_map[dest_id].get("public_kg_nodes_name", "")
+                    })
+            
+            result[node_name] = {"relations": relations}
+        
+        return result
 
+    def get_similar_concepts(self, name, top_k=5):
         # 2. 使用节点名称进行相似搜索
-        node_name = node[0]["public_kg_nodes_name"]
-        results = self.search_nodes(name=node_name, limit=top_k)
-
+        results = self.search_nodes(name=name, limit=top_k)
+        logger.info(f"Similar concepts search results: {results}")
         # 3. 格式化返回结果
         similar_concepts = [
-            {
-                "id": result["public_kg_nodes_id"],
-                "name": result["public_kg_nodes_name"],
-                "similarity": result.get("_score", 0.0)
-            }
+            result["public_kg_nodes_name"]
             for result in results
         ]
 
         return {"similar_concepts": similar_concepts}
+     
+    def get_drug_indications(self, drug_name):
+        drugs = self.search_nodes(name=drug_name, type="药品")
+        if not drugs:
+            return []
+
+        drug_map = {}
+        
+        for drug in drugs:
+            drug_name = drug.get("public_kg_nodes_name", "")
+            
+            if drug_name not in drug_map:
+                drug_map[drug_name] = {
+                    "drug": drug_name,
+                    "indications": []
+                }
+            
+            drug_info = drug_map[drug_name]
+            
+            # 查询药物适应症关系
+            edges = self.search_edges(name="适应症", src_id=drug["public_kg_nodes_id"])
+            logger.info(f"Get indications by drug id: {drug['public_kg_nodes_id']}, result: {edges}")
+            if not edges:
+                continue
+
+            # 收集适应症节点ID
+            indication_ids = [edge["public_kg_edges_dest_id"] for edge in edges if "public_kg_edges_dest_id" in edge]
+            if not indication_ids:
+                continue
+
+            # 查询适应症节点信息
+            indications = self.search_nodes(ids=indication_ids)
+            if not indications:
+                continue
+
+            # 收集适应症名称
+            for indication in indications:
+                if "public_kg_nodes_name" in indication:
+                    indication_name = indication["public_kg_nodes_name"]
+                    if indication_name not in drug_info["indications"]:
+                        drug_info["indications"].append(indication_name)
         
+        # 过滤掉适应症列表为空的药物
+        return [d for d in drug_map.values() if d["indications"]]
+
+    def suggest_appropriate_department(self, disease_name: str) -> list:
+        """
+        根据疾病名称推荐科室
+        :param disease_name: 疾病名称
+        :return: 返回疾病科室列表,每个元素包含疾病名称和对应的科室列表
+        """
+        try:
+            # 1. 根据疾病名称查询疾病列表
+            diseases = self.search_nodes(name=disease_name, type="疾病")
+            if not diseases:
+                return []
+                
+            result = []
+            
+            for disease in diseases:
+                disease_info = {
+                    "disease_name": disease.get("public_kg_nodes_name", ""),
+                    "departments": []
+                }
+                
+                # 2. 查询每个疾病的科室关系
+                edges = self.search_edges(name="所属科室", src_id=disease["public_kg_nodes_id"])
+                if not edges:
+                    continue
+                    
+                # 3. 收集科室节点ID
+                department_ids = [edge["public_kg_edges_dest_id"] for edge in edges 
+                                if "public_kg_edges_dest_id" in edge]
+                if not department_ids:
+                    continue
+                    
+                # 4. 查询科室节点信息
+                departments = self.search_nodes(ids=department_ids)
+                if not departments:
+                    continue
+                    
+                # 5. 收集科室名称并去重
+                department_set = set()
+                for dept in departments:
+                    if "public_kg_nodes_name" in dept:
+                        department_set.add(dept["public_kg_nodes_name"])
+                
+                if department_set:
+                    disease_info["departments"] = list(department_set)
+                    result.append(disease_info)
+            
+            return result
+            
+        except Exception as e:
+            logger.error(f"科室推荐失败: {str(e)}")
+            return []
+
     def validate_medical_record(self, medical_record: str, validate_type: str) -> dict:
         """
         验证病历数据
@@ -342,6 +446,110 @@ class SearchBusiness:
         except Exception as e:
             logger.error(f"病历验证失败: {str(e)}")
             return {"valid": False, "errors": [f"验证过程中发生错误: {str(e)}"]}
+            
+    def get_lab_examinations(self, disease_name: str) -> list:
+        """
+        根据疾病名称获取相关实验室检查项目
+        :param disease_name: 疾病名称
+        :return: 返回疾病实验室检查列表,每个元素包含疾病名称和对应的实验室检查列表
+        """
+        try:
+            # 1. 根据疾病名称查询疾病列表
+            diseases = self.search_nodes(name=disease_name, type="疾病")
+            if not diseases:
+                return []
+                
+            result = []
+            
+            for disease in diseases:
+                disease_info = {
+                    "disease_name": disease.get("public_kg_nodes_name", ""),
+                    "lab_examinations": []
+                }
+                
+                # 2. 查询每个疾病的实验室检查关系
+                edges = self.search_edges(name="实验室检查", src_id=disease["public_kg_nodes_id"])
+                if not edges:
+                    continue
+                    
+                # 3. 收集实验室检查节点ID
+                lab_exam_ids = [edge["public_kg_edges_dest_id"] for edge in edges 
+                               if "public_kg_edges_dest_id" in edge]
+                if not lab_exam_ids:
+                    continue
+                    
+                # 4. 查询实验室检查节点信息
+                lab_exams = self.search_nodes(ids=lab_exam_ids)
+                if not lab_exams:
+                    continue
+                    
+                # 5. 收集实验室检查名称并去重
+                lab_exam_set = set()
+                for exam in lab_exams:
+                    if "public_kg_nodes_name" in exam:
+                        lab_exam_set.add(exam["public_kg_nodes_name"])
+                
+                if lab_exam_set:
+                    disease_info["lab_examinations"] = list(lab_exam_set)
+                    result.append(disease_info)
+            
+            return result
+            
+        except Exception as e:
+            logger.error(f"实验室检查查询失败: {str(e)}")
+            return []
+            
+    def get_auxiliary_examinations(self, disease_name: str) -> list:
+        """
+        根据疾病名称获取相关辅助检查项目
+        :param disease_name: 疾病名称
+        :return: 返回疾病辅助检查列表,每个元素包含疾病名称和对应的辅助检查列表
+        """
+        try:
+            # 1. 根据疾病名称查询疾病列表
+            diseases = self.search_nodes(name=disease_name, type="疾病")
+            if not diseases:
+                return []
+                
+            result = []
+            
+            for disease in diseases:
+                disease_info = {
+                    "disease_name": disease.get("public_kg_nodes_name", ""),
+                    "auxiliary_examinations": []
+                }
+                
+                # 2. 查询每个疾病的辅助检查关系
+                edges = self.search_edges(name="辅助检查", src_id=disease["public_kg_nodes_id"])
+                if not edges:
+                    continue
+                    
+                # 3. 收集辅助检查节点ID
+                aux_exam_ids = [edge["public_kg_edges_dest_id"] for edge in edges 
+                               if "public_kg_edges_dest_id" in edge]
+                if not aux_exam_ids:
+                    continue
+                    
+                # 4. 查询辅助检查节点信息
+                aux_exams = self.search_nodes(ids=aux_exam_ids)
+                if not aux_exams:
+                    continue
+                    
+                # 5. 收集辅助检查名称并去重
+                aux_exam_set = set()
+                for exam in aux_exams:
+                    if "public_kg_nodes_name" in exam:
+                        aux_exam_set.add(exam["public_kg_nodes_name"])
+                
+                if aux_exam_set:
+                    disease_info["auxiliary_examinations"] = list(aux_exam_set)
+                    result.append(disease_info)
+            
+            return result
+            
+        except Exception as e:
+            logger.error(f"辅助检查查询失败: {str(e)}")
+            return []
 
 
 if __name__ == "__main__":