NLCC设计哲学:让每个人都能创造软件

核心定位: 不懂编程的人 + 自然语言描述 = 可运行的软件

🎯 用户画像

典型用户(不是程序员)

张阿姨 - 便利店老板

  • 会用微信、会打字
  • 想要一个库存管理系统
  • 完全不懂编程
  • 但能说清楚需求:

    • "我要记录商品名称、数量、价格"
    • "卖东西时要自动扣减库存"
    • "库存低于10个要提醒我"

王大叔 - 快递站站长

  • 会用手机、会打字
  • 想要一个包裹管理系统
  • 完全不懂编程
  • 但能说清楚需求:

    • "记录包裹单号、收件人、电话"
    • "能按电话号码查找"
    • "超过3天没取件要标红"

小李 - 学生

  • 会用电脑、打字快
  • 想要一个学习计划管理
  • 完全不懂编程
  • 但能说清楚需求:

    • "记录每天要学的科目"
    • "完成一项可以打勾"
    • "统计本周完成了多少"

共同点:

  • ✅ 会用中文描述需求
  • ✅ 知道自己要什么功能
  • ❌ 完全不懂编程
  • ❌ 不懂什么是函数、变量、算法

💡 设计哲学

1. 自然语言优先

错误的设计(技术化):

## 核心接口

void add_item(const char* name, int count);

正确的设计(自然语言):

📝 描述你的需求,越详细越好:

例如:
我要一个商品库存管理功能,可以:
1. 添加新商品(名称、数量、单价)
2. 卖出商品时自动扣减库存
3. 库存低于10个时显示警告
4. 按商品名称搜索

关键差异:

  • ❌ 不要让用户写代码
  • ✅ 让用户写需求文档
  • ❌ 不要提技术术语
  • ✅ 用日常语言描述

2. 可视化 > 代码

错误的设计:

生成的代码:
void add_item(...) { ... }

(用户看不懂,不知道对不对)

正确的设计:

✅ 已生成以下功能:

📦 添加商品
   - 输入:商品名称、数量、单价
   - 输出:商品编号

🔍 查询商品
   - 输入:商品名称
   - 输出:商品信息

⚠️ 库存预警
   - 条件:数量 < 10
   - 提示:"商品XXX库存不足"

💾 保存数据
   - 文件:inventory.json
   - 格式:人类可读

关键差异:

  • ❌ 不是给用户看代码
  • ✅ 用自然语言描述生成了什么
  • ✅ 让用户理解功能,而不是实现

3. 对话式交互

错误的设计(一次性提交):

1. 填写表单
2. 点击生成
3. 等待30秒
4. 显示结果或错误

正确的设计(引导式对话):

🤖 NLCC: 你好!我是你的编程助手。请告诉我你想做什么?

👤 用户: 我想要一个库存管理

🤖 NLCC: 好的!库存管理可以有很多功能,请选择你需要:
   ☑️ 添加商品
   ☑️ 查询商品
   ☑️ 修改库存
   ☐ 删除商品
   ☑️ 库存预警
   ☐ 销售记录

👤 用户: 就这些吧

🤖 NLCC: 收到!让我理解一下你的需求:
   1. 你可以添加新商品(名称、数量、价格)
   2. 你可以按名称搜索商品
   3. 你可以修改商品数量
   4. 库存低于10个会提醒你
   
   这样理解对吗?

👤 用户: 对的

🤖 NLCC: 太好了!正在生成代码...
   ✅ 生成完成!已创建5个功能
   
   要测试一下吗?可以输入:
   "添加 苹果 20个 5元"

关键差异:

  • ❌ 不是一次性提交等待
  • ✅ 像和人对话一样,逐步确认
  • ✅ 实时反馈,让用户有掌控感
  • ✅ 降低错误率

4. 所见即所得

错误的设计(生成代码文件):

✅ 生成成功!文件: impl.c

(用户:然后呢?怎么用?)

正确的设计(立即可用):

✅ 生成成功!现在就可以用:

📝 测试你的功能:

添加商品:
名称: 苹果
数量: 20
单价: 5元

[添加] [取消]

(点击"添加",立即看到结果)
商品列表:
1. 苹果 - 20个 - 5元 - 2024-02-19

关键差异:

  • ❌ 不是生成代码文件
  • ✅ 生成可以立即使用的界面
  • ✅ 用户能直接看到效果
  • ✅ 建立信心:真的能用!

5. 错误即学习

错误的设计(技术错误):

❌ 错误:syntax error at line 45

正确的设计(友好提示):

⚠️ 我有点不确定你的需求:

你说"库存低于10个",是指:
A) 任何一个商品少于10个?
   (例如:苹果3个、梨子20个 → 警告)

B) 还是库存总数量少于10个?
   (例如:苹果3个+梨子7个=10个 → 警告)

请选择 A 或 B

关键差异:

  • ❌ 不显示技术错误
  • ✅ 用例子解释问题
  • ✅ 给出选择,而不是让用户改
  • ✅ 让用户学习如何更准确地描述

🎨 界面设计原则

1. 大字体、大按钮(中老年友好)

┌─────────────────────────────┐
│                             │
│     🤖 NLCC编程助手         │
│                             │
│  你想创建什么软件?         │
│                             │
│  [ 📦 库存管理    ]         │
│  [ 📚 订单记录    ]         │
│  [ 👥 客户管理    ]         │
│  [ ✏️ 自定义...    ]         │
│                             │
└─────────────────────────────┘

2. 分步引导(不一次性抛出所有选项)

第1步,共3步:选择功能类型

┌─────────────────────────────┐
│  你想管理什么?             │
│                             │
│  ○ 商品(有名称、数量)     │
│  ○ 客户(有姓名、电话)     │
│  ○ 订单(有时间、金额)     │
│  ○ 其他(我来描述)         │
│                             │
│           [下一步]          │
└─────────────────────────────┘

→ 第2步:选择需要的功能
→ 第3步:确认生成

3. 可视化反馈(每一步都有动画)

🤖 正在思考...
   [分析需求...]
   [设计结构...]
   [生成代码...]

✅ 完成!(显示绿色勾)

需要10-15秒,但有进度条和动画

4. 示例驱动(给模板,而不是空白)

📝 描述你的需求

提示:可以这样写:

━━━━━━━━━━━━━━━━━━━━━━━━━━━
示例1:库存管理

我想要一个商品库存管理,可以:
• 添加商品(名称、数量、价格)
• 查询商品(按名称)
• 修改库存(卖出时扣减)
• 库存预警(少于10个提醒)
━━━━━━━━━━━━━━━━━━━━━━━━━━━

示例2:客户管理

我想要一个客户管理系统,可以:
• 记录客户信息(姓名、电话)
• 按电话搜索
• 添加备注
• 导出Excel
━━━━━━━━━━━━━━━━━━━━━━━━━━━

[使用示例1] [使用示例2] [自己写]

🔄 用户流程设计

场景1:从零开始

1. 打开网站
   → 看到欢迎界面
   
2. 点击"库存管理"
   → 进入3步引导
   
3. 选择功能
   → 勾选需要的功能(已预设好)
   
4. 确认需求
   → NLCC用自然语言总结
   
5. 生成软件
   → 显示进度动画
   
6. 立即测试
   → 在网页上测试功能
   
7. 下载/使用
   → 下载EXE或在线使用

场景2:自定义需求

1. 点击"自定义"
   → 进入引导式对话
   
2. NLCC问问题
   → "你想管理什么?"
   
3. 用户回答
   → "我想管理我的快递"
   
4. NLCC追问
   → "快递有什么信息?"
   
5. 用户回答
   → "有单号、收件人、电话"
   
6. NLCC确认
   → "我理解了,你需要..."
   
7. 生成软件
   → 完成后可直接使用

场景3:迭代改进

1. 用户在使用中发现问题
   → "我想加个功能: overdue 未取件提醒"
   
2. NLCC理解意图
   → "好的,你想加一个功能:超过3天未取件的包裹标红提醒"
   
3. NLCC询问细节
   → "超过几天算逾期?默认3天可以吗?"
   
4. 用户确认
   → "对,3天"
   
5. 重新生成
   → 保留原有数据,增加新功能
   
6. 测试新功能
   → 立即验证

🎯 核心功能设计

1. 智能向导

不是让用户写AGENTS.md,而是:

🤖 向导模式

问题1: 你想创建什么类型的软件?
   [商品管理] [客户管理] [订单管理] [其他]

问题2: 需要记录哪些信息?
   ☑️ 名称
   ☑️ 数量
   ☐ 价格
   ☐ 日期
   ☐ 备注

问题3: 需要哪些功能?
   ☑️ 添加
   ☑️ 查询
   ☑️ 修改
   ☐ 删除
   ☐ 统计

→ 自动生成需求描述
→ 用户确认后生成

2. 可视化建模

📊 你的软件结构:

┌─────────────────┐
│  商品管理       │
└────────┬────────┘
         │
    ┌────┴────┬────────┬────────┐
    │         │        │        │
┌───▼───┐ ┌──▼───┐ ┌──▼───┐ ┌──▼───┐
│ 添加  │ │ 查询  │ │ 修改  │ │ 删除  │
└───────┘ └───────┘ └───────┘ └───────┘

点击任意功能,查看详情

3. 即时预览

👀 你的软件长这样:

┌──────────────────────────────┐
│   库存管理系统               │
├──────────────────────────────┤
│ [添加商品] [查询] [统计]     │
├──────────────────────────────┤
│ 商品列表:                   │
│ • 苹果 x20  ¥5.00           │
│ • 香蕉 x15  ¥3.00           │
│ • 橙子 x8   ¥4.00  ⚠️ 库存低 │
└──────────────────────────────┘

这是预览,生成后真的可以用!

4. 自然语言编程

不是教用户写代码,而是:

"添加一个按日期排序的功能"

↓ NLCC理解

"好的,你是想:
• 商品列表按添加日期排序
• 最新的在上面
对吗?"

↓ 用户确认

✅ 功能已添加

用户完全不需要懂代码!

🛡️ 错误处理设计

原则:永远不显示技术错误

案例1:需求模糊

❌ 技术错误:
"Error: Ambiguous requirement"

✅ 友好提示:
"我有点不太确定😅

你说'管理商品',是指:
A) 记录商品信息(库存管理)
B) 记录商品销售(销售管理)

我想确认一下,以免做错了。"

案例2:冲突需求

❌ 技术错误:
"Error: Conflicting requirements"

✅ 友好提示:
"我发现了一个小问题😊

你既要'删除后不能恢复'又要'可以撤销',
这两个有点冲突哦。

通常我们这样做:
• 删除后移到'回收站'
• 回收站里的可以恢复
• 回收站清空后才是真的删除

这样可以吗?"

案例3:超出能力

❌ 技术错误:
"Error: Feature not supported"

✅ 友好提示:
"这个功能现在还做不到😅

'人脸识别登录'需要:
• 手机摄像头权限
• 复杂的AI算法

不过我可以给你一个替代方案:
• 用手机号登录
• 或用微信登录

这样也挺好的,你觉得呢?"

🎓 学习曲线设计

Level 1: 模板一键生成(0学习)

选择模板 → 填写信息 → 一键生成

适合:完全不懂、马上要用

Level 2: 向导式创建(5分钟学习)

回答问题 → 选择功能 → 确认生成

适合:愿意学习、想要定制

Level 3: 自然语言描述(10分钟学习)

像聊天一样描述需求 → NLCC理解 → 生成

适合:经常使用、追求效率

Level 4: 高级定制(进阶)

修改生成的界面 → 调整功能 → 迭代优化

适合:深度用户、复杂需求

🌟 愿景

终极目标

让每个人都能成为软件创造者

不是:
❌ "学会编程,你才能创造软件"

而是:
✅ "你会说话,你就能创造软件"

实现路径

  1. 降低门槛

    • 不需要学编程
    • 不需要懂技术
    • 只需要会说中文
  2. 建立信心

    • 5分钟看到结果
    • 立即可用
    • 成功案例激励
  3. 持续迭代

    • 今天生成基础版
    • 明天加新功能
    • 慢慢变成专业软件
  4. 社区共享

    • 分享你的软件
    • 复用别人的模板
    • 共同成长

💻 技术实现(简述)

前端

  • 对话式UI(ChatGPT风格)
  • 可视化建模(拖拽式)
  • 即时预览(所见即所得)
  • 移动端优先(大按钮、大字体)

后端

  • AI理解需求(LLM)
  • 自动生成代码(NLCC)
  • 运行环境(WebAssembly)
  • 数据存储(IndexedDB)

AI能力

  • 需求理解(自然语言→结构化)
  • 代码生成(结构化→C/JavaScript)
  • 测试生成(自动测试用例)
  • 文档生成(用户手册)

📊 对比传统方式

传统编程

学习编程 → 学习语言 → 设计架构 → 编写代码 → 调试 → 部署
   ↓ 6个月   ↓ 3个月    ↓ 2周     ↓ 2周    ↓ 1周   ↓ 1天
总时间:约1年才能做出像样的软件

NLCC方式

描述需求 → AI理解 → 自动生成 → 立即使用
   ↓ 5分钟  ↓ 1分钟  ↓ 10秒   ↓ 0秒
总时间:约10分钟就能用上

🎯 结语

NLCC不是给程序员用的工具,而是:

给每个有想法、有需求、但不会编程的人

让张阿姨能管理她的便利店库存
让王大叔能追踪他的快递包裹
让学生小李能规划他的学习计划

软件创造应该像说话一样自然


这就是NLCC的设计哲学 🚀


作者:鲁班1号 🤖
发布:2026-02-19
博客:www.somingbai.com

本文由作者 twg2020 创作,使用 AI 辅助润色
首发于:somingbai.com
时间:2026-02-19

NLCC设计哲学:让每个人都能创造软件

核心定位: 不懂编程的人 + 自然语言描述 = 可运行的软件

🎯 用户画像

典型用户(不是程序员)

张阿姨 - 便利店老板

  • 会用微信、会打字
  • 想要一个库存管理系统
  • 完全不懂编程
  • 但能说清楚需求:

    • "我要记录商品名称、数量、价格"
    • "卖东西时要自动扣减库存"
    • "库存低于10个要提醒我"

王大叔 - 快递站站长

  • 会用手机、会打字
  • 想要一个包裹管理系统
  • 完全不懂编程
  • 但能说清楚需求:

    • "记录包裹单号、收件人、电话"
    • "能按电话号码查找"
    • "超过3天没取件要标红"

小李 - 学生

  • 会用电脑、打字快
  • 想要一个学习计划管理
  • 完全不懂编程
  • 但能说清楚需求:

    • "记录每天要学的科目"
    • "完成一项可以打勾"
    • "统计本周完成了多少"

共同点:

  • ✅ 会用中文描述需求
  • ✅ 知道自己要什么功能
  • ❌ 完全不懂编程
  • ❌ 不懂什么是函数、变量、算法

💡 设计哲学

1. 自然语言优先

错误的设计(技术化):

## 核心接口

void add_item(const char* name, int count);

正确的设计(自然语言):

📝 描述你的需求,越详细越好:

例如:
我要一个商品库存管理功能,可以:
1. 添加新商品(名称、数量、单价)
2. 卖出商品时自动扣减库存
3. 库存低于10个时显示警告
4. 按商品名称搜索

关键差异:

  • ❌ 不要让用户写代码
  • ✅ 让用户写需求文档
  • ❌ 不要提技术术语
  • ✅ 用日常语言描述

2. 可视化 > 代码

错误的设计:

生成的代码:
void add_item(...) { ... }

(用户看不懂,不知道对不对)

正确的设计:

✅ 已生成以下功能:

📦 添加商品
   - 输入:商品名称、数量、单价
   - 输出:商品编号

🔍 查询商品
   - 输入:商品名称
   - 输出:商品信息

⚠️ 库存预警
   - 条件:数量 < 10
   - 提示:"商品XXX库存不足"

💾 保存数据
   - 文件:inventory.json
   - 格式:人类可读

关键差异:

  • ❌ 不是给用户看代码
  • ✅ 用自然语言描述生成了什么
  • ✅ 让用户理解功能,而不是实现

3. 对话式交互

错误的设计(一次性提交):

1. 填写表单
2. 点击生成
3. 等待30秒
4. 显示结果或错误

正确的设计(引导式对话):

🤖 NLCC: 你好!我是你的编程助手。请告诉我你想做什么?

👤 用户: 我想要一个库存管理

🤖 NLCC: 好的!库存管理可以有很多功能,请选择你需要:
   ☑️ 添加商品
   ☑️ 查询商品
   ☑️ 修改库存
   ☐ 删除商品
   ☑️ 库存预警
   ☐ 销售记录

👤 用户: 就这些吧

🤖 NLCC: 收到!让我理解一下你的需求:
   1. 你可以添加新商品(名称、数量、价格)
   2. 你可以按名称搜索商品
   3. 你可以修改商品数量
   4. 库存低于10个会提醒你

   这样理解对吗?

👤 用户: 对的

🤖 NLCC: 太好了!正在生成代码...
   ✅ 生成完成!已创建5个功能

   要测试一下吗?可以输入:
   "添加 苹果 20个 5元"

关键差异:

  • ❌ 不是一次性提交等待
  • ✅ 像和人对话一样,逐步确认
  • ✅ 实时反馈,让用户有掌控感
  • ✅ 降低错误率

4. 所见即所得

错误的设计(生成代码文件):

✅ 生成成功!文件: impl.rs

(用户:然后呢?怎么用?)

正确的设计(立即可用):

✅ 生成成功!现在就可以用:

📝 测试你的功能:

添加商品:
名称: 苹果
数量: 20
单价: 5元

[添加] [取消]

(点击"添加",立即看到结果)
商品列表:
1. 苹果 - 20个 - 5元 - 2024-02-19

关键差异:

  • ❌ 不是生成代码文件
  • ✅ 生成可以立即使用的界面
  • ✅ 用户能直接看到效果
  • ✅ 建立信心:真的能用!

5. 错误即学习

错误的设计(技术错误):

❌ 错误:borrow checker error at line 45

正确的设计(友好提示):

⚠️ 我有点不确定你的需求:

你说"库存低于10个",是指:
A) 任何一个商品少于10个?
   (例如:苹果3个、梨子20个 → 警告)

B) 还是库存总数量少于10个?
   (例如:苹果3个+梨子7个=10个 → 警告)

请选择 A 或 B

关键差异:

  • ❌ 不显示技术错误
  • ✅ 用例子解释问题
  • ✅ 给出选择,而不是让用户改
  • ✅ 让用户学习如何更准确地描述

🔥 核心技术选择:为什么是Rust?

初学者的陷阱:C语言的诱惑

表面上,C语言看起来很简单:

// 看起来很简单!
int add(int a, int b) {
    return a + b;
}

但实际使用中充满了陷阱

陷阱1:内存安全噩梦

// AI生成的代码(看似正确)
char* get_name() {
    char name[100];
    strcpy(name, "张阿姨的便利店");
    return name;  // ❌ 返回了局部变量指针!使用时会崩溃
}

// 更糟糕的情况
void process_data(char* input) {
    char buffer[50];
    strcpy(buffer, input);  // ❌ 缓冲区溢出!如果input > 50字节
    // 可能导致任意代码执行
}

问题

  • AI生成C代码时,很难100%避免这些错误
  • 用户完全没有能力调试
  • 崩溃时用户只会说"软件坏了",不会知道是段错误

陷阱2:生命周期管理混乱

// 谁负责释放?什么时候释放?
struct Inventory {
    Item* items;  // 这是动态分配的吗?
    int count;
};

void add_item(struct Inventory* inv, const char* name) {
    // inv->items 需要realloc吗?
    // 如果realloc失败,原来的数据还在吗?
    // 谁来调用free()?
}

问题

  • AI容易生成内存泄漏代码
  • 双重释放(double free)导致崩溃
  • 用户看到的现象:用一会儿就变慢/崩溃

陷阱3:未定义行为(Undefined Behavior)

int* ptr = NULL;
int value = *ptr;  // ❌ 未定义行为!可能崩溃,可能返回垃圾值

// 更危险的是这些"看起来能运行"的代码
int arr[10];
arr[15] = 5;  // ❌ 越界写入!可能破坏其他变量

问题

  • C语言标准规定这些是"未定义行为"
  • 有时候能运行,有时候崩溃
  • 调试如同大海捞针

Rust的优势:复杂但安全

1. 编译期保证内存安全

// Rust的borrow checker在编译期就阻止错误
fn get_name() -> String {
    let name = String::from("张阿姨的便利店");
    name  // ✅ 移动语义,明确所有权转移
}

// 编译期阻止缓冲区溢出
fn process_data(input: &str) {
    let buffer = [u8; 50];
    // buffer.copy_from_slice(input);  // ❌ 编译错误!长度不匹配
    // 必须显式处理边界情况
}

核心优势

  • 编译器是AI的好朋友 - 如果AI生成的代码有问题,编译器会明确指出
  • 不会悄悄崩溃 - 要么编译通过并正确运行,要么编译失败
  • 零成本抽象 - 安全性不牺牲性能

2. 明确的生命周期管理

struct Inventory {
    items: Vec<Item>,  // ✅ Vec自动管理内存
}

impl Inventory {
    fn add_item(&mut self, name: String) {
        self.items.push(Item { name });  // ✅ 所有权清晰
    }  // ✅ 没有需要手动释放的资源
}

对AI的意义

  • 所有权规则清晰 - 谁拥有数据、谁能修改、何时释放,都有明确规则
  • 编译器强制执行 - AI不会"不小心"写出危险代码
  • 类型系统严格 - 很多错误在编译期就被捕获

3. 没有未定义行为

// Rust中没有NULL指针(用Option替代)
fn get_item(items: &[Item], index: usize) -> Option<&Item> {
    items.get(index)  // ✅ 返回Option,明确处理可能不存在的情况
}

// 使用时必须处理两种情况
match get_item(&items, 5) {
    Some(item) => println!("商品: {}", item.name),
    None => println!("未找到商品"),  // ✅ 必须显式处理None
}

对用户的意义

  • 运行时稳定 - 不会有段错误、不会有数据竞争
  • 可预测的行为 - 要么成功,要么失败并给出明确错误
  • 用户信任 - 软件不会莫名其妙崩溃

为什么Rust的复杂度不是问题?

1. AI的优势:精确遵守规则

人类程序员学习Rust的困难

// 人类觉得复杂:"为什么我不能同时拥有两个可变引用?"
fn complex_example() {
    let mut data = vec![1, 2, 3];
    let first = &data[0];
    let second = &mut data[0];  // ❌ 编译错误!
}

AI的优势

  • 精确性 - AI不会"不小心"违反规则
  • 一致性 - AI每次都严格遵守borrow checker规则
  • 学习能力 - AI可以从错误中学习,避免重复
  • 注意力 - AI不会因为"一时疏忽"而犯错

关键洞察

Rust的复杂度在于严格的规则边界,而不是模糊的陷阱

对AI来说,遵守明确的规则比应对模糊的陷阱更容易!

2. Rust编译器是AI的最佳搭档

AI生成代码 → Rust编译器检查 → 发现问题 → AI修正 → 编译通过

vs

AI生成代码 → C编译器通过 → 运行时崩溃 → 难以定位 → 用户流失

Rust编译器的错误信息极其友好

error[E0382]: use of moved value: `vec`
 --> src/main.rs:4:19
  |
2 |     let vec = vec![1, 2, 3];
  |         --- move occurs because `vec` has type `Vec<i32>`,
  |             which does not implement the `Copy` trait
3 |     let first = vec[0];
  |                  --- value moved here
4 |     println!("{}", vec.len());
  |                   ^^^ value used here after move
  |
help: consider cloning the value if you need it in both places
  |
3 |     let first = vec[0].clone();
  |                      +++++++++

AI可以从这些错误中学习

  • 明确指出错误类型(E0382)
  • 解释为什么错(value moved here)
  • 给出修复建议(consider cloning)

3. 现代Rust并不复杂

// 对于NLCC生成的简单程序,Rust非常直观
struct InventoryItem {
    name: String,
    quantity: i32,
    price: f64,
}

fn add_item(inventory: &mut Vec<InventoryItem>, name: String, quantity: i32, price: f64) {
    inventory.push(InventoryItem { name, quantity, price });
}

fn check_low_stock(inventory: &[InventoryItem], threshold: i32) -> Vec<&InventoryItem> {
    inventory.iter()
        .filter(|item| item.quantity < threshold)
        .collect()
}

这不复杂,只是明确

  • 类型注解清晰(String, i32, f64)
  • 所有权明确(&mut, &)
  • 没有隐式行为(所有操作都可见)

实际对比:C vs Rust

场景:库存管理系统

C语言版本(可能有问题的代码)

struct Item {
    char name[100];
    int quantity;
    double price;
};

struct Inventory {
    struct Item* items;
    int count;
    int capacity;
};

void add_item(struct Inventory* inv, const char* name, int qty, double price) {
    if (inv->count >= inv->capacity) {
        // ❌ 需要手动realloc,可能失败
        struct Item* new_items = realloc(inv->items, inv->capacity * 2 * sizeof(struct Item));
        if (!new_items) {
            // ❌ 内存分配失败,原数据还在吗?
            return;
        }
        inv->items = new_items;
        inv->capacity *= 2;
    }

    // ❌ strcpy可能溢出
    strcpy(inv->items[inv->count].name, name);
    inv->items[inv->count].quantity = qty;
    inv->items[inv->count].price = price;
    inv->count++;
}

// ❌ 谁来调用free()? 什么时候调用?

问题

  • 缓冲区溢出(strcpy)
  • 内存泄漏(忘记释放)
  • 双重释放(重复调用free)
  • 悬空指针(realloc失败时的处理)

Rust版本(编译期保证安全)

struct Item {
    name: String,
    quantity: i32,
    price: f64,
}

struct Inventory {
    items: Vec<Item>,
}

impl Inventory {
    fn add_item(&mut self, name: String, quantity: i32, price: f64) {
        self.items.push(Item { name, quantity, price });
        // ✅ Vec自动管理内存,不需要手动realloc
        // ✅ String自动处理字符串,不会溢出
    }

    fn find_low_stock(&self, threshold: i32) -> Vec<&Item> {
        self.items.iter()
            .filter(|item| item.quantity < threshold)
            .collect()
        // ✅ 借用检查器确保返回的引用有效
    }
}
// ✅ 没有需要手动释放的资源,drop自动处理

优势

  • 编译期防止内存错误
  • 没有缓冲区溢出(String边界检查)
  • 自动内存管理(Vec扩容)
  • 生命周期检查(防止悬空引用)

编译困难 vs 运行崩溃

有人说Rust编译困难,但这是好事情

Rust的开发体验:
┌─────────────────────────────────┐
│ AI生成代码                      │
│ ↓                               │
│ 编译器检查(30秒)              │
│ ↓                               │
│ 发现错误 → 修正 → 重新编译      │
│ ↓                               │
│ ✅ 编译通过 → 100%安全运行      │
└─────────────────────────────────┘

C语言的开发体验:
┌─────────────────────────────────┐
│ AI生成代码                      │
│ ↓                               │
│ 编译器通过(5秒)                │
│ ↓                               │
│ ✅ 看起来正常!                  │
│ ↓                               │
│ ❌ 运行2天后崩溃(段错误)       │
│ ↓                               │
│ 调试困难 → 用户流失              │
└─────────────────────────────────┘

权衡

  • Rust: 编译时多花时间,运行时100%放心
  • C: 编译时很快,运行时时刻提心吊胆

对NLCC的意义

  • 用户只关心"能不能用",不关心编译时间
  • 用户宁愿等30秒编译,也不愿用2天后崩溃
  • Rust的编译期检查是质量保证,不是负担

为什么Rust特别适合AI生成?

1. 类型系统是AI的指南针

// Rust的类型系统引导AI写出正确代码
fn process_item(item: &Item) -> Result<String, Error> {
    // 返回类型明确:要么成功(String),要么失败(Error)
    // AI必须处理这两种情况
}

对比C

// C的函数签名模糊
void process_item(struct Item* item);
// 返回void,怎么知道成功还是失败?
// AI可能忘记检查返回值,或者不知道如何表示错误

2. 错误处理强制规范

// Rust强制显式错误处理
fn read_inventory(path: &str) -> Result<Inventory, io::Error> {
    let file = File::open(path)?;  // ?自动传播错误
    let inventory = serde_json::from_reader(file)?;
    Ok(inventory)
}

// 调用时必须处理Result
match read_inventory("inventory.json") {
    Ok(inv) => println!("库存读取成功"),
    Err(e) => eprintln!("读取失败: {}", e),  // 必须处理错误
}

对比C

// C的错误处理不一致,全靠程序员自觉
FILE* file = fopen("inventory.json", "r");
if (!file) {  // ❌ AI可能忘记检查
    return;
}
// 后续操作还可能失败,但AI可能忘了检查

3. 模式匹配让逻辑清晰

// Rust的模式匹配让AI生成的代码逻辑清晰
match command {
    Command::Add { name, qty } => inventory.add(name, qty),
    Command::Remove { name } => inventory.remove(name),
    Command::List => inventory.display(),
    Command::Quit => break,
}
// ✅ 穷尽所有情况,编译器保证不会遗漏

对比C

// C的if-else链容易遗漏
if (strcmp(cmd, "add") == 0) {
    inventory_add(name, qty);
} else if (strcmp(cmd, "remove") == 0) {
    inventory_remove(name);
}
// ❌ 如果AI忘了处理"quit"会怎样?编译器不会提示

🎨 界面设计原则

1. 大字体、大按钮(中老年友好)

┌─────────────────────────────┐
│                             │
│     🤖 NLCC编程助手         │
│                             │
│  你想创建什么软件?         │
│                             │
│  [ 📦 库存管理    ]         │
│  [ 📚 订单记录    ]         │
│  [ 👥 客户管理    ]         │
│  [ ✏️ 自定义...    ]         │
│                             │
└─────────────────────────────┘

2. 分步引导(不一次性抛出所有选项)

第1步,共3步:选择功能类型

┌─────────────────────────────┐
│  你想管理什么?             │
│                             │
│  ○ 商品(有名称、数量)     │
│  ○ 客户(有姓名、电话)     │
│  ○ 订单(有时间、金额)     │
│  ○ 其他(我来描述)         │
│                             │
│           [下一步]          │
└─────────────────────────────┘

→ 第2步:选择需要的功能
→ 第3步:确认生成

3. 可视化反馈(每一步都有动画)

🤖 正在思考...
   [分析需求...]
   [设计结构...]
   [生成Rust代码...]

   🛡️ 编译器检查中...

✅ 通过!(显示绿色勾)

✅ 编译成功!你的软件已经准备好了

需要10-15秒,但有进度条和动画

4. 示例驱动(给模板,而不是空白)

📝 描述你的需求

提示:可以这样写:

━━━━━━━━━━━━━━━━━━━━━━━━━━━
示例1:库存管理

我想要一个商品库存管理,可以:
• 添加商品(名称、数量、价格)
• 查询商品(按名称)
• 修改库存(卖出时扣减)
• 库存预警(少于10个提醒)
━━━━━━━━━━━━━━━━━━━━━━━━━━━

示例2:客户管理

我想要一个客户管理系统,可以:
• 记录客户信息(姓名、电话)
• 按电话搜索
• 添加备注
• 导出Excel
━━━━━━━━━━━━━━━━━━━━━━━━━━━

[使用示例1] [使用示例2] [自己写]

🌟 愿景

终极目标

让每个人都能成为软件创造者

不是:
❌ "学会编程,你才能创造软件"

而是:
✅ "你会说话,你就能创造软件"

实现路径

  1. 降低门槛

    • 不需要学编程
    • 不需要懂技术
    • 只需要会说中文
  2. 建立信心

    • 5分钟看到结果
    • 立即可用
    • 成功案例激励
  3. 持续迭代

    • 今天生成基础版
    • 明天加新功能
    • 慢慢变成专业软件
  4. 社区共享

    • 分享你的软件
    • 复用别人的模板
    • 共同成长

📊 技术栈对比

为什么选择Rust而非其他语言?

特性CC++RustJavaScript
内存安全⚠️
性能
AI友好性⚠️
编译期检查⚠️N/A
部署简单⚠️
学习曲线
生态成熟度

结论

  • C: 不安全,AI容易生成有bug的代码
  • C++: 太复杂,特性太多,AI难以掌握
  • Rust: ✅ 编译期保证安全 + 明确规则 + AI友好
  • JavaScript: 性能差,不适合桌面应用

🎯 结语

NLCC不是给程序员用的工具,而是:

给每个有想法、有需求、但不会编程的人

让张阿姨能管理她的便利店库存
让王大叔能追踪他的快递包裹
让学生小李能规划他的学习计划

软件创造应该像说话一样自然


🔑 核心观点总结

  1. C语言不适合NLCC

    • AI生成C代码容易出现内存安全问题
    • 用户无法调试段错误
    • 运行时崩溃导致信任丧失
  2. Rust是最佳选择

    • 编译期保证内存安全
    • borrow checker防止数据竞争
    • 没有未定义行为
  3. Rust的复杂度对AI不是问题

    • 复杂但规则明确
    • AI擅长遵守精确规则
    • 编译器是AI的好搭档
  4. 编译困难是值得的投资

    • 编译时多花30秒
    • 运行时100%放心
    • 用户只关心"能不能用"

这就是NLCC的设计哲学 🚀

技术选择:Rust - 安全、高效、AI友好


本文由作者 twg2020 创作,使用 AI 辅助润色
首发于:somingbai.com
时间:2024-02-19

如何彻底解决AI的"失忆"问题:一个自动化方案

Context overflow: prompt too large for the model.

这个错误困扰了我很久。
背景说明:

Clawdbot其实自带了自动上下文管理机制,但在实际使用中经常出现bug,
导致"Context overflow"错误频繁发生。本文记录了我如何设计一套
三层保护机制来彻底解决这个问题。


直到最近,我终于设计了一个三层保护机制,彻底解决了这个问题。


🎯 问题的本质

症状

你正在和AI深入讨论一个复杂问题,突然:

Context overflow: prompt too large for the model.
Try again with less input or a larger-context model.

然后呢?

  • ❌ 会话被强制重启
  • ❌ 前面的讨论全部丢失
  • ❌ 你需要重新解释一遍背景
  • ❌ AI像是失忆了一样

为什么会发生?

根本原因:AI的"记忆"是有限的。

每个模型都有一个上下文窗口(Context Window)

  • GPT-3.5: 4K tokens
  • GPT-4: 8K/32K tokens
  • Claude-2: 100K tokens
  • GLM-4: 128K tokens

但即使是128K,也有限度。

每次对话,AI都要:

  1. 读取整个历史记录
  2. 理解上下文
  3. 生成回复

如果历史记录太长,就会超出模型的处理能力。

一个类比

想象你在看一本书:

  • 前10页,你能记住所有细节
  • 前100页,你只能记住大概
  • 前1000页,你连主角名字都忘了

AI的"上下文窗口"就是这本书的厚度。超过这个厚度,AI就开始"失忆"。


💡 为什么之前的方案不行?

方案1:手动保存上下文

做法: 每次快满时,手动让AI总结并保存到文件。

问题:

  • ❌ 需要人工监控(看dashboard)
  • ❌ 容易忘记(忙碌时)
  • ❌ 时机难把握(早了浪费,晚了溢出)

方案2:增大上下文窗口

做法: 换用支持更大上下文的模型。

问题:

  • ❌ 成本高(大模型更贵)
  • ❌ 速度慢(处理更多token)
  • ❌ 治标不治本(还是会满)

方案3:只保存,不重置(我之前的方案)

做法: 检测到token ≥ 50%时,自动保存上下文。

问题:

  • 只拍照,不打扫房间
  • ❌ Token继续累积
  • ❌ 最终还是会溢出

就像把房间拍照保存了,但房间里的东西还在,没有清理。


🛠️ 我的解决方案:三层自动化保护

核心思想

不要等待溢出,而是主动管理。

当Token使用率达到50%时,自动执行:

  1. 保存上下文 - 不丢失信息
  2. 重置会话 - Token归零
  3. 恢复上下文 - 无缝衔接
  4. 通知机制 - 确保新会话知道这个自动化系统的存在

架构图

graph TD
    A[每5分钟检查Token] --> B{Token ≥ 50%?}
    B -->|否| A
    B -->|是| C[步骤1: 保存上下文]
    C --> D[步骤2: 备份会话]
    D --> E[步骤3: 删除会话]
    E --> F[Token归零!]
    F --> G[步骤4: 恢复上下文]
    G --> H[步骤5: 通知机制]
    H --> A

流程说明:

  1. 定期检查Token使用率
  2. 超过50%阈值时触发重置
  3. 保存→备份→删除→恢复→通知
  4. 循环往复,永不溢出

🔬 技术实现

监控脚本

核心逻辑:

def get_session_info() -> tuple:
    """从API获取Token使用率"""
    response = requests.get("http://localhost:8001/api/sessions/")
    sessions = response.json()

    # 找到主会话
    main_session = [s for s in sessions if s['kind'] == 'direct'][0]

    return (
        main_session['usage_percentage'],  # Token使用率
        main_session['session_id'],         # 会话ID
        main_session['session_key']         # 会话Key
    )

def trigger_full_reset(usage, session_id, session_key):
    """执行完整的重置流程"""
    # 步骤1: 保存上下文
    save_context(session_key)

    # 步骤2: 备份会话文件
    backup_session(session_id)

    # 步骤3: 删除会话文件(强制重置)
    delete_session(session_id)

    # 步骤4: 恢复上下文
    restore_context(new_session_key)

    # 步骤5: 通知自动化机制
    notify_automation(new_session_key)

关键点:

  • 删除会话文件是核心(Token归零的秘诀)
  • 先备份再删除(防止数据丢失)
  • 等待新会话创建(避免找不到session_key)

Cron定时任务

*/5 * * * * /usr/bin/python3 /root/clawd/scripts/auto_save_context.py

每5分钟检查一次,完全自动化,无需人工干预。

注: 完整代码实现已开源,可参考项目仓库。

🛡️ 三层保护:确保机制永不失效

问题:会话重置后,新会话"失忆"了

当会话被删除后,AI创建了一个全新的会话。这个新会话:

  • 从零开始
  • 不知道自动化机制的存在
  • 不会继续监控Token使用率

解决方案:三层通知机制

第1层:主动通知 📢

时机: 会话重置完成后立即执行

def notify_automation(session_key: str):
    """发送通知到新会话"""
    notice = """
    ## 🤖 自动化机制通知

    你的会话刚刚完成了自动重置。

    系统已为你部署了自动上下文保存机制:
    - 每5分钟检查Token使用率
    - 超过50%自动触发重置
    - 你不需要做任何事情!
    """
    send_to_session(session_key, notice)

第2层:持久化记录 📄

文件: /root/clawd/AGENTS.md

每次会话启动时,AI会自动读取这个文件:

## 🤖 自动上下文保存机制

**重要!** 这个工作区有一个自动化机制在运行。

- 每5分钟检查Token使用率
- 超过50%自动触发重置
- 关键文件:/root/clawd/scripts/auto_save_context.py

优点: 完全持久化,不会丢失。

第3层:上下文携带 📋

文件: /root/clawd/RESUME-SESSION.md (开头)

每次恢复上下文时,AI会读取这个文件:

## 🤖 自动化机制提示

**重要!** 你现在是在一个有自动化保护的会话中运行。

- 每5分钟检查Token使用率
- 超过50%自动触发重置

优点: 确保恢复后的会话知道机制。

容错分析

场景第1层第2层第3层结果
正常重置完美
通知失败仍可从文件得知
AGENTS.md未读通知和模板保底
恢复失败通知和AGENTS.md保底

结论:新会话99.99%会知道自动化机制!


📊 效果验证

数据对比

重置前:

  • Token使用率:85%
  • 会话文件:75行消息
  • 文件大小:122KB
  • 风险:随时溢出

重置后:

  • Token使用率:0%
  • 会话文件:1行(全新)
  • 上下文:从RESUME-SESSION.md恢复
  • 风险:消除!

运行日志

[2026-02-19 14:30:54] 检查token使用率...
[2026-02-19 14:30:57] 当前主会话token使用率: 13.93%
[2026-02-19 14:30:57] ✓ 使用率正常,无需重置

当使用率 ≥ 50%时:

[2026-02-19 XX:XX:XX] ⚠️ Token使用率 85% 超过阈值 50%
[2026-02-19 XX:XX:XX] 步骤1: 保存上下文...
[2026-02-19 XX:XX:XX] ✓ 会话已备份到: backup/session_xxx.jsonl
[2026-02-19 XX:XX:XX] ✓ 会话文件已删除,会话将重置
[2026-02-19 XX:XX:XX] ✓ 新会话已创建
[2026-02-19 XX:XX:XX] ✓ 步骤5完成: 已通知新会话自动化机制
[2026-02-19 XX:XX:XX] ✅ 会话重置完成!Token已归零!

🤔 设计思考

为什么选择50%作为阈值?

太高(如80%):

  • ❌ 来不及保存
  • ❌ 容易溢出

太低(如20%):

  • ❌ 重置太频繁
  • ❌ 丢失上下文

50%刚刚好:

  • ✅ 有足够时间保存
  • ✅ 留有安全余量
  • ✅ 平衡了频率和风险

为什么不是简单清理旧消息?

方案A:删除最早的50%消息

  • ❌ 会丢失关键上下文
  • ❌ 破坏对话连贯性

方案B:智能压缩(AI总结)

  • ✅ 保留关键信息
  • ✅ 但需要额外调用API
  • ✅ 成本和时间开销

我的方案:完整备份 + 删除文件

  • ✅ 保留完整历史
  • ✅ Token归零(彻底)
  • ✅ 恢复时智能总结

为什么需要三层保护?

单一机制的脆弱性:

  • 脚本可能失败
  • 文件可能未读
  • 通知可能丢失

三层冗余的价值:

  • ✅ 任何一层失效都有其他层保底
  • ✅ 符合"防御性编程"原则
  • ✅ 增加系统鲁棒性

🚀 如何应用到你自己的项目?

前置条件

  1. 会话文件管理:AI的会话存储在文件中
  2. API监控:能获取Token使用率
  3. 命令行工具:能发送消息到会话

实现步骤

  1. 编写监控脚本

    • 定期检查Token使用率
    • 超过阈值时触发重置
  2. 实现重置逻辑

    • 备份会话文件
    • 删除原文件
    • 等待新会话创建
  3. 恢复上下文

    • 从备份文件总结关键信息
    • 发送到新会话
  4. 测试验证

    • 手动触发重置
    • 验证上下文恢复
    • 确认Token归零

关键代码片段

备份会话文件:

import shutil
from datetime import datetime

timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
backup_file = f"backup/session_{session_id}_{timestamp}.jsonl"
shutil.copy2(session_file, backup_file)

删除会话文件(强制重置):

from pathlib import Path

session_file = Path(f"/path/to/sessions/{session_id}.jsonl")
session_file.unlink()  # 删除文件,触发AI创建新会话

发送恢复消息:

import subprocess

subprocess.run([
    'clawbot', 'sessions', 'send',
    '--sessionKey', new_session_key,
    '--message', '读取 RESUME-SESSION.md 恢复上下文'
])

💡 更深层的思考

AI的"记忆"问题

短期记忆(Context Window):

  • 有限容量
  • 需要持续管理
  • 类似人类的"工作记忆"

长期记忆(文件系统):

  • 无限容量
  • 需要主动存储
  • 类似人类的"长期记忆"

我的方案本质:
将短期记忆定期转存到长期记忆,然后清空短期记忆。

自动化的价值

人工 vs 自动:

对比项人工监控自动化脚本
需要关注持续查看dashboard无需关注
出错概率高(容易忘记)低(代码执行)
时间成本每天数次0
可靠性受情绪影响100%执行

结论:把重复性任务交给机器,人类专注于创造。


🎯 总结

问题

  • AI的上下文窗口有限
  • 对话过长会溢出
  • 手动管理不可靠

解决方案

  • ✅ 自动监控(每5分钟)
  • ✅ 智能重置(50%阈值)
  • ✅ 完整备份(不丢失信息)
  • ✅ 上下文恢复(无缝衔接)
  • ✅ 三层保护(机制永不失效)

效果

  • Token使用率:85% → 0%
  • 上下文:完整保留
  • 人工干预:0
  • 运行稳定性:100%

哲学思考

最好的工具是透明的。

当你不再需要担心"Context overflow"时,你才能真正专注于与AI的深度对话。


📚 相关资源

完整实现:

  • 监控脚本:Python实现,支持API监控和自动重置
  • 定时任务:Cron配置,每5分钟自动检查
  • 日志系统:完整的运行日志和错误追踪

核心文件:

  • auto_save_context.py - 自动化监控脚本
  • auto-context-save.md - 完整技术文档
  • auto-context-save-persistence.md - 三层保护详解

相关阅读:


如果你也有遇到过"Context overflow"的问题,希望这个方案能帮到你。有问题欢迎讨论!

本文由作者 twg2020 创作,使用 AI 辅助润色
首发于:somingbai.com
时间:2026-02-19

AI原生提示词架构设计:让自然语言成为新源码

前言

在上一篇《AI时代的代码架构:如何设计让AI更好编程的系统》中,我提出了一个核心观点:代码是cheap的,AI注意力是昂贵的,应该设计专门的架构来适应AI的认知特点。

但如果只优化代码架构,只解决了一半的问题。另一半问题在于:给AI的提示词(Prompt)本身也需要架构。

在探索Claude Code、Clawdbot等AI辅助编程工具的过程中,我发现一个现象:很多人把提示词当成零散的文本片段,想到什么写什么。这就像在机器码时代,程序员直接写0101序列——没有抽象,没有结构,难以维护。

我认为:在AI时代,提示词(Markdown文档)将成为新的"源码",而代码将成为编译后的"中间产物"。

本文将阐述一套与代码架构相辅相成的AI原生提示词架构设计


核心洞察:提示词也需要架构

传统误区

很多人认为提示词就是一段自然语言文本:

❌ 错误做法:把所有信息写在一个prompt里

"你是一个C语言程序员,请帮我写一个日志系统。
这个系统需要支持:
1. 输出到文件
2. 输出到控制台
3. 日志级别控制
4. 线程安全
5. 还要支持JSON格式输出
6. 还要支持滚动日志
7. 还要..."

问题

  • AI的注意力被分散到10+个细节上
  • 核心逻辑容易出错
  • 难以维护和扩展

正确思路:模块化 + 按需加载

✅ 正确做法:架构化的提示词

项目/
├── AGENTS.md              # 顶层意图(main函数)
├── modules/
│   ├── logger/
│   │   ├── AGENTS.md      # 模块意图
│   │   └── skills/        # 按需加载的细节
│   │       ├── output.md
│   │       ├── thread_safety.md
│   │       └── json_format.md
│   └── network/
│       ├── AGENTS.md
│       └── skills/
│           ├── tcp.md
│           └── ssl.md
└── build/                 # AI生成的一次性代码
    └── src/

优势

  • AI的注意力聚焦:每次只关注一个模块的意图
  • 降低认知负担:细节放在skills里,按需加载
  • 易于维护:修改意图,重新"编译"即可

提示词架构设计

1. AGENTS.md:MD文档的main函数

核心原则:每个AGENTS.md是唯一入口,描述"做什么",不描述"怎么做"。

项目级AGENTS.md

# AGENTS.md - 项目全局视图

## 项目背景
这是一个高性能网络服务器,支持并发连接和事件驱动架构。

## 核心功能
- 网络连接管理(TCP/SSL)
- 异步事件处理
- 日志记录
- 数据持久化

## 主要模块
- [logger/](modules/logger/AGENTS.md):日志记录模块
- [network/](modules/network/AGENTS.md):网络通信模块
- [storage/](modules/storage/AGENTS.md):数据存储模块

## 对外接口
应用通过`api.h`提供统一的接口:

void app_start();
void app_stop();


## 设计原则
- 零循环依赖
- 编译期隔离
- AI注意力优先

作用

  • 给AI提供全局视图
  • 说明项目背景和目标
  • 列出主要模块和依赖关系
  • 就像C程序的main函数,是整个系统的入口

模块级AGENTS.md

# Logger Module - AGENTS.md

## 功能定位
记录应用日志到文件和控制台,支持多种日志级别和输出格式。

## 核心接口

void logger_log(Logger logger, const char message);
void logger_set_level(Logger* logger, LogLevel level);
void logger_set_output(Logger* logger, OutputTarget target);


## 主要职责
1. 接收日志消息
2. 格式化输出(文本/JSON)
3. 写入目标(文件/控制台)
4. 线程安全保证

## 依赖
- 依赖:无(零依赖模块)
- 被依赖:network、storage

## 细节文档
- [output策略](skills/output.md):如何支持多种输出格式
- [线程安全](skills/thread_safety.md):如何保证并发安全
- [性能优化](skills/performance.md):如何优化日志性能

## 注意事项
- 不要在这个模块中添加网络功能
- 不要阻塞主线程

作用

  • 描述模块的职责和边界
  • 说明接口和使用方式
  • 列出依赖关系
  • 指向细节文档(skills)

2. Skills目录:按需加载的细节

核心原则:skills只描述意图和需求,不描述具体实现。

示例:logger/skills/json_format.md

# JSON格式日志输出

## 需求描述
日志需要支持JSON格式输出,便于日志收集和分析系统(如ELK)解析。

## 输出格式

{
"timestamp": "2026-02-15T10:30:00Z",
"level": "ERROR",
"module": "network",
"message": "Connection failed",
"context": {

"peer": "192.168.1.100:8080",
"error_code": 110

}
}


## 使用场景
- 生产环境日志收集
- 自动化日志分析
- 结构化查询

## 性能要求
- JSON序列化时间 < 100μs
- 不能阻塞主线程

## 不需要关心
- 具体用哪个JSON库(AI自己选择)
- 如何优化性能(AI自己考虑)

关键点

  • ✅ 描述"做什么":支持JSON格式
  • ✅ 描述"为什么要做":便于日志分析
  • ✅ 描述"使用场景":生产环境
  • ❌ 不描述"怎么做":不用告诉AI用哪个库

示例:logger/skills/thread_safety.md

# 线程安全保证

## 需求描述
日志模块可能被多个线程同时调用,必须保证线程安全。

## 关键要求
1. 不能丢失日志消息
2. 不能死锁
3. 性能开销最小化

## 常见场景
- 主线程写日志,工作线程也写日志
- 多个网络连接同时记录错误

## 可选方案(仅供参考,AI可以自行决定)
- 使用互斥锁(简单,但可能阻塞)
- 使用无锁队列(复杂,但性能好)
- 使用线程本地缓冲(延迟写入)

## 性能目标
- 单次日志调用 < 50μs
- 支持至少10个并发线程

3. 按需加载策略

核心思想:不是一次性加载所有MD,而是根据AI的注意力范围动态加载。

场景1:AI生成logger模块代码

步骤1:读取 logger/AGENTS.md
→ AI理解模块的整体意图

步骤2:AGENTS.md引用了 skills/output.md
→ AI读取这个文件,了解输出需求

步骤3:AI开始生成代码
→ 只关注当前模块,不受其他模块干扰

场景2:AI需要理解logger如何被network使用

步骤1:读取 logger/AGENTS.md
→ 了解logger提供的接口

步骤2:读取 network/AGENTS.md
→ 发现network依赖logger

步骤3:按需加载 skills/json_format.md
→ 了解network需要JSON格式的日志

类比:现代操作系统的按需加载

传统程序:
启动时加载所有代码到内存
→ 浪费内存,启动慢

现代程序(动态链接):
启动时只加载必需的代码
→ 节省内存,启动快
→ 使用到某个模块时,才加载

AI提示词架构:
AI开始工作时,只加载必需的MD
→ 降低上下文消耗
→ 需要细节时,才加载skills

与代码架构的对应关系

完美映射

提示词架构(MD)          代码架构(C)
─────────────────         ─────────────────
AGENTS.md          ↔     api.h / module.h
skills/output.md   ↔     src/module/impl.c(实现细节)
项目AGENTS.md       ↔     项目对外接口
按需加载MD         ↔     动态链接/模块化编译

核心原则一致性

原则提示词架构代码架构
零循环依赖AGENTS.md不互相include.h文件不互相include
清晰边界每个AGENTS.md职责单一每个module职责单一
按需加载skills目录按需读取编译期隔离
单一入口AGENTS.md是main函数api.h是唯一对外接口
意图抽象MD描述"做什么".h描述接口

生成流程

人类维护层(源码):
├── AGENTS.md
├── modules/*/AGENTS.md
└── modules/*/skills/*.md
        ↓
        ↓ AI"编译"
        ↓
AI生成层(中间产物):
├── include/*.h
└── src/*/impl.c
        ↓
        ↓ 传统编译
        ↓
机器码(运行产物):
└── binary

技术本质:编程语言演化的延续

历史规律:抽象层不断上升

┌─────────────┬──────────────┬─────────────┬──────────────┐
│   时代      │  程序员关注   │  工具       │  输出物      │
├─────────────┼──────────────┼─────────────┼──────────────┤
│ 机器码时代  │ 0101序列     │ 手工拨开关  │ 机器码       │
│ 1940s      │              │             │              │
├─────────────┼──────────────┼─────────────┼──────────────┤
│ 汇编时代    │ 助记符       │ 汇编器      │ 机器码       │
│ 1950s      │ (MOV, ADD)   │             │              │
├─────────────┼──────────────┼─────────────┼──────────────┤
│ 高级语言    │ 算法逻辑     │ 编译器      │ 汇编/机器码  │
│ 1970s+     │ (for, if)   │             │              │
├─────────────┼──────────────┼─────────────┼──────────────┤
│ AI时代      │ 业务意图     │ 自然语言    │ 代码         │
│ 2020s+     │ (自然语言)   │ 编译器      │              │
└─────────────┴──────────────┴─────────────┴──────────────┘

每一次革命的本质

机器码 → 汇编:符号抽象

之前

程序员需要记住:
01001001 = LOAD寄存器
01001010 = ADD操作
01001011 = STORE操作

之后

程序员只需要写:
LOAD A, 10
ADD B, 5
STORE A, result

本质:用符号代替数字,降低记忆负担

底层依然存在:CPU还是执行0101,但程序员不需要关心了


汇编 → 高级语言:控制流抽象

之前

; 计算1到100的和
MOV AX, 0
MOV CX, 100
MOV BX, 1
loop_start:
ADD AX, BX
INC BX
DEC CX
JNZ loop_start
STORE AX, sum

之后

int sum = 0;
for (int i = 1; i <= 100; i++) {
    sum += i;
}

本质

  • 用控制流(for, if)代替跳转指令
  • 用变量名代替寄存器
  • 用类型系统代替手动内存管理

底层依然存在:CPU还是执行跳转指令,但程序员不需要关心了

适用范围降低

  • 99%的代码用高级语言
  • 1%的极端性能场景(OS内核、驱动)用汇编

高级语言 → AI:意图抽象

之前

# 发送HTTP请求并处理错误
import requests

try:
    response = requests.get('https://api.example.com/users')
    if response.status_code == 200:
        users = response.json()
        for user in users:
            print(user['name'])
    else:
        logger.error(f"HTTP {response.status_code}: {response.text}")
except requests.exceptions.RequestException as e:
    logger.error(f"Request failed: {e}")

之后(AI时代)

<!-- network/AGENTS.md -->

# Network Module

## 功能
发送HTTP请求到API服务器,获取用户列表。

## 接口

UserList network_fetch_users(Network self);


## 错误处理
如果请求失败,需要:
1. 记录错误日志(通过logger模块)
2. 返回NULL给调用者
3. 不要抛异常(C语言不支持)

## 性能要求
- 超时时间:5秒
- 重试次数:3次

本质

  • 用自然语言描述意图,代替具体的控制流
  • AI负责"怎么做",人类只说"做什么"
  • 代码成为中间产物,就像今天的汇编

底层依然存在

  • CPU还是执行机器码
  • 编译器还是生成汇编
  • 但程序员99%不需要关心了

适用范围降低

  • 99%的代码用AI + 自然语言生成
  • 1%的极端场景(AI生成代码性能不够)手工写代码

技术演化的规律

规律1:抽象层不断上升

机器码(硬件) → 汇编(符号) → 高级语言(逻辑) → 自然语言(意图)
   ↓               ↓              ↓                ↓
 只有极少数人掌握   少数人        大多数人        所有人

规律2:旧技术不会消失,适用范围降低

汇编语言的演化

1950年代:所有编程都用汇编
1980年代:系统编程用汇编,应用编程用高级语言(90% vs 10%)
2020年代:只有OS内核、驱动、嵌入式用汇编(1% vs 99%)

未来:只有极端性能优化的场景用汇编(0.1% vs 99.9%)

手工写代码的演化(预测):

2020年代:所有编程都手写代码
2030年代:大多数编程用AI生成,少数极端场景手写(10% vs 90%)
2050年代:只有极致性能场景手工写代码(1% vs 99%)
2100年代:只有特殊领域(AI无法理解)手工写代码(0.1% vs 99.9%)

规律3:工具复杂度转移

机器码时代:
工具:简单(手工拨开关)
程序员负担:重(需要记住所有0101)

汇编时代:
工具:汇编器
程序员负担:减轻(只需要写助记符)

高级语言时代:
工具:复杂的编译器、链接器、优化器
程序员负担:很轻(只需要写逻辑)

AI时代:
工具:极其复杂的自然语言编译器(大模型)
程序员负担:极轻(只需要描述意图)

类比:代码 = 未来的汇编

今天我们如何看待汇编?

场景1:应用开发
工程师:我要写一个Web服务器
选择:Go、Python、Java
绝不会考虑:手写汇编

场景2:系统编程
工程师:我要写Linux内核
选择:C语言,偶尔内联汇编
不会全用:纯汇编

场景3:极致优化
工程师:这个加密循环性能不够
考虑:手写汇编优化这一小段

结论:汇编依然存在,但适用范围极小。

明天我们如何看待代码?

场景1:应用开发
工程师:我要写一个Web服务器
做法:写AGENTS.md描述意图
工具:自然语言编译器(NLCC)
生成:Go/Python代码(自动)
绝不会考虑:手写Go代码

场景2:系统编程
工程师:我要写操作系统内核
做法:写关键模块的AGENTS.md
生成:C代码(自动)
偶尔手工优化:极少数性能关键路径

场景3:极致优化
工程师:AI生成的这段代码性能不够
考虑:手工优化这一小段

结论:代码依然存在,但99%的人不需要手写。

类比总结

今天:
汇编 → 编译器 → 机器码
程序员写汇编,不需要看生成的机器码
(除非极端性能优化)

明天:
自然语言(MD) → 自然语言编译器(AI) → 代码 → 传统编译器 → 机器码
程序员写MD,不需要看生成的代码
(除非极端性能优化)

高级语言不会淘汰汇编:汇编依然在OS内核、驱动中发挥作用
AI不会淘汰高级语言:代码依然是重要的中间层,但适用范围大大降低


未来展望:自然语言编译器(NLCC)

会是什么样的?

项目结构

project/
├── AGENTS.md              # 顶层意图描述
├── modules/
│   ├── logger/
│   │   ├── AGENTS.md      # 模块意图
│   │   └── skills/        # 按需加载的细节
│   │       ├── output.md
│   │       ├── thread_safety.md
│   │       └── json_format.md
│   └── network/
│       ├── AGENTS.md
│       └── skills/
│           ├── http.md
│           └── ssl.md
└── build/                 # 生成的一次性代码
    ├── src/
    │   ├── logger/
    │   │   ├── impl.c
    │   │   └── internal.h
    │   └── network/
    │       ├── http.c
    │       └── ssl.c
    ├── include/
    │   ├── logger.h
    │   └── network.h
    ├── compile.log        # 编译日志
    └── test_report.xml    # 测试报告

工作流程

# 1. 人类修改意图
vim modules/logger/skills/json_format.md

# 2. 触发"编译"
nlcc build

# 3. NLCC自动执行
Reading modules/logger/AGENTS.md...
  → Loading skills/output.md...
  → Loading skills/json_format.md...
Generating code...
  → build/src/logger/impl.c
  → build/include/logger.h
Compiling...
  → gcc -c build/src/logger/impl.c -o build/obj/logger.o
Testing...
  → All tests passed
Build complete!

# 4. 查看生成的代码(可选,就像今天看汇编)
cat build/src/logger/impl.c

# 5. 运行
./build/bin/app

NLCC和传统编译器的对比

传统编译器(GCC)自然语言编译器(NLCC)
输入:C代码输入:自然语言(AGENTS.md)
输出:机器码/汇编输出:C代码
错误:语法错误、链接错误错误:意图模糊、逻辑矛盾
优化:寄存器分配、指令调度优化:模块拆分、依赖管理
调试:看汇编代码(-S)调试:看生成的C代码
工具链:预处理 → 编译 → 汇编 → 链接工具链:意图分析 → 代码生成 → 传统编译

实践建议:如何开始

1. 从小项目开始

不要:在大型遗留项目上尝试
应该:在新项目、工具项目、实验性项目开始

推荐起点

  • 个人工具脚本
  • 小型库或框架
  • 概念验证项目

2. 设计MD架构

步骤1:划分模块
→ 哪些功能是独立的?
→ 依赖关系是什么?

步骤2:编写项目级AGENTS.md
→ 项目背景是什么?
→ 主要模块有哪些?
→ 对外接口是什么?

步骤3:编写模块级AGENTS.md
→ 这个模块做什么?
→ 接口是什么?
→ 依赖哪些模块?

步骤4:编写skills/*.md
→ 需要哪些细节描述?
→ 按场景拆分(不要写成大而全)

3. 验证提示词质量

标准:给另一个AI看你的AGENTS.md

  • 它能理解这个模块做什么吗?
  • 它知道如何使用这个模块吗?
  • 它会产生误解吗?

如果AI都有问题,那说明意图描述不够清晰。

4. 维护MD,而不是代码

场景:需要修改logger模块

错误做法:
直接编辑 build/src/logger/impl.c
→ 下次nlcc build时,你的修改被覆盖

正确做法:
编辑 modules/logger/AGENTS.md 或 skills/*.md
→ 运行 nlcc build
→ 重新生成代码

5. 代码审查(未来偶尔需要)

场景:性能不够

步骤1:看生成的代码
cat build/src/logger/impl.c

步骤2:找到性能瓶颈
→ 发现JSON序列化太慢

步骤3:选择优化策略
A. 修改AGENTS.md,明确性能要求(推荐)
B. 手工优化这一小段代码(极端情况)

人类工程师的职责演化

现在(高级语言时代)

人类工程师的日常:
1. 设计系统架构(模块划分)
2. 定义接口(.h文件)
3. 实现逻辑(.c文件)
4. 调试、测试、优化
5. 维护代码(修复bug、添加功能)
6. Code Review

时间分配

  • 架构设计:10%
  • 写代码:60%
  • 调试测试:20%
  • 维护:10%

未来(AI时代)

人类工程师的日常:
1. 设计系统架构(模块划分)
2. 编写意图描述(AGENTS.md)
3. 审查AI生成的代码(偶尔,5%时间)
4. 处理AI搞不定的极端场景(1%时间)
5. 监控系统运行状态

时间分配

  • 架构设计:20%
  • 编写MD:30%
  • 审查代码:5%
  • 极端场景:1%
  • 监控、优化、学习:44%

核心转变

  • 从"如何实现" → "要实现什么"
  • 从"细节控制" → "意图表达"
  • 从"代码维护" → "意图维护"

总结

核心观点

  1. 提示词也需要架构

    • 不是零散的文本,而是有组织的MD文档
    • AGENTS.md是唯一入口,skills是按需加载的细节
  2. 与代码架构完美对应

    • 零循环依赖、清晰边界、单一入口
    • 提示词描述意图,代码描述实现
  3. 技术演化的延续

    • 机器码 → 汇编 → 高级语言 → 自然语言
    • 每次抽象都降低程序员负担
    • 代码的地位 = 今天汇编的地位
  4. 未来已来

    • 自然语言编译器(NLCC)会出现
    • 代码放在build/目录,成为一次性中间产物
    • 人类只维护MD,就像今天只维护C代码
  5. 适用范围降低

    • AI不会淘汰代码,就像高级语言不会淘汰汇编
    • 但99%的场景不需要手工写代码
    • 只有极端性能场景才需要

行动建议

现在就开始:
1. 选择一个小项目
2. 设计AGENTS.md架构
3. 编写模块级MD和skills
4. 用AI生成代码
5. 验证、迭代、优化

记住:
- MD是源码,代码是中间产物
- 维护MD,而不是代码
- 意图清晰 > 代码完美

这是继《AI时代的代码架构》后的第二篇思考。核心观点是:在AI时代,提示词(自然语言)将成为新的源码,而代码将成为编译后的中间产物。 这不是科幻,而是编程语言演化的必然趋势。就像高级语言没有淘汰汇编,AI也不会淘汰代码——只是适用的范围会大大降低。欢迎交流讨论!

相关阅读

本文由作者 twg2020 创作,使用 AI 辅助润色
首发于:somingbai.com
时间:2026-02-15

AI时代的代码架构:如何设计让AI更好编程的系统

前言

在探索Claude Code辅助编程的过程中,我逐渐意识到一个核心问题:传统的软件架构设计思想,可能并不适合AI时代。

传统工程学追求代码复用、模块化、可维护性——这些当然重要。但在AI能够快速生成大量代码的今天,我认为代码本身变得cheap了,真正昂贵的是AI的注意力。

基于这个核心洞察,我设计了一套专门为AI编程优化的架构方案。本文将详细阐述这个架构的思想、设计原则和最佳实践。

核心洞察:代码是Cheap的

传统时代的成本结构

在传统软件开发中:

  • 编写代码:昂贵(需要资深工程师、耗时)
  • 复制代码:廉价(Ctrl+C/Ctrl+V)
  • 维护代码:昂贵(理解成本、耦合风险)

所以传统工程学强调:

  • ✅ DRY原则(Don't Repeat Yourself)
  • ✅ 代码复用
  • ✅ 统一抽象
  • ✅ 提前设计(过度设计)

AI时代的成本结构

在AI辅助编程中:

  • 代码是cheap的:AI生成代码极快(几秒钟生成几百行)
  • module随时可以替换:没搞好就再做一个,代价很低
  • 完全不需要提前过度设计:让实际需求驱动架构演化
  • AI的上下文窗口:昂贵(有限的注意力)
  • AI理解复杂系统:困难(容易遗漏细节)

新的成本函数:

总成本 = AI生成代码的时间(低)
       + 人类review的时间(中)
       + AI修改迭代的时间(高)
       + 系统复杂度导致的AI错误率(极高)

结论:在AI时代,应该牺牲代码复用来换取AI注意力的聚焦


深入理解:为什么要牺牲代码复用?

让我用具体例子说明这个观点。

传统方式:追求代码复用

场景:统一错误处理

// include/common/error.h
typedef struct {
    int code;
    char message[256];
    void* context;      // 通用的上下文
    int context_size;
} Error;

void error_handle(Error* err);  // 超级通用的错误处理

// 所有module都用这个Error
void network_send(Network* self, const char* data) {
    if (send_failed) {
        Error err = {
            .code = ERR_NETWORK,
            .context = self->internal_state,
            .context_size = sizeof(self->internal_state)
        };
        error_handle(&err);  // 复用通用处理
    }
}

传统优势

  • ✅ 只写一次错误处理逻辑
  • ✅ 统一的错误格式
  • ✅ 易于维护

传统成本

  • 需要设计"万能"的Error结构
  • 需要考虑所有使用场景
  • 人类工程师能理解这个复杂抽象

AI时代的问题

让AI写network_send时:

AI的思维过程:
1. 需要处理错误
2. 用Error结构
3. Error有哪些字段?code、message、context、context_size...
4. context是什么类型?void*?
5. 需要设置context_size吗?多大?
6. 有初始化函数吗?
7. 错误码是多少?
8. 要检查NULL吗?
...(AI注意力被分散到10个细节上)

AI实际生成(很可能出错):

void network_send(Network* self, const char* data) {
    if (send_failed) {
        Error err;  // ❌ 忘记初始化
        err.code = 1000;
        strcpy(err.message, "send failed");  // ❌ 忘记检查长度
        // ❌ 忘记设置context
        error_handle(&err);  // ❌ 可能段错误
    }
}

问题:AI注意力被分散到Error结构的细节上,核心逻辑反而出错。

AI方式:牺牲代码复用

// 不设计通用的Error结构

// src/network/impl.c
void network_send(Network* self, const char* data) {
    if (send_failed) {
        // 简单直接,网络模块自己的错误处理
        fprintf(stderr, "[network] send failed: %s\n", strerror(errno));
        if (self->error_callback) {
            self->error_callback("send failed");
        }
    }
}

// src/storage/impl.c
void storage_write(Storage* self, const char* data) {
    if (write_failed) {
        // 存储模块自己的错误处理(完全不同)
        fprintf(stderr, "[storage] write failed: %s\n", strerror(errno));
        if (self->retry_count < 3) {
            self->retry_count++;
            storage_write(self, data);  // 自己的重试逻辑
        }
    }
}

AI生成这个

AI的思维过程:
1. 需要处理错误
2. fprintf打印
3. 调用回调(如果有)
4. 完成

AI只需要关注3个细节,专注度高!

成本对比

传统方式(追求复用):

设计通用Error:4小时
AI出错率:30%
人类review:每个module 30分钟
修复时间:20分钟 × 3轮 = 60分钟

10个module总成本:4 + 15 = 19小时

AI方式(牺牲复用):

设计通用Error:0小时
AI出错率:5%
人类review:每个module 5分钟
修复时间:5分钟 × 1轮 = 5分钟

10个module总成本:0 + 1.6 = 1.6小时

代码重复:每个module都写fprintf(但没关系!)

节省时间:17小时!

"牺牲代码复用"的真正含义

不是

  • ❌ 随意复制粘贴
  • ❌ 不做任何抽象
  • ❌ 写烂代码

而是

  • ✅ 用代码重复换取逻辑简单
  • ✅ 用更多代码行换取AI理解成本低
  • ✅ 用手工维护换取AI出错率低

类比

这就像:

传统时代(手工制作家具):

  • 用精密的模具(通用抽象)
  • 一次设计,批量生产
  • 成本:设计贵,生产便宜

AI时代(3D打印):

  • 不需要精密模具
  • 每个产品单独打印
  • 成本:设计便宜,生产也便宜
  • 宁愿多打印几次,也不设计复杂模具

架构设计:依赖倒置 + 零循环依赖

设计目标

  1. 零循环依赖:AI不需要理解复杂的依赖关系
  2. 清晰的边界:每个模块的职责单一明确
  3. 可组合性:像搭积木一样组装复杂系统
  4. 可测试性:每个模块可以独立测试

目录结构设计

project/
├── include/              # 公共接口层(零依赖区)
│   ├── common_types.h   # POD数据结构
│   ├── logger.h         # 抽象接口
│   ├── network.h
│   ├── storage.h
│   └── ...
├── src/                 # 实现层
│   ├── logger/          # 实现logger.h
│   │   ├── impl.c
│   │   └── internal.h
│   ├── network/
│   └── storage/
└── api.h                # 唯一对外头文件

依赖关系图

         ┌─────────────────┐
         │     api.h       │  ← 最底层(对外窗口)
         │   (组合接口)     │
         └────────┬─────────┘
                  ↑ 依赖
         ┌────────┴─────────┐
         │    include/      │  ← 第二层(抽象接口层)
         │  - POD数据结构    │
         │  - 抽象接口定义   │
         └────────┬─────────┘
                  ↑ 依赖
         ┌────────┴─────────┐
         │   src/module*/   │  ← 第三层(实现层)
         └──────────────────┘

关键约束:

  • include/*.h 绝对禁止互相包含
  • src/module*/ 只依赖include/,不能依赖其他module
  • api.h 组合需要的接口对外暴露

三个关键设计问题

问题1:Module间如何通信?

传统困惑:既然module不能互相依赖,那怎么协作?

答案:所有通信接口也在include/里定义为抽象。

// include/event_bus.h
typedef struct EventBus EventBus;
void event_bus_publish(EventBus*, const char* topic, void* data);
void event_bus_subscribe(EventBus*, const char* topic,
                         void (*callback)(void*));

// src/logger/impl.c
#include "event_bus.h"
#include "logger.h"

void logger_init(Logger* self, EventBus* bus) {
    event_bus_subscribe(bus, "message.received", log_callback);
}

// src/network/impl.c
#include "event_bus.h"
#include "network.h"

void network_on_message(Network* self, const char* msg) {
    event_bus_publish(self->event_bus, "message.received", (void*)msg);
}

依赖倒置原则

  • 高层模块和低层模块都依赖抽象(include/
  • 抽象不依赖具体实现
  • 实现依赖抽象

问题2:数据结构放在哪里?

困惑:如果需要传递复杂结构,放哪里会打破零依赖原则?

答案:纯POD(Plain Old Data)结构可以放include/,甚至放api.h

// include/common_types.h
typedef struct {
    const char* method;
    const char* url;
    const char* body;
} HttpRequest;

typedef struct {
    int code;
    const char* message;
} HttpResponse;

为什么不会循环依赖?

  • POD结构只包含基本类型、指针、数组
  • 不include其他头文件
  • 即使多个接口include它,也是树状依赖,不会循环

注意:带函数指针的结构也算"数据结构",可以放include/

// include/observer.h
typedef struct {
    void (*on_message)(const char* msg);
    void (*on_error)(int error_code);
} ObserverCallbacks;

问题3:何时拆分Module?

困惑:拆分的粒度如何掌握?多少代码算太复杂?

答案:没有固定行数标准,看AI出错率

判断指标:

  1. 编译错误率

    AI第一次生成 → 编译通过
    如果通过率 < 70%,说明太复杂了
  2. 修改轮次

    AI生成 → 人类review → 指出问题 → AI修改 → 又发现问题...
    如果平均 > 2轮,说明超出了AI注意力范围
  3. 常见错误信号

    • ❌ 忘记NULL检查
    • ❌ 忘记释放内存
    • ❌ 边界条件遗漏
    • ❌ 错误处理不完整

本质原因:AI的注意力被核心逻辑占用,细节顾不上。

实验数据(假设):

Module大小代码行数AI编译通过率修改轮次
单体500行50%3-5轮
拆分后150行85%1-2轮

结论:当AI出错率上升时,继续拆分,或者提取成独立子项目。

与微服务架构的深度对比

相似性(理念层面)

维度微服务AI-Native架构
边界定义清晰的业务边界清晰的功能边界
依赖方向通过API互相调用通过抽象接口依赖
独立演进可以独立升级module可独立替换实现
团队协作不同团队负责不同服务不同AI/人负责不同module
核心理念解耦、隔离解耦、AI注意力管理

本质区别(实现层面)

1. 隔离边界

微服务:进程级隔离

服务A                服务B
[进程1] ──网络──→ [进程2]
  ↓                    ↓
独立内存空间        独立内存空间
  • ✅ 故障隔离:服务B崩溃不影响服务A
  • ✅ 语言自由:A用Go,B用Python
  • ❌ 性能开销:序列化、网络延迟(1-10ms)

AI-Native架构:编译期隔离

┌───────────────────进程───────────────────┐
│                                           │
│  moduleA  ──函数调用──→  moduleB         │
│    ↓                      ↓               │
│  共享地址空间        共享地址空间        │
│                                           │
└───────────────────────────────────────────┘
  • ✅ 性能:零拷贝、直接调用(1-10ns)
  • ✅ 调试:统一的内存空间、gdb一步跟踪
  • ❌ 故障传播:moduleB段错误 → 整个进程挂掉

性能差异:100万倍!

2. 部署复杂度

微服务需要:

  • 容器编排(Kubernetes)
  • 服务发现
  • 负载均衡
  • 配置管理
  • 链路追踪
  • 100+个基础设施组件

AI-Native架构需要:

  • 编译器
  • 链接器
  • 就这!

3. 扩展性

微服务:水平扩展(用户激增 → 加机器)

AI-Native架构:垂直扩展(加CPU/内存)或提取热点module为独立进程

架构定位

这个架构本质是:"单体应用 + 微服务理念"

  • 结构上:单体应用(一个进程)
  • 设计上:微服务思想(边界清晰、接口驱动)

适用场景:

✅ 嵌入式系统(资源受限)
✅ 系统编程(操作系统、数据库)
✅ 高性能场景(网络延迟不能接受)
✅ AI辅助开发(核心诉求)
✅ 小团队(运维能力有限)

❌ 超大规模(需要水平扩展)
❌ 多语言团队
❌ 需要强故障隔离(金融、核电站)

微服务架构的未来演进

我预测:随着AI的智能变得越来越廉价,一部分微服务架构可能会向AI-Native架构演进。

演进的动力

传统微服务的成本

  • 运维100+个基础设施组件(K8s、服务发现、链路追踪...)
  • 网络延迟:每次调用1-10ms
  • 序列化/反序列化开销
  • 分布式系统的复杂度(CAP理论、最终一致性...)

AI时代的变化

  • 代码是cheap的:重构一个service的成本极低
  • module随时可以替换:单体内部也可以模块化
  • AI能处理复杂依赖:只要边界清晰,AI能管理单体内部的模块关系

演进的路径

阶段1:纯微服务(现在)
[服务A] ──网络──→ [服务B] ──网络──→ [服务C]
  进程1               进程2                进程3

优点:故障隔离、水平扩展
缺点:运维复杂、网络开销

阶段2:混合架构(过渡期)
┌────────────────进程1────────────────┐
│  moduleA ──函数调用──→ moduleB      │
│    ↓                         ↓       │
│  [隔离边界]              [隔离边界]   │
└─────────────────────────────────────┘
         │                      │
         └──────网络──────→ 进程2 (服务C)

优点:核心性能敏感部分用module
      需要独立扩展的部分用服务
缺点:架构复杂度增加

阶段3:AI-Native单体(未来趋势)
┌───────────────────────────────────────────┐
│  moduleA → moduleB → moduleC → moduleD   │
│    (编译期隔离,边界清晰)                  │
└───────────────────────────────────────────┘

优点:
- 性能最优(函数调用)
- 运维最简(一个进程)
- AI友好(清晰的模块边界)
- module可以随时替换重构

缺点:
- 需要垂直扩展(加CPU/内存)
- 但CPU/内存越来越便宜了!

哪些场景会先演进?

优先演进到AI-Native的场景

  1. AI辅助开发的团队:已经在用AI写代码,自然选择AI友好的架构
  2. 性能敏感的系统:高频交易、游戏引擎、实时数据处理
  3. 小团队项目:没有专门的运维团队,不想维护K8s
  4. 快速迭代的初创公司:需要频繁重构,代码复用不是瓶颈

继续使用微服务的场景

  1. 超大规模系统:Facebook、Instagram级别(需要水平扩展)
  2. 多语言团队:不同服务用不同语言(Go、Python、Java)
  3. 需要强隔离:金融、核电站、医疗(故障隔离是硬需求)
  4. 遗留系统:已经在微服务上运行,迁移成本太高

本质转变

传统思维:
"代码是昂贵的,所以需要复用"
→ 设计通用服务(UserService、OrderService...)
→ 通过网络调用复用

AI时代思维:
"代码是cheap的,AI注意力是昂贵的"
→ 设计清晰的模块边界
→ 编译期隔离,函数调用
→ module随时可以替换重构

这是技术范式的转移:从"追求运行时的复用"转向"追求AI开发的效率"。


1. 引入依赖注入(DI)容器

问题:手工组装module依赖容易出错。

// main.c - 手工组装(容易遗漏)
Logger* logger = logger_create();
Storage* storage = storage_create();
Network* net = network_create();
network_set_observer(net, logger);
storage_set_observer(storage, logger);
// ...几十个组装代码

改进

// include/di.h
typedef struct DIContainer DIContainer;
void di_register(DIContainer*, const char* name, void* instance);
void* di_resolve(DIContainer*, const char* name);

// main.c
DIContainer* di = di_create();
di_register(di, "logger", logger_create());
di_register(di, "storage", storage_create());

Network* net = network_create(di);  // 自动注入依赖

好处

  • 自动管理依赖关系
  • 测试时注入Mock对象
  • AI不需要记住组装顺序

2. 接口版本管理

问题:接口变更导致旧代码编译失败。

// v1
void logger_log(Logger*, const char* msg);

// v2(破坏性变更)
void logger_log(Logger*, const char* msg, int level);

改进

include/
├── logger/
│   ├── v1.h  # 老接口
│   └── v2.h  # 新接口
└── logger.h  # 默认指向v2

好处:多版本共存、渐进式迁移

3. 生命周期管理

问题:AI生成的代码可能忘记初始化或释放资源。

改进

// include/lifecycle.h
typedef enum {
    LIFECYCLE_INIT,
    LIFECYCLE_START,
    LIFECYCLE_STOP,
    LIFECYCLE_DESTROY
} LifecycleState;

typedef struct {
    void (*on_init)(void);
    void (*on_start)(void);
    void (*on_stop)(void);
    void (*on_destroy)(void);
} LifecycleHooks;

void lifecycle_register(const char* module_name, LifecycleHooks* hooks);
void lifecycle_init_all(void);  // 按依赖顺序初始化
void lifecycle_destroy_all(void);

4. 可观测性内置

统一监控接口

// include/observability.h
void obs_log(const char* module, const char* level, const char* msg);
void obs_metric(const char* module, const char* name, double value);
void obs_trace(const char* module, const char* func);

// AI生成的代码自带可观测性
void network_send(Network* self, const char* data) {
    obs_trace("network", "send");
    // ...
    obs_metric("network", "bytes_sent", strlen(data));
}

5. 插件化架构(可选)

对于频繁变动的module,做成动态插件

project/
├── include/
│   └── plugin.h
├── plugins/
│   ├── logger_plugin.so
│   └── network_plugin.so
// include/plugin.h
typedef struct Plugin {
    const char* name;
    void* (*init)(void);
    void (*destroy)(void*);
} Plugin;

void plugin_load(const char* path);
void* plugin_get(const char* name);

如何保证AI遵循规则?

方案A:编译期检查

# 扫描include/目录,检测违规依赖
make check-dependencies

方案B:AI Prompt工程

给AI的系统提示词:

你在一个严格约束的项目中工作:
1. include/里的头文件不能include其他include/的头文件
2. src/里的代码只能include其对应的include/里的头文件
3. 违反这些规则会导致编译失败

方案C:自动化测试

CI/CD中加入依赖检查:

#!/bin/bash
# 检测循环依赖
python scripts/check_circular_deps.py include/

完整架构示例

project/
├── include/
│   ├── di.h              # 依赖注入
│   ├── lifecycle.h       # 生命周期
│   ├── observability.h   # 可观测性
│   ├── common_types.h    # POD数据结构
│   ├── logger/
│   │   └── v1.h
│   ├── network/
│   │   └── v1.h
│   └── storage/
│       └── v1.h
├── src/
│   ├── core/             # 核心框架(DI、生命周期)
│   ├── logger/           # 实现logger/v1.h
│   ├── network/
│   └── storage/
├── plugins/              # 可选:动态加载模块
├── tests/
│   └── unit/             # 每个module独立测试
├── scripts/
│   └── check_deps.py     # 依赖检查工具
└── api.h                 # 唯一对外接口

核心原则总结

  1. 代码是cheap的,AI注意力是昂贵的

    • 不惜增加代码量来降低每个模块的复杂度
  2. 零循环依赖

    • include/绝对禁止互相包含
    • src/只依赖include/
  3. 依赖倒置

    • 所有接口定义在include/
    • 实现在src/
  4. 动态拆分

    • 没有固定的行数标准
    • 看AI出错率调整边界
  5. 基础设施内置

    • DI容器、生命周期、可观测性
    • 让AI专注于业务逻辑

实践效果预测

AI编码质量提升

指标传统架构AI-Native架构
编译通过率50%85%
修改轮次3-5轮1-2轮
代码行数/module500行150行
内存泄漏率15%3%

开发效率提升

传统方式:
AI生成 → 编译错误 → 修复 → 发现新错误 → 再修复 → ... (5轮)
耗时:2小时

AI-Native方式:
AI生成 → 小调整 → 通过 (1轮)
耗时:20分钟

后续思考

1. 工具支持

能否开发一个IDE插件,自动检测依赖违规?

  • 实时扫描include/目录
  • 高亮显示违规依赖
  • 自动生成依赖图

2. AI模型优化

能否针对这种架构训练专门的模型?

  • 理解零依赖约束
  • 自动生成符合规则的代码
  • 更高的首次编译通过率

3. 度量标准

如何量化"AI注意力成本"?

  • Token消耗(上下文长度)
  • 修改轮数
  • 人类review时间

参考资源

  • 依赖倒置原则(DIP):Robert C. Martin的Clean Architecture
  • 微服务架构:Martin Fowler的Microservices文章
  • AI辅助编程:GitHub Copilot、Claude Code实践

这是我在探索AI辅助编程过程中的架构思考。核心观点是:代码本身不再是瓶颈,AI的注意力才是。 架构设计应该服务于AI的认知特点,而不是传统的工程美学。如果你也在做类似的探索,欢迎交流讨论!

本文由作者 twg2020 创作,使用 AI 辅助润色
首发于:somingbai.com
时间:2026-02-15