AI药典助手 - 项目体系全面分析报告

Pharmacopoeia AI Agent 项目架构、功能实现与缺陷诊断

分析日期:2026-07-20 | 项目阶段:Phase 1-2 过渡期

一、项目概览

AI药典助手(Pharmacopoeia AI)是一个面向药店从业人员(药师、营业员、医生)的智能问答系统,基于《中华人民共和国药典》构建 RAG(检索增强生成) 知识库,通过通义千问(Qwen)大模型提供专业药学问答服务。同时规划了执业药师考试辅导模块。

2
后端语言(Java + Python)
9
数据库表
40+
API 端点
3
前端形态(Web + 小程序 + 静态)

项目阶段进度

Phase 1: 骨架搭建
Phase 2: 数据采集
Phase 3: RAG 上线
Phase 4: 学习模块
当前状态
项目处于 Phase 1-2 过渡期:骨架已搭建完成,RAG 链路已打通(pgvector + DashScope Embedding + Qwen LLM),Java 后端为 主力运行环境,Python 后端为辅助开发方向。核心瓶颈在于数据采集(药典 PDF 解析、NMPA 爬虫)尚未完成。

二、技术架构

整体架构图

flowchart TB
    subgraph 客户端层
      MP[微信小程序
uni-app / Vue] WEB[Web 前端
HTML + JS] STATIC[静态演示页
Mock 数据] end subgraph 网关层 NG[Nginx
反向代理 + SSL + SSE + 限流] end subgraph 后端层 JAVA[Java 后端 - Spring Boot 3.3
主力运行 | 端口 9000] PY[Python 后端 - FastAPI
辅助开发 | 端口 8000] end subgraph AI 服务 QWEN[通义千问 Qwen API
文本/视觉/Embedding] RERANK[Reranker
启发式重排序] end subgraph 存储层 PG[(PostgreSQL 16
+ pgvector 向量检索)] RD[(Redis
限流 / 缓存)] end subgraph 数据管道 CRAWL[爬虫模块
维基/NMPA/药典PDF] PROC[处理模块
切片/清洗/Embedding] end MP --> NG WEB --> NG NG --> JAVA NG --> PY JAVA --> QWEN JAVA --> RERANK JAVA --> PG JAVA --> RD PY --> QWEN PY --> PG CRAWL --> PROC PROC --> PG
图 1:AI药典助手整体系统架构

技术栈总览

层次技术说明
Java 后端Spring Boot 3.3 + Java 21Servlet 容器 + WebFlux(SSE/WebClient)
Python 后端FastAPI + asyncpg + SQLAlchemy异步框架,辅助开发方向
数据库PostgreSQL 16 + pgvector向量维度 1024,IVFFlat 索引
缓存Redis限流(已配置,部分未启用)
LLM通义千问 Qwen(DashScope)qwen3.7-max(对话)/ qwen3.6-flash(视觉)/ text-embedding-v3
小程序uni-app + Vue微信小程序,SSE 流式对话
Web 前端原生 HTML + JS + Fetch内嵌于 Spring Boot 静态资源
部署Docker Compose + Nginx + Supervisor两套配置共存(Java/Python)

三、Java 后端(主力运行)

3.1 项目结构

职责关键类
config配置类JwtProperties, QwenProperties, WechatProperties, RateLimitProperties, JsonbConverter, GlobalExceptionHandler
controllerAPI 控制器(10 个)ChatController, DrugController, AuthController, AdminController, AdminKnowledgeController, ExamChapterController, ExamPracticeController, ExamProgressController, ExamQaController, HealthController
dto数据传输对象(16 个)ChatRequest, DrugSearchRequest, LoginRequest, MultimodalChatRequest 等
entityJPA 实体(9 个)Drug, DrugChunk, User, Conversation, Message, KnowledgePoint, Question, AnswerRecord, UserProgress
repository数据访问层(10 个)继承 JpaRepository,含自定义查询
security安全框架JwtAuthFilter, JwtUtil, RateLimitFilter, SecurityConfig
service业务逻辑(8 个)LLMService, RetrieverService, RerankerService, PromptService, DrugService, ChatPersistenceService, AuthService, AdminKnowledgeService

3.2 核心 RAG 对话流程

核心数据流
用户提问 → 意图分类(关键词匹配,5 种意图)→ 药品名提取(精确/前缀/模糊匹配)→ pgvector 向量检索(top 20)→ 启发式重排序(阈值过滤 + 关键词加权 + Jaccard 去重,top 5)→ Prompt 构建(6 套意图模板 + 合规规则)→ Qwen LLM 生成来源拼接持久化 → SSE/同步返回

3.3 API 端点清单

控制器路径前缀端点数状态
ChatController/api/v1/chat12完整实现
DrugController/api/v1/drug3完整实现
AuthController/api/v1/auth2完整实现
AdminController/api/v1/admin3部分占位
AdminKnowledgeController/api/v1/admin/knowledge18CRUD 完整 / 导入占位
ExamChapterController/api/v1/exam/chapter2空壳/硬编码
ExamPracticeController/api/v1/exam/practice3空壳
ExamProgressController/api/v1/exam/progress2空壳
ExamQaController/api/v1/exam/qa2空壳
HealthController/health1完整实现

3.4 已完成的功能

  • 多模态对话:支持纯文本、图片(OCR)、视频、混合输入,同步 + SSE 流式双模式
  • 意图分类:5 种意图(药品查询、用药指导、法规条款、症状建议、考试辅导)+ 否定语义检测
  • 向量检索:pgvector 余弦距离,先精确匹配药品名再向量检索
  • 启发式重排序:阈值过滤 + 关键词覆盖率加权 + Section 相关性 + 版本优先级 + Jaccard 去重
  • Prompt 工程:6 套意图模板,含合规规则(来源标注、AI 免责声明、不编造)
  • 药品管理 CRUD:搜索、详情、分类树、创建、更新、软删除
  • 知识点/题库 CRUD:完整增删改查 + 批量审核
  • 对话持久化:会话管理、消息记录、反馈收集
  • 微信登录:jscode2session + 游客登录降级
  • JWT 鉴权:HS256 签名,24 小时有效期
  • IP 限流:内存滑动窗口,每分钟 60 次 / 每小时 1000 次
  • 知识库统计:药品数、向量覆盖率、知识点数、题目数

3.5 Java 后端存在的问题

严重问题
  • JWT 密钥硬编码:application.yml 中 64 位十六进制密钥明文存储,任何有代码权限的人可伪造任意用户 Token
  • 安全配置形同虚设:SecurityConfig 中所有路径 permitAll(),包括 /api/v1/admin/**,管理员接口完全无保护
  • CORS 完全开放setAllowedOriginPatterns("*") + setAllowCredentials(true),允许任何域名带凭证跨域访问
  • 数据库默认弱密码:默认密码 pharma2025
性能问题
  • 对话历史全量加载ChatPersistenceService.getHistory() 使用 findAll() 全量加载所有对话到内存再排序分页,数据量大时将 OOM
  • 无 Embedding 缓存:每次检索都调用远程 API 生成向量,相同 query 重复调用浪费时间和费用
  • LLM 同步阻塞.block() 阻塞调用,高并发下 Servlet 线程池可能耗尽
代码质量问题
  • ChatController 职责过重:770 行代码,包含 RAG 管线、来源构建、药品名提取等多个职责
  • SECTION_DISPLAY 重复定义:ChatController 和 PromptService 各自定义了一份映射,存在不一致风险
  • 异常处理吞掉错误:LLMService 中多处 catch (Exception e) { return ""; },无法区分模型返回空和调用失败
  • Conversation.userId 硬编码为 0:未关联实际用户
  • 死代码buildDirectAnswer() 定义但从未调用

四、Python 后端(辅助开发)

Python 后端基于 FastAPI 构建,是项目的辅助开发方向。API 端点与 Java 后端基本对齐,但在实现深度上存在差异。

4.1 与 Java 后端的差异

维度Java 后端Python 后端
运行状态主力运行辅助开发
ORM 使用JPA 全量使用大部分用原生 SQL,ORM 形同虚设
数据库连接连接池自动管理chat.py 每次请求创建新引擎(严重性能问题)
权限控制SecurityConfig(虽无效但有框架)无任何权限校验
管理接口CRUD 完整实现大部分返回硬编码空数据
限流内存滑动窗口(已启用)Redis 限流类已定义但未调用
对话上下文无多轮历史无多轮历史

4.2 Python 后端特有问题

  • 数据库连接未复用:chat.py 中 _save_message_ensure_user 每次都 create_async_engine,高并发下会耗尽数据库连接
  • 对话历史不按用户过滤:返回所有用户的对话,存在数据泄露风险
  • ORM 模型与实际使用脱节:大部分路由用原生 text() SQL,ORM 定义基本只在 drug.py 使用
  • drug.py 硬编码数据库连接字符串:未使用 config.py 的配置
  • Base 重复定义base.pyuser.py 各定义了一个 DeclarativeBase()
  • RateLimiter 未被使用:定义了类但在任何 API 路由中都没有调用
  • get_current_user 返回 payload dict:而非 User 对象,路由拿到的 user 只有 sub(openid)
  • 默认 secret_key="change-me":生产环境严重安全隐患

五、前端与小程序

5.1 前端形态对比

前端路径类型API 连接状态
生产级 Webbackend-java/.../static/index.html内嵌 Spring Boot真实 API(非流式)可用
演示 Webfrontend-web/index.html独立 HTMLMock 数据演示用
静态副本static/index.html独立 HTMLMock 数据冗余文件
API 测试frontend-web/test.html独立 HTMLSSE(Token 已过期)不可用
小程序页面miniprogram/pages/ai-yaodian/uni-app Vue真实 SSE API可用
小程序组件miniprogram/components/ai-chat/浮动面板组件真实 SSE API可用

5.2 前端已完成功能

  • 生产级 Web:JWT 鉴权、对话历史侧边栏、消息队列可视化、反馈功能(👍👎)、药品库分页搜索、健康检查
  • 小程序页面:SSE 流式对话、消息队列(排队发送)、停止功能、多媒体上传、快捷标签、来源展示、意图标签
  • 小程序浮动组件:可嵌入任意页面的 AI 对话面板,支持 drugName prop 自动填入
  • 演示页:完整的 UI 交互演示,含药品库浏览、媒体上传预览、打字机效果

5.3 前端存在的问题

关键缺陷
  • 生产级 Web 未使用 SSE:调用非流式 /chat/ask,浪费了后端已实现的 /chat/stream SSE 能力
  • Markdown 渲染逻辑三处重复:frontend-web、ai-yaodian 页面、ai-chat 组件各自独立实现,维护成本极高
  • SSE 工具类未被使用utils/sse.js 提供了通用 SSE 能力,但 api/ai.js 内联了几乎相同的逻辑
  • 运算符优先级 Bug:frontend-web/index.html 三元表达式嵌套错误,导致媒体类型显示为 true/false
  • 小程序 BASE_URL 占位符https://your-api-domain.com 未配置
  • 文件冗余static/index.htmlfrontend-web/index.html 完全相同
  • scrollToBottom 不可靠:固定大值方式在部分场景下失效
  • XSS 风险:药品详情页 sections 内容直接 innerHTML 输出未转义

六、数据管道

6.1 爬虫模块状态

爬虫文件状态说明
维基百科采集wiki_spider.py已实现BeautifulSoup 解析,匹配药典相关栏目
批量维基采集batch_collect.py已实现限量 50 个/轮
药典 PDF 目录提取extract_catalog.py已实现PyMuPDF + 动态阈值
多源探测probe.py已实现数据可用性检测工具
基础框架spider.py框架存在Scrapy BasePharmSpider,引用了不存在的 middleware
NMPA 爬虫nmpa_spider.py空壳 Phase 2需要 Selenium/Playwright
药典 PDF 解析pharmacopoeia.py空壳 Phase 2PyMuPDF,核心数据源未实现
考试大纲采集exam_outline.py空壳 Phase 2待实现

6.2 处理模块状态

处理器文件状态说明
智能切片器chunker.py已实现三种模式(药品/法规/考试),但未被 ingest.py 使用
文本清洗cleaner.py已实现OCR 纠错字典,但未被 ingest.py 调用
远程 Embeddingingest.py已实现DashScope text-embedding-v3,批量 10 条
本地 Embeddingembedder.py空壳BGE-M3 返回全零向量
知识点切片knowledge_chunker.py空壳Phase 2
题目生成question_generator.py空壳Phase 2
核心瓶颈

药典 PDF 解析器(pharmacopoeia.py)是整个项目的最大瓶颈。当前只能依赖手动整理的 JSON 数据和维基百科采集,药典正文数据的最主要来源尚未实现。同时,已实现的 chunker.pycleaner.pyingest.py 绕过,数据处理质量未达到设计标准。

6.3 数据入库流程

ingest.py 数据流
JSON 文件 → 按 section 切 chunk → 拼接药品名+栏目名+来源 → 批量调用 DashScope Embedding API(每批 10 条)→ 写入 drug_chunks 表(content + embedding JSON + vec pgvector)→ 写入 drugs 表(ON CONFLICT DO UPDATE)

ingest.py 存在的问题:逐条 INSERT 无批量操作、无错误处理和断点续传、同时写 embedding(JSON) 和 vec(pgvector) 冗余存储、手动解析 .env 而非使用配置管理。

七、数据库设计

7.1 表结构总览

表名说明关键字段状态
users用户openid(UK), nickname, role已使用
drugs药品主表drug_id(UK), name, sections(JSONB), 分类, source_version已使用
drug_chunks药品文本切片content, vec(vector(1024)), embedding(JSON)已使用
conversations对话会话conversation_id(UK), user_id, titleuser_id 硬编码 0
messages对话消息role, content, intent, sources(JSONB), feedback已使用
knowledge_points考试知识点point_id(UK), subject, chapter, difficulty, frequency已建表/无数据
questions考试题目question_id(UK), type(A/B/X), options(JSONB), answer已建表/无数据
user_progress用户学习进度user_id, subject, chapter, questions_answered已建表/无数据
answer_records答题记录user_id, question_id, is_correct已建表/无数据

7.2 索引设计

  • pgvector IVFFlat 索引idx_drug_chunks_vec(lists=10)
  • GIN 索引ix_drugs_sections_gin(JSONB sections 列)
  • 唯一索引:drug_id, conversation_id, point_id, question_id, openid
  • 外键:messages→conversations, answer_records→users, user_progress→users

7.3 数据库存在的问题

  • IVFFlat 索引 lists=10 过小:数据量增长到数万条时检索质量严重下降,建议使用 HNSW 或增大 lists
  • embedding 和 vec 冗余存储:drug_chunks 同时有 embedding(JSON) 和 vec(vector),embedding 列完全多余
  • 无 tsvector 全文搜索索引:BM25 检索无法实现
  • 无 created_at 索引:按时间排序的查询会全表扫描
  • conversations.user_id 允许 NULL:与 messages 外键引用和实际使用(硬编码 0)设计不一致

八、部署方案

8.1 部署架构

组件工具说明
容器编排Docker Compose仅定义 PostgreSQL + Redis,后端未纳入
反向代理Nginx两套配置共存(Java 端口 9000 / Python 端口 8000)
进程管理Supervisor两套配置共存(Java JAR / Python uvicorn)
SSLNginx证书路径为占位符,未配置

8.2 部署存在的问题

  • 两套配置共存:nginx.conf / nginx-pharmacopoeia.conf、supervisord.conf / supervisord-java.conf,说明部署架构还在 Java/Python 过渡期
  • 后端未纳入 Docker Compose:FastAPI 应用未容器化
  • SSL 证书占位符/etc/nginx/ssl/cert.pem
  • supervisord.conf 引用不存在的 tasks 模块celery -A app.tasks worker
  • supervisord-java.conf 硬编码密码和 API Key
  • PostgreSQL 默认密码POSTGRES_PASSWORD: postgres

九、缺陷清单与风险评估

9.1 严重缺陷(P0 - 必须立即修复)

#缺陷位置影响
1JWT 密钥硬编码在配置文件中Java: application.yml任何人可伪造 Token,完全绕过认证
2所有 API 路径 permitAll(),无权限控制Java: SecurityConfig.java管理员接口完全无保护,任何人可执行增删改查
3CORS 完全开放 + 允许凭证Java: SecurityConfig.javaCSRF 风险,任何网站可代用户操作
4对话历史不按用户过滤Python: chat.py数据泄露,任何用户可查看所有对话
5Python 后端每次请求创建新数据库引擎Python: chat.py高并发下耗尽数据库连接,服务崩溃

9.2 高优先级缺陷(P1 - 尽快修复)

#缺陷位置影响
6对话历史全量加载到内存分页Java: ChatPersistenceService数据量增长后 OOM 和严重延迟
7数据库默认弱密码Java: application.yml / Docker数据库安全风险
8Python 默认 secret_key="change-me"Python: config.pyJWT 可被轻易伪造
9Conversation.userId 硬编码为 0Java: ChatPersistenceService对话无法关联到具体用户
10无多轮对话上下文Java + PythonLLM 无法理解上下文,问答质量受限
11生产级 Web 未使用 SSE 流式Java: static/index.html用户体验差,浪费后端能力
12小程序 BASE_URL 为占位符miniprogram: api/ai.js小程序无法连接后端

9.3 中优先级缺陷(P2 - 计划修复)

#缺陷位置影响
13无 Embedding 缓存Java: RetrieverService重复查询浪费 API 费用和时间
14LLMService 同步阻塞Java: LLMService高并发下线程池耗尽
15BM25 检索未实现Java + Python混合检索只实现了一半,检索召回率受限
16BGE-Reranker 未加载Java + Python重排序使用简单启发式,精度不足
17Markdown 渲染逻辑三处重复前端多文件维护成本极高,行为不一致
18ChatController 职责过重(770 行)Java: ChatController代码可维护性差
19ingest.py 未使用 chunker/cleanerdata-pipeline数据处理质量未达设计标准
20IVFFlat 索引 lists=10 过小database: schema.sql数据量增长后检索质量下降
21embedding 和 vec 冗余存储database + ingest存储浪费,一致性风险
22异常处理吞掉错误Java: LLMService无法区分模型返回空和调用失败
23Python ORM 模型与实际使用脱节Python: models/代码混乱,维护困难
24部署配置两套共存deploy/部署混乱,易出错

9.4 低优先级缺陷(P3 - 优化改进)

#缺陷位置影响
25文件冗余(static/index.html 重复)static/维护混乱
26工具脚本功能重叠tools/应合并为一个
27test.html Token 过期frontend-web/测试工具不可用
28test_qwen_api.py .env 路径错误tools/测试工具无法找到配置
29scrollToBottom 实现不可靠小程序部分场景滚动失效
30XSS 防护不一致前端多文件药品详情页 sections 未转义
31死代码 buildDirectAnswer()Java: ChatController代码整洁度
32SECTION_DISPLAY 重复定义Java: ChatController + PromptService不一致风险
33RateLimitFilter 仅内存限流Java多实例部署无法共享限流状态
34缺少 @Transactional(readOnly=true)Java: Repository浪费数据库资源
35视频 base64 传输Python: llm_client.py50MB 视频产生 ~67MB base64,内存压力极大

9.5 未完成模块

模块状态影响
药典 PDF 解析器空壳核心数据源缺失,是最主要瓶颈
NMPA 药品数据库爬虫空壳药品数据来源受限
考试学习模块(4 个 Controller)全部空壳考试辅导功能完全不可用
管理后台导入/索引/AI 出题占位批量操作不可用
Celery 异步任务无 tasks 模块长时间操作无法异步执行
本地 BGE-M3 Embedding返回全零向量依赖远程 API,成本和延迟较高
BM25 全文检索未实现混合检索只实现了一半
BGE-Reranker 模型空方法重排序精度不足

十、总结与建议

10.1 项目成果总结

AI药典助手项目已经完成了基础架构搭建和核心 RAG 链路打通,具体成果包括:

  • 搭建了完整的双后端体系(Java 主力 + Python 辅助),覆盖 40+ API 端点
  • 实现了基于 pgvector 的向量检索 + 启发式重排序 + Qwen LLM 生成的 RAG 管线
  • 支持多模态输入(文本/图片/视频),SSE 流式输出
  • 完成了微信小程序和 Web 前端的 UI 交互实现
  • 设计了完整的数据库结构(9 张表)和知识库管理 CRUD
  • 构建了数据管道框架(爬虫 + 处理器 + 入库脚本)
  • 完成了 Prompt 工程(6 套意图模板 + 合规规则)

10.2 核心问题诊断

三大核心问题
  1. 安全体系缺失:JWT 密钥硬编码、权限控制形同虚设、CORS 完全开放,生产环境存在严重安全风险
  2. 数据采集瓶颈:药典 PDF 解析器和 NMPA 爬虫未实现,知识库数据量严重不足,直接影响问答质量
  3. 双后端维护成本:Java/Python 两套后端共存,部署配置、ORM 使用、API 实现深度均不一致,增加维护复杂度

10.3 优先修复建议

优先级行动项预期效果
P0修复安全配置:JWT 密钥改用环境变量、admin 路由强制认证、限制 CORS 来源消除生产环境安全风险
P0修复数据泄露:对话历史按 user_id 过滤、Python 后端复用数据库连接防止用户数据泄露和服务崩溃
P1实现药典 PDF 解析器突破数据采集瓶颈,充实知识库
P1修复对话历史分页查询、关联真实 userId解决 OOM 风险和用户隔离
P1生产级 Web 切换到 SSE 流式、小程序配置真实 BASE_URL提升用户体验
P2引入 Embedding 缓存、实现 BM25 检索、加载 BGE-Reranker提升检索质量和性能
P2统一部署配置、合并冗余文件、重构 ChatController降低维护成本
P2前端抽取共享 Markdown 渲染和 SSE 工具消除代码重复
P2数据库升级 IVFFlat→HNSW、清理冗余 embedding 列、添加 tsvector 索引提升检索性能和可扩展性

10.4 架构演进建议

  1. 明确后端策略:建议以 Java 后端为唯一生产环境,Python 后端仅用于数据管道和脚本工具,避免双后端维护负担
  2. 引入多轮对话:当前每次请求只发送当前问题,应携带历史消息上下文以提升问答质量
  3. 完善监控体系:添加请求日志、LLM 调用统计、API 用量追踪,便于运维和成本控制
  4. 数据质量管控:让 ingest.py 使用已实现的 chunker.py 和 cleaner.py,确保入库数据质量
  5. 渐进式功能交付:考试模块可先实现章节树和基础刷题,再逐步加入 AI 出题和进度跟踪