
1. 起点一个想清楚才开始做的产品决定去年有相当长一段时间我状态是真不行。白天上班像在梦游晚上躺下就开始胡思乱想两三点还睁着眼睛看天花板。那种迷茫和焦虑拧在一起的感觉经历过的人都懂。后来我做了一件现在回看挺莽的事一边上班一边自己动手做了一个 AI 聊天虚拟恋人 App。不是那种跑两天就扔的玩具 demo而是真正带完整支付流程、配了独立官网、从下载到付款全链路能跑通的产品。从起念头到上线第一个可用版本前后大概三个多月中间踩的坑够写一本小册子。这篇文章我想把这三个月的东西完整摊开讲。如果你也在考虑做一个 AI 类的 App尤其是涉及支付变现和官网配套的那我走过的路你大概率也要走一遍。我会讲清楚三件事这类方向为什么有人愿意付费、支付这条链路到底怎么打通、官网和应用上架有哪些绕不开的槛。技术选型、数据模型、支付回调的幂等处理、应用商店被拒的真实原因我都尽量讲到能直接抄作业的程度。先说清楚适合谁看。完全不写代码的纯小白这篇文章能让你看懂一个 App 是怎么从想法变成能收钱的产品写过几个 demo 的开发者支付和上架这两块能帮你省下至少两三周的试错时间。我不灌鸡汤只讲我实际做过、测过、被坑过的东西。1.1 为什么是情感陪伴这个方向市面上做 AI 聊天的产品多如牛毛为什么我偏偏选了情感陪伴这个切口因为需求真实而且用户付费意愿明确。你会发现纯粹的工具型 AI 应用用户用完就走很难形成粘性;但陪伴型对话不一样用户每天会来、会待很久、会投入情绪而情绪投入是付费转化最强的燃料。我做了个小范围的用户访谈找了二十多个愿意聊的人问他们为什么愿意跟一个 AI 说心里话。答案出乎意料地一致没有负担。跟真人倾诉怕被评判、怕麻烦别人、怕说出去;跟 AI 说永远不用担心这些。这个低心理成本就是这类产品的核心价值也是它区别于普通聊天机器人的地方。但这里必须敲一个重点情感陪伴类产品的生命线是内容安全。很多同类产品不是死在技术上而是死在内容审核上。所以我从第一天就给产品定了规矩——人设可以温柔、可以体贴、可以有性格但对话内容必须经过安全过滤输入和输出双向都要过审核层。这不是可选项是能不能活下来的前提。1.2 为什么一定要配支付和官网有人会问做一个聊天 App 不就行了为什么非要折腾支付和官网因为这两样决定了它是一个自娱自乐的项目还是一个能自己养活自己的产品。支付是商业闭环的起点。没有支付,你永远只能靠爱发电,服务器账单、模型调用费用全得自己贴。我算过一笔账,早期一个月光模型调用的开销就接近四位数,不做变现根本撑不住。官网则是信任的入口。用户下载一个陌生 App 之前十有八九会先搜一下看看有没有官网、靠不靠谱。一个正经的官网,哪怕只有几个页面,也能显著降低用户的决策门槛。更实际的一点是,官网还是应用商店审核时的重要加分项。审核人员看到一个有备案、有内容、有隐私政策的官网,对产品的信任度会高很多。这一点我在后面讲上架的时候会详细说。2. 三端架构:一个 App 背后的完整拼图很多人以为做个 App 就是写个客户端,其实真正的产品至少是三端:用户看到的 App 端、提供信任和下载入口的官网端、以及管着订单和用户的运营后台。三端分工明确,但共用一套服务端 API 和数据库。这一章我讲整体架构和选型,把为什么这么设计讲透。2.1 App 端、官网端、后台服务的分工App 端是主战场,承载聊天、登录、充值、个人中心四大块。聊天是核心,登录是入口,充值决定收入,个人中心负责留存。这四块里,充值那条链路是最容易出问题的,因为它要跟外部支付系统打交道,后面单独用一大章讲。官网端看着简单,其实职责不少:一是做品牌展示,让用户知道你是谁、做什么的;二是放隐私政策和用户协议,这是合规的硬性要求;三是做下载引导,把用户导流到应用商店或直接下载安装包;四是做 SEO,让搜索相关关键词的人能找过来。后台服务是最容易被忽视的一块。我当时偷懒,最开始想跳过后台,结果运营两天就崩溃了——订单状态查不了、用户退款要手动改数据库、对话出问题没法定位。后来花了整整一周补了个简易后台,能看订单、能查用户、能封禁违规账号、能手动补发权益。这部分投入回报极高,千万别省。三端通过统一的 API 网关通信,鉴权用 JWT,官网的公开接口和 App 的登录接口分开限流。这样做的好处是,官网被爬或者被刷不至于拖垮 App 的核心服务。2.2 技术栈选型:怎么选才不会后悔选型这件事,我的原则只有一条:选你将来能自己维护的,而不是选最潮的。一个人做产品,最大的成本不是开发时间,是后期维护。后端我用了 Python 的 Django 框架配轻量 API 层。为什么不用更时髦的方案?因为 Django 自带 ORM、自带后台管理、自带用户系统,这三样能帮我省下大量重复劳动。订单模型、用户模型直接在自带后台里就能管,Django 的 admin 几乎是白送一个运营后台。很多教程会推荐更灵活的框架,但对于要快速上线又要长期维护的个人项目,这种自带电池的框架反而更省心。App 端我用的是跨平台方案,一套代码同时出两个平台的包。选跨平台不是因为性能多好,而是因为一个人真的没精力同时维护两套原生代码。实测下来,聊天这种以文本和网络请求为主的场景,跨平台方案完全够用,性能瓶颈根本不在这里。官网用了一个主打服务端渲染的前端框架。为什么官网要服务端渲染?因为 SEO。单页应用对搜索引擎不友好,而官网的一大作用就是被搜到,服务端渲染能让页面内容被正常抓取,这一点在获客上很关键。数据库选了关系型数据库配一个缓存层。订单、用户这类数据要强一致,关系型数据库更稳;聊天上下文和高频读取的配置走缓存,降低数据库压力。2.3 数据模型怎么设计才不返工数据模型一旦定错,后期改起来很痛苦。我在设计阶段花了两天画表结构,事实证明这时间花得值。核心就四张表:用户表、订单表、权益表、对话记录表。用户表除了基础的账号信息,关键要留一个渠道来源字段,记录用户是从官网来的还是从应用商店来的,方便后期算获客成本。订单表要预留订单号、金额、状态、支付渠道、外部交易号、回调时间这些字段,一个都不能少,尤其是外部交易号,对账的时候全靠它。权益表是最容易设计错的地方。很多人把会员到期时间直接塞进用户表,结果一遇到多档位、多类型权益就傻眼。我的做法是单独建表,一行代表一份权益,记录类型、数量、生效时间、过期时间。这样不管是包月、包年还是一次性购买,都能统一处理。对话记录表要特别注意隐私。我的做法是只存必要的上下文,敏感信息不落库,并且给用户提供一键清空对话的功能。这既是合规要求,也是建立用户信任的手段。3. AI 聊天核心:从能对话到像真人这是整个产品最核心也最难的部分。让 AI 回一句话很容易,让 AI 连续聊一个月还不掉人设、还记得你上次说过什么、还不会说出不该说的话,这才是真功夫。这一章我拆开讲。3.1 大模型接入与流式输出接入大模型本身不难,难的是让回复像打字一样一个字一个字蹦出来,而不是等好几秒突然冒出一大段。用户对延迟极其敏感,等待超过两秒就会觉得卡,超过五秒基本就想关掉了。解决方案是流式输出。服务端调用模型时开启流式模式,拿到分片就直接推给客户端,前端边收边渲染。这里面有个技术选型:用长连接还是用服务端推送事件。我实测下来,这个场景下服务端推送事件更简单,它基于普通 HTTP,接入成本低,容器环境下也不用为长连接做特殊配置。下面是一段服务端流式转发的核心逻辑,简化后大概长这样:def stream_chat(request): user auth(request) message request.json.get(message) # 先过输入审核,不合规直接拒绝 if not content_check(message): return json_response({error: 内容不合规}, status400) def generate(): buffer for chunk in model_client.stream(promptbuild_prompt(user, message)): buffer chunk # 按句边界切分,避免把敏感词切碎导致漏检 if buffer.endswith((。, , , \n)): if not content_check(buffer): buffer 这个话题我们换个方向聊聊吧。 yield fdata: {buffer}\n\n buffer if buffer: yield fdata: {buffer}\n\n return stream_response(generate())注意:流式输出和内容审核天然冲突。如果等全部生成完再审核,用户体验就退化成非流式了;如果边生成边审,又要把句子切碎判断。我最后采用的是按句边界切分 缓冲审核的方案,牺牲一点点流畅度换审核可靠性,这个取舍在陪伴类产品里非常值得。3.2 人设系统与上下文记忆让 AI 有稳定人设,靠的是系统提示词。但系统提示词不是随便写句话就完事,它需要包含身份设定、说话风格、价值观边界、禁忌事项四个部分。我踩过的坑是:提示词写得越松散,模型越容易在长对话里跑偏。后来我把人设写成结构化的模板,明确规定了语气词的使用频率、回复长度范围、遇到敏感话题时的标准应对,人设才稳定下来。上下文记忆是另一个硬骨头。模型能记住的上下文长度是有限的,聊得越久,早期内容就越容易被挤出去。我的处理是分三层:最近几轮完整保留;更早的对话做摘要压缩,把关键信息提炼成几句话;再往前的用户偏好(比如喜欢被怎么称呼、讨厌什么话题)单独存一份用户画像,每次对话都带进去。这样处理之后,用户会有一种它真的记得我的感觉。而被记得恰恰是陪伴类产品留存的关键。3.3 内容安全层:生死攸关的一环前面反复强调内容安全,这里讲具体怎么落地。我的方案是三层过滤。第一层是输入过滤,用户发出来的内容先过一遍,命中违规直接拦截,并把这条记录进风控日志。第二层是提示词约束,在系统提示词里明确写着遇到特定话题要如何引导、如何转移。第三层是输出过滤,模型生成的内容按句切分后逐句检查,命中就替换成安全话术。三层里最重要的是输出过滤,因为大部分风险都来自模型的自由发挥。这里有个经验:不要依赖关键词黑名单,那样误伤率极高,正常句子稍微沾点边就被拦了。我接的是内容安全服务,它做的是语义级别的判断,准确率高很多。同时我做了申诉机制。用户如果觉得被误判,可以提交申诉,人工复核。这既是对用户负责,也能帮我把误判样本收集起来,反哺过滤策略的调整。4. 支付模块:从零到跑通全链路这一章是全文的重头,也是我踩坑最多的地方。支付这件事,难点从来不在调起支付那一下,而在于状态管理、回调处理、对账和退款这一整套。下面一步步拆。4.1 支付通道怎么选选支付通道,要看你产品的用户主要在哪个环境里。如果核心用户在某个社交应用的内置浏览器里,那对应的网页支付是首选;如果主要在 App 内,那要考虑 App 内支付的各种方案;如果用户分散在普通手机浏览器,那第三方聚合支付能省很多事。我一开始只接了一种,上线一周发现相当一部分用户在我的主推环境里付不了款,才赶紧补了第二种。教训很直接:别拍脑袋决定,先用小范围测试确认你的用户到底从哪里来。另外提一句,如果产品涉及虚拟商品,在部分平台上是有特殊限制的,有些渠道对虚拟商品的抽成比例和结算周期跟实物不一样。这些规则一定要提前查清楚,别等到上线才发现结算规则跟预期差一大截。4.2 微信支付接入里最容易卡住的那个坑微信支付接入里,有一个问题几乎每个人都会遇到,就是那个必须传 openid 的报错。很多人一看就懵了:openid 是什么?我上哪弄去?简单解释一下。在某些微信支付场景里,支付接口需要知道是谁在付款,这个谁就是用 openid 来标识的。它不是用户在你系统里的账号,而是用户在微信体系里的唯一标识。所以你必须先从微信那里拿到这个 openid,才能调起支付。获取它的流程叫网页授权。用户进入你的页面时,你把他引导到微信的授权地址,他确认后,微信会带着一个临时的 code 跳回你的回调地址,你用这个 code 去换 openid。整个过程用静默授权就能完成,用户几乎无感。下面是后端用 code 换 openid 的核心代码:import requests def get_openid(code): url https://api.weixin.qq.com/sns/oauth2/access_token params { appid: APPID, secret: APPSECRET, code: code, grant_type: authorization_code, } resp requests.get(url, paramsparams, timeout5).json() if openid in resp: return resp[openid], resp.get(access_token) # 错误码要打日志,常见的是 code 被重复使用 raise Exception(f获取 openid 失败: {resp})注意三个高频坑。第一,code 只能用一次,用过就失效,所以拿到 openid 后要立刻缓存,别重复请求。第二,授权域名的配置要在微信后台提前配好,否则回调会被拦。第三,openid 是按应用隔离的,你在 A 应用拿到的 openid 在 B 应用里不通用,别混用。调起支付那一步,前端拿到后端签名好的参数后调起支付面板,用户输密码完成付款。付款结果不能信前端的成功回调,必须以后端收到的异步通知为准。这一点极其重要,后面讲幂等时细说。4.3 订单状态机与回调幂等支付系统最容易出 bug 的地方就是状态混乱。我的做法是给订单定义清晰的状态机:待支付、支付中、已支付、已发放权益、已关闭、已退款。每个状态只能按规定路径流转,不允许跳转。状态流转如下表:当前状态允许流转到触发条件待支付支付中发起支付请求支付中已支付收到支付成功回调支付中已关闭超时未支付(默认15分钟)已支付已发放权益权益发放逻辑执行成功已支付已退款用户申请退款并审核通过回调幂等是必须处理的。支付平台的异步通知可能会重复发送,如果你不做幂等,用户付一次钱可能被加两次权益。我的做法是给订单号加唯一索引,回调进来先查订单状态,如果已经是已发放权益,直接返回成功,不重复处理。def handle_payment_callback(order_no, trade_no): order Order.objects.select_for_update().get(order_noorder_no) if order.status granted: return SUCCESS # 已处理过,直接返回,保证幂等 if order.status ! paid: return FAIL grant_benefit(order) # 发放权益 order.status granted order.trade_no trade_no order.save() return SUCCESS这里用了数据库的行级锁,防止同一订单的回调并发处理。对于个人项目来说,这比引入分布式锁简单得多,也足够可靠。4.4 虚拟商品的定价与退款策略定价上,我走的是低门槛体验 阶梯订阅的路线。新用户有一小段免费额度,用完自然引导付费;付费分月卡、季卡、年卡三档,年卡单价最低但不推,因为它拉低现金流,主推季卡。这个策略是被数据教育出来的:一开始只做月卡,复购率不高;加了季卡之后,客单价和留存都上去了。退款策略要提前想好。虚拟商品一旦发放权益,退款的合理性就存在争议。我的规则是:未发放权益的订单可以全额退,已发放的按未使用比例退,并且退款要走人工审核。这一步麻烦,但能大幅降低纠纷和投诉,对应用商店的评分也有正面作用。还有一点,所有交易记录要能导出,方便对账。我做了个每日对账脚本,拉取支付平台的账单和我自己的订单表比对,有差异就报警。上线三个月,靠这个脚本发现过两次回调丢失,及时补了单。5. 官网搭建与应用上架:最后一公里的坑技术全通了,不代表产品能上线。官网和应用商店这一关,卡住了无数人。这一章讲怎么过低成本上线路线和审核。5.1 官网最低成本上线路线官网不需要多华丽,但要满足几个硬条件:有备案、能正常访问、有隐私政策和用户协议、有联系方式。这四样缺一不可,尤其是隐私政策,很多应用商店审核时会重点看。我的路线是这样的:域名买好后先做备案,这一步周期比较长,要提前启动;服务器选轻量级的云主机就够,早期访问量不大,没必要上高配;官网用服务端渲染方案,保证 SEO;内容上放产品介绍、功能介绍、下载入口、隐私政策、用户协议五个页面就可以了。提示:隐私政策不能随便从网上抄一份。里面涉及的权限说明、数据用途、第三方 SDK 清单,必须跟你 App 的实际行为一致。审核时会核对,对不上直接拒。5.2 应用商店审核的常见卡点上架被拒是常态,我第一次提交被拒了两次。常见的拒因有这么几类,整理成表方便对照。拒因类别具体表现应对方式内容合规审核员发现聊天内容有风险强化审核层,提交时附审核机制说明资质不全缺少特定经营资质提前咨询平台规则,补齐材料隐私问题权限申请与功能不匹配删掉不必要的权限,补充隐私说明功能不完整出现空白页、崩溃提交前多机型真机测试支付违规使用了平台不允许的支付方式严格按平台要求接入内容合规这类拒因最麻烦,因为审核员会实际去聊。我的应对是提交审核前先跑一遍自己的产品,把风险话术都试出来,并且专门准备一份内容审核机制说明文档随审核一起提交,让审核员知道你有做防护。这个动作很加分。5.3 合规与资质该准备哪些这块我吃过大亏。最开始我以为做个 App 只要写代码就行,结果发现涉及收费、涉及内容运营,需要的材料一样不少。大致要准备的有:主体的相关证照、隐私政策、用户协议、内容审核制度说明、部分场景下可能还需要特定资质。具体需要哪些,不同平台、不同产品类型要求不一样,我建议在动手开发之前先去目标应用商店的开发者文档里查清楚,列一份清单。我就是因为没提前查,中途补材料耽误了两周。记住一句话:合规材料的时间成本,永远比你想的高。6. 踩过的坑和排查实录前面讲的都是应该怎么做,这一章讲做错了会怎样,都是我在实际运维里撞出来的。6.1 支付回调丢失怎么办上线第二周,有个用户投诉付了钱没到账。我查订单,状态停在支付中,但支付平台那边显示已成功。典型回调丢失。排查思路是这样的:先确认支付平台那边确实成功,再查我的回调接口日志。发现那次接口因为一次部署重启,请求打进来时服务正好在启动,直接失败了。支付平台虽然会重试,但重试有次数上限,超过就不发了。解决办法有两层。第一层是被动兜底:写个定时任务,定时查支付中超过一定时间的订单,主动去支付平台查询状态,补上漏掉的处理。第二层是主动对账:每天拉一次账单,跟订单表比对,有差异报警。def reconcile_daily(): # 拉取支付平台的账单 bills fetch_platform_bills(dateyesterday()) for bill in bills: order Order.objects.filter(order_nobill.order_no).first() if order and order.status pending and bill.status success: handle_payment_callback(order.order_no, bill.trade_no) log_alert(f补单成功: {order.order_no})这个补单脚本救过我好几次,强烈建议每个做支付的人都写一个。6.2 抓包和联调时的问题联调支付的时候,抓包是绕不开的。但抓包经常失败,尤其是 App 端,原因通常是证书校验、代理配置或者请求走了非 HTTP 协议。我的经验是:不要一上来就抓生产环境的包,先在测试环境用日志把关键参数打出来,确认参数对了再抓包定位网络层问题。还有一个高频问题是环境混淆。我在测试环境配的支付参数,不小心带到了生产,导致线上调起支付直接报错。后来我强制要求所有支付相关的配置走环境变量,并且加了一个启动自检,配置缺失或明显不对就直接启动失败。这样虽然启动麻烦点,但避免了线上事故。6.3 模型成本怎么压下来成本是这类产品长期运营的关键。我早期一个月模型开销不低,后来做了几个优化:一是对话摘要,长对话不全部回传,只回传摘要加最近几轮,大幅减少了 token 消耗;二是缓存常见回复,对于你好在吗这类高频开场,直接命中缓存,不走模型;三是按场景选模型,闲聊用轻量模型,复杂情感分析才用大模型。这几招下来,单用户成本降了差不多一半。在定价不变的情况下,毛利直接改善。对于要长期运营的产品,这种优化比拉新还重要。6.4 服务器和稳定性的一些经验个人项目没必要追求多高配。我早期用一台中等配置的云主机,跑服务加数据库加缓存,完全够用。等用户量上来了,再把数据库拆出去单独部署。扩容的顺序应该是:先升配,再拆服务,最后才考虑上集群。过早追求复杂架构,维护成本会把你拖垮。监控也简单点来。我就装了个基础的应用性能监控,关注三个指标:接口响应时间、错误率、模型调用量。任何一个异常就发通知。这三个指标能覆盖绝大多数线上问题。别搞一堆花哨的看板,最后自己都不看。7. 一些没说透但很重要的细节聊到这儿,把几个容易被忽略但影响很大的点单独拎出来讲讲,都是我实际踩过才明白的。第一个是登录体验。我一开始只做手机号验证码登录,结果流失率高得吓人。后来加了游客模式,让用户不登录就能先聊几句,想充值的时候再引导登录。这一改动让首日留存明显上升。陪伴类产品一定要让用户先体验到陪伴感,再谈注册。第二个是消息推送。用户不会主动打开你的 App,你得把他们拉回来。但推送要克制,我用的是人设化的每日问候,比如晚上固定时间发一句符合人设的话。打开率比通用推送文案高很多,而且不会让人觉得骚扰。第三个是数据备份。这条说起来简单,但我真的见过有人把生产数据库误删的经历。我现在的做法是每天自动备份,备份文件异地保存,并且每月演练一次恢复流程。备份没演练过,等于没有备份。第四个是版本发布的节奏。我早期一天发好几个版本,结果用户刚适应又变了,投诉不少。后来改成每周固定发一版,紧急修复才走热更新。稳定的节奏本身就是一种产品体验。第五个是用户反馈的收集。别指望用户会主动给你发邮件。我在 App 里做了个一键反馈入口,并且每次重要更新后用应用内弹窗问一句这个版本你满意吗。这些一手反馈是产品迭代最宝贵的输入。8. 我的几点真实体会做完这个产品,我最大的感受是:一个人做产品,拼的不是技术多强,而是能在多少细节上不偷懒。支付回调的幂等、内容审核的三层过滤、订单对账脚本,这些都不酷,但正是它们决定了产品能不能活下去。另外想说的是,不要被上线这两个字绑架。我一开始特别急,恨不得一周就把所有功能都做完,结果做出来的东西漏洞百出。后来我放慢节奏,一次只把一件事做扎实,反而更快接近可用状态。迷茫和焦虑不会因为你做了个产品就消失,但当你看着用户真的在用、真的愿意付费的时候,那种确定感是别的东西给不了的。如果你也准备动手,我的建议是从最小可用版本开始:先跑通聊天,再加支付,最后补官网和后台。每一步都做扎实,别跳步。前面讲的这些坑,你大概率躲不过,但至少看完这篇,你能知道坑长什么样,掉进去的时候能爬得快一点。