跳到主要内容

Windows VSCode 调用 WSL 中的 Hermes Agent 实战

· 阅读需 9 分钟

背景

这套组合的出现有一个很现实的理由:

  • VSCode 是 Windows 上最好的编辑器之一,生态丰富,Remote 插件体系成熟
  • WSL 提供了完整的 Linux 开发环境,项目依赖、脚本、网络工具链都在 WSL 里
  • Hermes Agent 跑在 Linux 上最顺畅,它需要访问项目的 Git 历史、文件结构、终端环境

所以很自然的,你会想让 VSCode 连进 WSL,然后在编辑器里直接和 Hermes 交互——写完代码让它审,遇到问题让它查,重构代码让它帮。

这篇文章就讲清楚这条路怎么打通,以及打通之后能怎么用。

HyperFrames 视频脚本:GB200 NVL72 — 一台 300 万美元的 AI 机柜,钱到底花在哪?

· 阅读需 41 分钟

本文是一份完整的 HyperFrames 时间线视频制作脚本 + 实际生成记录。前半部分为逐帧镜头设计和生图 Prompt,后半部分记录了用 edge-tts + Pillow + ffmpeg 纯代码生成视频的全过程(含踩坑)。成品 1080p / 3m51s / 7.5MB,带 TTS 配音和硬字幕。


视频总览

  • 时长:实际 231 秒 / 3 分 51 秒(28 个镜头,TTS 中速朗读), 理想压缩后可到 2 分钟
  • 风格:HyperFrames 快节奏数据可视化 + 产品特写 + 动态图表
  • 配音:edge-tts zh-CN-YunxiNeural 男声,rate +10%
  • 字幕:底部中文字幕,SRT 硬字幕(微软雅黑)
  • 画面:Pillow 代码信息图(可替换为 GPT Image 2 / Midjourney 出图升级)
  • BGM:暂无(可后期加入科技感电子乐垫底)

成本分解总表(核心数据)

组件数量单价(估算)小计占比
GB200 Superchip (1 Grace + 2 B200)36$60K-$70K$2.16M-$2.52M~72-78%
NVLink 5 Switch 交换盘18$12K-$15K$216K-$270K~7-9%
液冷散热系统 (DLC/CDU)1 套$80K-$120K$80K-$120K~3-4%
ConnectX-8/7 网卡 + Spectrum-X 交换机36 NIC + 交换机整套 ~$120K-$180K$120K-$180K~4-6%
定制机柜 + 电源分配 (PDU)1 套$40K-$70K$40K-$70K~1.5-2.5%
BlueField-3 DPU2-4$3K-$5K$12K-$20K~0.5%
组装/集成/测试 + 原厂 margin~$100K-$150K~3-5%
合计~$2.7M-$3.3M100%

来源说明:NVIDIA 不公开组件级定价。以上数据综合自 SemiAnalysis 深度分析(2024.03)、Morgan Stanley 研报(2024.03)、Dell/Supermicro OEM 报价泄露、ServeTheHomeTom's Hardware 报道。实际价格因 OEM 厂商、采购规模、配置差异浮动 ±15%。

Function Calling 诞生的背景:LLM 为什么要学会调用函数

· 阅读需 8 分钟

引言

2023 年 6 月,OpenAI 在 GPT-4-0613 和 GPT-3.5-turbo-0613 中首次引入了 Function Calling 能力。当时很多人第一反应是:"这不就是让模型生成 JSON 吗?有什么特别的?"

两年后再回头去看,Function Calling 是 LLM 从"聊天玩具"走向"生产工具"的关键一步。本文不讲 API 怎么调用,而是聊清楚一个更根本的问题:Function Calling 到底解决了什么问题?它为什么一定会出现?

DeepSeek开源的价值

· 阅读需 3 分钟

引言

2024 年底,DeepSeek 发布了 DeepSeek-V2 和 DeepSeek-R1 系列模型,并选择完全开源。这一举动在全球 AI 社区引发了巨大反响。本文试图从多个维度分析 DeepSeek 开源战略的真正价值。

AI Infra 到底是什么

· 阅读需 4 分钟

一句话

AI Infra = AI Infrastructure(AI 基础设施),指的是支撑 AI 系统从研发到落地全流程的底层技术栈。

只要你听过"大模型训练太贵了"、"推理速度不够快"、"GPU 利用率上不去"——这些问题的根都在 AI Infra 上。


四层架构

AI Infra 不是单一的东西,从上到下可以拆成四个层面:

1. 硬件层 — 算力的物理基础

这层最重、最贵,也是普通人最容易感知的部分:

  • GPU / NPU / TPU — 算力核心。NVIDIA H100/B200 是当前主流,AMD MI300X 在追赶,Google 有自己的 TPU
  • 高速互联 — 多卡多机通信的命脉:NVLink、InfiniBand、RoCE
  • 存储系统 — 数据集和 checkpoint 的读写瓶颈:Lustre、GPFS、MinIO、JuiceFS

训练一个 70B 模型,单机 8 卡 H100 是不够的,需要几十上百台机器组集群,这时候 InfiniBand 的带宽决定了你"能不能卡在通信上"。

2. 编排层 — 算力怎么分、怎么调

硬件买回来只是开始,怎么让几十上百台机器跑起来是另一回事:

  • 资源调度 — Slurm(学术圈标配)、Kubernetes + GPU Operator(工业界主流)、Volcano
  • 任务调度 — 谁先跑、跑多久、失败了怎么重试:Apache Airflow、Ray
  • 弹性/混部 — 训练和推理任务混合调度,提高 GPU 利用率

搞过 K8s 的人都知道,加上 GPU 之后调度复杂度直接翻倍——要处理 GPU 显存碎片、MIG 分区、节点选择、拓扑亲和性。这层是 AI Infra Engineer 最常打交道的地方。

3. 平台软件层 — 训练和推理的工程化

这层解决两个核心问题:怎么训得快怎么跑得稳

训练方向:

  • PyTorch / JAX — 框架选型
  • DeepSpeed、Megatron-LM、FSDP — 分布式策略:ZeRO、TP、PP、SP
  • 混合精度训练(FP16/BF16/FP8)
  • Checkpoint 管理和故障恢复

推理方向:

  • vLLM、TensorRT-LLM、TGI、SGLang — 推理引擎
  • PagedAttention、Continuous Batching、FlashAttention — 推理加速技术
  • FP8/INT4/INT8 量化

模型与数据管理:

  • MLflow、Hugging Face Hub、NVIDIA NIM — 模型注册和版本管理
  • Spark、Ray Data、Dask — 数据预处理流水线

4. 服务/业务层 — 让模型真正可用

模型训练完了,要部署成线上服务,这层关注的是稳定性、可观测性和自动化:

  • 推理网关 — Triton Inference Server、KServe,负责路由、限流、负载均衡
  • 监控 — Prometheus + Grafana 盯 GPU 利用率、吞吐、P99 延迟
  • MLOps — 自动评测、A/B 部署、模型回滚(Kubeflow、MLflow、Weights & Biases)

为什么 AI Infra 这么重要

三个字:成本差

同样的 70B 模型,AI Infra 做得好的团队,训练成本可能是别人的 1/3,推理延迟可能是别人的 1/5。这不是夸张——DeepSpeed 的 ZeRO-3 能在同样硬件上省 60% 显存,vLLM 的 PagedAttention 能提升 2-4 倍推理吞吐。

另一个角度:GPU 利用率就是钱

H100 一小时几十块的折旧成本,利用率从 30% 提到 80%,相当于 2.6 倍的硬件收益。AI Infra 干的就是这件事。


谁在干这个活

对应的职位通常是 AI Infra Engineer / AI 基础设施工程师,日常工作包括:

  • GPU 集群的搭建、监控和维护
  • 分布式训练的性能分析和优化
  • 推理服务的延迟优化和稳定性保障
  • MLOps 平台和 CI/CD 流水线的建设
  • 存储和网络层面的性能调优

如果你在用 Rust / Go / C++ 做这些方向,非常明确就是 Infra 角色。


一张图总结

┌─────────────────────────────────┐
│ 服务/业务层 │
│ 推理网关 · 监控 · MLOps · CI/CD│
├─────────────────────────────────┤
│ 平台软件层 │
│ PyTorch · DeepSpeed · vLLM │
│ TensorRT · Triton · MLflow │
├─────────────────────────────────┤
│ 编排层 │
│ K8s + GPU Op · Slurm · Ray │
│ 调度 · 弹性 · 混部 │
├─────────────────────────────────┤
│ 硬件层 │
│ GPU · InfiniBand · 分布式存储 │
└─────────────────────────────────┘

AI Infra = 让 AI 模型能"算得快、训得起、部署稳"的底层工程体系。

不是每个人都需要深入每一层,但理解这个分层结构,能帮你快速定位问题在哪层,以及你的工作落在哪个位置。

用 LangChain + Qdrant + DeepSeek 搭建简历 RAG 系统

· 阅读需 4 分钟

背景

需要从一份 Word 简历中提取结构化信息(姓名、专业技能、工作年限),用 RAG 方案比直接写正则解析灵活得多。

技术栈

组件选型
文档加载UnstructuredLoader
向量库Qdrant (Docker)
嵌入模型通义千问 text-embedding-v1
LLMDeepSeek v4 Flash
编排框架LangChain
运行环境Python 3.13 + uv

项目结构

rag/
├── main.py # 主流程
├── llm.py # LLM + 向量库封装
├── prompt.py # 本地 prompt 模板
├── sensenova.py # 备用 LLM 客户端
├── pyproject.toml # 依赖管理
└── uv.lock

核心流程

1. 文档加载与切片

word = UnstructuredLoader("简历.docx")
docs = word.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=50, chunk_overlap=20)
chunks = splitter.split_documents(docs)

UnstructuredLoader 支持 .docx/.pdf/.pptx 等格式,自动提取文本。分片用 50 字符 + 20 字符重叠,对简历这种短文档粒度合适。

2. 向量化存储

embeddings = DashScopeEmbeddings(
dashscope_api_key=os.environ.get("dashscope"),
model="text-embedding-v1",
)
vectordb = QdrantVectorStore.from_documents(
chunks, embeddings,
collection_name="resume",
url="http://localhost:6333",
)

嵌入用通义千问的 text-embedding-v1,向量库用 Qdrant(Docker 运行),collection 名 resume

3. LCEL 链

chain = {
"context": vec_store.as_retriever() | format_docs,
"question": RunnablePassthrough(),
} | prompt | llm | StrOutputParser()

用 LangChain Expression Language 串联:检索 → 格式化上下文 → 填充 prompt → LLM 推理 → 解析输出。

4. 查询

chain.invoke("请输入姓名. 格式如下\n姓名: ?")
chain.invoke("总结专业技能情况. 格式如下\n专业技能: ?")
chain.invoke("根据工作年份总结工作经验. 格式如下\n工作经验: ?年")

三次调用分别提取姓名、技能、工作年限,prompt 里约束了输出格式。

实际输出

姓名: XX
专业技能: Go, Python, C/C++, C#, Java, Lua
工作经验: 约16年

踩坑记录

hub.pull 安全限制

hub.pull("rlm/rag-prompt") 默认不允许拉取公开 prompt,需要:

from langsmith import Client as LangSmithClient
client = LangSmithClient()
prompt = client.pull_prompt("rlm/rag-prompt", dangerously_pull_public_prompt=True)

缺失依赖

langchain-text-splitterslangchain-communitydashscope 需要在 pyproject.toml 中显式声明。

Qdrant 连接

Qdrant 通过 Docker 启动,确保 localhost:6333 可访问。

完整代码

main.py

import os

from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_unstructured import UnstructuredLoader
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langsmith import Client as LangSmithClient

from llm import DeepSeek, QdrantVecStoreFromDocs


def clearstr(s: str) -> str:
filter_chars = ['\n', '\r', '\t', '\u3000', ' ']
for char in filter_chars:
s = s.replace(char, '')
return s


def format_docs(docs) -> str:
return "\n\n".join(clearstr(doc.page_content) for doc in docs)


def load_doc():
word = UnstructuredLoader("C:\\Users\\Administrator\\Downloads\\xxx.docx")
docs = word.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=50, chunk_overlap=20)
chunks = splitter.split_documents(docs)
vec_store = QdrantVecStoreFromDocs(chunks, collection_name="resume")
llm = DeepSeek()
client = LangSmithClient()
prompt = client.pull_prompt("rlm/rag-prompt", dangerously_pull_public_prompt=True)

chain = {
"context": vec_store.as_retriever() | format_docs,
"question": RunnablePassthrough(),
} | prompt | llm | StrOutputParser()

ret = chain.invoke("请输入姓名. 格式如下\n姓名: ?")
print(ret)
ret = chain.invoke("总结专业技能情况,内容可能包含golang、AI Agent、python、rag等.格式如下\n专业技能: ?")
print(ret)
ret = chain.invoke("根据各大公司工作过的年份总结工作经验有多少年.格式如下\n工作经验: ?年")
print(ret)


def main():
print("Hello from rag!")
load_doc()


if __name__ == "__main__":
main()

llm.py

import os
from typing import List, Optional

from langchain_community.embeddings import DashScopeEmbeddings
from langchain_core.documents import Document
from langchain_openai import ChatOpenAI
from langchain_qdrant import QdrantVectorStore


def DeepSeek():
return ChatOpenAI(
model="deepseek-v4-flash",
api_key=os.environ.get("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com/v1",
)


def get_embeddings():
return DashScopeEmbeddings(
dashscope_api_key=os.environ.get("dashscope"),
model="text-embedding-v1",
)


def QdrantVecStoreFromDocs(docs: List[Document], collection_name: str,
qdrant_url: Optional[str] = None,
qdrant_api_key: Optional[str] = None):
if qdrant_url is None:
qdrant_url = "http://localhost:6333"
embeddings = get_embeddings()
vectordb = QdrantVectorStore.from_documents(
docs, embeddings, collection_name=collection_name,
url=qdrant_url, api_key=qdrant_api_key,
)
return vectordb

prompt.py

RAGPrompt = """
You are an assistant for question-answering tasks.
Use the following pieces of retrieved context to answer the question.
If you don't know the answer, just say that you don't know,
don't try to make up an answer.
Use three sentences maximum and keep the answer concise.
Question: {question}
Context: {context}
Answer:
"""

pyproject.toml

[project]
name = "rag"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"langchain>=1.3.11",
"langchain-unstructured>=0.1.0",
"langchain-openai>=1.3.3",
"langchain-text-splitters>=0.3.0",
"langchain-community>=0.3.0",
"nltk>=3.9.4",
"python-docx>=1.2.0",
"unstructured>=0.23.1",
"langchain-qdrant>=1.1.0",
"dashscope>=1.0.0",
]

总结

LangChain 的 LCEL 写 RAG pipeline 非常简洁,配合 Docker 运行的 Qdrant 和 DeepSeek 的 API,从文档到结构化输出只要几十行代码。这套方案不仅适用于简历解析,合同审核、知识库 QA 等场景也能直接复用。

一个快速查看端口占用进程的工具 sonar

· 阅读需 2 分钟

安装

curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh |bash
. ~/.bashrc

一条命令看清全貌

sonar list

带资源统计

sonar list --stats

自定义列

sonar list -c port,process,cpu,mem,uptime,state

端口详情

sonar info 80

按端口杀进程

sonar kill 80 # SIGTERM
sonar kill 80 -f # SIGKILL

查看日志

sonar logs 80

连接到服务

sonar attach 80

实时监控

# 每2秒刷新,显示变化
sonar watch
# 实时资源监控
sonar watch --stats
# 更快的刷新间隔
sonar watch -i 500ms
# 端口上下线时发送桌面通知
sonar watch --notify

依赖关系图

sonar graph

等待端口就绪

# 等待TCP连接可用
sonar wait 80
# 多个端口
sonar wait 80 6379
# 等待HTTP 200
sonar wait 80 --http
# 检查特定断点
sonar wait 80 --http=/health
# 超时
sonar wait 80 --timeout 30s

端口映射

# 把 6873 端口的服务映射到3002 端口。
sonar map 6873 3002

查找空闲端口

sonar next
# 从 8000 开始
sonar next 8000
# 在范围搜索
sonar next 3000-3100
# 找 3 个连续空闲端口
sonar next -n 3

远程扫描

#
sonar list --host user@server
sonar watch --host user@server

index

· 阅读需 1 分钟

blog index.md