ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从反馈真空到AI写作教练:一款英语写作APP的技术实现与成本优化

从反馈真空到AI写作教练:一款英语写作APP的技术实现与成本优化

很多人学英语卡住的地方,不是词汇量不够,而是写完之后“没人管”。上大学那会儿我写英文作文,交上去要等老师好几天才能返回来,批注还多半是几句“注意时态”“表达不地道”这类笼统的话。工作以后写英文邮件,自己读三遍觉得没毛病,发给母语同事再一看,还是在礼貌程度、句式自然度上被委婉地挑出问题。这种“缺乏即时反馈”的困境,恰恰是AI英语写作APP最值得解决的核心痛点。

于是我自己动手做了一个面向英语学习者的写作训练工具,定位是“随叫随到的AI写作教练”,而不是“一键帮你写完全文”的生成器。这篇文章会把整个项目的需求分析、技术选型、Prompt工程、成本控制、踩坑记录和评测方法完整拆出来讲,内容会偏向实操,适合想用大模型做垂直应用的开发者、独立开发者,或者正在规划AI教育类产品的产品经理参考。

1. 需求洞察:先搞清楚用户到底要什么

1.1 英语写作的反馈真空,才是真痛点

市面上的翻译工具解决的是“我不会表达”,但写作训练的最大问题不是“不会表达”,而是“表达之后没有高质量反馈”。我梳理了三类核心用户,痛点差异很明显:

  • 学生群体:写作文、写申请文书,老师批改周期长,而且批改集中在扣分点上,很少有人告诉你“这句话为什么不对、下次怎么避免”。
  • 职场人群:英文邮件、会议纪要,用户往往不是不懂语法,而是担心语气不礼貌、表达不简洁、用词不专业,这类反馈恰恰是普通语法工具给不了的。
  • 备考人群:雅思、托福等考试有现成评分维度,用户需要知道自己“为什么是6分而不是7分”,需要的是维度化诊断和提升路径。

三类用户的共同诉求是:即时反馈、解释清楚、给出可执行的修改方向。这就决定了产品不能只做一个“查错工具”,而要做成一个能解释、能示范、能打分的辅助教练。

1.2 MVP功能边界:只做输入、批改、反馈的闭环

项目启动时其实很容易犯“功能越多越好”的毛病。我们最早列了十几个功能,包括智能扩写、全文重写、风格模仿、语音朗读、生词标注、长难句分析等等,后来全部砍掉,第一版只保留了三个核心能力:语法与拼写纠错、表达润色、维度评分。理由很简单:先验证“AI写作教练”这个体验模型是否成立,再谈功能的宽度。

就拿润色来说,我们尝试过“一键改写全文”这种激进方案,结果内测用户反馈并不好。原因是:当AI把整篇作文全部改写之后,用户根本不知道哪些地方需要学,反而产生了一种挫败感。后来我们把润色拆成“逐句可选的修改建议”,让用户自己决定接不接受,接受率反而大幅提升。这个细节后来成为整个产品的设计基石:AI建议是可交互的建议,不是替代你的终稿。

1.3 坚决不做“一键代写”的考量

说句实在话,以现在大模型的能力,做“用户输入一个中文题目,AI直接生成一篇地道英文作文”是技术上最容易实现的。但我们最终没有把它放进主流程,原因有三层:第一,这个功能会诱导学术不端,尤其在学生用户中会带来严重的合规风险;第二,从产品价值看,它培养的不是写作能力,而是对AI的依赖;第三,从调性和留存看,真正让用户持续打开APP的,是“我自己改出来的句子”带来的成就感。

所以整条产品线走的是“教练”路线:用户必须自己写,AI负责发现问题、解释问题、示范更好的表达,但绝不在没有用户参与的情况下直接产出整篇成品。这样的工具,才经得起时间的检验。

2. 技术架构选型:规则引擎在前,大模型在后

2.1 整体架构:客户端、业务服务、模型层三层分离

项目第一版就采用了清晰的分层架构,而不是把所有逻辑塞进客户端。核心考量是:大模型调度、敏感内容过滤、用户数据缓存、评测日志这些能力必须集中在服务端,否则客户端每次发版都会阻塞产品迭代。

  • 客户端:跨端开发框架,同时覆盖小程序和移动端,首版以微信小程序为主,降低用户获取成本。客户端只负责文本输入、结果渲染和交互反馈,不直接调用大模型。
  • 业务服务层:用Python异步框架搭建,负责用户鉴权、文章解析、缓存判断、规则引擎检测、大模型调用编排、结果格式校验。所有业务逻辑都在这一层收敛。
  • 模型层:统一封装大模型API网关和开源自托管模型的接口,上层业务无感知切换。文本安全审核也在这里以插件形式接入。

这个分层在项目后期帮了大忙。我们尝试替换不同模型服务商时,业务服务层几乎没动,只改了模型层的一个适配接口。

2.2 模型选型:商业API先跑通,开源私有化再降本

模型选型的核心不是“谁的分数高”,而是“你的业务对数据敏感性、成本、延迟的容忍度”。我第一版全部走商业大模型API,因为上线速度最快、效果最稳定;到第二版访问量上来之后,才开始调研开源自托管方案。

  • 商业API:文本质量好,多语言理解能力强,不需要自己维护推理集群,适合冷启动阶段。
  • 开源自托管模型:一次付费后边际成本低,数据不出内网,适合用户量稳定后分流一部分高频简单请求。缺点是需要自己解决推理部署、并发和负载问题。

这里有个小经验:不要急着私有化全部流量。我们一开始把低难度请求切到开源模型,发现某些复杂语法句法场景下质量下降明显,于是改成“按文本难度分流”:简单文本走开源模型,复杂文本走商业API,两端各发挥优势。

2.3 为什么要在前面加一道规则引擎

很多同行做AI写作产品时,把“纠错”完全交给大模型。这是让成本失控最常见的原因。我们第一版上线一周,发现账单增长比用户增长还快,仔细分析之后,决定在所有大模型调用之前加一个“规则引擎前置过滤器”。

规则引擎负责处理那些确定性很强的基础错误:单词拼写、主谓一致、冠词缺失、时态基础错误、明显的中式搭配等等。这类错误大约占用户文本错误总量的35%到45%,而且在规则库中已经覆盖得不错,不需要大模型介入。

我做过一笔粗略的账:假设每次用户提交一篇150词的短文,输入约1800个token,如果全部走大模型,一次请求成本在某个档位;加上规则引擎之后,约40%的请求可以在只返回规则检测结果、不调用大模型的情况下完成——也就是说,这部分请求的成本直接从单次计费降到几乎为零。同时规则引擎返回结果速度更快、可解释性更强,用户能看到“这是固定搭配问题”这种确定性反馈。在不动体验的前提下,这个大前置让整体API成本下降了约30%。聊技术的人常说“降低延迟、降低成本”,我觉得真正有效的降本手段永远是架构级的:能不用大模型的地方,就不用。

3. 核心功能拆解与实现:从“找出错误”到“给出可行动的反馈”

3.1 分句与预处理:为什么不能整篇丢给模型

早期原型图省事,用户提交整篇作文后直接拼进Prompt发给模型,结果出现两类问题:第一,输入超长导致接口超时;第二,模型对长文的关注度被稀释,经常出现漏改、误改。后来我把处理流程改成:先分句,再逐句(或按句组)送入模型,最后合并结果。

分句没有直接用第三方库,而是自己维护了一套规则,原因是有个坑:英文论文里常见的缩写词“Prof.”“e.g.”“Mr.”后面那个点,在通用分词器那里往往被判定为句子结束符。我们早期就因为这个问题,把人家一句话拦腰截成两半喂给模型,结果模型在断句处脑补了一堆不存在的错误。后来加了缩写词白名单,只在词尾点号后跟随大写字母且该词不属于白名单时才判定为句子边界。

分块方面,如果单个句子特别长(超过80个词),我们还会按从句边界再切成子句块,并保留前后各一小段上下文作为“重叠窗口”,防止模型因为缺少语境而误判指代关系。这套预处理逻辑虽然不起眼,但直接影响后续所有环节的准确率。

3.2 批注式输出:纠错结果的数据结构设计

为了让前端能稳定渲染修改建议,我们跟模型约定了一种结构化的返回格式。每次检测一个句子,模型需要返回包括错误类别、原文片段、修改建议、解释说明、严重程度在内的JSON数组。这个设计很好用,前端拿到之后可以直接渲染成“错误列表 + 文本高亮”的复合视图。

比如这样一条返回:

{ "sentence_id": 3, "original_sentence": "He go to school yesterday.", "issues": [ { "error_type": "主谓一致", "error_severity": "high", "original_text": "go", "suggestion": "went", "explanation": "根据yesterday判断时态应为一般过去时,go的过去式是went。", "is_grammar_error": true } ] }

这种结构化设计最大的好处是“可解释”。用户看到的不只是“go错了”,而是每一处错误都有类型标签、等级、建议和解释,点开还能看到这句话为什么错。这也帮助我们后续做用户错题本和薄弱点分析,因为所有错误类型都是结构化存储的,可以直接做数据聚合。

3.3 三种强度的润色模式:从“改对”到“改好”

纠错解决的是“对错”问题,润色解决的是“好坏”问题。我们给润色设计了三个强度级别,用户可以选择:

  • 保守型:只调整明显不自然、不地道但不算错的表达,保留原句结构和学习者的用词偏好。适合日常笔记、初稿练习。
  • 均衡型:在保留原意基础上,优化句式结构、替换更准确或更正式的用词,适合邮件、申请书、作文定稿场景。
  • 大胆型:允许大幅度重构句式,使表达更贴近母语者习惯,适合润色自己反复写了但始终不满意的句子。

这个设计背后有一个很关键的洞察:改写的强度越大,用户的学习收获就越难保证。如果你直接把一句普通英语改成高级长难句,用户多半只会觉得“哇好厉害”,但完全不知道是怎么变的。所以我们给每个润色建议都附带了“改动原因”,并且在“大胆型”模式下额外给出“原句-过渡句-最终句”三阶段展示,让用户能看到一条清晰的变化路径。实测下来,均衡型的使用率最高,保守型次之,大胆型用得最少但用户粘性最强——因为能啃下这种句子的用户,学习动机本来就很高。

3.4 维度评分:从“一个分数”到“一幅画像”

评分功能我们参考了常见英语写作评分维度,设计了五个评分项:语法准确性、词汇丰富度、句式多样性、内容连贯性、任务完成度。每个维度输出四个等级,并附带一句简短评语和两个改进方向。

为什么不用单一总分?因为单一分值对提升没有指导意义。用户看见一个6分没有任何行动方向;但如果告诉他“词汇丰富度处于C等,原因是重复使用了good和important,建议替换为significant、essential、crucial”,他就知道下一步该干什么。这也是整个产品“教练感”的核心体现:给出诊断,给出处方,而不是只有一个判决。

这里有一个技术细节:我们要求模型在评分时必须引用原文中的具体例子作为依据,比如“你在第2段重复使用了3次important”。这样可以防止模型给出一堆通用废话。如果模型找不到依据,宁可判定为“样本不足”,也不会硬凑理由,这也是Prompt工程里重点约束的内容。

4. Prompt工程与输出控制:驯服不稳定的LLM是核心功课

4.1 从自由文本到结构化JSON的版本演进

很多人第一次接大模型,都喜欢让AI“自然回答”,结果前端没法稳定解析。我们在这块也走过弯路,Prompt工程一共经历了四个大的版本迭代:

  • v1:自由文本。让模型直接输出“第X句有个错误,应该改成XX”。结果格式五花八门,前端解析成本极高,经常漏掉后半段建议。
  • v2:增加格式要求。明确要求“以JSON数组返回”,效果好很多,但偶尔模型会夹杂解释文字,导致解析失败。
  • v3:增加示例。在Prompt里给出1到2个输入输出的few-shot示例,输出稳定性明显提升,格式符合率超过95%。
  • v4:字段级约束与降级兜底。进一步限定每个字段的候选枚举值(比如error_type只能从给定集合取),并在业务层加入正则解析兜底,彻底解决了解析率的问题。

最终版纠错任务的系统指令大概长这样,分享一个简化版本:

你是一名专业的英语写作导师。你的任务是帮助学习者修改英文句子。 要求: 1. 只处理英文文本,不要改变原文意图,不要重写整句。 2. 找出所有需要修改的错误,包括语法错误、词汇搭配、表达不自然。 3. 使用UTF-8 JSON数组返回,不要输出任何解释文字。 4. 每个错误对象必须包含以下字段: - error_type:只能是 ["拼写", "时态", "主谓一致", "搭配不当", "冠词", "介词", "句式冗余", "表达不地道"] - original_text:原文错误片段 - suggestion:修改后的正确表达 - explanation:用中文解释为什么这样改,不超过20个字 5. 如果没有错误,返回空数组。 示例输入:He go to school yesterday. 示例输出:[{"error_type": "时态", "original_text": "go", "suggestion": "went", "explanation": "由yesterday可知应为一般过去时"}]

这类结构化约束的Prompt,本质上是把大模型当成一个需要写清接口文档的组件来用。我在实际调试中发现,在Prompt里给枚举值和示例的效果,远比增加命令性措辞(比如“务必”“绝对不能”)要好。模型更擅长模仿例子,而不是服从抽象指令。

4.2 JSON解析容错:不能只靠一次解析成功

就算Prompt写得很规范,模型偶尔也会输出带markdown代码块标记、或者某个字段多了一个逗号的非法JSON。我们在业务层做了三层容错:

第一层:尝试标准JSON解析器;第二层:用正则剥离多余文本(比如 ```json 开头和结尾标记),提取出最外层中括号内的内容再解析;第三层:如果还是失败,把这次请求标记为“解析失败”,自动发起一次带“请严格只输出JSON数组”补充指令的重试。整套兜底下来,最终解析失败的比例被压到了0.1%以下。

这里还有个隐藏问题——模型返回空结果不一定是没错误,也可能是懒。我们在内测中遇到过几次:明显有错误,模型却返回空数组。查了日志发现是用户文本里包含中文字符,模型把它当成“不要处理中文”的指令,于是跳过整句。后来在Prompt里加了一条“中文部分只是背景说明,不需要修改,但英文句子中的错误仍然必须找出”,情况才改善。这类细节很难在通用文档里查到,全靠真实语料踩出来。

4.3 中英混杂文本的特殊处理

中国用户的写作习惯和纯英文母语者差别很大——很多人写英文作文时会夹杂中文备注,比如“这里我觉得用让步关系更好”,或者干脆整段思维是中文的逻辑。这类文本如果直接丢给模型,往往会出现两种极端:要么模型忽略错误只回复中文,要么模型把中文拿过来强行改成英文句子。

我们的处理策略是:在预处理层先把中文和英文分离开,识别出“纯中文段落”和“中英混合句子”。对纯中文段落不做纠错,只提示“本篇仅检测英文内容”;对中英混合句子,在Prompt中明确告知模型“忽略中文部分,仅检测英文部分,但误解中文会干扰原文意图”。事实证明,明确告知“忽略某部分内容”能显著减少模型的误操作。这一点对所有做“多语言夹杂场景”的开发者都有参考价值。

5. 上下文管理与成本优化:1万日活背后的账单控制

5.1 多轮改写的历史管理

用户在产品里不会只改一遍。往往一次提交之后,他会根据建议改一回、再改一回,反复两三轮。如果不做历史管理,第二轮的输入就会带上第一轮的全文,上下文越来越长,到第三轮可能就把整个会话的历史都拼进去了,token消耗翻倍。

我们的做法是:服务端保存用户的每一版文本,但每次调用模型时,只传入“上一版全文 + 当前版本中发生变化的句子列表”。这样既保留了改动脉络,又不会把历史垃圾全部灌进Prompt。一个用户修改三次同一篇文章,总token消耗大约是直线拼接方式的60%左右。

5.2 文本指纹缓存:相同文本不重复调用

写作工具场景其实天然存在大量重复提交:用户改了某个句子、重新粘贴全文;同一个班级的老师给学生安排同一篇作文,几十个学生会提交相似度极高的文本;还有用户自己反复提交同一篇文章测试效果。这类请求如果每次都走大模型,其实就是白烧钱。

我们在业务层加了一层缓存:对提交文本做归一化(转小写、去多余空白),然后计算哈希值作为指纹,命中缓存就直接返回结果,只有新内容才触发真实调用。这个策略上线后,API调用量直接降了30%,而且用户的响应速度从原来的3秒变成毫秒级。这里的关键是缓存不能只存结果,还要存住结果的过期时间,因为模型升级后旧结果不一定还准确,我们给缓存设置了7天有效期,模型版本更新时自动清空。

5.3 分级调用:简单任务走规则模型,复杂任务上大模型

前文提到规则引擎前置过滤,这里展开讲讲更细的分级策略。经过对线上数据的分析,我们发现用户提交的文本里,大约40%的基础错误(如拼写、简单主谓一致)用规则引擎就能高质量解决,另外30%需要上下文理解(如搭配、时态选择),只有剩下的复杂场景才真正需要大模型的语义能力。

于是我们设计了一个三级漏斗:

级别处理方式适用错误类型单次请求成本特征
一级规则引擎直接返回拼写、简单语法、固定搭配几乎为零,毫秒级
二级开源自托管小模型时态选择、介词用法、中等改写极低,私有化部署
三级商业大模型API复杂句式重构、地道性、维度评分正常计费

这套漏斗把一个典型的100词短文批改请求,从“全量走商业API”改为“80%的请求仅走到第一或第二级”,综合成本下降了接近一半。我认为这是所有AI应用开发者都应该优先考虑的架构:先用低成本方案消化大部分请求,让昂贵的大模型只处理它真正擅长的复杂任务——语义理解与创造性表达。

6. 上线前后踩坑实录:那些文档里查不到的教训

6.1 缩写词把句子拆成两半

这个坑在前面提过,但值得单独再强调一遍。我们在分句逻辑里遇到的最大意外就是缩写词。像“Prof. Smith”“e.g. Apple”“Mr. Zhang”这些词,通用分句规则会把缩写符当成句子结束。处理方式看起来很简单——加一个缩写词白名单,但实际维护起来特别麻烦:各学科缩写词持续增长,而且用户在写作中可能用不标准的缩写。

后来我们想了一个更稳的方案:根据两个特征同时判断——点号后是否有空格and下一个词是否以大写字母开头,再结合白名单做加权判断。这样一来,被误拆的句子比例大幅下降。即便偶尔判断错误,后续也会被合并逻辑兜底,把相邻两个过短句子块重新拼成一句,保证模型不会在断句处产生幻觉错误。

6.2 用户整篇粘贴导致超时和截断

上线的第一个星期就有用户反馈“为什么我贴了500词的文章,转圈半天告诉我超时?”查了日志发现,模型的输出长度上限是写死的,而一篇500词的作文解析结果远超这个上限,于是接口直接截断,前端解析失败,进入重试循环,又造成更大的并发压力。

我们调整了策略:按句子粒度分批请求,并行度控制在3到5个并发,用队列机制削峰。前端拿到结果时可以一条一条渲染,用户看到的是“第一句改完了,第二句正在检查”的渐进式体验,心理感知明显更好。同时给整个请求链路设置了总超时时间,如果某个批次失败,只重试那一批,不影响整个文章的其余部分。

6.3 模型把学习者的“简单风格”过度改写成“炫技风格”

这个问题的发现很有意思:某内测用户提交了一篇用简单句写得很清晰的作文,结果系统在润色模式下把大半句子都改成了复杂从句叠加的“炫技文”。用户反馈“这不是我的文风了,我根本读不下去”。我们复盘后认为,问题出在Prompt里“让表达更地道”这个指令被模型理解成了“让句式更复杂”。

调整方案有两个层面:第一,在润色要求中增加“保留作者原有风格与句式偏好,除非原表达有明显问题”;第二,在业务层加入“最小必要改动”的控制逻辑——用diff算法计算建议文本与原文本的修改跨度,跨度过大时降低推荐优先级,并主动给用户展示两种方案(最小改动版和优化版)。这个设计后来成了润色功能的体验护城河:用户信任你,是因为你尊重他的表达,而不是把他变成另一个人。

6.4 安全审核与写作用途引导

做教育类产品,内容和合规问题不能回避。我们上线时就接入了内容安全检测接口,对用户提交的文本做前置过滤,出现不合规内容时给出统一提示,不让这类文本进入大模型检测流程。同时,产品内设置了对应的使用协议和免责声明,明确说明“AI建议仅供学习参考,涉及学术提交或正式场合使用时,请自觉遵守相应规范”。

刚开始我们担心做内容过滤会影响用户体验,毕竟用户只是来学英语的。但实际运行后发现问题概率极低,而且一旦出现就必须严格处理,不然产品的社会责任边界就模糊了。这里想提醒所有做类似产品的同行:功能上线之前先想清楚边界,比上线后补救容易得多。

7. 评测与迭代:把“我觉得好用”变成“数据说了算”

7.1 建一个属于自己的评测集,别只看Demo效果

大模型产品迭代最怕的就是“凭感觉”。今天换一个Prompt,觉得效果好一点;明天换一个模型,又觉得差一点,但到底是好是坏,说不清楚。我们第二个月就在内测用户群里征集了一批匿名作文样本,重建了一整套评测流程。

评测集由约300篇真实学生作文组成,覆盖不同水平、不同题材,并且由英语老师参与标注了“正确修改”和“错误级别”。每次迭代模型或调整Prompt,我们都会在这套评测集上跑一遍,对比修改精确率、漏改率、误报率等指标。评测集的价值是让你摆脱“某个例子看着好”的错觉。

7.2 关键指标:Precision/Recall、采纳率、改写幅度

这个产品要看的核心指标,我认为有三个维度:

  • 修改精确率与召回率:建议修改中真正正确的比例;原文中实际错误被发现的百分比。这两个指标互相制约,Prompt太激进则精确率下降,太保守则召回率下降。
  • 用户采纳率:用户对AI建议点击“接受”的比例,反映了建议的合理性和可操作性。我们实测正常范围在45%到60%之间。
  • 端到端延迟:从用户点击按钮到完整渲染结果的时间。我们设定的目标是平均2.5秒内完成一篇100词短文。

尤其是用户采纳率,这个指标比模型在离线评测集上的分数更能说明问题——毕竟离线分数高不意味着用户愿意接受你的改法。我们做了一次比较大的版本升级后,离线指标提升了8%,但用户采纳率反而下降了3%,就是因为新版本建议偏“语感化”而偏离了用户的认知水平,后来回退了部分改动。

7.3 灰度发布与实时反馈闭环

每个新Prompt或模型参数上线前,我们都走“小流量灰度-数据对比-全量发布”的流程。灰度比例一般是5%,观察一两天内关键指标的变化,再做决策。此外,每个建议条目后面都带一个“有帮助/没帮助”的轻量反馈按钮,用户点击结果会回流到埋点系统,用来持续修正Prompt用词和模型选型。

这个反馈闭环的效果非常明显。比如我们发现“解释过长导致用户不看”这个问题,就是在反馈数据里看到的——很多用户对长解释直接划掉。后来我们把解释压缩到20个字以内,并且优先展示“错的点+正确用法”,采纳率回升了7个百分点。让用户用行为投票,比任何内部讨论都可靠。

写在最后

回头看这个项目,最深刻的体会不是“用了多先进的大模型”,而是“如何让AI成为一个负责任的学习伙伴”。这中间有太多细节需要平衡:既要纠正错误,又不能破坏学习动机;既要提升表达,又不能替代用户思考;既要追求效果,又要把成本控制在可持续的范围内。整条链路里,真正的工程量有一半在模型之外的业务层——分句、缓存、降级、评测、反馈闭环——这些看起来“不性感”的部分,恰恰决定了用户体验的下限。

如果你也在规划类似的AI教育应用,我给一个非常具体的建议:留出专门的时间建一套离线评测集,把评测自动化脚本写到项目工程里。有了这套东西,你后面做Prompt迭代、模型替换才能大胆去试。再就是,尽早把成本画像算清楚,哪怕只是一个估算表,都能让你在做架构决策时少走很多弯路。

这个项目后续还有很多可以扩展的方向,比如针对不同考试风格(学术写作、商务邮件、日常表达)定制评分模型,或者根据用户历次错误记录自动生成个性化练习。技术上都可行,但优先级要取决于用户反馈会指向哪里。做产品就是这样——听数据的声音,尊重用户的真实需求,然后一步步把“看起来能用”打磨成“用了就离不开”。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进