[{"content":"日志是安全排查的第一手资料 系统层面的关键日志位置：\n/var/log/auth.log（Debian/Ubuntu）或 journalctl -u sshd：登录与认证记录 /var/log/syslog / journalctl：系统级事件 /var/log/nginx/access.log：Web 访问记录 auditd 日志（/var/log/audit/audit.log）：文件访问与系统调用审计 快速排查异常登录 # 查看最近登录成功记录 last -20 # 查看登录失败记录 sudo grep \u0026#34;Failed password\u0026#34; /var/log/auth.log | tail -50 # 统计失败登录来源 IP 排名 sudo grep \u0026#34;Failed password\u0026#34; /var/log/auth.log \\ | awk \u0026#39;{print $(NF-3)}\u0026#39; | sort | uniq -c | sort -nr | head 使用 auditd 监控关键文件 sudo apt install auditd sudo systemctl enable --now auditd # 监控 /etc/passwd 的写入操作 sudo auditctl -w /etc/passwd -p wa -k passwd_changes # 查询相关审计记录 sudo ausearch -k passwd_changes 规则可写入 /etc/audit/rules.d/audit.rules 实现持久化，重启后仍然生效。\n轻量级入侵检测：AIDE AIDE（Advanced Intrusion Detection Environment）通过文件完整性校验发现未授权变更：\nsudo apt install aide sudo aideinit sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db # 定期检查 sudo aide --check 建议配合 cron 或 systemd timer 定期执行检查，并将结果发送到独立的日志收集系统，避免攻击者篡改本机日志后不留痕迹。\n集中化日志的价值 单机日志容易被入侵者清除或篡改。对多台服务器场景，建议将日志实时转发到独立的日志服务器或云端日志服务（如通过 rsyslog 转发），确保即便主机被攻陷，审计记录依然可追溯。\n# /etc/rsyslog.d/50-forward.conf *.* @@log-server.internal:514 小结 日志审计的核心不在于工具本身，而在于是否建立了“定期检查 + 集中存储 + 关键指标告警”的闭环流程。auditd 与 AIDE 是入门级但足够实用的组合。\n","permalink":"https://www.itnote.org/posts/linux-log-audit-ids/","summary":"\u003ch2 id=\"日志是安全排查的第一手资料\"\u003e日志是安全排查的第一手资料\u003c/h2\u003e\n\u003cp\u003e系统层面的关键日志位置：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e/var/log/auth.log\u003c/code\u003e（Debian/Ubuntu）或 \u003ccode\u003ejournalctl -u sshd\u003c/code\u003e：登录与认证记录\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e/var/log/syslog\u003c/code\u003e / \u003ccode\u003ejournalctl\u003c/code\u003e：系统级事件\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e/var/log/nginx/access.log\u003c/code\u003e：Web 访问记录\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eauditd\u003c/code\u003e 日志（\u003ccode\u003e/var/log/audit/audit.log\u003c/code\u003e）：文件访问与系统调用审计\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"快速排查异常登录\"\u003e快速排查异常登录\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 查看最近登录成功记录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003elast -20\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 查看登录失败记录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo grep \u003cspan class=\"s2\"\u003e\u0026#34;Failed password\u0026#34;\u003c/span\u003e /var/log/auth.log \u003cspan class=\"p\"\u003e|\u003c/span\u003e tail -50\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 统计失败登录来源 IP 排名\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo grep \u003cspan class=\"s2\"\u003e\u0026#34;Failed password\u0026#34;\u003c/span\u003e /var/log/auth.log \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e|\u003c/span\u003e awk \u003cspan class=\"s1\"\u003e\u0026#39;{print $(NF-3)}\u0026#39;\u003c/span\u003e \u003cspan class=\"p\"\u003e|\u003c/span\u003e sort \u003cspan class=\"p\"\u003e|\u003c/span\u003e uniq -c \u003cspan class=\"p\"\u003e|\u003c/span\u003e sort -nr \u003cspan class=\"p\"\u003e|\u003c/span\u003e head\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"使用-auditd-监控关键文件\"\u003e使用 auditd 监控关键文件\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install auditd\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl \u003cspan class=\"nb\"\u003eenable\u003c/span\u003e --now auditd\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 监控 /etc/passwd 的写入操作\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo auditctl -w /etc/passwd -p wa -k passwd_changes\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 查询相关审计记录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo ausearch -k passwd_changes\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e规则可写入 \u003ccode\u003e/etc/audit/rules.d/audit.rules\u003c/code\u003e 实现持久化，重启后仍然生效。\u003c/p\u003e","title":"Linux 日志审计与轻量级入侵检测实践"},{"content":"安装 Nginx sudo apt update sudo apt install nginx sudo systemctl enable --now nginx 反向代理配置示例 以代理本地 vLLM 服务（监听 127.0.0.1:8000）为例：\n# /etc/nginx/sites-available/api.example.com server { listen 80; server_name api.example.com; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 流式响应（SSE）需要关闭缓冲 proxy_buffering off; proxy_read_timeout 300s; } } sudo ln -s /etc/nginx/sites-available/api.example.com /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx 使用 Let\u0026rsquo;s Encrypt 签发 HTTPS 证书 sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d api.example.com certbot 会自动修改配置文件，添加 443 端口监听与证书路径，并配置 HTTP 到 HTTPS 的重定向。证书默认 90 天有效期，certbot 会自动注册续期任务，可通过以下命令验证：\nsudo certbot renew --dry-run 基础限流配置 保护后端推理服务，避免单一来源占满并发：\nlimit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s; server { location / { limit_req zone=api_limit burst=10 nodelay; proxy_pass http://127.0.0.1:8000; } } Hugo 静态站点的配置示例 server { listen 443 ssl; server_name blog.example.com; root /var/www/blog/public; index index.html; location / { try_files $uri $uri/ =404; } ssl_certificate /etc/letsencrypt/live/blog.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/blog.example.com/privkey.pem; } 小结 无论是代理 AI 推理接口还是托管 Hugo 静态站点，Nginx + Let\u0026rsquo;s Encrypt 都是低成本且成熟稳定的组合，配合限流与合理的超时设置即可满足大多数个人和小团队场景。\n","permalink":"https://www.itnote.org/posts/nginx-reverse-proxy-https/","summary":"\u003ch2 id=\"安装-nginx\"\u003e安装 Nginx\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt update\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install nginx\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl \u003cspan class=\"nb\"\u003eenable\u003c/span\u003e --now nginx\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"反向代理配置示例\"\u003e反向代理配置示例\u003c/h2\u003e\n\u003cp\u003e以代理本地 vLLM 服务（监听 127.0.0.1:8000）为例：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-nginx\" data-lang=\"nginx\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# /etc/nginx/sites-available/api.example.com\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eserver\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kn\"\u003elisten\u003c/span\u003e \u003cspan class=\"mi\"\u003e80\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kn\"\u003eserver_name\u003c/span\u003e \u003cspan class=\"s\"\u003eapi.example.com\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kn\"\u003elocation\u003c/span\u003e \u003cspan class=\"s\"\u003e/\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kn\"\u003eproxy_pass\u003c/span\u003e \u003cspan class=\"s\"\u003ehttp://127.0.0.1:8000\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kn\"\u003eproxy_set_header\u003c/span\u003e \u003cspan class=\"s\"\u003eHost\u003c/span\u003e \u003cspan class=\"nv\"\u003e$host\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kn\"\u003eproxy_set_header\u003c/span\u003e \u003cspan class=\"s\"\u003eX-Real-IP\u003c/span\u003e \u003cspan class=\"nv\"\u003e$remote_addr\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kn\"\u003eproxy_set_header\u003c/span\u003e \u003cspan class=\"s\"\u003eX-Forwarded-For\u003c/span\u003e \u003cspan class=\"nv\"\u003e$proxy_add_x_forwarded_for\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"c1\"\u003e# 流式响应（SSE）需要关闭缓冲\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kn\"\u003eproxy_buffering\u003c/span\u003e \u003cspan class=\"no\"\u003eoff\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kn\"\u003eproxy_read_timeout\u003c/span\u003e \u003cspan class=\"s\"\u003e300s\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo ln -s /etc/nginx/sites-available/api.example.com /etc/nginx/sites-enabled/\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo nginx -t\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl reload nginx\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"使用-lets-encrypt-签发-https-证书\"\u003e使用 Let\u0026rsquo;s Encrypt 签发 HTTPS 证书\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install certbot python3-certbot-nginx\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo certbot --nginx -d api.example.com\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ecertbot 会自动修改配置文件，添加 443 端口监听与证书路径，并配置 HTTP 到 HTTPS 的重定向。证书默认 90 天有效期，certbot 会自动注册续期任务，可通过以下命令验证：\u003c/p\u003e","title":"Nginx 反向代理与 HTTPS 配置实践"},{"content":"为什么容器化 AI 服务 环境隔离，避免 CUDA / Python 依赖版本冲突 便于在多台机器间快速复制部署 结合编排工具（Compose / K8s）实现弹性伸缩 前提：安装 NVIDIA Container Toolkit distribution=$(. /etc/os-release; echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list \\ | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt update sudo apt install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker 使用官方 vLLM 镜像启动服务 docker run -d \\ --name vllm-server \\ --gpus all \\ -p 8000:8000 \\ --ipc=host \\ -v ~/.cache/huggingface:/root/.cache/huggingface \\ vllm/vllm-openai:latest \\ --model Qwen/Qwen2.5-7B-Instruct-AWQ \\ --quantization awq 要点说明：\n--ipc=host：避免多进程间共享内存不足导致的报错 -v 挂载 HuggingFace 缓存目录，避免每次重建容器都重新下载模型 --gpus all 也可指定具体卡号，如 --gpus '\u0026quot;device=0,1\u0026quot;' 使用 docker compose 管理 # docker-compose.yml services: vllm: image: vllm/vllm-openai:latest command: [\u0026#34;--model\u0026#34;, \u0026#34;Qwen/Qwen2.5-7B-Instruct-AWQ\u0026#34;, \u0026#34;--quantization\u0026#34;, \u0026#34;awq\u0026#34;] ports: - \u0026#34;8000:8000\u0026#34; volumes: - ~/.cache/huggingface:/root/.cache/huggingface deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] restart: unless-stopped docker compose up -d docker compose logs -f vllm 资源与安全注意事项 容器内进程默认以 root 运行，生产环境建议通过 --user 指定非特权用户 使用 --memory 与 --cpus 限制资源，避免单容器耗尽宿主机资源 定期更新基础镜像，关注 CVE 公告 小结 容器化并不改变 vLLM 本身的调优逻辑，重点在于处理好 GPU 直通、缓存挂载与资源隔离三个工程细节。\n","permalink":"https://www.itnote.org/posts/docker-ai-deployment/","summary":"\u003ch2 id=\"为什么容器化-ai-服务\"\u003e为什么容器化 AI 服务\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e环境隔离，避免 CUDA / Python 依赖版本冲突\u003c/li\u003e\n\u003cli\u003e便于在多台机器间快速复制部署\u003c/li\u003e\n\u003cli\u003e结合编排工具（Compose / K8s）实现弹性伸缩\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"前提安装-nvidia-container-toolkit\"\u003e前提：安装 NVIDIA Container Toolkit\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003edistribution\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"k\"\u003e$(\u003c/span\u003e. /etc/os-release\u003cspan class=\"p\"\u003e;\u003c/span\u003e \u003cspan class=\"nb\"\u003eecho\u003c/span\u003e \u003cspan class=\"nv\"\u003e$ID$VERSION_ID\u003c/span\u003e\u003cspan class=\"k\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecurl -s -L https://nvidia.github.io/libnvidia-container/gpgkey \u003cspan class=\"p\"\u003e|\u003c/span\u003e sudo apt-key add -\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecurl -s -L https://nvidia.github.io/libnvidia-container/\u003cspan class=\"nv\"\u003e$distribution\u003c/span\u003e/libnvidia-container.list \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e|\u003c/span\u003e sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt update\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install -y nvidia-container-toolkit\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo nvidia-ctk runtime configure --runtime\u003cspan class=\"o\"\u003e=\u003c/span\u003edocker\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl restart docker\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"使用官方-vllm-镜像启动服务\"\u003e使用官方 vLLM 镜像启动服务\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edocker run -d \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --name vllm-server \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --gpus all \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -p 8000:8000 \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --ipc\u003cspan class=\"o\"\u003e=\u003c/span\u003ehost \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -v ~/.cache/huggingface:/root/.cache/huggingface \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  vllm/vllm-openai:latest \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --model Qwen/Qwen2.5-7B-Instruct-AWQ \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --quantization awq\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e要点说明：\u003c/p\u003e","title":"使用 Docker 容器化部署 AI 推理服务"},{"content":"编写一个基础 unit 文件 # /etc/systemd/system/myapp.service [Unit] Description=My Application After=network.target [Service] Type=simple User=appuser Group=appuser WorkingDirectory=/opt/myapp ExecStart=/opt/myapp/venv/bin/python app.py Restart=on-failure RestartSec=5 Environment=PYTHONUNBUFFERED=1 EnvironmentFile=-/opt/myapp/.env [Install] WantedBy=multi-user.target 关键字段说明：\nType=simple：主进程即服务本身，适合大多数常驻程序 Restart=on-failure：进程异常退出时自动重启，避免服务假死 EnvironmentFile=-：前缀 - 表示文件不存在也不报错 常用管理命令 sudo systemctl daemon-reload # 修改 unit 文件后重新加载 sudo systemctl start myapp sudo systemctl enable myapp # 设置开机自启 sudo systemctl status myapp sudo systemctl restart myapp sudo systemctl stop myapp sudo systemctl disable myapp 查看日志 journalctl -u myapp -f # 实时跟踪日志 journalctl -u myapp --since today journalctl -u myapp -p err # 只看错误级别日志 资源限制 对 AI 推理等资源密集型服务，建议在 unit 中限制资源占用，避免单个服务拖垮整机：\n[Service] MemoryMax=16G CPUQuota=400% 依赖与启动顺序 [Unit] Requires=postgresql.service After=postgresql.service Requires 表示强依赖（依赖服务失败则本服务也失败），After 仅控制启动顺序，两者通常搭配使用。\n定时任务：timer 单元替代 cron # /etc/systemd/system/backup.timer [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target 相比 cron，systemd timer 具备更好的日志集成与依赖管理能力，适合逐步替代传统 crontab。\n小结 掌握 unit 文件的编写规范和资源限制配置，是稳定运行自建服务（包括 AI 推理服务）的基础运维能力。\n","permalink":"https://www.itnote.org/posts/systemd-service-management/","summary":"\u003ch2 id=\"编写一个基础-unit-文件\"\u003e编写一个基础 unit 文件\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-ini\" data-lang=\"ini\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# /etc/systemd/system/myapp.service\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[Unit]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eDescription\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003eMy Application\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eAfter\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003enetwork.target\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[Service]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eType\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003esimple\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eUser\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003eappuser\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eGroup\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003eappuser\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eWorkingDirectory\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e/opt/myapp\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eExecStart\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e/opt/myapp/venv/bin/python app.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eRestart\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003eon-failure\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eRestartSec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eEnvironment\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003ePYTHONUNBUFFERED=1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eEnvironmentFile\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e-/opt/myapp/.env\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[Install]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eWantedBy\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003emulti-user.target\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e关键字段说明：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003eType=simple\u003c/code\u003e：主进程即服务本身，适合大多数常驻程序\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eRestart=on-failure\u003c/code\u003e：进程异常退出时自动重启，避免服务假死\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eEnvironmentFile=-\u003c/code\u003e：前缀 \u003ccode\u003e-\u003c/code\u003e 表示文件不存在也不报错\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"常用管理命令\"\u003e常用管理命令\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl daemon-reload      \u003cspan class=\"c1\"\u003e# 修改 unit 文件后重新加载\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl start myapp\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl \u003cspan class=\"nb\"\u003eenable\u003c/span\u003e myapp       \u003cspan class=\"c1\"\u003e# 设置开机自启\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl status myapp\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl restart myapp\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl stop myapp\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl disable myapp\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"查看日志\"\u003e查看日志\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ejournalctl -u myapp -f            \u003cspan class=\"c1\"\u003e# 实时跟踪日志\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ejournalctl -u myapp --since today\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ejournalctl -u myapp -p err        \u003cspan class=\"c1\"\u003e# 只看错误级别日志\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"资源限制\"\u003e资源限制\u003c/h2\u003e\n\u003cp\u003e对 AI 推理等资源密集型服务，建议在 unit 中限制资源占用，避免单个服务拖垮整机：\u003c/p\u003e","title":"systemd 服务管理与开机自启配置详解"},{"content":"ufw：面向新手的简化管理 ufw（Uncomplicated Firewall）是对 iptables/nftables 的简化封装，适合快速配置基础规则。\nsudo apt install ufw # 默认策略：拒绝入站，允许出站 sudo ufw default deny incoming sudo ufw default allow outgoing # 放行必要端口 sudo ufw allow 22022/tcp # SSH（对应自定义端口） sudo ufw allow 80/tcp sudo ufw allow 443/tcp # 限制某端口的来源 IP 段 sudo ufw allow from 192.168.1.0/24 to any port 8000 sudo ufw enable sudo ufw status verbose nftables：更细粒度的现代方案 nftables 是 iptables 的继任者，语法更统一，规则集也更易维护。\nsudo apt install nftables # /etc/nftables.conf table inet filter { chain input { type filter hook input priority 0; policy drop; ct state established,related accept iif lo accept tcp dport 22022 accept tcp dport { 80, 443 } accept # 限制单 IP 新建连接速率，缓解简单的连接洪泛 tcp dport 22022 ct state new limit rate 10/minute accept } chain forward { type filter hook forward priority 0; policy drop; } chain output { type filter hook output priority 0; policy accept; } } sudo nft -f /etc/nftables.conf sudo systemctl enable --now nftables 场景示例：仅内网可访问的 AI 推理服务 将 vLLM 等服务监听在内网接口，或通过防火墙限制外部访问：\nsudo ufw allow from 10.0.0.0/8 to any port 8000 sudo ufw deny 8000 规则顺序在 ufw 中很重要，更具体的规则应放在通用拒绝规则之前生效。\n验证规则是否生效 sudo ufw status numbered sudo nft list ruleset 小结 对于单机小型部署，ufw 已经足够；如果需要更复杂的流量整形、NAT 或多接口策略，建议直接使用 nftables 原生语法以获得更好的可维护性。\n","permalink":"https://www.itnote.org/posts/linux-firewall-guide/","summary":"\u003ch2 id=\"ufw面向新手的简化管理\"\u003eufw：面向新手的简化管理\u003c/h2\u003e\n\u003cp\u003e\u003ccode\u003eufw\u003c/code\u003e（Uncomplicated Firewall）是对 iptables/nftables 的简化封装，适合快速配置基础规则。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install ufw\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 默认策略：拒绝入站，允许出站\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo ufw default deny incoming\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo ufw default allow outgoing\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 放行必要端口\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo ufw allow 22022/tcp   \u003cspan class=\"c1\"\u003e# SSH（对应自定义端口）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo ufw allow 80/tcp\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo ufw allow 443/tcp\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 限制某端口的来源 IP 段\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo ufw allow from 192.168.1.0/24 to any port \u003cspan class=\"m\"\u003e8000\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo ufw \u003cspan class=\"nb\"\u003eenable\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo ufw status verbose\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"nftables更细粒度的现代方案\"\u003enftables：更细粒度的现代方案\u003c/h2\u003e\n\u003cp\u003enftables 是 iptables 的继任者，语法更统一，规则集也更易维护。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install nftables\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# /etc/nftables.conf\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003etable inet filter {\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  chain input {\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    type filter hook input priority 0; policy drop;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    ct state established,related accept\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    iif lo accept\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    tcp dport 22022 accept\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    tcp dport { 80, 443 } accept\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    # 限制单 IP 新建连接速率，缓解简单的连接洪泛\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    tcp dport 22022 ct state new limit rate 10/minute accept\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  chain forward {\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    type filter hook forward priority 0; policy drop;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  chain output {\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    type filter hook output priority 0; policy accept;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  }\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo nft -f /etc/nftables.conf\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl \u003cspan class=\"nb\"\u003eenable\u003c/span\u003e --now nftables\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"场景示例仅内网可访问的-ai-推理服务\"\u003e场景示例：仅内网可访问的 AI 推理服务\u003c/h2\u003e\n\u003cp\u003e将 vLLM 等服务监听在内网接口，或通过防火墙限制外部访问：\u003c/p\u003e","title":"Linux 防火墙配置指南：ufw 与 nftables"},{"content":"使用密钥认证替代密码登录 # 本地生成密钥对（推荐 ed25519） ssh-keygen -t ed25519 -C \u0026#34;your_email@example.com\u0026#34; # 上传公钥到服务器 ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server /etc/ssh/sshd_config 关键配置 # 禁用密码登录，强制密钥认证 PasswordAuthentication no PermitEmptyPasswords no # 禁止 root 远程登录 PermitRootLogin no # 更改默认端口，降低自动化扫描命中率（非核心防护手段，只是降噪） Port 22022 # 限制协议版本与登录尝试 Protocol 2 MaxAuthTries 3 LoginGraceTime 30 # 仅允许特定用户/组登录 AllowUsers deploy admin 修改后重启服务：\nsudo systemctl restart sshd 注意：修改端口或禁用密码登录前，务必保留一个已登录的会话窗口，避免配置错误导致无法远程访问。\n使用 fail2ban 防暴力破解 sudo apt install fail2ban # /etc/fail2ban/jail.local [sshd] enabled = true port = 22022 maxretry = 5 bantime = 3600 findtime = 600 sudo systemctl enable --now fail2ban sudo fail2ban-client status sshd 双因素认证（可选增强） 对高安全要求场景，可结合 libpam-google-authenticator 实现 SSH 二次验证，在密钥认证基础上再叠加一层动态口令。\n限制来源 IP 若访问来源固定，建议直接在防火墙层限制 SSH 端口的可访问 IP 段，而非仅依赖应用层配置，具体见《Linux 防火墙配置指南》一文。\n小结 SSH 是服务器最重要的入口之一，密钥认证 + 禁用 root 登录 + fail2ban 是性价比最高的三件套，可以覆盖绝大多数暴力破解与凭证泄露风险。\n","permalink":"https://www.itnote.org/posts/ssh-security-best-practices/","summary":"\u003ch2 id=\"使用密钥认证替代密码登录\"\u003e使用密钥认证替代密码登录\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 本地生成密钥对（推荐 ed25519）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003essh-keygen -t ed25519 -C \u003cspan class=\"s2\"\u003e\u0026#34;your_email@example.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 上传公钥到服务器\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003essh-copy-id -i ~/.ssh/id_ed25519.pub user@server\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"etcsshsshd_config-关键配置\"\u003e/etc/ssh/sshd_config 关键配置\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# 禁用密码登录，强制密钥认证\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ePasswordAuthentication no\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ePermitEmptyPasswords no\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# 禁止 root 远程登录\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ePermitRootLogin no\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# 更改默认端口，降低自动化扫描命中率（非核心防护手段，只是降噪）\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ePort 22022\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# 限制协议版本与登录尝试\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eProtocol 2\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eMaxAuthTries 3\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eLoginGraceTime 30\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# 仅允许特定用户/组登录\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eAllowUsers deploy admin\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e修改后重启服务：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl restart sshd\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cblockquote\u003e\n\u003cp\u003e注意：修改端口或禁用密码登录前，务必保留一个已登录的会话窗口，避免配置错误导致无法远程访问。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"使用-fail2ban-防暴力破解\"\u003e使用 fail2ban 防暴力破解\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install fail2ban\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-ini\" data-lang=\"ini\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# /etc/fail2ban/jail.local\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[sshd]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eenabled\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003etrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eport\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e22022\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003emaxretry\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003ebantime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e3600\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003efindtime\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003e600\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl \u003cspan class=\"nb\"\u003eenable\u003c/span\u003e --now fail2ban\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo fail2ban-client status sshd\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"双因素认证可选增强\"\u003e双因素认证（可选增强）\u003c/h2\u003e\n\u003cp\u003e对高安全要求场景，可结合 \u003ccode\u003elibpam-google-authenticator\u003c/code\u003e 实现 SSH 二次验证，在密钥认证基础上再叠加一层动态口令。\u003c/p\u003e","title":"SSH 安全配置最佳实践"},{"content":"账户与权限 禁用 root 直接远程登录，改用普通账户 + sudo 为每个人员/服务分配独立账户，避免共享凭证 定期审查 sudo -l 权限范围，遵循最小权限原则 # 检查是否有异常的 sudo 权限 sudo -l -U username 更新与补丁 sudo apt update \u0026amp;\u0026amp; sudo apt upgrade -y # 开启无人值守安全更新（Debian/Ubuntu） sudo apt install unattended-upgrades sudo dpkg-reconfigure --priority=low unattended-upgrades 文件与目录权限 # 查找全局可写的敏感文件 find / -xdev -type f -perm -0002 -not -path \u0026#34;/proc/*\u0026#34; 2\u0026gt;/dev/null # 查找 SUID/SGID 程序，核对是否为预期程序 find / -xdev \\( -perm -4000 -o -perm -2000 \\) -type f 2\u0026gt;/dev/null 关闭不必要的服务 systemctl list-unit-files --type=service --state=enabled sudo systemctl disable \u0026lt;不需要的服务\u0026gt; 内核参数加固（/etc/sysctl.conf） # 禁止 IP 转发（非路由器场景） net.ipv4.ip_forward = 0 # 防止 SYN Flood net.ipv4.tcp_syncookies = 1 # 忽略 ICMP 广播请求 net.ipv4.icmp_echo_ignore_broadcasts = 1 # 禁用来源路由 net.ipv4.conf.all.accept_source_route = 0 sudo sysctl -p 日志与审计 安装 auditd 记录关键系统调用与文件访问，配合 journalctl 定期审查异常登录尝试：\nsudo apt install auditd sudo systemctl enable --now auditd 小结 安全加固没有一劳永逸的方案，本文覆盖的是最基础的加固面。SSH、防火墙、入侵检测等专题将在后续文章中详细展开。\n","permalink":"https://www.itnote.org/posts/linux-hardening-basics/","summary":"\u003ch2 id=\"账户与权限\"\u003e账户与权限\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e禁用 root 直接远程登录，改用普通账户 + sudo\u003c/li\u003e\n\u003cli\u003e为每个人员/服务分配独立账户，避免共享凭证\u003c/li\u003e\n\u003cli\u003e定期审查 \u003ccode\u003esudo -l\u003c/code\u003e 权限范围，遵循最小权限原则\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 检查是否有异常的 sudo 权限\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo -l -U username\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"更新与补丁\"\u003e更新与补丁\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt update \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e sudo apt upgrade -y\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 开启无人值守安全更新（Debian/Ubuntu）\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install unattended-upgrades\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo dpkg-reconfigure --priority\u003cspan class=\"o\"\u003e=\u003c/span\u003elow unattended-upgrades\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"文件与目录权限\"\u003e文件与目录权限\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 查找全局可写的敏感文件\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003efind / -xdev -type f -perm -0002 -not -path \u003cspan class=\"s2\"\u003e\u0026#34;/proc/*\u0026#34;\u003c/span\u003e 2\u0026gt;/dev/null\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 查找 SUID/SGID 程序，核对是否为预期程序\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003efind / -xdev \u003cspan class=\"se\"\u003e\\(\u003c/span\u003e -perm -4000 -o -perm -2000 \u003cspan class=\"se\"\u003e\\)\u003c/span\u003e -type f 2\u0026gt;/dev/null\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"关闭不必要的服务\"\u003e关闭不必要的服务\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esystemctl list-unit-files --type\u003cspan class=\"o\"\u003e=\u003c/span\u003eservice --state\u003cspan class=\"o\"\u003e=\u003c/span\u003eenabled\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl disable \u0026lt;不需要的服务\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"内核参数加固etcsysctlconf\"\u003e内核参数加固（/etc/sysctl.conf）\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# 禁止 IP 转发（非路由器场景）\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003enet.ipv4.ip_forward = 0\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# 防止 SYN Flood\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003enet.ipv4.tcp_syncookies = 1\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# 忽略 ICMP 广播请求\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003enet.ipv4.icmp_echo_ignore_broadcasts = 1\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# 禁用来源路由\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003enet.ipv4.conf.all.accept_source_route = 0\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo sysctl -p\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"日志与审计\"\u003e日志与审计\u003c/h2\u003e\n\u003cp\u003e安装 \u003ccode\u003eauditd\u003c/code\u003e 记录关键系统调用与文件访问，配合 \u003ccode\u003ejournalctl\u003c/code\u003e 定期审查异常登录尝试：\u003c/p\u003e","title":"Linux 系统安全加固基础清单"},{"content":"为什么需要框架 直接调用 LLM API 可以完成简单问答，但一旦涉及多轮工具调用、状态管理、多 Agent 协作，手写代码的复杂度会迅速上升。框架的价值在于提供标准化的抽象层。\n主流框架简要对比 框架 定位 优势 局限 LangChain 通用 LLM 应用开发 生态最全，集成组件多 抽象层较重，调试复杂链路较麻烦 LlamaIndex 数据检索与 RAG 为核心 索引与检索能力强 Agent 能力相对偏弱 AutoGen 多 Agent 协作 天然支持多角色对话式协作 对单 Agent 简单任务偏重 原生 Function Calling 直接使用模型能力 轻量、可控性最高 需要自行实现状态管理 选型建议 简单问答 / 单轮工具调用：优先直接使用模型的 function calling 能力，避免引入不必要的框架开销 知识库问答类应用：LlamaIndex 在索引构建与检索优化上更专注 复杂多步骤任务编排：LangChain 的 LCEL（表达式语言）或 LangGraph 提供了较好的状态图抽象 需要多个专业角色协作（如“规划者 + 执行者 + 审核者”）：AutoGen 一类的多 Agent 框架更契合 一个最小 Agent 示例（伪代码） tools = [search_tool, calculator_tool] def run_agent(query): while True: response = llm.chat(messages, tools=tools) if response.tool_calls: for call in response.tool_calls: result = execute_tool(call) messages.append(tool_result(call, result)) else: return response.content 理解这个基本循环（LLM 决策 → 工具执行 → 结果回填 → 再决策）比死记框架 API 更重要，框架本质上都是在此基础上做工程化封装。\n小结 框架不是必须品，关键在于任务复杂度是否值得引入额外的抽象成本。项目初期建议先用最小实现验证可行性，再决定是否迁移到成熟框架。\n","permalink":"https://www.itnote.org/posts/agent-framework-comparison/","summary":"\u003ch2 id=\"为什么需要框架\"\u003e为什么需要框架\u003c/h2\u003e\n\u003cp\u003e直接调用 LLM API 可以完成简单问答，但一旦涉及多轮工具调用、状态管理、多 Agent 协作，手写代码的复杂度会迅速上升。框架的价值在于提供标准化的抽象层。\u003c/p\u003e\n\u003ch2 id=\"主流框架简要对比\"\u003e主流框架简要对比\u003c/h2\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003e框架\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e定位\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e优势\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e局限\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eLangChain\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e通用 LLM 应用开发\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e生态最全，集成组件多\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e抽象层较重，调试复杂链路较麻烦\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eLlamaIndex\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e数据检索与 RAG 为核心\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e索引与检索能力强\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eAgent 能力相对偏弱\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eAutoGen\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e多 Agent 协作\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e天然支持多角色对话式协作\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e对单 Agent 简单任务偏重\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e原生 Function Calling\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e直接使用模型能力\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e轻量、可控性最高\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e需要自行实现状态管理\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"选型建议\"\u003e选型建议\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e简单问答 / 单轮工具调用\u003c/strong\u003e：优先直接使用模型的 function calling 能力，避免引入不必要的框架开销\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e知识库问答类应用\u003c/strong\u003e：LlamaIndex 在索引构建与检索优化上更专注\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e复杂多步骤任务编排\u003c/strong\u003e：LangChain 的 LCEL（表达式语言）或 LangGraph 提供了较好的状态图抽象\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e需要多个专业角色协作\u003c/strong\u003e（如“规划者 + 执行者 + 审核者”）：AutoGen 一类的多 Agent 框架更契合\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"一个最小-agent-示例伪代码\"\u003e一个最小 Agent 示例（伪代码）\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003etools\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"n\"\u003esearch_tool\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003ecalculator_tool\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003erun_agent\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003equery\u003c/span\u003e\u003cspan class=\"p\"\u003e):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ewhile\u003c/span\u003e \u003cspan class=\"kc\"\u003eTrue\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"n\"\u003eresponse\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ellm\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echat\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emessages\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003etools\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003etools\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"n\"\u003eresponse\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etool_calls\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003ecall\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003eresponse\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003etool_calls\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"n\"\u003eresult\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eexecute_tool\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecall\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"n\"\u003emessages\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eappend\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003etool_result\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ecall\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eresult\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"k\"\u003eelse\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"n\"\u003eresponse\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econtent\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e理解这个基本循环（LLM 决策 → 工具执行 → 结果回填 → 再决策）比死记框架 API 更重要，框架本质上都是在此基础上做工程化封装。\u003c/p\u003e","title":"AI 应用开发：LangChain 与 Agent 框架选型对比"},{"content":"结构化 Prompt 的基本框架 一个稳定可复用的 Prompt 通常包含以下几个部分：\n[角色设定] 你是一名资深的后端工程师 [任务描述] 请审查以下代码是否存在安全隐患 [输出约束] 以 JSON 格式输出，字段包括 issue、severity、suggestion [输入内容] {code} 将角色、任务、约束与输入明确分区，可以显著降低模型输出格式不稳定的概率。\n强制结构化输出 对接下游程序时，建议明确要求 JSON 并给出 schema 示例：\n请仅输出如下格式的 JSON，不要包含任何多余文字： { \u0026#34;summary\u0026#34;: \u0026#34;string\u0026#34;, \u0026#34;risk_level\u0026#34;: \u0026#34;low | medium | high\u0026#34;, \u0026#34;actions\u0026#34;: [\u0026#34;string\u0026#34;] } 如果使用支持 function calling 或 structured output 的模型/框架，优先使用原生能力而非纯文本约束，稳定性更高。\n思维链（CoT）引导 对于推理类任务，显式要求模型分步思考能提升准确率：\n请先列出解决该问题需要的关键步骤，再逐步推导，最后给出结论。 需要注意的是，面向最终用户展示的产品通常应隐藏推理过程，只暴露结论，避免冗长输出影响体验。\nFew-shot 示例的选择 示例数量并非越多越好，2~4 个高质量示例通常优于大量低质量示例 示例应覆盖边界情况（如空输入、异常格式），而不仅是“标准”场景 示例格式必须与期望输出格式完全一致，包括缩进和标点 常见反模式 在 Prompt 中堆砌矛盾指令（如同时要求“详细”又要求“简洁”） 过度依赖否定式指令（“不要做 X”），效果通常弱于正向描述期望行为 忽略模型的上下文长度限制，导致关键指令被截断 小结 Prompt 工程的本质是通过清晰的结构和约束，降低模型输出的不确定性，使其更适配工程化的下游调用。\n","permalink":"https://www.itnote.org/posts/prompt-engineering-practice/","summary":"\u003ch2 id=\"结构化-prompt-的基本框架\"\u003e结构化 Prompt 的基本框架\u003c/h2\u003e\n\u003cp\u003e一个稳定可复用的 Prompt 通常包含以下几个部分：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e[角色设定]  你是一名资深的后端工程师\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e[任务描述]  请审查以下代码是否存在安全隐患\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e[输出约束]  以 JSON 格式输出，字段包括 issue、severity、suggestion\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e[输入内容]  {code}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e将角色、任务、约束与输入明确分区，可以显著降低模型输出格式不稳定的概率。\u003c/p\u003e\n\u003ch2 id=\"强制结构化输出\"\u003e强制结构化输出\u003c/h2\u003e\n\u003cp\u003e对接下游程序时，建议明确要求 JSON 并给出 schema 示例：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e请仅输出如下格式的 JSON，不要包含任何多余文字：\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u0026#34;summary\u0026#34;: \u0026#34;string\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u0026#34;risk_level\u0026#34;: \u0026#34;low | medium | high\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u0026#34;actions\u0026#34;: [\u0026#34;string\u0026#34;]\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e如果使用支持 function calling 或 structured output 的模型/框架，优先使用原生能力而非纯文本约束，稳定性更高。\u003c/p\u003e\n\u003ch2 id=\"思维链cot引导\"\u003e思维链（CoT）引导\u003c/h2\u003e\n\u003cp\u003e对于推理类任务，显式要求模型分步思考能提升准确率：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e请先列出解决该问题需要的关键步骤，再逐步推导，最后给出结论。\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e需要注意的是，面向最终用户展示的产品通常应隐藏推理过程，只暴露结论，避免冗长输出影响体验。\u003c/p\u003e\n\u003ch2 id=\"few-shot-示例的选择\"\u003eFew-shot 示例的选择\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e示例数量并非越多越好，2~4 个高质量示例通常优于大量低质量示例\u003c/li\u003e\n\u003cli\u003e示例应覆盖边界情况（如空输入、异常格式），而不仅是“标准”场景\u003c/li\u003e\n\u003cli\u003e示例格式必须与期望输出格式完全一致，包括缩进和标点\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"常见反模式\"\u003e常见反模式\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e在 Prompt 中堆砌矛盾指令（如同时要求“详细”又要求“简洁”）\u003c/li\u003e\n\u003cli\u003e过度依赖否定式指令（“不要做 X”），效果通常弱于正向描述期望行为\u003c/li\u003e\n\u003cli\u003e忽略模型的上下文长度限制，导致关键指令被截断\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"小结\"\u003e小结\u003c/h2\u003e\n\u003cp\u003ePrompt 工程的本质是通过清晰的结构和约束，降低模型输出的不确定性，使其更适配工程化的下游调用。\u003c/p\u003e","title":"AI 应用开发：Prompt 工程实践技巧"},{"content":"RAG 的基本流程 一个典型 RAG 系统由四个阶段组成：文档切分 → 向量化 → 检索 → 生成。\n原始文档 → Chunking → Embedding → 向量数据库 ↓ 用户问题 → Embedding → 向量检索 → Top-K 片段 → 拼接 Prompt → LLM 生成答案 文档切分策略 切分粒度直接影响检索质量：\n固定长度切分：实现简单，但可能截断语义完整的段落 按语义切分：借助标题、段落结构切分，效果更好但实现复杂 滑动窗口重叠：相邻 chunk 间保留 10%~20% 重叠，缓解边界信息丢失 一般建议 chunk 大小控制在 300~800 token 之间，具体需结合模型上下文长度与检索精度需求测试确定。\n向量数据库选型 方案 特点 适用场景 Milvus 分布式、功能全面 大规模生产环境 Qdrant 轻量、Rust 实现、性能好 中小规模自建 Chroma 极简易用 原型开发、本地实验 pgvector 复用现有 PostgreSQL 已有 PG 基础设施的团队 检索质量优化 混合检索：结合稀疏检索（BM25）与稠密向量检索，弥补语义检索对专有名词、编号类查询不敏感的问题 Rerank：检索出 Top-20 后，用专门的 rerank 模型重新排序取 Top-5，显著提升精度 查询改写：对用户原始问题做扩展或拆分，尤其适合处理多跳问题 常见陷阱 忽略 chunk 元数据（来源、章节）会导致答案缺乏可追溯性 检索结果未去重，可能造成同一内容多次占用上下文 未设置相似度阈值，低相关片段也被强行拼入 Prompt，反而干扰生成质量 小结 RAG 并非简单的“检索 + 拼接”，切分策略、检索方式与重排序环节的组合调优才是决定系统效果的关键。\n","permalink":"https://www.itnote.org/posts/rag-architecture/","summary":"\u003ch2 id=\"rag-的基本流程\"\u003eRAG 的基本流程\u003c/h2\u003e\n\u003cp\u003e一个典型 RAG 系统由四个阶段组成：\u003cstrong\u003e文档切分 → 向量化 → 检索 → 生成\u003c/strong\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-fallback\" data-lang=\"fallback\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e原始文档 → Chunking → Embedding → 向量数据库\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                        ↓\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e用户问题 → Embedding → 向量检索 → Top-K 片段 → 拼接 Prompt → LLM 生成答案\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"文档切分策略\"\u003e文档切分策略\u003c/h2\u003e\n\u003cp\u003e切分粒度直接影响检索质量：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e固定长度切分\u003c/strong\u003e：实现简单，但可能截断语义完整的段落\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e按语义切分\u003c/strong\u003e：借助标题、段落结构切分，效果更好但实现复杂\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e滑动窗口重叠\u003c/strong\u003e：相邻 chunk 间保留 10%~20% 重叠，缓解边界信息丢失\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e一般建议 chunk 大小控制在 300~800 token 之间，具体需结合模型上下文长度与检索精度需求测试确定。\u003c/p\u003e\n\u003ch2 id=\"向量数据库选型\"\u003e向量数据库选型\u003c/h2\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003e方案\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e特点\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e适用场景\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eMilvus\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e分布式、功能全面\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e大规模生产环境\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eQdrant\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e轻量、Rust 实现、性能好\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e中小规模自建\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eChroma\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e极简易用\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e原型开发、本地实验\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003epgvector\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e复用现有 PostgreSQL\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e已有 PG 基础设施的团队\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"检索质量优化\"\u003e检索质量优化\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e混合检索\u003c/strong\u003e：结合稀疏检索（BM25）与稠密向量检索，弥补语义检索对专有名词、编号类查询不敏感的问题\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eRerank\u003c/strong\u003e：检索出 Top-20 后，用专门的 rerank 模型重新排序取 Top-5，显著提升精度\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e查询改写\u003c/strong\u003e：对用户原始问题做扩展或拆分，尤其适合处理多跳问题\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"常见陷阱\"\u003e常见陷阱\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e忽略 chunk 元数据（来源、章节）会导致答案缺乏可追溯性\u003c/li\u003e\n\u003cli\u003e检索结果未去重，可能造成同一内容多次占用上下文\u003c/li\u003e\n\u003cli\u003e未设置相似度阈值，低相关片段也被强行拼入 Prompt，反而干扰生成质量\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"小结\"\u003e小结\u003c/h2\u003e\n\u003cp\u003eRAG 并非简单的“检索 + 拼接”，切分策略、检索方式与重排序环节的组合调优才是决定系统效果的关键。\u003c/p\u003e","title":"AI 应用开发：RAG 系统架构设计要点"},{"content":"目标 让本地部署的模型可以像调用 OpenAI 官方 API 一样被现有代码无缝调用，只需替换 base_url 和 api_key。\n启动服务 vllm serve Qwen/Qwen2.5-7B-Instruct-AWQ \\ --quantization awq \\ --served-model-name my-local-llm \\ --api-key sk-local-demo-key \\ --port 8000 --served-model-name 决定客户端请求中 model 字段应填写的值；--api-key 用于简单鉴权。\nPython 客户端调用 from openai import OpenAI client = OpenAI( base_url=\u0026#34;http://127.0.0.1:8000/v1\u0026#34;, api_key=\u0026#34;sk-local-demo-key\u0026#34;, ) resp = client.chat.completions.create( model=\u0026#34;my-local-llm\u0026#34;, messages=[{\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;用一句话解释向量数据库\u0026#34;}], ) print(resp.choices[0].message.content) 使用 systemd 常驻服务 避免通过 nohup 挂起进程，推荐用 systemd 管理：\n# /etc/systemd/system/vllm.service [Unit] Description=vLLM Inference Server After=network.target [Service] User=vllmuser WorkingDirectory=/opt/vllm ExecStart=/opt/vllm/vllm-env/bin/vllm serve Qwen/Qwen2.5-7B-Instruct-AWQ --port 8000 Restart=always RestartSec=5 [Install] WantedBy=multi-user.target sudo systemctl daemon-reload sudo systemctl enable --now vllm 通过 Nginx 反向代理暴露服务 生产环境不建议直接暴露 8000 端口，应通过 Nginx 做 TLS 终止与限流，具体配置可参考本站《Nginx 反向代理与 HTTPS 配置》一文。\n小结 vLLM 的 OpenAI 兼容层大幅降低了从云端 API 迁移到自建推理的成本，配合 systemd 与反向代理即可获得接近生产可用的稳定服务。\n","permalink":"https://www.itnote.org/posts/vllm-openai-api-service/","summary":"\u003ch2 id=\"目标\"\u003e目标\u003c/h2\u003e\n\u003cp\u003e让本地部署的模型可以像调用 OpenAI 官方 API 一样被现有代码无缝调用，只需替换 \u003ccode\u003ebase_url\u003c/code\u003e 和 \u003ccode\u003eapi_key\u003c/code\u003e。\u003c/p\u003e\n\u003ch2 id=\"启动服务\"\u003e启动服务\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003evllm serve Qwen/Qwen2.5-7B-Instruct-AWQ \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --quantization awq \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --served-model-name my-local-llm \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --api-key sk-local-demo-key \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --port \u003cspan class=\"m\"\u003e8000\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003e--served-model-name\u003c/code\u003e 决定客户端请求中 \u003ccode\u003emodel\u003c/code\u003e 字段应填写的值；\u003ccode\u003e--api-key\u003c/code\u003e 用于简单鉴权。\u003c/p\u003e\n\u003ch2 id=\"python-客户端调用\"\u003ePython 客户端调用\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003efrom\u003c/span\u003e \u003cspan class=\"nn\"\u003eopenai\u003c/span\u003e \u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"n\"\u003eOpenAI\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eclient\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eOpenAI\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ebase_url\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;http://127.0.0.1:8000/v1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003eapi_key\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;sk-local-demo-key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eresp\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eclient\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echat\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecompletions\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecreate\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emodel\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;my-local-llm\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emessages\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"p\"\u003e[{\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;role\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;user\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;content\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;用一句话解释向量数据库\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e}],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eresp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003echoices\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003emessage\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econtent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"使用-systemd-常驻服务\"\u003e使用 systemd 常驻服务\u003c/h2\u003e\n\u003cp\u003e避免通过 nohup 挂起进程，推荐用 systemd 管理：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-ini\" data-lang=\"ini\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# /etc/systemd/system/vllm.service\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[Unit]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eDescription\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003evLLM Inference Server\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eAfter\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003enetwork.target\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[Service]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eUser\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003evllmuser\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eWorkingDirectory\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e/opt/vllm\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eExecStart\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e/opt/vllm/vllm-env/bin/vllm serve Qwen/Qwen2.5-7B-Instruct-AWQ --port 8000\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eRestart\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003ealways\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eRestartSec\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[Install]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"na\"\u003eWantedBy\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003emulti-user.target\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl daemon-reload\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo systemctl \u003cspan class=\"nb\"\u003eenable\u003c/span\u003e --now vllm\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"通过-nginx-反向代理暴露服务\"\u003e通过 Nginx 反向代理暴露服务\u003c/h2\u003e\n\u003cp\u003e生产环境不建议直接暴露 8000 端口，应通过 Nginx 做 TLS 终止与限流，具体配置可参考本站《Nginx 反向代理与 HTTPS 配置》一文。\u003c/p\u003e","title":"基于 vLLM 搭建 OpenAI 兼容 API 服务并接入现有应用"},{"content":"影响显存占用的关键参数 参数 作用 建议值 --gpu-memory-utilization GPU 显存预留比例 单卡场景 0.85~0.9 --max-model-len 最大上下文长度 按实际业务设置，避免过大浪费 --max-num-seqs 同时处理的最大序列数 根据显存余量调整 --block-size PagedAttention 分页大小 默认 16，一般无需更改 --swap-space CPU 侧交换空间(GB) 显存紧张时可设置 4~8 量化降低显存占用 对 7B 级别模型，FP16 大约需要 14GB 显存用于权重本身，加上 KV Cache 后往往超过消费级显卡容量。使用 AWQ 或 GPTQ 4-bit 量化可将权重显存需求降低到原来的 1/4 左右：\nvllm serve Qwen/Qwen2.5-7B-Instruct-AWQ --quantization awq 提升吞吐的关键：Continuous Batching vLLM 默认启用连续批处理，无需手动配置。但可以通过 --max-num-batched-tokens 控制单次调度的 token 总量，值越大吞吐越高，但延迟波动也会增加，需要根据 SLA 要求权衡。\n多卡场景：张量并行 vllm serve meta-llama/Llama-3-70B-Instruct \\ --tensor-parallel-size 4 \\ --gpu-memory-utilization 0.9 --tensor-parallel-size 需与实际 GPU 数量匹配，且各卡显存尽量一致，否则会以最小显存的卡为瓶颈。\n监控建议 结合 nvidia-smi -l 1 观察显存与利用率变化，同时关注 vLLM 自带的 /metrics Prometheus 端点，重点关注 num_requests_waiting 与 gpu_cache_usage_perc 两个指标，用于判断是否需要扩容或调整批处理参数。\n","permalink":"https://www.itnote.org/posts/vllm-memory-tuning/","summary":"\u003ch2 id=\"影响显存占用的关键参数\"\u003e影响显存占用的关键参数\u003c/h2\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003e参数\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e作用\u003c/th\u003e\n\t\t\t\t\t\u003cth\u003e建议值\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003e--gpu-memory-utilization\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eGPU 显存预留比例\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e单卡场景 0.85~0.9\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003e--max-model-len\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e最大上下文长度\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e按实际业务设置，避免过大浪费\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003e--max-num-seqs\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e同时处理的最大序列数\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e根据显存余量调整\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003e--block-size\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003ePagedAttention 分页大小\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e默认 16，一般无需更改\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003ccode\u003e--swap-space\u003c/code\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003eCPU 侧交换空间(GB)\u003c/td\u003e\n\t\t\t\t\t\u003ctd\u003e显存紧张时可设置 4~8\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"量化降低显存占用\"\u003e量化降低显存占用\u003c/h2\u003e\n\u003cp\u003e对 7B 级别模型，FP16 大约需要 14GB 显存用于权重本身，加上 KV Cache 后往往超过消费级显卡容量。使用 AWQ 或 GPTQ 4-bit 量化可将权重显存需求降低到原来的 1/4 左右：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003evllm serve Qwen/Qwen2.5-7B-Instruct-AWQ --quantization awq\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"提升吞吐的关键continuous-batching\"\u003e提升吞吐的关键：Continuous Batching\u003c/h2\u003e\n\u003cp\u003evLLM 默认启用连续批处理，无需手动配置。但可以通过 \u003ccode\u003e--max-num-batched-tokens\u003c/code\u003e 控制单次调度的 token 总量，值越大吞吐越高，但延迟波动也会增加，需要根据 SLA 要求权衡。\u003c/p\u003e\n\u003ch2 id=\"多卡场景张量并行\"\u003e多卡场景：张量并行\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003evllm serve meta-llama/Llama-3-70B-Instruct \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --tensor-parallel-size \u003cspan class=\"m\"\u003e4\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --gpu-memory-utilization 0.9\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ccode\u003e--tensor-parallel-size\u003c/code\u003e 需与实际 GPU 数量匹配，且各卡显存尽量一致，否则会以最小显存的卡为瓶颈。\u003c/p\u003e","title":"vLLM 显存优化与批处理参数调优实战"},{"content":"为什么选择 vLLM 在自建大模型推理服务时，显存利用率和吞吐量往往是最大的瓶颈。传统的 HuggingFace transformers 推理方式在处理并发请求时，KV Cache 的管理效率较低，容易出现显存碎片化。vLLM 通过 PagedAttention 机制，将 KV Cache 按照固定大小的“页”进行管理，类似操作系统的虚拟内存分页，从而大幅提升显存利用率与并发吞吐能力。\n核心特性 PagedAttention：按页管理 KV Cache，减少显存浪费 Continuous Batching：动态批处理，新请求可以在旧请求未完成时插入 OpenAI 兼容 API：可直接替换 OpenAI SDK 的 base_url 多种量化支持：AWQ、GPTQ、FP8 等，降低显存占用 安装 python3 -m venv vllm-env source vllm-env/bin/activate pip install vllm 对于显存有限的轻量环境，建议使用较小参数量模型并结合量化版本，例如 Qwen2.5-7B-Instruct-AWQ。\n启动一个推理服务 vllm serve Qwen/Qwen2.5-7B-Instruct-AWQ \\ --quantization awq \\ --max-model-len 8192 \\ --gpu-memory-utilization 0.85 \\ --port 8000 启动后即可通过标准 OpenAI 接口调用：\ncurl http://localhost:8000/v1/chat/completions \\ -H \u0026#34;Content-Type: application/json\u0026#34; \\ -d \u0026#39;{ \u0026#34;model\u0026#34;: \u0026#34;Qwen/Qwen2.5-7B-Instruct-AWQ\u0026#34;, \u0026#34;messages\u0026#34;: [{\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;你好\u0026#34;}] }\u0026#39; 小结 vLLM 的轻量化并不意味着功能阉割，而是在保持高吞吐的同时降低了部署门槛。后续文章将深入探讨显存调优、批处理参数以及生产环境的服务化实践。\n","permalink":"https://www.itnote.org/posts/vllm-intro/","summary":"\u003ch2 id=\"为什么选择-vllm\"\u003e为什么选择 vLLM\u003c/h2\u003e\n\u003cp\u003e在自建大模型推理服务时，显存利用率和吞吐量往往是最大的瓶颈。传统的 HuggingFace \u003ccode\u003etransformers\u003c/code\u003e 推理方式在处理并发请求时，KV Cache 的管理效率较低，容易出现显存碎片化。vLLM 通过 \u003cstrong\u003ePagedAttention\u003c/strong\u003e 机制，将 KV Cache 按照固定大小的“页”进行管理，类似操作系统的虚拟内存分页，从而大幅提升显存利用率与并发吞吐能力。\u003c/p\u003e\n\u003ch2 id=\"核心特性\"\u003e核心特性\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003ePagedAttention\u003c/strong\u003e：按页管理 KV Cache，减少显存浪费\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eContinuous Batching\u003c/strong\u003e：动态批处理，新请求可以在旧请求未完成时插入\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eOpenAI 兼容 API\u003c/strong\u003e：可直接替换 OpenAI SDK 的 base_url\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e多种量化支持\u003c/strong\u003e：AWQ、GPTQ、FP8 等，降低显存占用\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"安装\"\u003e安装\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003epython3 -m venv vllm-env\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003esource\u003c/span\u003e vllm-env/bin/activate\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003epip install vllm\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e对于显存有限的轻量环境，建议使用较小参数量模型并结合量化版本，例如 Qwen2.5-7B-Instruct-AWQ。\u003c/p\u003e\n\u003ch2 id=\"启动一个推理服务\"\u003e启动一个推理服务\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003evllm serve Qwen/Qwen2.5-7B-Instruct-AWQ \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --quantization awq \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --max-model-len \u003cspan class=\"m\"\u003e8192\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --gpu-memory-utilization 0.85 \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  --port \u003cspan class=\"m\"\u003e8000\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e启动后即可通过标准 OpenAI 接口调用：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecurl http://localhost:8000/v1/chat/completions \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -H \u003cspan class=\"s2\"\u003e\u0026#34;Content-Type: application/json\u0026#34;\u003c/span\u003e \u003cspan class=\"se\"\u003e\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  -d \u003cspan class=\"s1\"\u003e\u0026#39;{\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s1\"\u003e    \u0026#34;model\u0026#34;: \u0026#34;Qwen/Qwen2.5-7B-Instruct-AWQ\u0026#34;,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s1\"\u003e    \u0026#34;messages\u0026#34;: [{\u0026#34;role\u0026#34;: \u0026#34;user\u0026#34;, \u0026#34;content\u0026#34;: \u0026#34;你好\u0026#34;}]\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s1\"\u003e  }\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"小结\"\u003e小结\u003c/h2\u003e\n\u003cp\u003evLLM 的轻量化并不意味着功能阉割，而是在保持高吞吐的同时降低了部署门槛。后续文章将深入探讨显存调优、批处理参数以及生产环境的服务化实践。\u003c/p\u003e","title":"vLLM 入门：轻量级大模型推理引擎原理与部署"}]