Agent 架构设计
一、起因:LLM 一次调用不够
我做了个工具—— text2everything.vip 自然语言描述流程,LLM 出 Mermaid 代码,右边实时渲染。
第一版是单次调用:用户输入 → LLM → 出图。跑了几个月发现两类问题:
- 语法错了没救 —— LLM 生成的代码看着对,Mermaid 渲染直接
Parse error,用户看到红色堆栈就走了。 - 语义偏了不自知 —— 用户说”画个登录流程”,LLM 惯性给你加个”发送验证码”,既不问,也不告诉你它加了。
这两个问题都不是”再调 prompt”能治的:第一次失败得有第二次机会;补常识没错,但必须留痕才能审计。
所以第二版做成一个 agent:能多轮对话,能自己纠错,能记住用户说过什么。这篇讲一下这个 agent 长什么样。
二、核心洞察:这不是一个循环,是两个
看似”多轮生成 UML”是一个循环,拆开看是两个,目标完全不同:
1 | 外层 · 问清楚要画啥 |
外层管 “信息够不够” ,内层管 “代码对不对” 。混在一起做的话,你会发现”这个歧义要问用户吗”永远没答案 —— 因为外层的歧义(用户没说)和内层的歧义(生成错了)是两回事。
三、Agent 是个团队,分工要明确
我把 agent 想象成一家律师事务所处理案子。每个角色只做一件事:
| 角色 | 做什么 | 不做什么 |
|---|---|---|
| 记录员 | 把用户说过的事实记进档案 | 不猜、不推断 |
| 审查员 | 看档案哪一栏是空的 | 不决定问不问 |
| 决策官 | 决定问不问用户、问哪个 | 不自己去问 |
| 律师 | 拿档案起草文件(生成 Mermaid) | 但可以补合理假设 |
| 校对员 | 检查文件语法 + 有没有夹带私货 | 有错就退回让律师改 |
| 前台 | 按顺序叫各角色出场,维护整个档案 | 不做任何判断 |
一开始我把这些揉在一个 prompt 里,发现 debug 极其痛苦 —— 因为说不清是”记录员搞错了”还是”律师瞎猜了” 。拆开之后每个角色都是纯函数,给一个输入永远给一个输出,单独测试。
调用关系:前台按顺序叫各角色出场
6 个角色之间不是各自平级各干各的,而是一条流水线,前台是唯一的调度者:
1 | 用户消息 |
几个值得注意的点:
- 前台是唯一有状态的,别的角色都是”输入 → 输出”的纯函数,不记得上一次。多轮对话的记忆全靠前台维护档案。
- 决策官是唯一分叉点,整个 agent “问 or 画”就它一个人决定。
- 内层修复循环发生在律师和校对员之间,不惊动用户 —— Mermaid 语法错的自愈就靠这一段。
- 语义检查发现问题不阻塞出图,而是跟着图一起呈现给用户(“图给你了,顺便问一下我加的这个要不要?”),这样用户看着图判断更容易。
关键规矩:记录员保守 vs 律师可以猜
这是整个架构的地基,展开讲一下。
用户说”画个登录流程,用户输密码,系统验证后返回结果”。记录员输出:
1 | { |
sync: "unknown" 这个字段就是追问的信号 —— 审查员看到 unknown,决策官就决定要不要问。
如果记录员帮用户补了(比如”登录一般同步,填 sync”),这个信号就没了 —— agent 分不清”用户真说过 sync”和”我瞎猜的 sync”,追问逻辑就崩了。
律师就没这个约束了。生成 Mermaid 时,律师可以补”验证码服务”这种合理假设,但必须写进档案的”假设”栏。后面校对员会拿档案 + 假设对账 —— 图里出现的每个元素都必须能追溯到”用户说的”或”律师的假设”,找不到就叫”夹带私货”,单独拉出来问用户”我加了这个,要保留吗?”
这一步一确定,后面很多问题自然就解了 —— 尤其是”用户说过’不要 X’,下一轮 LLM 又画上了 X”这种坑。因为夹带私货能被自动检测出来,agent 会主动把它捞出来问用户,而不是甩给用户自己发现。
四、”要不要追问用户”这件事,只让一个人管
这是我最喜欢的一条决策:所有”问不问用户”的判断,集中在一个纯函数里,叫 Planner(决策官)。
- 审查员 / 校对员只识别问题 —— 缺什么、错什么。
- 决策官拿三样东西做决定:候选问题池 + 剩余预算 + 之前问过哪些。
- 输出三选一:问一个 / 信息够了开始画 / 给用户看摘要让他确认。
一个 session 有个全局预算(比如 5 轮 agent 主动提问)。用户主动改需求 / 修图 / 要求重画都不算消耗预算 —— 只有 agent 主动打扰用户才算。这一条防止用户”越用越怕说话”。
这个设计的实际收益:想改追问节奏、调预算策略,只改这一个函数。别的组件不用动。
五、走一个例子 · 4 轮对话
看架构不够直观,走一个真实场景:
1 | Turn 1 用户:"画个用户注册流程时序图" |
5 轮预算,agent 实际主动追问 3 次,剩余 2 轮备用。 这就是全局预算的弹性。
六、加新图类型的成本
系统支持 Sequence · Flowchart · ERD · State · Class · Mindmap · Gantt · Arch 八种。
加一种新图 = 新写 4 个角色的实现:
- 记录员 —— 怎么从自然语言提取事实
- 审查员 —— 哪些字段是必填,哪些是可选
- 校对员 —— 什么算夹带私货
- 措辞员 —— 怎么问用户(时序图问”参与者”,类图问”实体”,措辞不一样)
决策官 / 前台 / 状态存储都不用动,因为它们不关心画的是哪种图。
七、3 条我觉得值得抄的经验
- 两层循环拆开做 —— “问清楚”和”画出来”是两件事,共享数据但目标不同。混在一起会陷入”这个歧义要问吗”的死循环。
- 记录员保守 + 律师可以猜,分工要严格 —— 记录员帮用户补常识就等于把 agent 的判断力交给了 LLM 的直觉。律师的每个假设必须留档,校对员才能审。
- 所有 policy 集中在一个决策官纯函数里 —— 想调追问节奏、改预算策略,只动一处代码。别的角色都是”识别问题”,只有它做”决定要不要问”。
八、后续
近期在做的:
- 自动分类置信度校准(用户不说图类型时,LLM 猜错的概率)
- 每种图的”夹带私货”规则集扩充
- 一键分享:把 prompt + spec + 生成图打包成链接,收到 issue 时能一键重放整个对话
如果你也在做类似的 LLM 多轮 agent(不管是画图 / 写 SQL / 生成 API mock),这三条我觉得最能救命。Agent 不是”用 LLM 多调几次”这么简单,是要设计一个能自己纠错、能记住负面反馈、能审计每个决策的团队。
欢迎大家试用 https://text2everything.vip/ 给我提 bug。