我如何利用ChatGPT编写了自己的私人法语导师
逐步指南:如何使用最新的AI服务教我一门新语言,从架构到提示工程
讨论的外语导师的代码可以在我的GitHub页面的companion
仓库中找到,并且您可以自由地用于任何非商业用途。

所以在推迟了一段时间后,我决定继续学习法语。当我报名上课时,我突然想到:如果我能编程ChatGPT成为我的个人法语导师会怎样呢?如果我能跟它交谈,它也能回答我呢?作为一名与LLMs合作的数据科学家,我觉得这似乎是值得构建的东西。当然,我可以和我的法国妻子交谈,但那不如设计一个由ChatGPT构成的个人导师酷。
但现在说真的,这个项目不仅仅是“另一个酷炫的代码玩具”。生成式人工智能正在走向我们生活的每个领域,而大型语言模型(LLMs)似乎在这方面处于领先地位。现在,一个人在使用这些模型时所能做的事情令人瞠目结舌,我认为这个项目值得我花费时间,也值得您花费时间,原因有两个:
- 使用ChatGPT作为众所周知的在线工具很强大,但将LLM集成到您的代码中是完全不同的事情。LLMs仍然有些不可预测,当您的产品依赖于LLM(或其他任何GenAI模型)作为核心产品时,您需要学习如何真正控制GenAI。而这并不像听起来那么容易。
- 获得第一个可用版本只需要几天的工作时间。在GenAI和LLMs之前,这可能需要几个月的时间,而且可能需要不止一个人。使用这些工具来快速创建强大的应用的能力是您自己必须亲自尝试的——那就是我看到的未来。我们不会回到过去。
此外,这个项目实际上可以有所作为。我妈妈真的想找个人可以和她练习英语。现在她可以了,而且每月花费不到3美元。我妻子的妈妈想开始学习韩语。同样的事情,同样的费用。当然我自己也会使用它!这个项目真的帮助人们,而且每个月的费用还不到一小杯咖啡的价格。如果你问我,这才是真正的GenAI革命。
从零开始
从高层次的角度来看这个项目,我需要4个元素:
- 语音转文本,将我的声音转录成文字
- 大型语言模型,最好是一个可以向其提问并获得回答的Chat-LLM
- 文本转语音,将LLM的答案转换为声音
- 翻译,将我不完全理解的法语文本转换为英语(或者希伯来语,我的母语)
幸运的是,现在是2023年,上述所有内容都非常容易获得。我还选择使用托管服务和API,而不是在本地运行任何这些服务,因为这种推理方式将更快。此外,这些API在个人使用方面的低价格使得这个决定变得毫无疑问。
在尝试了几种替代方案后,我选择了OpenAI的Whisper和ChatGPT作为我的语音转文本和LLM,以及Google的文本转语音和翻译作为其他模块。创建API密钥并设置这些服务非常简单,我能够在几分钟内通过它们的原生Python库与它们进行通信。
在测试所有这些服务之后,真正让我震惊的是,我正在构建的导师不仅仅是一个英法教师;由于Whisper、ChatGPT和Google翻译与TTS支持数十种语言,这可以用来学习几乎任何一种语言,同时使用任何其他语言交流。这太疯狂了!

架构与线程
首先确保整体流程被充分理解:(1)我们首先录制用户的声音,将其(2)发送到Whisper API,并返回为文本。(3)文本被添加到聊天历史记录并发送到ChatGPT,后者(4)返回一份书面回复。其回复被(5)发送到Google Text-to-speech,返回一个将被(6)作为音频播放的声音文件。

我的第一步是将其分解为组件并设计整体架构。我知道我需要一个UI,最好是Web UI,因为现在通过浏览器启动应用程序比拥有独立的可执行文件更容易。我还需要一个“后端”,它将是实际的Python代码,与所有不同的服务进行通信。但为了提供实时流畅的体验,我意识到我需要将其拆分为不同的线程。
主线程将运行大部分代码:它将将我的录音转录为文本(通过Whisper),将此文本显示在屏幕上作为聊天的一部分,并将导师的书面回复显示在聊天屏幕上(由ChatGPT接收)。但我将需要将导师的文本转语音移到一个单独的线程中-否则,我们将会出现以下情况:
- 只有在从ChatGPT接收到整个消息后,才能听到导师的声音,而且它的回复可能很长
- 当导师正在说话时,它会阻止用户做出响应
这不是我希望的“流畅”行为;我希望导师在其消息写在屏幕上时开始说话,并且当音频仍在播放时,确保不阻止用户做出响应。
为了做到这一点,该项目的文本转语音部分被拆分为两个额外的线程。当从ChatGPT逐标记地接收到导师的回复时,将每个完整的句子传递给另一个线程,然后将其发送到文本转语音服务,将其转换为声音文件。这里我想强调的是“文件”一词-因为我正在逐句发送文本到TTS服务,所以我也有多个音频文件,每个句子一个,需要按正确的顺序播放。这些声音文件然后从另一个线程中播放,确保音频播放不会阻塞程序的其他部分运行。
使所有这些工作正常运行,以及源自UI和服务器交互的其他一些问题,是这个项目的复杂部分。令人惊讶吗-软件工程是事情变得困难的地方。
设计UI

嗯,我知道我需要一个UI,并且我也大致知道我想要它的样子-但编写一个UI超出了我的知识范围。所以我决定尝试一种新颖的方法:我请ChatGPT帮我写UI。
为此,我使用了实际的ChatGPT服务(而不是API),并使用了GPT-4(是的,我是一个自豪的付费用户!)。令人惊讶的是,我的初始提示:
为聊天机器人应用程序编写一个Python Web UI。用户输入提示的文本框位于屏幕底部,所有先前的消息都保留在屏幕上
给出了一个令人惊叹的第一个结果,最终得到了Python-Flask后端,jQuery代码,HTML和相匹配的CSS。但那只占我希望获得的所有功能的80%,所以我花了大约10个小时与GPT-4来回交流,逐步优化和升级我的UI。
如果我让它看起来简单,那我不想明确地说它并不简单。我增加了更多的请求,GPT-4就越困惑,交付出故障的代码,有时手动修复比要求它修复更容易。我有很多请求:
- 在每个消息旁边添加个人资料图片
- 为每个消息添加一个重新播放音频的按钮
- 为每个法语消息添加一个按钮,将其翻译添加到原始文本下方
- 添加保存会话和加载会话按钮
- 添加暗模式选项,使其自动选择正确的模式
- 在等待服务的响应时添加“工作”图标
- 还有很多很多…
尽管通常情况下,GPT的代码从未可以直接使用,但考虑到我在前端领域几乎没有知识,结果令人惊叹——远远超出了我通过谷歌搜索和StackOverflow能够做到的任何事情。我在学习如何制作更好的提示方面也取得了很大进步。想想看,也许我应该写一篇关于从零开始构建产品并与LLM并行的经验教训的博文…敬请期待!
提示工程
在本文的这部分,我假设您对如何通过API与Chat LLM(如ChatGPT)进行通信具有一些基本知识。如果您对此不了解,可能会有点迷失。

最后但绝对不是最不重要的——我必须让GPT扮演私人导师的角色。
作为起点,我在聊天的开头添加了一个系统提示。由于与LLM的聊天基本上是用户和机器人互相发送的消息列表,系统提示通常是聊天的第一条消息,它向机器人描述了它应该如何行事以及对它的期望。我的提示大致如下(花括号括起来的参数会被运行时值替换):
您是一名名为{teacher_name}的{language}教师。您与学生{user_name}进行一对一辅导。{user_name}的{language}水平是:{level}。您的任务是帮助学生提高{language}水平。* 会话开始时,为{user_name}提供适当的会话,除非要求其他内容。* {user_name}的母语是{user_language}。{user_name}在感觉到自己的{language}不够好时可能会用自己的语言与您交流。当发生这种情况时,请先将他们的消息翻译成{language},然后回复。* 重要提示:如果学生犯了任何错误,无论是拼写错误还是语法错误,您必须先纠正学生,然后再回复。* 您只能使用{language}说话。
实际上,这的确取得了不错的结果,但随着聊天的进行,我给机器人的行为指令(“在我说错的时候纠正我”,“总是用法语回复”)的有效性似乎在逐渐减弱。
为了对抗这种消失的行为,我想出了一个有趣的解决方案;在将用户消息发送给GPT之前,我操纵了用户消息。无论用户的消息是什么,我都在其后面添加了额外的文本:
[用户消息在此]---重要提示:* 如果我用{language}回答并犯了任何错误(语法、拼写等),您必须在回复之前纠正我* 您必须保持会话的流程,您的回复不能结束会话。尽量避免“您想做什么”这样的广泛问题,而是提供与之相关的问题和练习。* 您必须用{language}回复。
在每个用户消息的末尾添加这些内容确保LLM的回复完全符合我的期望。值得一提的是,我添加的长后缀是用英语写的,而用户的消息可能不是。这就是为什么我在原始消息和我的附加内容之间添加了一个明确的分隔符(---
),终止了原始消息的上下文并开始了一个新的上下文。还要注意,由于这个后缀是添加到用户的消息中的,它是以第一人称(“我”,“我”等)写的。这个小技巧极大改善了结果和行为。虽然这可能是不言而喻的,但值得强调的是,这个后缀不会显示在聊天界面上,用户不知道它被添加到他们的消息中。它是在幕后插入的,在与ChatGPT的聊天历史一起发送之前。
我想要的另一个行为是让导师先说话,也就是说,在会话开始时,ChatGPT会发送第一条消息,而不需要等待用户发起会话。显然,ChatGPT并不是为此而设计的。
当我尝试让ChatGPT在只包含系统提示的消息历史上进行回复时,我发现ChatGPT“迷失了方向”,开始自己和自己对话,扮演用户和机器人的角色。无论我尝试了什么,都无法使其在用户先说话之前正确地开始会话。
然后我有了一个主意。当会话初始化时,我代表用户向ChatGPT发送了以下消息:
向我问候,并建议三个适合我水平的可选课程主题。你必须用{language}回复。
这个请求的设计是为了使GPT的回复看起来正好符合我认为机器人正确初始化会话时的样子。然后,我从对话中删除了我的消息,并让它看起来像是机器人自己发起了会话。
总结

这个有趣的小念头开始变成现实,几乎在一眨眼的功夫内完成,完全是由一个非常忙碌的人在业余时间完成的。这样简单创建任务的事实令我叹为观止。就在一年前,像ChatGPT这样的东西还是科幻,而现在我可以在自己的个人笔记本上塑造它。
这是未来的开端,无论未来会带来什么,至少我知道我会准备好迎接它,掌握一门外语。再见!