大模型工程化的自举迭代框架:从 Demo 到可持续生产系统的五层实践

大模型项目的最大陷阱不是模型不够强,而是做完 Demo 就停滞了。让一个 LLM 驱动的系统持续稳定运行,需要的不是更好的 prompt,而是一套”让模型能够优化自己工作过程”的工程体系。

引言:Demo 之后是什么

过去一年多,我用 AI 辅助编程从”新奇工具”逐步演变成了日常开发的核心环节1。在这个过程中反复出现一个规律:做一个能跑一次的 Demo 很简单,但让系统持续稳定运行几个月,难度是指数级上升的。

原因不难理解。Demo 只需要 model + prompt 就能出效果,但生产系统面临的是完全不同的约束:

这套经验的本质,可以概括为一个闭环:

graph LR
    A[手动验证] --> B[固化脚本]
    B --> C[定时触发 / CI]
    C --> D[自动收集反馈]
    D --> E[分析 Debug 信息]
    E --> F[蒸馏 / 优化模型或 prompt]
    F --> A

    style A fill:#90EE90
    style B fill:#87CEEB
    style C fill:#87CEEB
    style D fill:#FFD700
    style E fill:#FFD700
    style F fill:#FF6347

让 LLM 不仅解决问题,还能持续优化解决过程本身——这就是”自举”的含义。

下面按成熟度从低到高,逐一拆解五层工程实践。

一、复杂流程固化:不要让 LLM 重复学习同一件事

最基础也最容易被忽略的一层。LLM 每次运行都是从零开始”思考”,但很多流程是稳定的、可重复的。反复让模型重新推导这些固定流程,既是浪费 token,也是引入不确定性。

核心原则:一旦某个流程跑通了三次以上,就把它从 prompt 里抽出来,固化成脚本或 API。

流程类型 固化方式 实例
稳定的 prompt 链 Python 脚本 自动加载 CLAUDE.md,注入项目上下文
周期性测试流程 Nightly 脚本 夜间批量跑回归测试用例2
Agent 重启 / 恢复 tmux + 脚本 自动重启 /loop 循环
外部调用 FastAPI 封装 将 Agent 能力暴露为 HTTP API
# 示例:定时自动化脚本
0 2 * * * /path/to/nightly_test.sh       # 夜间测试
*/30 * * * * tmux send-keys -t claude "load claude.md" Enter  # 定时刷新上下文

固化不仅仅是省 token。更重要的是,一旦流程变成脚本,它就进入了版本控制,可审计、可回归、可复用。这是从”人在驱动模型”到”系统在驱动模型”的第一步。

二、tmux 作为 Agent 运行时核心

这是整套框架里最独特的一层。大多数 LLM 工具链关注的是”调用 API 一次拿结果”,但长期运行的 Agent 需要的是一个持久化的运行时环境。tmux 恰好提供了这个能力。

核心模式:

# 创建持久化 Agent 会话
tmux new -s claude_agent

# 发送 prompt 而不打断会话
tmux send-keys -t claude_agent "analyze the latest logs" Enter

# 捕获输出到文件
tmux capture-pane -t claude_agent -p > latest_output.txt

为什么用 tmux 而不是直接调用 API?三个原因:

  1. LLM 保持长期状态:上下文、记忆、思维宫殿不因单次调用结束而丢失
  2. 自动化脚本可以”悄悄观测”:通过 capture-pane 读取输出,而不干扰正在进行的推理
  3. 崩溃后可恢复:tmux session 独立于进程,即使客户端断开,Agent 仍在运行
sequenceDiagram
    participant Script as 定时脚本
    participant tmux as tmux Session
    participant Agent as Claude Agent
    participant FS as 文件系统

    Script->>tmux: send-keys "nightly test"
    tmux->>Agent: 传递指令
    Agent->>Agent: 执行测试分析
    Script->>tmux: capture-pane 捕获输出
    tmux-->>Script: 输出内容
    Script->>FS: 保存 latest_output.txt
    Note over Script: 解析结果,决定下一步

tmux 在这里承担的角色,类似于容器运行时之于微服务——它提供进程隔离、生命周期管理和输入输出信道。这是把 LLM 当作”长期服务”而非”一次性函数调用”的关键基础设施。

三、Compact Conversation 卡点的工程解法

上下文爆炸是长期运行 Agent 面临的最棘手的工程问题。典型症状:

解法是一个混合记忆策略,把不同生命周期的信息放在不同层级:

class HybridMemory:
    def __init__(self):
        self.short_term = []           # 当前对话窗口
        self.memory_palace = MemoryPalace()  # 结构化长时记忆
        self.claude_memory = ClaudeCodeMemory()  # 原生 memory 机制

    def compact(self):
        # 在压缩前自动提取关键决策
        decisions = extract_important_decisions(self.short_term)
        self.memory_palace.add(decisions)
        # 再调用原生压缩
        self.short_term = self.claude_memory.compress(self.short_term)
卡点症状 方案 工程实现
对话过长 思维宫殿 结构化记忆:summary/entities/relations 保存到 JSON
压缩丢关键信息 定时脚本固化 每次 compact 前自动提取 debug 信息
Agent 迷失 Memory 机制 Claude Code 内置 memory + 外部结构化存储

关键洞察:compact 不是纯压缩,而是一次”蒸馏”——把对话里的噪声压掉,把决策留下来。 这要求在压缩动作前后各加一层逻辑:压缩前提取,压缩后注入核心上下文。

四、埋点驱动的迭代:构建数据飞轮

模型本身不会告诉你它哪里做得不好。要让系统持续改进,需要在生产代码里埋入多层 debug 信息,形成反馈闭环。

Level 1 — 输入输出:
  - raw_prompt
  - llm_response
  - latency / token_usage

Level 2 — 决策路径:
  - which_functions_called
  - compact_triggered_at
  - retry_sequence

Level 3 — 业务结果:
  - task_success (bool)
  - retry_count
  - hallucination_flag

三层埋点的设计遵循从”发生了什么”到”为什么发生”的递进:

graph TD
    A["Nightly 测试失败"] --> B["查 L1 日志:输入输出"]
    B --> C["查 L2 日志:决策路径"]
    C --> D["定位某类错误高频"]
    D --> E["蒸馏正确 case"]
    E --> F["优化 prompt / 微调模型"]
    F --> G["下一轮 Nightly 覆盖"]

    style A fill:#FF6347
    style D fill:#FFD700
    style G fill:#90EE90

这套循环已经在实践中验证过有效。例如在做 Java task_server 到 Rust 的迁移项目中2,Nightly CI 测试失败 → 查 debug 日志 → 发现某类边界条件高频出错 → 把正确处理方法蒸馏到 prompt 模板 → 下一轮覆盖率提升。没有埋点,这个循环就断了。

五、用强类型驯服 LLM 的不确定性

LLM 输出天然 unstructured,但生产系统需要 structured。这两者之间的张力,是所有 LLM 工程化项目的终局问题。

Python 生态里常见的写法是:

if "action" in response:
    do_something()
elif response.get("result"):
    ...

这种防御式编程在面对 LLM 的输出多样性时非常脆弱——模型换一个表达方式,if-else 就漏过去了。

Rust 的强类型系统提供了一种更可靠的方案:

// 强类型约束 LLM 输出结构
#[derive(Deserialize)]
struct LLMAction {
    action_type: ActionType,      // 枚举,非法值直接反序列化失败
    parameters: ValidatedParams,  // Option 强制处理缺失
}

// 而不是散落各处的 `if "action" in response`

强类型在这里的价值不是性能,而是把校验从运行时提到编译期

具体应用场景包括:

工程化成熟度总结

实践 解决的问题 成熟度 复用性
流程固化(脚本/API) 避免 LLM 重复学习 ⭐ 基础 极高
tmux 运行时 Agent 持久化的工程基础 ⭐⭐ 进阶 高(独特点)
Compact 卡点解法 控制 token 成本 + 保留关键信息 ⭐⭐⭐ 高阶
埋点驱动迭代 形成数据飞轮,持续改进 ⭐⭐⭐ 高阶 极高
强类型驯服不确定性 对抗 LLM 输出不可靠 ⭐⭐⭐⭐ 前瞻 中高

自举的本质

回到最核心的那个闭环图。五层实践的共性不是”让模型更强”,而是把人的工程判断逐步沉淀为系统能力

  1. 手动跑通 → 写成脚本(自动化)
  2. 脚本稳定 → 接入 CI(持续化)
  3. CI 出问题 → 埋点收集数据(可观测)
  4. 数据积累 → 分析 pattern → 优化 prompt 或蒸馏模型(自优化)

每一步都是在把”人驱动模型”的占比降低一点,把”系统驱动模型”的占比提高一点。这就是自举的含义——不是一次性配置好就完事,而是构建一套能持续自我改进的机制。

这和软件工程的经典原则并无不同:自动化、可观测、持续集成、反馈闭环。只是这一次,优化的对象不是代码,而是”模型理解代码、生成代码、维护代码”的过程本身。

References

  1. 之前的文章:《One Year of AI-Assisted Programming: Insights, Practices, and Reflections》,2026-01-31。总结了从 AI 工具使用者到将其深度融入日常开发工作流的经验。 

  2. 之前的文章:《从 Java task_server 到 Rust(htyts / htyproc):用 AI 推进迁移,用 GitHub CI 与基础设施兜住 E2E》,2026-03-22。用 AI 驱动的跨语言迁移实践,包含 Nightly CI、Docker Compose 联调、AuthCore 集成等工程化细节。  2

My Github Page: https://github.com/liweinan

B站视频: https://space.bilibili.com/21947620

Powered by Jekyll and Theme by solid

If you have any question want to ask or find bugs regarding with my blog posts, please report it here:
https://github.com/liweinan/liweinan.github.io/issues