跳到正文
博客园· 吃西瓜的星星·· 3 小时前AI 评分66

一个人加 AI 用 66 天从空目录做到生产环境:P2P 内网穿透产品开发复盘

一个人 + AI:66 天,从空目录到生产环境 —— P2P 内网穿透产品开发复盘(附全自动编程方法论) - 吃西瓜的星星

AI 导读

作者用 AI 编码智能体在 66 天内完成开源 P2P 内网穿透产品 P2PSocket_AI,全程未手写业务代码,产出约 6.8 万行代码、995 项自动化测试和 193 次提交,并已部署生产。

正文

2026-08-20,我建了一个空目录和一份 PRD;2026-10-25,这个项目在生产环境服役,TCP 打洞的新流程刚刚上线成交。全程我没有亲手写过一行业务代码——从协议字节到 SQL 迁移、从 Vue 页面到 systemd 沙箱,全部由 AI 编码智能体完成。本文复盘整个过程:项目是什么、怎么走过来的、现在跑成什么样,以及最重要的——怎么用 AI 跑通一个完整产品的"全自动编程"。

一、先说结果

  • 193 次提交,66 天,五个里程碑全部收官:核心链路 → 打洞完整 → 管理后台 → 交付打包 → 安全加固。
  • 约 6.8 万行代码(C# 5.2 万行 / 335 个文件 + 前端 1.5 万行 / 94 个文件),995 项自动化测试(后端 837 + 前端 158),编译 0 警告,CI 强制覆盖率门槛(Core 行覆盖 80%+,门槛 70%)。
  • 已部署生产:一台 2C/2GB 的云服务器跑了服务器端,多台 Windows / Linux 客户端日常服役(远程桌面就走在自己这条隧道上)。
  • 维护期靠实弹回流持续进化:最近两周从生产日志抓出并修复了两个 CGNAT 深水区缺陷,其中 TCP 打洞整段流程被推翻重设计,上线当天生产首连成交。

项目叫 P2PSocket_AI,已开源:https://github.com/bobowire/P2PSocket_AI 。它是我多年前开源项目 P2PSocket 的产品化重构——代码是全新的,经验是老项目攒下的,而这一次的写法完全不同。

二、这个项目是什么

一句话:把一台设备上的内网服务,通过 P2P 打洞直连隧道,暴露给另一台设备。

典型场景是远程桌面:公司电脑建立映射,回家访问 100.64.0.2:3588,流量走打洞直连隧道直达公司电脑的 3389 端口——不经第三方中转、端到端加密。类似的还有内网网站发布、SSH、NAS、数据库跨网互访。

访问方设备 A                     服务端(公网部署)                  服务方设备 B
┌──────────────┐                ┌───────────────┐                ┌──────────────┐
│ P2P.Client   │◀─控制 7000/TCP─│ P2P.Server    │◀─控制 7000/TCP─│ P2P.Client   │
│ 虚拟网卡      │   STUN 3478   │ 注册/授权/信令 │   STUN 3478    │ 虚拟网卡      │
└──────┬───────┘                └───────────────┘                └──────┬───────┘
       │      UDP/TCP 打洞 → 加密隧道直连(失败→自动回退中继 7010-7020)    │
       └──────────────────────────────────────────────────────────────────┘
本机应用连 100.64.0.2:本地端口 ──▶ 映射引擎 ──▶ 隧道 ──▶ 对端 127.0.0.1:目标端口

设计原则只有两条:控制面集中、数据面 P2P——公网服务器只做注册、信令、STUN 和打洞失败时的中继兜底,不做业务流量中转;全链路不依赖 TLS——隧道用 ECDH(P-256) + HKDF + AES-256-GCM 端到端加密,控制通道 HMAC 防重放,加密原语全部用 .NET 内置实现,零第三方加密依赖。

技术栈:.NET 10(ASP.NET Core Minimal API + Generic Host + Pipelines)、Vue 3 + TypeScript + Element Plus、SQLite + EF Core、MessagePack、自研 PCP 控制协议(7000/TCP)+ STUN(3478)、Windows Wintun / Linux TUN 虚拟网卡。

三、从 0 开始:动手写代码之前,先写了一堆文档

这是整篇文章最重要的一节。AI 编码的瓶颈从来不是"写不出代码",而是"不知道该写什么"。

很多朋友用 AI 写项目的方式是:开一个会话,描述需求,看 AI 生成,不满意再聊。这种方式写 demo 可以,写产品必死——因为每次会话 AI 都在"重新理解世界",你上一次口头达成的共识它不知道,需求含糊处它在替你做决定,而你甚至不知道它做了哪些决定。

我的做法是把传统开发中"程序员脑子里的隐性知识"全部显性化成三层文档:

  1. PRD(产品需求):功能需求逐条编号(FR-S 服务端 / FR-C 客户端),连安全需求(SEC)、非功能需求(NFR)、网络行为(NET)都独立编号。目前迭代到 v0.15。
  2. 技术设计(10 个分册):协议分册写到字节级——每条消息的 msgType、MessagePack 字段序号、错误码总表、加密握手时序、防重放窗口;此外还有数据模型、API 契约、前端路由、安全设计、构建交付、测试策略、追溯矩阵。目前修订到 v1.83。
  3. 任务清单(5 个里程碑,119 个编号任务):每个任务是一个可独立验收的交付单元,自带测试要求。

下面这份协议文档的精度,是"能跑测试向量"级别的——STUN 实现直接用 RFC 5769 官方测试向量做单元测试:

Core/Stun:RFC5389 Binding 子集 + XOR-MAPPED-ADDRESS(RFC5769 向量)+ DEVICE-AUTH 属性(M1-10,依据 02 §3.1/3.2、FR-S-603)

这是项目的第一个提交之一。因为"写什么"已经在文档里定死,AI 只需要回答"怎么写"。

于是第一天发生了什么?2026-08-20,16 个提交:九项目解决方案骨架、构建脚本 + CI、前端 workspace 骨架、统一加密封装(ECDH/HKDF/AES-GCM/HMAC/ECIES)、PCP 协议编解码(帧内 HMAC)、注册消息族、业务消息族、隧道协议(帧编解码 + 滑动窗口防重放 + 双重 ECDH 握手)、STUN 子集、数据库层(EF Core 11 张表 + WAL)、远程码生成、控制会话状态机、注册处理、用户能力模式——每一项都带单元测试。

这不是 AI 神奇,这是文档在神奇。你给 AI 一句模糊需求,它还你一个平均分的设计;你给它一份字节级协议,它还你一个能跑向量的实现。

四、开发过程:五个里程碑,越写越快

里程碑 时间 内容 任务数
M1 核心链路 08-20 ~ 09-12(23 天) 两台设备注册 + 第一条 UDP 直连映射端到端跑通 37
M2 打洞完整与授权闭环 09-12 ~ 09-30(18 天) TCP 打洞、中继回退、分组/远程码/白名单、UDP 映射、密钥轮换、网卡自愈 38
M3 管理面与可观测 09-30 ~ 10-07(7 天) 服务端 Web 管理后台全功能 18
M4 交付打磨 10-07 ~ 10-11(4 天) Windows 安装包、Linux deb/rpm、Docker 镜像、基准报告、随版手册 10
M5 安全加固 10-22 ~ 10-24(3 天) 3 个 P0 修复 + 告警/安全中心/IP 黑名单 + 平台加固 16

(M2/M3 各剩两三个需要特定实机环境的手工验收项,不阻塞主线;提交记录也看得出这不是全职投入,中间有不少空档。)

越写越快不是错觉:M1 平均 0.6 天一个任务,M5 平均 0.2 天。原因是文档、测试和代码模式都在复利——后面每个任务都是在"收敛",不是在"探险"。

挑两个里程碑里的关键设计展开讲讲。

M1:造了一个"假互联网"

测试打洞最大的难题是:CI 里没有 NAT。总不能每次跑测试都租两条不同运营商的宽带。

解决方案是 NatSimulator——一个单实例扮演"整个互联网 + 全部客户端 NAT"的模拟器:它持有全部"公网"套接字,内置 FullCone / RestrictedCone / PortRestricted / Symmetric 四种 NAT 模式(外加两种封锁模式),内嵌 STUN 代理按事务改写 XOR-MAPPED-ADDRESS,入站过滤行为严格按 RFC 定义实现。上千项测试全部在本地回环离线、确定性、可重复地跑。

这个装置成了整个项目的信任基石:后来它长出了 47 格的"打洞成功率矩阵"基准(5 种 UDP NAT 两两组合 + TCP 模式 × 并发路数),打洞算法每次改动都在这个矩阵上验证。

M5:3 天 16 项任务的安全加固

M5 的输入是一次全面安全评估,回流了 3 个 P0:

  • 登录密码明文传输(协议层历史遗留)→ ECIES 加密硬切。部署完成后我用 tcpdump 在公网抓包留证:修复前登录帧里密码字段是 65 字节明文,修复后是 102 字节 ECIES 密文,帧内唯一可读的 ASCII 只剩用户名。
  • 注册与登录无防滥用 → 注册三重闸门(开关 / 单 IP 令牌桶 / 设备总量)+ 登录防爆破(账户、IP 双维指数延迟,四入口统一)。
  • 平台面 → IP 黑名单四面拦截 + 自动封禁、安全事件 webhook 告警、管理端安全中心、设备凭据落库加密、systemd 最小权限沙箱(非 root + ProtectSystem=strict,全文件系统只读、白名单唯二可写)、升级产物 SHA-256 清单。

16 项任务,3 天,全部带测试和文档回写。

五、现在达到了什么效果

工程面:编译 0 警告 0 错误;后端 837 项测试 + 前端 158 项测试全绿;Core 库行覆盖 80%+(CI 解析 cobertura 报告强制 70% 门槛——顺带一提,coverlet 的阈值参数实测并不拦截,只能自己解析,这本身就是个值得单独写一篇的坑);45 份 Markdown 文档与代码同步演进。

性能面(自建七段基准 harness,每格独立世界、两轮一致性校验):

  • 打洞直连建立耗时 p50 = 219ms(生产实机实测 192ms,互相印证);中继回退约 10.2s(含 10s 打洞预算的固有成本,可配置权衡)。
  • 4 流吞吐约 200Mbps,瓶颈分析结论:在端侧全栈加密分帧,而不是中继路径(服务端 8 字节头零解密转发不构成瓶颈)。
  • RTT 附加开销:直连 +0.22ms,中继再 +0.04ms——相对真实网络几十 ms 的 RTT 可以忽略。
  • 500 设备注册压测:稳态 CPU 0.7%、内存 236MB(2C/2GB 机器)——一台最低配 VPS 就能服务一个小型团队。

生产面:服务器上线以来持续服役,抽样 10 天窗口统计到 2465 条打洞记录,当前版本零中继失败。直连占比只有 0.53%?这是部署拓扑的必然而非缺陷:家宽出口是移动 CGNAT,云服务器安全组挡掉随机打洞端口,中继就是这个拓扑下的常态承载;cone×cone 组合按矩阵应当直连。管理后台只绑回环,外部端口扫描实证 7500 不可达。

维护期的两个真实故事(说明这个系统交付后还在进化):

  1. 某设备升级后打洞全灭 + 中继也失败。两侧日志对出两层根因:打洞腿是出口 NAT 换成了移动 CGNAT,属预期内的中继回退场景;但中继腿暴露真缺陷——CGNAT 对中继 TCP 端口是 DROP 型封锁(不是 RST),旧代码的异常过滤器只接 IOException/SocketException,10 秒超时抛出的取消异常穿透过滤器,导致 UDP 兜底永远不会触发。修复只有一行语义:超时也是"承载不可用",转 UDP。修复前用新测试复现失败,修复后命中——红绿实证。
  2. TCP 打洞旧流程靠"端口预测":探测后推测对端将分配的端口再去连。实弹证明它在 CGNAT 时序扰动下脆弱——出口 NAT 对预测端口主动 RST,12 波齐射全灭。于是整段流程推翻重设计为"晚探测":双端先经 STUN-TCP 交换拿到对端实测端点作开火锚点,替代推测,再扇形齐射。配套的 11 个集成场景按新的扰动代数重写——重写前 11/11 确定性失败、重写后 11/11 绿,上线当天生产首连成交。

六、方法论:怎么用 AI 跑通"全自动编程"

先定义清楚我说的"全自动":人不写代码,人的输出是需求、决策和验收;从需求到提交的全部代码由 AI 完成。 不是"AI 补全代码我缝合",也不是"AI 出方案我把关每一行"。以下八条是我用 119 个任务验证过的做法,按重要性排序。

1. 文档先行,给 AI 一份"可执行的需求"

PRD → 技术设计 → 任务清单,三级缺一不可。协议、存储结构、API 形状、错误码全部定案到字节/字段级。这份文档同时是给 AI 的"外部记忆"——任何一次新会话,AI 的启动动作都是"读最小必读集",而不是靠你复述上下文。工具叫什么不重要,各家命令行 Agent 都行,重要的是工作流。

2. 一切编号化,让每个行为可追溯

需求 FR、技术决策 TD、未决问题 OQ、安全 SEC……每个行为都有编号出处,提交信息强制携带:

[Server] Feat:中继服务双承载与 0x74 分配闭环(M2-07,依据 02 §6、05 §6、FR-S-701/704、TD-11)

这不只是审计好看。AI 在实现时能精确引用设计原文,而不是"自由发挥";出问题时你能沿编号在 30 秒内定位到是哪条需求、哪次决策。

3. 给 AI 立规矩:把"已知失效模式"当安全漏洞来防

我写了 34 条编号规则(AI-01 ~ AI-34),每条针对一类真实翻车过的 AI 失效模式:

  • 防幻觉:不确定的 API 先查证再写,禁止凭记忆臆造方法签名;P/Invoke 逐参数对照官方头文件。
  • 防镀金:第三方依赖白名单制,新增任何 NuGet/npm 包 = 停下上报;用户亲自定过的参数原样实现,禁止"优化"——这条至关重要,AI 特别喜欢"顺手帮你优化"一个你已经权衡过的参数。
  • 防漂移:术语 → 代码标识符对照表,连"禁止的同义词"都写明(比如远程码只许叫 remoteCode,不许叫 code/token/pin);协议字段、表结构列、API 字段是同一实体的三个投影,改任何一处必查其余两处。
  • 防撒谎:未完成就说未完成;测试失败必须带原始输出;禁止用"理论上可以"冒充已验证。
  • 防作弊:禁止修改断言迁就实现;禁止用 TODO / 占位实现冒充完成。

4. OQ 机制:AI 的"不确定"必须有出口

文档有缺口或矛盾时,唯一正确的动作是:停任务 → 登记未决问题(附两处出处原文)→ 人做决议 → 决议编号化回填文档 → 继续干。AI 无权仲裁设计矛盾——我曾真实翻过车:两处各自自洽的设计互相矛盾,三轮审查才抓出来 13 项。此后这成了铁律。

整个项目累计 22 个 OQ。人只做选择题,AI 负责把选择题出清楚(附每个选项的代价分析)。失控的 AI 在猜,受控的 AI 在问——这就是"全自动"和"翻车"的分界线。

5. 任务粒度 = 一次可评审交付,交付前过十项自检

每个任务自带测试、可独立验收;完成前逐项过清单:

[ ] 1. 每个改动都有编号依据
[ ] 2. 编译零错误,新代码不留新警告
[ ] 3. 测试全过,失败项如实列出
[ ] 4. 动了消息/表列/API 字段:三视图三处已核对
[ ] 5. 改名/删除:旧名+同义词 全库 grep 无漏改
[ ] 6. 改变设计语义:文档+修订记录+追溯矩阵三处回写
[ ] 7. 无秘密进日志
[ ] 8. 无白名单外新依赖
[ ] 9. 并发纪律符合约定
[ ] 10. 新文件落在规范目录

任何一项不过 = 任务未完成。AI 的产出以提交为单位沉淀,而不是聊天记录——每个提交都是完整、可回滚、可追溯的单元。

6. 测试是信任锚:把"不可测"变成"可测"

NatSimulator 把打洞这个"没法测"的问题变成离线确定性测试;覆盖率门槛进 CI;flaky 不当作环境问题而是当作缺陷——9 个不稳定测试家族,逐一用测试结果文件取证定位根因(包括一个很典型的:CI 只有 2 核,同步 SQLite I/O 阻塞线程池 → 异步续体排队 → 整窗停顿,本地多核从不复现)。

关键纪律是红绿实证:修复前必须先有稳定失败。重写 11 个打洞场景时,先证明它们 11/11 确定性失败,重写后 11/11 绿——这样"测试有效"才不是自欺。

7. 生产反馈闭环:让实弹给 AI 出题

上线不是终点。生产日志、服务端统计、必要时的抓包取证是需求的来源;缺陷进台账清单;修复必须带红绿测试;发布前回滚件先备份。第五节那两个 CGNAT 故事就是这条闭环跑出来的——而且我观察到一个反直觉的现象:AI 非常擅长修这类"带完整证据链的复杂缺陷"。两侧日志对照 → 定位两层根因 → 一处修复共用入口 → 红绿验证 → 文档回写,人做要几天,AI 一个晚上。

8. 人的角色:从"写代码的"变成"出题和验收的"

把上面七条合起来,人在这个流程里实际承担四件事:写需求(文档)、做决策(OQ 拍板、参数定夺)、验收(看 diff、看测试报告)、喂实弹(生产反馈)。代码这件事本身,人退出了。

七、成本与不够浪漫的部分

说实话的部分:

  • 前期投入很重。第一周几乎没有"产出"——全在写 PRD 和设计。如果只做一个周末 demo,这套流程是杀鸡用牛刀;它从第二个里程碑开始回本,越往后越赚。
  • 验收没有消失,变形了。每个任务我都要看 diff、看自检报告、拍板 OQ。我更像这个项目的架构师 + Tech Lead + QA,AI 是那个读文档极快、从不遗忘、可以无限并行的实现工程师——但你不能不看就签收,AI 的自信程度和它的正确程度是两个独立变量。
  • 上下文管理是真实的坑。大仓库长会话必漂移,解法不是把一切塞进上下文,而是"编号引用 + 最小必读集"——让 AI 随时能精确取回它需要的哪一小份设计,而不是背着全部历史。
  • 不同任务的成功率差异很大。网络时序、协议字节、并发竞态这类"逻辑刚性问题",AI 配上模拟器和测试代数后做得比大多数人好;而 UI 审美、文案措辞这类"感受型问题",它需要你给出明确的评估标准和分批批复,否则它会在"你觉得不对但说不清哪不对"的地方空转。

八、写在最后

回头看,这套方法论的内核其实一句话:把工程纪律做成 AI 能执行的形态。文档让 AI 不漂移,编号让历史可追溯,规则防住已知的失效模式,测试让改动不回归,OQ 让不确定有出口——这些本来就是好工程该有的东西,只是过去它们靠人的自觉和记忆,现在它们变成了流程里强制的一环。

AI 没有替代我,它把我从打字员的位置上解放出来,还给了我一间以前雇不起的实现团队。

项目已开源,欢迎围观、试用、拍砖:

如果你也在用 AI 做完整项目,欢迎在评论区交流你踩的坑。

来源:博客园 · cnblogs.com