AI图鉴

AI图鉴首页 › AI 资讯 › 做了个"状态机 + 台账"的 LLM 应用糖糖写作,聊聊架构踩坑

做了个"状态机 + 台账"的 LLM 应用糖糖写作,聊聊架构踩坑

来源:掘金 · 发布时间:11-02 · 由 AI图鉴每小时自动聚合

把一个长篇写作任务拆成 8 环节状态机ai写作智能体,挂四本结构化台账,规则卡按环节加载。跑完 260 章、70 多万字,这篇只讲架构上哪几个决定是对的、哪几个坑是我自己挖的。

一、先说结论:三个决定是对的,两个是纯踩坑

下面把"为什么"讲清楚。

二、架构长什么样(三层)

┌──────────────────────────────────────────┐

│ 控制层:8 环节状态机 │

│ C14 → DEEPEN → SEED → PLAN → OUTLINE → │

│ DRAFT → REVIEW → FINAL │

│ 职责:知道"现在第几步"、上一环缺字段不放行 │

├──────────────────────────────────────────┤

│ 约束层:26 张规则卡(按环节加载) │

│ 职责:告诉模型"这一步该怎么想" │

├──────────────────────────────────────────┤

│ 记忆层:四本台账(人物/事实/伏笔/摘要) │

│ 职责:让程序记住模型记不住的东西 │

└──────────────────────────────────────────┘

分层的关键不在"分了三层",在于三层的失效方式是独立的:

- 控制层坏了 → 你会一直卡在某一步,看得见;

- 约束层坏了 → 文风开始漂,要几十章才看得出来;

- 记忆层坏了 → 事实开始打架,要等读者骂你才发现。

所以三层里,记忆层最需要自动化校验,因为它最晚暴露。

三、坑 1:状态机写成了"if-else 瀑布"

我一开始的写法:每个环节写完,直接调用下一个环节——本质上是一条递归的函数链。

问题:递归下去就回不来了。用户在 DRAFT 环节想改 SEED 的人物,没有任何入口。而且一旦某一步抛异常,整个调用栈没了, "现在在第几步"这个信息就丢了。

改法:状态机只负责两件事——"现在允许进入哪一步"和"进入之前缺什么",它不负责跑流程。跑流程是外层的事。

两个要点:

- 闸门必须返回"缺哪个字段"。 返回一句"校验未通过",前端只能显示"失败了",人会一直点重试,而重试是最贵的动作;

- 状态必须落库,不能只存在内存里。 状态存在内存里,进程一重启,"第几步"就没了——这就是最初版本重启后要重跑一遍的原因。

四、坑 2:把台账交给模型写,废稿进了长期记忆

我一开始的写法:DRAFT 每生成一版,就顺手把这一版里的新事实写进台账。

结果:改稿改掉的设定(比如"主角其实没杀他")照样进了事实台账。台账污染是静默的——它不报错,只是在几十章之后让剧情出现一个说不通的转折。

改法:写回是单向 + 延迟 + 可拒绝的。

写回的四个约束:

- 只允许定稿环节写——初稿的废稿内容不能进长期记忆;

- 入库成功之后才写——入库失败但台账写了,账实不符;

- 撞了"不可推翻"的条目就抛错转人工——有些事实推翻一次,全书就废了;

- 写之前留一份快照——改坏了能退到上一章。

四个约束一句话:只允许定稿写、入库之后写、撞了不可变量就抛错、写前留快照。

这四个约束的价值不在"严格",在"污染是静默的"。 台账写错了不报错,它只是让几十章之后的剧情出现一个说不通的转折——那时候你已经找不到是哪一次写回造成的。

五、坑 3:摘要让模型自由发挥,误差滚雪球

我一开始的写法:让模型"用一段话概括本章"。

结果:写到 40 多章,后文开始引用"摘要里没有、但正文里有"的细节——因为摘要把它压掉了,模型只能"补"。而摘要又是下一章输入的一部分,所以误差会链式累积。

改法:摘要由程序按固定字段拼装——章号、字数、本章出场人物、发生地点、新增事实、埋设与回收的伏笔。模型只负责"结尾状态"那一句。

为什么只留一句给模型? 因为这一句是唯一需要判断的("本章停在什么状态"),其余都是可以被程序数出来的事实。能被数出来的东西,不要让模型去概括。

代价:摘要可读性变差,人工回看要多读两行。收益:误差不再复利。

六、坑 4:检索用了向量相似度,召回"很像对的"的错东西

我一开始的想法:既然有向量库,那就把正文切块、语义检索,多省事。

结果(跑了 30 章就停):主角查一个已死角色的旧部,检索召回了"该角色生前的段落",模型据此写出"他回来了"。

根因:向量检索没有"这件事发生在第几章"这个维度。而长篇里,时间恰恰是最重要的一维。

改法:检索键换成确定性字段(人物、章号、事实条目)。如果一定要用向量,至少把章号做成元数据过滤条件——但那已经半个台账了。

七、坑 5:预算裁剪裁掉了不该裁的

我一开始的写法:超预算了?按体积排序,从最大的块开始裁。

结果:锚点块正好最大,被裁了。那一章的语言风格和前后完全不像。

改法:裁剪顺序写死成一条业务规则——先裁前情摘要,再裁事实条目,最后才动本章框架;锚点和规则卡不在候选列表里。

顺序是业务规则,不是体积排序。 按体积排,最大的块一定先被裁,而最大的块通常正是锚点。

再加一条断言:裁完还超预算,直接报错。 如果裁完还超,说明不是"内容太多",是"固定开销本身设计错了"——这种错误早点炸出来比晚点炸好。 否则它会表现为"这一章莫名变短了",而你要花很久才能定位到预算配置上。

八、实测条件(不带条件的数字没意义)

都是内部实测,不代表别人复现同样结果。

九、失败案例还有一个:状态机卡死

现象:某环节上游条件反复不满足,流程原地循环,用户没有任何办法往下走。

根因:只设计了"确认"和"重试",没设计"绕过"。没有逃生通道的状态机,会把一次可恢复的失败变成不可恢复的失败。

改法:三个键的语义分开——

- 确认:这一步看过了,放行;

- 修改:只改当前环节,不跳转;

- 自由输入:权限最高,专门处理"突然要倒回去改前一章剧情"这种非常规情况,平时用得很少。

这条教训我后来写在代码注释里:状态机不是越严越好,是越"可解释地放宽"越好。

十、边界:这套架构别乱抄

不适合:

- 单轮任务(翻译、摘要、分类)——没有环节,状态机是纯开销;

- 1 万字以内的短篇——四张台账的固定开销(约 6 万字符)摊不平,直接对话更便宜;

- 流程还没稳定的项目——流程一天改三次时,状态机会变成维护负担,先稳定再建模;

- 不能接受"停下等确认"的场景——那这条路的负体验会很明显。

已知没解决的:

- 换题材时台账要清空重建,目前手动,误操作会把上一本的设定带进新书;

- 1000 章以上没测过;

- 规则卡没有版本管理,改坏了只能人工回滚;

- 多线并行的状态分支没有通用模式。

十一、三条回头看最有用的建议

- 先定义"这一步算完成",再定义"这一步做什么"。 大多数人反过来,写得出 prompt,说不出验收条件,于是流程永远推不动。

- 闸门返回"缺什么",不返回"不通过"。 可修的报错才叫报错。

- 记忆层一定要能打印出来看。 台账的价值一半在"存",一半在"能人工核对"。不可审计的记忆,等于没有记忆。

常见疑问(Q&A)

Q1:为什么不用现成的 workflow 编排框架? A:可以,而且省事。但框架管的是"调用顺序与重试",这里真正要管的是"上一环的产出是否满足下一环的准入条件"**——那是业务语义,框架不提供,还是得自己写。

Q2:状态存哪? A:不重要。文件、数据库、对象存储都行。唯一要求是进程重启后能恢复"当前环节 + 该环节字段"。 我早期就是 JSON 文件,够用很久。

Q3:8 个环节是拍脑袋定的吗? A:不是,但这也不是通用答案。判断标准是:每个环节是否有一个独立的、可验收的产出。 没有独立产出的环节应该合并。

Q4:这套东西跑起来慢不慢? A:慢,而且这是明码标价的。做法是把"慢"放在环节边界(等人确认),把"快"放在环节内部(连续生成) 。不能容忍任何停顿的场景别用。

Q5:为什么不用更长的上下文窗口一劳永逸? A:容量解决"塞得下",不解决"顾得上"。我自己的观察是:输入还在窗口内,早期设定已经被明显忽略。**窗口是容量,注意力才是带宽。

本文由 AI图鉴自动抓取并翻译,版权归原作者所有;如需查看原文请点下方链接。

相关 AI 工具

相关免费羊毛

同源资讯

阅读原文(juejin.cn)

标题、摘要与正文均来自该信源的公开页面,版权归原作者所有;本站自动聚合与翻译,仅作出处跳转。

← 返回 AI 资讯列表AI工具图鉴首页

返回 AI图鉴首页 · 提交工具 · 商务合作 · 关于本站 · 608 款 AI 工具分类导航 · 每日 AI 热门项目与动态