资讯动态

对话式Agent架构设计:从需求到生产落地的关键实践

发布时间:2026/10/18 7:10:45 来源:尧图企业网站定制
1. 先别急着写 Agent先把“架构设计”翻译成需求不管你有没有听过 Clawdbot 这个名字只要你准备做一个带对话能力的 Bot哪怕是给内部客服做个答疑机器人架构设计这件事都躲不开。我自己前后做过几个类似的助手系统对这个标题的感受最深的不是“选哪个模型”而是“怎么把它当作一个会二十四小时跑的后端服务来设计”。Clawdbot 这个项目本质上就是一个会聊天还会办事的 Bot 服务用户发来一句话它判断意图可能去查文档、调内部工具、翻历史记录最后组织一段回复。听起来简单但一旦涉及多轮对话、多个技能、多人同时使用代码不提前划好边界三个月后就是改一行动就要炸的泥潭。这篇内容适合正在搭 Bot 底层、想让助手真正上生产、又不想被一堆 Agent 概念绕晕的开发者参考。1.1 Clawdbot 到底要解决谁的问题我拿到一个项目先不看技术选型先问一句它到底帮谁解决什么问题Clawdbot 的典型用户画像是通过对话完成杂事的人比如“帮我查一下上个月的订单明细”“把这篇会议纪要整理成待办”“给团队发个周报提醒”。这类需求共同点是单看一句话很轻背后却要串起权限、检索、工具调用、内容生成这条链路。我一般会把需求分成三类来看信息获取类查知识库、查订单、查排班核心瓶颈在检索准确率和上下文裁剪。事务操作类发通知、建任务、写文档并发送核心瓶颈在工具调用的安全性和结果确认。分析汇总类总结多份资料、生成周报框架核心瓶颈在上下文预算和生成质量。这三种类型对架构的要求完全不一样。信息获取可以靠检索兜底事务操作必须有严肃的工具协议分析汇总则需要给模型留出更大的推理空间。架构设计的第一步不是画分层图而是把这些需求拆成明确的、路由对象可见的单元。1.2 从需求反推出来的四个架构目标把需求转成架构目标我一般只写四个词扩展、稳定、可控、可观测。架构目标需求来源落地含义扩展会不断新增工具和技能新增能力不改主流程只做注册和配置稳定模型接口、工具接口都可能挂超时、熔断、异步降级是标配可控工具操作可能影响业务数据调用鉴权、二次确认、审计日志一条不少可观测线上出问题要快速定位请求带 trace id每个节点打指标这四个目标会直接影响几个关键设计决定接入协议与业务逻辑分离模型封装成可替换组件工具统一走注册表管理所有请求从入口就带 trace id上下文预算按比例分块避免无限膨胀。1.3 最容易翻车的三个设计误区我见过很多 Bot 项目不是死在模型能力上而是死在一些看似不起眼的设计习惯上。第一个误区是只把 Prompt 当产品。团队把大量逻辑塞进 system prompt今天加一句规则明天补一段示例最后 Prompt 变成谁都改不动的大泥球。Prompt 当然重要但它应该是配置而不是架构真正的分支判断要走状态和路由。第二个误区是让上下文无限堆叠。用户每来一句就追加原文上下文越滚越大模型越来越慢回答越来越偏。上下文不是存档位它是预算每一轮都要算着花。第三个误区是把工具调用写死在 if/else 里。今天支持查天气就写一个 if明天支持查订单就再写一个 elif等工具到二十个的时候主流程已经没人敢动了。工具应该是数据是一份份声明而不是散落在代码里的分支。2. 整体分层可插拔、可观测、能上生产的四层骨架做架构不是画个好看的分层图而是定好依赖方向。我最终采用的形态是四层接入适配层、会话编排层、能力工具层、数据存储层。每一层只对下一层有依赖每一层都可以单独部署、单独回滚。层级主要职责关键设计接入适配层协议转换、鉴权、限流、平台差异屏蔽用适配器模式保持薄会话编排层状态管理、意图路由、模型调用、工具调度循环可重入、可恢复能力工具层工具注册、执行、结果精简、配额控制协议统一同步异步分开数据存储层会话记录、记忆、向量索引、配置、审计日志读写分离冷热分层之所以把这几层拆开不是追求架构上的“正确”而是为了让每个环节可以被独立测试。接入层坏了不影响编排层工具超时不会拖垮会话循环模型接口换掉也不需要动业务代码。2.1 接入层一定要“薄”接入层只需要处理三件事认证与限流、消息格式转换、平台差异屏蔽。很多项目把业务逻辑写在这里今天出通知明天出卡片后天又要适配同一个消息在另一个入口的形态最后适配层变成一座屎山。我的经验是接入层只负责把各种入口的输入转成一条标准化的内部请求体再把最终回复转成入口要求的消息形态。所有“理解”和“决定”都放到编排层。这样做的好处非常直接新增一个入口时你只需要新写一个适配器把外部协议翻译成内部标准结构不用碰任何 Bot 逻辑。我在实际项目里试过同时接 Web 窗口和内部 IM 平台核心代码零改动只新增适配器就够了。2.2 编排层才是大脑对话循环和调度逻辑编排层是真正的大脑。每来一条用户消息都走同一套循环加载会话状态组合上下文调用模型判断意图必要时选择工具执行工具或要求用户补充信息更新状态最后生成回复。这个循环必须支持中断恢复。比如工具执行超过三秒不能一直傻等先返回“正在处理中”再通过回调或者任务结果查询来收尾。循环里每一步都要打日志和埋指标否则后面排障无从下手。编排层还有一个容易被忽略的职责工具选择的白名单过滤。不是所有用户都能调用所有工具编排层在把候选工具交给模型之前要先按用户角色、权限和当前会话上下文做一次过滤。这一步放在编排层做比放在工具层做更安全因为工具层看到的只是执行指令不具备全局判断能力。2.3 能力层和存储层越松耦合越好能力工具层的设计重点是注册表。每个工具声明名字、描述、入参结构、超时时间、是否幂等编排层只根据模型选择的工具名去注册表里取执行器。工具内部可以调用任意内部系统但对外只暴露统一结果格式。这样做的好处是加一个工具就是往注册表里挂一条记录不需要改主流程。如果某个工具体量太重就把它摘掉如果某个工具频繁超时就直接熔断都不需要发版。存储层再往下拆成 KV 缓存、关系数据、向量索引和日志桶按访问频率和生命周期分开放。会话热记录放缓存画像和长期记忆放关系存储文档知识放向量索引审计日志单独归档。别把所有东西塞在一个库里否则将来扩展任何一个维度都会被拖累。3. 深水区细节会话状态、工具协议、记忆和检索分层解决的是模块边界问题但真正决定 Clawdbot 好不好用的是几个细节性的设计会话状态怎么建模、工具声明怎么写、记忆怎么更新、检索结果怎么进上下文。这四个点都属于“平时没人讲踩坑才后悔”的深水区。3.1 会话状态建模别把上下文都交给模型很多对话框架把会话理解成“把历史消息一股脑传给模型”这在小规模 demo 里能用一上生产就出问题。我习惯把会话状态显式建模成结构化对象而不是一堆历史文本。{ session_id: s_8f31, intent: create_reminder, state: waiting_for_time, pending_params: {target_user: 张三}, entities: {reminder_type: weekly_report}, tool_call: null, summary: 用户希望给张三创建周报提醒还缺时间信息 }编排层每轮先读这个状态而不是从零把历史给模型。关键信息沉淀到 summary 字段就算历史消息被裁剪掉模型也知道当前进行到哪一步。状态更新必须是原子化的尤其是用户在多个入口同时操作时至少要保证状态不被写坏。这个设计的另一个好处是可调试。出问题时直接看 session 状态就能还原现场比翻几百行对话日志高效得多。3.2 工具声明协议结构化的 Function 描述比自然语言硬编码靠谱工具调用最容易踩坑的一点是让模型自由发挥自然语言动作。你让模型返回“请调用搜索工具查询订单 20240001”这种字符串解析起来让人痛不欲生。我采用的方法是给模型一份结构化 Function 声明让它返回 JSON而不是文本。{ name: query_order, description: 根据订单号查询订单状态, parameters: { type: object, properties: { order_id: {type: string, description: 完整订单号} }, required: [order_id] } }声明越严路由越稳。description 要写清楚什么场景用、什么场景不用不要让模型在候选工具里挑花眼。还要约定几条铁律只放当前对话可能用到的工具工具海的召回率并不高。工具必须设置超时默认三秒超过就转异步任务。工具结果太大时不要直接拼进上下文先压缩或者提炼成要点。我在实际项目中就吃过亏。早期把二十个工具的声明全部塞给模型结果模型经常选错工具后来改成按意图预分组每次只给三到五个候选准确率一下子就上来了。3.3 记忆系统短期、长期、画像三层分开管长期记忆如果设计不好要么记不住要么变成隐私炸弹。我分三层管理短期会话记忆只保留当前 session 内的信息会话结束就过期。长期画像记忆存用户偏好、常用实体比如“张三偏好列表式汇报”。情节记忆存过去发生的重要事件比如“上周帮张三处理过权限异常”。更新走后台不阻塞主回复。每轮对话结束由一个小模型判断这轮有没有值得写进记忆的信息要不要更新旧的画像然后通过异步任务队列写入。每条记忆都要设置过期时间和删除入口这是底线。用户说“忘掉我之前提到的偏好”系统至少要能删除对应的画像条目。记忆不是越多越好留不住重点也删不掉旧账的记忆系统迟早会变成模型回答里的噪音源。3.4 检索与上下文预算同一个窗口里做减法只要挂了检索检索质量就直接决定回答质量。我建议用稀疏加稠密混合检索再加一层重排。混合检索解决关键词和语义两头的问题重排模型把候选进一步排序保证进入上下文的内容是高置信度的而不是靠召回数量堆出假效果。另一个常被忽略的是上下文预算。一个 8K token 的模型我给 system 3500、历史 1500、检索结果 1500、生成预留 1500多出来的检索结果一律先摘要再放进来。预算块建议占比职责系统规则40%角色、能力边界、安全约束历史摘要20%当前进度和已确认信息检索/工具结果20%本轮真正需要的外部事实生成预留20%保证模型有空间写出完整回复定预算的目的不是算得准而是逼着你给内容分层、砍噪音。上下文里塞十条可能相关的文档不如塞两条高置信度的文档加一句“还有其他相似结果需要继续列出吗”。4. 落地实现最小可用版本的核心流程与参数讲完设计很多朋友会关心具体怎么落地。我坚持一个原则先做一个单机进程内能跑通的最小版本再考虑拆服务。架构是长出来的不是第一天设计出来的。4.1 工程目录与模块边界开始落代码时别一上来就把目录拆成十几个微服务。单机模块化就够。clawdbot/ adapters/ # 平台接入只做协议转换 core/ # 会话编排与状态机 skills/ # 工具注册表与执行器 memory/ # 会话记忆、画像、情节记忆 storage/ # KV 缓存、检索、日志 configs/ # 模型与预算配置 tests/ # 单测加场景回归模块边界比目录名重要。规则只有一条core 不能反向 import adaptersskills 只能通过注册表被调度。这样做之后换适配层、换模型、加技能都不会牵一发动全身。4.2 一个稳定的对话循环该长什么样这个循环写得再朴素都没关系关键是每个节点可观测、可中断。下面这段是我常用的核心流程伪代码去掉了具体框架依赖保留逻辑骨架。def handle_message(session_id, raw_input): state load_session(session_id) # 1. 先判断意图缺参数就先问不急着调模型硬答 intent parse_intent(raw_input, state) if intent.need_param: return ask_for(paramintent.missing_param, statestate) # 2. 按用户角色过滤可用工具再把候选交给模型 tool select_tool(intent, enabled_tools(session.user)) # 3. 工具执行必须带超时宁可转异步也不能拖住主链路 result execute_tool_with_timeout(tool, intent.params, timeout3) material summarize_context(result, budget) # 4. 生成回复最后更新会话状态 reply generate_reply(material, state, budget) save_session(session_id, state.updated(), summaryreply.summary) # 5. 每轮结束把 trace_id 写到日志方便后续排障 trace_log(trace_idrequest.trace_id, spanloop, okTrue) return reply中间任何一步失败都返回统一错误文案并把 trace id 带给用户或技术支持。工具执行超过超时不硬等转异步再提示用户结果稍后给出。这一步让我在真实流量下少接了很多投诉。4.3 参数选型与成本预估参数选型没有绝对标准但有几个起点可以抄。参数建议值逻辑temperature0.2 到 0.4事务类任务要低随机性max_tokens模型上限的一半左右留空间给回复防止被截断工具超时3 秒超出转异步保护主链路用户级限流每分钟 5 到 10 次防滥用也控成本成本预估可以套一个简单公式月 token 成本约等于日均轮次乘平均单轮 token 再乘 30 天乘用户数。假设单用户每轮平均 1500 token一天 50 轮一个月就是约 225 万 token。这个公式有什么用它强迫你估算上下文预算对成本的影响。上下文裁剪做得好不好最后都会直接反映在账单上。5. 上线后必踩的坑误调用、上下文膨胀、延迟毛刺Clawdbot 这类系统的坑不在第一行代码而在上线之后。我挑四个最典型的每个都是踩过之后才长记性。5.1 工具误调用怎么防都不过分误调用是最隐蔽的线上事故。比如模型把“转发”理解成“删除”把“提醒一下”理解成“直接发送”。我的防御清单很简单工具权限跟随用户角色路由前做一次白名单过滤。对高风险工具回复里必须带二次确认卡片用户点了确认才执行。凡是有可能产生数据影响的工具执行前记审计日志执行后验证结果。有一次我把“创建任务”和“完成任务”两个工具的 description 写得不够清晰模型连续三次选错用户被创建了一堆垃圾任务。从那以后高风险工具的 description 里我都会加一句“只有在用户明确要求完成操作时才选择”。5.2 上下文膨胀能切就切能摘要就摘要上下文膨胀常见症状是模型开始自说自话、答非所问。用户问 A模型扯到 B其实就是窗口里塞了太多无关注释。我用的策略是历史超过二十轮先做摘要不把原始逐字记录继续堆。检索结果超过预算就按重要度截断不要全量塞进 prompt。工具执行结果落库后下一轮只带摘要不重复带原始 JSON。电话会议里有个习惯叫“行动计划只留结论讨论过程归档”上下文管理也是一样。模型不需要看每一份工具返回的完整 JSON它只需要知道结论和必要的细节其余都在存储层躺着。5.3 延迟毛刺和限流回退模型接口一慢整个入口就跟着慢。我做了三层保险第一层查询类结果做缓存同样的问题一分钟内直接命中减少模型调用。 第二层调用带超时和熔断连续五次超时就暂时摘掉该能力不继续死磕。 第三层体量大的工具都走异步任务前端立刻返回任务号用户稍后刷新。这三层加完后主链路的响应时间基本稳定住了。异步任务的好处是即使工具执行要十秒用户的对话入口也不会被卡住体验上只是“稍后查一下结果”。5.4 可观测性没有链路追踪就等于蒙眼开车没有链路追踪就等于晚上不开灯修车。每个请求进门就给一个 trace id经过编排循环、工具调用、记忆读写都记录时间开销。我重点盯五个指标意图识别准确率、工具调用成功率、上下文平均 token 数、P95 响应时长、单用户成本。这些指标可以先落日志再慢慢上监控面板但必须有。现象排查入口处理方向回复越来越偏看上下文摘要是否覆盖关键实体重建会话历史或收紧裁剪规则工具不触发看工具声明是否在候选列表里简化 description 或调整意图分组某个入口很慢看接入层日志耗时占比降级为异步或加缓存成本突然上涨看平均 token 数和检索命中率收紧预算或换更小的模型6. 从 v1 到 v2我的迭代顺序和一点个人体会很多团队拿到一个架构图就急着拆微服务这不是不行是大多数项目用不上。6.1 别在第一天就做微服务我没见过哪个团队一上来就需要微服务。Clawdbot 的 v1 适合做单机模块化把四层放进一个进程。等到出现了独立容量瓶颈比如检索流量太大、异步任务太多再把对应模块拆出去。我建议的迭代顺序大概是先写长消息通道加用户反馈闭环再加金标测试集等这些都稳定了再谈网关和弹性伸缩。每一步都要有一个明确痛点逼着你去拆而不是为了架构上的“高级感”。6.2 迭代铁律先通链路再打指标最后才做编排最后分享我个人在几个项目里沉淀的经验。如果你的 Prompt 改一次要动三个文件说明边界没划好如果查问题只能靠看日志里的报错堆栈说明可观测性欠账如果新增一个工具要求全量发版说明注册表还没做到位。架构设计的价值不是第一天画出一张漂亮图而是三个月后你还能在不动主干的情况下把一个新能力塞进去。Clawdbot 对我来说就是这么一套越用越顺的壳。它不解决模型聪明不聪明的问题只保证一旦模型变聪明你的系统能接得住。我自己的做法是每轮改动后都记录一次上下文平均 token 数和工具调用准确率这两个数字会像体检报告一样告诉你哪里开始不健康了。把这套细节管住架构设计才不是纸上谈兵。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑