大模型应用:AI 智能体核心引擎:RAG检索增强生成原理与医疗场景深度落地.126

简介: 本文详解RAG(检索增强生成)在医疗智能体中的落地实践:针对大模型知识过时、幻觉、专业性不足三大痛点,基于Qwen本地大模型、MiniLM嵌入、FAISS向量库与LangChain框架,实现全流程可追溯、全本地化、无幻觉的精准问答。含环境配置、适配器封装、知识库构建及调试分析。

一、前言

       在 AI 智能体的实际落地中,大模型知识过时、事实性幻觉、专业领域回答不精准是三大核心痛点。检索增强生成RAG作为解决上述问题的最优方案,已经成为 AI 智能体的标配能力。RAG 的核心逻辑极简且高效:不依赖大模型记忆,先从外部知识库精准检索相关知识,再让大模型基于检索结果生成答案,从根源上杜绝幻觉,保证知识实时性与专业性。

       今天我们结合以往的各类基础知识,基于Qwen本地大模型、FAISS 向量数据库、LangChain 框架以及MiniLM模型,以医疗智能体为场景,深度解析RAG原理、核心组件,提供可完整适配智能体的实践方案。

127.2-AI智能体核心引擎.png

二、RAG 核心原理

1. 大模型的缺陷

  • 知识截止:模型训练数据固定,无法获取最新知识,如最新医疗指南
  • 事实幻觉:凭空编造不存在的医疗建议、数据,存在安全风险
  • 专业不足:通用大模型在医疗、法律等垂直领域精度不足

127.3-RAG 与原生模型答案准确率对比 rag_vs_base_comparison.png

2. RAG 工作流程

标准 RAG 五步法:

127.4-RAG 核心工作流程 medical_rag_process.png

  • 1. 用户提问:输入医疗相关问题
  • 2. Embedding 向量化:将问题转换为数值向量
  • 3. FAISS 语义检索:在向量库中匹配最相关的专业知识
  • 4. 知识召回:筛选高相似度可信知识
  • 5. 大模型生成:严格基于召回知识生成合规答案

核心价值:答案可追溯、知识可更新、无幻觉、全本地化部署

3. 技术选型说明

模块 技术选型 核心优势
大语言模型 Qwen1.5-1.8B-Chat 轻量级、CPU 可运行、私有化部署
向量模型 paraphrase-multilingual-MiniLM-L12-v2 多语言支持、语义匹配精度高、轻量化
向量数据库 FAISS Facebook 开源、CPU 本地检索、毫秒级响应
开发框架 LangChain 标准化 RAG 流程、组件化开发
应用场景 医疗问答智能体 知识合规、答案可追溯、无幻觉

三、RAG 实践案例

1. 环境与模型初始化

核心目标:加载本地大模型 + 向量模型,避免重复下载,保证数据隐私。

# 模型路径配置
model_name = "qwen/Qwen1.5-1.8B-Chat"
embedding_model_id = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
cache_dir = "D:\\modelscope\\hub"
# 加载本地大模型(CPU兼容)
local_model_path = snapshot_download(model_name, cache_dir=cache_dir)
tokenizer = AutoTokenizer.from_pretrained(local_model_path, trust_remote_code=True)
llm_model = AutoModelForCausalLM.from_pretrained(
    local_model_path, trust_remote_code=True,
    torch_dtype=torch.float32, device_map="cpu"
).eval()
# 加载向量模型
embedding_local_path = snapshot_download(embedding_model_id, cache_dir=cache_dir)
embedding_model = SentenceTransformer(embedding_local_path, device="cpu")

image.gif

重点说明:

  • 模型路径配置:指定大模型与向量模型名称及本地缓存目录,统一管理资源下载路径,便于离线部署与维护。
  • 大模型本地加载:通过snapshot_download获取模型文件,利用CPU加载量化后的对话模型,降低硬件门槛并保障隐私。
  • 推理环境优化:设置float32精度与CPU设备映射,调用eval模式冻结参数,确保在无GPU环境下稳定进行推理。
  • 向量模型初始化:独立加载多语言句子变换模型至CPU,专用于文本向量化,实现语义检索与大模型生成的解耦。

2. 自定义向量适配器

向量模型(Embedding)是 RAG 的翻译官,负责把文字转换为计算机可计算的向量。

# --------------------------
# 3. 自定义LangChain Embedding适配器
# 作用:将句子转换为向量,用于语义匹配
# --------------------------
class LocalEmbedding(Embeddings):
    def __init__(self, model):
        self.model = model
    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        return self.model.encode(texts, convert_to_numpy=True).tolist()
    def embed_query(self, text: str) -> List[float]:
        return self.model.encode(text, convert_to_numpy=True).tolist()
embedding = LocalEmbedding(embedding_model)

image.gif

核心作用:

  • LangChain协议适配:继承Embeddings基类,封装本地模型接口,使其兼容LangChain生态,实现无缝集成。
  • 批量文档嵌入:embed_documents方法支持文本列表批量编码,高效处理知识库构建时的大规模数据向量化。
  • 单句查询嵌入:embed_query方法专为用户提问设计,将单条文本转为向量,用于实时检索时的语义匹配。
  • 本地模型封装:直接调用本地模型encode接口并转换格式,避免网络依赖,保障医疗数据隐私与低延迟。

127.5-医疗知识向量空间分布 medical_vector_space.png

3. 自定义大模型适配器

将 Qwen 大模型封装为 LangChain 标准 LLM,实现可控、可追溯、无幻觉的生成能力。

class LocalQwenLLM(LLM):
    tokenizer: Any
    model: Any
    max_new_tokens: int = 512
    temperature: float = 0.1  # 低温度=高确定性,杜绝幻觉
    @property
    def _llm_type(self) -> str:
        return "qwen_local"
    def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
        inputs = self.tokenizer(prompt, return_tensors="pt")
        with torch.no_grad():
            outputs = self.model.generate(
                **inputs, max_new_tokens=self.max_new_tokens,
                temperature=self.temperature, do_sample=False
            )
        return self.tokenizer.decode(outputs[0][len(inputs["input_ids"][0]):], skip_special_tokens=True)

image.gif

重点说明:

  • LangChain接口封装:继承LLM基类并定义类型,将本地Qwen模型包装为标准组件,无缝接入LangChain调用链。
  • 低温度防幻觉:设置0.1低温与贪婪解码,抑制随机性,确保医疗回答严谨确定,最大限度减少模型幻觉。
  • 无梯度推理执行:使用no_grad上下文阻断梯度计算,调用generate生成文本,显著降低显存占用并提升推理速度。
  • 精准回复提取:解码时自动剔除输入提示词部分,仅返回模型新生成的内容,保证输出结果纯净且可直接使用。

关键参数解析:

  • temperature=0.1:降低生成随机性,保证医疗答案严谨性
  • do_sample=False:禁用采样,生成确定性结果
  • torch.no_grad():推理禁用梯度计算,提速 50% 以上

4. FAISS 向量库构建

FAISS 是 RAG 的检索核心,负责海量知识的快速语义匹配。

# 医疗专业知识库(可扩展PDF/Excel/数据库)
medical_knowledge = [
    Document(page_content="高血压饮食建议:低盐饮食,每日食盐不超过5克...", metadata={"category": "饮食", "disease": "高血压"}),
    Document(page_content="糖尿病饮食建议:控制碳水化合物摄入量...", metadata={"category": "饮食", "disease": "糖尿病"}),
    Document(page_content="感冒护理建议:保证充足睡眠,多饮温水...", metadata={"category": "护理", "disease": "感冒"}),
    Document(page_content="冠心病预防:戒烟限酒,规律运动...", metadata={"category": "预防", "disease": "冠心病"})
]
# 构建FAISS向量库 + 本地持久化
vector_store = FAISS.from_documents(medical_knowledge, embedding)
vector_store.save_local("D:\\medical_rag_faiss_db", "medical_index")

image.gif

重点说明:

  • 数据结构化存储:采用Document对象封装内容与元数据,清晰分类疾病与类别,便于后续精准检索与过滤。
  • 知识库可扩展性:列表结构支持动态追加,可轻松接入PDF、Excel等多源医疗数据,灵活构建大规模知识库。
  • FAISS向量库构建:利用FAISS将文档向量化并建立索引,实现毫秒级高维语义搜索,大幅提升检索效率。
  • 本地持久化保存:将构建好的向量索引保存至本地磁盘,避免重复计算,支持系统重启后快速加载与复用。

5. 问答相似度匹配计算

主要用于调试和分析检索增强生成(RAG)系统中“问题”与“医疗知识库文档”之间的匹配程度。通过计算余弦相似度,量化用户提出的问题与库中每一篇文档的相关性,并打印出得分和简要内容。

def show_similarity_scores(question: str):
    """展示问题与所有文档的相似度得分"""
    print(f"\n[向量相似度分析] 问题: {question}")
    print("-" * 50)
    # 计算问题向量
    query_vector = embedding.embed_query(question)
    # 计算与每个文档的相似度
    import numpy as np
    for i, doc in enumerate(medical_knowledge):
        doc_vector = embedding.embed_query(doc.page_content)
        # 余弦相似度
        query_np = np.array(query_vector)
        doc_np = np.array(doc_vector)
        similarity = np.dot(query_np, doc_np) / (np.linalg.norm(query_np) * np.linalg.norm(doc_np))
        # 标记是否超过阈值
        status = "✓" if similarity > 0.6 else "✗"
        print(f"{status} 文档{i+1} ({doc.metadata['disease']}): {similarity:.4f}")
        print(f"  内容: {doc.page_content[:50]}...")
    print()

image.gif

重点说明:

  • 向量嵌入计算:将文本问题与文档转化为高维向量,使计算机能数值化地衡量语义相似度,是检索的基础。
  • 余弦相似度算法:通过计算向量夹角余弦值量化相关性,结果越接近1表示语义越相似,用于精准匹配文档。
  • 阈值判定机制:设定0.6为界限,自动标记命中或未命中文档,快速筛选高相关素材,辅助调整检索策略。
  • 元数据展示:提取疾病名称等关键标签,直观显示匹配来源,帮助开发者在医疗场景中快速定位错误关联。
  • 调试与可视化:遍历打印所有得分与摘要,专为开发调优设计,便于观察模型表现并优化知识库切片策略。

127.6-向量余弦相似度热力图 rag_similarity_heatmap.png

6. RAG 核心查询函数

这是AI 智能体的 RAG 大脑,实现:检索→过滤→提示词构建→生成全流程。

def rag_query(question: str, k: int = 2, threshold: float = 0.6) -> dict:
    # 1. 计算问题向量
    query_vector = embedding.embed_query(question)
    
    # 2. 余弦相似度检索 + 阈值过滤
    scored_docs = []
    for doc in medical_knowledge:
        doc_vector = embedding.embed_query(doc.page_content)
        similarity = np.dot(query_np, doc_np) / (np.linalg.norm(query_np) * np.linalg.norm(doc_np))
        if similarity > threshold:
            scored_docs.append((doc, similarity))
    
    # 3. 按相似度排序,取Top2
    scored_docs.sort(key=lambda x: x[1], reverse=True)
    docs = [doc for doc, score in scored_docs[:k]]
    # 4. 构建约束型提示词(强制基于知识回答)
    prompt = f"""你是专业医疗顾问,严格基于知识库回答,不编造信息。
    知识库:{context}
    用户问题:{question}"""
    # 5. 大模型生成答案
    answer = local_llm._call(prompt)
    return {"question": question, "answer": answer, "source_documents": docs}

image.gif

重点说明:

  • 余弦相似度计算:语义匹配最常用算法,数值越接近 1 越相关
  • 相似度阈值(0.6):过滤无关知识,避免干扰生成
  • Top-K 召回(2 条):平衡精度与效率
  • 约束提示词:从机制上杜绝大模型幻觉
  • 可追溯:返回来源文档,答案有据可查

7. 运行结果输出

加载本地大模型+Embedding模型...

构建医疗知识库...

构建FAISS向量检索库...

✅ 检索流程图已保存:medical_rag_process.png

==================================================

医疗问答测试

==================================================

用户问题:高血压患者平时应该怎么吃饭?

[调试] 检索到 1 条相关文档(阈值: 0.6):

 文档1 (相似度: 0.8282): 高血压饮食建议:低盐饮食,每日食盐不超过5克;多吃蔬菜、全谷物;减少油炸食品、动物内脏摄 入

 元数据: {'category': '饮食', 'disease': '高血压'}

模型答案:

高血压患者在日常饮食上应遵循以下原则:

1. **低盐饮食**:

  - 每日食盐量不超过5克(约0.9克)。

  - 食盐的主要成分是氯化钠,过多摄入可能导致血压升高。因此,高血压患者应尽量避免或限制食用含盐较高的食物,如腌制 食品、咸菜、方便面等。

  - 增加蔬菜和全谷物的摄入,这些食物富含钾离子,有助于降低血压。例如,新鲜的绿叶蔬菜(如菠菜、芹菜)、土豆、糙米 等都是良好的选择。

  - 减少油炸食品、动物内脏等高脂肪、高胆固醇的食物的摄入,因为它们会增加血液中的甘油三酯水平,进一步加重高血压症 状。

2. **多吃蔬菜、全谷物**:

  - 蔬菜和全谷物富含膳食纤维,能够帮助控制血糖和血脂,从而降低血压。同时,它们还含有丰富的维生素和矿物质,对身体 健康有益。

  - 可以选择各种颜色的蔬菜,如深绿色叶菜(如菠菜、羽衣甘蓝)、红色辣椒、黄色南瓜等,这些色彩丰富的蔬菜可以提供多 种营养素,满足身体对不同营养的需求。

  - 全谷物包括燕麦、糙米、全麦面包等,它们的碳水化合物含量较高,但相对于精制白米,

.......

==================================================

用户问题:感冒了需要注意什么?

[对比测试] 直接查看知识库中的感冒文档:

找到:感冒护理建议:保证充足睡眠,多饮温水,症状严重时可服用解热镇痛药,病程一般3-7天

[向量相似度分析] 问题: 感冒了需要注意什么?

--------------------------------------------------

✗ 文档1 (高血压): 0.2543

 内容: 高血压饮食建议:低盐饮食,每日食盐不超过5克;多吃蔬菜、全谷物;减少油炸食品、动物内脏摄入...

✗ 文档2 (糖尿病): 0.2573

 内容: 糖尿病饮食建议:控制碳水化合物摄入量,优先选择低升糖指数食物,定时定量进餐,避免含糖饮料...

✓ 文档3 (感冒): 0.6377

 内容: 感冒护理建议:保证充足睡眠,多饮温水,症状严重时可服用解热镇痛药,病程一般3-7天...

✗ 文档4 (冠心病): 0.2835

 内容: 冠心病预防:戒烟限酒,规律运动,控制血压血脂,避免情绪剧烈波动,定期体检...

[调试] 检索到 1 条相关文档(阈值: 0.6):

 文档1 (相似度: 0.6377): 感冒护理建议:保证充足睡眠,多饮温水,症状严重时可服用解热镇痛药,病程一般3-7天

 元数据: {'category': '护理', 'disease': '感冒'}

模型答案:

知识1: 感冒护理建议:

1. **保证充足睡眠**:充足的休息可以帮助身体恢复和抵抗病毒入侵,提高免疫力。

2. **多饮温水**:保持水分摄入有助于稀释黏液,减轻鼻塞、喉咙痛等症状,同时也能帮助缓解咳嗽和发热。

。。。。。。

总之,感冒期间应注意休息、补充水分、合理用药、加强个人卫生、调整饮食、保持室内空气流通以及适当运动,以帮助身体尽快恢复健康。若症状持续不减或加重,应及时就医并遵循医生的指导进行治疗。

==================================================

用户问题:感冒护理建议

[向量相似度分析] 问题: 感冒护理建议

--------------------------------------------------

✗ 文档1 (高血压): 0.2983

 内容: 高血压饮食建议:低盐饮食,每日食盐不超过5克;多吃蔬菜、全谷物;减少油炸食品、动物内脏摄入...

✗ 文档2 (糖尿病): 0.3093

 内容: 糖尿病饮食建议:控制碳水化合物摄入量,优先选择低升糖指数食物,定时定量进餐,避免含糖饮料...

✓ 文档3 (感冒): 0.7600

 内容: 感冒护理建议:保证充足睡眠,多饮温水,症状严重时可服用解热镇痛药,病程一般3-7天...

✗ 文档4 (冠心病): 0.4085

 内容: 冠心病预防:戒烟限酒,规律运动,控制血压血脂,避免情绪剧烈波动,定期体检...

[调试] 检索到 1 条相关文档(阈值: 0.6):

 文档1 (相似度: 0.7600): 感冒护理建议:保证充足睡眠,多饮温水,症状严重时可服用解热镇痛药,病程一般3-7天

 元数据: {'category': '护理', 'disease': '感冒'}

模型答案:

  - 睡眠是身体恢复和免疫力增强的重要环节,充足的睡眠有助于身体修复受损的组织、提高免疫系统的功能。

  - 患者应尽量保持规律的作息时间,避免熬夜或过度劳累,因为这些都可能影响身体对病毒的抵抗力。

  - 对于儿童和青少年,家长可以适当调整他们的作息时间,确保他们有足够的休息时间,以应对可能出现的感冒症状。      

  - 多喝水还可以帮助身体排除体内的毒素,促进新陈代谢,有利于病情的康复。

......

总之,感冒期间应注重休息、饮食调节以及适当的药物治疗,以促进身体的康复和减少并发症的发生。如果症状持续不减或者加重,应及时就医,遵医嘱进行治疗。同时,保持良好的个人卫生习惯,如勤洗手、戴口罩、避免人群聚集等,也是预防感冒的重要手段。

✅ 医疗知识库RAG系统部署完成!

结果分析:检索模块表现优异,精准匹配

  • 语义识别准确:系统能精准区分不同疾病场景。
  • 问“高血压饮食”时,仅召回高血压文档(相似度0.8282)。
  • 问“感冒”相关时,准确锁定感冒文档(相似度0.63~0.76),并有效过滤了高血压、糖尿病等无关文档(相似度均<0.41)。
  • 阈值控制有效:设定的 0.6 相似度阈值成功拦截了低相关性内容,保证了输入给大模型的上下文质量。

127.7-RAG 系统各模块耗时分布 rag_module_time.png

四、总结

       总的来说,RAG 才是 AI 智能体的硬核标配,说到底,RAG就是A 智能体的专属知识底座,更是根治大模型通病的关键方案,完美解决知识过时、事实幻觉、垂直领域不专业三大行业痛点,让智能体告别胡编乱造,回答精准又靠谱。它的核心逻辑“先检索、再生成”,对比模型微调成本更低、落地更快,知识库还能随时更新,不用反复训练模型,实用性拉满。

       如今 AI 智能体早已从通用化走向垂直深耕,RAG 早就不是可有可无的加分项,而是打造安全、可靠、可信专业智能体的必备能力,想让AI落地更加务实好用,RAG必须安排到位。

附录:完整的代码示例

import os
import torch
import matplotlib.pyplot as plt
from modelscope import snapshot_download
from transformers import AutoTokenizer, AutoModelForCausalLM
from sentence_transformers import SentenceTransformer
# LangChain 核心模块
from langchain_core.embeddings import Embeddings
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
from langchain_core.language_models.llms import LLM
from langchain_core.callbacks.manager import CallbackManagerForLLMRun
from typing import Any, List, Optional
# --------------------------
# 1. 配置路径(复用你的本地模型)
# --------------------------
model_name = "qwen/Qwen1.5-1.8B-Chat"
embedding_model_id = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
cache_dir = "D:\\modelscope\\hub"
faiss_db_path = "D:\\medical_rag_faiss_db"  # 向量库持久化路径
os.makedirs(faiss_db_path, exist_ok=True)
# --------------------------
# 2. 下载/加载本地模型(无重复下载)
# --------------------------
print("="*50)
print("加载本地大模型+Embedding模型...")
# 加载对话大模型
local_model_path = snapshot_download(model_name, cache_dir=cache_dir)
tokenizer = AutoTokenizer.from_pretrained(local_model_path, trust_remote_code=True)
llm_model = AutoModelForCausalLM.from_pretrained(
    local_model_path,
    trust_remote_code=True,
    torch_dtype=torch.float32,  # CPU兼容
    device_map="cpu"
).eval()
# 加载Embedding模型
embedding_local_path = snapshot_download(embedding_model_id, cache_dir=cache_dir, revision="master")
embedding_model = SentenceTransformer(embedding_local_path, device="cpu")
# --------------------------
# 3. 自定义LangChain Embedding适配器
# 作用:将句子转换为向量,用于语义匹配
# --------------------------
class LocalEmbedding(Embeddings):
    def __init__(self, model):
        self.model = model
    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        return self.model.encode(texts, convert_to_numpy=True).tolist()
    def embed_query(self, text: str) -> List[float]:
        return self.model.encode(text, convert_to_numpy=True).tolist()
embedding = LocalEmbedding(embedding_model)
# --------------------------
# 4. 自定义LangChain LLM适配器
# 作用:对接本地Qwen大模型,实现生成能力
# --------------------------
class LocalQwenLLM(LLM):
    tokenizer: Any
    model: Any
    max_new_tokens: int = 512
    temperature: float = 0.1
    @property
    def _llm_type(self) -> str:
        return "qwen_local"
    def _call(
        self,
        prompt: str,
        stop: Optional[List[str]] = None,
        run_manager: Optional[CallbackManagerForLLMRun] = None,
        **kwargs: Any,
    ) -> str:
        inputs = self.tokenizer(prompt, return_tensors="pt")
        with torch.no_grad():
            outputs = self.model.generate(
                **inputs,
                max_new_tokens=self.max_new_tokens,
                temperature=self.temperature,
                do_sample=False,
                pad_token_id=self.tokenizer.eos_token_id
            )
        response = self.tokenizer.decode(outputs[0][len(inputs["input_ids"][0]):], skip_special_tokens=True)
        return response
# 初始化本地大模型包装器
local_llm = LocalQwenLLM(tokenizer=tokenizer, model=llm_model)
# --------------------------
# 5. 构建医疗知识库(可扩展为Excel/文档读取)
# --------------------------
print("构建医疗知识库...")
medical_knowledge = [
    Document(
        page_content="高血压饮食建议:低盐饮食,每日食盐不超过5克;多吃蔬菜、全谷物;减少油炸食品、动物内脏摄入",
        metadata={"category": "饮食", "disease": "高血压"}
    ),
    Document(
        page_content="糖尿病饮食建议:控制碳水化合物摄入量,优先选择低升糖指数食物,定时定量进餐,避免含糖饮料",
        metadata={"category": "饮食", "disease": "糖尿病"}
    ),
    Document(
        page_content="感冒护理建议:保证充足睡眠,多饮温水,症状严重时可服用解热镇痛药,病程一般3-7天",
        metadata={"category": "护理", "disease": "感冒"}
    ),
    Document(
        page_content="冠心病预防:戒烟限酒,规律运动,控制血压血脂,避免情绪剧烈波动,定期体检",
        metadata={"category": "预防", "disease": "冠心病"}
    )
]
# --------------------------
# 6. 构建FAISS向量库(核心检索模块)
# 技术细节:FAISS使用L2距离进行语义相似度计算
# --------------------------
print("构建FAISS向量检索库...")
vector_store = FAISS.from_documents(medical_knowledge, embedding)
# 持久化保存向量库(下次直接加载,无需重新构建)
vector_store.save_local(faiss_db_path, "medical_index")
# --------------------------
# 7. 生成FAISS检索流程图(可视化输出图片)
# --------------------------
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.figure(figsize=(10, 6))
plt.title("医疗知识库RAG检索流程", fontsize=16, pad=20)
# 流程节点
steps = [
    "用户问题",
    "Embedding向量化",
    "FAISS语义检索",
    "召回相关医疗知识",
    "大模型生成答案"
]
# 节点坐标
x = [1, 2, 3, 4, 5]
y = [1, 1, 1, 1, 1]
# 绘制流程
plt.plot(x, y, "o-", linewidth=3, markersize=15, color="#2E86AB")
for i, step in enumerate(steps):
    plt.text(x[i], y[i]+0.1, step, ha="center", fontsize=12, bbox=dict(boxstyle="round,pad=0.3", facecolor="#A2D6F9"))
plt.ylim(0.5, 1.5)
plt.axis("off")
plt.tight_layout()
plt.savefig("medical_rag_process.png", dpi=300, bbox_inches="tight")
print("✅ 检索流程图已保存:medical_rag_process.png")
# --------------------------
# 8. 手动构建RAG问答链(简化版,避免LangChain兼容性问题)
# 检索参数:top_k=2 召回最相关的2条知识
# --------------------------
def rag_query(question: str, k: int = 2, threshold: float = 0.6) -> dict:
    """RAG查询函数"""
    # 1. 检索相关文档并计算相似度
    import numpy as np
    # 获取所有文档的相似度
    query_vector = embedding.embed_query(question)
    scored_docs = []
    for doc in medical_knowledge:
        doc_vector = embedding.embed_query(doc.page_content)
        query_np = np.array(query_vector)
        doc_np = np.array(doc_vector)
        similarity = np.dot(query_np, doc_np) / (np.linalg.norm(query_np) * np.linalg.norm(doc_np))
        # 只保留相似度大于阈值的文档
        if similarity > threshold:
            scored_docs.append((doc, similarity))
    # 按相似度排序,取top_k
    scored_docs.sort(key=lambda x: x[1], reverse=True)
    docs = [doc for doc, score in scored_docs[:k]]
    # 打印检索到的文档(验证RAG是否生效)
    print(f"\n[调试] 检索到 {len(docs)} 条相关文档(阈值: {threshold}):")
    for i, (doc, score) in enumerate(scored_docs[:k]):
        print(f"  文档{i+1} (相似度: {score:.4f}): {doc.page_content}")
        print(f"  元数据: {doc.metadata}")
    # 2. 判断是否有检索结果
    if len(docs) == 0:
        answer = f"抱歉,知识库中没有与您的问题相关的信息(最高相似度低于{threshold})。"
        return {
            "question": question,
            "answer": answer,
            "source_documents": []
        }
    # 3. 构建提示词
    context = "\n\n".join([f"知识{i+1}: {doc.page_content}" for i, doc in enumerate(docs)])
    prompt = f"""你是一名专业的医疗顾问。请**严格基于以下知识库内容**回答用户问题。
【重要要求】
1. 你的答案必须来自下方提供的知识库内容
2. 不要编造知识库以外的信息
3. 如果知识库中没有相关信息,请明确说明"知识库中没有相关信息"
【知识库内容】
{context}
【用户问题】
{question}
【请基于知识库内容回答】"""
    # 4. 调用大模型生成答案
    answer = local_llm._call(prompt)
    return {
        "question": question,
        "answer": answer,
        "source_documents": docs
    }
def show_similarity_scores(question: str):
    """展示问题与所有文档的相似度得分"""
    print(f"\n[向量相似度分析] 问题: {question}")
    print("-" * 50)
    # 计算问题向量
    query_vector = embedding.embed_query(question)
    # 计算与每个文档的相似度
    import numpy as np
    for i, doc in enumerate(medical_knowledge):
        doc_vector = embedding.embed_query(doc.page_content)
        # 余弦相似度
        query_np = np.array(query_vector)
        doc_np = np.array(doc_vector)
        similarity = np.dot(query_np, doc_np) / (np.linalg.norm(query_np) * np.linalg.norm(doc_np))
        # 标记是否超过阈值
        status = "✓" if similarity > 0.6 else "✗"
        print(f"{status} 文档{i+1} ({doc.metadata['disease']}): {similarity:.4f}")
        print(f"  内容: {doc.page_content[:50]}...")
    print()
# --------------------------
# 9. 医疗问答测试(实战演示)
# --------------------------
print("\n" + "="*50)
print("医疗问答测试")
print("="*50)
# 测试问题1 - 高血压(应该能准确检索)
query1 = "高血压患者平时应该怎么吃饭?"
print(f"\n用户问题:{query1}")
result1 = rag_query(query1)
print(f"模型答案:{result1['answer']}")
# 测试问题2 - 感冒(向量检索可能不精确)
print("\n" + "="*50)
query2 = "感冒了需要注意什么?"
print(f"\n用户问题:{query2}")
print("\n[对比测试] 直接查看知识库中的感冒文档:")
for doc in medical_knowledge:
    if "感冒" in doc.page_content:
        print(f"找到:{doc.page_content}")
# 先展示向量相似度分析
show_similarity_scores("感冒了需要注意什么?")
result2 = rag_query(query2)
print(f"模型答案:{result2['answer']}")
# 测试问题3 - 直接询问感冒护理(使用更精确的关键词)
print("\n" + "="*50)
query3 = "感冒护理建议"
print(f"\n用户问题:{query3}")
show_similarity_scores("感冒护理建议")
result3 = rag_query(query3)
print(f"模型答案:{result3['answer']}")
# --------------------------
# 10. 加载已有向量库(生产环境使用)
# --------------------------
# vector_store = FAISS.load_local(faiss_db_path, embedding, allow_dangerous_deserialization=True)
# 然后重新调用rag_query函数
print("\n✅ 医疗知识库RAG系统部署完成!")

image.gif

相关文章
|
5天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
2696 9
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
13天前
|
人工智能 开发工具 iOS开发
Claude Code 新手完全上手指南:安装、国产模型配置与常用命令全解
Claude Code 是一款运行在终端环境中的 AI 编程助手,能够直接在命令行中完成代码生成、项目分析、文件修改、命令执行、Git 管理等开发全流程工作。它最大的特点是**任务驱动、终端原生、轻量高效、多模型兼容**,无需图形界面、不依赖 IDE 插件,能够深度融入开发者日常工作流。
3451 12
|
16天前
|
Shell API 开发工具
Claude Code 快速上手指南(新手友好版)
AI编程工具卷疯啦!Claude Code凭借任务驱动+终端原生的特性,成了开发者的效率搭子。本文从安装、登录、切换国产模型到常用命令,手把手带新手快速上手,全程避坑,30分钟独立用起来。
3529 25
|
9天前
|
人工智能 Linux BI
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
JeecgBoot AI专题研究 一键脚本:Claude Code + JeecgBoot Skills + DeepSeek 全平台接入 一行命令装好 Claude Code + JeecgBoot Skills + DeepSeek 接入,无需翻墙使用 Claude Code,支持 Wind
2666 6
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
|
7天前
|
人工智能 自然语言处理 供应链
|
7天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全+三种模式+记忆体系+实战工作流完整手册
Claude Code 是当前最流行的终端级 AI 编程助手,能够直接在命令行中完成代码生成、项目理解、文件修改、命令执行、错误修复等全流程开发工作。它不依赖图形界面、不占用额外资源,却能深度理解项目结构,自动生成规范代码,大幅提升研发效率。
1227 3
|
28天前
|
人工智能 JSON 供应链
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」
LucianaiB分享零成本畅用JVS Claw教程(学生认证享7个月使用权),并开源GeoMind项目——将JVS改造为科研与产业地理情报可视化AI助手,支持飞书文档解析、地理编码与腾讯地图可视化,助力产业关系图谱构建。
23611 15
畅用7个月无影 JVS Claw |手把手教你把JVS改造成「科研与产业地理情报可视化大师」

热门文章

最新文章