当前位置: 首页 > news >正文

复盘:企业级 Agent 平台,落地踩过的坑

一开始低估的事:边界

最早动手时,我们对"Bounded Context"的理解停在概念层。会话(Session)、工具(Tool)、审计(Audit)都放在一个 service 里,靠函数调用区分。第一个月运行没什么问题,第二个月工具调用加了审批流程,要改 Session 状态机,同时改审计写入时机,一次改动影响了三个方向,回归测试全部要重跑。

拆分到独立 BC 以后这个问题消失了。Tool BC 加审批逻辑,改的是自己内部的状态机,Session BC 只感知"工具调用完成"这一个事件,不关心审批细节。代价是多了 gRPC 调用,增加了几毫秒延迟,但这个代价完全值得。

结论:BC 边界不是为了架构图好看,是为了让每次改动的影响范围可控。边界划得晚比划错更痛苦。


走了弯路:Session 状态机

Session 的状态设计,我们反复改了几版。

最纠结的一个问题是:数据库里需要细粒度的状态来区分"LLM 正在思考"、“正在调工具”、"等待人工审批"这些不同阶段,但如果把这些全塞进同一个状态枚举,状态机的迁移规则会变得非常复杂——几十种组合,改一处怕漏另一处。

最终我们用了两级设计:State 和 Phase。

State(状态)是会话的生命周期,一共 6 个:

  • idle

    :会话已创建,还没开始跑

  • running

    :正在执行 ReAct 循环

  • paused

    :暂停,等 HITL 人工审批

  • completed

    :正常结束(终态)

  • failed

    :异常退出,lastError记录原因(终态)

  • cancelled

    :用户或系统主动取消(终态)

Phase(阶段)running状态下的子阶段,用来做 DB 持久化和 SSE 流事件对齐:

  • thinking

    :LLM 正在生成响应

  • tool_use

    :正在执行工具调用

  • finalizing

    :收尾整理最终回复

这样做的好处是:State 层面只需要管 6 个状态的合法迁移,规则很简单——一张validTransitions转换表就够:

  • idle

    running(调Start()激活)、cancelled

  • running

    paused(HITL 中断)、completedfailedcancelled

  • paused

    running(审批通过恢复)、cancelled

  • completed

    failedcancelled是终态,不能再迁移

任何不在表里的迁移,代码直接返回ErrInvalidStateTransition错误,不会静默通过。Phase 的推进则由SetPhase()方法驱动,只在running状态下才生效,其他状态调用是空操作。

你可以把 State 想象成火车运行图上的大站(始发、运行中、临时停车、到站、故障停运、取消),Phase 是运行中的小站(加速、减速、过桥)。大站之间有严格的调度规则,小站只是记录"此刻在干什么"。

结论:当状态粒度需求在不同层面不一样时,用两级(State + Phase)比把所有东西塞进一个枚举更清晰。状态机的价值不只是代码,是让"哪些迁移合法"变成一张可审查的表。


踩过的坑:异步不代表可以忽略失败

Memory 的记忆提炼是异步 fire-and-forget。上线初期日志里偶尔出现提炼失败,我们当时觉得"最多这次对话的内容没被记住,不影响主流程",就没处理。

运行一段时间后发现,失败率偏高,原因是提炼用的 LLM 调用不够稳定。用户感知不到失败(主流程没报错),但记忆系统慢慢变薄——常用的偏好没被记住,用户下次对话又要重新告知 Agent。虽然不是数据丢失,但体验在悄悄变差。

当前代码的做法是:失败时保留事件不清空(SaveTx事务保证事件不丢),上层可以决定是否重试。同时持久层做了分层降级——优先走事务(SaveTx:聚合落库 + 事件写入同一事务),事务失败则退到非事务路径(Save + Publish)。这比最初"失败就丢了"强很多,但完全自动化的重试(如指数退避)还在 roadmap 中。

结论:fire-and-forget 不是"失败了算了",是"失败了不阻塞主流程,但要有自己的兜底"。事件不丢是最低要求,自动重试是进阶目标。


没想到的问题:HITL 超时

HITL 上线时,我们设了审批超时 5 分钟(代码里是HITLTimeout = 5 * time.Minute),超时后自动拒绝,由一个每 5 分钟跑一次的 CronJob(hitl-timeout)检查并处理过期中断。

这个时间对"人在电脑前等着"的场景够用,但对"需要找领导确认"的场景太短。而且超时后走的是RejectInterrupt路径(decided_by="system:hitl-timeout"),原始参数虽然保留了(存在session_interrupts表的args里),但用户需要从头重新发起请求。

当前超时值是硬编码常量,还没有做到按租户/工具风险等级可配置——这是 roadmap 中的改进项。

这个问题不是纯技术问题,是没有从用户的工作流角度思考超时设定。

结论:涉及人工操作的流程,超时和重试的设计要从人的行为习惯出发,不能只从系统稳定性考虑。


值得的决定:RLS 在数据库层做隔离

多租户隔离最开始有两个方案争论:应用层过滤(每个查询手动加WHERE tenant_id = ?)vs 数据库 RLS。

应用层方案实现简单,但有个明显的风险:新人写查询忘了加WHERE tenant_id,数据就串了。RLS 在数据库层强制过滤,代码忘了加条件,数据库帮你加。代价是每个事务开头要SET LOCAL app.tenant_id,多了一次数据库交互。

上线以后做过两次代码 review,发现有 3 个查询路径确实遗漏了应用层过滤——如果靠应用层方案,这 3 个地方就是数据串的漏洞。RLS 兜住了。

结论:隔离应该是系统约束,不是依赖开发者自律。多一次数据库交互的代价远低于一次数据泄露事故。


值得的决定:指标集中定义

早期各 BC 各自注册指标,名字不统一。有的叫agent_runs,有的叫agent.runs.total,Grafana 面板对不上,每次加新面板要先 grep 代码找实际的指标名。

把所有指标集中到metrics.Metrics结构体,命名约定强制deepflux.<domain>.<measure>,一个文件能看到全平台所有指标。Grafana 面板配置按这个命名写,再也不用翻代码。

结论:可观测性基础设施早期投入是值得的,散乱的指标命名是技术债,修复成本很高。


总结

做企业级 Agent 平台,技术本身不是最难的部分。难的是:在系统还很小的时候,做出那些在系统变大以后才能体现价值的设计决定。BC 边界、状态机、RLS 隔离、集中指标——每一个在实现时都比"快速能跑"麻烦,但后来都成了省心的地方。

选 Eino 做 Agent 编排框架,节省了大量 ReAct 循环的基础设施工作,让我们可以把更多时间花在业务逻辑和运营能力上。这个选择目前看来是对的。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

http://www.jsqmd.com/news/1093232/

相关文章:

  • rabbitmq+websocket实时通知
  • dotnet 10 run file 支持多文件
  • JavaScript--错误处理
  • OpenClaw(龙虾)2026 最新安装部署终极指南
  • xref_data_to_array
  • CSDN博客-第1天-单神经元反向传播
  • 计算机二级基础知识-计算机体系结构
  • 中小微企业建站首选!PageAdmin CMS,零代码搞定官网运维
  • chunk重叠overlap设多少:切断上下文的坑
  • 支持多端生成的AI开发软件怎么选?功能对比指南
  • AI编程新范式:Skills技能库如何提升Claude、Cursor代码生成质量
  • AI Agent开发实战:从零构建一个能自主规划任务的智能体
  • Python学习笔记·第24天:Pandas数据清洗——缺失值、重复值与透视表实战
  • 使用visual studio和ai制作ppt
  • AI 学习助手:基于 HarmonyOS ArkTS 的智能学习伴侣开发实践
  • 第一批被龙虾气到的人出现了
  • Vue3 项目从开发到上线:环境变量、打包优化与 Nginx 部署全流程
  • 相处的艺术:尊重与边界
  • 企业知识图谱的拐点: 当本体工程遇上 LLM 与 MCP
  • Spring Boot 自定义 Starter 机制
  • GPT-5.6 Sol预览解读:max推理、ultra多Agent与分层安全栈
  • 剑指offer-79、最⻓不含重复字符的
  • Codex Linux 教程:从安装配置到卸载清理全流程指南
  • 基于Anthropic-Cybersecurity-Skills构建网络安全AI智能体实战指南
  • FontForge字体设计完全指南:从入门到精通掌握专业字体编辑
  • GPT-5.6系列模型发布遇阻:OpenAI面临多国监管审批,Claude Fable 5重返引发全球讨论
  • Vibe Coding 实战复盘:一个人 + AI,从零打造会聊天的个人主页
  • 关于多线程归并排序的性能瓶颈与优化方案的技术7
  • HFSS求解设置实战解析:从驱动求解到本征模求解的核心配置
  • 数据中心电力模块的发展趋势对数据中心建设有哪些影响?