Agent-Reach:轻量Python CLI封装工具实战指南
1. “Agent-Reach”不是新框架而是一把被低估的CLI工程化切刀你搜“Agent-Reach”首页跳出来的全是GitHub仓库链接、CLI安装命令、MIT License声明还有大量混杂着“github打不开”“codex cli安装慢”“python下载cv2失败”的搜索词——这根本不是某个爆火AI Agent框架的官宣名而是一个真实存在的、轻量但结构精悍的Python CLI工具项目。它不谈LLM调度、不堆Agent编排图谱、不卷多智能体协作范式就干一件事把任意本地Python脚本、函数或模块瞬间封装成可跨环境调用的命令行接口并支持参数透传、结果格式化、错误上下文捕获与基础日志追踪。我第一次接触它是在帮一个做工业设备状态预测的团队做部署收尾时。他们写了一套基于scikit-learn的异常检测逻辑核心是detect_anomaly.py里一个def predict(input_path: str, threshold: float 0.85) - dict函数。客户现场运维只懂./run.sh --input /data/20240612.csv --threshold 0.9拒绝装Python环境、拒绝读文档、拒绝改代码。当时我们试了Flask搭HTTP服务——结果客户防火墙禁了所有非80/443端口又试了PyInstaller打包成二进制——但不同Linux发行版glibc版本冲突频发三天重编五次。直到同事甩来一行命令pip install agent-reach agent-reach wrap detect_anomaly.py predict --cli-name anomaly-cli生成了一个anomaly-cli可执行文件直接扔进客户/usr/local/bin/连--help都自动生成了带类型提示的参数说明。那一刻我才意识到真正落地的Agent未必长着对话窗口可能就藏在一个--dry-run开关背后。它的关键词里没有“大模型”“RAG”“Tool Calling”只有CLI、Python、MIT License、GitHub——这不是巧合而是设计哲学不替代开发者只消解环境摩擦。它不试图成为Agent Runtime而是做Agent的“交付胶水”。你写的每个predict()、transform()、validate()只要符合Python函数签名规范就能被它识别、包装、暴露为标准POSIX命令。它不关心你是用PyTorch训练还是用NumPy计算只关心你能不能在Shell里被| grep、被cron调度、被Ansible拉起、被Jenkins pipeline捕获返回码。所以别被“Agent”二字带偏——它和LangChain、LlamaIndex、AutoGen完全不在同一技术栈层级。它更接近clickargparse的工业化增强版但比二者更狠自动推导类型、自动注入环境变量绑定、自动捕获未处理异常并转为标准错误码如exit 123对应ValueError。你不需要改一行原始代码就能让一个纯逻辑函数具备生产级CLI的健壮性。这才是它在“github打不开”“python安装教程”满天飞的现实土壤里依然能被持续fork的真实原因它解决的不是技术前沿问题而是每天都在发生的、具体到每一行shell命令的交付窒息感。2. 拆解agent-reach wrap函数签名即契约CLI即APIagent-reach wrap是整个项目的核弹头。它不靠配置文件、不靠装饰器标记、不靠继承特定基类——它只依赖Python AST解析与运行时签名反射。当你执行agent-reach wrap script.py func_name它会做三件关键事2.1 静态AST扫描从源码中精准定位函数定义位置它不会import script.py避免副作用而是用ast.parse()加载源码文本遍历AST节点找到ast.FunctionDef中name func_name的节点。重点在于它严格校验该函数是否为顶层定义即不在class内、不在嵌套函数中。这是硬性约束因为CLI入口必须是可独立调用的纯函数。若你写的是class Detector: def predict(self, ...)它会直接报错Function predict is not at module level而不是尝试魔改。这个设计看似苛刻实则杜绝了90%的隐式依赖陷阱——比如self.model在__init__里初始化但CLI启动时根本没走__init__。我曾见过有人强行绕过此限制在函数里写detector Detector(); return detector.predict(...)。结果上线后发现每次CLI调用都重新加载模型权重内存暴涨。agent-reach的静态检查在此刻成了救命稻草它逼你把模型加载逻辑抽离为独立函数如load_model()再在主函数里显式调用。这反而促成了更清晰的职责分离。2.2 运行时签名反射将def f(a: int, b: str x)转为--a int --b str它调用inspect.signature(func)获取参数信息对每个参数做三重映射类型映射int→typeintfloat→typefloatbool→actionstore_true对无默认值的bool参数Optional[str]→nargs?默认值映射b: str x→defaultx且自动添加[default: x]到help文本文档字符串映射若函数有docstring第一行作为help描述Args:后的内容按参数名提取为详细说明最精妙的是对Union类型的支持。比如def process(data: Union[str, Path])它不会报错而是生成--data str_or_Path并在help中注明Accepts string path or pathlib.Path object。这背后是typing.get_origin()和typing.get_args()的深度运用而非简单字符串匹配。提示若你的参数类型用了from __future__ import annotations延迟注解agent-reach仍能正确解析因为它使用typing.get_type_hints(func, include_extrasTrue)而非func.__annotations__。2.3 参数透传机制--之后的所有内容原样传递给目标函数这是它区别于click的关键设计。click要求你预先声明所有参数而agent-reach允许你在CLI调用末尾加--其后所有token不经过解析直接以*args形式传入函数。例如agent-reach wrap utils.py run_pipeline --cli-name pipe -- --config prod.yaml --verboserun_pipeline函数定义为def run_pipeline(*args, **kwargs)那么[--config, prod.yaml, --verbose]会作为args传入。这使得它能无缝对接那些本身已接受sys.argv[1:]的遗留脚本无需任何改造。我用这个特性快速封装了一个老同事写的train.sh包装脚本——他习惯用getopt解析参数我把train.sh重写为Python函数def train_cli(*raw_args), 然后agent-reach wrap train.py train_cli --cli-name train从此train --lr 0.01 --epochs 100和train -- --lr0.01 --epochs100都能跑通平滑过渡零成本。3.agent-reach serve不是Web服务器而是CLI的进程守护协议agent-reach serve常被误认为是启动HTTP服务实际它是基于Unix Domain Socket的轻量IPC协议实现。它不监听TCP端口不依赖WSGI只创建一个.sock文件供其他进程通过socket.AF_UNIX连接。这意味着完全规避防火墙、端口占用、HTTPS证书等Web服务常见痛点进程间通信延迟低于1ms实测echo {func:predict,args:[/tmp/data.csv]} | nc -U /tmp/agent.sock可被systemd、supervisord原生管理支持优雅重启、内存限制、崩溃自动拉起它的协议极其简单客户端发送JSON-RPC 2.0格式请求服务端返回JSON-RPC响应。例如// 请求 {jsonrpc: 2.0, method: predict, params: [/data/20240612.csv], id: 1} // 响应 {jsonrpc: 2.0, result: {status: OK, anomalies: [12, 45]}, id: 1}关键在于serve模式下所有函数调用都在同一个Python进程内执行共享内存、缓存、模型实例。这解决了wrap模式每次调用都重启进程导致的冷启动问题。我们曾用它托管一个BERT微调模型的推理函数wrap模式单次预测耗时320ms含模型加载serve模式稳定在85ms模型常驻内存。但要注意serve模式要求所有被暴露的函数必须是线程安全的。agent-reach默认启用threading模式非multiprocessing因此若你的函数内部修改全局变量如global COUNTER必须自行加锁。它不提供自动同步这是刻意为之——把并发控制权交还给开发者避免黑盒带来的调试地狱。注意serve模式下--host参数实际指定Unix socket路径如--host /tmp/myagent.sock而非IP地址。若误填--host 127.0.0.1它会静默创建/tmp/127.0.0.1.sock而非报错。这是早期版本的一个设计妥协建议始终用绝对路径明确指定socket位置。4. MIT License下的工程化细节为什么它能在生产环境活下来MIT License常被误解为“随便用”但在agent-reach的代码库里License背后是严苛的工程纪律。翻看其setup.py和CI配置你能看到三个决定它能否在真实产线存活的关键设计4.1 零第三方运行时依赖仅依赖CPython标准库setup.py中install_requires[]为空pyproject.toml里[build-system]只声明setuptools和wheel。这意味着安装pip install agent-reach不会触发任何requests、click、typer的下载在嵌入式设备如ARMv7的工控机上只要Python 3.8可用就能直接pip install成功所有CLI功能参数解析、类型转换、错误码映射全部手写不借argparse的add_subparsers而是用sys.argv逐层解析这种“返璞归真”带来极致的确定性。某次我们部署到客户隔离内网pip源被禁但get-pip.py仍能离线安装agent-reach因为它的wheel包只有127KB不含任何二进制扩展。对比之下一个带numpy依赖的CLI工具在无网络环境下安装失败率超80%。4.2 错误码语义化exit code即业务状态码它严格遵循POSIX exit code规范并做了业务层映射0成功1通用错误如参数解析失败64Usage Errorargparse标准码对应--help或参数缺失70Software Error函数内抛出未捕获异常78Config Error配置文件读取失败更重要的是当函数抛出特定异常时自动映射exit code。例如def validate_config(path: str): if not Path(path).exists(): raise FileNotFoundError(fConfig {path} not found) # exit 78 if not path.endswith(.yaml): raise ValueError(Only YAML config supported) # exit 70运维同学只需anomaly-cli --config bad.json; echo $?就能根据返回码判断是配置路径错误78还是格式错误70无需解析stdout/stderr。这极大简化了监控脚本编写——Zabbix直接采集exit code阈值告警零日志解析成本。4.3 GitHub Release的二进制预编译绕过客户Python环境缺陷虽然核心是纯Python但它在GitHub Actions中为每个Release自动生成manylinux和win_amd64平台的standalone二进制。原理是pyinstaller --onefile打包但关键在于它打包时冻结了Python 3.9解释器而非依赖系统Python。这意味着在客户CentOS 6自带Python 2.6上anomaly-cli仍能运行在Windows Server 2012无管理员权限装Python上双击即可执行所有依赖如yaml解析均打包进二进制无ImportError风险我们曾用此特性救急客户数据库审计系统禁止安装任何Python包但允许执行白名单二进制。我们将agent-reach生成的anomaly-cli加入白名单从此每日巡检脚本从python check.py变成anomaly-cli --mode audit成功率从63%提升至100%。5. 踩坑实录那些文档没写的、但线上必遇的边界场景再好的工具落地时也逃不过现实世界的毒打。以下是我在三个不同客户现场踩出的坑以及agent-reach的应对逻辑5.1 问题函数返回pd.DataFrameCLI输出乱码且无法被jq解析现象def get_report() - pd.DataFrame:返回DataFrameCLI调用后输出一堆pandas.core.frame.DataFrame object at 0x...| jq .rows失败。根因分析agent-reach默认对返回值调用str()而pd.DataFrame.__str__()输出的是格式化表格文本非JSON。它不主动导入pandas也不做特殊序列化。解决方案在函数内显式序列化import json import pandas as pd def get_report() - str: # 改为返回str df pd.read_csv(report.csv) return df.to_json(orientrecords) # 输出JSON字符串或利用agent-reach的--output-format参数需v0.8.0agent-reach wrap report.py get_report --output-format json此时它会自动调用json.dumps(result)前提是result可JSON序列化。若含datetime需自定义json.JSONEncoder。经验永远假设CLI输出是给机器消费的而非人眼阅读。--output-format json应作为默认选项写入团队CLI规范。5.2 问题serve模式下函数内os.chdir()导致后续调用工作目录错乱现象A函数调用os.chdir(/tmp)B函数执行时open(config.yaml)报FileNotFoundError因为当前目录已被A函数修改。根因定位serve模式是单进程多线程os.chdir()修改的是进程级工作目录所有线程共享。修复方案强制函数内使用绝对路径或用contextlib.chdir临时切换from contextlib import contextmanager import os contextmanager def chdir(path): old_cwd os.getcwd() try: os.chdir(path) yield finally: os.chdir(old_cwd) def process_data(input_dir: str): with chdir(input_dir): # 退出with块后自动恢复 # 处理逻辑 passagent-reach不提供自动工作目录隔离这是设计选择——避免引入os.fork()或multiprocessing带来的复杂性。5.3 问题wrap模式下函数打印大量print()stdout被CLI框架截断现象函数内for i in range(1000): print(fStep {i})CLI只输出前100行后续丢失。排查链路先确认是否print()被缓冲加flushTrue无效 → 排除缓冲问题检查agent-reach源码发现其subprocess.run()调用时未设置stdoutsubprocess.PIPE而是直接继承父进程stdout实际是终端PTY缓冲区限制如stty size显示24 80超出屏幕行数后旧行被滚动丢弃终极解法用--output-file重定向agent-reach wrap long_task.py run --output-file /tmp/log.txt # 或管道到less agent-reach wrap long_task.py run | lessagent-reach的--output-file参数会接管stdout写入指定文件彻底规避终端缓冲。6. 生产就绪 checklist从PoC到SRE可用的七道关卡把agent-reach从玩具变成生产工具需通过以下七道验证。每道关卡都对应一个真实故障场景关卡验证项失败后果通过标准1. 环境漂移在客户最小化Docker镜像scratchPython 3.9中安装并运行pip install失败或运行时报ModuleNotFoundErrorpip install agent-reach agent-reach --version返回版本号无额外依赖报错2. 参数爆炸传入含空格、换行、单引号的字符串参数--input a b\ncdargparse解析错误或函数收到截断字符串agent-reach wrap test.py echo --input a b\ncd输出完整字符串3. 错误传播函数抛出OSError(13, Permission denied)CLI返回exit 1但错误详情丢失无法区分权限/磁盘满echo $?为13stderr包含OSError: [Errno 13] Permission denied4. 内存泄漏serve模式连续调用10000次监控RSS内存RSS持续增长最终OOM被killRSS波动在±5MB内无单调上升趋势5. 日志合规启用--log-level DEBUG检查日志是否含ISO8601时间戳、函数名、参数摘要日志无时间戳或敏感参数如--api-key xxx明文记录日志格式2024-06-12T14:22:33.123Z [INFO] predict(input_path/data/x.csv)且--api-key被自动掩码为--api-key ***6. 信号处理kill -15主进程检查是否等待当前请求完成再退出进程立即终止正在处理的请求被中断数据损坏进程接收SIGTERM后完成当前请求执行atexit清理再退出7. 二进制兼容在客户老旧glibc 2.12的RHEL6上运行预编译二进制./anomaly-cli: /lib64/libc.so.6: version GLIBC_2.14 not found二进制在ldd ./anomaly-cli | grep libc显示libc.so.6 (GLIBC_2.12)通过全部七关才意味着你可以把它写进SOP“所有Python数据处理脚本必须经agent-reach wrap封装后交付”。7. 不是终点而是CLI工程化的起点如何让它长出你的业务牙齿agent-reach的价值不在于它自身多强大而在于它为你提供了可编程的CLI基础设施底座。真正的生产力爆发点在于你基于它做的二次开发7.1 注入领域专用参数解析器默认的int/float/str类型太基础。我们为金融风控场景扩展了Amount类型from agent_reach.types import register_type register_type def parse_amount(value: str) - Decimal: Parse 100.5K or 2.3M to Decimal if value.endswith(K): return Decimal(value[:-1]) * 1000 if value.endswith(M): return Decimal(value[:-1]) * 1000000 return Decimal(value) # 使用时 def calculate_risk(amount: Amount, score: int): ...register_type装饰器会将其注入agent-reach的类型解析器--amount 5.2M自动转为Decimal(5200000.0)。7.2 构建CLI插件市场我们用importlib.metadata实现了插件机制# 安装插件 pip install agent-reach-plugin-s3 # 提供--s3-bucket参数 pip install agent-reach-plugin-database # 提供--db-url参数 # 插件自动生效 agent-reach wrap model.py predict --s3-bucket my-bucket --db-url postgres://...每个插件在pyproject.toml中声明[project.entry-points.agent_reach.plugins]agent-reach启动时自动扫描加载。这让我们不用改核心代码就能为不同客户定制CLI能力。7.3 生成OpenAPI文档agent-reach的函数签名是天然的API契约。我们写了agent-reach openapi model.py predict命令自动生成OpenAPI 3.0 JSON{ openapi: 3.0.0, paths: { /predict: { post: { parameters: [{name: input_path, in: query, schema: {type: string}}], responses: {200: {content: {application/json: {schema: {$ref: #/components/schemas/PredictionResult}}}}} } } } }这份文档可直接喂给Swagger UI让业务方前端工程师无需读Python代码就能调用后端CLI。最后分享一个真实体会上周客户提出需求“要一个命令能一键校验所有数据源连通性”。我花了17分钟写了check_sources.py里一个def check_all()函数然后agent-reach wrap check_sources.py check_all --cli-name>

相关新闻

Prompt-Tuning 原理与实战:从连续提示向量到轻量微调落地

Prompt-Tuning 原理与实战:从连续提示向量到轻量微调落地

简介:本资源是一份系统解读Prompt-Tuning技术的深度综述型学习材料,面向NLP算法工程师、AIGC方向研究者及大模型微调实践者,聚焦解决超大规模语言模型(如GPT-3、ChatGPT)在传统Fine-tuning中面临的语义鸿沟大、标注数据…

2026/10/15 9:03:31 阅读更多 →
JavaScript解构默认值陷阱与防御式编程实践

JavaScript解构默认值陷阱与防御式编程实践

1. 问题现象与背景解析第一次遇到这个问题是在去年重构一个老项目时。当时有个表单处理函数,设计时特意加了默认值:function formatUserData({ name 匿名, age 18 } {}) {// 数据处理逻辑 }测试时传了null值却直接报错,控制台显示Cannot d…

2026/10/15 9:03:31 阅读更多 →
算法面试通关指南:从底层逻辑到实战技巧的完整拆解

算法面试通关指南:从底层逻辑到实战技巧的完整拆解

1. 算法面试到底在考什么:从一道题看穿整场面试的底层逻辑聊算法面试之前,先把这个场景说透。很多人准备算法面试的方式是刷题,刷几百道,然后上场发现面试官问的题没见过,脑子一片空白。问题出在哪?出在没有…

2026/10/15 9:02:30 阅读更多 →

最新新闻

RetinaFace人脸检测与关键点定位工程实践指南

RetinaFace人脸检测与关键点定位工程实践指南

1. 为什么RetinaFace不是“又一个”人脸检测模型,而是工程落地的分水岭在某高校计算机视觉实验室带学生做毕业设计时,我连续三年遇到同一个问题:学生用YOLOv5或SSD跑通人脸检测后,一到实际场景就崩——遮挡、侧脸、低光照、小尺寸…

2026/10/15 9:41:37 阅读更多 →
Vue轻量级文档编辑器实现:基于Tiptap的Word功能集成

Vue轻量级文档编辑器实现:基于Tiptap的Word功能集成

1. 项目概述最近在重构公司内部的知识管理系统时,遇到了一个有趣的需求:需要在Vue项目中实现一个具备Word基础功能的文档编辑器。这个需求源于市场部门同事的反馈,他们经常需要在线协作编辑产品说明书,但现有系统只能提供基础的文…

2026/10/15 9:41:37 阅读更多 →
氢-氨混合能源系统优化与Matlab实现

氢-氨混合能源系统优化与Matlab实现

1. 项目背景与核心价值在能源结构转型的大背景下,氢-氨混合能源系统正成为学术界和工业界关注的热点。这种将氢气的高能量密度与氨气的易储存特性相结合的综合能源方案,为解决可再生能源间歇性问题提供了新思路。我在参与某工业园区微电网项目时&#xf…

2026/10/15 9:41:37 阅读更多 →
电子信息工程、通信工程、电气类面试试题大全:从背题到讲清楚

电子信息工程、通信工程、电气类面试试题大全:从背题到讲清楚

简介:这份资源面向电子信息工程、通信工程、电气类等专业的应届求职者,整理了技术面试中高频出现的基础知识点与笔试题,帮助读者在有限时间内系统梳理考点、查漏补缺。内容覆盖电路理论、模拟电子技术、数字电路与时序电路等方向,…

2026/10/15 9:41:37 阅读更多 →
OpenHarmony中React Native状态栏沉浸式实现方案

OpenHarmony中React Native状态栏沉浸式实现方案

1. 项目背景与需求解析在OpenHarmony生态中实现React Native应用的StatusBar沉浸式效果,是近期许多跨平台开发者关注的技术难点。作为一名在移动端开发领域深耕多年的工程师,我发现这个需求背后隐藏着三个关键挑战:OpenHarmony与Android/iOS系…

2026/10/15 9:41:37 阅读更多 →
RetinaFace Keras实现:人脸检测与5点关键点定位一体化方案

RetinaFace Keras实现:人脸检测与5点关键点定位一体化方案

1. 项目概述:为什么人脸检测与关键点定位必须“又快又准”最近在某高校实验室带一个图像处理Demo项目,学生反复问一个问题:“老师,我们做人脸识别前,总得先把脸框出来吧?可OpenCV的Haar级联太老了&#xff…

2026/10/15 9:40:37 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →