ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

企业大模型网关架构设计与Agent工作流落地实践

企业大模型网关架构设计与Agent工作流落地实践 1. 企业大模型网关到底解决什么问题1.1 从一个真实场景说起去年下半年我帮一家做企业服务的公司做技术咨询他们内部已经有将近十个团队在各自调用大模型接口。听起来挺繁荣但问题很快就暴露了每个团队自己申请API Key自己写重试逻辑自己处理超时自己算Token消耗。财务那边到了月底拿着一堆账单根本对不上号安全团队发现有人把Key硬编码在前端代码里运维团队则被各种不同的超时配置和并发策略搞得焦头烂额。这不是个别现象。任何一家公司只要大模型用超过三个月几乎必然会走到这一步——调用入口分散、成本不可控、安全无审计、模型切换成本高。大模型网关要解决的就是这一堆问题它本质上是一个统一的中间层所有对大模型的请求都从这里过由它来负责鉴权、限流、路由、计费、日志、缓存和降级。你可以把它理解成公司内部的“模型调用总机”。以前每个人要打电话都得自己找号码、自己拨现在统一拨总机总机帮你转接、记录通话时长、控制同时通话人数还能在某个线路忙的时候自动切到备用线路。1.2 网关的核心能力清单一个能落地的大模型网关至少要覆盖下面这些能力缺一个都会在后续运维中付出代价统一鉴权与租户隔离内部各业务线用不同的虚拟Key网关映射到真实上游Key业务线之间互不可见。多模型路由同一个请求可以根据模型名、租户、请求特征路由到OpenAI、Claude、国产模型或自部署模型。限流与配额按租户、按模型、按时间窗口做QPS和Token双维度限制。成本核算每次调用记录输入输出Token数按模型单价折算成金额落到租户账上。可观测性请求日志、延迟分布、错误率、首Token时间这些指标要能按租户和模型维度下钻。缓存与降级相同Prompt命中缓存直接返回上游故障时切备用模型或返回兜底结果。内容安全入口做敏感词和合规检查出口做结果过滤。这七项里前四项是刚需后三项是加分项。我见过不少团队一上来就想做全套结果鉴权都没做扎实就去做缓存最后缓存穿透把上游打挂。顺序很重要。1.3 为什么不用现成的API管理平台有人会问市面上不是有API Gateway吗为什么不能直接用答案是能用但不够。传统API网关是为RESTful接口设计的它不理解Token这个概念不知道一次请求消耗了多少输入输出Token也没法按Token计费。更重要的是大模型请求的延迟特征完全不同——首Token时间可能好几秒流式返回可能持续几十秒传统网关的超时和连接池策略直接套上去会出各种诡异问题。所以我的建议是网络层、TLS终止、基础限流可以复用现有网关但Token级别的计量、模型路由、Prompt缓存这些必须自己写一层。这一层不需要多复杂几千行代码就能跑起来但设计要对。2. 网关架构设计与技术选型2.1 整体分层思路我在实际项目中采用的架构分四层从外到内依次是接入层、网关核心层、适配层和上游层。接入层负责TLS终止、IP白名单、基础DDoS防护这部分直接用Nginx或云厂商的负载均衡就行不要自己造。网关核心层是重点包含鉴权模块、限流模块、路由模块、计量模块和日志模块这几个模块之间通过内存队列解耦避免某个模块慢拖垮整条链路。适配层负责把统一的内部请求格式转换成各家上游的格式OpenAI、Claude、国产模型的请求体结构差异不小这层要做归一化。上游层就是真正的模型服务。这样分层的好处是换模型只需要改适配层换限流算法只需要改核心层互不影响。我见过把路由逻辑写死在业务代码里的项目后来想加一个国产模型备份改了三天。2.2 技术栈选择与理由语言层面我推荐Go或Rust。Go的生态成熟goroutine处理高并发流式转发很自然标准库的httputil.ReverseProxy改一改就能用。Rust性能更好、内存更可控但开发速度慢一些适合对延迟极度敏感的场景。Java也不是不行但JVM的GC在长连接流式场景下需要额外调优Spring WebFlux的学习曲线也不低。存储层面计量和配额数据用Redis因为要高频读写且能接受最终一致。请求日志先写本地文件再由采集器异步推到日志系统不要同步写数据库否则高峰期数据库先挂。租户配置和模型配置用MySQL或PostgreSQL变更频率低需要事务保证。配置中心我倾向用etcd或Nacos网关实例多的时候配置变更要能秒级推送。如果实例少直接读数据库加本地缓存也行但要有主动刷新机制。2.3 关键设计决策的取舍第一个决策是同步还是异步计量。同步计量准确但增加延迟异步计量有丢失风险。我的做法是配额扣减同步做用Redis的原子操作详细日志异步写。这样既保证了不会超配额又不会因为写日志拖慢请求。第二个决策是流式响应的计量怎么做。流式返回时Token是逐步产生的你没法在请求开始时就知道输出多少Token。我的方案是边转发边累计请求结束时把总数写回。如果连接中途断开按已产生的部分计费。这个逻辑要写清楚否则客户会质疑计费准确性。第三个决策是缓存粒度。Prompt完全匹配缓存命中率低语义缓存命中率高但可能返回不准确的结果。我的建议是分级精确匹配缓存用于系统Prompt和常见问答语义缓存只用于对准确性要求不高的场景且要设置相似度阈值我一般设0.95以上。3. 自动化编程与Agent工作流落地3.1 Agent和普通工作流的本质区别很多人把Agent和工作流混为一谈其实区别很明显。工作流是你预先定义好步骤A做完做BB做完做C路径是固定的。Agent是给定一个目标由模型自己决定下一步做什么路径是动态的。举个例子简历筛选如果规则固定——先解析PDF再提取关键词再打分排序——那是工作流。如果让模型自己决定先看哪份简历、要不要追问候选人、要不要调整筛选标准那是Agent。实际落地中纯Agent和纯工作流都少见主流是混合模式外层用工作流保证流程可控内层某个节点用Agent处理不确定性。比如简历筛选整体流程是工作流但“判断候选人经历是否匹配岗位”这个节点交给Agent让它自己决定要不要查更多信息。3.2 用网关支撑Agent调用的关键点Agent对网关的要求比普通调用高得多。第一是并发一个Agent任务可能瞬间发起十几个工具调用网关要能扛住这种突发。第二是超时Agent的思考链路长单次调用超时设太短会频繁失败设太长会占着连接不放。我的做法是按调用类型区分超时普通对话30秒工具调用60秒长文本生成120秒。第三是幂等Agent可能因为重试机制重复调用同一个工具网关要能识别并去重。我一般让客户端带一个request_id网关在Redis里查这个id是否处理过处理过就直接返回缓存结果。第四是可观测Agent的调用链路是树状的网关的日志要能还原出完整的调用树。这需要在请求头里传递trace_id和parent_id网关记录时把这两个字段存下来。3.3 一个可复现的简历筛选工作流我拿简历筛选举例把整个工作流拆开讲。输入是一批简历文件和岗位描述输出是排序后的候选人列表加筛选理由。第一步文件解析。PDF和Word格式不统一用Python的pdfplumber和python-docx分别处理统一转成纯文本。这一步不涉及模型纯工程活。第二步结构化提取。把简历文本送给模型让它输出JSON格式的结构化信息姓名、学历、工作年限、技能列表、项目经历。这里要用function calling或JSON mode保证输出可解析。Prompt里要明确字段定义和格式要求我一般会给一个示例。第三步匹配打分。把结构化信息和岗位描述一起送给模型让它按维度打分并给出理由。维度包括技能匹配度、经验匹配度、学历匹配度每个维度1到5分。这一步可以用Agent模式让模型自己决定要不要看候选人的项目细节。第四步排序输出。按总分排序同分的按技能匹配度排。输出格式是表格加理由方便HR直接看。整个流程跑下来一百份简历大概三到五分钟成本在几块钱。比人工筛快得多而且标准统一。3.4 工作流编排工具的选择市面上编排工具不少Coze、Dify、n8n各有特点。Coze上手快适合非技术人员搭简单流程但复杂逻辑和自定义代码支持有限。Dify对开发者友好支持自定义节点和API接入但上下文长度限制需要注意超长上下文会截断。n8n偏自动化集成适合把模型调用和现有系统串起来。我的建议是原型阶段用Coze快速验证生产阶段用代码自己写编排逻辑或者用Dify加自定义节点。原因很简单生产环境需要版本控制、灰度发布、回滚能力这些可视化工具支持得都不够好。自己写编排虽然前期慢但后期可控。4. 实操部署与常见问题排查4.1 从零部署一个最小可用网关假设你已经有一台服务器和Redis下面是从零跑起来的最小步骤。第一步初始化项目。用Go的话go mod init gateway引入gin或echo作为HTTP框架引入go-redis作为Redis客户端。第二步定义配置结构。租户配置包含租户ID、虚拟Key、配额、允许的模型列表。模型配置包含模型名、上游地址、真实Key、单价、超时时间。这些配置从数据库加载到内存定时刷新。第三步实现鉴权中间件。从请求头取虚拟Key查内存中的租户配置找不到就返回401。找到后把租户信息塞进context后续模块从context取。第四步实现限流。用Redis的INCR加EXPIRE做滑动窗口key是租户ID加时间窗口。超过配额返回429并在响应头里带上剩余配额。第五步实现路由转发。根据请求体里的model字段查模型配置构造上游请求转发并流式返回。转发时记录开始时间、首Token时间、结束时间、输入输出Token数。第六步实现计量。请求结束后把Token数乘以单价用Redis的HINCRBY累加到租户账上。同时把详细日志写到本地文件。这六步做完一个能用的网关就有了。代码量大概两千行左右我一个人一周能写完。4.2 常见问题速查表问题现象可能原因排查方法解决方案请求偶发超时上游限流或网络抖动看网关日志里的上游响应时间分布增加重试和备用模型路由Token计量偏少流式中断未累计检查断开时的日志在defer里补写计量配额扣减不准Redis并发竞争用Redis的原子操作改用Lua脚本保证原子性流式返回卡顿缓冲区太小检查转发时的buffer大小增大buffer或禁用缓冲模型切换失败适配层格式不兼容对比请求体结构补全字段映射日志丢失异步写队列满监控队列长度增加队列容量或降级丢弃4.3 几个踩过的坑第一个坑是超时设置。我一开始给所有请求设了30秒超时结果长文本生成经常失败。后来改成按模型和调用类型区分长文本给到120秒问题解决。这里要注意网关的超时要大于上游的超时否则上游还在生成网关已经断了。第二个坑是Redis连接池。高峰期并发上来Redis连接不够用限流模块开始报错。后来把连接池从默认的10调到100并且加了连接超时和重试。这个参数要根据实际QPS调没有万能值。第三个坑是日志量。一开始所有请求都记详细日志一天下来几百GB磁盘直接爆了。后来改成采样记录正常请求记摘要错误请求记详情日志量降了90%。第四个坑是模型单价更新。上游调价了网关里的单价没更新导致计费偏差。后来加了一个配置变更通知机制调价时自动刷新内存配置。4.4 性能优化的几个实用技巧连接复用是第一步。和上游建立长连接避免每次请求都握手。Go的http.Transport默认就支持但要调大MaxIdleConns和MaxIdleConnsPerHost。批量计量是第二步。不要每次请求都写Redis攒一批再写减少网络往返。但要注意配额扣减不能批量必须实时。本地缓存是第三步。租户配置和模型配置读多写少放本地内存定时刷新。刷新间隔我一般设30秒太长会导致配置变更不及时太短会增加数据库压力。异步日志是第四步。日志写本地文件用带缓冲的writer或者直接丢到channel由单独的goroutine写。不要在主请求链路里做磁盘IO。5. 安全与合规的底线5.1 密钥管理真实的上游Key绝对不能出现在业务代码里也不能出现在前端。网关是唯一持有真实Key的地方业务方只拿虚拟Key。虚拟Key要支持轮换泄露了能快速失效。我一般给每个租户生成一对Key一个用于生产一个用于测试权限分开。Key的存储要加密数据库里存密文网关启动时解密到内存。解密密钥通过环境变量注入不要写在配置文件里。5.2 内容安全入口要做Prompt检查出口要做结果检查。检查可以用规则加模型两种方式。规则检查快但覆盖有限模型检查准但增加延迟。我的做法是规则先过一遍明显违规的直接拦剩下的抽样送模型检查。检查规则要可配置不同业务线的敏感词不一样。规则更新要能热生效不能重启网关。5.3 审计日志每次调用要记录谁调的、什么时候调的、调的哪个模型、输入输出Token数、花了多少钱、结果是否成功。这些字段缺一不可否则出了问题查不到。日志要保留至少半年满足审计要求。存储要加密访问要授权不能谁都能看。6. 后续扩展方向网关跑起来之后可以往上加的东西很多。比如加一个Prompt管理模块把常用Prompt集中管理支持版本和A/B测试。比如加一个评测模块定期用标准数据集测各模型的表现为路由决策提供依据。比如加一个成本预警模块租户花费接近配额时自动通知。Agent方向可以做的更多。比如给Agent加记忆模块把历史对话存到向量数据库下次调用时检索相关记忆。比如给Agent加工具市场常用工具注册一次到处能用。比如给Agent加沙盒危险操作在隔离环境里跑。这些扩展不用一次做完按需加就行。关键是网关这一层要设计好留出扩展点。我见过一开始没留扩展点的项目后来加功能只能推倒重来。我个人在实际操作中的体会是网关这东西前期投入值得越早做越好。等到业务线多了再补迁移成本会高很多。另外不要追求大而全先把鉴权、限流、计量、日志这四样做扎实其他的慢慢加。最后分享一个小技巧网关的配置变更一定要有回滚机制改错了能一键恢复这个在半夜出故障的时候能救命。
返回列表