📊 中华诗词知识库 · 第四章:Web与AI智能化设计

Knowledge Base of Chinese Poetry (KBCP) — Chapter 4: Web & AI

🌟GitHub 开源地址:https://github.com/liang1057/Knowledge-Base-of-Chinese-Poetry
🌟 如果资源对你有帮助,欢迎 Star 支持!
📥 JSON数据下载https://download.csdn.net/download/sdust_dx/92826598


🎯 前言

前三章完成了数据收集、清洗与 Schema 设计。本章将在此基础上,构建一套完整的 Web 可视化系统,并引入 大语言模型(LLM) 实现诗词的智能化分析与自动标注。

本章的 Web 系统围绕 Schema 展开——前端展示诗词的文学属性,后端通过 LLM 自动为 6.2 万首诗词打上主题、风格、情感等多维度标签。

本章的核心目标是:从"结构化数据"到"可视化交互",再到"AI 智能增强"的完整链路实现


一、Web 开发:用大模型辅助,但不止于大模型

1.1 为什么需要大模型

首先,从业内的AI经验来看,Web开发是非常适合大模型的一个工作:Web 开发是一个"细节密集、样板重复"的工程。 从页面布局、CSS 样式到 API 接口、数据库查询,大量代码属于"知道怎么做,但写起来费时"的机械劳动。对于个人开发者或小团队,这种重复性工作会严重挤压核心功能的开发时间。
其次,对我个人来说,我知道Web开发的大概步骤,略懂Web的Python开发和HTML语法,但是个人的技术储备不足以完成开发 ,AI模型则是让我具备了六边形战士的能力

大模型的核心价值在于将"写代码"转化为"描述需求"。不再需要手写 jQuery 事件绑定、Flask 路由注册或 SQLAlchemy 关系定义,而是直接用自然语言描述意图——“左侧树形导航点击诗人后异步加载诗词列表”——模型即可生成可运行的代码骨架。这相当于把开发效率从"逐行编码"提升到"逐块组装"。

更关键的是跨栈整合能力。本项目涉及前端(jsTree + Bootstrap)、后端(Flask + SQLAlchemy)、数据库(SQLite 外键约束)和 AI(LLM Provider 抽象层)四个技术栈。大模型能够同时理解这些栈的交互逻辑,生成前后端联调的完整代码,避免"前端写完了,发现后端接口格式不对"的返工。

但大模型不是替代开发者思考,而是加速从"想法"到"可验证原型"的跨越。你仍然需要理解生成的代码、判断架构合理性、处理边界情况。大模型负责"写出来",你负责"想明白"——这才是"用大模型辅助,但不止于大模型"的本意。

1.2 需要什么样的 Web 系统?

第三章的 Schema 设计解决了"数据如何存"的问题,但 6.2 万首诗词躺在 SQLite 数据库里,对普通人而言毫无意义。真正要读诗词,需要一个网页作为载体:

  • 浏览层:按朝代-诗人-诗词的树形导航,快速定位作品
  • 编辑层:管理员可修正正文、赏析、翻译,维护数据质量
  • 标签层:为每首诗打上主题、风格、情感等标签,支撑后续 RAG 检索
  • 管理层:朝代、作者、受控词表的 CRUD,保证数据一致性

1.3 技术选型思路

本项目的技术栈选择遵循"轻量、可控、易部署"原则:

层级 技术 选择理由
后端 Python 3 + Flask + Flask-SQLAlchemy 轻量框架,ORM 直接映射第三章的 Schema,开发效率高
前端 HTML/CSS/JS + jQuery + Bootstrap 5 无需构建工具,直接引用 CDN,降低部署门槛
树控件 jsTree 支持异步加载、搜索、多选,完美适配朝代-诗人层级
数据库 SQLite 第三章已设计好的 Schema,FK 约束 + 复合主键,单文件部署
AI 层 Ollama / DeepSeek / 智谱 API 本地+云端双模式,零成本起步

💡 为什么不选 Vue/React + Django?
本项目面向个人研究者和小型团队,Flask + jQuery 的组合足够支撑功能,
且无需配置 Node.js 构建环境,树莓派上也能直接运行(AI要选用云端实现)。


二、系统架构与项目结构

2.1 整体架构

┌─────────────────────────────────────────────────────────────┐
│                        用户层                               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │ 诗词浏览  │  │ 标签管理  │  │ 后台管理  │  │ AI 打标  │   │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘   │
├─────────────────────────────────────────────────────────────┤
│                        API 层 (Flask)                       │
│  /api/dynasties  /api/poems  /api/poem/save  /api/search   │
├─────────────────────────────────────────────────────────────┤
│                        数据层 (SQLite)                      │
│  poem  │  author  │  dynasty  │  vocab  │  poem_tag       │
├─────────────────────────────────────────────────────────────┤
│                        AI 层                                │
│  KBCP_AutoTag.py → KBCP_LLM_Provider.py                   │
│  (Ollama / DeepSeek / 智谱)                                │
└─────────────────────────────────────────────────────────────┘

2.2 项目结构

Prj_Poetry_China/
├── dataset/
│   └── kbcp.db                    # 数据库文件(第三章 Schema v2)
├── data/
│   ├── Poetry_China_all.json       # 原始诗词数据
│   ├── Dynasty.json                # 朝代数据
│   └── Author.json                 # 诗人数据
├── KBCP_RAG_Poem_Schema.py        # Schema 定义(第三章)
├── KBCP_RAG_Poetry_DB.py          # 数据库构建脚本(第三章)
├── KBCP_web/                      # Web 应用(本章核心)
│   ├── KBCP_app.py                # Flask 主程序
│   ├── KBCP_auth.py               # 认证模块(session + 密码哈希)
│   ├── KBCP_models.py             # SQLAlchemy ORM 模型(映射第三章 Schema)
│   ├── config.py                  # 配置文件
│   ├── templates/                 # Jinja2 模板
│   │   ├── KBCP_base.html         # 基础模板(导航栏 + 布局框架)
│   │   ├── KBCP_index.html        # 首页(四栏布局:树形导航 + 诗词列表 + 详情 + 标签)
│   │   ├── KBCP_admin.html        # 管理后台(Tab 页:朝代/作者/诗词/词表/用户)
│   │   ├── KBCP_admin_modals.html # 管理 Modal(添加/编辑弹窗)
│   │   └── KBCP_login.html        # 登录页
│   └── static/
│       ├── css/
│       │   └── KBCP_style.css     # 自定义样式(诗词楷体展示、标签配色)
│       └── js/
│           ├── KBCP_tree.js       # jsTree 异步加载 + 点击事件
│           ├── KBCP_editor.js     # 诗词编辑器 + 标签增删
│           └── KBCP_admin.js      # 管理后台 CRUD 操作
├── KBCP_AutoTag.py                # AI 自动打标主程序(本章重点)
├── KBCP_LLM_Provider.py           # LLM 提供者抽象层
├── KBCP_LLM_config.ini            # LLM 配置文件(含 API Key,已加入 .gitignore)
└── KBCP_LLM_config.example.ini    # 配置模板(无 Key,可提交 Git)

三、前端设计:四栏布局与交互逻辑

3.1 页面布局

首页采用经典的 四栏布局,左侧树形导航、中间诗词列表、右侧详情与标签:

┌──────────────────────────────────────────────────────────────────┐
│  [导航栏]  诗词库 v2  |  首页  |  管理  |  搜索  |  [用户名/退出] │
├──────────┬──────────┬──────────────────────┬────────────────────┤
│  左一栏   │  左二栏   │      左三栏          │      左四栏        │
│ 朝代-诗人 │ 诗词列表  │  标题 / 作者         │    诗词标签        │
│  树形导航 │          │  正文(可编辑)      │   [+增加标签]       │
│          │          │  赏析(可编辑)      │   [清除标签]        │
│  先秦(4) │  静夜思   │  翻译(可编辑)      │   # 体裁            │
│  唐(2475)│  望庐山   │  [保存修改]          │   诗 [×]           │
│   │─李白  │  瀑布    │                     │   # 主题            │
│   │─杜甫  │  将进酒   │                     │   思乡 [×] 月夜 [×] │
│  宋(1497)│  ...     │                     │   # 情感            │
│  ...     │          │                     │   悲伤 [×]          │
├──────────┴──────────┴──────────────────────┴────────────────────┤
│  统计栏:  **朝代 | xxx 诗人 | xxxxx 诗词 | xxx 标签           │
└──────────────────────────────────────────────────────────────────┘

3.2 交互设计要点

交互场景 实现方式 说明
朝代展开 jsTree 异步加载 点击"唐",AJAX 请求 /api/authors/T,返回李白、杜甫等诗人列表
诗人点击 加载诗词列表 点击"李白",中间栏显示其全部诗词标题
诗词点击 详情 + 标签联动 点击"静夜思",右三栏显示正文/赏析/翻译,右四栏显示所有标签
标签删除 即时反馈 点击标签旁的 [×],AJAX 删除,无需刷新页面
标签添加 Modal 多选 弹出标签选择器,按类别(主题/风格/情感等)分组,支持批量勾选
正文编辑 ContentEditable 管理员模式下,正文、赏析、翻译可直接编辑,点击保存后 AJAX 提交

四、后端设计:Flask API 与权限控制

4.1 核心 API 设计

API 分为三类:公开接口(无需登录)、管理接口(需管理员权限)、超级管理员接口

类别 方法 路由 说明
公开 GET /api/dynasties 获取朝代树一级节点(含诗词数量)
公开 GET /api/authors/<dynasty_id> 获取某朝代诗人列表(含诗词数量)
公开 GET /api/poems/<author_id> 获取某诗人诗词列表
公开 GET /api/poem/detail?poem_id= 获取诗词详情(含标签)
公开 GET /api/search?q= 全文搜索诗词(标题/作者/正文)
公开 GET /api/stats 统计数据(朝代/诗人/诗词/标签数)
管理 POST /api/poem/save 保存诗词编辑(正文/赏析/翻译)
管理 POST /api/poem/tag/add 批量添加标签
管理 POST /api/poem/tag/remove 移除单个标签
管理 POST /api/author/add 添加作者
管理 POST /api/author/delete/<author_id> 删除作者(级联删除其所有诗词)
管理 POST /api/vocab/add 添加受控词条
超级管理 POST /api/user/add 添加管理员账号

4.2 权限控制实现

采用 Session + 装饰器 的轻量方案,这个内容不论是Deepseek还是Kimi、智谱、GPT、豆包等待,都能实现

4.3 关键后端代码:ORM 映射第三章 Schema

KBCP_models.py 直接映射第三章设计的五张核心表:

# 具体实现略了

db = SQLAlchemy()

class Dynasty(db.Model):
    __tablename__ = 'dynasty'
    
class Author(db.Model):
    __tablename__ = 'author'

class Poem(db.Model):
    __tablename__ = 'poem'

class Vocab(db.Model):
    __tablename__ = 'vocab'

class PoemTag(db.Model):
    __tablename__ = 'poem_tag'

💡 设计要点PoemTag 作为中间表,实现了 poemvocab 的多对多关系。这与第三章的 Schema 设计完全一致,保证了标签的标准化——所有标签必须从 vocab 表中选取,杜绝自由文本标签。


五、智能诗词打标签:LLM 的工程化实践

5.1 为什么需要 AI 打标?

6.2 万首诗词,人工标注不现实。但标签质量直接决定后续 RAG 检索的效果。我的方案是:

  • 受控词表约束:LLM 只能从 vocab 表中选择标签,不能自创
  • 多维度标注:主题、风格、情感、意象、季节、节令,每首诗最多 3 个标签/类别
  • 增量更新:支持断点续传,已分析的诗不会重复处理
  • 多模型后端:本地 Ollama(免费)+ 云端 API(快速),按需切换

5.2 架构设计

KBCP_AutoTag.py (分析主控)
  ├── 读取 poem 表(跳过已分析)
  ├── 读取 vocab 表(获取受控词表)
  ├── 构建 Prompt(诗词 + 可用标签列表)
  ├── 调用 KBCP_LLM_Provider.py
  │    ├── OllamaProvider       (本地: http://localhost:11434)
  │    ├── DeepSeekProvider     (云端: api.deepseek.com)
  │    └── ZhipuProvider        (云端: open.bigmodel.cn)
  ├── 解析 LLM 返回的 JSON
  ├── 匹配 vocab_id → 写入 poem_tag 表
  └── 写入 auto_tag_log(断点续传)

5.3 Prompt 工程:为什么用 XML 标签?

在 Prompt 设计中,采用了 XML 标签结构化 的方式。这与传统纯文本 Prompt 相比,有显著优势:

根据 Anthropic 官方《Prompt Engineering Guide》的推荐,XML 标签能利用 LLM 在预训练阶段阅读大量代码(HTML/XML)的特性,强制给 Token 加上"路标"和"围栏",从而把概率猜测变成确定性执行。

我的 Prompt 模板

你是一位精通中华诗词的分析专家。分析下面这首诗,为每个类别
从可用标签中选择最合适的标签(每个类别最多选3个)。

要求:
1. 只输出 JSON 格式,不要输出任何其他内容
2. 仅从下方"可用标签"中选择,不要自创标签
3. 类别名称使用英文
4. 如果某类别无法确定,省略该字段

输出示例:
{"theme":"思乡","style":"清新","emotion":"哀愁","imagery":"月","season":"秋"}

可用标签:
【theme】思乡、送别、边塞、怀古、山水、田园……
【style】豪放、婉约、沉郁、清新、雄浑……
……

诗题:静夜思
作者:李白
诗歌正文:
床前明月光
疑是地上霜
……

5.4 LLM 结果解析:先提取 JSON,再清洗

许多开发者的习惯是"先清洗思考链,再提取 JSON",但这容易误删 JSON 中的方括号。采用 “先定位 JSON,再解析” 的策略:

import re
import json

def parse_llm_response(response_text, vocab_dict):
    """解析 LLM 返回的文本,提取 JSON 标签结果"""
    # 策略:先定位 JSON 对象(防止方括号被误当作思考链清除)
    
    # 1. 直接定位 JSON 对象
    json_match = re.search(r'\{.*\}', response_text, re.DOTALL)
    if not json_match:
        return None, "未找到 JSON 对象"
    
    json_str = json_match.group()
    
    # 2. 自动修复常见格式问题
    json_str = json_str.replace("'", '"')           # 单引号转双引号
    json_str = re.sub(r',\s*\}', '}', json_str)     # 去除末尾逗号
    json_str = re.sub(r',\s*\]', ']', json_str)     # 去除数组末尾逗号
    
    # 3. 解析 JSON
    try:
        result = json.loads(json_str)
    except json.JSONDecodeError as e:
        return None, f"JSON 解析失败: {e}"
    
    # 4. 标签匹配:精确优先 → 模糊匹配兜底
    tags = {}
    for cat in ['theme', 'style', 'emotion', 'imagery', 'season', 'festival']:
        label = result.get(cat, "")
        if not label:
            continue
            
        # 精确匹配
        if label in vocab_dict.get(cat, {}):
            tags[cat] = label
        else:
            # 模糊匹配:包含关系
            for vocab_label in vocab_dict.get(cat, {}):
                if label in vocab_label or vocab_label in label:
                    tags[cat] = vocab_label
                    break
    
    return tags, "ok"

5.5 多模型提供者设计

通过抽象层 KBCP_LLM_Provider.py,实现无缝切换:

具体的代码可以看Github。

5.7 性能与成本对比

提供者 模型 每首耗时 1万首耗时 成本 适用场景
Ollama 本地 deepseek-r1:8b 5-15s 14-42h 免费 本地开发、数据敏感
DeepSeek API deepseek-chat 1-3s 3-8h ~¥0.5/百万token 批量标注、快速验证
智谱 GLM API glm-4-flash 1-3s 3-8h ~¥0.5/百万token 国内稳定、薅羊毛

💡 实际经验:智谱 GLM-4-Flash 对中文诗词的理解能力出色,且新用户有免费额度,6.2 万首诗词的标注成本可控制在极低水平。


下一章,将会介绍诗词的Web可视化的效果和初步运行的一些统计。


🌟 如果本文对你有帮助,欢迎 Star 支持!

GitHub 开源地址:https://github.com/liang1057/Knowledge-Base-of-Chinese-Poetry

CSDN 专栏:中华诗词知识库(KBCP)系列文章

📧 交流邮箱:liang1057@163.com

更多推荐