Python诗歌生成器:从NLP词库构建到规则引擎的创意编程实践
2026/8/18 2:46:59 网站建设 项目流程

1. 项目概述:从代码到诗意的跨越

“Python-Poem-Maker”,这个名字听起来就很有意思。它不是一个严肃的算法库,也不是一个复杂的Web框架,而是一个带着点浪漫和趣味色彩的项目。简单来说,这就是一个用Python来“写诗”的程序。但别误会,它可不是让你去写“Hello World”或者打印九九乘法表那种入门练习。这个项目的核心,在于探索如何让冰冷的代码逻辑,去模拟、生成甚至创作出具有美感和一定结构的文本——诗歌。

我最初接触这个想法,是源于对自然语言处理和创意编程的兴趣。市面上有很多教你怎么用Python做数据分析、爬虫或者自动化的教程,但很少有人系统地聊聊,怎么用这门语言去触碰一下“艺术”的边。Python-Poem-Maker恰恰填补了这个空白。它适合的人群很广:对于Python新手,这是一个绝佳的、有趣的综合练习项目,能串联起字符串处理、列表操作、文件读写、随机选择甚至一些简单的算法;对于有一定基础的开发者,它可以作为一个进入NLP(自然语言处理)和文本生成领域的敲门砖,理解词库构建、概率模型和生成规则;甚至对于纯粹的诗文爱好者,它也能提供一个全新的视角,看看AI是如何“理解”和“创作”诗歌的。

这个项目的价值,远不止于生成几行押韵的句子。它背后涉及的是语言模型、数据结构设计、美学规则的量化等一系列有趣的问题。你会思考:一首诗需要什么样的结构?五言还是七言?押韵的规则怎么用代码实现?如何让生成的句子不只是随机词的堆砌,而是有一定的意境连贯性?解决这些问题的过程,本身就是一次深刻的编程思维训练。接下来,我就把自己搭建一个Python诗歌生成器的完整思路、踩过的坑和最终实现方案,详细地分享给你。

2. 核心思路与架构设计

2.1 诗歌生成的基本原理拆解

在动手写代码之前,我们必须想清楚,一首诗(特别是中文古诗)是怎么被“制造”出来的。我们不能指望程序真的拥有情感和灵感,所以必须把创作过程分解成可计算的规则。经过分析和实践,我总结出几个核心要素:

  1. 词汇库:这是原料。程序需要知道哪些词可以用来写诗。我们需要按词性(名词、动词、形容词等)和主题(山水、情感、季节等)对词汇进行分类存储。
  2. 格律规则:这是模具。主要指平仄和押韵。对于入门项目,我们可以先从简化规则开始,比如只考虑句子的字数(五言、七言)和末尾字的押韵。平仄规则比较复杂,初期可以忽略或做极大简化。
  3. 生成算法:这是生产线。如何从词汇库中选取词语,按照格律规则组装成句子,再进一步组合成有意义的篇章?常见的思路有基于模板的填充、基于马尔可夫链的随机漫步,或者使用简单的递归神经网络(RNN)。

对于我们的“Python-Poem-Maker”,我建议采用一种**“规则模板+随机填充+简单优化”**的混合策略。这样既能保证生成的诗句符合基本形式,又具有一定的随机性和趣味性,实现难度也适中。

2.2 技术栈选型与项目结构

我们完全使用Python标准库来实现核心功能,以保证项目的纯净和可移植性。主要用到的模块包括:

  • random:用于从词库中随机选择词语。
  • jsonpickle:用于存储和加载我们构建好的结构化词库。
  • re(正则表达式):可选,用于更复杂的文本处理和韵律检查。

对于想要更深入、实现更复杂生成逻辑的朋友,后期可以引入jieba进行分词,或者用numpypandas来管理更庞大的词库数据,但这属于进阶内容,我们基础版先不涉及。

项目目录结构可以这样规划:

poem_maker/ ├── data/ # 数据目录 │ ├── word_lib.json # 核心词库文件 │ └── templates.json # 诗歌模板文件 ├── src/ # 源代码目录 │ ├── __init__.py │ ├── word_library.py # 词库构建与管理模块 │ ├── poem_generator.py # 诗歌生成核心逻辑 │ └── utils.py # 工具函数(如押韵检查) └── main.py # 主程序入口

这种结构清晰地将数据、逻辑和入口分离,方便后续维护和扩展。

2.3 词库设计:诗歌的“食材仓库”

词库是项目的基石,它的质量直接决定生成诗歌的“口感”。我们不能直接用现代汉语词典,因为古诗用词凝练、典雅。我的做法是,从《全唐诗》等公开的电子文本中,通过程序提取高频且意境优美的词汇,并进行人工筛选和分类。

一个简单的词库数据结构可以是这样的(用JSON格式存储):

{ "nouns": { "nature": ["山", "水", "风", "月", "云", "松", "竹", "梅", "江", "海"], "time": ["春", "秋", "朝", "夕", "夜", "岁", "时"], "emotion": ["心", "情", "思", "愁", "梦", "泪"] }, "verbs": { "action": ["望", "听", "登", "临", "归", "宿", "飞", "落"], "link": ["是", "在", "有", "如", "似"] }, "adjectives": ["青", "幽", "明", "静", "寒", "远", "孤", "独"] }

在实际构建时,分类可以更细致。例如,名词还可以按“天文”、“地理”、“植物”、“器物”等进一步划分。动词可以区分及物和不及物。形容词可以标注感情色彩(积极/消极)。

注意:构建词库是一个需要耐心和一定文学素养的过程。初期可以从小规模词库开始,比如每个类别20-30个词,确保生成的诗句基本通顺。之后可以像滚雪球一样,通过分析生成结果的好坏,不断补充和优化词库。一个常见的坑是,某些动词和名词的搭配在逻辑上是不成立的(如“吃月亮”),需要在词库设计或生成规则中加以限制。

3. 核心模块实现详解

3.1 词库管理模块的实现

我们首先实现word_library.py。这个模块负责加载词库、提供按类别随机取词的接口,以及可能的词库扩展功能。

import json import random import os class WordLibrary: def __init__(self, lib_path='data/word_lib.json'): """ 初始化词库 :param lib_path: 词库JSON文件的路径 """ self.lib_path = lib_path self.word_dict = self._load_library() def _load_library(self): """加载词库文件""" if not os.path.exists(self.lib_path): # 如果词库文件不存在,创建一个极简的示例词库 default_lib = { "nouns": {"nature": ["山", "水", "风", "月"], "time": ["春", "秋"]}, "verbs": {"action": ["望", "听"], "link": ["如"]}, "adjectives": ["青", "幽"] } os.makedirs(os.path.dirname(self.lib_path), exist_ok=True) with open(self.lib_path, 'w', encoding='utf-8') as f: json.dump(default_lib, f, ensure_ascii=False, indent=2) return default_lib else: with open(self.lib_path, 'r', encoding='utf-8') as f: return json.load(f) def get_random_word(self, category, subcategory=None): """ 随机获取一个词语 :param category: 大类别,如 'nouns', 'verbs' :param subcategory: 子类别,如 'nature', 'action'。如果为None,则从该大类的所有词中随机选 :return: 一个随机的词语字符串 """ if category not in self.word_dict: raise ValueError(f"词库中不存在类别: {category}") target_collection = self.word_dict[category] if subcategory: if subcategory not in target_collection: raise ValueError(f"类别 {category} 中不存在子类: {subcategory}") word_list = target_collection[subcategory] else: # 如果未指定子类,则将该大类下所有子类的词合并到一个列表中 word_list = [] for sub in target_collection.values(): if isinstance(sub, list): word_list.extend(sub) if not word_list: return None return random.choice(word_list) if word_list else None def add_word(self, category, subcategory, word): """向词库中添加一个新词(仅内存中,需调用save方法持久化)""" if category not in self.word_dict: self.word_dict[category] = {} if subcategory not in self.word_dict[category]: self.word_dict[category][subcategory] = [] if word not in self.word_dict[category][subcategory]: self.word_dict[category][subcategory].append(word) return True return False def save(self): """将内存中的词库保存到文件""" with open(self.lib_path, 'w', encoding='utf-8') as f: json.dump(self.word_dict, f, ensure_ascii=False, indent=2)

这个类提供了词库的基础CRUD操作。关键点在于get_random_word方法,它是生成诗句时取词的唯一入口。通过分离词库管理逻辑,主生成程序会变得非常清晰。

3.2 诗歌生成引擎的核心逻辑

接下来是重头戏poem_generator.py。这里我们将实现不同的生成策略。

策略一:基于固定模板的填充这是最简单的方法。我们预先定义好一些诗句的“骨架”,比如一个五言句的模板可能是[形容词][名词][动词][方位名词],对应生成“青松立岩畔”。我们需要先定义一套模板。

# 在 poem_generator.py 中 class TemplatePoemGenerator: def __init__(self, word_lib): self.word_lib = word_lib # 定义一些简单的句子模板,用{}占位符表示需要填充的词性 self.templates = [ "{adj}{noun}{verb}{place}", "{noun}{verb}{adj}{noun}", "{adj}{noun},{adj}{noun}", "{place}{verb}{adj}{noun}" ] # 映射模板占位符到词库中的类别 self.category_map = { 'adj': ('adjectives', None), 'noun': ('nouns', 'nature'), 'verb': ('verbs', 'action'), 'place': ('nouns', 'place') # 假设词库中有'place'子类 } def generate_line(self): """生成一行诗""" template = random.choice(self.templates) line = template for placeholder, (cat, sub_cat) in self.category_map.items(): if f"{{{placeholder}}}" in line: word = self.word_lib.get_random_word(cat, sub_cat) if word: line = line.replace(f"{{{placeholder}}}", word) else: # 如果取不到词,用默认词替代,避免生成失败 line = line.replace(f"{{{placeholder}}}", "空") return line def generate_poem(self, lines=4): """生成一首诗,默认四句""" poem_lines = [] for _ in range(lines): poem_lines.append(self.generate_line()) return "\n".join(poem_lines)

这种方法优点是速度快,结构稳定。缺点是生成的诗句容易显得呆板、重复,因为模板是有限的。

策略二:基于简单语法树的随机生成我们可以定义更灵活的生成规则,模仿一个简单的上下文无关文法。例如,定义一个“诗句”可以由“主语部分+谓语部分”构成,“主语部分”可以是“形容词+名词”等。

class GrammarPoemGenerator: def __init__(self, word_lib): self.word_lib = word_lib def _generate_phrase(self, grammar_rule): """ 根据语法规则生成一个短语 :param grammar_rule: 例如 ['adj', 'noun'] 或 ['noun', 'verb', 'noun'] """ phrase = [] for elem in grammar_rule: if elem == 'adj': word = self.word_lib.get_random_word('adjectives') elif elem == 'noun_nature': word = self.word_lib.get_random_word('nouns', 'nature') elif elem == 'verb_action': word = self.word_lib.get_random_word('verbs', 'action') else: word = '[?]' phrase.append(word if word else '[空]') return ''.join(phrase) def generate_line(self, word_count=5): """生成指定字数的诗句,通过组合不同的语法规则来实现""" # 定义一些基本语法规则组合来凑字数 # 例如,五言诗可以是 2+3 或 3+2 结构 grammar_patterns = [ [['adj', 'noun_nature'], ['verb_action', 'noun_nature']], # 2+3 [['noun_nature', 'verb_action'], ['adj', 'noun_nature']], # 3+2 ] pattern = random.choice(grammar_patterns) line_parts = [] for part_rule in pattern: line_parts.append(self._generate_phrase(part_rule)) line = ''.join(line_parts) # 简单修剪或补全到指定字数(这里逻辑较简单,实际需要更精细控制) return line[:word_count] if len(line) >= word_count else line + '。'*(word_count-len(line))

这种方法比纯模板更灵活,能生成更多样的句子结构。但如何设计一套合理且能生成优美诗句的语法规则,需要大量的调试和语言学知识。

3.3 押韵功能的集成

对于诗歌来说,押韵是灵魂。我们可以实现一个简单的押韵检查模块。一个取巧的方法是:预先建立一个“押韵字表”。例如,将所有押“ong”韵的字(如“空”、“同”、“中”、“红”)放在一个集合里。在生成每一行末尾字时,从指定的韵部中选取。

首先,在utils.py中创建一个韵部工具:

# utils.py class RhymeChecker: def __init__(self): # 这里只是一个极简示例,实际需要庞大的押韵字典 self.rhyme_groups = { 'ong': ['空', '同', '中', '红', '风', '浓', '穹', '穷'], 'an': ['山', '间', '还', '颜', '关', '寒', '难', '闲'], 'i': ['里', '起', '意', '地', '期', '时', '思', '迟'] } # 反向映射:字 -> 韵部 self.char_to_rhyme = {} for rhyme, chars in self.rhyme_groups.items(): for char in chars: self.char_to_rhyme[char] = rhyme def get_rhyme_group(self, char): """获取一个字的韵部""" return self.char_to_rhyme.get(char, None) def is_rhyme_with(self, char1, char2): """判断两个字是否押韵""" return self.get_rhyme_group(char1) == self.get_rhyme_group(char2) and self.get_rhyme_group(char1) is not None def get_random_char_in_rhyme(self, rhyme_group): """从指定韵部随机取一个字""" if rhyme_group in self.rhyme_groups: return random.choice(self.rhyme_groups[rhyme_group]) return None

然后,在生成诗歌时,特别是在生成绝句(四句)时,我们可以规定第二、四句的末尾字必须押同一个韵。在生成过程中,先随机选定一个韵部,然后在生成第二、四句时,确保句尾字从该韵部中选取。这需要对之前的生成逻辑进行改造,在组词成句的最后一步,替换或选择符合押韵要求的字。这会增加算法的复杂度,但能显著提升生成诗歌的“像样”程度。

实操心得:押韵功能的集成是项目从“玩具”升级到“像样作品”的关键一步。但初期不要追求完美的古韵(平水韵),那太复杂了。可以从现代汉语拼音的韵母相同开始,实现一个简化版的押韵,效果已经足够让人眼前一亮。构建押韵字典是一个体力活,可以从开源的古诗数据库中提取高频押韵字来构建。

4. 项目集成与功能拓展

4.1 主程序与用户交互

有了核心模块,我们需要一个main.py来把它们串起来,并提供友好的命令行界面。

# main.py import argparse from src.word_library import WordLibrary from src.poem_generator import TemplatePoemGenerator, GrammarPoemGenerator from src.utils import RhymeChecker def main(): parser = argparse.ArgumentParser(description='Python Poem Maker - 你的AI诗人') parser.add_argument('--style', choices=['template', 'grammar'], default='template', help='诗歌生成风格:template(模板填充), grammar(语法生成)') parser.add_argument('--lines', type=int, default=4, help='诗歌的行数') parser.add_argument('--rhyme', action='store_true', help='是否启用押韵功能') parser.add_argument('--count', type=int, default=1, help='生成诗歌的数量') args = parser.parse_args() # 初始化组件 print("正在加载词库...") word_lib = WordLibrary() rhyme_checker = RhymeChecker() if args.rhyme else None # 选择生成器 if args.style == 'template': generator = TemplatePoemGenerator(word_lib) else: generator = GrammarPoemGenerator(word_lib) # 如果启用押韵,我们需要一个支持押韵的生成器包装类 # 这里为了示例,假设我们有一个新的支持押韵的生成器类 RhymedPoemGenerator # 实际开发中,需要将押韵逻辑嵌入到上述某个生成器中,或创建新的子类 if args.rhyme: print("警告:押韵功能需要更复杂的生成器,示例中暂未实现完整集成。") print("将使用基础生成器,并尝试在生成后简单调整韵脚(效果可能不理想)。") # 此处应调用 RhymedPoemGenerator print(f"\n生成 {args.count} 首{args.lines}行诗,风格:{args.style}...\n") for i in range(args.count): poem = generator.generate_poem(lines=args.lines) print(f"【诗 {i+1}】") print(poem) print("-" * 20) if __name__ == '__main__': main()

这样,用户就可以通过命令行参数来控制生成诗歌的风格、行数和是否押韵,体验更完整。

4.2 进阶功能探索

一个基础的诗歌生成器完成后,有很多方向可以深入,让项目变得更有挑战性和实用性:

  1. 引入机器学习:使用RNN、LSTM或更现代的Transformer模型(如GPT-2的微调)来训练一个真正的诗歌生成模型。这需要大量的唐诗宋词作为训练语料。你可以使用tensorflowpytorch来实现。这将使生成的诗歌在连贯性和意境上有一个质的飞跃。
  2. 主题控制:让用户输入一个关键词,如“秋天”、“离别”,然后生成符合该主题的诗歌。这需要在词库中为词语打上主题标签,并在生成时提高相关主题词语的选取概率。
  3. 格律精细化:实现真正的平仄规则。你需要为汉字标注平仄(古音),并在生成句子时,按照“平平仄仄平”这样的格律模板来选字。这是一个巨大的工程,但做出来会非常酷。
  4. Web可视化界面:使用FlaskStreamlit快速搭建一个网页应用,用户点击按钮就能生成诗歌,并配上自动生成的山水画背景(可以调用一些AI绘画的API),体验感十足。
  5. 对联生成:诗歌生成的一个变种。对联要求上下联对仗工整,平仄相对,意境相关。可以看作是一个约束条件更严格的文本生成问题,非常适合作为下一个练手项目。

4.3 工程化与部署思考

如果想让你的“Python-Poem-Maker”成为一个可以持续运行、提供服务的项目,就需要考虑工程化问题:

  • 性能:如果词库很大,每次生成都加载整个JSON文件可能效率不高。可以考虑使用数据库(如SQLite)来存储和管理词库,或者将词库加载到内存中常驻(对于Web服务)。
  • 配置化:将诗歌风格、模板、生成规则等参数都放到配置文件中(如YAML),这样不用修改代码就能调整生成逻辑。
  • 日志与监控:记录每次生成请求的参数和结果,便于分析哪种风格更受欢迎,或者排查生成异常的问题。
  • API化:将核心生成功能封装成RESTful API,方便其他应用调用。使用FastAPI可以非常快速地实现。

5. 常见问题与调试心得

在开发过程中,我遇到了不少典型问题,这里列出来供你参考:

问题1:生成的句子不通顺,搭配怪异。

  • 原因:词库分类不够精细,或者生成规则允许了不合理的词性组合(如形容词直接接动词)。
  • 解决
    1. 细化词库分类。不仅是名词、动词,还要考虑词语的及物性、常用搭配。例如,“吹”这个动词,常与“风”、“笛”搭配,而不与“石头”搭配。可以在词库中建立简单的搭配关系表。
    2. 优化生成模板或语法规则。避免出现“形容词+动词”这类不符合中文习惯的结构。多参考真实古诗的句式。
    3. 引入“n-gram”概率模型。从大量古诗中统计两个词、三个词连续出现的概率,在生成时优先选择概率高的组合。这能极大提升通顺度。

问题2:诗歌缺乏整体意境,每句诗之间毫无关联。

  • 原因:生成算法是逐句独立随机的,没有考虑上下文。
  • 解决
    1. 主题贯穿:在生成一首诗前,先随机确定一个核心主题(如“送别”),然后在生成每一句时,都倾向于从与该主题相关的词库子集中选词。
    2. 状态记忆:让生成器记住上一句用了哪些意象(如“月亮”、“江水”),下一句可以尝试使用与之相关的意象(如“倒影”、“行舟”),形成简单的呼应。
    3. 使用序列模型:这是根本解决方法。使用RNN/LSTM等模型,它们天生就会考虑上文信息来预测下一个字。

问题3:押韵功能导致诗句生硬,为了押韵凑字。

  • 原因:押韵是在句子生成完成后强行替换末尾字,破坏了句子本身的自然度。
  • 解决:将押韵约束提前到生成过程中。例如,在采用语法树生成时,先确定韵脚,然后在生成句末短语时,只从符合该韵脚的字集中选择。这需要生成算法与押韵模块深度耦合,设计难度更高,但效果更好。

问题4:程序运行慢,生成一首诗要好几秒。

  • 原因:可能是词库文件过大,加载慢;或者是生成算法中存在低效的循环或搜索。
  • 解决
    1. 对于词库,使用json加载后,可以将其转换为Python字典常驻内存,而不是每次生成都读文件。
    2. 对于算法,审视核心循环。例如,随机选词时,如果某个词库子集是列表,random.choice是O(1)操作,很快。但如果需要频繁判断“这个词是否押某韵脚”,而押韵判断是通过遍历列表实现的,就会慢。此时应建立字典索引,例如{韵母: [字1, 字2...]},实现O(1)查询。
    3. 对于复杂模型(如神经网络),生成速度慢是正常的,需要考虑使用GPU加速或模型量化。

调试技巧实录

  • 设置随机种子:在调试时,在程序开头使用random.seed(42)固定随机数种子。这样每次运行程序,生成的诗歌都是一样的,便于你反复调整参数和逻辑,观察变化。
  • 分步输出:不要一次性生成整首诗。在生成器中加入调试标志,让它打印出中间过程,比如“当前选择的模板是XXX”、“从‘nature’类别中随机选取了‘山’”、“尝试押韵‘ong’,找到字‘空’”。这能帮你精准定位问题出在哪一环。
  • 人工评估与迭代:生成几百首诗,快速浏览,把读起来特别通顺、有意境的句子和特别怪异的句子都标记出来。分析好句子为什么好(用了什么词、什么结构),坏句子为什么坏。用这些洞见反过来优化你的词库和生成规则。这个过程是提升模型质量最有效的方法,没有之一。

最后,我想说,Python-Poem-Maker项目的魅力在于它介于严格的工程和自由的创作之间。你写的每一行代码,都在定义一种“诗意”的算法。它可能永远也写不出李白的豪迈或杜甫的沉郁,但当你看到程序第一次生成出一句勉强可读、甚至偶有亮眼的句子时,那种跨越逻辑与情感边界的成就感,是其他纯工具性项目难以给予的。不妨就从构建一个不到100个词的小词库开始,运行你的第一个生成器,看看这位“AI诗人”的处女作吧。

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

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

立即咨询