☰
用 Python 从零搭建病人信息管理系统:TaoToken 统一 Key 接入与配置文件骨架
2026/9/27 14:52:29 网站建设 项目流程

1. 从 Tkinter 到 AI 辅助:病人信息管理系统为什么需要统一 Key

用 Python 写病人信息管理系统,很多人第一版都是 Tkinter + pymssql 直连数据库:登录窗口、病人登记、病例查询、医生管理,一套界面堆下来能跑,但真正上线到本地开发环境后,问题会集中爆发。最典型的是三件事:数据库连接参数散落在每个类里,改一次密码要全局搜索替换;AI 辅助录入、病历摘要、智能查询这些能力没有统一入口,每接一个模型就多一套 Key 和 SDK;配置文件格式混乱,config.toml和settings.json各写一半,新人拉下来根本不知道先改哪个。

这篇面向的是需要快速跑通 AI 辅助录入与查询的 Python 开发者。目标很明确:交付一份可复制的config.toml与settings.json骨架,把数据库连接、TaoToken 统一 Key、模型通道收敛到一处;再给出启动后验证病人信息增删改查是否生效的具体动作。你不需要推翻原来的 Tkinter 界面,只需要把数据层和 AI 调用层抽出来,接上统一通道即可。

先说清楚 TaoToken 在这个系统里扮演什么角色。它提供的是统一的 API 通道和 Key 管理,官网是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。你可以把它理解成“一个 Key 走通多个模型”的网关:病人登记时用 AI 做字段纠错、病例查询时用 AI 做自然语言转 SQL 草稿、医生录入时用 AI 做摘要,这些调用都走同一个 Key,不用在代码里塞五六个厂商的密钥。对本地开发场景来说,这能省掉大量配置切换的时间。

需要提前说明的是,本文所有操作都在本地开发环境完成,数据库用你现有的 SQL Server 或换成 SQLite 都行,重点是配置骨架和验证流程。下面从原问题拆解开始,一步步把可复制的配置和验证动作给出来。

2. 原问题与场景:Tkinter 直连数据库的三个坑

先复盘一下传统写法的痛点,这样你才知道配置骨架要解决什么。参考的原始代码里,dbTools()函数在每个类里被反复调用,连接字符串pymssql.connect('DESKTOP-9NADTHD', 'sa', 'shiyike', 'hospital')硬编码在函数体内。这意味着:

第一,环境切换成本高。开发机、测试机、演示机的数据库地址不同,每次换环境都要改代码。如果再加上 AI 模型的 Key,配置项会膨胀到十几个,散落在Login、RecordPatient、QueryPatient各个类里,维护起来非常痛苦。

第二,AI 能力接入没有统一层。假设你想在病人登记时加一个“根据主诉自动填充科室”的功能,传统做法是在RecordPatient._confirm()里直接调某个模型的 HTTP 接口。等你想换模型或者加一个“病历摘要”功能,又要在AddPaList里再写一遍请求逻辑。Key 管理、超时重试、错误处理全部重复。

第三,配置格式不统一。有人用.ini,有人用.json,有人直接写 Python 常量。团队协作时,config.toml和settings.json混用,读取逻辑各写各的,新人接手第一小时全花在找配置上。

所以这篇的解法是:把配置分成两层。config.toml管“连接类”信息——数据库地址、端口、账号、TaoToken 的 base_url 和 Key 引用;settings.json管“业务类”信息——模型名称、超时时间、重试次数、AI 功能开关。两者通过一个ConfigLoader类统一读取,业务代码只依赖这个 Loader,不直接碰文件。

场景落地是这样的:你本地已经有一个能跑的 Tkinter 病人管理系统,现在要加三个 AI 辅助功能——登记时字段校验、查询时自然语言转条件、病例录入时自动摘要。这三个功能都通过 TaoToken 统一 Key 调用,配置全部收敛到两个文件里。下面先讲 TaoToken 的前置准备。

3. TaoToken 前置:Key 申请与通道确认

在写配置骨架之前,你需要先拿到统一 Key 并确认通道地址。这一步不复杂,但有几个细节容易踩坑。

首先访问官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 了解通道能力,然后进入控制台创建 API Key。控制台入口是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,API Keys 管理页是 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。创建时建议按用途命名,比如patient-system-dev,方便后续区分开发和生产。

拿到 Key 之后,确认两件事:base_url 用https://taotoken.net/api,不要带 UTM 参数,这是给代码调用的干净地址;模型名称要和你settings.json里写的一致。如果你不确定用哪个模型,可以先到模型对话页 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat&utm_campaign=rewrite 试一下,确认通道通不通、返回格式是否符合预期。

这里有个实操建议:不要把 Key 直接写进config.toml提交到 Git。正确做法是config.toml里写占位符,真实 Key 放在环境变量里,Loader 读取时做一次替换。这样配置文件可以安全地进版本库,Key 通过.env或系统环境变量注入。下面第 4 节的骨架就是按这个思路设计的。

另外,如果你的系统后续要做长期编码或 Agent 类功能,比如自动生成病历模板、批量处理病人数据,可以了解 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,它更适合持续性的编码任务。本文聚焦的是本地开发场景下的接入与验证,先用按量调用跑通即可。

4. 可复制配置:config.toml 与 settings.json 骨架

这一节是核心交付。先给目录结构,再给两个文件的完整内容,最后给 Loader 代码。你直接复制就能用。

目录结构建议这样组织:

patient_system/ ├── config/ │ ├── config.toml │ └── settings.json ├── core/ │ ├── config_loader.py │ └── db.py ├── ai/ │ └── client.py ├── ui/ │ └── main_window.py └── main.py

config/config.toml负责连接类配置:

# config/config.toml # 数据库连接配置 [database] driver = "pymssql" host = "127.0.0.1" port = 1433 user = "sa" password = "${DB_PASSWORD}" # 从环境变量注入 database = "hospital" charset = "utf8" timeout = 5 # TaoToken 统一通道配置 [taotoken] base_url = "https://taotoken.net/api" api_key = "${TAOTOKEN_API_KEY}" # 从环境变量注入 default_model = "claude-3-5-sonnet" connect_timeout = 10 read_timeout = 60 max_retries = 2 # 日志配置 [logging] level = "INFO" file = "logs/patient_system.log"

config/settings.json负责业务类配置:

{ "app": { "name": "病人信息管理系统", "version": "1.0.0", "debug": true }, "ai_features": { "enable_field_validation": true, "enable_nl_query": true, "enable_record_summary": true }, "model_params": { "temperature": 0.2, "max_tokens": 1024, "top_p": 0.9 }, "ui": { "window_width": 500, "window_height": 300, "theme": "default" } }

两个文件的分工要记清楚:config.toml里的值会随环境变化,所以用环境变量占位;settings.json里的值是业务逻辑参数,相对稳定,可以直接写死。接下来是 Loader,它负责把两者合并成一个可访问的对象:

# core/config_loader.py import os import json import tomllib from pathlib import Path class ConfigLoader: _instance = None def __new__(cls, config_dir="config"): if cls._instance is None: cls._instance = super().__new__(cls) cls._instance._load(config_dir) return cls._instance def _load(self, config_dir): base = Path(config_dir) with open(base / "config.toml", "rb") as f: self.toml = tomllib.load(f) with open(base / "settings.json", "r", encoding="utf-8") as f: self.json = json.load(f) self._resolve_env(self.toml) def _resolve_env(self, node): if isinstance(node, dict): for k, v in node.items(): if isinstance(v, str) and v.startswith("${") and v.endswith("}"): env_key = v[2:-1] node[k] = os.environ.get(env_key, "") else: self._resolve_env(v) @property def db(self): return self.toml["database"] @property def taotoken(self): return self.toml["taotoken"] def ai_enabled(self, feature): return self.json["ai_features"].get(feature, False) def model_params(self): return self.json["model_params"]

注意tomllib是 Python 3.11 起内置的,如果你用 3.10 及以下,换成tomli并pip install tomli即可。Loader 用单例模式,保证全局只读一次文件,避免每个类都去解析配置。

数据库连接层也顺手抽出来,替换掉原来散落的dbTools():

# core/db.py import pymssql from core.config_loader import ConfigLoader class DB: def __init__(self): cfg = ConfigLoader().db self.conn = pymssql.connect( server=cfg["host"], user=cfg["user"], password=cfg["password"], database=cfg["database"], port=cfg["port"], charset=cfg["charset"], timeout=cfg["timeout"], ) def cursor(self): return self.conn.cursor() def commit(self): self.conn.commit() def close(self): self.conn.close()

这样RecordPatient、QueryPatient里只需要db = DB(),不再关心连接参数从哪来。配置骨架到这里就完整了,下面进入 AI 客户端和验证环节。

5. 接入 AI 辅助:统一 Key 调用与增删改查验证

配置就绪后,写一个统一的 AI 客户端,所有 AI 功能都走它。这样 Key 只在一处使用,换模型只改settings.json。

# ai/client.py import requests from core.config_loader import ConfigLoader class AIClient: def __init__(self): cfg = ConfigLoader().taotoken self.base_url = cfg["base_url"].rstrip("/") self.api_key = cfg["api_key"] self.model = cfg["default_model"] self.timeout = (cfg["connect_timeout"], cfg["read_timeout"]) self.max_retries = cfg["max_retries"] self.params = ConfigLoader().model_params() def chat(self, prompt, system=None): url = f"{self.base_url}/v1/chat/completions" headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", } messages = [] if system: messages.append({"role": "system", "content": system}) messages.append({"role": "user", "content": prompt}) payload = { "model": self.model, "messages": messages, "temperature": self.params["temperature"], "max_tokens": self.params["max_tokens"], "top_p": self.params["top_p"], } last_err = None for _ in range(self.max_retries + 1): try: resp = requests.post(url, headers=headers, json=payload, timeout=self.timeout) resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"] except Exception as e: last_err = e raise RuntimeError(f"AI 调用失败: {last_err}")

现在把 AI 辅助接到病人登记流程里。原来的RecordPatient._confirm()只做非空校验,现在加一层字段纠错:把姓名、出生日期、性别丢给模型,让它返回规范化后的 JSON。

# ui/record_patient.py import json import tkinter as tk from tkinter import ttk, messagebox from core.db import DB from core.config_loader import ConfigLoader from ai.client import AIClient class RecordPatient: def __init__(self): self.root = tk.Tk() self.root.title("病人登记") self.root.geometry("300x250") self.cmb = ttk.Combobox(self.root, width=10) self.cmb["values"] = ("男", "女") self.cmb.current(0) self.name_label = tk.Label(self.root, text="姓名: ") self.birthdate_label = tk.Label(self.root, text="出生日期: \n(yyyy-mm-dd)") self.sex_label = tk.Label(self.root, text="性别: ") self.input_name = tk.Entry(self.root, width=12) self.input_birthdate = tk.Entry(self.root, width=12) self.okk_button = tk.Button(self.root, text="登记", width=10, command=self._confirm) self._gui_arrang() def _gui_arrang(self): self.name_label.place(x=20, y=20) self.birthdate_label.place(x=20, y=80) self.sex_label.place(x=20, y=140) self.input_name.place(x=160, y=20) self.input_birthdate.place(x=160, y=80) self.cmb.place(x=160, y=140) self.okk_button.place(x=90, y=180) def _confirm(self): name = self.input_name.get().strip() birthdate = self.input_birthdate.get().strip() sex = self.cmb.get() if not (name and birthdate and sex): messagebox.showerror(message="有内容为空") return if ConfigLoader().ai_enabled("enable_field_validation"): name, birthdate, sex = self._ai_normalize(name, birthdate, sex) db = DB() cursor = db.cursor() sql = "INSERT INTO patient (name, birthday, sex) VALUES (%s, %s, %s)" cursor.execute(sql, (name, birthdate, sex)) db.commit() cursor.execute("SELECT MAX(id) FROM patient") new_id = cursor.fetchone()[0] db.close() messagebox.showinfo("注册成功", f"注册成功!,病人id为{new_id}") self.input_name.delete(0, "end") self.input_birthdate.delete(0, "end") def _ai_normalize(self, name, birthdate, sex): client = AIClient() prompt = ( f"请规范化以下病人信息,只返回 JSON,不要解释。" f"姓名:{name} 出生日期:{birthdate} 性别:{sex}。" f"日期格式必须是 yyyy-mm-dd,性别只能是 男 或 女。" ) try: raw = client.chat(prompt, system="你是数据规范化助手,只输出 JSON。") data = json.loads(raw) return data.get("name", name), data.get("birthdate", birthdate), data.get("sex", sex) except Exception: return name, birthdate, sex

注意 SQL 从原来的字符串拼接改成了参数化%s,这是顺手修掉的一个注入风险。AI 规范化失败时回退到原始值,不阻塞登记流程。

启动验证分三步。第一步,确认环境变量已注入:

export TAOTOKEN_API_KEY="你的Key" export DB_PASSWORD="你的数据库密码" python -c "from core.config_loader import ConfigLoader; c=ConfigLoader(); print(c.taotoken['base_url']); print(c.db['host'])"

预期输出是https://taotoken.net/api和你的数据库地址,说明占位符替换成功。

第二步,单独验证 AI 通道:

python -c " from ai.client import AIClient c = AIClient() print(c.chat('返回 JSON: {\"ok\": true}', system='只输出 JSON')) "

如果返回类似{"ok": true}的内容,说明 Key 和通道都正常。如果报 401,检查 Key 是否复制完整;如果超时,检查网络和read_timeout设置。

第三步,跑通增删改查。启动主程序python main.py,依次做四个动作:登记一个新病人,观察是否弹出“注册成功”并返回 id;用查询窗口输入该 id,确认姓名、生日、性别显示正确;在管理中心修改该病人信息,重新查询确认更新生效;删除该记录,再查询确认返回“未查询到记录”。四个动作都通过,说明配置骨架和 AI 辅助层已经正确接入。

6. 本篇常见错排查

接入过程中最容易卡住的几个点,我按出现频率排一下。

第一个是tomllib导入失败。如果你用的是 Python 3.10 或更早版本,import tomllib会直接报ModuleNotFoundError。解决办法是pip install tomli,然后把import tomllib改成import tomli as tomllib。这个错误在启动阶段就会暴露,比较好定位。

第二个是环境变量没生效导致 Key 为空。表现是 AI 调用返回 401 或提示api_key为空。排查方法是打印ConfigLoader().taotoken['api_key']的前四位,确认不是空字符串。注意export只在当前终端会话有效,如果你用 IDE 运行,需要在运行配置里单独设置环境变量。

第三个是数据库连接超时。pymssql连接 SQL Server 时,如果host写了主机名而不是 IP,本地 DNS 解析可能很慢。建议config.toml里直接写127.0.0.1。另外timeout设太小会在网络抖动时误报,本地开发设 5 秒比较合适。

第四个是 AI 返回内容不是纯 JSON。模型有时会在 JSON 外面包一层 ```json 代码块,导致json.loads失败。稳妥做法是在_ai_normalize里先做一次清洗,去掉首尾的代码块标记再解析。我在ai/client.py里没有强制清洗,是因为不同模型行为不同,建议你在业务层按实际返回处理。

第五个是 Tkinter 多窗口导致主循环冲突。原代码里每个类都tkinter.Tk(),多个窗口同时存在时mainloop行为会异常。建议改成tk.Toplevel()挂到主窗口下,或者用单主窗口 + Frame 切换的方式。这个不影响配置验证,但会影响实际使用体验。

第六个是 SQL 参数化后%s和?混用。pymssql用%s,sqlite3用?,如果你中途换数据库驱动,记得同步改占位符。配置骨架里driver字段就是为这个预留的,可以在DB类里根据driver分支处理。

排查顺序建议从配置读取开始,再到通道连通性,最后到业务逻辑。大部分问题在前两步就能定位,不用一上来就怀疑 AI 调用代码。

7. 下一步:把配置骨架用到真实开发流

配置骨架跑通之后,你可以按自己的节奏扩展。如果接下来要长期做编码类任务,比如自动生成病历模板、批量清洗病人数据、写单元测试,可以看看 Coding Plan https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,它更适合持续性的开发场景。如果只是想先验证模型返回质量,模型对话页 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat&utm_campaign=rewrite 可以直接试。接入过程中遇到 Key 或通道问题,API Keys 管理页 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 和接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 是最快的排查入口。

最后留一个实用技巧:把config.toml和settings.json的示例文件命名为config.example.toml和settings.example.json提交到仓库,真实文件加入.gitignore。新人拉下来只需要复制示例、填入自己的环境变量,五分钟就能跑起来。这个习惯在多人协作的本地开发场景里,比任何文档都管用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询