基于 LangGraph 构建智能分诊系统(一):项目概述与环境搭建

从零搭建一个带记忆、工具调用和持久化的医疗分诊 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 数据库来存储:

  1. 对话检查点(Checkpointer):保存每个会话的状态,支持多轮对话记忆。

  2. 用户长期记忆(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。

  • macOSbrew install postgresql

  • Linuxsudo 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 函数根据类型创建 ChatOpenAIOpenAIEmbeddings 实例。

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

六、验证环境是否就绪

在开始编码核心功能前,建议先进行快速验证:

  1. 确认 PostgreSQL 容器运行正常docker ps | grep langgraph-postgres

  2. 测试数据库连接 :编写简单 Python 脚本,使用 psycopg2 连接并执行 SELECT 1

  3. 测试 LLM 连接 :调用 initialize_llm("qwen") 并发送一条简单消息,确保返回非空。

  4. 准备向量库数据 :运行 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)

  • 测试完整的对话流程(包括记忆、工具调用和检索重写)

如果你在搭建过程中遇到任何问题,欢迎在评论区留言。我们下篇见!

相关推荐
小林ixn1 小时前
大模型的“高考成绩单”:读懂Benchmark,选对真·生产力模型
人工智能·llm·测试
冬奇Lab1 小时前
AI 评测系列(04):RAG 评测——RAGAS 四指标实战与一个反直觉发现
人工智能·llm·agent
三声三视1 小时前
uni-app 鸿蒙端传参变成 [object Object]?顺着源码追到 ArkTS router 底层才搞明白
人工智能·ai·uni-app·aigc·ai编程·harmonyos
fthux2 小时前
“装闭”,让装修套路“装”不下去
人工智能·ai·开源·github·open source
andxe2 小时前
安科士 AndXe 技术博客:400G QSFP112 SR4 光模块|AI 算力与超算短距互联最优方案
网络·人工智能·光模块·光通信
玉鸯2 小时前
Agent Hook:在概率推理之上,为 Agent 叠加确定性控制
python·langchain·agent
计算机魔术师3 小时前
Karpathy:用语音与LLM长谈可提升理解效率
人工智能·ai编程
甲维斯4 小时前
我要开始吹牛逼了!Kimi K3 “宇宙无敌”!
前端·人工智能
周末程序猿4 小时前
图解 120 个大语言模型(LLM)核心概念(61-90)
人工智能