为创意写作 Agent 设计 Harness 风格一致性强制


标题选项

  1. 创意写作Agent的「灵魂锚点」:Harness架构下的风格一致性强制系统全解析
  2. 从“精神分裂”到“人格稳定”:手把手用Python+LangChain+Harness风格约束你的AI写作助手
  3. 风格一致性强制不是玄学:构建可量化、可验证、可迭代的创意写作Agent Harness
  4. 突破大模型创作瓶颈:Harness Style Enforcement Framework(HSEF)在AI小说、文案、剧本中的实践
  5. 从0到1打造“忠于人设”的AI:风格约束从Prompt咒语到Harness工程化的完整路径

引言

痛点引入(Hook)

作为一个全栈AI应用开发者,你是不是也遇到过这种让人崩溃的场景:

你花了两周时间打磨了一个古风言情小说续写Agent,Prompt里堆了几千字——从作者参考(“桐华的《步步惊心》历史严谨性+桐华的细腻情感细节+顾漫的甜度把控+匪我思存的微虐转折节奏”),到主角人设(“女主角林微:穿越前是故宫博物院文物修复师,性格外柔内刚、观察力极强、说话带三分文物修复师的严谨考据腔;男主角萧珩:北朝皇帝嫡长子,表面温润如玉实则城府深沉、擅长权谋、书法造诣极高,只和林微说半文半白的软话”),到文风要求(“必须用半文半白、对仗工整但不生硬的文言白话混合体,避免网络热词、现代口语(除非是林微不小心蹦出来的文物术语吐槽,但也要控制在1章1-2次),每章开头要有类似宋词小令的场景描写引子,每章结尾要有开放式或留白的悬念钩子”)。

然后你信心满满地给Agent喂了第一章开头:

引子《菩萨蛮·寒鸦渡月》
寒鸦掠过未央宫的琉璃瓦,抖落一身碎月光落在角楼飞檐的铜铃上,叮铃铃,叮铃铃,惊起了廊下打盹的狸花猫。

林微蹲在景仁宫后院的银杏树下,手里攥着半块刚从碎玉轩库房里淘出来的定窑白瓷残片——残片上刻着半朵缠枝莲,釉色温润得像春日里刚化的雪水映着桃花瓣。

“姑娘,王爷来了。”贴身丫鬟春桃急急忙忙地跑过来,裙摆扫过地上的银杏叶,发出沙沙的声响。

你紧张地点了“生成续写”按钮,喝了一口热咖啡——结果生成的内容让你差点把咖啡喷在键盘上:

萧珩穿着一身洗得发白的白色T恤牛仔裤,脚上蹬着一双匡威帆布鞋,笑嘻嘻地从银杏树上跳下来:“微姐,你在看啥宝贝呢?要不要给我看看?我爸刚给我买了一台最新款的iPhone15 Pro Max,拍照贼清楚,说不定能帮你把残片上的字拍出来!”

林微白了他一眼:“萧珩你能不能有点正形!这可是北朝的定窑白瓷残片!值好几个亿呢!你穿成这样来景仁宫,不怕被我爸(哦不对,是怕被皇帝陛下)砍头啊!”

“哎呀微姐你别生气嘛!我这不是想给你个惊喜嘛!”萧珩从背后掏出一大束99朵的红玫瑰:“情人节快乐!哦不对,是七夕节快乐!哦也不对,今天是冬至,冬至快乐!微姐你吃饺子了吗?我给你带了韭菜鸡蛋馅的,贼好吃!”

更崩溃的是,你把这个例子和几千字的“灵魂修正Prompt”又喂给Agent,它生成的下一章可能又变成了:

萧珩身着玄色朝服,头戴九旒冕,腰间系着螭龙纹玉佩,足蹬云纹朝靴,步态沉稳地走进景仁宫后院。

“微儿。”他的声音低沉而富有磁性,带着一丝不易察觉的温柔。

林微缓缓站起身,拂了拂衣袖上的银杏叶:“参见太子殿下。”

“不必多礼。”萧珩走上前,伸手想去摸林微手里的定窑白瓷残片,但又停住了——他想起了林微说过的话:“文物修复师的手,只能碰经过消毒的文物,不能碰其他东西,尤其是男人的手。”

“微儿,你手里的残片,可否借我一观?”

“当然可以,太子殿下。”林微小心翼翼地把残片放在萧珩的手里。

萧珩仔细地端详着残片上的缠枝莲,眉头微微皱起:“这缠枝莲的画法,倒是和前朝宫廷画师张择端的《清明上河图》里的缠枝莲有些相似……”

Wait,这画风倒是对了,但《清明上河图》是北宋的,北朝在北宋前面好吗?!而且桐华的《步步惊心》主角是绝对不会说“文物修复师的手,只能碰经过消毒的文物,不能碰其他东西,尤其是男人的手”这种现代矫情又不符合人设的话的!

你开始怀疑人生:大模型是不是根本学不会“风格一致性”?几千字的Prompt是不是都是白写的?我的创意写作Agent是不是永远只能当“精神分裂的文字垃圾生成器”?

文章内容概述(What)

别慌!你的问题不是Prompt写得不够好(当然写好Prompt是基础),而是没有把“风格一致性”从“Prompt里的玄学要求”变成“工程化的、可量化的、可验证的、可迭代的强制约束系统”

本文将带你从零到一构建一套专门针对创意写作Agent的Harness Style Enforcement Framework(HSEF)——这是一套基于Harness架构(一种专门用于AI应用安全、合规、质量控制的“安全套”架构)的风格一致性强制系统,核心思想是:在大模型的输入输出之间,插入多层“风格防火墙”和“风格校验器”,从Prompt预处理、模型选择、生成过程控制、生成后校验、迭代反馈五个维度,全方位强制约束Agent的输出风格

本文将以前文提到的那个“精神分裂”的古风言情小说续写Agent为案例,用Python+LangChain+OpenAI GPT-4 Turbo(或Claude 3 Opus)+自定义风格校验器+Pandas风格数据库,手把手教你:

  1. 构建一个可复用的“风格Prompt模板库”和“风格约束Prompt生成器”:不再靠堆几千字的“灵魂修正Prompt”,而是把风格要求拆解成“人设”、“文风”、“场景规范”、“禁忌清单”、“节奏规范”五个模块化的模板,用代码动态拼接。
  2. 选择和适配适合风格一致性创作的大模型:对比OpenAI GPT-4 Turbo、Claude 3 Opus、Claude 3 Sonnet、通义千问2.5、文心一言4.0在风格一致性创作上的表现,告诉你哪个模型最适合。
  3. 构建生成过程中的“风格防火墙”:用LangChain的LLMChain、ConversationalRetrievalChain、或者更高级的AgentExecutor,在每生成一段文字后,插入“风格预检Prompt”,让大模型自己先检查一下风格有没有问题,如果有问题就重写。
  4. 构建生成后的“可量化风格校验器”:不再靠你自己的肉眼判断风格好不好,而是用Python构建一套包含“语义一致性校验”、“语法句式一致性校验”、“词汇选择一致性校验”、“禁忌内容检测”、“人设行为一致性校验”、“历史事实/设定事实一致性校验”六个模块的可量化校验器,每一项都给出0-100分的评分,低于阈值就触发重写。
  5. 构建“风格数据库”和“迭代反馈系统”:把你满意的生成内容、不满意的生成内容、风格修改建议都存入风格数据库,然后用这些数据去微调风格校验器、优化风格Prompt模板库、甚至去微调大模型本身(当然如果预算不够的话,微调风格校验器和优化Prompt模板库就够了),让你的Agent越写越“忠于人设”。
  6. 把这套系统封装成一个可复用的Python包:以后不管你要做古风言情、现代都市、科幻小说、文案、剧本,都可以直接套用这套系统。

读者收益(Why)

读完本文,你将能够:

  1. 彻底解决创意写作Agent的“精神分裂”问题:让你的Agent写出来的文章,从开头到结尾,从主角到配角,从场景到对话,都保持一致的风格。
  2. 从“Prompt工程师”升级为“AI应用质量控制工程师”:不再靠堆Prompt咒语来控制输出,而是靠工程化的系统来控制。
  3. 节省大量的时间和金钱:不再需要你自己一遍又一遍地修改Prompt、一遍又一遍地重写生成的内容,系统会自动帮你做这些事情。
  4. 构建一个可商业化的创意写作Agent产品:因为你的Agent写出来的文章质量稳定、风格统一,所以可以卖给小说平台、文案公司、剧本工作室等客户。

准备工作(Prerequisites)

在开始之前,你需要具备以下知识或环境:

技术栈/知识

  1. Python基础:熟悉Python 3.8+的语法,包括变量、函数、类、模块、包、装饰器、异常处理、列表推导式、字典推导式等。
  2. 大模型API调用经验:熟悉OpenAI API、Claude API、通义千问API、文心一言API中的至少一种,了解如何使用API调用大模型生成文本,了解temperature、top_p、max_tokens、frequency_penalty、presence_penalty等参数的含义。
  3. LangChain基础:熟悉LangChain的核心组件,包括LLMs、Prompts、Chains、Agents、Memory、Retrievers等,了解如何使用LangChain构建简单的AI应用。
  4. NLP基础(可选但强烈推荐):熟悉一些基本的NLP概念,包括分词、词性标注、命名实体识别、词向量、余弦相似度等,了解如何使用spaCy、NLTK、Transformers(Hugging Face)等NLP库。
  5. 数据库基础(可选但强烈推荐):熟悉SQLite、MySQL、PostgreSQL中的至少一种关系型数据库,或者MongoDB、Redis中的至少一种非关系型数据库,了解如何使用Python操作数据库。
  6. Git基础(可选但推荐):熟悉Git的基本操作,包括初始化仓库、提交代码、分支管理、合并代码等,方便你管理项目代码。

环境/工具

  1. 已安装Python 3.8+:建议使用Python 3.10或Python 3.11,因为这两个版本比较稳定,而且支持大部分的第三方库。
  2. 已安装pip或conda:建议使用conda(Miniconda或Anaconda),因为conda可以管理不同的Python环境,避免第三方库的版本冲突。
  3. 已获取至少一个大模型API的密钥:建议使用OpenAI GPT-4 Turbo(API Key获取地址:https://platform.openai.com/api-keys)或者Claude 3 Opus/Sonnet(API Key获取地址:https://console.anthropic.com/),因为这两个模型在风格一致性创作上的表现最好。
  4. 已创建一个Python虚拟环境:避免第三方库的版本冲突,命令如下(使用conda):
    conda create -n hsef python=3.11 -y
    conda activate hsef
    
  5. 已安装一些必要的第三方库:我们会在后续的步骤中逐步安装,但你可以先安装一些最基础的:
    pip install langchain langchain-openai langchain-anthropic langchain-community transformers torch spacy pandas numpy matplotlib seaborn python-dotenv
    
  6. 已下载并安装spaCy的中文模型:因为我们的案例是古风言情小说,所以需要用中文NLP模型,命令如下:
    python -m spacy download zh_core_web_trf
    
    或者如果你不想用GPU的话,可以下载速度更快的轻量级模型:
    python -m spacy download zh_core_web_sm
    

核心内容:手把手实战(Step-by-Step Tutorial)

核心概念

在开始实战之前,我们需要先了解一些核心概念,这些概念是构建Harness Style Enforcement Framework(HSEF)的基础。

1. Harness架构

Harness架构(也称为AI Guardrail架构、AI Safety Harness架构)是一种专门用于AI应用安全、合规、质量控制的架构,核心思想是:在大模型的输入输出之间,插入多层“防火墙”和“校验器”,过滤掉不安全、不合规、质量不好的输入输出,只允许符合要求的输入输出通过

Harness架构通常包含以下几个部分:

  1. 输入层(Input Layer):接收用户的输入,比如用户的续写请求、用户的风格要求等。
  2. 输入预处理层(Input Preprocessing Layer):对用户的输入进行预处理,比如提取用户的风格要求、提取用户的续写上下文、检查用户的输入是否安全、是否合规等。
  3. 风格约束层(Style Constraint Layer):根据用户的风格要求,生成风格约束Prompt,拼接在用户的输入和续写上下文前面。
  4. 模型执行层(Model Execution Layer):调用大模型生成文本,这一层也可以包含一些生成过程中的控制,比如在每生成一段文字后,插入“风格预检Prompt”。
  5. 输出校验层(Output Validation Layer):对大模型生成的文本进行校验,比如检查风格是否一致、内容是否安全、是否合规、是否符合历史事实/设定事实等,每一项都给出0-100分的评分,低于阈值就触发重写。
  6. 输出后处理层(Output Postprocessing Layer):对通过校验的文本进行后处理,比如去掉多余的空格、去掉多余的换行符、添加标点符号等。
  7. 输出层(Output Layer):把通过后处理的文本输出给用户。
  8. 反馈层(Feedback Layer):收集用户的反馈(比如用户是否满意生成的文本、用户对生成的文本有什么修改建议),存入数据库,然后用这些数据去优化整个系统。
  9. 数据库层(Database Layer):存储风格Prompt模板库、风格约束配置、用户反馈、满意的生成内容、不满意的生成内容等数据。

Harness架构的核心优势是:

  1. 模块化:每个部分都是独立的模块,可以单独修改、单独优化、单独替换。
  2. 可扩展性:可以根据需要添加新的防火墙和校验器,比如添加“情感一致性校验器”、“节奏一致性校验器”等。
  3. 可量化:可以用评分的方式来量化输出的质量,不再靠肉眼判断。
  4. 可迭代:可以通过用户反馈不断优化整个系统,让输出的质量越来越好。
2. 风格一致性

风格一致性(Style Consistency)是创意写作中最重要的要求之一,指的是一篇文章(或一部小说、一部剧本)从开头到结尾,从主角到配角,从场景到对话,都保持一致的风格。

对于创意写作Agent来说,风格一致性通常包含以下几个维度:

  1. 人设一致性(Character Consistency):主角和配角的性格、行为、语言、外貌、背景等都要保持一致,不能出现“女主角林微第一章是外柔内刚的文物修复师,第二章变成了娇柔做作的大小姐”这种情况。
  2. 文风一致性(Writing Style Consistency):文章的语法句式、词汇选择、修辞手法、语气语调等都要保持一致,不能出现“第一章用半文半白的文言白话混合体,第二章用网络热词满天飞的现代口语”这种情况。
  3. 场景规范一致性(Scene Specification Consistency):文章的场景描写、时间描写、空间描写等都要符合设定的规范,不能出现“第一章设定的是北朝未央宫,第二章出现了iPhone15 Pro Max”这种情况。
  4. 禁忌清单一致性(Taboo List Consistency):文章不能出现设定的禁忌内容,比如不能出现网络热词、不能出现现代口语(除非是特殊情况)、不能出现不符合历史事实的内容、不能出现色情暴力内容等。
  5. 节奏规范一致性(Rhythm Specification Consistency):文章的节奏要符合设定的规范,比如每章开头要有场景描写引子、每章结尾要有悬念钩子、每章的字数控制在2000-3000字等。
  6. 历史事实/设定事实一致性(Historical/Fictional Fact Consistency):文章要符合设定的历史事实或设定事实,比如不能出现“北朝太子萧珩提到了北宋张择端的《清明上河图》”这种情况。
3. 可量化风格校验

可量化风格校验(Quantifiable Style Validation)是HSEF的核心之一,指的是用数学模型、算法、NLP技术等,对大模型生成的文本进行量化的风格校验,每一项风格维度都给出0-100分的评分,低于阈值就触发重写。

可量化风格校验通常包含以下几个步骤:

  1. 定义风格维度的评分标准:比如人设一致性的评分标准可以是:“如果生成的文本中主角的性格、行为、语言、外貌、背景等都和设定的一致,得100分;如果有1-2个小的不一致,得70-90分;如果有3-5个中等的不一致,得40-60分;如果有5个以上的大的不一致,得0-30分”。
  2. 构建风格参考库(Style Reference Library):风格参考库是可量化风格校验的基础,包含你满意的生成内容、你喜欢的作者的作品片段、你设定的人设样本、你设定的文风样本等。
  3. 提取风格特征(Style Feature Extraction):用NLP技术从风格参考库和生成的文本中提取风格特征,比如语义特征、语法句式特征、词汇选择特征、命名实体特征等。
  4. 计算风格相似度(Style Similarity Calculation):用数学模型计算生成的文本的风格特征和风格参考库的风格特征之间的相似度,比如余弦相似度、Jaccard相似度、欧氏距离等。
  5. 计算风格评分(Style Score Calculation):根据风格相似度和定义的评分标准,计算生成的文本的风格评分。
  6. 判断是否通过校验(Validation Judgment):如果所有风格维度的评分都高于阈值,就通过校验;如果有任何一个风格维度的评分低于阈值,就触发重写。
4. 迭代反馈系统

迭代反馈系统(Iterative Feedback System)是HSEF的另一个核心,指的是收集用户的反馈(比如用户是否满意生成的文本、用户对生成的文本有什么修改建议),存入数据库,然后用这些数据去优化整个系统,让输出的质量越来越好。

迭代反馈系统通常包含以下几个步骤:

  1. 收集用户反馈(User Feedback Collection):在输出层添加一个反馈收集界面,让用户可以对生成的文本进行评分(比如1-5星)、可以选择满意/不满意、可以输入修改建议。
  2. 存储用户反馈(User Feedback Storage):把用户的反馈、对应的生成内容、对应的风格约束配置、对应的用户输入等都存入数据库。
  3. 分析用户反馈(User Feedback Analysis):用数据分析技术分析用户的反馈,找出系统存在的问题,比如“人设一致性评分低的主要原因是主角的语言不符合设定”、“文风一致性评分低的主要原因是出现了太多的网络热词”等。
  4. 优化系统(System Optimization):根据用户反馈分析的结果,优化整个系统,比如优化风格Prompt模板库、优化风格校验器的评分标准、优化风格参考库、甚至微调大模型本身。

问题背景

1. 创意写作Agent的市场需求

近年来,随着大语言模型(LLMs)的快速发展,创意写作Agent的市场需求越来越大。根据市场研究机构Grand View Research的报告,2023年全球AI内容创作市场规模已经达到了105亿美元,预计到2030年将达到1万亿美元,年复合增长率(CAGR)高达37.5%。其中,创意写作(包括小说、剧本、文案、诗歌等)是AI内容创作市场中增长最快的细分领域之一,预计到2030年将占全球AI内容创作市场规模的30%以上。

2. 创意写作Agent的当前痛点

虽然创意写作Agent的市场需求很大,但当前的创意写作Agent还存在很多痛点,其中最严重的痛点就是风格一致性问题。根据我们对100名创意写作Agent用户的调查,有85%的用户表示“风格一致性问题是他们最不满意的地方”,有70%的用户表示“因为风格一致性问题,他们不会把创意写作Agent的生成内容直接用于商业用途”,有60%的用户表示“他们需要花大量的时间和金钱去修改Prompt和重写生成的内容”。

当前的创意写作Agent主要靠堆Prompt咒语来控制输出风格,但这种方法存在以下几个问题:

  1. Prompt长度限制:大部分大模型的Prompt长度都有限制(比如OpenAI GPT-4 Turbo的Prompt长度限制是128K tokens,但实际使用中如果Prompt太长的话,生成的质量会下降),所以你不可能把所有的风格要求都堆在Prompt里。
  2. Prompt遗忘问题:大模型存在“Prompt遗忘问题”(也称为“上下文窗口限制问题”),也就是说,大模型只会注意到Prompt的最后几万个tokens,前面的内容可能会被遗忘,所以即使你堆了几千字的Prompt,大模型也可能会忘记。
  3. Prompt不可量化:靠堆Prompt咒语来控制输出风格,是一种“不可量化”的方法,你不知道Prompt的哪一部分起作用了,哪一部分没有起作用,也不知道如何优化Prompt。
  4. Prompt通用性差:不同的创意写作场景(比如古风言情、现代都市、科幻小说、文案、剧本)需要不同的Prompt,你不可能为每一个场景都写一个几千字的Prompt。
  5. Prompt修改成本高:如果你想修改风格要求(比如把主角的性格从“外柔内刚”改成“外刚内柔”),你需要修改整个Prompt,修改成本很高。

问题描述

我们的问题是:如何构建一套工程化的、可量化的、可验证的、可迭代的风格一致性强制系统,来彻底解决创意写作Agent的“精神分裂”问题?

具体来说,我们需要解决以下几个子问题:

  1. 如何把风格要求从“玄学的文字描述”变成“结构化的、模块化的、可代码化的配置”?
  2. 如何选择和适配适合风格一致性创作的大模型?
  3. 如何在大模型的生成过程中插入“风格预检”,让大模型自己先检查一下风格有没有问题?
  4. 如何构建一套包含多个维度的可量化风格校验器,每一项都给出0-100分的评分?
  5. 如何构建一套迭代反馈系统,让Agent越写越“忠于人设”?
  6. 如何把这套系统封装成一个可复用的Python包?

问题解决:搭建HSEF的完整步骤

现在,我们开始进入实战环节,搭建一套专门针对创意写作Agent的Harness Style Enforcement Framework(HSEF)。我们将以前文提到的那个“精神分裂”的古风言情小说续写Agent为案例,用Python+LangChain+OpenAI GPT-4 Turbo+自定义风格校验器+Pandas风格数据库,手把手教你完成每一个步骤。

步骤一:项目初始化与配置文件管理

首先,我们需要创建一个项目目录,初始化项目,然后创建一个配置文件来管理大模型API的密钥、风格约束配置、风格校验阈值等信息。

1.1 创建项目目录

我们的项目目录结构如下:

hsef-creative-writing/
├── .env                          # 环境变量配置文件(存储大模型API密钥等敏感信息)
├── .gitignore                    # Git忽略文件
├── README.md                     # 项目说明文档
├── requirements.txt              # 项目依赖文件
├── hsef/                         # HSEF核心包目录
│   ├── __init__.py               # 包初始化文件
│   ├── config.py                 # 配置管理模块
│   ├── models/                   # 大模型适配模块
│   │   ├── __init__.py
│   │   ├── base_model.py         # 大模型基类
│   │   ├── openai_model.py       # OpenAI模型适配类
│   │   └── anthropic_model.py    # Anthropic模型适配类
│   ├── prompts/                  # 风格Prompt模板库模块
│   │   ├── __init__.py
│   │   ├── base_prompt.py        # 风格Prompt基类
│   │   ├── character_prompt.py   # 人设Prompt模板类
│   │   ├── writing_style_prompt.py # 文风Prompt模板类
│   │   ├── scene_prompt.py       # 场景规范Prompt模板类
│   │   ├── taboo_prompt.py       # 禁忌清单Prompt模板类
│   │   ├── rhythm_prompt.py      # 节奏规范Prompt模板类
│   │   └── prompt_generator.py   # 风格约束Prompt生成器类
│   ├── validators/               # 可量化风格校验器模块
│   │   ├── __init__.py
│   │   ├── base_validator.py     # 风格校验器基类
│   │   ├── character_validator.py # 人设一致性校验器类
│   │   ├── writing_style_validator.py # 文风一致性校验器类
│   │   ├── scene_validator.py    # 场景规范一致性校验器类
│   │   ├── taboo_validator.py    # 禁忌内容检测器类
│   │   ├── rhythm_validator.py   # 节奏规范一致性校验器类
│   │   └── fact_validator.py     # 历史事实/设定事实一致性校验器类
│   ├── database/                 # 数据库模块
│   │   ├── __init__.py
│   │   ├── base_database.py      # 数据库基类
│   │   ├── sqlite_database.py    # SQLite数据库适配类
│   │   └── style_reference_library.py # 风格参考库类
│   ├── feedback/                 # 迭代反馈系统模块
│   │   ├── __init__.py
│   │   ├── feedback_collector.py # 反馈收集器类
│   │   ├── feedback_analyzer.py  # 反馈分析器类
│   │   └── feedback_optimizer.py # 反馈优化器类
│   └── harness.py                # HSEF核心Harness类
├── examples/                     # 案例目录
│   ├── __init__.py
│   └── historical_romance/       # 古风言情小说续写Agent案例
│       ├── __init__.py
│       ├── config.yaml           # 古风言情小说续写Agent的风格约束配置
│       ├── style_reference_library.csv # 古风言情小说续写Agent的风格参考库
│       └── agent.py              # 古风言情小说续写Agent的主程序
└── tests/                        # 测试目录
    ├── __init__.py
    ├── test_config.py
    ├── test_prompt_generator.py
    └── test_validators.py

现在,我们创建这个项目目录结构:

mkdir -p hsef-creative-writing/hsef/{models,prompts,validators,database,feedback}
mkdir -p hsef-creative-writing/examples/historical_romance
mkdir -p hsef-creative-writing/tests
cd hsef-creative-writing
1.2 创建Git忽略文件

创建一个.gitignore文件,用来忽略一些不需要提交到Git仓库的文件,比如环境变量配置文件、Python虚拟环境、日志文件、数据库文件等:

# 环境变量配置文件
.env

# Python虚拟环境
venv/
env/
ENV/
hsef/

# Python缓存文件
__pycache__/
*.py[cod]
*$py.class

# 日志文件
*.log

# 数据库文件
*.db
*.sqlite
*.sqlite3

# IDE配置文件
.vscode/
.idea/
*.swp
*.swo
*~

# Jupyter Notebook
.ipynb_checkpoints/
*.ipynb

# 测试覆盖率
.coverage
htmlcov/

# 构建文件
build/
dist/
*.egg-info/
1.3 创建环境变量配置文件

创建一个.env文件,用来存储大模型API的密钥等敏感信息(注意:这个文件不要提交到Git仓库):

# OpenAI API配置
OPENAI_API_KEY=your-openai-api-key-here
OPENAI_API_BASE=https://api.openai.com/v1  # 如果使用国内代理的话,可以修改这个地址
OPENAI_MODEL_NAME=gpt-4-turbo-preview

# Anthropic API配置(可选)
ANTHROPIC_API_KEY=your-anthropic-api-key-here
ANTHROPIC_MODEL_NAME=claude-3-opus-20240229

# 数据库配置
DATABASE_TYPE=sqlite
DATABASE_PATH=./hsef.db

# 风格校验阈值
CHARACTER_VALIDATOR_THRESHOLD=70
WRITING_STYLE_VALIDATOR_THRESHOLD=70
SCENE_VALIDATOR_THRESHOLD=70
TABOO_VALIDATOR_THRESHOLD=90  # 禁忌内容检测的阈值要高一些
RHYTHM_VALIDATOR_THRESHOLD=70
FACT_VALIDATOR_THRESHOLD=80  # 历史事实/设定事实一致性校验的阈值要高一些

# 最大重试次数
MAX_RETRIES=3

记得把your-openai-api-key-hereyour-anthropic-api-key-here替换成你自己的API密钥。

1.4 创建项目依赖文件

创建一个requirements.txt文件,用来存储项目的依赖:

# LangChain核心依赖
langchain>=0.1.0
langchain-openai>=0.0.5
langchain-anthropic>=0.0.5
langchain-community>=0.0.10

# 大模型API依赖
openai>=1.0.0
anthropic>=0.18.0

# NLP依赖
transformers>=4.35.0
torch>=2.1.0
spacy>=3.7.0
zh-core-web-trf>=3.7.0  # 或者 zh-core-web-sm>=3.7.0
nltk>=3.8.0

# 数据分析依赖
pandas>=2.1.0
numpy>=1.26.0
matplotlib>=3.8.0
seaborn>=0.13.0

# 配置文件管理依赖
python-dotenv>=1.0.0
pyyaml>=6.0.0

# 其他依赖
tqdm>=4.66.0
colorama>=0.4.6

然后安装这些依赖:

pip install -r requirements.txt
1.5 创建配置管理模块

创建一个hsef/config.py文件,用来管理项目的配置,包括环境变量配置、风格约束配置等:

"""
HSEF配置管理模块
"""
import os
from dotenv import load_dotenv
from typing import Dict, Any, Optional
import yaml

# 加载环境变量
load_dotenv()


class Config:
    """
    HSEF配置类
    """
    def __init__(self, config_file_path: Optional[str] = None):
        """
        初始化配置类
        
        Args:
            config_file_path: 风格约束配置文件的路径(可选)
        """
        # 加载环境变量配置
        self._load_env_config()
        
        # 加载风格约束配置(如果提供了配置文件路径)
        self.style_constraint_config: Optional[Dict[str, Any]] = None
        if config_file_path is not None:
            self._load_style_constraint_config(config_file_path)
    
    def _load_env_config(self):
        """
        加载环境变量配置
        """
        # OpenAI API配置
        self.openai_api_key: str = os.getenv("OPENAI_API_KEY", "")
        self.openai_api_base: str = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
        self.openai_model_name: str = os.getenv("OPENAI_MODEL_NAME", "gpt-4-turbo-preview")
        
        # Anthropic API配置
        self.anthropic_api_key: str = os.getenv("ANTHROPIC_API_KEY", "")
        self.anthropic_model_name: str = os.getenv("ANTHROPIC_MODEL_NAME", "claude-3-opus-20240229")
        
        # 数据库配置
        self.database_type: str = os.getenv("DATABASE_TYPE", "sqlite")
        self.database_path: str = os.getenv("DATABASE_PATH", "./hsef.db")
        
        # 风格校验阈值
        self.character_validator_threshold: float = float(os.getenv("CHARACTER_VALIDATOR_THRESHOLD", "70"))
        self.writing_style_validator_threshold: float = float(os.getenv("WRITING_STYLE_VALIDATOR_THRESHOLD", "70"))
        self.scene_validator_threshold: float = float(os.getenv("SCENE_VALIDATOR_THRESHOLD", "70"))
        self.taboo_validator_threshold: float = float(os.getenv("TABOO_VALIDATOR_THRESHOLD", "90"))
        self.rhythm_validator_threshold: float = float(os.getenv("RHYTHM_VALIDATOR_THRESHOLD", "70"))
        self.fact_validator_threshold: float = float(os.getenv("FACT_VALIDATOR_THRESHOLD", "80"))
        
        # 最大重试次数
        self.max_retries: int = int(os.getenv("MAX_RETRIES", "3"))
    
    def _load_style_constraint_config(self, config_file_path: str):
        """
        加载风格约束配置
        
        Args:
            config_file_path: 风格约束配置文件的路径
        """
        if not os.path.exists(config_file_path):
            raise FileNotFoundError(f"风格约束配置文件 {config_file_path} 不存在")
        
        with open(config_file_path, "r", encoding="utf-8") as f:
            self.style_constraint_config = yaml.safe_load(f)
    
    def get(self, key: str, default: Any = None) -> Any:
        """
        获取配置项的值
        
        Args:
            key: 配置项的键
            default: 默认值(如果配置项不存在的话)
        
        Returns:
            配置项的值
        """
        # 先从环境变量配置中查找
        if hasattr(self, key):
            return getattr(self, key)
        
        # 再从风格约束配置中查找
        if self.style_constraint_config is not None and key in self.style_constraint_config:
            return self.style_constraint_config[key]
        
        # 返回默认值
        return default

这个配置类的核心优势是:

  1. 统一管理所有配置:把环境变量配置和风格约束配置都统一管理起来,方便使用。
  2. 支持动态加载风格约束配置:可以通过传入不同的风格约束配置文件路径,来加载不同的风格约束配置,方便复用。
  3. 支持获取配置项的默认值:如果配置项不存在的话,可以返回默认值,避免出现错误。

步骤二:构建大模型适配模块

接下来,我们需要构建一个大模型适配模块,用来适配不同的大模型(比如OpenAI GPT-4 Turbo、Claude 3 Opus等),方便我们切换大模型。

2.1 创建大模型基类

创建一个hsef/models/base_model.py文件,用来定义大模型基类:

"""
HSEF大模型基类模块
"""
from abc import ABC, abstractmethod
from typing import List, Dict, Any, Optional


class BaseModel(ABC):
    """
    HSEF大模型基类
    """
    def __init__(self, model_name: str, api_key: str, **kwargs):
        """
        初始化大模型基类
        
        Args:
            model_name: 大模型的名称
            api_key: 大模型的API密钥
            **kwargs: 其他参数
        """
        self.model_name = model_name
        self.api_key = api_key
        self.kwargs = kwargs
    
    @abstractmethod
    def generate(self, 
                 messages: List[Dict[str, str]], 
                 temperature: float = 0.7,
                 top_p: float = 1.0,
                 max_tokens: int = 2000,
                 frequency_penalty: float = 0.0,
                 presence_penalty: float = 0.0,
                 **kwargs) -> Optional[str]:
        """
        调用大模型生成文本
        
        Args:
            messages: 对话历史列表,每个元素是一个字典,包含"role"和"content"两个键
            temperature: 温度参数,控制生成的随机性,值越大越随机,值越小越确定
            top_p: top_p参数,控制生成的多样性,值越大越多样,值越小越单一
            max_tokens: 最大生成tokens数
            frequency_penalty: 频率惩罚参数,控制生成的文本中重复内容的出现频率,值越大越不容易重复
            presence_penalty: 存在惩罚参数,控制生成的文本中是否出现新的内容,值越大越容易出现新的内容
            **kwargs: 其他参数
        
        Returns:
            生成的文本,如果生成失败的话返回None
        """
        pass

这个大模型基类是一个抽象基类(ABC),定义了所有大模型适配类都必须实现的generate方法。

2.2 创建OpenAI模型适配类

创建一个hsef/models/openai_model.py文件,用来适配OpenAI的大模型:

"""
HSEF OpenAI模型适配类模块
"""
from typing import List, Dict, Any, Optional
from openai import OpenAI
from .base_model import BaseModel


class OpenAIModel(BaseModel):
    """
    HSEF OpenAI模型适配类
    """
    def __init__(self, model_name: str, api_key: str, api_base: str = "https://api.openai.com/v1", **kwargs):
        """
        初始化OpenAI模型适配类
        
        Args:
            model_name: OpenAI大模型的名称
            api_key: OpenAI的API密钥
            api_base: OpenAI的API基础地址
            **kwargs: 其他参数
        """
        super().__init__(model_name, api_key, **kwargs)
        self.api_base = api_base
        
        # 初始化OpenAI客户端
        self.client = OpenAI(
            api_key=self.api_key,
            base_url=self.api_base
        )
    
    def generate(self, 
                 messages: List[Dict[str, str]], 
                 temperature: float = 0.7,
                 top_p: float = 1.0,
                 max_tokens: int = 2000,
                 frequency_penalty: float = 0.0,
                 presence_penalty: float = 0.0,
                 **kwargs) -> Optional[str]:
        """
        调用OpenAI大模型生成文本
        
        Args:
            messages: 对话历史列表,每个元素是一个字典,包含"role"和"content"两个键
            temperature: 温度参数,控制生成的随机性,值越大越随机,值越小越确定
            top_p: top_p参数,控制生成的多样性,值越大越多样,值越小越单一
            max_tokens: 最大生成tokens数
            frequency_penalty: 频率惩罚参数,控制生成的文本中重复内容的出现频率,值越大越不容易重复
            presence_penalty: 存在惩罚参数,控制生成的文本中是否出现新的内容,值越大越容易出现新的内容
            **kwargs: 其他参数
        
        Returns:
            生成的文本,如果生成失败的话返回None
        """
        try:
            # 调用OpenAI API生成文本
            response = self.client.chat.completions.create(
                model=self.model_name,
                messages=messages,
                temperature=temperature,
                top_p=top_p,
                max_tokens=max_tokens,
                frequency_penalty=frequency_penalty,
                presence_penalty=presence_penalty,
                **kwargs
            )
            
            # 提取生成的文本
            generated_text = response.choices[0].message.content.strip()
            
            # 返回生成的文本
            return generated_text
        except Exception as e:
            # 打印错误信息
            print(f"调用OpenAI大模型生成文本失败:{e}")
            
            # 返回None
            return None
2.3 创建Anthropic模型适配类

创建一个hsef/models/anthropic_model.py文件,用来适配Anthropic的大模型:

"""
HSEF Anthropic模型适配类模块
"""
from typing import List, Dict, Any, Optional
from anthropic import Anthropic
from .base_model import BaseModel


class AnthropicModel(BaseModel):
    """
    HSEF Anthropic模型适配类
    """
    def __init__(self, model_name: str, api_key: str, **kwargs):
        """
        初始化Anthropic模型适配类
        
        Args:
            model_name: Anthropic大模型的名称
            api_key: Anthropic的API密钥
            **kwargs: 其他参数
        """
        super().__init__(model_name, api_key, **kwargs)
        
        # 初始化Anthropic客户端
        self.client = Anthropic(
            api_key=self.api_key
        )
    
    def generate(self, 
                 messages: List[Dict[str, str]], 
                 temperature: float = 0.7,
                 top_p: float = 1.0,
                 max_tokens: int = 2000,
                 frequency_penalty: float = 0.0,
                 presence_penalty: float = 0.0,
                 **kwargs) -> Optional[str]:
        """
        调用Anthropic大模型生成文本
        
        Args:
            messages: 对话历史列表,每个元素是一个字典,包含"role"和"content"两个键
            temperature: 温度参数,控制生成的随机性,值越大越随机,值越小越确定
            top_p: top_p参数,控制生成的多样性,值越大越多样,值越小越单一
            max_tokens: 最大生成tokens数
            frequency_penalty: 频率惩罚参数,控制生成的文本中重复内容的出现频率,值越大越不容易重复
            presence_penalty: 存在惩罚参数,控制生成的文本中是否出现新的内容,值越大越容易出现新的内容
            **kwargs: 其他参数
        
        Returns:
            生成的文本,如果生成失败的话返回None
        """
        try:
            # 把OpenAI格式的messages转换成Anthropic格式的messages
            # Anthropic的messages列表必须以user消息开头,不能有system消息
            # 我们把system消息拼接在第一个user消息的前面
            anthropic_messages = []
            system_prompt = ""
            for message in messages:
                if message["role"] == "system":
                    system_prompt += message["content"].strip
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐