医疗问答系统搭建:RAG与大模型技术的实践指南
简介这是一套基于RAG与大模型技术的医疗问答系统完整资源包包含源代码、文档说明及全部配套资料专为计算机、人工智能、自动化等专业学生与从业者设计适用于毕业设计、课程设计及进阶学习。资源共75个文件集合了Python功能脚本、Jupyter分析笔记、JSON/YAML配置、Markdown说明、CSV数据集以及系统截图和知识图谱图片整体压缩包约84.65MB。包内覆盖从语料处理、命名实体识别、关系抽取、知识图谱构建到低秩适配微调、推理问答和Web界面展示的完整链路还提供环境配置说明、训练参数配置和运行结果分析笔记便于逐步复现。现有378人学习下载代码均经过调试保证可运行项目曾获98分高分适合从小白到进阶的读者参考亦可在其基础上扩展新功能具有很高的学习借鉴价值。1. 医疗问答系统为什么绕不开 RAG它解决的不是“智能”而是“可信”过去做大模型问答最常见的方式是把病历、用药指南、诊断路径直接拼进 Prompt 扔给大模型。结果大家都清楚参数一多就截断回答似是而非最要命的是查无实据——模型一本正经地编出“板蓝根治疗心梗”这种话你还找不到是哪句话带偏的。基于 RAG 与大模型技术的医疗问答系统就是把外部医学资料先切块、向量化、存进检索库再在大模型回答前把相关片段拉出来作为依据。它的核心价值不是让模型更聪明而是让每个答案都能被回溯到原始文档里这在医疗场景里比“聪明”重要得多。这篇笔记适合正在做毕业设计、或者准备做医疗领域知识问答的从业者我会把源码结构、关键脚本、参数选型和踩坑记录一次性讲透让你照着就能把系统落起来。2. 搭建可复现的 RAG 医疗问答系统核心链路与源码骨架很多同学拿到一个“RAG大模型医疗问答”的方向第一时间就去调大模型 API结果做了两周才发现真正决定系统可用性的不是模型而是知识库的处理方式。RAG 全称 Retrieval-Augmented Generation也就是检索增强生成它把整个链路拆成“文档加载 → 文本切分 → 向量化 → 检索→ 生成”五个环节。医疗领域的特殊性在于文档来源杂、专业术语多、答案对来源要求高所以每个环节都和通用聊天机器人不一样。我先给你看一个我在类似项目里常用的源码目录结构这个结构也可以直接作为毕业设计的“系统实现”章节骨架medical_qa_system/ ├── data/ # 原始医学文档PDF、Word、TXT │ ├── raw/ # 未处理的原始资料 │ ├── chunked/ # 切分后的文本片段JSON格式 │ └── test_set.json # 人工标注的测试问答对 ├── src/ │ ├── loader.py # 文档加载器支持 PDF/Word/HTML │ ├── splitter.py # 文本切分器负责 chunk 划分 │ ├── embedder.py # 向量化封装集成 embedding 模型 │ ├── retriever.py # 检索器实现向量召回 重排序 │ ├── generator.py # 大模型生成集成 prompt 模板 │ └── pipeline.py # 把上面串成完整的 RAG 流程 ├── app.py # FastAPI 服务入口 ├── config.yaml # 所有可调参数chunk_size、模型名、阈值 ├── build_vectorstore.py # 一键构建知识库脚本 ├── query_service.py # 本地测试问答脚本 ├── requirements.txt # 依赖清单 └── docs/ # 毕业设计文档/答辩PPT ├── 01_需求分析.md ├── 02_系统设计.md ├── 03_实验对比.md └── 04_使用说明.md这个目录设计背后有三个考量。第一是“数据与代码分离”医疗原始资料动辄几千万字切分出来的 chunk 可能有几万条如果混在代码目录里git 提交会非常痛苦而且向量库一旦构建失败原始数据也不容易被误删。第二是“所有参数集中到 config.yaml”切分大小、检索条数、模型 temperature 这些参数在复盘答辩时一定会被老师反复追问集中管理方便你反复试验并截图对比。第三是“测试集单独存放”没有人工标注的测试集就没法量化系统效果后面我专门讲怎么建这个测试集。2.1 加载与切分医疗文档chunk_size 和 overlap 怎么定医疗文档处理和通用文本最大的差异在于“语义边界不清晰”。一份《药品说明书》里同一段可能既讲适应症又讲不良反应而《临床指南》往往以“推荐意见”为段落单元。所以第一步不能只按固定字符硬切而是要结合文档结构。我会先写一个 loader用 LangChain 库读取 PDF 并保留标题信息# loader.py from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter def load_pdfs(data_dir: str): docs [] pdf_files list(Path(data_dir).glob(*.pdf)) for pdf_path in pdf_files: loader PyPDFLoader(str(pdf_path)) pages loader.load() for i, page in enumerate(pages): page.metadata[source] f{pdf_path.stem}_第{i1}页 docs.extend(pages) return docs这里之所以按页保留 metadata 里的 source是因为后续回答需要定位到“哪份文档哪一页”。很多初学者只保留文件名等到做引用溯源时发现同一页多个答案混在一起很难向答辩老师交代。切分我推荐用RecursiveCharacterTextSplitter它支持按天然分隔符比如标题、换行、句号逐级切分比硬按字数切更符合语义。但医疗文档有其特殊坑药品名称、医学单位、缩写容易正好被切在边界上比如“阿司匹林肠溶片”被切成“阿司匹林”和“肠溶片”检索时“肠溶片”会单独命中答案就可能张冠李戴。我的做法是先采用较大的chunk_size配合较小的chunk_overlap再结合标题段落合并。参数设置逻辑如下# config.yaml chunk_size: 512 chunk_overlap: 64为什么是这些值医疗文本以陈述句为主512 个字符大概能覆盖 812 句临床描述既能保证一个完整知识点被装进一个 chunk又不会因为过长导致向量化之后语义被稀释。chunk_overlap设置为 64是为了让相邻 chunk 之间保留上下文交接区避免“阿司匹林”这样的词在边界处丢失。如果你处理的文档是《临床路径》这类句式结构更强的可以尝试chunk_size: 768, chunk_overlap: 96但要通过检索命中率来回调。2.2 向量化与检索选 bge-large-zh 还是 text-embedding-3-small向量化是整个系统的关键。医疗领域有很多专业词汇比如“呋塞米”“肺栓塞”“甲泼尼龙”如果 embedding 模型不认识检索召回率就会很差。我在选型时通常对比两类第一类是你本地部署的国产开源模型典型代表是BAAI/bge-large-zh-v1.5。它的优势是中文语义理解好医疗语料表现稳定完全离线答辩时不会因为网络问题翻车。但需要一块 6GB 以上显存的显卡CPU 跑也很慢构建大规模知识库要等很久。第二类是云端 API 模型比如 OpenAI 的text-embedding-3-small。它的服务稳定而且维度可以压缩到 256内存占用小但每次调用都有费用而且医疗数据涉及患者隐私或医院内部资料时线上 API 可能会带来合规问题。学院的毕设如果用的是公开教材问题不大如果手上是真实病历务必考虑数据脱敏。我最常用的是 bge-large-zh-v1.5。这里给出封装代码# embedder.py from langchain_community.embeddings import HuggingFaceEmbeddings def build_embeddings(model_name: str BAAI/bge-large-zh-v1.5): return HuggingFaceEmbeddings( model_namemodel_name, encode_kwargs{normalize_embeddings: True}, )注意normalize_embeddings必须设置为 True。因为检索时计算的是向量余弦相似度归一化之后点积就等于余弦相似度可以简化计算并避免某些索引库的精度问题。这一点在答辩时经常被问到。检索器我建议加上“混合检索”。纯向量检索会漏掉那些“关键词存在但语义被掩埋”的文档。我的方案是向量检索 关键词召回再用一个重排序模型做二次排序。这里用BM25做关键词召回它不需要训练用 Elasticsearch 或rank_bm25库都能实现。再使用bge-reranker-base对两路召回的候选做精排。具体调参在第三节代码里体现。2.3 大模型生成限定答案来源依赖 prompt 约束生成阶段不是单纯把问题丢给大模型而是要“先给依据再让模型作答”。我常用的 prompt 模板如下# generator.py prompt_template 你是一个医疗领域知识助手。请仅根据下面给出的资料片段回答问题。 资料片段 {context} 问题{question} 要求 1. 如果资料中没有提到答案请直接回答“资料中没有相关信息”。 2. 回答时要引用资料片段编号格式如[1][2]。 3. 不得自行发挥或使用资料之外的医学知识。 这里的context是检索器返回的 top-k 个 chunk你需要在代码里给每个 chunk 编号并拼接进去。让模型引用编号是为了后续做答案溯源。很多人嫌麻烦会省略编号等到论文里没法展示“答案支持性审计”时再补就晚了。温度参数医疗问答建议设成 0.1 到 0.3绝不要用默认的 0.7。医疗场景容不得“创造性回答”温度低可以压制随机性。同时设置max_tokens或者max_new_tokens来限制回答长度防止模型在长文本生成中途跑偏。3. 跑通最小闭环从原始 PDF 到问答接口的完整命令这一章我会带你亲手搭建一套最小可运行系统。我们使用 LangChain 作为 RAG 框架、Chroma 作为向量库、FastAPI 作为服务层。理论上你可以替换成其他组件但这一节要确保你能在原封不动的情况下跑通。3.1 环境准备与依赖安装建议使用 Python 3.10 和虚拟环境避免系统 Python 里包冲突。创建环境并安装核心依赖python -m venv venv source venv/bin/activate # Windows 下用 venv\Scripts\activate pip install langchain langchain-community chromadb rank_bm25 pip install fastapi uvicorn pypdf这里chromadb是向量数据库pypdf用来解析 PDFrank_bm25实现关键词检索。如果你要本地跑 bge-large-zh 向量模型额外安装sentence-transformers和torchpip install sentence-transformers torch --index-url https://download.pytorch.org/whl/cpu注意 CPU 版 torch 只能跑速度偏慢。构建小规模知识库几千个 chunk问题不大如果要上十万级数据建议去申请带 GPU 的机器或者直接用云端 API。3.2 构建知识库脚本 build_vectorstore.py这是整个系统最耗时的部分也是出错最多的部分。我把完整脚本贴出来然后逐段说明参数改动的影响。# build_vectorstore.py import yaml from pathlib import Path from src.loader import load_pdfs from langchain.text_splitter import RecursiveCharacterTextSplitter from src.embedder import build_embeddings from langchain_community.vectorstores import Chroma # 读取配置 config yaml.safe_load(open(config.yaml)) # 1. 加载原始 PDF docs load_pdfs(data/raw) # 2. 切分文档 splitter RecursiveCharacterTextSplitter( chunk_sizeconfig[chunk_size], chunk_overlapconfig[chunk_overlap], separators[\n\n, \n, 。, , , ], keep_separatorend, ) chunks splitter.split_documents(docs) # 3. 为每个 chunk 添加全局编号和来源信息 for idx, chunk in enumerate(chunks): chunk.metadata[chunk_id] idx chunk.metadata[source] chunk.metadata.get(source, unknown) # 4. 向量化并存入 Chroma embeddings build_embeddings() vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directorydb/medical_db, ) print(f成功构建知识库共 {len(chunks)} 个文本块)这里的separators参数值得解释。默认的RecursiveCharacterTextSplitter分隔符顺序是先长后短我把中文句号。和分号加在末尾这意味着代码会优先按段落切如果段落太长再按句号切尽可能保证一个 chunk 内是完整句子。keep_separatorend会把分隔符保留在前一个 chunk 的末尾避免“阿司匹林。”被切成“阿司匹林”和“。”导致语义缺失。另一个容易踩坑的是persist_directory路径。Chroma 默认会想用PersistentClient写入磁盘如果你在 Windows 上遇到路径过长报错可以把目录放到项目根目录下的db目录。建议每次重新构建知识库之前先删除旧的db目录否则会出现“旧 chunk 残留 新 chunk 插入”导致重复检索。3.3 后端问答服务 query_service.py构建好知识库后我们就写一个命令行问答脚本方便本地验证。# query_service.py import yaml from langchain_community.vectorstores import Chroma from src.embedder import build_embeddings from langchain_community.llms import HuggingFacePipeline from langchain.prompts import PromptTemplate from langchain.chains import RetrievalQA # 加载配置和已有向量库 config yaml.safe_load(open(config.yaml)) embeddings build_embeddings() vectorstore Chroma( persist_directorydb/medical_db, embedding_functionembeddings, ) # 初始化大模型此处以本地模型为例也可以用 OpenAI API llm HuggingFacePipeline.from_pretrained( Qwen/Qwen2-7B-Instruct, max_new_tokens512, temperature0.1, device_mapauto, ) # 构建检索器 retriever vectorstore.as_retriever( search_typesimilarity_score_threshold, search_kwargs{score_threshold: 0.5, k: 4}, ) # 拼接 prompt 模板 prompt PromptTemplate.from_template( 请根据以下资料片段回答问题注意引用片段编号[1][2]。 资料片段 {context} 问题{question} 回答 ) qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, retrieverretriever, return_source_documentsTrue, chain_type_kwargs{prompt: prompt}, )这里我把score_threshold设置为 0.5k设置为 4。score_threshold表示相似度阈值低于 0.5 的 chunk 会被丢弃避免检索到一堆不相关的内容但这不能一刀切。对于bge-large-zh-v1.5这种模型语义相似度经常落在 0.40.7 之间如果你发现答案总是“资料中没有相关信息”很可能是阈值设高了要调低到 0.4反之如果答案满天飞但引用乱七八糟则调高到 0.6。运行问答# query_service.py 主流程 if __name__ __main__: while True: question input(你的问题) if question.strip() : break result qa_chain({query: question}) print(\n回答, result[result]) print(\n参考来源) for doc in result[source_documents]: print(doc.metadata[source], ——, doc.page_content[:30])这是一个可持续运行的最小闭环。你可以在终端看到模型回答了哪个问题依据来自哪些文档片段。如果引用的来源明显不对就根据来源定位到原始文档去调整切分方式或检索阈值。3.4 启动与演示如果你要做一个可演示的 Web 页面用 FastAPI 包一层接口即可。最简单的是写一个/answer接口from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class Query(BaseModel): question: str app.post(/answer) def answer(query: Query): result qa_chain({query: query.question}) return { answer: result[result], sources: [ {source: doc.metadata[source], snippet: doc.page_content[:50]} for doc in result[source_documents] ] }用uvicorn app:app --host 0.0.0.0 --port 8000启动后你就能用 Postman 或请求工具直接调用。在答辩演示时我个人建议浏览器打开 Swagger 文档FastAPI 自带的/docs页面在那里输入问题时导师能看到系统返回的结构化字段比黑乎乎的命令行有说服力得多。4. 把“高分毕设”做扎实文档体系与效果验证源码能跑只是第一步毕设能否拿高分关键在于文档和实验的说服力。很多同学过度关注代码却忽略了评审最看重的“完整闭环”和“量化指标”这部分我专门展开。4.1 论文文档要写什么从系统设计到实验对比毕设文档不是软件说明书它需要讲清楚“为什么用 RAG”和“RAG 比传统微调好在哪里”。我建议按这样的章节组织文档需求分析明确系统服务对象患者自诊?医生辅助?收集 10 份以上医疗资料作为知识库列举 20 个典型问题作为验收标准。系统设计画架构图离线构建流程与在线问答流程标注每层选用的组件和技术指标。关键技术实现贴 loader、splitter、retriever、generator 的核心代码配合参数表说明为什么选择chunk_size512而不是 256 或 1024。实验与评价这是最容易拉开差距的地方。要跑三组对比实验纯大模型不接 RAG在测试集上的表现基础 RAG 在测试集上的表现加入重排序的 RAG 在测试集上的表现每组实验都要给出“准确率、召回率、答案完整性”三个维度你可以用人工评判也可以用 GPT-4 做自动评价但至少要用表展示 3 组结果。4.2 评测指标与测试集评测是 RAG 项目里的黑匣子很多人不知道自己的系统到底改进在哪。医疗问答系统评测通常看两个层面一是检索层面二是生成层面。检索层面看“检索命中率”和“召回率”生成层面人工评价“答案是否与资料一致、是否完整覆盖问题”。我的建议是准备 100 条带标准答案的问答对每条都要包含“问题、标准答案、应引用的文档来源”。然后用 recallk 来评估检索质量# evaluate_retrieval.py def recall_at_k(retrieved_chunk_ids, gold_chunk_ids, k): hit set(retrieved_chunk_ids[:k]) set(gold_chunk_ids) return len(hit) / len(gold_chunk_ids)这个脚本不需要集成到主服务里单独跑就行。比如设置 k4统计 100 条测试题的平均 recall4如果在 0.7 以下说明检索还需要调。我把测试集放在data/test_set.json格式很简单[ { question: 阿司匹林禁用于哪些患者, answer: 对阿司匹林过敏者、活动性消化道溃疡患者、出血体质者禁用。, gold_source: 药理_第12章_第3页 } ]这个测试集是我用来倒逼系统迭代的。你在写文档时直接展示这种结构导师一眼就能看出你有“工程验证”的意识而不是把代码凑出来就交差。另一件值得做的事是“错误案例分析”。挑出 5 个系统回答错误的例子分别分析是检索错了、上下文不够、还是模型没有遵循 prompt。这个部分放在论文“不足与改进”里反而是加分项。5. 医疗问答系统常见问题避坑这 5 个坑我当年都踩过RAG 系统的开发看起来链路清晰但实际调试时会遇到各种反直觉的问题。我这里按“现象 → 原因 → 解决”的格式记录 5 个高频踩坑点都是医疗问答场景里特有的通用项目里可能遇不到。5.1 现象检索出来的内容不相关答案驴唇不对马嘴原因分析我最初用默认的Chroma.as_retriever()它采用similarity检索返回向量距离最近的 top-k。但医疗文档中存在大量同义词和上下级概念比如“高血压”和“血压升高”语义相似但向量距离可能很远更常见的问题是chunk_size过大导致一个 chunk 里混合了多个主题检索时距离被平均命中不了真正的答案。解决方案切换为similarity_score_threshold搜索并配合重排序模型。核心调参技巧retriever vectorstore.as_retriever( search_typesimilarity_score_threshold, search_kwargs{score_threshold: 0.55, k: 6}, )同时把top_k从 4 提升到 6召回更多的候选片段交给重排序模型精排。重排序模型可以用bge-reranker-basefrom langchain_community.cross_encoders import HuggingFaceCrossEncoder reranker HuggingFaceCrossEncoder(model_nameBAAI/bge-reranker-base)在获得向量检索结果后再让 reranker 对候选按“问题和片段的相关程度”打分取前 3 个作为最终上下文。这一层多加的耗时大约 100ms但准确率提升非常明显。5.2 现象答案引用了正确的文档但来源标注张冠李戴原因分析这是医疗问答中很严重的信任问题。我的一个教训是在最初的loader里没有正确保留页码信息多个 PDF 的 metadata 都是文件名检索结果打印出来全是一个来源答辩时被问“回答里的高血压内容到底来自哪一份文档”我当场无法区分。解决方案在构建知识库时把“文档名 章节名 页码”拼成完整 source 写入 metadata并且在构建之前打印抽样 chunk 验证一下。修改后的 loaderfrom langchain_community.document_loaders import PyPDFLoader, TextLoader def load_pdfs(data_dir): docs [] for pdf_path in Path(data_dir).glob(*.pdf): loader PyPDFLoader(str(pdf_path)) pages loader.load() for page, doc in enumerate(pages, start1): doc.metadata[source] f{pdf_path.stem}_第{page}页 docs.append(doc) return docs这个看似简单的改动直接决定你的系统能不能做“引用溯源”。没有精确来源的 RAG 在医疗场景里基本等于废物。5.3 现象向量库占用内存过大构建时直接内存溢出原因分析Chroma 在persist_directory模式下会把所有向量加载到内存如果知识库有几万个 chunk每一条向量 768 维bge-large 是 1024 维内存很快就告急。医疗文本动辄几百万字切分出来十万级 chunk 非常常见。解决方案如果是面向毕设的中小型数据控制在 2 万 chunk 以内不会有大问题。如果数据量实在大第一考虑降维使用text-embedding-3-small的 256 维第二改用FAISS向量库它支持索引文件和内存映射资源占用比 Chroma 更可控第三是分批写入每处理 1000 个 chunk 持久化一次避免一次性构建的峰值内存。我在处理《新编药物学》第 17 版时用 FAISS 把构建时内存峰值降了一半。如果你用 Chroma不要重复运行from_documents往同一个目录追加否则历史向量不会被清理每次追加后目录越来越大。5.4 现象大模型回答与检索内容相矛盾原因分析大模型在生成时并不可靠即使你给了它明确的资料片段它可能还是会“发挥”出资料之外的知识。这在医疗领域是致命的。现象是系统明明没检索到“禁用阿司匹林”的信息模型却回答“阿司匹林可以用于儿童退热”这是常识性错误但模型不会自知。解决方案除了把温度调低到 0.1更有效的是在 prompt 里强制加入“资料中没有相关内容时必须回答未知”。我用的强约束表达是如果资料片段中没有明确提及该问题的答案请只回答“根据现有资料无法回答”不要补充任何额外知识。同时在代码层做一个“矛盾检测”检查模型回答中的关键医学实体药物名、症状、剂量是否出现在检索到的上下文中。如果没有出现就丢弃那部分回答或直接返回“无法回答”。这个逻辑我写在pipeline.py里算是保险丝。5.5 现象API 调用超时导致前端频闪失败原因分析医疗问答系统的用户场景往往是在浏览器里等待答案而大模型 API 的响应时间普遍在 310 秒如果前端没有设置合适的超时就会频繁报错。解决方案在 FastAPI 层把问答接口设为异步并把前端超时拉到 30 秒。同时给接口加一个简单的缓存相同问题在 5 分钟内直接返回结果。这里单独抽一个小函数from functools import lru_cache lru_cache(maxsize100) def get_answer_cached(question: str): # 调用 qa_chain return qa_chain({query: question})但要注意lru_cache缓存的是同一个进程内的结果如果部署多 worker需要改用 Redis。对于毕设演示单进程缓存完全够用。另外要把超时时间从默认的 60 秒适当调低否则用户反复点击会导致系统连锁阻塞。6. 进阶把单轮问答改成可追溯的 Agentic RAG如果毕业设计想冲刺高分单轮 RAG 已经不够看了。现在的热点是 Agentic RAG也就是让大模型具备“自主决定检索什么、如何重试、如何整合”的能力。在医疗场景里这一步不是炫技而是实打实地解决单轮检索容易漏掉关键证据的问题。6.1 引入查询改写与意图路由先说查询改写。用户问“高血压患者能用布洛芬吗”这个 query 直接检索到的文本可能同时涉及“高血压”和“布洛芬”两个实体但文档中这两个词的关联性并不强。Agentic 的常见做法是让大模型自动拆解子问题比如先检索“布洛芬禁忌症”再检索“高血压用药注意事项”最后综合答案。代码层可以用 LangChain 的create_react_agent或AgentExecutor也可以手动实现一个简单的两步路由def rewrite_query(question: str) - list[str]: prompt f针对医疗问题拆成 1-3 个子检索词用逗号分隔{question} resp llm.invoke(prompt) return [q.strip() for q in resp.split(,) if q.strip()]然后对每个子检索词分别从向量库检索合并结果后去重再交给生成模型。这种小改造让系统在“多条件禁忌”问题上明显更有条理。6.2 用“引用溯源”让答案可验证我在生成 prompt 里要求模型按编号引用资料片段最终答案呈现在界面上时可以把这些编号映射成可点击的来源卡片。实现并不复杂——返回source_documents时附带每条的chunk_id前端用 Tooltip 展示来源文档名和原文片段。毕设答辩时导师点开引用卡片能看到原文档内容信任感完全不一样。这一步在源码里体现为retriever_result retriever.invoke(question) sorted_chunks reranker.rerank(question, retriever_result) context \n\n.join(f[{i1}] {chunk.page_content} for i, chunk in enumerate(sorted_chunks))千万记得把[1]的编号与实际传入的 chunk 顺序保持一致这比 prompt 本身更影响“引用正确性”。我有一次忘了重排序后重新编号结果答案引用 [2] 但实际对应的是另一段内容这种行为败好感度极重。6.3 我的收尾习惯我对 RAG 项目唯一的习惯是每次改完参数立刻重跑测试集并记录结果不要凭感觉说“好多了”。医疗问答系统里“感觉”是最不靠谱的没有量化指标你连自己系统有没有退化都不知道。毕设做到最后最值钱的不是那几行代码而是一套能说服人的数据表和完整的排错记录。希望这篇文章能帮你在医疗 RAG 这条路上少走几个跟头祝你的知识库目标命中率和答案可信度都能调到最优。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →