毕业设计做古诗词方向的Python项目,这两年确实是个大热门。知识图谱、可视化、情感分析、智能问答、AI写诗,五个关键词一组合,就是一个既能展示技术广度,又自带文化底蕴的完整系统。这篇博文我就以这个题目为蓝本,把整个项目的设计思路、技术选型、核心实现和排坑经验完整拆开讲一遍,给打算做类似方向的同学一个可以直接参考的落地路径。
1. 项目整体设计与技术选型思路
1.1 核心需求解析:这个题目到底要做什么
先把标题拆开看,表面上是一长串技术名词,实际归纳下来是五条明确的功能线:
- 知识图谱构建:把古诗词领域的概念(诗人、作品、朝代、词牌、意象)提取出来,组成图结构
- 可视化展示:把图谱关系、情感分布、词频统计等内容用交互图表呈现
- 情感分析:对诗词文本进行情感倾向分类,支持按诗人、按朝代聚合分析
- 智能问答:用户用自然语言提问,系统返回答案,比如"李白的代表作有哪些""含'月'的诗句有哪些"
- AI自动写诗:输入主题或首句,生成符合格律的古体诗
这五条线不是各自独立的,而是围绕同一个诗词数据集形成一条完整链路:数据处理 → 图谱存储 → 可视化/问答/写诗 → Web展示。很多同学做毕业设计容易犯一个毛病,就是功能之间互相孤立,答辩时被问"这几个模块之间有什么关系"就答不上来。这个题目天然规避了这个问题,因为知识图谱是所有上层应用的公共数据底座。
1.2 技术栈选型:为什么是Python全家桶
整体技术栈我推荐这样搭配:
| 模块 | 推荐方案 | 备选方案 |
|---|---|---|
| 数据存储 | Neo4j(图数据库) | MySQL + 关系表 |
| 后端框架 | Flask | Django |
| 前端框架 | Vue + ECharts/pyecharts | 纯HTML + Bootstrap |
| NLP处理 | Jieba + 自建词典 | HanLP |
| 情感分析 | 情感词典 + BiLSTM | SnowNLP |
| AI写诗 | 大模型API或微调小模型 | Transformer自训练 |
| 开发环境 | Python 3.8+ | Anaconda管理 |
选Neo4j的理由很直接:诗词领域的核心价值就在于"关系"。诗人写了哪些诗、用了哪些意象、属于哪个朝代、和哪些诗人有交集,这些天然就是图结构。如果用MySQL存,查询"和李白同朝代的诗人有哪些"这种问题要写多表Join,而Neo4j用Cypher一句MATCH就能搞定,开发效率和答辩演示效果都强很多。
后端用Flask而不是Django,是因为这个项目属于中小规模,Flask轻量灵活、路由写法简单,不需要Django那套完整的MVC约束。前端可视化选pyecharts而不是纯ECharts,是因为pyecharts可以在Python端直接生成图表配置,不用手动写大量JavaScript,对非前端专业的同学友好得多。
1.3 系统架构与功能模块划分
整个系统采用经典的三层架构:
数据层包括原始语料库、清洗后的结构化数据、Neo4j图数据、模型文件。业务层拆成五个服务模块:图谱服务负责实体关系查询,可视化服务负责数据聚合与图表生成,问答服务负责任务解析与答案检索,情感服务负责文本分类,写诗服务负责文本生成。表现层就是Web前端页面,包含图谱浏览页、统计分析页、问答交互页、写诗体验页。
这里有个设计细节需要注意:五个功能模块不要做成五个独立的页面,最好集成在一个统一的后台系统里,左侧导航切换。答辩演示时流畅地切换模块,比单页demo显得完整很多。
2. 知识图谱构建:从原始文本到图结构
2.1 数据获取与清洗:这一步决定了上限
诗词数据的质量直接决定整个项目的效果。公开数据集不少,常见的有全唐诗、全宋词的整理版本,但网上流传的数据集质量参差不齐,常见问题包括:繁体字未转换、标点混乱、作者名字不同写法("李白"和"李太白"并存)、重复收录。
拿到原始数据后,我按以下流程清洗:
- 统一简体:用OpenCC库做繁简转换
- 正则去噪:去掉注释标记、校勘符号、空白行
- 字段规范化:统一作者名字,合并同一首诗的多个版本
- 朝代补全:手动维护一个诗人-朝代映射表
- 去重去空:根据"标题+正文"拼接做MD5去重
清洗完的数据结构大概是这样的JSON格式:
{ "title": "静夜思", "author": "李白", "dynasty": "唐", "content": "床前明月光,疑是地上霜。举头望明月,低头思故乡。", "tags": ["思乡", "月亮", "夜晚"] }清洗这步别省,也别过度自动化。我实测的经验是:90%的清洗可以脚本搞定,剩下10%比如同名诗人区分、生僻字处理,必须靠人工校对。建议准备一个Excel表,把自动清洗后仍有疑问的记录导出来人工处理。
2.2 实体关系设计:图谱的"骨架"怎么搭
知识图谱的schema设计是核心,设计得合理,后续所有查询都顺手;设计得混乱,写Cypher时到处补逻辑。
我的设计包含四类实体节点和五类关系:
- 诗人节点:属性有姓名、朝代、字号、生平简介、代表作数量
- 诗作节点:属性有标题、正文、体裁(五言/七言/律诗/绝句)、词牌名、创作年代
- 朝代节点:属性有朝代名、起止年份、诗词总量
- 意象节点:属性有意象词、象征含义
关系设计:
- (诗人)-[创作]->(诗作)
- (诗作)-[属于]->(朝代)
- (诗人)-[属于]->(朝代)
- (诗作)-[使用]->(意象)
- (诗人)-[同朝]->(诗人)(可推导的关系,实际按需物化)
意象节点是知识图谱的亮点。用Jieba对诗词正文做分词后,结合一个手工整理的"诗词意象词典"(月、酒、花、柳、风、雪、雁、舟等上百年词),把诗句中的意象实体提取出来建立连接。答辩时直接演示"包含'月'这个意象的所有诗作"的图谱查询,效果非常直观。
2.3 Neo4j数据导入:批量写入的两种姿势
数据量大概在几千首诗、几百个诗人、上百个意象这个规模,用Python驱动逐条写入完全来得及,但更推荐用批量方式。
方式一:Cypher LOAD CSV
把实体和关系分别导出为CSV,然后用Neo4j自带的LOAD CSV语句导入。这种方式最简单,Neo4j Browser里一条命令搞定:
LOAD CSV WITH HEADERS FROM 'file:///poets.csv' AS row CREATE (p:Poet {name: row.name, dynasty: row.dynasty, intro: row.intro});方式二:py2neo批量提交
如果需要在导入时做去重、合并、动态判断关系,用Python的py2neo库更灵活。核心技巧是使用事务分批提交,不要逐条auto-commit:
from py2neo import Graph, Node, Relationship graph = Graph("bolt://localhost:7687", auth=("neo4j", "password")) def batch_create(nodes_data, batch_size=500): tx = graph.begin() for i, data in enumerate(nodes_data): node = Node("Poem", **data) tx.create(node) if i % batch_size == 0: tx.commit() tx = graph.begin() tx.commit()这个批量提交的小细节很多人不注意,几千条数据逐条提交会慢到怀疑人生,而且中途断了没法回滚。用事务分批后,速度提升十倍以上。
导入完成后的验证也很重要。跑几条计数查询确认节点和关系数量符合预期:
MATCH (n:Poet) RETURN count(n); MATCH (n:Poem)-[r:使用]->(n2:Imagery) RETURN count(r);3. 可视化与情感分析模块实现
3.1 图谱可视化:让关系"看得见"
知识图谱的价值在于展示,所以可视化这块要花心思。我用的方案是Neo4j Browser自带的图形展示做开发调试,前端页面用pyecharts的Graph图做用户展示。
诗人关系图谱是核心视图。把诗人作为节点,同朝代的诗人用"同朝"关系连接,节点大小按作品数量映射,颜色按朝代区分。ECharts的力导向布局会自动把关系紧密的节点聚在一起,滚动缩放、拖拽节点这些交互都是自带的,不需要额外开发。
诗句词云是另一个很出效果的图表。把全库诗句分词后统计词频,生成词云图,高频词如"月""风""花""人"一眼可见。词云可以用pyecharts的WordCloud图,自定义一个古风背景色和字体,视觉上很讨喜。
还有朝代诗词量趋势图:以朝代为横轴,诗作数量为纵轴画柱状图,配合曲线图展示唐诗宋词的兴衰。这种图虽然简单,但放在系统首页做数据总览,能快速让评委建立"这个系统有整体观"的印象。
3.2 情感分析方案对比:词典法还是模型法
古诗词情感分析比普通文本情感分析难,原因有两个:一是文言文表达含蓄,现代情感词典覆盖不了;二是诗词的情感往往多层交织,比如"感时花溅泪"表面写景、实际写悲。
我建议做双轨方案,答辩时能讲出深度:
第一轨:基于情感词典的规则方法。构建一个"古诗词情感词典",包含约2000个带有情感极性的词汇,标注悲、喜、愁、思、豪、闲六大类。对每首诗做分词匹配,统计各类情感词的数量占比,得分最高的一类就是该诗的主导情感。这个方法白盒可解释,答辩时能明确说出判断依据。
第二轨:基于深度学习的分类模型。用BiLSTM或TextCNN对诗词文本做七分类(六类情感加一个中性)。数据标注是个大工程,可以先用词典法自动打标生成训练集,再人工抽检修正一批,大概2000首标注数据就能训练出一个效果尚可的模型。
对比一下:词典法准确率大概在70%左右,胜在可解释、无需训练;深度模型准确率能到85%,但需要标注数据和训练时间。我的建议是系统里两个都做,页面提供切换对比。答辩时这个"规则与深度模型对比"的设计本身就是加分项。
3.3 情感分析结果的应用落地
情感分析不能只是算出个标签就完事,要跟图谱和可视化联动起来。我做了三个维度的分析展示:
情感分布总览:饼图展示全库六类情感占比,观察古诗词整体情感倾向。实际跑出来的数据通常"悲""思"类占比偏高,这符合古诗词"诗穷而后工"的特点,也是答辩时可以向评委讲的文化背景。
诗人情感画像:每位诗人的作品情感分布做成雷达图。李白和杜甫的画像差异非常明显,这类对比演示效果极好。查询语句也很简单:
MATCH (p:Poet {name:'李白'})-[:创作]->(poem:Poem) RETURN poem.emotion, count(poem) ORDER BY count(poem) DESC;朝代情感演变趋势:把"朝代+情感类别+数量"三个维度做成堆叠柱状图,能看到不同朝代的主流情感变迁。比如唐代豪迈类占比高,宋代思乡怀古类突出。这个图做出来,文化层面的解读空间很大,答辩时可以从历史背景展开讲,非常加分。
4. 智能问答与AI写诗系统实现
4.1 问答系统设计:规则模板起步,检索增强兜底
小规模领域的问答系统,不建议一上来就上大模型RAG,成本高、可控性差。我的做法是"模板匹配 + 实体识别 + Cypher查询"三层结构。
第一层:意图分类。用规则加关键词匹配判断用户问题类型,常见意图有:
| 意图 | 示例问题 | 对应查询 |
|---|---|---|
| 查询某诗人作品 | 李白写了哪些诗 | MATCH (p:Poet {name:'李白'})-[:创作]->(poem) RETURN poem.title |
| 查询诗句出处 | "床前明月光"是谁写的 | MATCH (poem:Poem {content: contains}) RETURN poem.author |
| 查询意象相关诗 | 含"月"的诗句有哪些 | MATCH (poem)-[:使用]->(i:Imagery {name:'月'}) RETURN poem |
| 查询同朝代诗人 | 唐代有哪些著名诗人 | MATCH (p:Poet)-[:属于]->(d:Dynasty {name:'唐'}) RETURN p.name |
第二层:实体抽取。用Jieba分词加自定义词典,从问题里抽出诗人名、朝代名、意象词、诗句片段。这里的关键是自定义词典要覆盖常见别名,"李白"和"李太白"都要能识别。
第三层:模板生成Cypher。根据意图和抽取结果拼装查询语句,执行后把结果格式化输出。
对于模糊问题,比如"关于思乡的诗有哪些",走一个简单的检索兜底:从情感分析结果里筛"思"类情感的诗,或者从标签字段匹配"思乡"关键词。这种方案在限定领域内效果很好,实测常见问题回答准确率能到90%以上。
4.2 AI写诗模块:大模型微调与提示词工程
AI写诗是这个项目的亮点,也是最容易踩坑的地方。我试过两条路,都讲讲亲身感受。
路线一:微调开源大模型。用中文诗歌语料对小型生成模型做指令微调,做得好效果惊艳,但成本和门槛都高。光是要准备训练数据、租GPU、调参,就够忙活一个月。而且小模型容易生成重复内容和乱格律,参数量不够就是不够。
路线二:调用现成大模型API,配合提示词工程。这是性价比最高的方案。核心思路是用精心设计的提示词约束输出格式,比如:
请根据主题"送别"创作一首七言绝句。要求: 1. 严格遵循七言绝句的平仄和押韵规则 2. 每句七个字,共四句 3. 诗句意境含蓄,避免直白口语化 4. 输出前标注每句的韵脚我实测下来的经验是:提示词里明确给出体裁格式、主题词、押韵要求,输出质量会显著提升。如果想控制风格,可以加一句"模仿王维的山水田园风格",效果也不错。
还应该加一个"写诗历史"功能,把用户输入的主题和生成结果存入本地SQLite,方便回看和演示。这个功能虽小,但对毕业设计来说体现了工程完整性。
4.3 前后端整合:Flask + Vue的联调细节
后端Flask提供RESTful API,前端Vue通过axios调用。几个接口设计示例:
@app.route('/api/qa', methods=['POST']) def qa(): question = request.json.get('question') intent = parse_intent(question) entities = extract_entities(question) answer = execute_qa(intent, entities) return jsonify({'answer': answer}) @app.route('/api/poem', methods=['POST']) def generate_poem(): topic = request.json.get('topic') style = request.json.get('style', '五言绝句') poem = llm_generate(topic, style) return jsonify({'poem': poem}) @app.route('/api/graph/poet', methods=['GET']) def poet_graph(): data = query_poet_network() return jsonify(data)前后端联调时最容易忽略的一个问题是CORS跨域。Flask后端需要设置CORS头,否则前端请求会被浏览器拦截。用flask-cors库一行代码就能解决:
from flask_cors import CORS CORS(app)这个坑我当年踩了好几个小时才反应过来,希望你们别走弯路。
5. 常见问题与排坑实录
5.1 Neo4j环境与导入的坑
版本兼容问题是第一个坑。Neo4j 4.x和5.x的Python驱动接口差异很大,py2neo库对Neo4j 5.x的支持并不完善,建议直接用官方neo4j驱动库。如果坚持用py2neo,注意锁定Neo4j 4.x版本配合使用。
中文乱码是第二个坑。Neo4j导入中文数据时,如果CSV文件编码不是UTF-8,导入后全是乱码。处理办法是CSV保存时明确选UTF-8 with BOM,或者导入前在Python里统一转码:
with open('poems.csv', 'r', encoding='utf-8-sig') as f: reader = csv.DictReader(f)第三个坑是连接池超时。Neo4j默认连接空闲久了会自动断开,后端服务跑一段时间后查询报错"Connection pool timeout"。解决办法是在cypher查询外层加重试机制,或者定时任务保持连接活跃。
5.2 情感分析与可视化展示的坑
Jieba分词对文言文的切分效果不稳定,比如"将进酒"会被切成"将"和"进酒"这种不合理结果。解决方法是维护一份自定义词典,把常见诗词标题和专有名词加进去,同时设置Jieba的优先词模式。
可视化层最大的坑是pyecharts版本问题。pyecharts从1.x升级到2.x后接口变化很大,网上很多教程还是老写法,直接抄会报错。建议安装时锁定版本:pip install pyecharts==1.9.1,这个版本稳定、资料最多。图表渲染出现空白时,优先检查是不是数据里有NaN或None值,先做数据清洗再传图表。
情感分析还有个细节:词典的情感词要区分语境,同词在不同语境下情感不同。比如"东风"在"东风不与周郎便"里是中性,在"东风夜放花千树"里是喜庆。严格做词义消歧成本太高,我的妥协方案是情感词典只收歧义较小的词,同时通过多词加权而不是单个强情感词决定分类结果。
5.3 写诗与问答模块的坑
AI写诗最大的问题是长度失控。大模型API对中文古诗的生成容易超长,生成八句变成十二句。解决方法是提示词里明确"严格四句,每句七字",如果API支持max_tokens参数就设置为56(28个汉字加标点),从源头卡死长度。生成完还要在后端校验一次,不符合格式就重新生成。
问答模块的坑在于同义词处理。"诗仙""谪仙人"都是李白,用户可能用任何别名提问。我在自定义词典里把所有别名都映射到诗人主名,查询时先做实体归一化再拼Cypher,实测这个预处理能显著提高回答命中率。
6. 答辩演示与项目扩展建议
6.1 答辩演示的节奏设计
这个项目的演示流程我建议按"总-分-总"来排:
开场用首页数据总览展示项目规模和完成度,让评委建立整体印象。然后进入知识图谱可视化页面,演示一个典型查询(比如"苏轼的社交关系网络"),边操作边讲解图谱schema的设计思路。接着切到情感分析模块,展示诗人情感画像对比图,把技术结果和文化解读结合起来讲。再演示问答系统的几个高频问题,重点展示从自然语言到Cypher查询的转换过程。最后用AI写诗收尾,现场输入主题生成一首诗,效果很惊艳。
整体控制在10到12分钟,每个模块2到3分钟,留足时间给评委提问。
6.2 后续可以扩展的方向
如果做完基础功能还有余力,或者想在答辩里讲"后续展望",可以往这几个方向扩展:
- 把问答系统升级为大模型RAG架构,用向量数据库存储诗词片段,支持更自由的语义提问
- 增加OCR识别功能,支持上传古籍图片自动识别并入库
- 做诗人风格的机器学习分类,把"李白风格""杜甫风格"量化,进一步用于风格化写诗
- 引入知识图谱的图算法,比如PageRank找出"最有影响力的诗人",社区发现找出"风格相近的诗人群体"
我个人做完这个项目的体会是:知识图谱这个底座选对了,后面所有功能都能挂上去。整套系统技术栈覆盖面广,从数据处理到图数据库、从机器学习到前端可视化、从NLP到大模型应用,每一个模块都有可以深挖的亮点。答辩时不需要面面俱到,挑两三个自己真正跑通、真正理解的技术点讲透,比所有功能都浅尝辄止要有说服力得多。
最后分享一个小技巧:答辩前一天,一定把演示环境的网络断开、依赖装齐、数据导入好。我见过太多人栽在"昨天还能跑,今天环境坏了"这种低级失误上。项目做得好是一方面,稳定地演示出来才是最后那一哆嗦。