从零搭建一个带记忆、工具调用和持久化的医疗分诊 AI Agent,先打好地基。
在医疗场景中,患者咨询往往涉及多轮对话、信息检索、数据计算甚至历史记忆。传统的固定流程(Chain)难以应对这种开放性需求。LangGraph 作为 LangChain 的进阶编排框架,允许我们构建带有循环、条件分支和状态持久化的复杂 Agent 工作流。
本系列将带你从零实现一个智能分诊系统,它能够:
-
理解用户意图,自主决定是否调用工具(检索健康档案、计算等)
-
并行执行多个工具,提高效率
-
对检索结果进行相关性评分,必要时重写查询
-
通过 PostgreSQL 持久化对话状态和用户长期记忆
-
提供 FastAPI 接口和 Gradio Web 界面
本篇作为系列开篇,我们重点完成项目背景理解、环境准备和配置管理,为后续的核心功能开发夯实基础。
一、项目概述与核心流程
1.1 为什么需要智能分诊系统?
传统的客服或分诊系统通常基于规则或固定对话树,无法处理复杂、开放式的用户提问。例如:
-
"帮我算一下 3 乘以 4 等于多少?"
-
"张三九的健康档案信息是什么?"
-
"记住我的名字叫 Kevin。"
这些问题分别涉及计算、检索和记忆 ,一个固定流程无法同时覆盖。我们的系统采用 Agent + 工具调用 的模式,让大模型(LLM)作为大脑,根据用户输入动态决策调用哪些工具,并支持多轮对话和状态持久化。
1.2 整体工作流程图解
系统核心是基于 LangGraph 构建的状态图(StateGraph),包含以下节点和路由:
text
用户输入 → agent(意图分析)
│
├─ 无需工具 → 直接 generate(回复)→ 结束
│
└─ 需调用工具 → call_tools(并行执行)
│
├─ 非检索类工具 → generate → 结束
│
└─ 检索类工具 → grade_documents(相关性评分)
│
├─ 相关 → generate → 结束
│
└─ 不相关 → rewrite(重写查询,最多3次)→ 回到 agent
关键设计:
-
并行工具执行:使用线程池同时调用多个工具,提升响应速度。
-
检索质量保障:对检索结果进行相关性评分,不相关则重写查询后重新尝试,最多 3 次,避免"答非所问"。
-
持久化记忆:不仅保存对话历史(线程内),还支持跨线程存储用户偏好(如"记住我的名字")。
1.3 核心功能模块一览
| 模块 | 功能 |
|---|---|
| 状态图工作流 | 定义 agent、call_tools、grade_documents、rewrite、generate 等节点及动态路由 |
| 工具管理与并行调用 | 通过 ToolConfig 管理工具列表和路由,ParallelToolNode 实现并行执行 |
| 数据库与持久化 | 使用 PostgreSQL + pgvector 存储检查点(对话状态)和用户长期记忆,支持连接池 |
| 提示模板与消息过滤 | 加载外部 txt 模板,过滤消息(仅保留最近 5 条 AIMessage/HumanMessage) |
| 日志与错误处理 | 支持文件轮转日志,多层次异常捕获与重试(tenacity) |
| 用户交互 | 命令行交互、FastAPI 接口、Gradio WebUI 三种方式 |
二、环境准备:Conda + 依赖库
2.1 创建 Conda 环境
建议使用 Python 3.11,避免依赖冲突。
bash
conda create -n L1-project-2 python=3.11
conda activate L1-project-2
2.2 安装核心依赖
根据项目文档,我们需要安装以下关键库:
bash
pip install langgraph==0.2.74
pip install langchain-openai==0.3.6
pip install langchain-community==0.3.19
pip install langchain-chroma==0.2.2
pip install pdfminer pdfminer.six
pip install nltk==3.9.1
pip install psycopg2==2.9.10
pip install concurrent-log-handler==0.9.25
pip install langgraph-checkpoint-postgres
pip install psycopg psycopg-pool
说明 :
langgraph-checkpoint-postgres用于将对话检查点持久化到 PostgreSQL,psycopg-pool提供连接池支持。如果后续用到向量检索,还需langchain-chroma作为本地向量库。
三、Docker 部署 PostgreSQL + pgvector
我们的系统需要 PostgreSQL 数据库来存储:
-
对话检查点(Checkpointer):保存每个会话的状态,支持多轮对话记忆。
-
用户长期记忆(Store):存储用户偏好信息(如"我叫 Kevin"),跨会话生效。
同时,由于 LangGraph 的 PostgresStore 依赖 pgvector 扩展(用于向量相似度搜索),我们需要在 PostgreSQL 中安装该扩展。
3.1 使用 Docker Compose 启动 PostgreSQL
编写 docker-compose.yml 文件(项目文档中给出,但未贴完整内容,这里提供一个标准配置):
yaml
version: '3.8'
services:
postgres:
image: postgres:15
container_name: langgraph-postgres
environment:
POSTGRES_USER: kevin
POSTGRES_PASSWORD: 123456
POSTGRES_DB: postgres
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
启动容器:
bash
docker-compose up -d
3.2 在容器内安装 pgvector
因为官方 PostgreSQL 镜像默认不含 pgvector,需要进入容器手动编译安装(或使用 pgvector/pgvector 镜像,但项目文档采用手动方式)。
进入容器(可通过 Docker Desktop 的终端或命令行):
bash
docker exec -it langgraph-postgres bash
执行安装步骤:
bash
# 更新包管理器并安装编译依赖
apt update
apt install -y git build-essential postgresql-server-dev-15
# 克隆 pgvector 源码(v0.7.0)
git clone --branch v0.7.0 https://github.com/pgvector/pgvector.git
cd pgvector
make
make install
# 验证安装
ls -l /usr/share/postgresql/15/extension/vector*
# 应显示 vector.control 文件
退出容器 ,然后创建扩展(连接到数据库):
bash
docker exec -it langgraph-postgres psql -U kevin -d postgres
CREATE EXTENSION vector;
\dx # 查看已安装扩展,应包含 vector
3.3 安装 PostgreSQL 客户端库(libpq)
Python 的 psycopg 需要 libpq 来连接数据库。根据操作系统选择安装方式:
-
Windows :推荐安装完整 PostgreSQL(含客户端工具),或下载独立二进制包,并将
bin目录添加到 PATH。 -
macOS :
brew install postgresql -
Linux :
sudo apt install libpq-dev
验证方法:
bash
where libpq.dll # Windows
which libpq # Linux/macOS
四、项目配置管理(Config + LLM 配置)
良好的配置管理是项目可维护性的关键。项目采用两个核心配置类:Config(全局常量)和 llms 模块(大模型实例化)。
4.1 全局配置类 Config
集中管理所有路径、数据库 URI、日志参数等,便于修改。
python
# config.py
import os
class Config:
# Prompt 模板文件路径
PROMPT_TEMPLATE_TXT_AGENT = "prompts/prompt_template_agent.txt"
PROMPT_TEMPLATE_TXT_GRADE = "prompts/prompt_template_grade.txt"
PROMPT_TEMPLATE_TXT_REWRITE = "prompts/prompt_template_rewrite.txt"
PROMPT_TEMPLATE_TXT_GENERATE = "prompts/prompt_template_generate.txt"
# Chroma 向量库配置
CHROMADB_DIRECTORY = "chromaDB"
CHROMADB_COLLECTION_NAME = "demo001"
# 日志配置
LOG_FILE = "output/app.log"
MAX_BYTES = 5 * 1024 * 1024 # 5MB 轮转
BACKUP_COUNT = 3
# 数据库连接 URI(从环境变量读取,或使用默认)
DB_URI = os.getenv("DB_URI", "postgresql://kevin:123456@localhost:5432/postgres?sslmode=disable")
4.2 大模型配置管理(llms.py)
支持多种模型服务商:OpenAI、阿里通义千问(Qwen)、OneAPI 聚合、本地 Ollama。通过 initialize_llm 函数根据类型创建 ChatOpenAI 和 OpenAIEmbeddings 实例。
python
# llms.py
import os
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
MODEL_CONFIGS = {
"openai": {
"base_url": os.getenv("OPENAI_BASE_URL"),
"api_key": os.getenv("OPENAI_API_KEY"),
"chat_model": "gpt-4o",
"embedding_model": "text-embedding-3-small"
},
"qwen": {
"base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"api_key": os.getenv("DASHSCOPE_API_KEY"),
"chat_model": "qwen-max",
"embedding_model": "text-embedding-v1"
},
"ollama": {
"base_url": "http://localhost:11434/v1",
"api_key": "ollama",
"chat_model": "qwen3:latest",
"embedding_model": "bge-m3:latest"
}
}
DEFAULT_LLM_TYPE = "qwen" # 可改为 openai 或 ollama
def initialize_llm(llm_type=DEFAULT_LLM_TYPE):
config = MODEL_CONFIGS[llm_type]
llm_chat = ChatOpenAI(
base_url=config["base_url"],
api_key=config["api_key"],
model=config["chat_model"],
temperature=0.1,
timeout=30,
max_retries=2
)
llm_embedding = OpenAIEmbeddings(
base_url=config["base_url"],
api_key=config["api_key"],
model=config["embedding_model"],
check_embedding_ctx_length=False # 重要!避免 Qwen 嵌入报错
)
return llm_chat, llm_embedding
特别注意 :当使用 Qwen 嵌入模型时,默认会检查上下文长度,但 Qwen 接口返回错误,需显式设置
check_embedding_ctx_length=False。这是项目踩坑后的优化点。
4.3 提示模板文件
项目使用外部 .txt 文件存储提示词,便于非开发人员修改。例如 prompt_template_agent.txt 内容大致为:
text
你是一个医疗分诊助手,你可以使用以下工具:
{tools}
请根据用户问题 {question} 和历史消息 {messages},以及用户信息 {userInfo},决定是否需要调用工具,并给出最终回复。
后续通过 create_chain 函数加载并缓存这些模板,提高效率。
五、项目目录结构建议
为保证后续开发的清晰性,推荐项目目录如下:
text
smart_triage/
├── config.py
├── llms.py
├── prompts/
│ ├── prompt_template_agent.txt
│ ├── prompt_template_grade.txt
│ ├── prompt_template_rewrite.txt
│ └── prompt_template_generate.txt
├── tools/
│ ├── __init__.py
│ └── tool_config.py
├── graph/
│ ├── __init__.py
│ ├── nodes.py # agent, generate, rewrite, grade_documents
│ └── workflow.py # 创建状态图
├── db/
│ └── postgres_store.py # 连接池和存储初始化
├── utils/
│ └── logger.py
├── main.py # 命令行交互入口
├── api.py # FastAPI 接口
├── webui.py # Gradio 界面
├── vectorSave.py # 预置向量库数据
└── docker-compose.yml
六、验证环境是否就绪
在开始编码核心功能前,建议先进行快速验证:
-
确认 PostgreSQL 容器运行正常 :
docker ps | grep langgraph-postgres -
测试数据库连接 :编写简单 Python 脚本,使用
psycopg2连接并执行SELECT 1。 -
测试 LLM 连接 :调用
initialize_llm("qwen")并发送一条简单消息,确保返回非空。 -
准备向量库数据 :运行
vectorSave.py(后续会提供),将健康档案文档切分并存入 Chroma,供检索工具使用。
七、踩坑提醒与最佳实践
-
Qwen 嵌入报错 :务必在
OpenAIEmbeddings中设置check_embedding_ctx_length=False。 -
Windows 下 libpq 缺失 :将 PostgreSQL 的
bin目录加入系统 PATH,重启终端。 -
连接池耗尽 :生产环境需根据负载调整
max_size,并在代码中做好超时和重试(项目已使用 tenacity)。 -
日志轮转 :使用
ConcurrentRotatingFileHandler避免多进程写日志冲突。 -
提示词模板管理 :将模板外置为
.txt文件,便于 A/B 测试和快速迭代。
结语与预告
本篇我们完成了:
-
理解智能分诊系统的整体架构与工作流程
-
搭建 Conda 环境并安装所有依赖
-
使用 Docker 部署 PostgreSQL + pgvector
-
配置管理类和大模型初始化
-
项目目录结构规划与验证要点
下一篇,我们将进入核心开发阶段:
-
定义工具(检索工具、计算工具)与工具配置管理
-
实现状态图的各个节点(agent、call_tools、grade_documents、rewrite、generate)
-
设计动态路由条件(tools_condition、route_after_tools、route_after_grade)
-
集成检查点(Checkpointer)和长期记忆(Store)
-
测试完整的对话流程(包括记忆、工具调用和检索重写)
如果你在搭建过程中遇到任何问题,欢迎在评论区留言。我们下篇见!