这个工具源自一场等待。
记得早在 2025 年初的时候,我就向官方网站提交了永久居留的申请。准备过程非常繁琐,包含许多材料,还需要公司以及房东的签名。我本以为整个流程几个月就可以结束,但结果拖了半年多才得到反馈。
那是一条由系统生成的邮件,排版丑陋且充满错误。其中仅有一条是签证官的回复,看上去还算是有点儿 「人类的味道」。上面写着,让我在两周之内提交入籍考试通过的证明,否则就要强制撤回申请。我对这个本该期待已久的回复感到诧异,因为官方网站上赫然写着:为了证明融入德国的程度,要么提供德国大学毕业证明,或是提供入籍考试证明。我盯着那个「或」字看了半天,确定自己没有看错。后来我拿着法律条文和官网信息去找他们申诉,但返回的结果依旧是 ” 要考试证明,要考试证明 “。感觉像是在和上了发条的机器对话,甚至还不如 GPT 的回复。
后来想着辩解太多也是白费力气,就别计较了,考了算了。网上再一查消息,最近的考试也要在三个月之后,大概是因为人数太多,爆满了。报名的方式也非常复古,是那种线下报名的方式。我能理解线下考试是为了确认身份、确保没有作弊,但都 2025 年了,居然报名也要线下实地进行,这着实让我百思不得其解。
大概在考前一个月,我开始慢慢收集和考试有关的消息,比如规则、题目类型之类。简单在 Google 输入关键词,就能找到一大堆题目网站,有官网的,也有民间的,还有收集好题目做成 PDF 的。
我浏览了一下这些排名靠前的网站,发现它们都不太符合我的需求。
首先按常理来说,入籍考试面对的是非德国人,竟然没有任何一个网站提供多语言支持。我的母语是中文,虽然也学过德语,即便让我用德语刷也没问题,但有时也想看看翻译,以确保我的理解没错。但我没有找到有任何网站支持这一点。
其次是刷题的方式,大概是受到了官方网站的启发,几乎所有网站都是 「一个页面一道题目」,选择后跳出答案,点击按钮才进入下一题。我无法看到刚才答题的结果,也没有一个全局的概览。如果想针对性地看看错误的题目,就需要一个个往回点击,十分不方便。
最后是样式。在网页技术和 AI 技术日新月异的今天,竟然大部分网页的样式都非常简陋且繁杂。各种奇怪的样式、字体,还有不明所以的图片到处乱飞。我就是想要刷题,给我题目、答案还有是否正确就好,何必搞得如此花里胡哨?我不明白。
经过简单的调研和思考,想到技术实现并不复杂,我当即决定要自己做个刷题工具。媒介就是网站,足够便宜,也要简单干净,满足 「哪里都可以刷题」 的需求就好。
整体思路是这样的:首先设计最基本的数据结构,结构上天然就支持多种语言;其次填充数据并加入多语言;再来才是制作网站,加入样式和核心逻辑功能;最后是部署。虽然描述是有顺序的,但做的时候都是并行穿插的,比如「网站部署」和「数据收集」就是同时完成的。我很享受网站被实现的那一刻。
最初,我用的是 Google 的 AI Studio,可以免费使用 Gemini 2.5 Pro。这个模型对长上下文非常友好。一般的数据处理任务,我会把想要的输入和输出格式交给它,然后让它给我返回 Python 或 Bash 脚本。在每次提示中,我都会要求它尽量输出简单且容易理解的脚本,确保我能快速浏览和理解代码,这样对检查 Bug 更友好,我也觉得更有控制力。
原始数据的语言是德语,格式是 JSON。多语言部分,我使用了额外的脚本,配合 OpenRouter 的 Qwen/Qwen3-Max 模型,价格便宜并且对多语言支持很不错。
域名还有部署,都使用的是 Cloudflare。域名价格不算很高,可以一键配置部署好的平台。平台是它的 Pages 服务。每当代码写好,Pipeline 自动触发,生成静态网站并自动部署,同时它还额外提供分支预览功能,对开发非常友好。
顺带一提,我的博客用的也是类似的技术。
完成了基础的平台搭建和数据填充,终于可以正式开始设计网站了。网站的 Framework 使用的是 AstroJS,既有 HTML 和 JS 朴素的优点,又支持模块化并兼容其他现代化框架。我感觉它是一个非常有东方味道的框架,兼容并蓄。
做网页开发的时候,我秉持的一个信念是:代码和文件必须保持精简,一个文件中可以完成的,绝不放在第二个文件中。太多的模块和文件会让应用变得复杂,也让我理解起来变得困难。另外,如果我想增加新功能或修复 Bug,我可以直接将包含全部上下文的代码发送到 Gemini 中。模型能快速定位,迅速解决问题。
十几轮对话之后,工具就已经初具规模。它包含了最基础的样式,能显示所有的题目,能点击并且提示对错。在此之后的几天,我陆续加入了语言翻译、重置答案、预览结果等等功能。我对此非常满意,即使在地铁站或公交车上,也可以打开浏览器快速地做题。
随着自己的使用,我体验出了一些使用不便的地方,比方说夜间模式,还有收藏模式。后者像是标记,哪道题目出错了,我可以简单标记上,即使答案重置了,我也可以跳回去反复去做,从而加深记忆。
后来在女友的询问下,我出于好奇心购买了 Claude Pro 的一个月会员,大概 20 欧元左右。我想体验一下网传 Vibe Coding 是否真的足够惊艳。使用过之后,我想说是的,它的确足够惊艳,能凭借着我的几句话调用工具、修改代码,从而解决问题。刚买会员的那几天,我用得很上瘾,恨不得一下班就打开它修改网页。
不过 「爽」 也是有代价的。当我数次向它请求重构代码之后,我发现逐步失去了对代码细节的掌控力。之前的代码在我印象里是一行行的,精确耦合在一起的,但现在它变成了一团雾。我需要钻进雾里,才能勉强看清代码的位置以及它是如何起作用的。虽然它会很自信地告诉我,代码现在的状态是最简洁、最干净的,但我仍能够时不时地浏览到一些很啰嗦的逻辑。直接 A 就能做的,非要从 A 到 B 再到 C,最后通过 C 来解决。
也许是我自己的表达和思路不清晰,它工作有时候会变得非常随意。举例来说,我习惯所有的样式都用 TailwindCSS 来处理,而不是写额外的自定义 CSS。我觉得不论是代码、项目还是团队,都会有一种默契和习惯,读懂它们传递出来的空气是很重要的。这种像是物理惯性的东西节约了很多沟通成本。不过模型不会理解这个,它是以 Prompt 和结果为导向的。它没有办法读出当前情况下的「惯性」,但是人类会。
意图这个东西,很多时候连我自己都意识不到。我会觉得这也许是个机会,通过模型的犯错,让我来纠正它,通过这个反馈来逐渐清晰我自己的意图,进而通过自然语言表达出来。但这个来回讨论过程的重点在于学习,而不是通过工程完成一件非常牢固的工具和产品。我能理解为什么不太懂代码的人会对它狂热,因为它有一种魔法感;也能理解为什么懂代码的人有时不太那么喜欢,因为它会脱离你的控制,欺骗你完成了事情,但实际上并没有遵循作者真正的意图,毕竟你能看懂它有时候写的代码真的不咋地。
在这个小项目里,我力争在加入新功能和学习代码之间(或说对代码的掌控力之间)寻找到一种平衡。我对自己的评价是尚可,虽然很多逻辑代码我写不出来,但起码知道它大概是如何运作的,识别出小 Bug 的位置是足够了。
做完了网站工具,我也参加完了考试,也有时间对这个工具做进一步的优化和推广。为此还特地邀请了女友作为微型项目的 Product Manager。她尝试了一下工具,并也请朋友试用了一下,得到的反馈是页面排版不好,颜色指示也不清晰。特别要命的是,网站没有记忆功能,答过的题目刷新网页就消失了。
为了实现更好的团队合作,我们使用 Trello 作为 Kanban Board。但因为还在摸索过程中,创建 Ticket 的规模和边界定义得都不是非常清晰,所以实践起来有一搭没一搭的。有时候遇到太小的 Bug,我会跳过或是合并多个后统一处理,跳过了 Ticket 的流程。
除了改善工具使用体验以外,最重要的莫过于推广。我知道推广很重要,但是因为性格特征,尤其作为一个习惯写程序的,在互联网上大摇大摆地展示自己做的东西怎样怎样,实在感觉有些害臊,因此从没有认真地去做过推广。为了转换心态,我把这个行为定义换了个词,不叫「做广告」,而叫「帮助别人」。这让我的感觉好了很多。
我的意图就是要帮助别人,帮助和我有着类似处境的人。有了这个信念之后,后续的事情似乎就自然了不少。我写了一段小文案,做了一些截图,放在一只手拿着 iPhone 的照片模版里,看起来很粗糙,但还是像那么点儿回事似的。
推广的结果稍微显现,但仍欠火候。我们还得多了解一下搜索 SEO 的优化和推荐机制才行。
现在这个工具运行稳定,逻辑正常,虽然会有一些弹出的广告,但绝不影响使用。除了使用工具保证题目是最新以外,我们还计划加入更多额外的有用的信息,也同样支持多语言。
当然,即使做了考试,对于永久居留的身份来说,我还需要再次提交,再次付费,再次等待,预计一切要拖到第二年才能尘埃落定。