Langchain-Chatchat在诗歌生成中的美学探索
在数字人文与人工智能交汇的今天,我们正见证一场静默却深刻的创作革命——AI不再只是回答问题的工具,而是开始参与那些曾被认为专属于人类灵魂的艺术表达。当一位诗人深夜伏案,试图捕捉心头那一缕难以言说的情绪时,他或许会打开一个本地运行的程序,轻声问:“如果李白写一首关于城市孤独的五言诗,会是什么样子?” 几秒钟后,一行行带着盛唐气象却又映照现代心境的文字缓缓浮现。
这不是科幻场景,而是借助Langchain-Chatchat这类开源本地知识库系统即可实现的真实可能。它让大型语言模型(LLM)不仅能“知道”,更能“懂得”某种风格、某位诗人、某一类情感的深层脉络,并以高度可控的方式进行模仿与再创造。
更重要的是,这一切都发生在你的电脑上,无需上传任何数据到云端。未发表的手稿、私密的日记、家族流传的诗句,都可以成为AI学习的语料,而不用担心被谁窥见。
要理解这种技术如何重塑诗歌创作,我们需要拆解它的三个核心支柱:本地化知识库系统(Langchain-Chatchat)、模块化开发框架(LangChain)和内容生成引擎(LLM)。它们共同构成了一种新型的人机协同创作范式——既尊重艺术的独特性,又释放机器的计算力。
先从最底层说起。Langchain-Chatchat 本质上是一个为中文优化的本地问答系统,但它不只是用来查文档的。当你把杜甫全集、李清照词选或北岛的现代诗手稿导入其中时,它做的不是简单的关键词匹配,而是将这些文本切片、向量化、存入本地数据库,建立起一套“语义记忆”。这个过程就像教一个学生背诵并理解大量经典作品,只为有一天让他能写出风格一致的新篇章。
整个流程是这样的:
首先是文档加载与清洗。无论是TXT、PDF还是Word格式,系统都能提取出纯文本内容。对于古籍扫描件,还可以结合OCR工具预处理。接着进行分段和规范化,比如统一繁体字、修正标点、去除页眉页脚等干扰信息。
然后是文本分块。这是关键一步。如果直接把整本《全唐诗》喂给嵌入模型,显然超出其最大输入长度。因此需要使用如RecursiveCharacterTextSplitter这样的策略,按语义单元切割成256或512个token的小块。但这里有个讲究:对古典诗歌而言,最好以“一首诗”为单位分割,避免把两首不同主题的作品混在同一chunk中,导致语义污染。
接下来是向量化与索引构建。这一步决定了AI是否“懂”风格。我们选用专门针对中文优化的嵌入模型,例如 BAAI 推出的BGE(Beijing AI Embedding)系列,尤其是bge-small-zh-v1.5或更大版本。这类模型在 MTEB 中文榜单上表现优异,能够精准捕捉“孤舟”与“独钓”之间的意境关联,而不只是字面相似。
所有向量最终存入本地向量数据库,如 FAISS 或 Chroma。FAISS 尤其适合离线部署,检索速度快,内存占用低,非常适合个人创作者使用。
最后进入生成阶段,也就是 RAG(Retrieval-Augmented Generation,检索增强生成)的核心逻辑:当用户提出请求——“请模仿王维写一首描写秋山的五言绝句”——系统首先将该查询转化为向量,在库中找出最相关的几段原文(比如《山居秋暝》《鹿柴》中的片段),然后把这些参考内容拼接成上下文,送入大模型进行条件生成。
这样一来,输出就不再是凭空臆造,而是有据可依的“仿作”。
下面这段代码展示了整个链条的基本实现:
from langchain.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import FAISS from langchain.chains import RetrievalQA from langchain.llms import HuggingFaceHub # 1. 加载诗歌文本 loader = TextLoader("poems_collection.txt", encoding="utf-8") documents = loader.load() # 2. 文本分块 text_splitter = RecursiveCharacterTextSplitter( chunk_size=256, chunk_overlap=50 ) texts = text_splitter.split_documents(documents) # 3. 初始化中文嵌入模型 embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5") # 4. 构建向量数据库 vectorstore = FAISS.from_documents(texts, embeddings) # 5. 创建检索器 retriever = vectorstore.as_retriever(search_kwargs={"k": 3}) # 6. 连接本地LLM(示例使用HuggingFaceHub,实际可用llama.cpp、ChatGLM本地API) llm = HuggingFaceHub( repo_id="THUDM/chatglm3-6b", model_kwargs={"temperature": 0.7, "max_length": 512}, huggingfacehub_api_token="your_token" ) # 7. 构建RAG链 qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=retriever, return_source_documents=True ) # 8. 提问示例 query = "请写一首描写庐山云雾的五言律诗,风格模仿李白" result = qa_chain({"query": query}) print("生成诗歌:") print(result["result"]) print("\n参考来源:") for doc in result["source_documents"]: print(f"- {doc.metadata['source']} 中的片段: {doc.page_content}")这段代码看似简单,实则凝聚了多个工程权衡。比如为什么用RecursiveCharacterTextSplitter?因为它在中文断句上比固定字符分割更智能,能优先按段落、句子切分,保留语义完整性。再比如温度设为0.7,这是一个经验性的折中值:太低会死板,太高则容易跑偏格律。
但真正让系统“像诗人”的,其实是提示工程(Prompt Engineering)的设计。你可以不满足于一句模糊的“模仿李白”,而是构造一个结构化的指令模板,明确告诉模型你要什么。
from langchain.prompts import PromptTemplate poetry_prompt_template = """ 你是一位精通中国古代诗歌的诗人。请根据以下参考资料创作一首新的诗歌。 要求如下: - 题材:{theme} - 形式:{form}(如五言律诗、七言绝句) - 风格:模仿{style}的笔法 - 情感基调:{tone} 参考资料: {context} 请仅输出诗歌本身,不要解释。 """ PROMPT = PromptTemplate( template=poetry_prompt_template, input_variables=["theme", "form", "style", "tone", "context"] ) qa_chain = RetrievalQA.from_chain_type( llm=llm, chain_type="stuff", retriever=retriever, chain_type_kwargs={"prompt": PROMPT} ) result = qa_chain({ "query": "", "theme": "江边送别", "form": "七言绝句", "style": "王昌龄", "tone": "苍凉悲壮", "context": "" })通过这种方式,你能精确控制输出的形式与气质。更重要的是,由于上下文{context}是由检索模块自动填充的真实诗句片段,模型很难完全脱离原作风格去胡编乱造。
当然,也不能高估当前技术的能力。LLM 仍然存在几个明显的短板:
一是幻觉问题。即使有检索支撑,模型仍可能虚构不存在的典故或误用意象。例如让它写“陶渊明风格”的诗,结果引用了宋代才出现的词汇。解决办法之一是设置更强的约束机制,比如只允许使用检索结果中出现过的词语集合。
二是格律偏差。大多数通用 LLM 并不具备内置的平仄检测能力。虽然可以通过提示词引导“押平声韵”“符合五律格式”,但无法保证每句都合规。理想的做法是在生成之后加入一个规则校验模块,比如调用专业的诗词格律分析库(如pyglib或自定义规则引擎)进行后处理。
三是资源门槛。要在本地流畅运行一个 6B 或 13B 参数的中文模型,至少需要一块拥有 12GB 显存的 GPU(如 RTX 3060/4060)。如果没有高端硬件,可以采用量化技术,比如使用 GGUF 格式的模型配合 llama.cpp,实现 CPU 上的推理,虽然速度慢些,但足以支持日常创作辅助。
那么,这套系统到底能做什么?
想象这样一个工作流:
- 你是一位研究海子的学者,手头有一批未公开的诗稿笔记。你将其整理成 TXT 文件导入 Langchain-Chatchat;
- 系统自动完成解析、分块、向量化,建立专属的知识库;
- 你在前端输入:“请以‘麦地’为主题,用海子早期口语化风格写一段自由诗”;
- AI 返回一首带有强烈个人印记的新作,参考来源显示其主要依据的是《麦地》《亚洲铜》等真实文本;
- 你觉得结尾不够有力,追加一句:“加入死亡意象,语气更决绝一些”;
- 系统结合之前的对话记忆(可通过
ConversationBufferMemory实现),重新生成一版更贴近海子晚期风格的作品。
这个过程已经不是单纯的“生成”,而是一种迭代式共创。人类提供灵感与审美判断,机器负责扩展表达与语言实验。两者互为镜像,彼此激发。
从系统架构上看,完整的链条包括:
[用户界面] ↓ (输入查询/创作指令) [LangChain 应用层] ├── Document Loader → 解析诗人手稿、诗集PDF等 ├── Text Splitter → 分块处理 ├── Embedding Model → 向量化 └── Vector Store (FAISS) ← 建立本地语义索引 ↑ [检索模块] ↓ [LLM 生成引擎] ← 提示模板 + 检索结果 + 用户指令 ↓ [生成诗歌输出] ↓ [后处理模块] → 格律检查、押韵分析、人工评分接口每一环都可以独立优化。比如你可以换掉默认的 HuggingFaceEmbeddings,换成自己微调过的中文诗意嵌入模型;也可以把 LLM 替换为本地部署的 Qwen 或 InternLM,甚至接入语音合成模块,让生成的诗被朗读出来。
在实践中,我们也发现一些值得深入的设计考量:
- 文本分割策略:对短诗宜整首保留;对长篇叙事诗或散文诗,则需滑动窗口重叠分块,确保上下文连续。
- 嵌入模型选择:
bge-large-zh虽然性能更强,但加载慢、占内存多,适合研究级应用;普通用户用bge-small即可获得良好体验。 - 评估机制建设:除了 BLEU、ROUGE 等自动指标,建议引入三人以上专家盲评,从“意境契合度”“语言创新性”“风格一致性”三个维度打分,形成闭环反馈。
回到最初的问题:AI 能写诗吗?
答案或许是:它不能替代诗人,但可以成为一个前所未有的创作伙伴。
Langchain-Chatchat 所代表的技术路径,其意义不仅在于实现了本地化、安全、可定制的内容生成,更在于它重新定义了“创作”的边界。当我们能把一位诗人的全部精神遗产装进一台笔记本电脑,让它随时回应我们的灵感召唤时,那种感觉近乎于——让逝去的声音再次开口说话。
而这,也许正是技术通往美学的最近路径。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考