大模型岗位核心工程能力:推理服务、RAG与Agent交付清单
发布时间:2026/9/28 15:38:54来源:尧图网络
“能交付”这三个字现在在大模型岗位的招聘里被反复强调但很多候选人还是在用“我会调API”“我跑过开源模型”“我看过RAG教程”的状态去面试。我自己经历过从算法研究转向工程交付的过程也带过几个校招生做推理服务、RAG和Agent项目很清楚面试官和你真正要面对的业务方关心的根本不是你会背多少概念而是你能不能把一个模型服务稳定跑上线、让检索真的能把答案找对、让Agent在真实任务里不翻车。这篇内容我就按自己在实际项目里积累的经验把大模型应用岗位最核心的三块工程能力——推理服务、RAG、Agent——拆成一份可以直接对照自检的能力清单每一块都结合真实的部署参数、报错场景和设计取舍来聊。不管你是准备面试、刚转岗还是在团队里从零搭一个LLM应用这份清单都值得你逐条核对。1. 先聊清楚大模型岗位到底要交付什么1.1 “能交付”三个字的真实分量我面试候选人的时候最常问的一个问题是“如果明天上线你负责的这部分挂了你怎么处理”能交付的人会说出具体的监控指标、日志位置、回滚方案、降级策略不能交付的人会说“那应该是运维的事”或者“我再查查”。这两种回答之间的差距就是岗位筛选的底层逻辑。所谓“能交付”翻译成工程语言就是你不仅知道模型怎么调用还要知道服务怎么部署、资源怎么估算、并发怎么扛、数据怎么流转、问题怎么排查、效果怎么验证。说得更直白一点你要对从模型权重到用户反馈的全链路负责。模型微调、推理优化、RAG召回、Agent规划这些都只是这条链路里的环节真正值钱的是你把它们串成一个稳定系统的能力。我在带项目的时候发现很多同学对“完成”的定义是“在我本地跑出了结果”。但在生产环境里“完成”意味着有版本管理的模型镜像、有可重复的部署流程、有明确的性能基线、有告警和降级预案、有评估数据集和回归测试。这些内容学校里很少教却是岗位考察的重点。所以你准备面试也好准备项目也罢都要带着“如果这是线上系统我要怎么做”的思路去补细节。另外大模型岗位现在细分得很厉害。有做模型训练和微调的有做推理加速的有做RAG知识库的有做Agent编排的还有纯粹做中间层封装的。岗位名称可能都叫“大模型工程师”或“算法工程师”但实际做的事有很大差别。你在准备的时候一定要先判断目标岗位的重心在哪一块再针对性地深挖。不过无论侧重哪一块推理服务、RAG、Agent这三个能力域都绕不开只是深度要求不同。1.2 能力地图推理服务、RAG、Agent三者的关系这三块能力不是并列的三个独立技能树它们之间有明确的依赖关系。推理服务是底座RAG是让模型“知道更多”Agent是让模型“能够行动”。一个完整的大模型应用大概率是这三者的组合底层有稳定的推理服务中间有检索增强来补全私域知识上层有Agent把模型能力编排成自动化流程。我把这个关系画成一张能力地图方便你对照自检能力域核心问题关键产出主要考察点推理服务模型怎么跑得稳、跑得快、跑得便宜在线接口、性能基线、压测报告部署方案、显存估算、并发优化、稳定性RAG模型怎么答得准、答得可信检索链路、评估报告、知识库更新机制切分策略、召回质量、重排、幻觉控制Agent模型怎么真正把事办成工具调用链路、任务执行记录、兜底机制函数调用、规划拆解、记忆、错误恢复对候选人来说我的建议是选一个最贴近目标岗位的方向做深另外两个至少做到能讲清楚原理、能指出关键坑的程度。比如你投的是Agent开发岗那Agent方向的函数调用和记忆机制你要能写出实战细节但RAG的切分策略和推理服务的显存计算你也要能聊出个一二三。因为面试官大概率会追问系统联调的问题——你的Agent用到的知识从哪来底层推理服务挂了怎么办这些跨域的追问才是真正区分“背题选手”和“实战选手”的地方。2. 推理服务从“能跑通”到“能扛压”2.1 部署方案选型vLLM、TGI、SGLang怎么选推理服务这块大家第一反应基本都是用开源框架把模型部署起来。但我面试的时候很多人只说得上来“我用vLLM部署了模型”再问为什么选vLLM、和TGI有什么差别、并发上来后效果如何就答不上来了。这种回答在项目复述层面是合格的但在“能交付”层面是远远不够的。目前主流的自托管推理框架就那几个vLLM、Hugging Face TGI、SGLang还有NVIDIA的TensorRT-LLM。我个人的经验是vLLM是目前生态最成熟、资料最多、社区最活跃的选择大多数人用它是没问题的。它基于PagedAttention管理KV Cache显存利用率比传统方案高很多而且兼容OpenAI的接口协议接入上层应用非常方便。TGI的优势是和Hugging Face生态绑定紧但性能表现和vLLM相差不大选择它更多是团队技术栈的延续。SGLang在复杂推理场景下通过RadixAttention做前缀缓存多轮对话和共享上下文的场景里优势明显但它的代码迭代非常快生产环境的稳定性需要多观察几天再说。如果你部署的是量化模型比如AWQ、GPTQ或者FP8那么不同框架的适配度也要纳入考虑。vLLM对主流量化格式的支持最全TGI次之SGLang相对晚一些。所以我的建议是没特殊需求就默认vLLM遇到多轮对话长上下文瓶颈就试试SGLang团队里有TensorRT经验再考虑TensorRT-LLM。选型的时候还要考虑硬件的差异。vLLM对NVIDIA的卡适配最好AMD的ROCm版本和华为昇腾的版本目前都是可以用的但问题会比NVIDIA多一些。这个细节在面试里提出来会非常加分因为说明你真的在多硬件环境下踩过坑。2.2 显存估算一张A100/H100到底能装多大模型推理服务部署第一步就是算显存。我见过很多新人二话不说就把70B模型往单卡上用然后OOM了再换方案完全没有前置估算的概念。显存计算其实是有明确公式的掌握之后你就能在选型阶段直接判断方案可行性。一个关键的概念是模型在推理时显存占用远不止权重本身。部署模型时占用显存的主要有三部分模型权重、KV Cache、推理过程的临时激活值。以13B模型为例FP16精度下权重本身占用的显存大约是13B乘以2字节也就是26GB左右。单卡A10080GB可以直接装下但如果用FP8量化权重降到约13GB剩余空间就可以给KV Cache留出更大的容量。KV Cache的大小和并发数直接相关。计算公式是KV Cache显存 2K和V × 层数 × 每层KV头维度 × 序列长度 × 并发数 × 精度字节数。以13B模型、40层、序列长度4096、并发16为例粗略计算下来KV Cache就要占20GB以上。所以我们常说中长上下文的并发场景KV Cache比权重还吃显存。实际操作中我建议你在部署前用以下步骤做快速估算确认模型的参数量和量化精度计算权重占用的显存。根据业务场景确认最大序列长度max_model_len。根据上游并发需求确认最大并发数max_num_seqs。用经验值权重显存 KV Cache显存 至少4GB的临时开销。看总量是否在单卡显存范围内超出就考虑切分或调整并发。你不需要把每个数值算得特别精确因为推理框架会动态分配显存。但有了这个估算你至少能判断一张80GB的显卡到底能不能稳定承载这个模型的并发服务还是必须用张量并行切分到多卡。这个判断能力是面试官很看重的。2.3 核心参数从配置到理解vLLM部署时有几个参数是我面试必问的max_model_len、gpu_memory_utilization、max_num_seqs、max_num_batched_tokens、enable_prefix_caching。很多人只会照着文档抄不知道改它们的实际影响。max_model_len决定模型能处理的最大上下文长度。这个参数直接决定KV Cache的上限。你把它设得越大能处理的单请求越长但KV Cache可分给并发请求的总预算就越少。所以我从来不建议无脑设成模型原生的最大长度而是根据业务需求去定。比如你的业务是客服问答上下文超过8000 token的场景极少那就设8192没必要设成32768然后把并发能力牺牲掉。gpu_memory_utilization控制推理框架占用的显存比例默认0.9也就是只留10%的余量给其他进程。如果这台机器还跑着别的服务必须调低这个值如果独占显卡可以调到0.92甚至0.95。我自己的经验是把它设到0.95以上容易在高并发时触发碎片化的OOM因为显存分配不是连续的。最稳的组合是0.9到0.92之间然后靠max_num_seqs控制并发上限。max_num_seqs是同时处理的请求数上限。这个参数和显存是联动的和max_model_len共同决定了KV Cache的压力。我的调优习惯是先用默认值压测一下观察显存利用率和TTFT首token延迟如果显存还有余量就逐步上调直到出现性能拐点就回退一档。性能拐点一般出现在TTFT显著升高或者批处理时间变长的时刻。enable_prefix_caching是vLLM的一个隐藏优化点。打开它后如果多个请求共享相同的前缀比如都是同一套系统提示词框架会把那条前缀的KV Cache缓存下来复用。实测在多轮对话场景里这个开关能减少30%到50%的重复计算。但是要注意它会把一部分显存固定留给缓存所以如果你本身的并发压力就很大需要权衡一下。2.4 并发优化与压测真实数据比感觉重要部署完成后的第一件事就是压测没有压测数据就不算交付。压测的核心指标有三个吞吐量tokens/s、TTFT、以及显存是否稳定。这三个指标分别代表服务“能处理多少”“响应快不快”“会不会偷偷泄漏”。最简单的压测方式是写一个并发脚本用线程池同时发起几十个请求统计总耗时和首token到达时间。我贴一个自己常用的最小实现import time import threading from openai import OpenAI client OpenAI(base_urlhttp://localhost:8000/v1, api_keydummy) def send_request(prompt, results, idx): start time.time() response client.chat.completions.create( model/path/to/model, messages[{role: user, content: prompt}], max_tokens512, temperature0.7, ) ttft time.time() - start results[idx] (response.usage.completion_tokens, ttft) prompts [请用300字解释人工智能 for _ in range(32)] results {} threads [threading.Thread(targetsend_request, args(prompts[i], results, i)) for i in range(32)] t0 time.time() for t in threads: t.start() for t in threads: t.join() total_time time.time() - t0 total_tokens sum(r[0] for r in results.values()) print(f并发32耗时: {total_time:.2f}s, 总输出: {total_tokens} tokens) print(f吞吐: {total_tokens / total_time:.1f} tokens/s) print(f平均TTFT: {sum(r[1] for r in results.values()) / len(results):.2f}s)跑压测的时候一定要盯住两个容易出问题的点显存碎片化和超时任务堆积。显存碎片化的典型症状是压测一段时间后某个请求报OOM但看总显存占用并不高。这种问题通常只能靠重启服务解决所以我建议在自动扩缩容策略里加上“显存碎片率超过阈值就自动重启实例”的规则。超时任务的典型症状是服务好像没挂但响应时间越来越长QPS没有明显变化但延迟持续走高一般是之前的慢请求占着资源不释放排查时重点看活跃请求数和等待队列长度。压测后要把结果整理成基线记录方便后续迭代时做对比。比如优化了启动参数后如果你知道之前的基线和当前的数据就能量化地说明这次改动的收益。面试时能把“调整max_num_seqs从64到128后吞吐从820提升到1100 tokens/s但TTFT从0.6s涨到1.4s最终我们选择了96作为折中”这种话讲出来和只会说“我做了性能优化”是完全不同的效果。2.5 稳定性与发布弹性伸缩、优雅下线与多版本共存推理服务上线后稳定性比性能更重要。模型推理服务和普通后端服务最大的差异在于它是无状态的但很重显存占用高所以弹性伸缩的策略要特殊设计。我见过团队直接用K8s的HPA按CPU使用率来扩缩容结果CPU都打满了实例还没扩出来因为申请新实例后要拉镜像、加载模型权重光准备时间就要两三分钟。正确做法是要结合显存水位和请求延迟设计扩缩容策略预留至少3到5分钟的预热缓冲。更讲究一点的做法是“预热队列”新扩容的实例先接收少量请求跑热模型再进入正式负载均衡池。优雅下线也是一个容易被忽略的点。因为推理进程加载了巨大的模型权重直接kill会导致当前正在处理的请求全部中断。我们当时的做法是在K8s的preStop钩子中调用vLLM的暂停接收新请求的接口等已进入的请求全部结束后再退出容器。看起来是一个细节但线上事故往往就发生在这些细节上。多版本共存适用于模型版本迭代的场景。上线新模型时不要直接替换旧版本而是新旧两个服务同时跑一段时间。流量按比例灰度切到新版同时用一个离线评估脚本对比新旧版本的输出质量。确认新版没有明显回退后再把流量全部切过去。这个过程在大模型应用里格外重要因为模型输出不像普通程序那样有明确的对错可能整体指标差不多但某些case变差了。灰度期能给你反悔的机会。3. RAG检索增强不是拼装是要能答对3.1 完整链路从文档入库到答案生成RAG项目我做了很多个最大的感受是几乎所有失败的项目都死于“把RAG理解得太简单”。很多人以为RAG就是文档切一切、向量化、然后相似度检索拼到prompt里。实际上完整的RAG链路至少包括文档解析、清洗、切分、向量化、索引构建、召回、重排、上下文压缩、生成以及贯穿始终的评估和知识更新机制。我给你一个能落地的链路设计参考阶段核心任务常见工具常见坑文档解析从PDF/Word/网页中抽取文本PyMuPDF、unstructured表格内容丢失、PDF乱码清洗去噪、去重复、格式归一正则、自定义规则清洗过度导致语义断裂切分按结构或语义切块LangChain文本切分器、自研切分逻辑固定大小切分破坏语义向量化文本转embeddingBGE、OpenAI embedding选错向量维度、未做归一化召回检索相关片段向量检索、BM25、混合检索TopK太小漏召回重排精排提升准确率bge-reranker、cross-encoder跳过重排导致相关性差生成拼接上下文并生成大模型、提示词上下文超限、答案漂移评估验证检索和生成效果RAGAS、自建评估集只看感觉不看数据文档解析这步很多人图省事直接用库里的默认参数结果表格被拆得七零八落。尤其是PDF里的表格。我试过用PyMuPDF直接提取表格结构几乎全丢后来只能用pdfplumber逐行提取加上表格结构正则或者用Unstructured的表格识别模式。一个简单的判断标准就是把解析出来的纯文本打开看一眼如果表格内容断成了无意义的碎片那后面的切分和检索都会带着这个缺陷。清洗比解析更容易被忽视。有些文档里每页都有页眉页脚嵌入向量后这些重复文本会和正文内容混在一起导致检索结果一直带上无意义的页眉。我的做法是先做一个规则过滤器把页眉页脚、页码、固定的版权声明文本全部去掉再进入切分流程。这类规则不复杂但对最终效果的影响非常大。3.2 切分策略固定大小 vs 语义切分切分是RAG里最微妙的一步。切太碎单个片段缺乏上下文检索回来模型看不懂切太大片段里噪声多而且超过向量模型的处理上限还可能要截断。我见过很多项目用固定大小256字符加50字重叠来切在通用文档上能跑但一旦遇到结构复杂一点的技术文档效果就很差。我自己的经验是先用结构优先切分再用大小兜底。意思是如果文档有明确的标题结构按Markdown标题、HTML结构或者PDF的大纲层级先把文档切成一棵章节树再把每个章节细分成适合检索的块。比如一个章节下面有若干小节优先保持小节完整性如果一个小节仍然很长再按段落切最后才用固定长度兜底。重叠overlap明显比很多人想的更重要。文本切分时加上前后重叠是为了保证一个语义完整的句子不会被拦腰斩断。比如一句话最后几个字被切到了下一个块查询时检索到的是前一块但答案信息在下一块开头就会漏召回。常见的策略是重叠50到100个字符并且尽量在句号或换行符处切断而不是硬切。从工程实现的角度LangChain的RecursiveCharacterTextSplitter可以按分隔符列表递归切分先用章节分隔符再用段落最后用句号。但如果你对切分质量有更高要求我建议自己写一个基于标题树的分块器先用正则把标题层级识别出来构建目录树然后按树结构遍历把内容分配到最近的标题下。这个实现可能多花半天时间但检索效果的提升是值得的。切分完成后最好把每个片段的字符数分布打出来看一眼如果方差特别大说明有部分内容切得不合理。3.3 向量化与召回不能只靠余弦相似度向量化模型的选择直接决定检索效果的底座。目前中文场景下BGE系列如BAAI/bge-large-zh-v1.5和智源的text2vec系列都比较经典最近也有一些新模型开源。我更看重的是你的向量模型和你的文档领域是否匹配。如果文档偏法律找法律领域微调的embedding模型效果会明显好于通用模型。如果文档偏代码那用代码专用的embedding模型。向量化之后的相似度计算也不都是简单余弦值。先做归一化再做点积效果等同于余弦相似度但在向量数据库中计算更快。这一点细节很多教程不会提但对企业里大量向量的场景来说性能差异是实打实的。召回阶段最大的坑是只做向量召回。向量召回擅长语义相似但字面差异大的情况但在专有名词、ID、缩写这类场景下BM25这种稀疏检索反而更精确。所以我现在的新项目基本都做混合检索Hybrid Search向量召回和BM25召回各取TopK合并后去重再交给重排模型精排。这个组合在大多数业务场景里比单路向量召回能稳定提升5到15个百分点的召回准确率。关于TopK怎么选我的经验是从10到20起步看重排后的效果再调整。如果TopK太小重排模型没有足够的候选可选如果太大重排的计算量上来了端到端延迟会增加。一个比较稳妥的方案是召回Top50重排取Top5。这个配置在长文档库上尤其有效因为前几步的检索会有一些位置偏颇多召回一些再做精排能拯救很多边界case。3.4 重排与上下文压缩别把全部片段塞给大模型重排Rerank的价值在于它用一个更强的cross-encoder模型重新计算每个候选片段和当前查询的相关性。不同于embedding检索的“离线向量比较”重排是在运行时真正把查询和文档片段一起过一遍模型所以相关性判断更准确。常用的是BGE系列的reranker也有用LLM做rerank的但成本太高线上实时链路里响应时间压不住。我用BGE reranker在多个项目里的经验是重排后Top5答案的命中率比直接取向量Top5能显著提升尤其是查询词比较口语化或者带歧义的时候。上下文压缩也是容易被忽略的一步。检索回来的Top5候选片段每个可能都有上千字拼到一起很容易就把模型的上下文撑爆。压缩的做法有两种一种是只截取片段中与查询最相关的部分用句子级别的相关度计算后裁剪另一种是用一个小模型把多个候选片段的内容概括成要点。第一种常用因为实现简单、不引入额外延迟。第二种效果好但成本高适合离线分析场景。生成阶段的提示词设计也要花心思。系统提示词里要明确告诉模型只依据提供的参考内容回答如果参考内容没有答案就如实说不知道不要编造。同时给模型提供引用来源的编号要求它在答案中标注来源这样用户可以在界面上溯源验证。这个“可溯源”能力在企业场景非常重要也是面试官很爱问的细节。3.5 RAG质量评估RAGAS和自建评测集缺一不可RAG项目不评估就上线基本等于裸奔。我之前带的一个项目开发同学觉得检索效果“看起来不错”结果上线后用户反馈答非所问的比例很高。后来我们才发现错在评估时只是肉眼看了几个case没有跑完整覆盖的数据集。现在我把评估当成RAG项目的必备环节。RAGAS是目前常用的开源评估框架核心指标包括忠实度答案有没有忠实于参考片段、答案相关性答没答所问、上下文相关性检索到的片段是否和问题相关。这三个指标分别对应生成质量、语义理解和检索质量加起来能比较完整地刻画一个RAG系统。跑评估的方式是把测试集里的每个问题用现链路完整走一遍然后把问题和生成结果提交给RAGAS计算分数。除了RAGAS我更建议每个RAG项目都维护一个业务专属的评测集。收集真实用户问题、运营人员手动标注的正确答案、返回的相关文档片段组成至少一两百条的数据集。每次修改切分策略、换向量模型、调TopK都在这个评测集上跑一遍对比用数字说话而不是靠感觉。这一步是“能交付”的一个非常重要的标志。评测集怎么构建也有学问。不要只收录容易的问题要刻意加入边界case比如包含专有名词缩写的、需要跨多个片段才能回答的、问题中带错别字的、知识库里答案出现在表格里的。这些case才是检验RAG质量的分水岭。我们团队的经验是评测集的效果往往比模型选择更影响你对系统质量的判断。4. Agent让模型真正“办事”4.1 从大模型到Agent工具、规划与记忆Agent是当前大模型应用最热门的方向也是“能交付”含金量最高的领域因为它把大模型从一个“聊天窗口”变成了“执行者”。我自己做Agent项目的体会是Agent应用的复杂度不在于模型本身而在于你如何设计工具调用协议、如何管理多轮状态、如何在模型犯错时兜底。一个典型的Agent系统由四部分组成大脑大模型、工具Function/Tool、记忆Memory、执行循环Agent Loop。大模型负责理解用户意图并决定调用哪个工具工具负责执行真实操作并返回结果记忆负责保存历史信息和任务中间状态执行循环负责让模型反复思考行动直到任务完成或给出最终回答。很多人最开始做Agent就是把Function Calling接到模型接口上然后发现效果非常不稳定有时候模型不调用工具有时候调用了但参数传错有时候模型陷入死循环。这就是因为缺少了对Agent执行循环的精细控制。Agent框架LangChain、LangGraph、MetaGPT、AutoGen、自研框架本质上就是对这个循环的封装但框架只是基础真正决定成败的是你对这个循环的理解深度。关于框架选择我的看法是Demo阶段用LangChain或LangGraph快速验证没问题但生产级Agent系统我目前更倾向于自己控制循环逻辑。因为LangChain抽象层次太高很多细节不可见出问题反而难排查。LangGraph好在把状态流显式化了能画出清晰的状态转换图。但不管用什么框架你都要能回答“模型决定调用工具之后工具返回结果怎么回填到上下文里”这个底层问题。4.2 函数调用Function Calling的正确姿势Function Calling是大模型Agent的第一块基石。模型本身不能执行任何操作它只是“决定”调用哪个函数、传入什么参数。这个决定是基于你对函数的结构化描述产生的。设计函数描述的关键是让模型的判断负担尽可能小。函数名要直观参数名要语义化参数描述要清楚说明每个参数的含义和取值范围。我踩过一个很典型的坑一个查询天气的函数参数里有个“location”字段描述只写了“地点”。结果模型经常传中文名比如“北京”而后端接口只接受经纬度或城市代码。后来我们把描述改成了“城市中文名例如‘北京’不接受英文或拼音”准确率立刻上来了。这个细节说明函数描述里要显式给出格式化示例让模型不用猜。参数校验是另一个关键环节。模型输出的参数不一定都是合法值后端服务收到后可能直接报错。所以函数入口必须有严格的参数校验层非法参数要能返回明确的错误信息并反馈给模型作为下一次修正的依据。我项目的做法是用JSON Schema约束参数类型和枚举值在函数执行前先用一个独立的校验函数检查失败时把具体原因拼成错误消息返回给模型。返回结果的处理也要设计。工具执行后的返回内容如果特别长比如查数据库返回了几千行全量塞回模型上下文会浪费token还可能干扰判断。我的做法是设置返回结果截断策略默认最多保留一定字符数比如2000字超过部分做摘要。同时给模型返回的格式要标准最好带一个执行状态字段比如“success”或“error”让模型一眼知道这次工具调用是否成功。4.3 记忆与多轮状态管理Agent的记忆机制是很多人忽略又最容易出问题的部分。短期记忆就是当前对话的上下文直接靠大模型的上下文窗口撑住长期记忆则是把有价值的信息持久化存储下次对话时再召回。实际做客服类Agent项目时需要让Agent记住用户的姓名、偏好、上一次沟通的进度。最简单的做法是把这些信息显式地放进系统提示词每次对话开始时注入。更进一步可以用一个独立的记忆库比如向量数据库或者Redis来管理用户画像和事实性信息在对话开始时自动检索相关记忆放入上下文。这个机制的工程化比想象中复杂什么时候写入记忆、什么时候更新记忆、记忆之间冲突了怎么办都需要制定规则。多轮状态管理还有一个坑模型会“幻觉记忆”。这是指模型在长时间对话中为了保持连贯而自己编造用户还没有提供过的事实。比如用户没说过自己在北京但模型后续回复里写了“您在北京的地址是xxx”。这个问题的根源在于上下文窗口里的旧信息会随着轮次增加被截断或遗忘模型会尝试用生成的方式补全缺失信息。解决办法是加上明确的护栏系统提示词里写清楚“只能使用对话历史中明确出现的信息不确定的信息要询问确认”同时在状态存储层维护一个“已知事实清单”在每次生成前校验生成内容是否与已知事实冲突。4.4 规划与任务拆解从ReAct到复杂流程Agent要完成复杂任务光靠一次Function Calling是不够的必须有能力把大任务拆解成多个子任务并有序执行。这就是规划Planning。ReAct模式是当前最经典的实现思考Reason→行动Act→观察Observe的循环模型每轮先想“现在要做什么”然后调用工具拿到结果后再进入下一轮思考。但在生产环境里ReAct模式有个显著问题模型可能陷入循环。有一个实习生做的项目模型反复调用同一个搜索工具查同一个关键词每次结果都一样它还是继续查。我们后来加了循环上限比如最多执行8轮并且让模型在再次调用相同参数的工具前必须解释为什么上一次结果没有解决问题不然直接终止。这个限制让Agent的行为稳定了很多。复杂流程还可以用更结构化的方式工作流编排。把任务拆成固定的步骤序列比如先查询用户订单、再判断是否需要退款、最后执行退款操作每一步使用一个独立的Agent或工具步骤间传递结构化数据。这种方式比自由规划更稳定适合业务流程相对固定的场景。我个人的经验是能用工作流表达的就不用自由的Agent规划。自由规划留给那些确实无法预知步骤的开放式任务。4.5 Agent稳定性错误处理、护栏与可观测性Agent系统的稳定性是整个大模型应用里最难做的因为它的行为有随机性。模型这次可能判断调用工具A下次可能判断调用工具B这种随机性在线上是不可接受的。所以生产级Agent必须有一个“金丝雀”层对模型的每个决策做合法性校验包括工具是否存在、参数是否合法、连续动作是否重复、调用频率是否超限。失败重试策略也很重要。Agent执行失败一般分两类模型侧的错误比如模型API超时、返回格式解析失败和工具侧的错误比如下游服务报了5xx。分开处理模型侧失败要重试并检查API的服务状态工具侧失败要把具体的错误信息返回给模型让它决定是修复参数再次调用还是换一个方案。我们团队在项目里总结了一个“三层兜底”机制我觉得值得分享硬兜底Agent任何一步失败就返回一个预设的友好兜底话术告知用户“暂时无法完成”并记录失败明细。软兜底模型第一次执行失败后把错误信息回填给模型一次“反思修正”的机会最多重试两次。人工兜底如果连续失败把case转入人工处理队列等待运营人员介入。这个机制的代码实现不复杂但对线上agent的可用性提升非常大。因为大模型应用不可能做到100%成功能优雅地失败并把失败的信息完整沉淀下来本身就是一种交付能力。4.6 Agent的可观测性Trace是标配Agent比普通接口难排查的地方在于一个请求在内部会经历多轮“模型决策→工具调用→结果反馈”的循环任何一个环节出错都可能让最终结果异常。没有Trace的话出了问题只能靠日志一点一点翻效率特别低。我现在的做法是Agent系统从第一天就接入Trace体系。最简单的方式是给每个请求生成一个request_id然后用JSON日志记录整个执行轨迹包括每一轮的模型输入输出、选择了哪个工具、工具返回了什么、耗时多久、是否重试。进阶的方案是接入LangSmith、Langfuse这类专门的LLM可观测平台它们能把Agent的多轮轨迹可视化地展示出来这个对Debug和调试的体验提升非常大。从面试角度讲能主动提到“我给Agent系统加了完整的Trace链路前端面板能看到模型在每一轮做了什么决策”是一个非常亮眼的点因为它直接证明了你“能交付”——你不仅让Agent跑起来了还让后续的维护和排查变得可行。5. 交付视角从Demo到生产环境的最后一公里5.1 可观测性与链路追踪你不知道线上发生了什么就是盲人摸象不管是推理服务还是RAG还是Agent生产环境必须具备可观测性。很多人做完Demo就停了Demo能跑通不代表能交付。可观测性做不好出了问题都不知道从哪里开始排查。我列一个生产环境最基础的监控清单监控对象核心指标告警阈值参考推理服务TTFT、吞吐、GPU显存使用率TTFT超过1.5s或者显存长时间超过90%推理服务请求错误率、P95/P99延迟错误率超过1%或P99超过5sRAG服务召回命中率、检索延迟命中率低于80%或检索延迟超过300msAgent服务工具调用成功率、循环超时次数工具失败率10%或超时次数持续增长底层基础设施节点CPU/内存/网络CPU峰值超过85%持续10分钟这里面TTFT和P99延迟是大模型服务的核心指标。相比传统的P95大模型服务的用户体验更依赖P99因为单个超时请求会让用户觉得服务卡顿。所以压测和监控都要把P99纳入重点。日志的结构化也非常重要。我见过团队排查问题的时候从一堆无格式的print输出里翻半天才找到关键信息。正确的做法是所有日志都用JSON格式输出包含request_id、模型名称、输入摘要、输出摘要、耗时、错误堆栈等字段。这样无论接入ELK还是自建日志平台排查效率都会高很多。5.2 成本与吞吐的平衡真实业务必须算这笔账大模型应用的成本是绕不开的话题。我见过很多技术Demo在资源充足的情况下效果很好一到业务方问“一天一百万次调用要多少成本”就哑火了。能算清楚成本也是“能交付”的重要部分。推理成本要从两个维度看单次调用的token数和并发吞吐。单次调用token数取决于你的提示词设计和输出长度限制这部分可以通过优化提示词、压缩历史记录、设置合理的max_tokens来降低。吞吐则是硬件决定的在不牺牲延迟的前提下尽量提高并发让单位成本摊薄到更多调用上。RAG成本里关键词是embedding和rerank调用的token消耗。一张文档库如果反复重新向量化成本会成倍增加。我的建议是采用增量索引只对新增和变更的文档重新向量化不变的文档直接复用。重排阶段也要控制候选数量Top50重排比Top100重排少一半的推理开销在效果差不多的情况下选Top50更经济。Agent的成本更惊人因为一个任务可能触发多轮模型调用。如果一轮任务平均要调用5次模型那单任务的成本就是5倍单次对话的成本。控制Agent成本最有效的办法是减少不必要的模型调用比如用规则引擎完成确定性流程对于可以固定的环节直接用代码写死只有真正需要决策的地方才交给模型。5.3 工程化代码示例一个推理接口的完整封装为了让你更直观地理解“能交付”的工程化长什么样我手写一个简化的推理服务封装示例包含并发控制、失败重试、超时处理和结构化响应。import json import time from typing import Any from openai import OpenAI class LLMService: def __init__(self, base_url: str, api_key: str dummy, timeout: float 60.0, max_retries: int 3) - None: self.client OpenAI(base_urlbase_url, api_keyapi_key) self.timeout timeout self.max_retries max_retries def generate(self, prompt: str, system_prompt: str | None, max_tokens: int, temperature: float 0.1) - dict[str, Any]: messages [] if system_prompt: messages.append({role: system, content: system_prompt}) messages.append({role: user, content: prompt}) last_error: Exception | None None for attempt in range(1, self.max_retries 1): start time.time() try: response self.client.chat.completions.create( modellocal-model, messagesmessages, max_tokensmax_tokens, temperaturetemperature, timeoutself.timeout, ) return { content: response.choices[0].message.content, total_tokens: response.usage.total_tokens, latency: round(time.time() - start, 3), attempt: attempt, retry_used: attempt 1, } except Exception as exc: last_error exc # 只有连接和超时类错误才值得重试 if not self._retryable(exc): break time.sleep(min(2 ** attempt, 8)) # 指数退避 raise RuntimeError(f模型调用失败: {last_error}) staticmethod def _retryable(exc: Exception) - bool: # 这里做简化判断实际应该根据异常类型精确区分 msg str(exc).lower() return any(key in msg for key in (timeout, connection, 5, 429))这段代码看起来简单但有三个设计点值得讲第一重试和超时放在一起处理。连接超时、上游5xx、限流429都值得重试但如果是参数错误4xx中没有429的部分重试多少次都不会成功反而会白白浪费时间和资源所以必须区分。第二响应里带上attempt和retry_used字段。这样你就能从监控里看到有多少请求是重试后才成功的如果重试比例突然变高说明服务健康状况下降该报警了。第三temperature默认设得很低。在业务场景里我并不需要模型发挥创造力而是要它稳定可复现。把默认temperature压到0.1到0.3之间比默认的0.7更合适。类似这样的工程细节在面试里只要你讲出来面试官就会觉得你是真的做过而不是背过。6. 关于准备和进阶一些实在的建议6.1 从项目经验反推学习清单如果你现在正准备投大模型岗位我建议你先别急着刷论文而是先想清楚我手上最拿得出手的项目能不能回答以下问题这个项目上线了吗线上规模多大QPS多少如果没上线为什么没上线卡在哪一步这个项目里最大的技术挑战是什么你怎么解决的如果让你重新做一遍你会在哪里换一种方案项目里哪些地方用了开源框架为什么选它哪些地方自研了这五个问题一个能都回答好的人和一个简历上写了“熟悉大模型应用开发”但什么都说不深的人面试表现完全是两回事。围绕你的主打项目把推理、RAG、Agent三个方向里的至少一个做深到可以回答任意追问另外两个能讲清楚设计思路和关键决策这个状态去面试主流的大模型应用岗位就是很有竞争力的。我认识的一位候选人学历普通但他自己做了一个完整的企业内部知识库问答系统用vLLM部署了13B模型做了BGE向量化和RAG链路最后用LangGraph套了一层权限校验的Agent。他把整个系统的架构图画得很清楚每一个模块为什么这么做、踩过什么坑、压测数据是多少都讲得非常具体。他拿到的offer数量比很多简历光鲜但项目空洞的候选人多得多。这个例子很能说明问题“能交付”这件事在面试里是可以被感知到的。6.2 动手做一个端到端项目最直接的路径如果一定要我给一条最快的成长路径那就是自己动手做一个端到端项目从零开始尽量不经手他人封装好的整包。我的推荐路线是找一个开源模型用vLLM部署成本地服务写一个比上一节的封装更完整的调用客户端。找一批业务文档比如产品手册或课程资料做一个完整的RAG系统加上混合检索和重排。给这个RAG系统套一层Agent能力让Agent能搜索知识库、能调用外部工具比如查天气或算加减法、能做多轮对话。架构上可以先用LangGraph画流程然后逐步把核心循环换成自研。所有服务都加上日志、监控、错误处理和性能压测。最后整理成一份技术报告这个报告本身就是你面试时最好的“作品集”。整个过程我建议你用个人云服务器或者本机显卡完成不用追求大模型规模7B或者13B的量级足够你掌握全部核心细节。模型大小不是重点工程细节才是。等这套小系统全部跑通、能稳定运行、出问题能快速定位了大模型岗位要求的“能交付”能力你基本就具备了。我现在带人做项目最强调的就是这个闭环部署一个模型→检查它的性能→检索到正确的文档→让模型依据文档正确地执行动作→整个过程可观测、可排查、可回滚。这条路走完你就不再是只会调包的人而是一个真正能交付大模型应用的人。
网站建设高端定制企业官网