简介:《美团大模型Agent实践手册》是一份面向技术开发者、业务应用者与决策者的参考指南,聚焦大模型Agent从理论到落地的完整链路。开篇先梳理Agent定义、核心能力、定位价值与发展历程;第二章围绕龙猫大模型(LongCat-Flash-Chat)阐述核心架构、模型训练流程与能力评估矩阵;随后结合外卖、到店、酒旅、共享单车业务线给出实践案例,展示不同场景的落地方法与效果。开发流程部分覆盖需求分析、数据准备、模型选型与微调、架构设计、测试优化;工程化实践则涉及工具链与平台支持、监控运维、安全合规,并进一步延伸到评估指标、A/B测试、迭代优化和避坑指南,兼顾深度与可操作性。资源为1个PDF文档,大小约753KB,目录结构完整、章节分明,便于按需查阅。已有179人学习下载,适合正在规划或推进大模型Agent相关工作的技术团队参考。
1. 大模型Agent实践手册:美团业务链路里真正在用的架构、工具、记忆与评测
美团业务里最不缺的就是「多一步判断」:外卖售后要先分责任,到店评价要先辨真伪,运力调度要同时看供需和时效。过去这些判断靠规则引擎一条条写,写到后面规则上万条,新增一个促销活动要改十几个分支。大模型Agent把问题换了问法——判断交给模型,执行留给系统,Agent负责理解、检索、调用和协作,人只留最终审核。这份实践手册讲的不是Agent论文复现,而是把美团这类真实业务链路里跑Agent需要的架构选型、工具接入、记忆管理和上线评测一次讲透。适合已经搭过原型、却被效果不稳和回归事故反复折磨的Agent开发者,也适合刚入行、想避开常见深坑的初学者。
2. Agent架构选择:单Agent与多Agent的分界线,以及四种编排范式
2.1 单一Agent为什么会在复杂链路里失灵
很多人第一个原型都是「一个Agent包打天下」:把业务规则、工具说明、话术风格全塞进一个system prompt,模型也确实能答上几句。但业务一复杂,问题立刻暴露。首先是提示词膨胀,规则越写越多,动辄三四千字,模型对早期指令的遵从度明显下降,尤其是把权限校验、售后策略、话术规范堆在一起时,模型经常捡了话术忘了校验。其次是上下文污染,售后意图的中间结果残留在上下文里,下一轮到店咨询就可能把上一单的商户ID带进来,生成答案出现串单。
最麻烦的是变更成本。规则引擎时代改一条规则,定位到分支改完就发布;单一Agent时代改一个环节,所有prompt片段都耦合在一起,你没法只改「退款策略」而不影响「情绪安抚」。而且有些环节根本不适合模型发挥,比如金额计算、库存扣减,模型做一次错一次。踩过这类坑之后,我一般建议团队先把「判断型任务」和「执行型任务」分开:判断交给Agent,执行交给确定性系统,Agent只负责选择工具和解析结果。这就是从单Agent走向多Agent的起点。
2.2 路由、串行、并行、反射:四种编排范式怎么选
多Agent不是把模型数量堆上去,而是把「职责」拆出来。实践里最常用的编排范式有四类,我按使用频率排一下:路由、串行、并行、反射。
| 范式 | 做法 | 适用场景 | 典型例子 |
|---|---|---|---|
| 路由 | 先判断请求类型,再分发给对应Agent | 意图差异大的入口 | 售后、到店、运力调度先分流 |
| 串行 | Agent按固定顺序接力处理 | 有明确前后依赖 | 先抽取槽位→再调工具→最后生成回复 |
| 并行 | 多个Agent同时处理互不依赖的子任务 | 需要同时取多方信息 | 同时查商户评级、竞对价格、天气路况 |
| 反射 | Agent完成后自我检查或让另一Agent审查 | 对正确率要求高的环节 | 退款金额复核、工具参数二次校验 |
路由是性价比最高的一个,它能把复杂问题拆成多个小问题,每个下游Agent的prompt都能短一大截。串行适合流水线型任务,比如先识别意图再填参数再执行。并行能明显降延迟,但要注意多个Agent同时访问资源时的限流。反射是口碑分化最严重的:用得好能挡掉不少幻觉,用不好会让延迟翻倍、成本上升,我一般只在金额计算和权限判断这类高风险节点加反射。很多团队第一反应是先微调一个领域模型,我一般劝他们先别急,先把编排范式定下来跑通链路,再看模型到底卡在哪里,很多问题调整prompt和工具就能解决,未必需要动微调。
2.3 最小可用的编排骨架:一个可以直接改的Python示例
下面这个例子不是完整框架,而是我习惯用来起项目的最小骨架,把路由和串行组合起来,足够撑起一个简单的售后咨询场景。
# workflow.py 最小多Agent编排:路由 + 串行 from dataclasses import dataclass, field @dataclass class AgentNode: name: str # 节点名称,用于日志和追踪 role_prompt: str # 该Agent的角色限定,尽量短 max_retry: int = 2 # 单节点失败重试次数 @dataclass class Workflow: route_node: AgentNode # 先由路由Agent决定分支 steps: list = field(default_factory=list) # 后续串行节点列表 max_iterations: int = 5 # 整个编排最大循环次数 wf = Workflow( route_node=AgentNode( name="router", role_prompt="判断用户请求属于售后/到店/运力哪一类,只输出类别ID", ), steps=[ AgentNode(name="intent", role_prompt="抽取用户意图与关键槽位"), AgentNode(name="tool_call", role_prompt="选择工具并给出参数"), AgentNode(name="reply", role_prompt="根据工具结果生成给用户的最终回复"), ], )逻辑说明:路由节点先判断请求类别,后续节点按顺序执行。每个节点的role_prompt都只聚焦一件事,避免一个长prompt包揽全部职责。max_iterations是兜底参数,防止多Agent相互触发形成死循环,这在后面排查章节还会专门讲。
参数说明:max_retry一般设2就够了,超过两次还失败说明工具或prompt有问题,重试更多次只会白白消耗Token。max_iterations建议5以内,这个值是全局循环上限,不是节点数上限。实际工程里我不会直接用Python类存工作流,而是把它序列化成JSON存到配置中心,这样业务方改流程不用发版,配合LangGraph或自研状态机都可以,关键在于「路由先行、串行兜底、循环有限」。
3. 工具调用与数据接入:Function Calling、MCP和RAG的边界
3.1 Function Calling与MCP:两类工具接入范式的对比
Agent光会聊天没有生产力,必须能调用业务系统。现在主流的两条路:Function Calling和MCP(Model Context Protocol)。Function Calling是大模型接口层面直接支持的机制,你在请求里声明工具Schema,模型输出结构化调用参数,应用层拿到参数后自己去执行HTTP接口。MCP则是一种标准化协议,把工具、资源、提示词统一暴露给Agent客户端,相当于给Agent做了一个「USB接口」。
我在实际项目里怎么选?内部系统多、接口杂、且团队以Java/Python为主时,优先Function Calling。原因很简单:每个内部系统已经有HTTP接口和鉴权体系,包一层工具Schema就能让模型调用,不需要为了接MCP额外搭一套协议服务。MCP更适合工具生态要对外开放、或者要接标准化外部能力的时候用。另外一个现实问题是外部的MCP Server不一定能进内网,企业场景里私有化部署或走内网网关才是常态,凭证下发和权限校验必须在网关层做,别让Agent直接接触Token。
| 对比维度 | Function Calling | MCP |
|---|---|---|
| 协议定义位置 | 模型厂商接口内 | 独立协议层 |
| 接入成本 | 低,声明Schema即可 | 中,需要MCP Server/Client |
| 适合场景 | 内部系统接口接入 | 标准化工具生态、对外开放 |
| 权限控制 | 由应用层实现 | 协议层可统一管控 |
3.2 把内部接口暴露给模型:工具Schema怎么写才不翻车
工具接入里翻车最多的不是模型能力,而是Schema写得太随意。模型对参数的理解完全依赖description,你写得不清楚,它就会发挥想象力。下面是我在实践里经常用的一份工具Schema,用于查询商户差评明细,字段不多但每个都有关键约束。
{ "type": "function", "function": { "name": "query_merchant_reviews", "description": "查询商户在指定时间窗口内的差评明细,用于售后和运营分析", "parameters": { "type": "object", "properties": { "merchant_id": { "type": "string", "description": "美团商户ID,来自用户订单或上下文,不可编造" }, "days": { "type": "integer", "enum": [7, 30, 90], "description": "查询时间窗口,只支持最近7天、30天、90天" }, "category": { "type": "string", "enum": ["food", "service", "delivery"], "description": "差评分类,不指定则查询全部" } }, "required": ["merchant_id"] } } }逻辑说明:核心是merchant_id的description里写清「来自用户订单或上下文,不可编造」,这一句话能挡掉大量参数幻觉。days和category都用enum收窄候选值,模型只能从集合里选,不会生成一个不存在的「45天」或「experience分类」。
参数说明:required只放真正必须的字段,把可选项都做成非必填,能显著降低模型填充参数的负担。进阶一点的做法是在执行前加一层校验——merchant_id必须是纯数字且能在商户表里查到,查不到直接返回「参数校验失败」并让模型重试一次,不要把这个错误结果直接发给用户。这套思路对任何内部接口都适用。
3.3 RAG与业务直查的边界:什么时候走向量,什么时候直接查库
工具调用解决的是「模型要系统做什么」,但Agent还需要「知识」。很多团队一上来就搭RAG,把文档全灌进向量库,结果答非所问。我的判断标准很简单:把数据分成「知识类」和「状态类」。知识类指变化慢、适合预先索引的内容,比如售后政策、活动规则、商品介绍,走RAG;状态类指实时性要求高的内容,比如订单状态、骑手位置、库存数量,必须走工具直查数据库,RAG搞不定实时数据。
RAG的参数也有讲究。我在实践中会把top_k控制在5到8,检索相似度阈值设在0.35以上,并对召回的片段做一次重排,避免前几个片段全是噪声。检索得分过低的内容宁可让模型说不清楚,也不能硬凑答案。单一Agent时代那种「上下文里有什么就信什么」的做法,在多Agent场景里会放大错误——下游Agent会把上游检索错的片段当成事实,继续往下传。所以每个RAG结果我都要带上来源ID和得分,一旦生成结果可疑,还能回溯到是哪一段知识污染了答案。
4. Agent记忆与上下文管理:短期、工作、长期三层模型怎么搭
4.1 三层记忆模型:为什么必须把记忆从模型里搬出来
模型本身是无状态的,上一轮聊了什么,下一轮就忘了。客服Agent尤其明显——用户刚报完订单号,转人工后再进来,Agent已经不知道之前发生了什么。实践里我会把记忆拆成三层:短期记忆、工作记忆、长期记忆。
| 记忆类型 | 存什么 | 放哪里 | 生命周期 | 场景例子 |
|---|---|---|---|---|
| 短期记忆 | 最近几轮对话原文 | 请求上下文 | 单次会话内 | 用户上一句说了什么 |
| 工作记忆 | 当前任务的关键状态 | Redis + 内存 | 任务执行期间 | 已选定的订单、待确认金额 |
| 长期记忆 | 用户画像、历史偏好、历史结论 | 向量库 + MySQL | 跨会话保留 | 用户常点川菜、上次退款原因 |
三层分开存是必须的。短期记忆负责「接住上下文」,工作记忆负责「别让任务断掉」,长期记忆负责「下次还能认出来」。把三层全堆进上下文,Token会迅速爆掉;把三层全放Redis,每次都要现查,延迟又高。我的做法是:短期记忆直接随请求传入,工作记忆用Redis键值对存,长期记忆写入向量库并关联用户ID,需要时按相似度召回。
4.2 上下文窗口不够用:滑窗、摘要与工具结果截断的代码实现
大模型上下文长度再长,也扛不住多轮对话里每轮都塞工具返回的原始JSON。工具返回结果往往几千字,真正有用的可能就几行。下面这段代码是我处理上下文超限的常规操作:把早期对话压缩成摘要,只保留最近几轮原文。
import tiktoken def compress_history(messages, max_tokens=8000, keep_last=6): enc = tiktoken.encoding_for_model("gpt-4o") # 先数一下当前总Token,避免做无用功 total = sum(len(enc.encode(m.get("content") or "")) for m in messages) if total <= max_tokens: return messages # 保留最近 keep_last 条原始消息 recent = messages[-keep_last:] history = messages[:-keep_last] # 对更早的消息调用LLM生成摘要,这里是占位函数 summary = summarize_with_llm(history) system_msg = {"role": "system", "content": "以下是更早对话的摘要:\n" + summary} return [system_msg] + recent逻辑说明:先估算总量,没超限就直接返回,省一次摘要调用。超限后保留最近几轮原文,因为贴近当前意图的消息不能丢;更早的对话压成摘要,放到system消息里兜底。这样模型既能看到「大致经过」,又保住了「当前状态」。
参数说明:max_tokens按模型窗口的70%来设,留出工具调用和生成回复的空间;keep_last我一般取6到8,太少上下文接不住,太多摘要失去意义。这条路上我踩过最深的坑是直接丢弃早期消息,结果用户问「我刚才是不是已经退了款」,Agent完全答不上来。有了摘要兜底,这类问题才算缓解。另外工具返回结果一定要先截断,默认只保留前1000字符,重要字段单独抽出来放进工作记忆,别让原始JSON进上下文。
4.3 记忆存储的底层结构:Redis与向量库里该放什么字段
长期记忆不能乱存,否则查询时根本找不回来。我习惯为每个用户建立独立的memory空间,核心字段固定在结构中。
| 字段 | 类型 | 说明 |
|---|---|---|
| user_id | string | 用户唯一标识,所有记忆的根 |
| task_id | string | 关联的任务或工单ID |
| content | text | 记忆内容,比如「用户反馈出餐慢」 |
| embedding | vector | content的向量,用于语义召回 |
| confidence | float | 记忆置信度,低于0.3不召回 |
| created_at | int | 写入时间戳,用于时效过滤 |
Redis侧存工作记忆,key形如agent:{user_id}:task:{task_id},TTL设为15分钟,任务结束自动过期。向量库侧存长期记忆,召回时按user_id过滤再加confidence过滤,最后按时间倒序。为什么不把长期记忆也放Redis?因为用户偏好是语义查询,不是精确匹配,向量检索才能找到「用户上次说不要香菜」和「用户备注了忌口」这种表述不同但含义相近的记忆。
5. Agent避坑与排查:五个上线前最容易翻车的场景
5.1 工具调用幻觉:模型编出一个不存在的商户ID
现象:Agent调用查询工具时,把商户ID写成「123456」,系统查无此店,它还能一本正经地说「该商户已关店」。原因:Schema里没强调ID来源,模型在上下文中找不到时就自己生成。解决:工具参数校验层加白名单校验,merchant_id必须能在商户表命中;不命中时让模型重新从历史消息提取。我在Schema的description里加了「不可编造」四个字之后,这类错误少了一半,剩下的一半靠校验兜底。
5.2 上下文超限:不到五轮就报Token不足
现象:用户聊到第五轮,请求直接报错,业务方以为是模型窗口太小。原因:每一轮工具返回的完整JSON都被塞进上下文,垃圾内容把窗口占满了。解决:工具结果按字段裁剪,只保留模型生成回复必需的核心字段;每次构造请求前先做一次Token估算,接近阈值就触发摘要压缩。上线前压测时要专门测「多轮对话+频繁调工具」的组合场景,只看单轮延迟会漏掉这个问题。
5.3 多Agent死循环:A调B、B调A,最后账单先爆了
现象:Agent A判断需要B处理,B又认为该A处理,两个Agent互相触发,日志像刷屏一样滚,Token消耗按分钟计。原因:编排图里存在环,且没有全局终止条件。解决:在编排引擎里加max_iterations,一个节点重复执行直接短路;每次调用都登记调用链,同一个节点第二次出现就中断并上报。实践里我把这个参数提到配置中心,业务方也能看,但默认值锁死在5,谁改谁就得说明理由。
5.4 RAG检索污染:置信度低的内容被当成依据
现象:用户问退款时效,Agent答非所问地扯到骑手补贴,但语气非常笃定。原因:检索召回的第一条片段得分不高,但top_k里包含了相似但无关的内容,模型把它当成依据。解决:把召回得分阈值从0.2提到0.35,top_k从10收到5;召回结果必须带来源和得分一起交给模型,让模型知道这段知识的可信度;可疑回答还要在界面上展示引用来源,方便人工复核。
5.5 离线评测虚高:ROUGE/BLEU好看,线上却没人用
现象:离线测试集跑出90%以上的ROUGE分数,上线后任务成功率只有60%。原因:生成式指标衡量的是「跟标准答案像不像」,不是「任务有没有完成」。一句回复字数接近标准答案就能得高分,但该调的接口没调、该退的款没退,指标完全反映不出来。解决:离线指标只看三个——任务完成率、工具调用准确率、平均对话轮次;把测试集按正常请求、歧义请求、越权请求、未知请求四类分别统计,哪类掉分补哪类。从这之后,我再也不拿ROUGE当Agent的核心指标。
6. Agent上线前的最后一道工序:回归集、影子模式与四个核心指标
Agent迭代快,一个prompt改动可能让已修复的问题复发。我每次发版前都会过一遍四条验证:回归评测集、影子模式、核心指标看板、成本账单。回归评测集至少准备四类样本:正常请求、歧义请求、越权请求、未知请求。歧义类专测Agent会不会追问确认,越权类专测权限边界,未知类专测会不会强行编答案。这四个分类能覆盖大部分线上翻车源头。
| 指标 | 计算方式 | 红线 |
|---|---|---|
| 任务成功率 | 成功完成任务数 / 总任务数 | 低于上一版本2个点则阻断发版 |
| 工具调用准确率 | 参数校验通过并执行成功次数 / 总调用次数 | 低于85%需要复盘Schema |
| 平均对话轮次 | 总轮次 / 任务数 | 超过5轮说明Agent在绕圈子 |
| 单任务成本与P95延迟 | 成本按Token计,延迟按网关统计 | 成本翻倍或P95突破5秒自动告警 |
影子模式是最后一道安全网:把线上真实流量复制一份打到新版Agent上,但不做真实写操作,只记录它会怎么回复、怎么调工具,和旧版本的结果做对比。新版在影子模式下跑两三天,看任务成功率有没有掉、有没有出现旧版没有的越权调用,确认没问题才切流量。我吃过一次亏:离线评测集都是精心标注的样本,跑出来成功率96%,上线后P95延迟从2秒涨到8秒,用户根本等不到Agent把话说完。从那以后我每次发版前都强制走一遍「回归集+影子模式+四指标」这个流程,确认成本和延迟没有异常才敢放量。希望帮到你。
本文还有配套的精品资源,点击获取