生产级医疗AI Agent:Multi-Agent RAG架构解析

大家好,我是一名深耕AI Agent领域的开发者。最近参与了一个医疗健康AI Agent的完整项目开发,从架构设计到生产部署踩过了无数坑。今天把整个项目的技术细节和盘托出,希望能帮到正在做Agent开发的朋友们。

如果你觉得这篇文章对你有帮助,欢迎点赞、关注、转发三连支持~后续我会持续输出更多Agent开发实战干货。


项目背景与挑战

医疗领域的AI问答系统面临着专业性、准确性、安全性三大核心挑战:

  • 专业性要求极高:医学知识容不得半点错误,一个错误的回答可能直接影响用户健康
  • 知识体系庞杂:中西医结合,既有现代医学文献,又有中医古籍,数据格式多样
  • 用户体验敏感:用户往往带着焦虑提问,响应速度和对话体验至关重要
  • 合规与追溯:医疗内容必须可追溯、可审核、可迭代优化

我们的目标是打造一个生产级医疗多模态AI Agent系统 ,基于 Multi-Agent RAG 架构,提供中西医问答、语音对话、数据飞轮等核心能力。


整体架构概览

整个系统采用七层分层架构,从接入层到基础设施层各司其职:

复制代码
接入层 (API Layer)
  POST /chat_stream | POST / | /voice/* | /feedback | /health

中间件层 (Middleware)
  AuditMiddleware | AuthMiddleware | CORS | ExtensionRegistry

缓存层 (Cache Layer)
  Redis 三层防护: 防穿透 + 防击穿 + 防雪崩

Agent编排层 (Orchestration)
  AgentOrchestrator -> RouterAgent -> Skills -> MedicalAgent

技能层 (Skills Layer)
  knowledge_search(Milvus) | web_search_tool | extract_doc

记忆层 (Memory Layer)
  ShortTermMemory(LRU) | LongTermMemory(Redis) | Semantic

基础设施层 (Infrastructure)
  Milvus | Redis | MySQL | OSS | ASR/TTS

核心技术栈

层级 技术选型
服务框架 FastAPI + Uvicorn(异步高性能)
大模型 DeepSeek-V4、GLM-5.2、Doubao-2.1
向量数据库 Milvus 2.x(HNSW + BM25 混合检索)
缓存 Redis(分布式锁 + 三层防护)
关系数据库 MySQL(用户、会话、计费数据)
语音 火山引擎 ASR/TTS、智谱 GLM-4-Voice、阶跃星辰 StepAudio 2.5
对象存储 阿里云 OSS

Multi-Agent 架构深度解析

这是整个系统的核心,也是最有技术含量的部分。我们没有采用简单的单向RAG流水线,而是构建了四级Multi-Agent流水线

复制代码
RouterAgent -> Skills -> MedicalAgent -> ReflectionAgent

1. BaseAgent 基类:ReAct + Reflection + Self-Correction

所有Agent都继承自 BaseAgent,内置三重机制:

  • ReAct 循环:推理(Reasoning) -> 行动(Action) -> 观察(Observation),最多5轮迭代
  • Reflection 反思:对输出进行四维度质量评估(0.0~1.0分)
  • Self-Correction 自修正:评分 < 0.7 时自动触发修正

核心数据结构:

python 复制代码
@dataclass
class AgentResult:
    content: str                    # 最终输出文本
    tools_used: List[ToolResult]    # 工具调用记录
    reflect_score: float = 1.0      # 反思评分
    corrected: bool = False         # 是否经过修正
    total_llm_calls: int = 0        # 累计LLM调用次数
    total_duration_ms: float = 0.0  # 总耗时

执行流程:

复制代码
run() -> Phase 1: _react_loop()
      -> Phase 2: _reflect() [可选]
      -> Phase 3: _correct() [仅当 score < threshold]

设计亮点:流式模式下为了优化TTFT(首token时间),会跳过反思和修正步骤,反思在流式结束后异步执行,结果写入记忆供下次参考。

2. RouterAgent:智能路由分诊

RouterAgent是系统的"门卫",负责判断用户意图:

  • 医疗查询 -> 进入MedicalAgent处理
  • 闲聊/问候 -> 直接返回寒暄话术
  • 非医疗问题 -> 返回免责声明
  • 垃圾请求 -> 返回默认兜底回复
  • 需要联网搜索 -> 先调用web_search_tool再进入医疗流程

这一层虽然简单,但极其重要------它能有效拦截无关请求,节省Token成本,同时确保医疗回答的专业性。

3. Skills 技能层:工具调用引擎

Skills层封装了三类核心工具:

工具名称 功能 调用时机
knowledge_search Milvus向量库检索 所有医疗问题默认调用
web_search_tool 联网搜索补充 需要最新医学资讯时
extract_doc_urls 提取检索结果中的文档/PDF链接 返回参考资料时

RouterAgent根据意图决定调用哪些工具,工具结果以结构化方式注入MedicalAgent的上下文。

4. MedicalAgent:专业医学问答

MedicalAgent是系统的"专家",基于检索到的医学知识生成专业回答。它的核心设计原则:

  • 严格基于检索结果:不凭空编造医学建议
  • 给出参考文献:回答末尾附带来源文档链接
  • 图文并茂:支持从检索结果中提取图片URL
  • 中西医分流:现代医学和中医古籍分库检索

5. ReflectionAgent:质量把关

ReflectionAgent是系统的"质检员",从四个维度评估回答质量:

  1. 医学准确性:内容是否符合医学规范
  2. 相关性:是否真正回答了用户的问题
  3. 安全性:是否包含危险建议(如自行用药指导)
  4. 完整性:回答是否全面、有条理

评分低于0.7分自动触发Self-Correction,基于反思反馈重新生成回答。


RAG检索增强:Milvus混合检索实战

RAG的质量直接决定了Agent的回答水平。我们采用了Milvus + 混合检索 + 父子文档的方案。

1. 混合检索:HNSW + BM25 + RRF

单一路召回永远无法兼顾语义匹配和关键词匹配,我们采用三路召回融合:

复制代码
用户Query -> HNSW 稠密向量检索(语义匹配)
          -> BM25 稀疏向量检索(关键词匹配) -> RRF融合 -> Top-K结果
          -> 混合检索参数调优

性能配置参数:

python 复制代码
MILVUS_PERF_CONFIG = {
    "search_params": {"nprobe": 16, "ef": 64},
    "top_k": 30,
    "rerank_method": "rrf",
    "rrf_k": 60
}

2. 父子文档两级切分

这是一个非常实用的技巧------用细粒度的child块做检索,用粗粒度的parent块做上下文:

复制代码
原始文档 -> parent chunk (2000字, overlap=200)
         -> child chunk  (400字,  overlap=50)  <- 用于检索
         -> child chunk  (400字,  overlap=50)  <- 用于检索

为什么这么做?

  • Child块:粒度细,语义单一,检索更精准
  • Parent块:上下文完整,给LLM的信息更充分
  • 检索用child,返回用parent:精准与完备兼得

3. 多源数据入库

系统支持三类数据源入库:

数据类型 来源 处理方式
JSONL问答对 结构化医学QA 文生图配图 -> OSS转存 -> Milvus入库
PDF文献 医学论文/指南 PDF转TXT -> 父子切分 -> 上传OSS -> 入库
TXT古籍 中医经典 元数据解析(书名/作者/朝代)-> 父子切分 -> 入库
文生图配图方案

对于JSONL问答数据,我们用豆包的文生图模型为每条数据生成配套医学图片:

python 复制代码
def generate_image_from_text(ark_client, text):
    template = f"""请根据以下文本描述生成一张医学展示图片:
    {text}
    图片内容应与描述高度相关,风格属于科学性质,
    用于医疗领域的展示,细节丰富,内容严谨。"""

    response = ark_client.images.generate(
        model="doubao-seedream-5-0-260128",
        prompt=template,
        size="2K",
        response_format="url",
        output_format="png",
        watermark=False,
    )
    return response.data[0].url

生成的图片先从火山云下载到本地,再转存到阿里云OSS,确保数据长期可控。


Redis三层缓存防护:高并发的底气

医疗Agent上线后,缓存就是你的生命线。我们在Redis层面构建了三层防护体系 ,应对各种缓存异常场景。

1. 防缓存穿透

问题:大量查询不存在的key,请求直接打到LLM,导致成本飙升甚至服务雪崩。

方案 :对于查无结果的问题,写入一个特殊的占位符 <EMPTY>,设置较短的TTL(如60秒)。下次同样的问题再来,直接从缓存命中占位符返回None,不会穿透到LLM。

python 复制代码
async def get_answer_async(self, question):
    key = self._generate_key(question)
    val = await asyncio.to_thread(self.client.get, key)
    if val:
        if val == "<EMPTY>":  # 防穿透占位符
            return None
        self.metrics.hit_count += 1
        return val
    else:
        self.metrics.miss_count += 1
        return None

2. 防缓存击穿

问题:某个热点key过期的瞬间,大量并发请求同时涌入,全部打到LLM。

方案:分布式锁 + 双重检查。当缓存未命中时,先尝试获取分布式锁,只有拿到锁的请求才去回源LLM,其他请求等待并重试缓存。

python 复制代码
def acquire_lock(self, key, timeout=10):
    lock_id = str(uuid.uuid4())
    ok = self.client.set(key, lock_id, nx=True, ex=timeout)
    return (lock_id, True) if ok else (None, False)

Lua脚本原子释放锁:用Lua脚本保证"判断锁归属 + 删除锁"的原子性,避免误删别人的锁。

lua 复制代码
if redis.call("get", KEYS[1]) == ARGV[1] then
    return redis.call("del", KEYS[1])
else
    return 0
end

3. 防缓存雪崩

问题:大量key在同一时刻过期,导致瞬时请求全部回源LLM。

方案:TTL添加 ±10% 随机抖动。比如基础TTL是3600秒,实际每个key的TTL在 3240~3960 秒之间随机分布,避免集中过期。

python 复制代码
def _get_ttl(self, base_ttl=3600):
    jitter = base_ttl * 0.1
    return base_ttl + random.uniform(-jitter, jitter)

4. 可观测性:RedisMetrics

缓存不是黑盒,我们内置了完整的监控指标:

python 复制代码
@dataclass
class RedisMetrics:
    hit_count: int = 0       # 命中次数
    miss_count: int = 0      # 未命中次数
    write_count: int = 0     # 写入次数
    error_count: int = 0     # 错误次数
    lock_acquired: int = 0   # 成功获取锁次数
    lock_failed: int = 0     # 获取锁失败次数

    @property
    def hit_rate(self) -> float:
        total = self.hit_count + self.miss_count
        return round(self.hit_count / total, 4) if total > 0 else 0.0

通过命中率、锁竞争频率这些指标,你可以持续优化缓存策略。


语音全链路:ASR -> RAG -> TTS 端到端流式

只做文本问答的Agent已经不够了,语音交互是用户体验的质变。

全链路架构

复制代码
用户语音 -> ASR(语音转文字) -> RAG检索 -> LLM生成 -> TTS(文字转语音) -> 用户收听

支持的语音服务:

  • ASR:火山引擎、阶跃星辰 StepASR 1.1
  • TTS:火山引擎、智谱 GLM-4-Voice、阶跃星辰 StepAudio 2.5

流式体验优化

语音场景下,延迟感知比文本更强。我们做了这些优化:

  1. 流式ASR:边说边转文字,不用等说完
  2. 流式LLM:文字逐token生成,不用等完整回答
  3. 流式TTS:拿到首句就开始合成语音,逐句播放
  4. 禁用thinking模式:流式场景下关闭模型内部思考,降低TTFT
python 复制代码
# 流式请求中禁用thinking,减少首token延迟
response = await self.llm_client.responses.create(
    model=self.model,
    input=input_messages,
    stream=True,
    extra_body={"thinking": {"type": "disabled"}},
)

数据飞轮:让AI越用越聪明

一个没有数据飞轮的AI系统,上线即巅峰。我们构建了完整的用户反馈 -> 专家审核 -> 持续优化闭环。

反馈体系设计

反馈类型 触发方式 处理流程
点赞 用户觉得回答好 标记为优质样本,纳入知识库候选
点踩 用户觉得回答差 进入专家审核队列
专家审核 后台人工介入 修正错误回答 -> 重新入库 -> 模型微调

核心接口

  • POST /feedback:用户提交反馈(点赞/点踩 + 文字补充)
  • GET /expert/pending:专家获取待审核列表
  • POST /expert/review:专家提交审核结果和修正内容
  • POST /expert/approve:审核通过,数据进入知识库

数据飞轮运转逻辑

复制代码
用户提问 -> Agent回答 -> 用户反馈
    | (差评)
    v
专家审核队列 -> 医学专家修正 -> 生成优质QA对
    |
    v
重新入库Milvus -> 下次相同问题命中正确答案
    |
    v
定期用优质样本微调模型 -> 模型能力持续提升

这才是AI产品真正的护城河------数据飞轮转起来之后,越用越好,越好用越多人用


Token计费:从玩具到产品的必经之路

做AI项目不能只谈情怀,商业化是绕不开的话题。我们实现了按用户/请求级别的Token消耗追踪

计费维度

  • 输入Token:用户问题 + 上下文 + 检索结果
  • 输出Token:LLM生成的回答内容
  • 工具调用Token:ReAct过程中工具描述和结果的消耗
  • 反思/修正Token:Reflection和Self-Correction的额外消耗

计费实现

python 复制代码
from token_billing import record_token_usage, estimate_tokens_from_chars

# 每次请求结束后记录
await record_token_usage(
    user_id=user_id,
    session_id=session_id,
    input_tokens=input_tokens,
    output_tokens=output_tokens,
    model=model_name,
    request_type="chat"  # chat / voice / stream
)

定时账单任务

启动时创建一个24小时的定时任务,每天生成日报表:

python 复制代码
# Token计费:启动每24小时定时账单任务
asyncio.create_task(start_billing_scheduler())

数据存在MySQL中,支持按用户、按模型、按时间维度统计。


记忆系统:让对话有上下文

一个不会记住你之前说什么的Agent,和搜索引擎有什么区别?我们实现了三层记忆体系:

记忆类型 存储介质 作用 生命周期
短期记忆 LRU内存缓存 当前会话上下文 会话期间
长期记忆 Redis 用户画像、历史偏好 30天
语义记忆 Milvus 重要对话的向量化存储 永久

MemoryManager 统一管理三层记忆,Agent执行时自动加载相关记忆到上下文。


生产级部署要点

1. 服务生命周期管理

用FastAPI的lifespan管理资源的初始化与优雅关闭:

python 复制代码
@asynccontextmanager
async def lifespan(app: FastAPI):
    # 启动:初始化Milvus、验证Redis、启动计费调度
    logger.info("服务启动中,正在初始化Milvus...")
    await milvus_manager.initialize()
    if redis_manager.is_healthy():
        logger.info("Redis连接正常")
    asyncio.create_task(start_billing_scheduler())

    yield  # 服务运行中...

    # 关闭:优雅释放资源
    logger.info("服务关闭中,正在释放Milvus连接...")
    await milvus_manager.close()

2. 中间件体系

中间件 作用
AuditMiddleware 审计日志:记录所有请求的用户、耗时、状态码
AuthMiddleware 认证鉴权:验证用户Token
CORS 跨域支持
ExtensionRegistry 扩展点注册:便于插件化开发

注册顺序很重要------FastAPI中间件是后注册先执行

3. 健康检查与可观测性

  • /health:服务健康状态探针
  • /metrics:运行指标(缓存命中率、QPS、平均延迟等)
  • app.log:结构化日志,包含所有业务事件

面试高频问题精选

整理了10个面试中最常被问到的问题,帮你快速复习:

Q1: 你的Agent项目如何做意图识别?

通过RouterAgent对用户query做多分类,区分医疗/闲聊/垃圾/需要联网等意图,基于LLM的少样本学习能力,不需要额外训练分类模型。

Q2: Milvus中有几路召回?如何融合?

三路召回:HNSW稠密向量(语义)+ BM25稀疏向量(关键词)+ 混合检索,用RRF算法融合结果。

Q3: 流式接口的TTFT(首token时间)M95是多少?怎么优化的?

优化后TTFT M95约200-300ms。优化手段:Redis缓存命中(10ms)、流式SSE、禁用thinking模式、向量库预热。

Q4: 只有文本接口吗?移动端语音呢?

完整支持语音全链路:ASR语音转文字 -> RAG检索 -> LLM生成 -> TTS文字转语音,端到端流式输出。

Q5: 支持多模态吗?如何做的?

支持。文本是核心,图片来源于两个途径:(1) 文生图模型为知识库配图 (2) 检索结果中提取PDF/文档预览图。回答中包含图片URL供前端展示。

Q6: 具备ReAct能力吗?还是单向WorkFlow?

完整的ReAct架构。RouterAgent通过工具调用决定调用哪些Skills(知识库检索/联网搜索),MedicalAgent基于工具结果生成答案,最多5轮迭代。

Q7: 有记忆能力吗?能识别之前的对话吗?

三层记忆体系:短期记忆(当前会话LRU)+ 长期记忆(Redis用户画像)+ 语义记忆(Milvus向量存储),Agent执行时自动加载。

Q8: 检索失败 + LLM服务同时挂了,怎么兜底?

多级降级策略:(1) 缓存命中直接返回 (2) Milvus失败则跳过检索纯LLM回答 (3) LLM主模型失败自动切到备用模型 (4) 全部失败返回友善的兜底话术,同时触发告警。

Q9: 用户觉得回答不对,有反馈和人工介入机制吗?

有完整数据飞轮:用户点踩 -> 进入专家审核队列 -> 医学专家修正 -> 重新入库 -> 下次问答质量提升。

Q10: 有付费机制吗?计费标准是什么?

有Token计费系统,按用户/请求级别追踪输入输出Token消耗,支持按模型阶梯定价,每日生成账单报表。


写在最后

这篇文章涵盖了一个生产级医疗AI Agent从架构设计到落地部署的完整链路。回顾一下整个系统的核心设计哲学:

  1. 分层解耦:七层架构各司其职,改动一层不影响其他层
  2. 安全优先:医疗领域容错率低,Reflection + 数据飞轮双重保障
  3. 性能为王:三层缓存 + 流式输出 + 向量库预热,TTFT低至200ms
  4. 持续进化:数据飞轮让系统越用越聪明,形成正向循环
  5. 可观测性:日志、指标、审计贯穿全链路,问题一目了然

如果你对AI Agent开发感兴趣,欢迎关注我,后续我会继续分享:

  • Agent的流式输出优化实战
  • Milvus向量库性能调优指南
  • 多模态Agent的前端交互设计
  • 更多真实项目的踩坑记录

觉得有帮助的话,别忘了点赞 + 在看 + 转发,让更多人看到~有任何问题欢迎在评论区交流!


关于作者:深耕AI Agent领域,专注于RAG、Multi-Agent架构与生产级部署。本文基于实战项目总结,代码和架构均经过生产环境验证。如需交流,欢迎关注后续内容。

相关推荐
Wang's Blog1 小时前
Java 项目实战: 外卖平台-软件开发流程与项目整体介绍
java·服务器·redis
Wang's Blog9 小时前
Java 接入Redis: 服务启动停止与后台运行配置
java·服务器·redis
Hrain-AI10 小时前
AI 爬虫三档授权工程落地:搜索放行、训练拦截、Agent 分层(附脚本)
人工智能·elasticsearch·milvus
程序员JerrySUN13 小时前
Jetson Edge AI 实战01:Nano、Xavier、Orin 怎么选?Jetson 硬件选型详解【视频讲解】
java·数据库·redis·安全·mybatis
行百里er14 小时前
Redis 版本演进、新特性与协议那些事儿
redis·后端
Asurplus14 小时前
【SpringBoot4】3、从SpringBoot4升级Sa-Token1.46.0报错
redis·sa-token·json·jackson·springboot4
zhoupenghui16819 小时前
Redis 集群的安装配置与服务交互
redis·cluster·redis集群
Wang's Blog21 小时前
Java 接入Redis: Redis下载与源码编译安装
java·服务器·redis
happy_king_zi1 天前
Milvus 生产环境部署,优化,日常维护中遇到的问题
llm·milvus