
周五晚上十一点一台运行中的 Agent 调度队列开始堆积。远端推理服务的响应时间从 1.8 秒涨到 14 秒再到请求超时。监控面板上30 个任务卡在同一阶段等待模型输出。你能做的只有取消任务或者继续等。这种体验在把 Agent 从实验阶段推向生产流程时几乎每个人都会遇到。问题不是模型能力不够而是推理这一层完全不在你手里。Self-Hosted Inference也就是自托管推理表面看只是把模型从服务商的机房搬到自己的主机上实际上它改变的是整条 Agent 工作流的可控性——延迟、数据边界、失败策略、上下文策略、成本结构全部从依赖外部服务商的状态变成由你决定。先说我的判断自托管推理的真正价值不是省推理费用也不是为了让你的履历里多一个模型部署项目。它真正的价值是让你把 Agent 当作自己的软件系统去调试、观察和维护。在托管 API 时代你买到的是模型能力在自托管时代你买到的是对模型调用方式的控制权。研究社区里讨论的 self-improving agents 听起来很好但很多生产 Agent 真正卡住的地方恰恰是推理层的抖动、超时和不可观测。1. 先想清楚Agent 需要的不是“模型”而是一条可控制的推理链路1.1 从一次线上排队说起单个模型调用很快不代表一个 Agent 任务很快。托管 API 在单次对话场景下体验很好你发一条消息模型返回一条回复延迟一秒钟还是三秒钟用户能接受。但 Agent 不一样。一个 Agent 任务往往是“任务拆解 → 调用工具 → 读取工具结果 → 生成下一步 → 再调用工具 → 最终回答”的循环。每一次箭头都是一次模型调用。算一笔简单的账一个任务需要 10 次模型调用单次调用平均 3 秒那这个任务至少需要 30 秒。如果同时有 10 个任务在跑而推理服务一次只能处理 4 个并发请求队列就会开始积压。托管 API 不是不能处理并发问题是你看不到它的调度策略。你只知道请求发出去之后要么成功要么超时。当远端服务出现抖动你的 Agent 任务会成片卡在“等待模型输出”的状态而你能做的只是在客户端加重试和超时拿不到服务端内部的队列长度和批处理情况。自托管推理改变了这个局面。模型跑在自己的机器上队列、批处理、并发上限、超时策略都由你控制。哪怕调度逻辑写得再粗糙至少你可以看到问题发生在哪一层而不是对着一个黑盒猜。1.2 为什么自托管会成为智能体工程的分岔点托管 API 起步快这是事实。你把一个 key 配好调一个接口就能完成原型验证。但当 Agent 从“偶尔跑一次”变成“每天处理几百个任务”时推理这一层的约束就会放大。第一个约束是数据边界。Agent 流程里模型会看到你的系统提示词、用户请求、工具返回结果甚至可能是数据库查询结果或内部文档。如果你对这些数据是否离开内网有要求托管 API 就变成了一项需要走合规评估的决策。自托管不等于默认安全但它至少把“数据是否出网”这个问题的主动权放回你手里。第二个约束是延迟。Agent 决策是序列化的每一步都要等前一步完成。多一跳外部网络就会多一段不可控的尾部延迟。本地推理可以把网络耗时压到很低并且你可以在日志里看到每一步的耗时分布。第三个约束是失败控制。一个任务有 10 次模型调用如果单次调用有 1% 的失败率整个任务就有大约 10% 的概率失败。托管 API 只提供请求级别的重试而本地推理可以做到步骤级别的重试、优先级队列、任务取消甚至把失败的 Agent 状态保存下来之后从断点继续。所以自托管并不是一个“更好的 API”它是一条你可以干预、拆分、观测的推理链路。这也是我把自托管推理和 Agent 工程放到一起讨论的原因。2. 聊天模型和 Agent“大脑”的推理要求根本不是一回事2.1 最小可用的 Agent 循环模型先给一个最简化的 Agent 循环用户任务 → 模型生成下一步计划 → 调用工具代码执行 / 查询接口 / 读写文件 → 把工具结果返回给模型 → 模型判断任务是否完成 → 未完成则继续生成下一步 → 完成后输出最终结果这里每一次模型的生成都是在做一次决策而不只是生成一段文字。这就带来一个容易被忽略的问题Agent 流程里上下文是不断累积的。工具结果会追加到对话历史里模型每一次决策都要基于前面的所有内容。这让推理请求比普通聊天更长、更复杂。如果你把一个聊天模型的部署方式原样搬到 Agent 场景很可能会发现单条对话很正常但跑多轮工具调用时响应变慢、输出格式不稳定、上下文被截断。聊天场景关心“回答得好不好”Agent 场景更关心“决策得稳不稳”。这是两套不同的评价标准。2.2 函数调用和结构化输出是硬指标传统聊天模型擅长生成自然语言但 Agent 需要模型输出能被程序解析的结构尤其是工具调用参数。很多开源模型在宣传时都会说支持 function calling但实际使用中要打一个问号。有的模型能输出一段像 JSON 的文本但字段名和定义不完全一致有的模型在单轮工具调用时很稳定但连续调用多个工具后就开始漏参数。这些差异在聊天场景里几乎感觉不到在 Agent 流程里却是致命问题。自托管时你需要确认两件事模型本身对工具调用指令的遵循能力。推理引擎是否支持在生成时约束输出为合法 JSON 或 JSON Schema。如果推理引擎支持这种结构化输出约束Agent 的稳定性会明显提升。因为模型不再“自由发挥”输出格式而是只能生成符合你定义的参数结构。这比单纯依赖模型指令遵循能力要可靠得多。建议在正式接入前做一个小样本测试准备 3 到 4 个工具定义用 20 条接近真实场景的指令逐条跑一遍统计“模型输出的工具调用能否被正确解析”的比率。如果低于 90% 到 95%要么调整模型要么调整引擎配置要么加一层输出修复逻辑。不要等到线上任务跑挂了再回头查。2.3 上下文管理不能只靠模型的长上下文现在很多模型宣传超大上下文窗口仿佛一万甚至十万 token 都不在话下。但 Agent 场景里Token 增长的速度往往超出预期。工具一次返回一份数据库查询结果可能就是几千 token代码执行输出一段日志又是几千 token几步下来上下文很快被撑满。长上下文不仅增加显存占用还会让生成速度下降。更麻烦的是模型对长上下文中间部分的注意力往往不如开头和结尾任务早期的关键信息可能会被淹没。自托管推理给你提供了控制上下文的机会。你可以设置模型的最大输入长度可以决定哪些历史消息保留、哪些被压缩成摘要、哪些移入向量检索。这样推理服务接收的上下文是经过管理的而不是无脑把所有内容往模型里塞。这里需要纠正一个误区长上下文不是让你不做记忆管理的理由。恰恰因为 Agent 会长期运行上下文策略才必须提前设计。2.4 中断、重试和并发调度本地推理要自己设计Agent 任务不总是能一口气跑完。有些任务需要人工审批有些任务运行到一半发现工具结果异常需要暂停或中止。在托管 API 场景里你能做的通常只是“发起一次请求等待返回超时则作废”。你很难在服务端真正停止一次生成。自托管推理改变的是这一层。你可以设计一个任务队列Agent 任务在队列里可以被取消、暂停、升级优先级。当任务被中断时推理服务可以立刻停止当前生成释放 GPU 资源并把对话状态保存下来等人工确认后再继续。多 Agent 并发时也一样。如果同时运行多个 Agent你需要“高优先级任务先跑”和“低优先级任务排队”的策略。托管 API 能给你的是分区限流本地推理则可以让你按业务规则动态调整。这里属于进阶设计第一版不一定做但提前知道有这个空间会让你的架构选择更合理。3. 一个最小可复用的自托管推理落地路径3.1 从单机 GPU 开始先跑通最小闭环自托管推理的第一步不是追求多强的模型而是尽可能在一台机器上把最小闭环跑通。先看你有什么硬件。单张 GPU 显存 24GB 是很常见的起点可以从 7B 或 14B 量级的开源模型开始再按需做量化。不要一上来就尝试 70B 甚至更大尺寸的模型。先把“模型能加载、能回答、能调用工具”这件事跑通比什么都重要。常见的启动方式是直接跑一个提供 OpenAI 兼容接口的高吞吐推理服务。这样你的 Agent 框架不需要改动太多就能从原来的托管 API 切换到本地端点。# 常见的高吞吐推理服务启动方式示例结构 python -m vllm.entrypoints.openai.api_server \ --model /path/to/local-model \ --served-model-name local-agent-model \ --host 0.0.0.0 \ --port 8000启动后先用一条普通消息验证模型可以正常返回再发一条带工具定义的请求确认函数调用能被引擎解析。这一步如果过不去后续一切优化都无从谈起。3.2 推理引擎选型先看吞吐再看功能自托管推理不是只有一种部署方式。常见的路径大致分两类。一类是面向高吞吐的 GPU 服务引擎代表方向是 vLLM、TGI 这类工具。这类引擎擅长处理并发请求内部有连续批处理、前缀缓存、Paged Attention 等优化适合在后台同时跑多个 Agent 任务。如果你的 Agent 系统会持续产生大量推理请求这类引擎通常是更合适的选择。另一类是轻量级本地运行时比如 llama.cpp 这一方向。它资源占用更低也可以 CPU 和 GPU 混合跑方便在单机、边缘设备或开发机上验证思路。它更适合“模型不大、并发不高、想快速看到效果”的起步阶段。选型时不一定要在一棵树上吊死。可以先在轻量运行时上验证模型效果再把同一个模型迁到高吞吐引擎上跑压力测试。关键在于确认引擎是否支持你需要的两个能力工具调用或 JSON 输出约束以及前缀缓存。前缀缓存对 Agent 尤其有用因为同一个 Agent 任务的多次推理调用会共享系统提示词和历史对话前缀缓存命中后能显著减少重复计算。3.3 OpenAI 兼容接口让现有 Agent 框架无缝切换Agent 框架通常只需要一个 BaseURL 和一个 API Key 就能连接模型服务。自托管推理服务如果暴露的是 OpenAI 兼容接口就可以做到无缝切换。from openai import OpenAI client OpenAI( base_urlhttp://127.0.0.1:8000/v1, api_keylocal-not-required, ) response client.chat.completions.create( modellocal-agent-model, messages[{role: user, content: 查一下今天的订单量}], tools[ { type: function, function: { name: query_order_count, description: 查询指定日期订单量, parameters: { type: object, properties: { date: {type: string, description: 日期格式 YYYY-MM-DD} }, required: [date], }, }, } ], ) print(response.choices[0].message)这段代码只是一个示例结构实际项目中可以根据你的工具定义调整。接入之后Agent 框架原来依赖托管 API 的逻辑基本不用重写只需要确认三个点工具调用格式是否一致、返回内容是否可解析、超时设置是否合理。不要因为接口长得像 OpenAI就默认行为也完全一样。不同引擎对tools参数的支持程度不同有的会严格约束输出有的只是把工具定义放在提示词里。你必须用真实任务跑一遍确认模型真的按照工具调用格式输出了结果。3.4 用一条任务样本验证四个指标本地推理服务启动后先不要急着调大量任务。取一条真实的 Agent 任务记录四个指标。指标含义为什么重要首 token 延迟请求发出到第一个 token 返回的时间影响任务反馈速度和整体排队时间单步总耗时一次模型调用从开始到结束的时间决定单个 Agent 任务的总时长工具调用解析成功率模型输出能否被解析成合法工具参数决定 Agent 是否真正能调用工具上下文截断率对话记录被截断或触发长度限制的比例长流程任务必须重点观察一个任务样本可能不够更稳妥的做法是先跑 10 条不同场景的任务把上面四个指标记录下来。如果工具调用解析成功率很低先排查是不是模型版本或引擎配置问题如果上下文截断率高就去调整上下文管理策略而不是一味加大模型最大长度。这一步做的不是“调参数”而是给你的 Agent 建立一套可量化的验收基线。后续切换模型、升级引擎、修改提示词都可以拿这套基线来做对照。4. 本地推理最容易忽略的不是显存而是运维工程4.1 单点 GPU 不等于高可用很多人把模型部署到一台 GPU 服务器上就觉得自托管完成了。实际上从这一天开始你多了一个需要 7×24 小时维护的在线服务。GPU 服务器会碰到驱动问题、显存耗尽、磁盘满、模型文件损坏、断电重启。任何一个问题都会让你的 Agent 任务中断。如果这是唯一一条推理链路所有任务都会跟着失败。所以自托管推理不建议一开始就做成“只此一条路”。至少要有一个降级方案可以是另一台机器上的小模型也可以是回到托管 API 的备用通道。健康检查、自动重启、日志采集这些基础能力要在第一天就规划进去而不是等出了问题再补。4.2 日志和可观测性要按 Agent 步骤来做托管 API 能给你请求日志但 Agent 需要的是步骤级日志。你要能看到一个任务里模型每一步生成了什么、调用了哪个工具、工具返回了什么、接下来为什么选择这一步。本地推理让你有条件把这些细节完整记录下来。每一条日志可以包含任务 ID、步骤号、调用类型、输入 token 数、输出 token 数、耗时、工具名、工具结果摘要。{ task_id: order-report-123, step: 3, type: tool_call, model: local-agent-model, input_tokens: 1240, output_tokens: 180, latency_ms: 2300, tool_name: query_order_count, tool_action_summary: date2025-01-06, tool_result_summary: count128 }有了这些日志出问题最快的方式就是按 task_id 把整个任务重放一遍而不是靠猜。托管 API 很难给你这种体验。4.3 模型更新必须配评估集模型更新在聊天场景里可能很简单新模型出来了试几条对话感觉不错就换了。但在 Agent 场景里这个流程非常危险。模型换版本后工具调用的输出格式可能变化拒绝回答的行为可能变化对一个长上下文的处理方式可能变化。你可能只换了一个权重文件却让原本能跑通的 Agent 流程突然开始产生大量解析失败。建议维护一个小型评估集包含 20 条左右真实任务每条都定义明确的通过条件。任何模型更新后先跑一遍评估集再决定是否切流。这个评估集不需要很复杂但必须覆盖工具调用、多轮对话、长上下文、失败恢复这几类典型场景。它能帮你避免“新模型感觉更聪明但 Agent 流程反而更不稳定”的尴尬。4.4 内部服务的暴露面要控制自托管推理服务一旦跑起来就是一个内部服务。要明确它能被哪些机器访问不能被谁访问。常见做法是把推理服务放在内网用 API Key 做调用鉴权限制请求体大小对工具执行环境做权限隔离。尤其要注意如果你的 Agent 能调用代码执行类工具模型输出本身就可能被提示词注入生成一些危险的指令。自托管不等于安全它只是把安全责任从服务商转移到了你身上。越早意识到这一点越少踩坑。5. 什么时候别自托管边界比热情更重要5.1 适合自托管和暂时不适合的场景自托管推理有非常明确的适用边界不是所有场景都该先上本地部署。场景是否适合自托管原因数据敏感不允许出内网适合数据边界可控Agent 任务高频、长流程适合延迟和成本可优化需要定制工具调用和上下文策略适合服务层可调快速原型验证不一定托管 API 起步更快业务依赖最新最强模型且无开源替代不适合模型能力差距可能成为瓶颈团队没有推理运维经验谨慎需要补日志、监控、更新和评估如果你的团队只有一个人且主要目标是验证 Agent 思路那么托管 API 往往更合适。自托管推理的运维成本是真实存在的不是只装一个推理引擎就行了。5.2 混合调度是更务实的生产模式“要么全自托管要么全托管”并不是唯一选择。很多生产系统会做一层路由根据任务类型决定请求走哪条链路。敏感任务走本地模型一般任务走托管 API低峰期用本地模型省钱高峰期切到托管 API 防排队需要最强能力时走大模型常规任务用小模型。这种混合模式在工程上更稳定也不会让你一次承担过多运维负担。但要注意引入路由层本身也增加了复杂度。你需要监控两条链路的响应时间、成功率和成本还要设计好切换规则避免“本地超时后切到托管托管也超时最后整个任务失败”的连锁问题。5.3 判断标准你要的是功能还是控制力一个很简单的判断问题你的 Agent 流程现在有没有遇到“推理层不可控”带来的问题如果只是觉得“自托管听起来很专业”或者“不用托管 API 会更酷”那建议先不要动手。如果现在的 Agent 任务经常因为外部服务抖动而失败如果你确实不能把某些数据送到外部接口如果你需要对上下文管理和工具调用做深度定制那么自托管是有价值的。这也是整篇文章最想表达的主判断自托管推理要解决的问题是控制力问题不是模型能力问题。它的价值不在于把模型放到自己的机器上而在于让整个 Agent 工作流变得可调试、可干预、可长期维护。6. 最后先画出你的 Agent 主循环再决定推理放在哪里6.1 从一次真实任务的计算开始如果你还在犹豫要不要自托管我建议先做一件事找一个真实的 Agent 任务把每一次模型调用的输入、输出、延迟全部打印出来数一数总共有多少次模型调用累积了多少 token中间是否出现过长上下文。如果这个任务只有一次模型调用托管 API 完全够用。如果它有 8 次、15 次并且过程中还有工具输出和上下文累积那你很快就会发现推理层的不确定性会被任务循环放大。这时候“推理层可控”就不再是加分项而是必需品。6.2 推理层的控制权是要靠工程拿回来的自托管推理不是一个硬件购置问题它是一组工程决策选模型、选引擎、设计上下文管理、写日志、做评估、配合调度。它会占用你相当多的时间但这些投入换来的是当 Agent 出现问题你能看到原因而不是只能对着外部服务商的限流和超时叹气。先画出主循环再决定推理放在哪里。对当前阶段的你来说最值得做的不是盲目追求更大模型也不是立刻迁移所有流量而是先让一个真实任务在你的可控环境里完整跑通再逐步把控制权拿回来。