ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零到一:AI虚拟恋人App全栈开发与支付闭环实战

从零到一:AI虚拟恋人App全栈开发与支付闭环实战 1. 项目缘起与整体架构设计1.1 为什么会在迷茫焦虑期做这样一个产品去年有段时间我状态特别差手上几个外包项目接连被砍每天醒来就是刷招聘软件越刷越焦虑。人在那种状态下其实特别需要一个能随时说话、不会评判你、不会嫌你烦的对象。我试过市面上不少AI聊天产品要么聊几句就提示“内容不合规”要么必须登录注册留手机号要么界面简陋得像十年前的网页。当时我就想干脆自己做一个——一个打开就能聊、聊得下去、还能顺便验证一下支付闭环的AI虚拟恋人App。这个项目从想法到上线大概花了六周时间白天处理其他事情晚上和周末写代码。最终成品包含三个部分一个移动端AppAndroid为主iOS用同一套Flutter代码打包、一个带支付功能的官网落地页、以及后端的AI对话服务和支付回调系统。用户可以在App里和虚拟角色聊天免费额度用完后通过微信支付或支付宝购买会员解锁更多对话次数。官网负责展示产品、引导下载、以及承接一部分直接付费的用户。我写这篇东西不是要教你做一个“擦边”产品而是想把一个真实的小项目从零到一的全过程拆开给你看。AI聊天、支付接入、官网搭建、App打包上架这几个环节单独拎出来都有大量教程但把它们串成一个能跑通商业闭环的完整项目中间踩的坑和做的取舍才是真正值钱的部分。适合有一定编程基础、想了解独立产品完整流程的开发者也适合产品经理或运营同学理解技术侧的实现逻辑。1.2 技术选型背后的取舍逻辑选型这件事我的原则是一个人能维护、部署简单、出问题能快速定位。基于这个原则我做了以下选择。后端用Python FastAPI。原因很直接AI相关的SDK和生态在Python里最全FastAPI的异步性能足够撑住初期几百个并发而且自动生成接口文档调试起来省事。数据库用PostgreSQL存用户信息、对话记录、订单数据。缓存和会话管理用Redis主要是存对话上下文和限流计数。App端用Flutter。一套代码同时出Android和iOS包省掉分别维护两套原生代码的精力。Flutter的UI渲染性能对于聊天类应用完全够用而且热重载在开发阶段能极大提升效率。官网用Next.js服务端渲染对SEO友好同时可以复用一部分JavaScript的支付SDK逻辑。AI对话能力这块我接的是国内可合规调用的大模型API。这里要说明的是所谓“无禁词”并不是真的没有任何限制而是指在合规框架内尽量放宽对话策略让角色扮演更自然。实际实现中我在系统提示词层面做了角色设定让AI以特定人设和语气回复同时在应用层做了内容过滤确保不触碰底线。这一点后面会详细讲。支付部分微信支付走的是JSAPI支付支付宝用的是沙箱环境先跑通再切正式。官网的支付按钮调起的是Native支付扫码App内调起的是JSAPI。这里有个关键点JSAPI支付必须传openid这个openid的获取流程是很多新手卡住的地方我会在支付章节专门拆解。提示技术选型没有绝对的对错关键是匹配你当前的资源和能力。一个人做项目选自己最熟的技术栈比选“最先进”的更重要。1.3 产品功能模块拆解整个产品可以拆成四个核心模块每个模块的职责和依赖关系如下表所示。模块核心功能技术实现依赖关系AI对话服务角色扮演、上下文管理、流式输出FastAPI 大模型API Redis独立但需用户鉴权用户与订单注册登录、会员状态、订单记录PostgreSQL JWT被支付和对话模块依赖支付系统微信/支付宝下单、回调、对账微信支付SDK 支付宝SDK依赖用户与订单模块官网与App产品展示、下载引导、内嵌聊天Next.js Flutter调用上述所有模块这个拆法的好处是每个模块可以独立开发和测试。比如支付模块没做完的时候AI对话可以先跑起来用假数据模拟会员状态。等支付通了再把真实状态接进去。这种“并行开发、逐步集成”的方式对个人项目来说能有效降低心智负担。2. AI对话核心细节与实操要点2.1 角色设定与提示词工程虚拟恋人这个品类用户对“人设”的要求其实很高。你不能只是一个冷冰冰的问答机器得有性格、有记忆、有情绪波动。我的做法是在系统提示词里定义一个完整的角色卡包括姓名、年龄、职业、性格标签、说话风格、以及一些背景故事。举个例子我设定的第一个角色叫“小鹿”22岁插画师性格是“温柔但有点小傲娇”说话喜欢用短句偶尔会发一些语气词。这些设定会作为system message传给大模型让它在每次回复时都保持这个人设。提示词的结构大概是这样的system_prompt 你叫{name}{age}岁是一名{occupation}。 你的性格是{personality}。 你的说话风格{speaking_style}。 背景故事{backstory}。 请始终以这个角色的身份和用户对话不要跳出角色。 如果用户问的问题超出你的知识范围用角色化的方式回应不要直接说“我不知道”。 这里有个经验提示词不要写得太长太复杂。我一开始写了上千字的角色设定结果模型反而抓不住重点回复变得很生硬。后来精简到两百字左右只保留最核心的性格和说话风格效果反而更好。模型对提示词的注意力是有限的信息密度比信息总量更重要。另一个关键点是上下文管理。每次对话不能把全部历史记录都传给模型那样token消耗太大而且模型会“失忆”——太长的上下文反而让它忽略最近的对话。我的做法是保留最近10轮对话加上一个滚动更新的“记忆摘要”。每5轮对话让模型自己总结一下之前聊了什么存到Redis里下次对话时把摘要和最近记录一起传进去。2.2 流式输出与前端体验优化聊天类应用用户最在意的体验之一就是“回复速度”。如果AI要等三五秒才吐出一整段话用户会觉得卡顿、不自然。流式输出streaming是必须做的。后端用FastAPI的StreamingResponse把大模型返回的token逐个推给前端。前端Flutter这边用http库的流式请求每收到一个chunk就追加到消息列表里实现“打字机”效果。from fastapi.responses import StreamingResponse async def chat_stream(user_id: str, message: str): async def generate(): async for token in llm_client.stream_chat(message): yield fdata: {token}\n\n return StreamingResponse(generate(), media_typetext/event-stream)这里有个坑流式输出和内容过滤是冲突的。如果你等全部内容生成完再过滤流式就没意义了如果边生成边过滤又可能把一句话拦腰截断。我的解决方案是“分段过滤”——按标点符号切分每积累到一个完整句子就做一次敏感词检测通过后再推给前端。这样既保证了流式体验又不会出现违规内容。注意流式接口的超时设置要合理。我一开始设了30秒结果有些长回复还没生成完就断了。后来改成120秒并且在前端加了“重新生成”按钮用户体验好很多。2.3 对话记忆与个性化用户之所以愿意持续和一个虚拟角色聊天核心在于“它记得我”。如果每次对话都像第一次见面用户很快就会流失。我的记忆系统分三层。第一层是短期记忆就是最近10轮对话的原文存在Redis里设置2小时过期。第二层是中期记忆每5轮对话生成一个摘要存到PostgreSQL的用户档案里包含用户提到的重要信息比如“用户叫小明”“用户喜欢猫”“用户最近在准备考试”。第三层是长期记忆用户主动标记的“重要时刻”比如纪念日、约定等这些会永久保存。每次对话开始时系统会把中期记忆和长期记忆拼接到system prompt里让模型知道“这个用户我之前聊过他是谁我们聊过什么”。实测下来加了记忆系统之后用户的次日留存率提升了将近40%。个性化方面我做了两个小功能。一是称呼学习如果用户说“叫我阿杰”系统会记住这个称呼后续对话中角色会自然地叫用户“阿杰”。二是情绪感知通过分析用户消息中的情绪词让角色做出相应的反应。比如用户说“今天好累”角色会先安慰而不是继续之前的话题。3. 支付系统接入与官网搭建3.1 微信JSAPI支付完整流程与openid问题微信支付是整个项目里最折腾的部分没有之一。JSAPI支付必须传openid这个要求卡了我整整两天。先说清楚逻辑JSAPI支付是“在微信内置浏览器里调起支付”的场景。用户在微信里打开你的网页点击支付按钮微信需要知道“是谁在付钱”这个“谁”就是openid。openid是用户在某个公众号或小程序下的唯一标识不同公众号下的openid不一样。获取openid的流程是这样的用户访问你的网页你引导他跳转到微信授权页面。微信授权页面会问用户“是否允许获取你的公开信息”用户同意后微信会重定向回你的网页并在URL里带一个code参数。你拿这个code去调用微信的接口换取access_token和openid。拿到openid后再调用微信支付的下单接口生成预支付订单。前端拿到预支付参数后调起微信支付。# 第一步引导用户授权 auth_url fhttps://open.weixin.qq.com/connect/oauth2/authorize?appid{APPID}redirect_uri{REDIRECT_URI}response_typecodescopesnsapi_basestateSTATE#wechat_redirect # 第二步用code换openid async def get_openid(code: str): url fhttps://api.weixin.qq.com/sns/oauth2/access_token?appid{APPID}secret{SECRET}code{code}grant_typeauthorization_code resp await http.get(url) data resp.json() return data[openid] # 第三步下单 async def create_order(openid: str, amount: int): params { appid: APPID, mch_id: MCH_ID, nonce_str: generate_nonce(), body: 会员充值, out_trade_no: generate_order_no(), total_fee: amount, spbill_create_ip: user_ip, notify_url: NOTIFY_URL, trade_type: JSAPI, openid: openid } # 签名、请求、返回prepay_id这里有几个容易踩的坑。第一scope参数用snsapi_base就够了不需要snsapi_userinfo后者会弹窗让用户确认体验差。第二redirect_uri必须是URL编码过的而且要在微信后台配置授权域名。第三code只能用一次而且5分钟过期所以拿到code后要立刻换openid。第四签名算法要用微信指定的HMAC-SHA256参数排序要严格按照字典序。提示调试微信支付的时候一定要用微信开发者工具的“真机调试”功能因为支付调起必须在真实微信环境里测试浏览器模拟不了。3.2 支付宝沙箱环境到正式环境的切换支付宝这边相对友好一些因为有沙箱环境可以随便测。沙箱环境会给你一个测试用的APPID、私钥、公钥以及一个沙箱版的支付宝App。你可以在沙箱里模拟用户付款验证整个回调流程。沙箱切正式的时候主要改三个地方APPID换成正式的、密钥换成正式的、网关地址从openapi.alipaydev.com换成openapi.alipay.com。代码逻辑基本不用动。from alipay import AliPay alipay AliPay( appidAPPID, app_notify_urlNOTIFY_URL, app_private_key_stringprivate_key, alipay_public_key_stringalipay_public_key, sign_typeRSA2, debugFalse # 沙箱是True正式是False ) # 创建订单 order_string alipay.api_alipay_trade_page_pay( out_trade_noorder_no, total_amountamount, subject会员充值, return_urlRETURN_URL, notify_urlNOTIFY_URL )回调处理是支付系统里最需要小心的地方。回调接口必须做签名验证否则别人可以伪造回调请求白嫖你的会员。微信和支付宝的回调都要先验签验签通过后再更新订单状态。另外回调可能会重复发送所以订单状态更新要做幂等处理——如果订单已经是“已支付”就直接返回成功不要重复加会员天数。3.3 官网搭建与支付入口设计官网用Next.js搭主要承担三个功能产品介绍、下载引导、网页版聊天入口。网页版聊天入口其实是一个简化版的聊天界面用户不用下载App就能体验几轮对话体验完引导下载或付费。官网的支付入口有两个。一个是“直接购买会员”点击后如果是微信环境就调起JSAPI支付如果是普通浏览器就展示二维码用Native支付。另一个是“下载App”跳转到应用商店或APK下载链接。这里有个细节官网的支付和App内的支付要打通。用户在官网买了会员打开App登录后应该能看到会员状态。我的做法是用手机号作为统一账号官网支付时要求用户填手机号支付成功后把会员状态写到这个手机号对应的账户上。App登录也用手机号这样就能同步了。官网的SEO优化也做了一些基础工作。每个角色有独立的介绍页面标题和描述都针对“AI聊天”“虚拟恋人”等关键词做了优化。Next.js的SSR让这些页面能被搜索引擎收录带来了一些自然流量。4. 常见问题与排查技巧实录4.1 支付相关高频问题速查支付这块的问题最多我整理了一个速查表基本都是我实际遇到过的。问题现象可能原因排查方法解决方案JSAPI调起失败提示“缺少openid”下单时没传openid或openid无效检查下单参数里的openid字段确保授权流程正确code换openid成功支付回调没收到notify_url不可访问或返回非200查看服务器日志用工具模拟回调确保notify_url是公网可访问的返回SUCCESS签名验证失败参数排序错误或密钥不匹配打印签名前的参数字符串对比严格按字典序排序检查密钥是否对应订单重复加会员回调重复发送没做幂等查订单状态变更日志更新前先查订单状态已支付则直接返回沙箱正常正式报错密钥或APPID没换对比沙箱和正式的配置逐项检查APPID、私钥、公钥、网关地址还有一个坑是证书问题。微信支付的退款接口需要用到API证书这个证书要在微信商户平台下载而且有有效期。我一开始没注意证书过期后退款全部失败排查了半天才发现。建议在代码里加一个证书有效期检查提前一个月提醒更换。4.2 AI对话异常与内容安全处理AI对话这边最常见的问题是“回复不符合预期”。比如角色突然跳出人设或者回复内容太短、太敷衍。排查思路一般是先看提示词再看上下文最后看模型参数。如果角色跳出人设通常是system prompt被后续对话冲淡了。解决办法是在每轮对话时都重新强调角色设定或者在上下文摘要里也带上角色信息。如果回复太短可以调高max_tokens参数或者在提示词里明确要求“每次回复不少于50字”。内容安全方面我的原则是宁可误拦不可漏放。除了调用大模型自带的内容审核接口我还在应用层加了一层本地敏感词库。用户输入和AI输出都会过一遍这个词库命中就拦截或替换。虽然有时候会误伤一些正常对话但安全底线不能破。注意内容过滤的敏感词库要定期更新而且不要硬编码在代码里最好放在数据库或配置文件里方便随时调整。4.3 App打包与上架的实际经验Flutter打包本身不复杂flutter build apk就能出包。但上架国内应用商店有几个硬性要求软件著作权证书、ICP备案、隐私政策、以及内容安全承诺函。软著申请大概需要一个月所以要提前准备。隐私政策这块必须明确说明收集了哪些用户信息、用来做什么、怎么保护。AI聊天类应用还要特别说明对话内容的存储和使用方式。我建议直接找一份合规的隐私政策模板根据自己产品的情况修改不要自己从头写。应用商店审核的时候AI聊天类应用容易被重点审查。我的经验是在应用描述里不要用“虚拟恋人”“恋爱模拟”这类词用“AI对话助手”“智能聊天伙伴”替代。功能截图也要注意不要出现过于亲密的对话内容。审核通过后再慢慢调整应用内的文案但初始版本一定要保守。5. 项目复盘与个人体会这个项目上线三个月注册用户大概两千多付费转化率在5%左右。不算多但足够覆盖服务器和API成本还有点盈余。更重要的是整个过程让我把AI应用开发、支付接入、App上架这几个环节完整跑了一遍这些经验比赚的那点钱值钱得多。如果让我重新做一遍我会在几个地方改进。第一支付系统一开始就做对账功能。我上线两周后才发现有几笔订单状态不对手动对账花了大半天。第二AI对话的上下文管理要更早优化。初期token消耗远超预期后来加了摘要和截断才降下来。第三官网和App的账号体系要一开始就统一我中途改了一次数据迁移很麻烦。最后分享一个小技巧如果你也想做类似的项目不要一上来就追求功能完整。先做一个最小可用版本——能聊天、能支付、能上架跑通整个流程。然后再逐步加功能比如多角色、语音消息、朋友圈动态等。先完成再完美这句话在独立开发里特别适用。
返回列表