咕咕鸽爱学习
type: channel
link: https://blog.bitday.top/
description: Your description here.
items: Cursor使用
items: deepwalk
items: 移动模型
items: K8S
items: CICD
items: 训练神经网络
items: 草稿
items: RAG知识库
items: 拼团设计模式
items: 测试

Cursor使用
type: item
date: 2025-10-29T11:45:02+08:00
description: Cursor 编辑器界面 ┌────────────────────────────────────────────┐ │ 顶部菜单栏（File / 编辑 / 选择 / 查看...）│ ├────────────────────────────────────────────┤ │ 左侧侧边栏（文件树 / 项目 / Git 等） │ ├────────────────────────────────────────────┤ │ 中间主编辑区（代码编辑） │ ├────────────────────────────────────────────┤ │ 右侧 AI 面板（Cursor 智能助手 / Chat） │ ├────────────────────────────────────────────┤ │ 底部状态栏（分支 / 文件类型 / 行列信息等） │ └────────────────────────────────────────────┘ 如何使用 Cursor 的 AI 功能 功能 作用 快捷键（默认） 🧠 Inline Edit 选中一段代码 → Ctrl + K（或右键 “Ask Cursor”）→ 输入自然语言指令（如“优化正则表达式”） Ctrl + K 🤖 Agent 面板 打开一个“聊天窗口”，直接和 Cursor 对话（如“帮我写个登录验证函数”） Ctrl + I ✨ Tab 补全 在代码中输入时，Cursor 自动预测后续内容 Tab 🔁 重新生成建议 当灰色提示出现但不理想时，按 `Alt + ``（或右键 “Regenerate”） `Alt + `` 选择一段代码+CTRL+K 修改指定的代码，直接在代码编辑区弹出修改窗口调用大模型。CTRL+ENTER 或者鼠标点击 应用修改 CTRL+N 或者 **鼠标点击 **拒绝修改 CTRL+I 1）图中设置的Auto表示自动选择模型； 2）@ 可以添加文件、文件夹到当前对话上下文，如果你在代码编辑区选择一段代码再 CTRL+I 或者 CTRL+L，也会自动将它添加进来。还可以直接拖拽资源管理器中的文件到AI对话框中。 3）+Browser 模式可以让模型看到整个项目文件 任务 你可以直接问 Cursor 找函数定义 “verifyPassword 函数定义在哪个文件？” 查找引用 “verifyCode 被调用了多少次？” 理解架构 “帮我总结整个项目的模块结构。” 改代码 “把所有 JS 文件里的 var 改成 let。” 生成文档 “根据这个项目代码生成一份 README。” 4）对话模式 Agent模式，默认的对话模式，功能最全，AI 不仅能回答，还会“主动思考、规划和执行”。可以理解为：“帮我干活”的模式。 Plan 模式，它可以浏览整个项目文件，但不会直接改代码，而是会：把你的需求拆分成多个步骤；告诉你“下一步该干什么”；有时生成一份修改计划或脚本方案。 Ask 模式：问答模式，和网页版使用大模型一样。 TAB 一般注释起手，如果出现灰色预测文字时，直接 Tab 就能接受 AI 自动补全 ，按ESC可以拒绝这个建议；否则就是普通的缩进。 触发逻辑 传统 IDE（比如 VS Code、IntelliJ） 的补全是词法或语法级触发： 你输入 “pri” → 提示 “print()”； 它只是基于关键字匹配。 而 Cursor 的补全 是“语义级”的： AI 根据上下文 推断你下一步可能在做什么。 它会综合考虑： 当前光标前后的代码； 注释 / 函数签名； 文件名； 项目中的其他定义； 甚至最近你在这个 Tab 里做的事。 阶段 触发动作 AI 响应 检测阶段 监听输入变化（按键、换行、注释等） 分析上下文语义树（AST） 预测阶段 生成“意图向量” 模型推断用户下一步目标 展示阶段 在光标后显示灰色 ghost text 等待你按 Tab 接受 触发时机 类型 触发条件 示例 行为 函数触发 输入 function / def function check... 预测参数和函数体 控制语句触发 输入 if / for 等 if (phone) 预测条件或逻辑块 注释触发 输入 //、#、/** // 校验邮箱格式 按注释生成实现 模板触发 class / import / try class User 预测类体、导入内容 上下文模仿 类似已有代码块 第二个函数定义 模仿风格 文件结构触发 同名模块、utils utils. 补出函数名 空行预测 新行、缩进后 空一行 猜测下一个合逻辑语句 Index&Docs Codebase Indexing（代码索引）： Cursor 会扫描整个项目文件夹； 提取文件路径、函数定义、类名、依赖关…

deepwalk
type: item
date: 2025-09-20T22:03:49+08:00
description: DeepWalk DeepWalk 的最终目标是—— 把图中的每个节点，用一个低维向量表示（embedding）出来，使得结构相似的节点在向量空间中也接近。 也就是说，如果两个节点在图上经常“一起出现”（相连、同社群等），那它们的 embedding 也应该相似。 主要思想 将图结构转化为“序列语料”： 在图上做 随机游走（random walks），生成顶点序列，类似于自然语言中的“句子”。 将随机游走得到的序列输入 Skip-Gram 模型，学习节点的低维嵌入表示。 学到的嵌入能捕捉到 邻居相似性、社区结构，可用于分类、聚类、链路预测等任务。 输入 & 输出 输入：图结构 $G=(V,E)$，随机游走参数（步长 $t$，次数 $\gamma$，窗口大小 $w$），嵌入维度 $d$。 输出：节点嵌入矩阵 $\Phi \in \mathbb{R}^{|V|\times d}$。 关键公式与目标 随机游走生成“句子”： 从某个顶点 $v_i$ 出发，采样一个长度为 $t$ 的随机游走序列： $$ W_{v_i} = (v_i, v_{i+1}, \dots, v_{i+t}) $$ 生成的序列 $W_{v_i}$ 就是一句“话”，用来训练 Skip-Gram 模型。在这些序列中，如果两个节点经常在相邻位置出现，就表示它们关系密切。 ["A", "B", "C", "D"] Skip-Gram 目标函数： 现在我们用 Word2Vec 的思想：对于一句话 ["A", "B", "C", "D"]，假设窗口大小 $w = 1$，也就是每个节点只看它的邻居。那么训练样本是这样的： 中心节点 它要预测的邻居 A B B A, C C B, D D C 模型要学的是： “给我节点 B，我要能预测出 A 和 C。” “给我节点 C，我要能预测出 B 和 D。” 于是就有这个公式，给定中心节点 $v_i$，最大化其上下文窗口内邻居节点的条件概率： $$ \max_{\Phi} \sum_{i=1}^{|V|} \sum_{u \in \mathcal{N}_w(v_i)} \log Pr(u \mid \Phi(v_i)) $$ 其中 $\mathcal{N}_w(v_i)$ 表示在随机游走序列中，窗口大小 $w$ 内的上下文节点。 我希望模型能学到这样一种 embedding：中心节点 $v_i$ 能够高概率预测出它周围的邻居 $u$。 优化形式（负对数似然）： 就是把上面的最大化目标，改写成一个最小化损失函数。 最大化“好事”（邻居出现的概率）= 最小化“坏事”（邻居预测错误的概率） $$ \min_{\Phi} - \log Pr\big( {v_{i-w},\dots,v_{i+w}} \mid \Phi(v_i) \big) $$ 概率建模（Hierarchical Softmax 或 Negative Sampling）： $$ Pr(u \mid \Phi(v_i)) = \frac{\exp\big( \Phi(u) \cdot \Phi(v_i) \big)}{\sum_{v \in V} \exp\big( \Phi(v) \cdot \Phi(v_i) \big)} $$ 这相当于用 Softmax 把所有节点的相似度转成概率分布。 其中： 分子：中心节点和邻居节点的相似度（点积越大越相似）； 分母：所有节点的相似度和（用来归一化成概率）。 ​ 如果 $u$ 是 $v_i$ 的邻居，那么 $\Phi(u)$ 与 $\Phi(v_i)$ 的点积就应更大。 例子 想象你是个“社交分析师”： 你观察到小明每天都和小红、小刚一起出现； 而小明几乎从不和小李在一起； 那你自然会说：小明和小红、小刚的关系更近。 DeepWalk 就是通过“随机游走 + 预测邻居”这个机制， 自动学出“谁跟谁关系近”的数值表示。 训练逻辑 1）加载 10+1 张图 A_list = [A100, A101, ..., A110] 我们取前 10 张作为输入，最后一张作为真实标签。 2）对每一个时间步的图做 DeepWalk for t in range(100, 110): emb_t = DeepWalk(A_t) 每张图 $A_t$ 都独立训练一个 节点 embedding（比如 400×64）。 400是节点数，64是嵌入维数 embedding 就是每个节点在这一时刻的“语义坐标”。 训练目标是：让在图里常相邻的节点在 embedding 空间也靠得近。 可以理解成： DeepWalk 把图结构变成“节点的向量表示”。 3）拼接成时间序列特征（10步） 对每对节点 (i, j)，你把过去10个时间步的 embedding 拿出来，计算每步的 …

移动模型
type: item
date: 2025-09-20T22:03:00+08:00
description: 移动模型 RWP（Random Waypoint，随机路标） 空间与时间： 在一个正方形活动区域 $[0,R]\times[0,R]$ 内，离散为 steps 个时间步。 节点运动规则： 初始位置：每个节点在区域内均匀随机选一个起点。 选目标点：从区域内均匀随机再选一个目标点（下一路标）。 速度：对该段路程，从区间 $[v_{\min}, v_{\max}]$ 均匀采样一个速度（以“每步移动的距离”计）。 运动轨迹：用直线匀速插值从当前点走到目标点，按需要的步数填充每个时间步的坐标。 停留：到达目标后，停留 pause_steps ~ U[pause_min, pause_max]（整数步）。 循环：停留结束后再选一个新的随机目标点，重复 3–5。 输出轨迹： 把每个时间步所有节点的 $(x,y)$ 位置拼成矩阵 $Y\in\mathbb{R}^{\text{steps}\times 2N}$。 邻接生成（通讯图）： 对每个时间步，任意两节点距离 $\le$ 通讯半径 comm_radius 则记为一条无向边（1），否则为 0，得到一组对称的 0/1 邻接矩阵序列。 要点：RWP 的目标点在区域内+“可停留”，因此轨迹呈 跳点—直线—驻留的节奏。 RW（Random Walk，随机游走） 空间与时间： 活动区域仍是边长 $R$ 的正方形（或你实现里也支持圆形采样作为初始点）。离散 steps。 节点运动规则： 初始位置：在活动区域内随机取一个点作为起点。 目标点：每次从一个随机边界点或区域内随机点中挑一个当目标（你的实现是 5 种可能：四条边上的均匀点或区域内随机点）。 速度：每段从 $[v_{\min}, v_{\max}]$ 均匀采样一个速度。 运动轨迹：按直线匀速插值走向目标。 无停留：到达目标立即选择下一目标继续走（不驻留）。 循环：重复 2–4。 邻接生成： 与 RWP 相同，以 comm_radius 做阈值逐步形成 0/1 邻接矩阵。 要点：RW 版本不设停留，且目标点常在边界，轨迹更“连续流动”，在边界附近来回穿梭的概率更高。 RD（Random Direction，随机方向） 空间与时间： 同样是正方形区域与离散时间。 节点运动规则： 初始位置：从边界上均匀随机选一个起点（四条边等概率）。 目标点：每段都从边界再均匀随机选一个新的边界点当目标（边界→边界）。 速度：每段速度 $[v_{\min}, v_{\max}]$ 均匀采样。 运动轨迹：直线匀速插值到目标。 停留：到达目标后停留 pause_steps ~ U[pause_min, pause_max] 步。 循环：继续从目标（边界点）出发，选下一个边界点为新目标。 邻接生成： 同上，按 comm_radius 阈值逐步构造邻接矩阵序列。 要点：RD 强化了边界—边界往返与停留，节点会频繁在边缘聚集、驻留，再切换到另一边。 Gaussian Markov Mobility（高斯-马尔科夫移动模型） 空间与时间： 在矩形区域 $[x_{\min}, x_{\max}] \times [y_{\min}, y_{\max}]$ 内，离散为多个时间步。 节点运动规则： 初始状态：每个节点随机生成位置 $(x,y)$，速度 $v \sim U(0.5, v_{\max})$，方向 $\theta \sim U(0,2\pi)$。 速度更新： $v_t = \alpha v_{t-1} + (1-\alpha)\mu_v + \sqrt{1-\alpha^2},\varepsilon_v,$ 其中 $\mu_v$ 是全局平均速度，$\varepsilon_v \sim \mathcal{N}(0,\sigma_v^2)$。 方向更新： $\theta_t = \alpha \theta_{t-1} + (1-\alpha)\mu_\theta + \sqrt{1-\alpha^2},\varepsilon_\theta,$ 其中 $\mu_\theta$ 是平均方向，$\varepsilon_\theta \sim \mathcal{N}(0,\sigma_\theta^2)$。 位置更新： $x_t = x_{t-1} + v_t \cos\theta_t, \quad y_t = y_{t-1} + v_t \sin\theta_t$ 边界处理：若节点越界，则进行反射，即位置镜像回区域内，同时方向在对应维度取反。 循环：重复步骤 2–5，生成连续轨迹。 邻接生成： 同前，设定通信半径 comm_radius，每个时间步任意两节点距离 ≤ 半径则连边，得到动态邻接矩阵序列。 要点： 参数 $\alpha$ 决定轨迹的平滑度/惯性： $\alpha \to 1$：…

K8S
type: item
date: 2025-09-08T21:56:23+08:00
description: Kubernetes (K8S) Kubernetes 是一个开源的容器编排平台，用于自动化部署、扩缩容（Pod 数量多了/少了自动调整）和自愈（坏掉的 Pod 会被自动重建） 基本架构 一个 Kubernetes 集群 (Cluster) = 控制平面 + 工作节点 的组合。要使用K8S，要先搭建集群，deployment.yaml 和 service.yaml 要提交到 K8S 集群，由它调度和运行。 控制平面 (Control Plane) 负责管理整个集群，不直接跑应用。 组件 作用 比喻 API Server 接收命令（kubectl）、提供统一接口 前台服务员 etcd 存储集群所有状态（配置、Pod 列表等） 账本/数据库 Scheduler 决定 Pod 跑在哪个 Node 上 领班 Controller Manager 保证实际状态符合预期（补 Pod、重建失败的 Pod） 经理 工作节点 (Worker Nodes) 实际跑应用容器。 组件 作用 Kubelet 负责跟 API Server 沟通，并启动/管理容器 容器运行时 运行容器（Docker、containerd） Kube-Proxy 管理网络规则，实现 Service 的负载均衡 graph TD A[控制平面] --> B[Node 1] A --> C[Node 2] A --> D[Node 3] B --> E[Pod] B --> F[Pod] C --> G[Pod] D --> H[Pod] K8S 核心概念 Pod 最小运行单元，一个 Pod 里可以有 1 个或多个容器。 共享网络和存储空间 Deployment 管 Pod 的「副本数」和「版本」。 支持滚动更新、回滚 Service 提供稳定的网络入口（因为 Pod IP 会变）。 负载均衡到一组 Pod。 ConfigMap & Secret ConfigMap：存储配置信息（非敏感）。 Secret：存储敏感信息（密码、Token），会加密。 基本使用方式 Deployment（定义 Pod 模板 + 副本数） apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 3 # 要 3 个 Pod selector: matchLabels: app: my-app template: # Pod 模板 metadata: labels: app: my-app #给 Pod 打标签，Service 用 selector 找到这些 Pod 做负载均衡 spec: containers: - name: my-app #Pod名 image: my-registry/my-app:v1 # ← 指向 CI 推送后的镜像（仓库/名称:标签） ports: - containerPort: 8080 #容器对外提供服务的端口 Pod名可能是：my-app-6f7c9d7c5d-abcde，它里面的容器名：my-app 映射关系： kind: Deployment → 创建一个「Pod 管理器」 replicas: 3 → 保证始终有 3 个 Pod template → Pod 的样子（运行哪个镜像、开哪个端口） Service（提供统一访问入口） apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-app # 找到所有带 app=my-app 标签的 Pod ports: - port: 80 # Service 入口端口 targetPort: 8080 # Pod 里容器的端口 type: LoadBalancer # 暴露给外部访问 映射关系： selector → 绑定到 Deployment 创建的 Pod，根据 Pod 的标签（my-app） ports → 用户访问 80 端口，会转发到 Pod 的 8080 type: LoadBalancer → 提供一个外部 IP 供用户访问 典型工作流程 sequenceDiagram 开发者->>Git: 提交代码 Git->>CI/CD: 触发构建 CI/CD->>镜像仓库: 构建Docker镜像 CI/CD->>K8S: kubectl apply K8S->>K8S: 创建/更新Pod K8S->>K8S: 健康检查 K8S->>用户: 服务可用 sequenceDiagram 开发者->>API Server: kubectl apply -f xxx.yaml API Server->>etcd: 写入期望状态 …

CICD
type: item
date: 2025-09-06T11:28:21+08:00
description: CI/CD 自动部署项目 使用Gitea Actions 1）启用Gitea Actions： 编辑你的Gitea服务器配置文件 app.ini（通常位于 /etc/gitea/或 Gitea 安装目录），添加： [actions] ENABLED = true 然后重启Gitea服务。 2）在部署服务器上安装Runner： # 1. 下载并安装 act_runner (需要sudo) sudo wget https://gitea.com/gitea/act_runner/releases/download/v0.2.10/act_runner-0.2.10-linux-amd64 -O /usr/local/bin/act_runner sudo chmod +x /usr/local/bin/act_runner # 2. 为Runner创建专用工作目录（推荐使用绝对路径） sudo mkdir -p /opt/gitea-runner sudo chown $USER:$USER /opt/gitea-runner # 将目录所有权给当前用户 cd /opt/gitea-runner # 3. 注册Runner（重要：必须添加labels标签） act_runner register --no-interactive \ --instance https://你的gitea域名.com \ --token <你的令牌> \ --name my-runner \ --labels self-hosted,linux # 这个标签必须与工作流文件中的runs-on匹配 # 4. 启动Runner（后台运行） nohup act_runner daemon > runner.log 2>&1 & # 5. 查看运行状态和日志 tail -f runner.log ps aux | grep act_runner 3）令牌获取： 如果你想给整个实例用 → 站点管理员设置 → Actions → Runners。 如果只想给某个仓库用 → 进入该仓库 → Settings → Actions → Runners。 点击 New Runner，系统会生成一个 TOKEN。 例如：abcdef1234567890 还是设置整个实例好！！ 4）将act_runner注册为服务自启动 sudo vim /etc/systemd/system/act_runner.service 写入以下内容： [Unit] Description=Gitea Actions Runner After=network.target [Service] ExecStart=/usr/local/bin/act_runner daemon WorkingDirectory=/opt/gitea-runner User=zy123 Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ExecStart 指向你安装的 act_runner 路径（你已经放在 /usr/local/bin/ 了）。 WorkingDirectory 可以写你打算存放 Runner 缓存的目录（比如 /home/zy123/act_runner，你已经在这里 register 过了）。 User=zy123 保证 Runner 以你当前用户运行，而不是 root。 重新加载 systemd 配置： sudo systemctl daemon-reexec 启动并开机自启: sudo systemctl enable --now act_runner 查看运行状态: systemctl status act_runner 5）在后端仓库根目录下，新建目录和文件： .gitea/workflows/deploy.yml 写入以下内容： name: Deploy Backend on: push: branches: [ "master" ] # master 分支推送时触发 jobs: build-and-deploy: runs-on: self-hosted steps: - name: Checkout code uses: actions/checkout@v3 - name: Create application-local.yml run: | mkdir -p src/main/resources/ cat << 'EOF' > src/main/resources/application-local.yml ${{ secrets.APPLICATION_LOCAL_YML }} EOF - n…

训练神经网络
type: item
date: 2025-08-31T22:22:27+08:00
description: 🧠 神经网络训练流程基础笔记 1. 数据集（Dataset） 数据集包含了 样本 (sample) 和 标签 (label) 在你的场景里： 样本 = 一个时间步的图（节点特征矩阵 + 邻接矩阵） 标签 = 每个节点是否掉线（0/1） 2. Batch（批量） Batch = 一次训练用到的一小部分样本 batch_size 表示 每次梯度更新时用多少个样本 例如： 数据集有 1000 个样本 batch_size=8 → 每次训练只拿 8 个样本来算梯度 这样能减少显存占用，也让模型更新更频繁 3. Epoch（轮次） Epoch = 把整个数据集完整训练一遍 如果： 数据集有 1000 个样本 batch_size=8 那么 1 个 epoch 需要 1000 / 8 = 125 次迭代，才能用完所有样本 训练 20 个 epoch，就相当于把数据重复“看”了 20 遍 4. 训练循环流程 一次完整训练过程一般是这样： 初始化模型参数（随机权重） 重复若干 epoch 打乱训练数据 按 batch_size 切成小批次 对每个 batch： 前向传播 (forward) 把输入样本丢进模型 得到预测结果 计算损失 (loss) 预测 vs 真实标签 的差距 反向传播 (backward) 自动求导，算出梯度 参数更新 (step) 用优化器（SGD/Adam）更新参数，让模型预测更接近标签 最终得到训练好的模型 5. 为什么要用 batch？ 全量训练 (batch_size=1000) 优点：精确 缺点：显存占用大，更新慢 小批量训练 (batch_size=8~32) 优点：节省显存，更新更频繁，收敛快 缺点：梯度有点“噪声”（但通常能帮助模型泛化） 👉 所以主流方法是 小批量训练 + 多个 epoch。 6. 直观理解 把训练比作 学生背单词： 样本 = 单词 batch_size = 一次背多少个单词（8 个单词一组，还是 50 个单词一组） epoch = 把词表完整过一遍（1000 个单词都背一遍） 多个 epoch = 重复背很多遍（记得更牢） 7. 在你现在的任务中 数据：1000 时间步 batch_size=8 → 一次训练 8 个时间步的图 epochs=20 → 每个时间步都要用到，整个过程重复 20 遍 总共更新参数的次数 = 1000/8 * 20 = 2500 次 📌 一句话总结： 训练神经网络 = 前向传播（算预测） + 损失函数（算误差） + 反向传播（算梯度） + 参数更新（优化器） 重复这个过程，按 batch 分批喂数据，按 epoch 控制重复多少轮。

草稿
type: item
date: 2025-08-29T09:13:51+08:00
description: 非常好的问题 💡 你抓住了 FMI 的一个关键弱点：它对类不平衡（尤其是“大簇 vs 小簇”）敏感。 我给你一个非常直观的小例子（带数字），让你一步就理解为什么大簇会“主导”FMI 的结果。 🧩 一、背景 FMI 衡量“延迟聚类是否正确识别真实的同簇节点对”。 它在计算时看的是： $\text{Precision} = \frac{TP}{TP + FP}, \quad \text{Recall} = \frac{TP}{TP + FN}$ 其中 TP、FP、FN 都是在节点对级别计算的。 而节点对的数量和簇大小密切相关！ 一个簇有 $n$ 个节点，它内部的节点对数量是： n(n−1)2\frac{n(n-1)}{2} 也就是说，大簇里的“同簇节点对”远远多于小簇。 所以 大簇错误一点点，FMI 会掉很多；小簇错一大片，FMI 变化反而不大。 🧮 二、具体例子：两种簇结构 假设我们有 10 个节点： 簇类型 节点 簇大小 内部节点对数 大簇 A, B, C, D, E, F, G, H 8 $\frac{8×7}{2} = 28$ 小簇 I, J 2 $\frac{2×1}{2} = 1$ 总同簇节点对 — — 29 对 可见： 👉 只有 1/29 ≈ 3.4% 的“真实同簇节点对”来自小簇。 🚀 三、聚类情况对比 我们比较两种延迟聚类结果： ✅ 情况 1：只错了小簇 延迟聚类： (A–H 在一起)，(I)、(J) 也就是： 大簇 8 个节点保持完美； 小簇被拆散成两个单独节点。 统计： TP（正确识别的同簇节点对）= 28（全部来自大簇） FN（漏掉的同簇节点对）= 1（小簇 I–J） FP（错误合并的节点对）= 0 计算： $Precision = 28/(28+0)=1.0, \quad Recall = 28/(28+1)=0.9655$$FMI = \sqrt{1.0 × 0.9655} ≈ 0.9826$ → FMI ≈ 0.98，非常高！ 尽管你其实完全错了小簇。 ❌ 情况 2：大簇错了一点 延迟聚类： (A–E 在一起)，(F–H)、(I,J) 也就是： 大簇被拆成两部分； 小簇正确。 统计： 大簇内部正确识别的节点对： A–E：$10$ 对 F–H：$3$ 对 实际大簇原有 $28$ 对 → 漏掉 $15$ 对 TP = 10 + 3 + 1(小簇)=14 FN = 15（漏掉的大簇内部关系） FP = 0（没有错误合并） 计算： $Precision = 14/(14+0)=1.0, \quad Recall = 14/(14+15)=0.4827$$FMI = \sqrt{1.0 × 0.4827} ≈ 0.694$ → FMI ≈ 0.69，骤降！ 虽然你只是把大簇分裂了一点点。 📊 四、比较结果 情况 错误类型 FMI 实际错误影响 ✅ 情况 1 小簇完全错 0.98 几乎没影响 ❌ 情况 2 大簇拆错一半 0.69 FMI 急剧下降 💡 五、结论直觉化 观察 含义 大簇内部有很多节点对（比如 28 对） → 错一部分会影响大量 TP/FN 计数 小簇内部节点对极少（1 对） → 即使错了也几乎不影响 FMI FMI 是基于“所有节点对”的全局比例 → 大簇权重大，小簇权重极小 所以我们说： FMI 对类不平衡（簇大小差异）敏感。 FMI 的高低主要反映“大簇聚类的一致性”，小簇的错误被“淹没”。 ✅ 六、一句话总结 在 FMI 中，大簇内部节点对的数量多得多， 导致它们在计算中权重更大。 因此 FMI 更能反映“大簇聚类的好坏”， 而忽略“小簇是否聚错”。 是否希望我帮你扩展这个例子写成一段 Python 演示代码？ 我可以打印出每种情况下的 TP/FP/FN/FMI，让你直接运行看到这两个场景 FMI 变化的数值差异。

RAG知识库
type: item
date: 2025-08-19T22:31:18+08:00
description: Spring AI + Ollama 1. Ollama 定位：本地/容器化的 大模型推理服务引擎 作用：负责加载模型、执行推理、返回结果 支持的模型：Qwen、DeepSeek、nomic-embed-text（embedding 模型）等 交互方式：REST API（默认 http://localhost:11434） ollama run qwen2.5:7b-instruct 2. Spring AI 定位：Spring 官方推出的 AI 接入框架 作用：统一封装对各种 AI 服务的调用逻辑，让开发者更容易接入（OpenAI、Ollama 等） 关键点 OllamaChatModel：封装了调用 Ollama 的对话接口 OllamaOptions：指定模型、参数（温度、上下文大小等） PgVectorStore：对接向量数据库（Spring AI 提供的默认向量数据库适配器。） TokenTextSplitter：默认的文本切分器 （Spring AI 内置逻辑） 3.pgVectorStore pgVectorStore 是 Spring AI 提供的向量存储接口实现，底层基于 PostgreSQL + pgvector 插件。它在项目中的作用： 1）存储向量和元数据： pgVectorStore.accept(splits); 这行代码会： 1.将 splits 中每个 Document 的 text → 调用 embedding 模型 → 生成向量 2.将生成的向量、原始文本、以及文档元数据统一存入数据库表（默认表名：vector_store）； embedding：存储生成的向量； content：存储原始文本内容； metadata：以 JSONB 形式存储元数据。 2）检索时自动生成 SQL： List<Document> documents = pgVectorStore.similaritySearch(request); 在执行检索时，pgVectorStore 会自动生成 SQL 查询， 解析查询请求中的文本； 生成查询向量； 自动构造 SQL（结合 pgvector 的 <-> 向量相似度运算符）； 按相似度排序返回最相关的文档列表。 进一步地，结合 filterExpression（例如 metadata->>'knowledge' = 'xxx'）可在相似度计算的基础上进一步进行条件过滤。 配置 ai: ollama: base-url: http://ollama:11434 #告诉 Spring AI 去 http://ollama:11434 调用模型接口。 embedding: options: num-batch: 512 #批处理参数 model: nomic-embed-text #指定使用的 embedding 模型 rag: embed: nomic-embed-text 注意，需要提前下载模型： ollama pull deepseek-r1:1.5b ollama pull qwen2.5:7b-instruct ollama pull nomic-embed-text ollama list Docker如何开启GPU加速大模型推理 巨坑！ 默认是CPU跑大模型，deepseek1.5b勉强能跑动，但速度很慢，一换qwen2.5:7b模型瞬间就跑不动了，这才发现一直在用CPU跑！！ 如何排查？ 1.查看ollama日志： load_backend: loaded CPU backend from /usr/lib/ollama/libggml-cpu-alderlake.so 2.本地cmd命令行输入，查看显存占用率。 nvidia-smi | 0 NVIDIA GeForce RTX 4060 ... WDDM | 00000000:01:00.0 On | N/A | | N/A 58C P0 24W / 110W | 2261MiB / 8188MiB | 6% Default | 设备状态： RTX 4060显卡驱动（576.02）和CUDA 12.9环境正常 当前GPU利用率仅6%（GPU-Util列） 显存占用2261MB/8188MB（约27.6%） 可见模型推理的时候压根没有用GPU！！！ 解决 参考博客：1-3 Windows Docker Desktop安装与设置docker实现容器GPU加速_windows docker gpu-CSDN博客 1）配置WSL2，打开 PowerShell（以管理员身份运行），执行以下命令： wsl --install -d Ubuntu # 安装 Linux 发行版 wsl --set-default-versi…

拼团设计模式
type: item
date: 2025-08-11T21:40:45+08:00
description: 设计模式 单例模式 懒汉 注意，单例模式的构造函数是私有的！ public class LazySingleton { private static volatile LazySingleton INSTANCE; private LazySingleton() {} public static LazySingleton getInstance() { if (INSTANCE == null) { // 第一次检查 synchronized (LazySingleton.class) { if (INSTANCE == null) { // 第二次检查 INSTANCE = new LazySingleton(); } } } return INSTANCE; } } 第一次检查：防止重复实例化、以及进行synchronized同步块（防止每次加锁的开销）。 第二次检查：防止有多个线程同时通过第一次检查，然后依次进入同步块后，创建N个实例。 volatile：防止指令重排序。 instance = new LazySingleton(); 正确顺序是： 1️⃣ memory = allocate(); // 分配内存 2️⃣ ctorInstance(memory); // 调用构造函数，初始化对象 3️⃣ INSTANCE = memory; // 将对象引用赋值给 INSTANCE 由于 JVM 和 CPU 都可能对指令进行优化重排，步骤 ② 和 ③ 的顺序可能被交换！ 1️⃣ memory = allocate(); // 分配内存 3️⃣ INSTANCE = memory; // 把引用赋给 INSTANCE（但未初始化完） 2️⃣ ctorInstance(memory); // 调用构造函数 线程 A刚执行完赋值（3），但没调用构造函数；此时线程B来了，发现 INSTANCE != null，直接返回这个未初始化完成的对象！！！ 饿汉 public class EagerSingleton { // 类加载时就初始化实例 private static final EagerSingleton INSTANCE = new EagerSingleton(); // 私有构造函数 private EagerSingleton() {} // 全局访问点 public static EagerSingleton getInstance() { return INSTANCE; } } 工厂模式 简单工厂 // 产品接口 interface Product { void use(); } // 具体产品A class ConcreteProductA implements Product { @Override public void use() { System.out.println("使用产品A"); } } // 具体产品B class ConcreteProductB implements Product { @Override public void use() { System.out.println("使用产品B"); } } class SimpleFactory { // 根据参数创建不同的产品 public static Product createProduct(String type) { switch (type) { case "A": return new ConcreteProductA(); case "B": return new ConcreteProductB(); default: throw new IllegalArgumentException("未知产品类型"); } } } public class Client { public static void main(String[] args) { // 通过工厂创建产品 Product productA = SimpleFactory.createProduct("A"); productA.use(); // 输出: 使用产品A Product productB = SimpleFactory.createProduct("B"); productB.use(); // 输出: 使用产品B } } 缺点：添加新产品需要修改工厂类（违反开闭原则） 抽象工厂 抽象工厂模式是一种创建型设计模式，它提供一个接口用于创建相关或依赖对象的家族，而不需要明确指定具体类。 // 抽象产品接口 interface Button { void render(); } interface Checkbox { void render…

测试
type: item
date: 2025-07-31T00:10:03+08:00
description: 测试 小明今天15岁了，它是天水小学上学。