公司动态
LLM角色重塑:从答案生成器到工具调度与RAG Agent实践
我在很长一段时间里对 LLM 的判断可能是错的。最早接触大语言模型时我把它误当成“更聪明的搜索框”输入问题返回一段看起来像人写的答案最多再结合上下文做点润色。真正开始做应用之后才发现这个定位完全支撑不起现实需求。你让 LLM 做知识库问答它会把错误信息说得理直气壮你让它按固定格式输出它偶尔会多出几个莫名其妙的字段你希望它去调用外部工具它根本没有手。更关键的是当 Agent、RAG、MCP 这类词开始频繁出现在项目里时我才意识到 LLM 在真实系统里扮演的从来不是“最终答案生成器”而更像一个调度枢纽、一个决策内核、一个能把工具、知识库和后续动作串起来的中间层。这轮认知更新是过去大半年里对我工作方式影响最大的一件事。这篇文章不想复述概念我想按实际做项目的顺序把 LLM 角色变化的起因、落地步骤、参数选择、部署边界和排查思路完整拆一遍。尤其是最近讨论比较多的 LLM wiki 范式、Agent 编排、Spring AI 这类框架组合我会把它们放回真实工程场景里说清楚它们到底解决了什么问题哪些地方容易被高估哪些坑我确实踩过。1. 我之前的理解为什么会错1.1 我最初把 LLM 当成“答案生成器”早期做产品原型时我的思路很单一把用户问题拼进 prompt调一次 LLM拿到文本后直接展示。那种模式在聊天机器人、文章总结、翻译工具里确实能跑通。只要 prompt 写得好输出质量就够看。但这个思路放在复杂业务里会出现明显断层。最典型的场景是私有知识库问答。我一开始以为只需要把相关文档片段塞进上下文让 LLM“读”完再回答。可问题很快暴露文档一多上下文塞不下即使能塞下模型也会把相似但无关的内容当成依据如果用户问到表格里的数据模型经常自己“推算出”一个看起来合理但完全不存在的数字。那时候我得出一个错误结论LLM 还不够强所以要等更强的模型。后来才发现问题不在模型强弱而在角色定位。我把它当成一个必须自己知道所有答案的“全知者”但现实里它不仅不知道还会自信地编。正确做法应该是让它当一个“会查资料、会调用工具、会按规则输出的工作人员”而不是让它硬背所有知识。1.2 现实情况LLM 更像调度器而不是知识容器真正改变我理解的是一个很朴素的项目经验。当时要做一套客服工单分类系统最初我让 LLM 直接读工单全文然后输出分类标签。效果不稳定标签偶尔重叠偶尔漏掉格式也不统一。后来我换了一个思路先让 LLM 看工单摘要再从预设的分类列表里选一个最后只输出一个 JSON 对象里面包含分类编号和置信度。这个改动看起来只是输出格式变了实际上是角色变了。LLM 不再负责“理解所有内容并给出最终答案”而是负责“理解当前情况在受限选项里做决策”。准确率立刻稳定很多后续接 RAG、接工具调用也顺理成章。这也是我后来理解 Karpathy 提出的 LLM wiki 范式时最有共鸣的地方。LLM wiki 的核心不是让模型把海量知识装进参数里而是把知识拆解成结构化的文档、卡片或条目再由 LLM 去检索、组织、调度。知识放在外部系统里LLM 负责定位和组合。这样一来模型的“记忆负担”大幅下降幻觉的空间也会被压缩因为每一次回答都能落到一个可追溯的条目上。所以我错在把 LLM 当成了知识容器。实际上它更接近操作系统的调度器接收目标拆解步骤决定该查什么、该调什么、该生成什么最后把各模块的结果拼装成用户需要的样子。2. 真实项目里 LLM 扮演的五个角色2.1 五种角色的典型技术组合当我重新盘点做过和接触过的项目后发现 LLM 在真实系统里基本能归成五类角色。不同角色对模型能力、参数配置、外部依赖的要求都不一样。角色解决什么问题典型技术组合判断标准文本生成器摘要、翻译、营销文案、报告起草prompt 基础模型输出可读、无明显事实错误、风格稳定知识路由私有知识库问答、资料检索RAG 向量库 嵌入模型召回内容准确、回答有引用来源工具调度器查询数据、调用接口、执行操作Function Calling / MCP Agent工具名正确、参数完整、执行结果可回填代码助手代码补全、脚本生成、报错解释代码模型 IDE 插件代码可运行、注释合理、不破坏上下文内容组织者资料整理、文档建联、知识卡片生成LLM wiki / 结构化输出条目可定位、链接可跳转、结构一致先说文本生成器。这是最容易上手也是定义最窄的角色。判断它做得好不好不看模型参数大不大而看输出能不能直接用。我一般会把输出要求写得极其具体包括字数、语气、是否允许 Markdown、是否需要列表否则后续处理会很痛苦。知识路由是目前最常见的企业应用方向。技术上绕不开 RAG先把文档切块做嵌入存进向量库用户提问时先检索相似内容再带着检索结果让 LLM 作答。这里最容易忽略的不是模型而是嵌入模型和向量库的配置。很多项目报错“文本向量 API 未配置”就是因为只配了对话模型没配 embedding 模型或者向量库索引没有建。工具调度器是 Agent 的核心。LLM 根据用户意图决定调用哪个工具、传入哪些参数再把工具返回的结果整理成最终回答。现在很多框架支持 MCPModel Context Protocol本质就是让 LLM 和外部工具之间有一套标准化接口。这个角色的难点不在“让 LLM 说人话”而在“让 LLM 准确表达动作”。代码助手和内容组织者我放在一起说。代码助手我已经不指望它能直接写出一整系统但它很适合做单函数生成、报错解释、重构建议。内容组织者是我最近很看好的方向典型做法就是把零散笔记交给 LLM 提炼成结构化条目再按主题建索引形成个人 wiki。这类项目不需要 GPU 集群甚至用 API 就够了但对输出稳定性要求很高。2.2 角色不同参数和验收标准也要变很多新手拿到一个 LLM 项目第一件事就是调温度temperature但角色不同参数的优先级完全不同。只做文本生成时温度可以适当高一点比如 0.7 到 0.9让句子更有变化。但做工具调度时温度必须降得很低我一般会控制在 0 到 0.2。因为工具调度不需要创造性需要稳定和可复现。如果温度太高同一个用户问题可能第一次调用“查询订单”第二次调用“删除订单”这在业务里是不可接受的。max_tokens 也要注意。如果只把 LLM 当调度器输出本来就很短像一段 JSON 或一个工具名那就没必要把 max_tokens 设成 4096。设得太大反而可能让模型输出冗余内容增加解析失败的概率。做 RAG 时还要额外关注上下文长度和召回数量不是召回越多越好召回太多反而会把无关信息喂给模型。验收标准也要换。判断一个对话模型好不好可以看回答是否通顺但判断一个工具调度模型好不好要看输出能否被程序解析、工具名是否正确、参数是否完整、失败后能不能重试。换句话说文本生成的验收标准是“人看着舒服”工具调度的验收标准是“程序能跑通”。3. 从“问答接口”到“工具路由器”的改造步骤3.1 最小可运行流程想把 LLM 从文本生成器改造成工具路由器不需要一上来就搭全套 Agent 框架。我建议先跑一个最小流程验证三件事模型支持不稳定输出、程序能解析输出、解析后的动作能执行。下面是一个示意流程。假设用户要求抓取一个网页并总结成要点我们希望 LLM 不要直接假装抓到了网页而是先返回一个“抓取网页”的动作。# 示意代码依赖以实际项目为准 messages [ {role: system, content: 你是任务调度器。请从工具列表中选择合适的工具并返回 JSON。}, {role: user, content: 把 https://example.com 的内容抓取下来总结成三条要点} ] resp llm_client.chat(messages) action json.loads(resp.content) # action 可能是这样的结构 # {tool: fetch_url, params: {url: https://example.com}, next: summarize} print(action)这段代码的重点不是具体调用哪个 SDK而是让 LLM 输出一个“动作描述”不是输出最终答案。拿到动作之后程序再去执行真正的网页抓取。抓取完成再把网页文本塞回给 LLM让它做总结。这样 LLM 就不需要假装知道网页内容只需要完成“决策抓取动作”和“总结已有文本”这两件事。如果你用的模型支持 Function Calling那更好可以直接按官方协议声明工具。如果不支持就在 system prompt 里给出工具列表、参数说明和 JSON 样例。只要模型的输出足够稳定这种“提示词约束”的方式也能跑通。但要注意如果模型没有经过工具调用训练即使提示词写得再细也可能输出非法 JSON。遇到这种情况先换一个支持函数调用的模型比反复调 prompt 更有效。3.2 单条任务怎么验证我把首次接入工具调用的验证拆成了四步每步都有明确的成功标准。第一步验证基础对话。给模型发一个最简单的消息确认 API Key、模型名称、网络连通性都正常。这一步如果失败后面所有工作都白搭。第二步验证 JSON 输出。让模型生成一段固定结构的 JSON比如包含“tool”和“params”两个字段。成功标准是json.loads能直接解析不需要人工修正。第三步验证工具执行。从模型返回的 JSON 中取出工具名和参数在真实环境里调用一次。比如调用抓取网页接口确认能拿到 HTTP 响应和正文内容。第四步验证结果回填。把工具执行结果传回给模型让模型基于真实结果生成最终答案。这一步能有效降低幻觉因为模型不再需要“猜”网页内容。这四步全部跑通后才算完成了一个最基础的工具路由闭环。我通常会把这个闭环写成一个函数后续所有任务都走同一个入口。3.3 为什么不建议直接上并发很多人在演示环境里跑通一次马上就想上并发。我的建议是别急。工具路由和普通文本生成的差异在于普通文本生成失败最多就是回答烂一点工具路由失败可能真的会误调接口、误传参数、误删数据。先跑单条任务观察完整链路的时间消耗。然后再加一条带特殊字符的输入确认 JSON 解析不会崩。再试试工具返回异常时模型能不能感知到。比如网页抓取返回 404模型应该告诉用户“页面不存在”而不是假装抓取成功。这一步不做并发越高错误越规模化。3.4 接入 MCP 和 RAG 的顺序如果项目需要更复杂的工具生态可以考虑 MCP。它把工具描述和调用方式标准化让不同的 LLM 应用可以共用同一套工具服务。我的接入顺序一般是先手工定义工具函数跑通路由闭环再把这套工具改成 MCP Server最后再让应用通过 MCP Client 连接。这样一旦出问题你能判断是业务逻辑问题还是协议实现问题。RAG 的接入顺序则可以放在工具路由之后。先用 LLM 判断用户问题是否需要查资料如果需要再调用检索工具把召回的文本交给 LLM 生成答案。把 RAG 看成一个“外部工具”会让架构清晰很多也不会每轮对话都触发向量检索节省成本和时间。4. 精度、部署与硬件边界4.1 精度选择fp16、fp32、bf16 怎么理解本地跑模型时绕不开精度问题。很多资料里看到 fp16、fp32、bf16容易被绕晕。简单说它们代表模型参数保存时的数值类型不同精度会直接影响显存占用、计算速度和生成质量。fp32 是单精度信息保留最完整但占用最大。fp16 是半精度占用少一半速度通常更快但在某些数值范围上容易丢失细节。bf16 也用半精度但指数范围和 fp32 更接近所以在大模型场景里更常用尤其适合训练和推理。很多人说 bf16 比 fp16 更稳原因就在这里。不过具体使用哪种精度要看你的硬件驱动和框架支不支持。有些显卡对 fp16 支持很好对 bf16 支持一般。我的建议是先查两份资料一是模型卡说明二是推理框架的文档不要只看网上结论。低精度不是“有损压缩”的绝对坏事很多时候生成质量差别很小但显存占用差距很大。如果显存不够优先尝试 8 位或 4 位量化而不是一直和精度死磕。4.2 ComfyUI 与 LLM 要不要放同一台电脑这是搜索里出现频率很高的问题来自一个很实际的使用场景一个人既要跑 ComfyUI 做图像生成又要跑 LLM 做文本推理但机器只有一张显卡不知道该怎么分配。答案很直接不一定非要同一台电脑。ComfyUI 核心是图像生成模型LLM 核心是文本生成模型两者资源需求完全不同。如果你的显卡只有 8G 显存同时在本地跑一个较大的图像模型和一个较大的 LLM大概率会内存溢出或卡死。有两种常见解法。第一种错开任务。同一台机器图像任务和文本任务不要同时跑。跑 ComfyUI 时LLM 走远端 API跑 LLM 时先关掉 ComfyUI。这种方式适合学习和小规模使用。第二种分工。ComfyUI 放在有 NVIDIA 显卡的 Windows 或 Linux 机器LLM 放在另一台 Mac 或云服务器。通过 API 调用连接这样两边可以同时工作互不干扰。需要注意的是这种方案需要自己管理网络调用、API 地址和并发不是零成本。如果你的机器配置很高比如 24G 以上显存当然可以在同一台机器上跑 ComfyUI 和一个小参数 LLM。但无论如何先看显存占满会怎样再看任务类型。图像生成经常吃满显存文本推理瞬时内存也高两者叠加极不稳定。4.3 Mac 本地推理引擎怎么选Mac 用户想跑 LLM通常会问选哪个推理引擎。这个问题不能一概而论但判断标准是固定的模型格式兼容性、是否支持 Metal、量化支持、上下文长度处理能力。很多 Mac 本地推理工具本质是调 llama.cpp 或其分支支持 GGUF 格式模型。只要把模型转成 GGUF 或用别人转好的 GGUF 文件大多数都能跑。选择引擎时我建议先看官方文档里是否明确提到自家芯片支持列表。苹果芯片的内存带宽很高跑 LLM 有天然优势但不能只看总内存。一个 32G 统一内存的 Mac能跑的模型规模大约是 14B 到 34B 的量化版具体要看模型结构、量化位数和上下文长度。不要光看“推荐某某引擎”的结论。正确的做法是拿你计划部署的模型分别用两个引擎跑同一条推理请求对比三样东西首 token 延迟、生成速度和内存占用。文本推理没有绝对的最优引擎只有最适合你模型格式和硬件条件的引擎。4.4 什么时候果断用 API本地部署最大的优点是数据不出本机离线也能用长期不一定比 API 贵。但它也有明显代价硬件维护、模型更新、依赖兼容、并发规划都要自己管。如果只是做应用开发、拼业务原型或者团队只有一两个人不建议前期就投入大量精力做本地部署。先用成熟的模型 API 把流程跑通成本更可控速度也更快。等到你确认了模型类型、推理频率和业务指标再评估是否要本地部署。很多团队一上来就想“私有化部署一个开源模型”最后卡在显存不够、推理太慢、精度对不齐这些问题上反而拖慢进度。5. 新范式下最容易踩的坑和排查顺序5.1 按现象排查工具调用类和 RAG 类项目常见问题是有共性的。我总结成一张排查表。现象优先排查方向常见原因LLM 返回内容无法解析先看输出格式提示词没有给出明确的 JSON 示例或模型不支持函数调用工具调用总是选错检查工具描述和参数命名工具描述太模糊或两个工具功能太接近工具执行成功但答案不对检查结果回填只把工具结果放在 response 里没有作为上下文传给模型RAG 召回内容为空检查向量 API 和索引嵌入模型未配置或文档没有切块RAG 召回了但不相关检查切块大小和检索 top_k切块太大语义被稀释或 top_k 设置过多Agent 反复调用同一工具检查终止条件缺少最大轮数限制或模型没有得到最终结果判断依据本地推理内存不够检查量化参数和上下文长度模型位数太高或上下文设得太大5.2 Agent 与编排框架的边界现在很多人一提到 LLM 应用就想到 Agent。但 Agent 不是银弹。它适合的是需要多步决策、需要工具调用、需要把外部系统结果回传的任务。而简单的“问题转答案”场景直接调用模型反而更稳定。编排框架如 Spring AI、LangChain 这类工具解决的核心问题有三件屏蔽不同模型 API 的差异、管理多步任务的上下文、提供 RAG 和 Agent 的常用组件。项目里要不要上框架取决于你要自己控制多少细节。如果你只是调用文本生成接口框架是多余的。如果要把 Spring AI、MCP、RAG、Agent、Skill 组合到同一个业务系统里框架能少写很多胶水代码但也意味着你需要理解它的抽象方式、配置项和版本兼容。我见过最多的问题不是框架不会用而是把框架当黑盒。项目跑起来后出现“输入了问题但 Agent 没有任何动作”排查半天才发现是某个配置项没打开比如工具列表没注册或者向量 API 的地址写错。所以使用任何编排框架第一件事是搞清楚它的关键配置项在哪里尤其是模型地址、工具列表、向量库连接和超时时间。5.3 从单条任务到批量任务的四道关单条任务跑通后不要直接写 for 循环批量跑。批量任务和单条任务是不同量级的问题。第一关是输入归一化。批量数据里可能混入空值、超长文本、错误编码。在进入 LLM 之前先做清洗和格式校验。否则某一条异常输入可能导致整批任务失败。第二关是输出命名。每条任务结果要能对应回输入。建议在请求里带上业务 ID并把业务 ID 放入日志和输出文件命名。不要只按时间戳命名不然出错了根本不知道是哪条数据。第三关是失败重试。LLM 接口可能因为限流、网络抖动、模型服务过载而报错。批量任务要有重试策略比如重试 3 次每次间隔递增。还要注意幂等性同一个任务重试多次不应该是重复执行多次工具操作否则可能产生副作用。第四关是并发控制。并发不是越大越好。开太大接口会被限流本地推理会内存不足。先测一条请求的延迟和资源消耗再决定并发数。建议从小并发开始观察稳定后逐步上调。不要一上来就开 32、64 并发那几乎一定会翻车。6. 最后一点反思6.1 不再问“模型能生成什么”而是问“模型能不能稳定执行动作”这几天我在写新项目时已经完全换了一套提问方式。以前我会问“这个模型能写出高质量文章吗”现在我更关心“给它一个明确的动作列表它能不能稳定输出对应的 JSON如果第一次输出不对重试一次能不能纠正”这个转变让 LLM 的定位落到了实处。它不再是产品里最显眼的“大脑”而是整个流程中的一个处理节点。它负责理解、决策和调度但真正执行动作的是业务代码、外部工具、数据库和知识库。你需要把它当做一个能力边界清晰、输出可能不稳定的组件来设计。所有关键路径都要有校验、重试和兜底。如果你问我未来 LLM 会扮演什么角色我现在的答案是它会越来越像系统里的“统一交互层”。用户不需要记住工具叫什么不需要自己拼参数只要描述目标LLM 负责把它翻译成动作序列再交给后端执行。至于执行结果再由 LLM 整理回人类可读的样子。这个模式对文本、代码、图像、音频都成立。6.2 给新手的项目启动顺序如果你正准备把一个 LLM 想法变成项目我建议按照下面的顺序走能少踩很多坑。第一先定义 LLM 的角色。它在这个项目里是文本生成器、知识路由、工具调度器还是内容组织者角色定义不清楚后面所有参数和架构都会乱。第二先跑最小闭环。用最简单的本地脚本调一次模型拿到结果完成一个判断或动作。不要一开始就接 Multi-Agent不要同时配三个框架。第三再补外部依赖。需要知识库就接 RAG需要工具就接 Function Calling 或 MCP需要长流程再加编排框架。每加一个依赖都要单独验证。第四最后再讨论部署和精度。本地还是 API、fp16 还是量化、要不要两台电脑都放到业务逻辑基本稳定之后再看。过早优化部署只会分散注意力。我在这个过程中最大的教训就是不要用“模型能力”来掩盖“架构问题”。很多时候任务做不好不是因为模型太笨而是因为把不该给模型的任务交给了它。LLM 最擅长的是理解意图、做取舍、组织语言和决策而不是替你把所有业务逻辑都记住。把这个边界想清楚项目推进会稳很多。踩过几次坑之后我最大的变化是不再纠结“这个模型聪明不聪明”而是先问“这个任务到底应该由谁负责”。LLM 的作用是让越来越多的事情变得不再需要人肉翻译和手工调度。但在那之前我们得先把它放对位置。