从Python到Rust:AI Agent框架SkillLite的性能优化实战
发布时间:2026/9/10 6:20:04 作者:尧图编辑部 阅读量:1,286

SkillLite 这个项目最早压根不是 Rust 写的。它最初的形态是一套 Python 实现的 Agent 技能编排框架目标是把工具调用、API 封装、Prompt 模版统一成可复用的 Skill让上层 Agent 通过函数调用function calling动态加载和执行技能。当时选 Python 的理由和大多数团队一模一样生态成熟、上手快LangChain/LangGraph 那套思路能直接抄作业更重要的是——团队里没有任何一个人写过 Rust。转折发生在线上接入的会话量逐步上来之后。Agent 运行时不像普通 Web 服务那样请求来、响应走就结束了它要维护会话上下文、串联多轮工具调用、处理 LLM 返回的流式输出还要在任务中途响应外部取消请求。Python 版本在这些场景下暴露的瓶颈越来越明显冷启动太慢、内存占用高、GIL 把并发上限卡死。于是我们做了一个在当时的团队里争议极大的决定用 Rust 重写核心运行时最终完成了约五万行代码的替换。这篇文章不是要证明Rust 比 Python 好这种口水命题而是想把 SkillLite 从 Python 到 Rust 的整个决策过程、架构设计、性能数据和踩坑经历完整记录下来。如果你正在做 AI Agent 框架选型或者团队正在犹豫要不要把一部分 Python 服务换成 Rust这篇文章应该能给你一些参考。1. 为什么要动这刀AI Agent 运行时比其他后端服务更吃性能1.1 Agent 运行时到底和普通 Web 服务有什么不一样很多人觉得 Agent 服务也是接 HTTP 请求、调 LLM、返回结果性能压力全在模型推理上本地代码优化没什么必要。这个想法在 demo 阶段是对的但一旦接入真实业务情况就完全不同了。普通 Web 服务是无状态的请求处理完就释放资源最多用 Redis 存一下 session。Agent 运行时必须把会话状态、工具调用栈、中间产物、用户偏好这些数据一直挂在内存里。一个复杂的多轮 Agent 任务可能要做 5 到 10 次工具调用中间还穿插 LLM 的多次往返。每做一次函数调用就要做参数解析、权限校验、技能分发、结果收集、上下文拼接这些全是计算密集的小操作。Python 版本的 SkillLite 把这些操作串在一个 asyncio 事件循环里。单线程跑起来问题不大但一旦 Session 数量上来每个 Session 都是独立任务事件循环里同时挂着几百个协程Python 的解释器开销、对象创建开销、GIL 切换开销就全部变成了延迟。最难受的是asyncio 的取消机制对 Agent 任务支持非常差一个工具调用正在执行时外部要取消整个任务链经常出现取消信号丢失或者协程泄漏。1.2 SkillLite Python 版本的量化瓶颈我们的业务主要是给企业内部的客服、数据分析助手提供 Agent 能力高峰期并发会话在 200 到 300 个左右。按道理这个量级不算夸张但实测数据很打脸指标Python 版表现业务容忍度服务冷启动新容器拉起800ms 到 1.5s小于 200ms单次函数调用 P95 延迟12ms 到 30ms小于 5ms300 并发会话时内存占用2.1GB小于 1GB频繁创建/销毁 Session 时的 OOM 频率每周 2 到 3 次零容忍最让人头疼的是内存。Python 对象模型在大量小对象频繁创建销毁时内存碎片和 GC 停顿都会被放大。Agent 任务里到处都是字典、列表、字符串切片Python 解释器为了维持灵活的动态类型每个对象都带一坨类型信息和引用计数。300 个会话跑一个小时内存占用能从 800MB 涨到 2GB然后崩溃。冷启动问题也很致命。我们当时想把 Agent 能力部署到边缘节点做到近端推理、就近响应但 Python 版本的启动时间直接把这条路堵死了。容器每次扩容都要拉模型配置、加载技能注册表、初始化连接池800ms 起步的延迟根本满足不了毫秒级弹性的要求。真正让我们下决心重写的是 Agent 的一次线上故障。某个凌晨的流量高峰一个会话任务链里有 3 个技能并行执行asyncio 事件循环里出现了一个死锁所有协程全部挂起。服务看起来还活着健康检查也过了但所有请求都在等一个永远等不到的信号。三小时后值班同学才发现问题手动重启才恢复。这种问题在 Python 里几乎无法根治只能通过超时机制缓解。我们那时候才意识到Agent 运行时需要的不是写起来方便而是行为和性能都可预测。2. 选型不是Rust 好这么简单Go、C 和 Rust 三方对比2.1 为什么第一个排除了 GoSkillLite 要重写时Go 是最先被讨论的候选。社区里很多人觉得 Go 和 Rust 都是高并发后端语言选哪个差别不大。但我当时在技术评审会上直接说Go 解决不了我们的核心问题。Go 的优点确实明确goroutine 并发模型简单部署也方便静态编译出单一二进制。但 Go 最大的短板是自动垃圾回收。GC 在低延迟场景下表现不稳定虽然 Go 的 GC 一直在优化但 STWStop The World停顿还是时不时发生。Agent 运行时里有大量小对象频繁创建GC 压力会非常大。我们做过一个简单的压力测试模拟 1000 个并发协程反复创建和销毁 map、sliceGo 的 P99 延迟会出现周期性尖刺尖刺时间和 GC 周期高度相关。另外Go 的类型系统对状态建模的表达力有限。SkillLite 要处理技能定义技能执行结果Agent 状态快照这些复杂数据模型Go 的 interface 加 struct 组合虽然能用但表达起来很啰嗦大量使用空接口后类型安全就形同虚设了。当时团队里有人说用 Go 只是把 Python 的动态类型问题换了个形式继续存在这句话我觉得很准确。C 当然也被列进了候选。性能绝对够但 C 的内存安全是硬伤。Agent 运行时跑在公网环境要解析各种外部输入、加载第三方技能内存漏洞一旦被利用后果比性能问题严重得多。我们没有一支专职做 C 的团队可以支撑长期维护这个选项在讨论第一天就被否决了。2.2 Rust 在 Agent 场景下的三个决定性优势Rust 最终胜出不是因为性能数字好看而是因为它在可预测性上做到了我们想要的极致。第一无 GC 带来的延迟可预测性。Rust 没有垃圾回收器所有内存都在编译期决定好生命周期。这意味着运行时不会出现不知道什么时候触发 GC、GC 要停多久的不确定性。Agent 对话场景里用户等一个回复已经有几百毫秒的模型延迟了本地的工具调用延迟如果还能稳定控制在微秒到毫秒级别那整个交互链路的延迟就完全可控。这点对后面的边缘部署计划尤其重要。第二所有权模型对并发安全的保证。Agent 运行时最大的并发风险是共享状态Python 时代我们花了很多精力做锁、做同步结果还是出了前面的死锁问题。Rust 在写代码的阶段就把数据竞争问题暴露出来——var 能不能跨线程传、共享变量有没有用 Arc 包起来、可变引用有没有同时存在多个全部由编译器把关。我们把 Python 版的死锁问题整理成用例用 Rust 重写之后这类问题几乎不可能发生。第三无运行时、静态二进制部署。Rust 编译出来就是一个静态链接的可执行文件直接扔到目标机器上就能跑不需要 Python 运行时、不需要装依赖、不需要虚拟环境。对边缘设备、嵌入式场景我们后来确实接了一个具身智能方面的需求这种部署方式简直是降维打击。2.3 团队能接受 Rust 的前提条件Rust 的学习曲线是真实存在的这点不能装看不见。我们团队当时的背景是:大部分人写 Python一个人写过两年 C还有一个人把《Rust 权威指南》翻了大半本。在决定用 Rust 之前我先花了两周做了一个技术验证用 Rust 写一个最小的 Agent skill 注册和执行引擎核心功能包括热加载技能、函数调用参数校验、结果回传。两周后这个 demo 跑通了代码量只有 Python 版的 40%单次函数调用延迟降到了 Python 版的 1/10。这个 demo 在团队里起到了关键的说服作用。大家亲眼看到Rust 版本不仅性能好代码结构也因为类型系统的约束变得更清晰了。当然代价是前两个月开发效率确实低于 Python我们通过拆分任务、结对编程、每次 code review 专门扫 unsafe 代码的方式把学习成本控制在了可接受范围内。如果你要复制这条路团队里最好至少有一个人愿意承担Rust 导师的角色否则项目很可能在第一个月就卡在借用检查器上。3. SkillLite 在 Rust 下的架构重构从动态分发到编译期约束3.1 整体设计思路不再是解释器而是编译器Python 版 SkillLite 的本质是一个小型的动态解释器技能库存放在配置中心运行时通过字符串匹配找到对应的处理器再用 eval 或者 getattr 动态执行。灵活是真灵活但每加一个新技能都要经过一次字符串查找 - 动态加载 - 参数校验 - 执行的链性能损耗大而且一旦技能名拼错要跑到运行时才报错。Rust 版彻底改变了这个模式。我们把技能从运行时的动态配置变成了编译期的静态注册用宏macro和 trait 对象组合的方式重新设计了技能加载机制。一个技能的定义从 Python 版的这样skill.register(translate_text) def translate_text(text: str, target_lang: str) - str: # 调用翻译 API return api_call(text, target_lang)变成了 Rust 版的这样#[derive(Serialize, Deserialize)] struct TranslateParams { text: String, target_lang: String, } #[skill(name translate_text, description Translate text to target language)] async fn translate_text(params: TranslateParams) - ResultString, SkillError { let client TranslationClient::new(); client.translate(params.text, params.target_lang).await } register_skill!(translate_text);这个变化看起来只是语言不同实质上是把技能从一个运行时字符串变成了一个编译期实体。参数结构、校验逻辑、执行函数在编译时就被类型系统约束住了不可能出现 Python 版那种传一个非法参数运行到一半才报错的情况。3.2 五万行代码的模块划分SkillLite 的最终代码量大约五万行分布在下面几个核心模块里skill-core技能定义、trait 实现、参数校验框架大约 8000 行skill-registry技能注册表、静态注册宏、技能发现机制大约 5000 行agent-runtimeAgent 会话管理、任务调度、事件循环、取消处理大约 15000 行function-callingLLM 结构化输出的解析、参数映射、函数调用管线大约 12000 行persistence会话状态快照、技能执行历史记录大约 5000 行edge-runtime边缘部署适配、资源限制、嵌入式平台支持大约 5000 行这个拆分思路是让每个模块只做一件事模块之间用 trait 定义边界。skill-registry 不关心技能内部实现是什么只要实现了 Skill trait 就能被注册agent-runtime 不关心具体技能逻辑它只负责调度和执行function-calling 模块负责把 LLM 输出的 JSON 或者结构化指令解析成类型安全的调用参数。这样拆的好处是测试特别好写。每个模块都是独立的 crate可以单独跑单元测试和集成测试。五万行代码看着很多但真正核心的 agent-runtime 只有一万五千行其他部分都是围绕这个核心的配套模块。3.3 宏编程Agent 技能声明式配置的关键Rust 的宏在 SkillLite 里扮演了非常关键的角色这可能是 Python 版完全替代不了的能力。Python 的装饰器虽然能做到类似的事但装饰器本质上是运行时包装它改变不了函数签名也无法在编译期做静态校验。我们自定义了两个核心宏#[skill(...)]属性宏用来标注一个技能函数。它会根据函数签名自动生成参数解析和校验代码同时把技能的元信息名称、描述、参数 schema写入一个编译器可见的静态注册表中。register_skill!声明宏把技能函数注册到一个全局的静态分发表中。这个分发表使用OnceLock或者在编译期用phf这类库做静态哈希映射查找复杂度是 O(1)没有运行时字符串匹配的开销。用宏还有一个额外好处技能清单可以生成给大模型用的 tool schema。我们在属性宏里直接声明了#[derive(Serialize)]生成 JSON Schema每次技能定义变更工具的 schema 也跟着变不可能出现 Python 版那样定义和文档不一致的问题。3.4 agent-runtime 的并发设计tokio 下的结构化并发Agent 会话的并发模型是整个架构设计里最核心的部分。Python 版用的是 asyncio 单线程事件循环Rust 版我们选择了 tokio 多线程运行时。每个 Agent 会话对应一个 tokio task会话之间的状态完全隔离共享数据通过ArcRwLockState保护。一个会话内部可能同时开出多个子任务比如同时调用翻译技能和搜索技能。这些子任务需要取消机制——用户中断对话时整条任务链要全部取消。tokio 提供了tokio::select!宏和任务取消相关的工具但真正复杂的是取消安全设计。一个技能执行到一半被取消时要确保没有脏数据写进数据库没有未完成的请求泄漏。我们为此引入了一个类似结构化并发的抽象所有子任务都必须在一个TaskScope内创建TaskScope 被 drop 时所有子任务会被自动取消并等待完成。这比 Python 版的手动取消靠谱得多因为编译器保障了任务一定能被清理干净。4. 性能实测五万行 Rust 代码换回来了什么4.1 测试场景设计性能测试我们没有盲目地测单纯的 mock 接口而是构造了和真实业务一致的场景一个 Agent 会话模型返回结构化函数调用请求运行时解析参数、加载技能、执行技能、把结果回传给模型。整个链路涵盖了 function calling 的完整流程。压测工具用 Rust 写的模拟 100 到 1000 个并发会话每个会话执行 3 到 5 次技能调用。对比对象是 Python 版 SkillLite 的线上版本。两台机器相同配置16 核 32GB 内存各自独立部署。4.2 数据对比指标Python 版Rust 版提升幅度冷启动时间空载启动到可服务850ms18ms47 倍单次技能调用 P50 延迟6ms0.4ms15 倍单次技能调用 P95 延迟28ms1.1ms25 倍500 并发会话时内存峰值3.8GB480MB8 倍1000 并发会话时的成功率92%99.99%-无 GC 场景下延迟抖动标准差8ms0.2ms40 倍最让我触动的是 P95 延迟。Python 版的 P95 是 28ms虽然比 P50 慢了四倍多但还能接受。Rust 版的 P95 只有 1.1ms而且抖动非常小。这意味着在 Agent 对话场景里用户几乎感知不到工具调用的本地耗时整个交互延迟基本上就是模型推理的时间。内存上从 3.8GB 降到 480MB这个意义不只是省成本而是真正解锁了边缘部署。480MB 的内存占用对一些嵌入式设备还是偏高但已经可以在树莓派级别的硬件上跑起来了。我们后来在一个资源受限的边缘设备上做了测试Rust 版跑起来非常流畅Python 版在那个设备上连启动都成为问题。4.3 性能是怎么优化出来的性能不是写完就有的Rust 版也经历了三轮优化。第一轮是减少无谓的 clone。刚开始写的时候很多地方为了省事直接 clone 字符串和结构体导致内存分配极其频繁。优化思路是梳理数据流把参数传递改成借用用Cow处理需要修改的情况。优化后单次调用的内存分配次数从 400 多次降到了 50 多次。第二轮是避开全局锁。agent-runtime 里的共享状态最开始统一用一个大RwLock包着并发一高就出现锁竞争。后来拆成无锁的结构技能的注册表编译期就固定了用静态只读数据会话状态按照 session id 做 shard每个 shard 一个锁不同会话之间的锁完全隔离。第三轮是重写热点路径。函数调用的参数校验、JSON 解析我们一开始用 serde_json 的默认行为后来在关键路径上换成了simd-json解析耗时又降了一半。还有技能结果的 JSON 序列化我们避免了多次拷贝直接写到流式 writer 里省掉了中间缓冲。这些都是常规性能优化手段但前提是 Rust 的类型系统和所有权模型给了你足够的信心做激进优化不用担心改完一个引用就引入数据竞争。5. 从 Python 迁移到 Rust 踩过的坑所有权、异步与宏展开5.1 借用检查器对 Agent 状态建模的改造从 Python 到 Rust 最痛苦的不是语法而是思维模式的转换。Python 里持有一个对象然后随手修改字段是理所当然的操作到了 Rust 里全成了借用检查器的报错。Agent 会话状态是最典型的例子。Python 版里一个 Session 就是一个字典技能执行过程中可以往里面塞任意字段当前步骤、中间结果、用户偏好。Rust 版里我们一开始老老实实定义了AgentState结构体但很快发现一个问题不同的技能需要访问状态的不同部分如果都往结构体上堆字段要么用大量的Option要么就得频繁获取和释放锁。后来我们做了一次妥协把强类型的会话状态和KV 形式的临时状态分开。强类型状态用 Rust 结构体保存负责核心流程的控制临时状态放一个HashMapString, Value但要通过一个自定义 trait 来访问保证不会出现跨线程的数据竞争。这个设计既保留了 Rust 的类型安全优势又避免了一些场景下建模过于僵化的问题。Rust 的借用检查器让我重新理解了 Agent 状态管理的本质状态不是一个可以随意篡改的对象而是一个需要明确定义所有权的资源。谁可以读它、谁可以写它、什么时候释放这些问题在架构设计阶段就应该想清楚而不是等运行时报错再回来找 bug。5.2 tokio 异步生态和 asyncio 的思维差异Python 的 asyncio 是单线程协程虽然也支持 await但本质上所有协程跑在同一个事件循环线程里变量跨线程的问题基本不存在。Rust 的 tokio 默认是多线程运行时你的 async fn 可能在任何一个工作线程上执行这就引出了Send static的约束。在 Python 里你可以写一个全局共享的连接池每个协程直接用完全不用考虑线程安全。到了 Rust 里连接池比如 redis 连接或者 HTTP 客户端连接必须是Send的否则无法跨线程。刚开始我们经常遇到future is not Send的编译错误需要给客户端包一层Arc或者通过tokio::sync::Mutex保护连接。还有一个差异在超时和取消。asyncio 的超时直接用asyncio.wait_for就行但在 tokio 里要特别注意超时后的状态清理。如果tokio::time::timeout触发了future 被 drop但 future 内部持有的资源比如已经发出但还没收到响应的 HTTP 请求不会自动撤销。技能执行过程中如果被超时中断我们需要在 drop 逻辑里做补偿操作比如记录一条失败日志、回滚部分写入的状态。这些坑都是实践后才能体会到的。5.3 工具链与落地部署的细节Rust 的工具链整体体验是好的但有几个实际问题。第一个是依赖下载速度。国内网络环境拉 crates.io 的依赖很慢需要配置国内镜像源。我们在.cargo/config.toml里配置了 rsproxy 之类的镜像显著改善了构建体验。如果部署环境是内网还需要提前把依赖 vendoring 下来用cargo vendor生成离线依赖目录。这个对信创和内部系统尤其重要不能依赖外网拉包。第二个是交叉编译。我们要把 Agent 运行时部署到 ARM 的边缘设备上交叉编译成了必备技能。Rust 的交叉编译比 Python 好太多Python 要在目标设备上装解释器和依赖Rust 只要一个目标平台的 toolchain。我们用的是cross工具一条命令就能写出 ARM 版本后来发现cargo-zigbuild在某些 glibc 版本上也很好用能解决旧系统自带 glibc 版本过低的问题。第三个是编译时间。五万行代码的增量编译如果配置不当能等到天荒地老。我们在.cargo/config.toml里做了两个关键配置[profile.release] lto thin codegen-units 16 opt-level 3 [build] rustc-wrapper sccachelto thin在保持大部分链接时优化效果的同时显著加快链接速度codegen-units 16让编译器并行处理更多代码单元sccache 作为编译缓存让不同分支的编译共享缓存节省了大量时间。我见过很多团队因为这三点没配置编译一次要十几分钟就觉得 Rust 开发效率太低而放弃其实大部分是配置问题。宏展开调试是另一个坑。我们用宏自动生成技能注册代码但宏报错的时候错误信息非常天书化经常是expected type, found{这种完全定位不到问题在哪儿的提示。解决方案是装一个cargo expand工具把宏展开后的代码打印出来看。这个方法救了我无数次。写宏的时候也要克制尽量让宏只做机械的代码生成复杂的逻辑放在普通函数里否则调试成本会直线上升。5.4 一个典型的线上问题的排查过程这里分享一个我们当时排查了三天的线上问题非常经典。上线 Rust 版 SkillLite 之后某天突然反馈说部分会话的上下文丢失了技能执行结果没有正确回填到对话历史里。这个问题在 Python 版从来没出现过因为 Python 版的上下文是一个全局字典技能执行完直接往里面塞Rust 版我们做了更严格的模块划分上下文由 agent-runtime 统一管理技能只能通过返回结果回传数据。排查过程一开始认为数据格式有问题反复检查了序列化和反序列化代码没有发现异常。后来怀疑是锁竞争导致状态被覆盖给共享状态加了专门的测试用例也复现不出来。最后是在一个很偶然的时机抓到了线索负责状态回填的模块里我们用了tokio::spawn开启了一个后台任务来异步写上下文。后台任务的执行顺序不保证当两个技能同时完成时两个后台任务同时写上下文后写的数据覆盖了先写的。因为用户提问的措辞这个覆盖往往看不出来但偶尔会丢掉关键上下文。修复方式是取消了后台任务改为在技能完成后同步地、按顺序地写上下文。性能影响微乎其微但彻底解决了问题。这个坑给我的教训是Rust 的优势是明确性但如果自己用异步任务把执行顺序搞乱反而会引入 Python 时代不存在的隐式错误。Rust 不是银弹它依然需要你正确地设计并发模型。6. 复盘结论Rust 并不是所有 AI Agent 项目的答案6.1 适合用 Rust 的 Agent 场景经过了这次从 Python 到 Rust 的完整迁移我梳理了一下到底什么样的 Agent 项目适合用 Rust 做。第一类是延迟敏感的交互式 Agent。比如语音助手、实时对话机器人用户的体感延迟是整个系统成功与否的核心指标。这类场景下Rust 的延迟可预测性优势非常明显。语音交互场景里本地工具调用的延迟哪怕只是 5ms 和 1ms 的区别在整条链路上积累起来都会变得显著。第二类是边端部署的 Agent。具身智能设备、嵌入式机器人、需要在地端实时处理数据的场景对内存占用和运行效率极其敏感。Rust 的无 GC、静态编译、极小运行时这几个特质简直是边端部署的完美匹配。我们后来接的具身智能相关需求就是用 SkillLite 的 edge-runtime 跑的。第三类是长时间运行的服务端 Agent 运行时。一个 Agent 服务可能需要在线上跑几个月不回滚内存泄漏、并发崩溃这类问题在大规模部署时会无限放大。Rust 的所有权模型和类型系统在编译期就排除了一大批这类 bug让服务具备更强的长期稳定性。6.2 不适合用 Rust 的场景反过来有些场景我觉得大可不必折腾 Rust。如果你还在快速验证产品 ideaAgent 的核心逻辑每天都在变今天换成 LangChain明天换成自研框架那乖乖用 Python 就好。Rust 的开发效率在前期确实比不上 Python类型系统的约束会让快速迭代时感觉束手束脚。如果业务非常依赖 Python 生态的库比如 pandas、numpy、scikit-learn、以及大量 AI 开源仓库都是 Python 优先强行用 Rust 会非常痛苦。SkillLite 之所以能切是因为我们核心逻辑不依赖第三方 Python 库只有 HTTP 调用和 JSON 处理在 Rust 生态里都有高质量替代品。另外如果团队完全没有 Rust 背景也没有人愿意花时间去啃 Rust 的所有权和异步模型那我还是劝你三思。我们不缺任何一个能用 echo 写出 hello world 的 Rust 开发者缺的是能从编译错误里快速定位设计问题的工程师。团队的学习意愿和培训投入必须作为选型的重要考量。6.3 想走这条路的话我给你几个实在的建议第一不要一次性重写。SkillLite 虽然是整体重写但我们是分模块进行的先把最核心的 function-calling 模块用 Rust 重写通过 FFI 或者独立服务的方式接入 Python 系统验证性能提升之后再逐步替换其他模块。直接一把梭的大重写风险极高很容易半年过去还跑不起来。第二认真设计你的状态模型。Rust 最大的开发成本是状态和并发的设计。如果你沿用 Python 时代的全局字典 随手改的做法死磕一天都过不了编译。反过来如果你愿意花时间设计清晰的 state 结构、明确的共享边界Rust 的类型系统会帮你省掉未来几个月调 bug 的成本。第三让团队先做一个可独立验证的技术 demo。就像我们当初做的那个 skill 注册引擎范围要小、结论要明确性能提升多少、代码可维护性如何、团队整体的接受度怎么样。用数据说话比开会争论语言优劣有用一百倍。最后说说 Rust 生态近一年给我带来的感受。Rust 社区在 AI Agent 方向的关注度越来越高有人问 LangGraph 为什么没有官方 Rust 版本也有人组了 agent rust 方向的 discussion。目前 Rust 的 Agent 生态相比 Python 还有差距但 AI Agent 这个领域本身还很年轻核心的价值——性能、安全、可部署性——恰好是 Rust 的传统强项。如果和我们的实践互相印证我觉得未来一两年 Rust 在 Agent 基础设施层的位置会越来越稳。SkillLite 迁移成 Rust 之后团队内部也形成了一个共识语言选型不是追新也不是守旧而是把项目要达到的目标、团队能付出的成本、生态能提供的支撑放到一张表里做综合权衡。如果本文的复盘能帮你在做类似决策时少走一点弯路那就值得了。