创建 Rails 插件(Plugin)完全指南:基于 Ruby on Rails 从零构建、测试与发布可复用 Gem 创建 Rails 插件Plugin完全指南基于 Ruby on Rails 从零构建、测试与发布可复用 Gem【免费下载链接】railsRuby on Rails项目地址: https://gitcode.com/GitHub_Trending/rai/rails本指南面向希望将通用能力沉淀为 Rails 插件、从而扩展或定制 Rails 应用行为的开发者。文中以构建一个名为ApiBoost的 API 增强插件为主线完整演示如何用rails plugin new生成工程骨架、扩展 Ruby 核心类与ApplicationRecord、借助 Railtie 深度接入 Rails 启动流程并最终把插件测试、发布为 RubyGems 上的正式 Gem。读完本文你将掌握插件与引擎的选型边界、插件目录结构与 gemspec 规范以及 Railtie、ActiveSupport::Concern、ActiveSupport.on_load等核心机制的实际用法。什么是 Rails 插件PluginRails 插件Plugin是一种打包好的扩展它把额外的功能注入 Rails 应用。插件存在的价值主要有三点允许开发者在不影响核心代码库稳定性的前提下试验新想法支撑模块化架构使功能可以独立维护、独立升级、独立发版让团队不必把一切功能都塞进框架而是以插件形式对外释放能力。从技术层面看插件就是一个被设计成“在 Rails 应用内工作”的 Ruby gem。它通常通过Railtie钩入 Rails 的启动流程从而以结构化方式扩展或修改框架行为。Railtie 是扩展 Rails 最基础的集成点——当插件需要新增配置项、Rake 任务或初始化代码但又不暴露控制器、视图或模型时一般就使用 Railtie。在仓库中可以找到 Railtie 的完整实现railties/lib/rails/railtie.rb它提供rake_tasks、console、runner、generators、server、initializer与config等类级钩子见Railtie.register_block_for及Railtie::Configuration。插件与引擎Engine的关系在官方文档中界定得非常清楚引擎是插件的进阶形态它表现得像一个迷你 Rails 应用——自带路由、控制器、视图乃至资源assets。所有引擎都是插件但并非所有插件都是引擎二者的本质差别在“范围”插件通常用于小而美的定制或跨应用共享的行为引擎则提供带自身路由、模型、视图的更完整功能组件。rails plugin new生成器选项Rails 插件以 gem 形式构建可通过 RubyGems 与 Bundler 在多个 Rails 应用间共享。rails plugin new命令支持多个选项决定了生成何种形态的插件工程。仓库中生成器实现位于 railties/lib/rails/generators/rails/plugin/plugin_generator.rb选项定义与用法可在 railties/lib/rails/generators/rails/plugin/USAGE 中查看。基础插件Basic Plugin默认形态不加任何参数时生成最小化的插件结构适合简单扩展核心类方法、工具函数等$ rails plugin new api_boost完整插件--full生成包含app目录树models、views、controllers、config/routes.rb以及lib/api_boost/engine.rbEngine 类的更完整结构$ rails plugin new api_boost --full当插件需要自己的模型、控制器或视图但不需要命名空间隔离时使用--full。从生成器源码可看到--full会创建app/models、app/controllers、app/mailers、app/jobs等目录PluginBuilder#app方法并在lib下生成 engine 文件PluginBuilder#libengine?时生成lib/.../engine.rb。对应模板为 engine.rb.ttclass Engine ::Rails::Engine # --mountable 时注入: isolate_namespace ApiBoost # --api 时注入: config.generators.api_only true end可挂载引擎--mountable生成完全隔离、可挂载的引擎它包含--full的全部内容并额外提供命名空间隔离所有类以ApiBoost::前缀命名隔离的路由ApiBoost::Engine.routes.draw资源清单文件asset manifest命名空间化的ApplicationController与ApplicationHelper自动在 dummy 应用测试脚手架应用中挂载引擎以便测试。$ rails plugin new api_boost --mountable在源码层面--mountable通过生成器中的mountable?判定options[:mountable]模板engine.rb.tt中对应isolate_namespace的注入逻辑。构建自包含功能可独立成一个应用的功能如管理后台、博客、API 模块时优先考虑--mountable。引擎的详细用法可参阅 Getting Started with Engines引擎入门指南。选型速查基础插件简单工具、核心类扩展或小型 helper 方法--full插件需要 models/controllers、但与宿主应用共享命名空间的复杂功能--mountable引擎自包含特性管理面板、博客、API 模块等。随时可用帮助命令查看全部选项与用法说明$ rails plugin new --help除上述三个核心选项外生成器还支持--api为 API 应用插件生成精简技术栈见 plugin_generator.rb 中class_option :api及模板中config.generators.api_only true、--dummy_path自定义 dummy 应用路径默认test/dummy、--skip_gemspec、--skip_gemfile_entry等且“Rails 的任何部分都可以在插件生成时跳过”USAGE 示例rails plugin new blog --mountable --skip-asset-pipeline。项目场景设定假设你在构建 API 服务希望做一个为任意 Rails API 应用增强通用能力的插件覆盖请求限流throttling、响应缓存caching、自动生成 API 文档等场景。本指南创建名为ApiBoost的插件来承载这些功能。环境搭建与工程骨架生成插件$ rails plugin new api_boost生成后的目录结构如下api_boost/ ├── api_boost.gemspec ├── Gemfile ├── lib/ │ ├── api_boost/ │ │ └── version.rb │ ├── api_boost.rb │ └── tasks/ │ └── api_boost_tasks.rake ├── test/ │ ├── dummy/ │ │ ├── app/ │ │ ├── bin/ │ │ ├── config/ │ │ ├── db/ │ │ ├── public/ │ │ └── ... (完整 Rails 应用) │ ├── integration/ │ └── test_helper.rb ├── MIT-LICENSE └── README.md该结构与仓库中 plugin generator 模板目录 一一对应根级文件由create_root_files生成lib、test树分别由create_lib_files、create_test_files处理。各组成部分的职责lib目录存放插件源码lib/api_boost.rb——插件的主入口文件对应模板 %namespaced_name%.rb.tt非引擎形态会require api_boost/railtielib/api_boost/——插件功能所用的模块与类如version.rb定义版本号也是 gemspec 引用的常量来源lib/tasks/——插件对外提供的 Rake 任务。test/dummy目录包含一个完整 Rails 应用专门用于测试插件通过 Gemfile 自动加载你的插件提供测试插件集成的 Rails 运行环境可按需携带 generators、models、controllers、views 用于测试可交互地使用rails console与rails server。dummy 应用的生成逻辑在生成器的generate_test_dummy方法中它会以当前选项动态调用Rails::Generators::AppGenerator随后通过test_dummy_config、test_dummy_clean做定制例如 mountable 形态会重写 dummy 的config/routes.rb自动挂载引擎plugin_generator.rb 的test_dummy_config。gemspec 文件api_boost.gemspec定义 gem 的元数据、依赖以及打包时包含的文件。生成器模板 %name%.gemspec.tt 展示了关键约定——spec.files通过Dir[{app,config,db,lib}/**/*, MIT-LICENSE, Rakefile, README.md]圈定文件范围并预留了allowed_push_host、homepage_uri、source_code_uri、changelog_uri等 metadata 占位。初始化配置进入插件所在目录编辑api_boost.gemspec替换所有TODO占位spec.homepage http://example.com spec.summary Enhance your API endpoints spec.description Adds common API functionality like request throttling, response caching, and automatic API documentation. # ... spec.metadata[source_code_uri] http://example.com spec.metadata[changelog_uri] http://example.com然后执行bundle install。接着配置测试数据库——进入test/dummy目录并执行$ cd test/dummy $ bin/rails db:createdummy 应用与普通 Rails 应用无异你可以生成模型、跑迁移、启动服务器或打开 console 来边开发边验证插件功能。数据库就绪后回到插件根目录cd ../..运行bin/test应当看到生成器自带的一个冒烟测试通过$ bin/test ... 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips这表示一切生成正确可以开始添加功能了。扩展核心类Core Classes本节演示如何给Integer增加一个在全 Rails 应用任意位置都可用的方法。WARNING开始前务必明白——扩展核心类如 String、Array、Hash 等应尽量克制甚至避免。核心类扩展可能脆弱、危险且常常没必要因为它们可能导致多个 gem 用同名方法扩展同一类时的命名冲突Ruby 或 Rails 升级改变核心类行为时的意外损坏方法来源不直观导致的排错困难插件与其它代码之间的耦合问题。更优替代方案创建工具模块或辅助类、用组合替代猴子补丁composition over monkey patching、把功能实现为自有类上的实例方法。即便如此理解核心类扩展如何工作依然有价值——下面示例演示该技术但应谨慎使用。本例给Integer添加一个requests_per_hour方法。先修改lib/api_boost.rb加入require api_boost/core_ext# api_boost/lib/api_boost.rb require api_boost/version require api_boost/railtie require api_boost/core_ext module ApiBoost # Your code goes here... end新建core_ext.rb定义一个RateLimit值类型并给Integer添加方法用法与10.hours返回一个 Time 类似10.requests_per_hour将返回一个限流描述对象# api_boost/lib/api_boost/core_ext.rb ApiBoost::RateLimit Data.define(:requests, :per) class Integer def requests_per_hour ApiBoost::RateLimit.new(self, :hour) end end这里的Data.defineRuby 3.2 引入的 immutable value object与文档示例一致返回一个携带requests与per两个字段的不可变数据结构。要观察效果进入test/dummy启动 console$ cd test/dummy $ bin/rails consoleirb 10.requests_per_hour #data ApiBoost::RateLimit requests10, per:hourdummy 应用会自动加载插件因此你添加的任何扩展都会立即可用于测试。给 Active Record 添加 acts_as 方法插件中一个常见模式是给模型添加名为acts_as_something的方法。此处我们编写acts_as_api_resource为 Active Record 模型注入 API 专属功能。假设你在构建 API希望跟踪某个资源比如Product最近一次被 API 访问的时间戳用途包括对请求限流、在管理后台显示“最后活跃时间”、优先同步过期记录。与其在每个模型里重复写这套逻辑不如通过共享插件实现。acts_as_api_resource把该功能赋予任意模型通过更新一个时间戳字段来记录 API 活动。首先准备好文件# api_boost/lib/api_boost.rb require api_boost/version require api_boost/railtie require api_boost/core_ext require api_boost/acts_as_api_resource module ApiBoost # Your code goes here... end# api_boost/lib/api_boost/acts_as_api_resource.rb module ApiBoost module ActsAsApiResource extend ActiveSupport::Concern class_methods do def acts_as_api_resource(api_timestamp_field: :last_requested_at) # 创建类级设置保存 API 时间戳使用的字段名 cattr_accessor :api_timestamp_field, default: api_timestamp_field.to_s end end end end上述代码使用ActiveSupport::Concern简化“既含类方法又含实例方法”的模块 includeclass_methods块里的方法在模块被 include 时成为类方法。Concern的实现可查看 activesupport/lib/active_support/concern.rb。添加类方法默认情况下插件期望模型具有名为last_requested_at的列。不过该列名可能已被占用因此插件允许通过api_timestamp_field:关键字传参自定义。内部该值存放在名为api_timestamp_field的类级设置里由 Rails 提供的cattr_accessor类属性存取器实现插件更新时间戳时会读取它。例如希望用last_api_call替代last_requested_at作为列名。先在 dummy 应用中生成模型来验证功能。在test/dummy目录下执行$ cd test/dummy $ bin/rails generate model Product last_requested_at:datetime last_api_call:datetime $ bin/rails db:migrate更新 Product 模型使其“表现”为一个 API 资源# test/dummy/app/models/product.rb class Product ApplicationRecord acts_as_api_resource api_timestamp_field: :last_api_call end为了让所有模型都能使用把模块 include 进ApplicationRecord稍后会介绍如何自动完成这一步骤# test/dummy/app/models/application_record.rb class ApplicationRecord ActiveRecord::Base include ApiBoost::ActsAsApiResource self.abstract_class true end在 Rails console 中验证irb Product.api_timestamp_field last_api_call添加实例方法插件为所有调用acts_as_api_resource的 Active Record 模型注入名为track_api_request的实例方法把配置的时间戳字段设置为当前时间或传入的自定义时间。更新acts_as_api_resource.rb# api_boost/lib/api_boost/acts_as_api_resource.rb module ApiBoost module ActsAsApiResource extend ActiveSupport::Concern class_methods do def acts_as_api_resource(options {}) cattr_accessor :api_timestamp_field, default: (options[:api_timestamp_field] || :last_requested_at).to_s end end def track_api_request(timestamp Time.current) write_attribute(self.class.api_timestamp_field, timestamp) end end endNOTE上面用write_attribute写入模型字段只是插件与模型交互的一种示例它并不总是最合适的选择。比如你可能更偏好send——它实际调用的是 setter 方法会触发 Active Record 的赋值逻辑、类型转换回调等send(#{self.class.api_timestamp_field}, timestamp)在 console 中验证irb product Product.new irb product.track_api_request irb product.last_api_call 2025-06-01 10:31:15 UTC进阶集成使用 Railtie目前构建的插件对基础功能足够好。但当插件需要更深度地接入 Rails 框架时就应该使用Railtie。以下场景必须引入 Railtie添加可通过Rails.application.config访问的配置项无需人工配置即可自动把模块 include 进 Rails 类向宿主应用提供 Rake 任务设置随 Rails 启动运行的初始化器initializer向应用中间件栈追加中间件配置 Rails generators订阅ActiveSupport::Notifications。对仅扩展核心类或添加模块的简单插件Railtie 并非必需。从源码可以印证这些能力点railties/lib/rails/railtie.rb 中定义了rake_tasks、console、runner、generators、server等类方法它们调用私有方法register_block_for注册回调块由 Rails 启动流程在相应阶段执行。初始化器则由 railties/lib/rails/initializable.rb 支撑initializer类方法声明具名初始化器Initializer::Collection通过TSort按before/after约束做拓扑排序后执行。配置项Configuration假设你希望让to_throttled_response方法中的默认限流值可配置。先创建 Railtie# api_boost/lib/api_boost/railtie.rb module ApiBoost class Railtie Rails::Railtie config.api_boost ActiveSupport::OrderedOptions.new config.api_boost.default_rate_limit 60.requests_per_hour initializer api_boost.configure do |app| ApiBoost.configuration app.config.api_boost end end end给插件添加配置模块# api_boost/lib/api_boost/configuration.rb module ApiBoost mattr_accessor :configuration, default: nil def self.configure yield(configuration) if block_given? end end这里的config.api_boost ActiveSupport::OrderedOptions.new是一个关键点OrderedOptions让你可以在config命名空间下按需挂任意自定义键如default_rate_limit并保持配置的顺序语义初始化的真正连通发生在自定义的api_boost.configure初始化器内它把app.config.api_boost交给ApiBoost.configuration持有。更新核心扩展以使用该配置# api_boost/lib/api_boost/core_ext.rb module ApiBoost module ActsAsApiResource def to_throttled_json(rate_limit ApiBoost.configuration.default_rate_limit) limit_window 1.send(rate_limit.per).ago.. num_of_requests self.class.where(self.class.api_timestamp_field limit_window).count if num_of_requests rate_limit.requests { error: Rate limit reached }.to_json else to_json end end end end在主插件文件里 require 新文件# api_boost/lib/api_boost.rb require api_boost/version require api_boost/configuration require api_boost/railtie require api_boost/core_ext require api_boost/acts_as_api_resource module ApiBoost # Your code goes here... end现在使用该插件的应用可以这样配置在宿主应用的config/application.rb中# config/application.rb config.api_boost.default_rate_limit 100 requests per hour自动 include 模块与其要求用户手动把ActsAsApiResourceinclude 进他们的ApplicationRecord不如用 Railtie 自动完成# api_boost/lib/api_boost/railtie.rb module ApiBoost class Railtie Rails::Railtie config.api_boost ActiveSupport::OrderedOptions.new config.api_boost.default_rate_limit 60.requests_per_hour initializer api_boost.configure do |app| ApiBoost.configuration app.config.api_boost end initializer api_boost.active_record do ActiveSupport.on_load(:active_record) do include ApiBoost::ActsAsApiResource end end end endActiveSupport.on_load钩子确保模块在 Rails 初始化过程中、Active Record 完全加载之后的正确时机被 include。这是 Rails 框架自身的通行做法例如 Active Record 自己的 Railtie 中大量使用ActiveSupport.on_load(:active_record) { ... }来注入默认行为见 activerecord/lib/active_record/railtie.rb 中on_load(:active_record)的多处用法。on_load回调块的接收者是 Active Record 基类自身因此在块内直接写include等价于ActiveRecord::Base.include(...)。Rake 任务要向使用插件的应用提供 Rake 任务# api_boost/lib/api_boost/railtie.rb module ApiBoost class Railtie Rails::Railtie # ... 既有配置 ... rake_tasks do load tasks/api_boost_tasks.rake end end end创建 Rake 任务文件# api_boost/lib/tasks/api_boost_tasks.rake namespace :api_boost do desc Show API usage statistics task stats: :environment do puts API Boost Statistics: puts Models using acts_as_api_resource: #{api_resource_models.count} end def api_resource_models ApplicationRecord.descendants.select do |model| model.include?(ApiBoost::ActsAsApiResource) end end end使用插件的应用将获得rails api_boost:stats任务。注意生成器默认已在lib/tasks/%namespaced_name%_tasks.rake准备了同名任务模板占位文件开发时把任务写在那里即可被rake_tasks块按需加载。上述rake_tasks do ... end块正是通过 Railtie 的register_block_for(:rake_tasks, blk)注册的在宿主应用加载任务阶段执行load。测试 Railtie在 dummy 应用中验证 Railtie 是否正确工作# api_boost/test/railtie_test.rb require test_helper class RailtieTest ActiveSupport::TestCase def test_configuration_is_available assert_not_nil ApiBoost.configuration assert_equal 60.requests_per_hour, ApiBoost.configuration.default_rate_limit end def test_acts_as_api_resource_is_automatically_included assert Class.new(ApplicationRecord).include?(ApiBoost::ActsAsApiResource) end def test_rake_tasks_are_loaded Rails.application.load_tasks assert Rake::Task.task_defined?(api_boost:stats) end endRailtie 提供了一种干净利落的方式把插件接入 Rails 的初始化流程。关于完整初始化生命周期的更多细节见 Rails 初始化过程指南。测试你的插件为插件添加测试是良好实践插件生成器已经为你搭好了测试框架test/test_helper.rb、dummy 应用与bin/test命令。下面为刚构建的功能补上测试。测试核心扩展# api_boost/test/core_ext_test.rb require test_helper class CoreExtTest ActiveSupport::TestCase def test_to_throttled_response_adds_rate_limit_header response_data Hello API expected { data: Hello API, rate_limit: 60.requests_per_hour } assert_equal expected, response_data.to_throttled_response end def test_to_throttled_response_with_custom_limit response_data User data expected { data: User data, rate_limit: 100 requests per hour } assert_equal expected, response_data.to_throttled_response(100 requests per hour) end end测试 ActsAs 方法# api_boost/test/acts_as_api_resource_test.rb require test_helper class ActsAsApiResourceTest ActiveSupport::TestCase def test_a_users_api_timestamp_field_should_be_last_requested_at assert_equal last_requested_at, User.api_timestamp_field end def test_a_products_api_timestamp_field_should_be_last_api_call assert_equal last_api_call, Product.api_timestamp_field end def test_users_track_api_request_should_populate_last_requested_at user User.new freeze_time Time.current Time.stub(:current, freeze_time) do user.track_api_request assert_equal freeze_time.to_s, user.last_requested_at.to_s end end def test_products_track_api_request_should_populate_last_api_call product Product.new freeze_time Time.current Time.stub(:current, freeze_time) do product.track_api_request assert_equal freeze_time.to_s, product.last_api_call.to_s end end end测试中用Time.stub(:current, ...)冻结时间确保断言与真实时钟无关——这正是 Rails 自带 ActiveSupport::Testing 测试扩展的常见技巧仓库中大量测试文件均采用此模式例如 activesupport/test/time_travel_test.rb 展示的时间旅行断言。运行全部测试确认一切正常$ bin/test ... 6 runs, 6 assertions, 0 failures, 0 errors, 0 skips关于 Rails 测试框架的更完整介绍可参考 测试 Rails 应用指南。Generators生成器只需在插件的lib/generators目录中创建生成器gem 即自动获得生成器能力。创建生成器的细节参见 Generators Guide生成器指南。这种“约定优于配置”的做法在 Rails 各组件中广泛使用——例如 ActionCable、ActionMailbox 等内置组件的生成器都位于各自lib/rails/generators/目录下参见 actioncable/lib/rails/generators、actionmailbox/lib/rails/generators可作为插件组织生成器的参考范式。发布你的 Gem开发中的 gem 插件可以方便地从任意 Git 仓库共享。把 ApiBoost 的代码提交到 Git 仓库然后在目标应用的Gemfile中添加一行gem api_boost, git: https://github.com/YOUR_GITHUB_HANDLE/api_boost.git执行bundle install后gem 的功能即可被该应用使用。当 gem 准备好正式发版时可发布到 RubyGems。另一种途径是使用 Bundler 提供的 Rake 任务。查看完整任务列表$ bundle exec rake -T $ bundle exec rake build # Build api_boost-0.1.0.gem into the pkg directory $ bundle exec rake install # Build and install api_boost-0.1.0.gem into system gems $ bundle exec rake release # Create tag v0.1.0 and build and push api_boost-0.1.0.gem to Rubygems其中release会先打v0.1.0标签再构建并推送 gem——spec.version由 gemspec 从lib/api_boost/version.rb读取生成器模板require_relative lib/api_boost/version因此发版前先更新版本常量即可。rails 官方发布流程本身也是类似的 tag gem push 模式可参考 RELEASING_RAILS.md。RDoc 文档插件稳定后应撰写文档。第一步是完善README.md建议包含你的名字安装方式如何把功能接入应用若干常见用例示例对用户有帮助的警告、坑点或技巧。README 打磨到位后为开发者会使用的所有方法补充 RDoc 注释习惯上对不属公共 API 的代码加# :nodoc:注释将其排除在 API 文档之外。注释就绪后在插件目录执行$ bundle exec rake rdoc小结从rails plugin new api_boost一个命令出发本文走完了 Rails 插件的完整生命周期选择基础/--full/--mountable三种工程形态理解 gemspec、lib与test/dummy的角色分工通过Data.define与核心类扩展实现requests_per_hour这样的值对象用ActiveSupport::Concerncattr_accessor实现可参数化的acts_as_api_resource再用 Railtie 打通配置项、ActiveSupport.on_load自动注入、Rake 任务与初始化器这些深度集成点最后以 ActiveSupport::TestCase 补齐测试并经 Bundler 任务发布。插件与引擎的本质区别在于作用域与集成深度——小定制选插件自包含功能选引擎而 Railtie 正是把二者接入 Rails 启动生命周期的标准通道。【免费下载链接】railsRuby on Rails项目地址: https://gitcode.com/GitHub_Trending/rai/rails创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

最新新闻

Rust 编译器错误码 E0547 深度解析:稳定性属性中缺失 `issue` 字段的原因、修复与实现原理

Rust 编译器错误码 E0547 深度解析:稳定性属性中缺失 `issue` 字段的原因、修复与实现原理

Rust 编译器错误码 E0547 深度解析:稳定性属性中缺失 issue 字段的原因、修复与实现原理 【免费下载链接】rust Empowering everyone to build reliable and efficient software. 项目地址: https://gitcode.com/GitHub_Trending/ru/rust 在编写或使用 Rust …

2026/9/8 22:00:51
opencode实战指南:从安装配置到进阶玩法全解析

opencode实战指南:从安装配置到进阶玩法全解析

1. 为什么我最终留下了opencode:它解决了我最烦的那类问题先说个背景。过去半年我把自己项目里能交给AI Agent干的事基本都试了个遍,从GitHub Copilot的命令行模式,到Codex、Claude Code,再到市面上各种套壳工具,每个都…

2026/9/8 22:00:51
Flutter Engine 头文件守卫一致性检查工具 header_guard_check 全解析:规范、命名规则、CLI 用法与自动修复

Flutter Engine 头文件守卫一致性检查工具 header_guard_check 全解析:规范、命名规则、CLI 用法与自动修复

Flutter Engine 头文件守卫一致性检查工具 header_guard_check 全解析:规范、命名规则、CLI 用法与自动修复 【免费下载链接】flutter Flutter makes it easy and fast to build beautiful apps for mobile and beyond 项目地址: https://gitcode.com/GitHub_Tren…

2026/9/8 22:00:51
opencode:开源终端AI编程助手实战指南

opencode:开源终端AI编程助手实战指南

最近几个月,我基本把日常开发里的"脏活累活"都扔给了终端里的AI编程助手。从最早折腾Claude Code,到后来试Codex CLI、Google的codex,再到这个叫opencode的开源工具,一圈用下来,opencode是目前我留在工作流里…

2026/9/8 22:00:51
机器人足球源码重构:从6000行单文件到感知-决策-执行分层架构

机器人足球源码重构:从6000行单文件到感知-决策-执行分层架构

简介:合肥工业大学机器人足球球队源代码,是一套面向机器人足球竞赛的完整软件工程资源,适合学习机器人控制、多智能体协作与AI策略规划的开发者参考。代码覆盖硬件驱动、运动控制、策略规划、传感器处理与通信协议等关键环节,底层…

2026/9/8 22:00:51
AI写论文哪个软件最好?别急着下结论,先看懂“好”的定义

AI写论文哪个软件最好?别急着下结论,先看懂“好”的定义

毕夏AI官网 www.bixiaai.com 毕夏AI写作官网 www.bixiaai.com 毕夏官网 www.bixiaai.com 毕夏智能写作官网 www.bixiaai.com 这个问题我太常被问到了——“老师,AI写论文到底哪个软件最好?” 每次被问,我都不知道怎么回答。不是因为没…

2026/9/8 21:55:51