刘春龙的博客 刘春龙的博客,大量原创文章。关注AI,科技,金融等技术。 https://php.js.cn/ zh_CN 2026-08-20 19:00:37 2026-08-20 18:00:37 EndCMS RSS Generator 5 <![CDATA[在 A100 32GB 显卡上部署 Qwen3.8-27B]]> https://php.js.cn/blog/run-qwen3.8-27b-on-a100-32g-pg199/ 单张 A100 32GB SM80 显卡,跑 27B 混合注意力模型,256K 上下文 + MTP 投机解码 + 工具调用全开。本文记录完整的部署参数、踩坑过程和实测速度表。 --- ## 1. 硬件环境 | 部件 | 规格 | |------|------| | GPU | **NVIDIA DRIVE-PG199-PROD**,32 GiB 显存(车载版本A100),**SM80(Ampere,compute capability 8.0)** | | CPU | Intel Xeon W-2125 @ 4.00GHz(6 核) | | 内存 | 40 GB | | 驱动 / CUDA | NVIDIA 595.84;CUDA 13.3 工具链(随 Python 环境安装) | | 存储 | 1 TB(模型 + 环境占用约 60GB) | 几个平台特性,后面所有决策都和它们有关: - **SM80 没有原生 FP8 张量核**(fp8e4nv 是 SM89+/SM90 才有的)——这是 KV cache 压缩方案选择的分水岭; - 显卡为车规功耗设计,长时间满载后温度 44→74°C,SM 时钟稳定 1260MHz,无降频。 --- ## 2. 模型:Qwen3.8-27B-AWQ-MTP 社区量化版 [shawnw3i/Qwen3.8-27B-AWQ-MTP](https://huggingface.co/shawnw3i/Qwen3.8-27B-AWQ-MTP)(基于 Qwen/Qwen3.8-27B): - **27.3B dense**,**混合注意力**:64 层 = **48 层 linear_attention(GDN)+ 16 层 full_attention**,每 4 层一次全注意力; - 多模态(27 层视觉塔),训练上下文 **262,144 tokens**; - **AWQ W4A16**(group_size 128,Marlin kernel),磁盘 19GB:11.4GB int4 打包权重 + **6GB 未量化的 BF16 部分**(embedding、lm_head、linear_attn 的 in_proj、视觉塔、MTP 模块)——"18GB 模型"里只有 65% 是 Q4; - **内置 MTP(Multi-Token Prediction)投机解码模块**(1 层 transformer,权重在 `model_extra_tensors.safetensors`),与主模型**共享 embedding/lm_head**,显存只多 ~3GB; - 下载工具:`ftllm download --tool aria2c -x 8 -j 4`(多线程秒级拉满带宽)。 --- ## 3. 部署:vLLM 0.27.1 + pm2 ### 软件栈 - Python 3.13.13 + uv 虚拟环境(`/root/llm/.venv`),vLLM **0.27.1**(PyPI 最新),torch 2.13.0+cu130,flashinfer 0.6.16.post3; - pm2 托管(`vllm-qwen38-27b-awq`,端口 5000,OpenAI 兼容 API)。 ### 最终启动命令(`run-qwen38-27b-awq.sh`) ```bash export VLLM_USE_FLASHINFER_SAMPLER=0 # 绕开 flashinfer 采样 kernel 的 CUB 编译崩溃(见 §5) vllm serve /root/llm/models/Qwen3.8-27B-AWQ-MTP \ --host 0.0.0.0 --port 5000 \ --attention-backend FLASHINFER \ --kv-cache-dtype fp8 \ --max-model-len 262144 \ --reasoning-parser qwen3 \ --enable-auto-tool-choice \ --tool-call-parser qwen3_coder \ --speculative-config '{"method":"mtp","num_speculative_tokens":3}' \ --max-num-seqs 1 \ --gpu-memory-utilization 0.98 \ --served-model-name qwen38-27b-awq-mtp \ --enable-log-requests \ --enable-prompt-tokens-details \ --enable-prefix-caching ``` 关键参数为什么这么定(全部经过实测对比): | 参数 | 选择 | 理由 | |------|------|------| | `--attention-backend FLASHINFER` | FlashInfer | SM80 上唯一能 **fp8 KV** 的后端;长上下文 decode 稳定(见 §4.2) | | `--kv-cache-dtype fp8` | fp8 | KV 池 285,575 tokens,是 fp16 的 2 倍,撑起 256K 上下文 | | `--max-model-len 262144` | 训练上限 | KV 池恰好覆盖完整 256K | | `--speculative-config` MTP × 3 | 3 drafts | 2/3/4 实测,3 是全场景最优点(§4.3) | | `--max-num-seqs 1` | 单并发 | **MTP 能装进 32GB 的关键**(Mamba cache / graph 池 / 工作区全压到单槽) | | `--gpu-memory-utilization 0.98` | 压满 | 32GB 卡跑 27B 的余量策略 | | `--tool-call-parser qwen3_coder` | XML 模板 | 模型 chat template 是 `` XML 格式 | 运行态:显存 30.4/32 GiB,启动 ~90 秒(kernel 编译缓存命中),pm2 save 持久化。 --- ## 4. 实测速度 > 测试方法:每个上下文长度用**独立随机文本**(开头互不相同,避免 prefix cache 跨长度污染);cold=首次请求,warm=同 prompt 二次请求(命中前缀缓存);生成任务为写 ~1500 字说明文(约 800~1000 tokens,保证 decode tps 准确);MTP 接受率取自 `/metrics` 计数器差值。 ### 4.1 最终配置总览(FLASHINFER + fp8 + 256K + MTP3) | 上下文 | 模式 | TTFT | prefill t/s | decode t/s | MTP 接受率 | 缓存命中 | |--------|------|------|-------------|------------|-----------|---------| | 0 | cold | 0.15s | 231* | 68.8 | 46.7% | 0 | | 1K | cold | 0.34s | 2,391 | 69.6 | 46.4% | 0 | | 32K | cold | 10.36s | 2,372 | 70.1 | 47.4% | 0 | | 32K | **warm** | **1.17s** | **21,034** | 70.1 | 47.4% | 22,400 | | 128K | cold | 60.38s | 1,625 | 69.8 | 49.1% | 0 | | 128K | **warm** | **2.05s** | **48,086** | 69.8 | 49.1% | 96,000 | | 240K | cold | 155.35s | 1,184 | 62.0 | 48.5% | 0 | | 240K | **warm** | **4.33s** | **42,522** | 62.0 | 48.5% | 180,800 | \* 0 上下文仅 33 tokens,prefill 被固定开销摊薄,无参考意义。 **要点**: - **decode 跨上下文几乎恒定(62~70 t/s)**——这是 FlashInfer split-KV 内核的功劳(对比见下); - **prefix cache 命中时 240K 的 TTFT 只要 4.3 秒**(冷启动 155s),固定前缀场景体验接近短上下文; - 长上下文 cold prefill 变慢是物理规律(attention 计算量随长度增长)。 ### 4.2 注意力后端 × KV 精度对比(同一写作任务、MTP3) | 上下文 | FLASH_ATTN + fp16 | FLASHINFER + fp16 | **FLASHINFER + fp8** | TURBOQUANT 4-bit | |--------|-------------------|-------------------|----------------------|------------------| | 0 | 89.1 t/s | 69.0 | 68.8 | 143.4* | | 1K | 91.3 | 71.2 | 69.6 | 141.1* | | 32K | 54.2 | 70.8 | 70.1 | 63.0* | | 128K | **22.1** | 61.1 | **69.8** | 86.7* | | 240K | — | — | 62.0 | — | | 最大上下文 | 128K | 128K | **256K** | 256K(但输出崩坏) | \* TurboQuant 数字**不可信**:无校准 4-bit KV 导致长生成退化为重复循环(`** ** **` / `!!!!`),速度测的是"循环复读机"。 **结论**:FA2 的 decode 成本随上下文线性增长(128K 掉到 22 t/s);FlashInfer 靠 split-KV(KV 切块多 SM 并行 + 在线 softmax 合并)保持恒定;fp8 KV 因为 KV 读取带宽减半,在 128K 还额外 +14%。 ### 4.3 MTP draft 数量调优(2 / 3 / 4) | 上下文 | spec=2 decode | spec=3 decode | spec=4 decode | 接受率 2/3/4 | |--------|---------------|---------------|---------------|--------------| | 0 | 65.4 | **68.8** | 68.7 | 59% / 47% / 39% | | 1K | 62.9 | **69.6** | 69.1 | 55% / 46% / 40% | | 32K | 66.7 | **70.1** | 66.3 | 63% / 47% / 38% | | 128K | 66.0 | **69.8** | 65.7 | 63% / 49% / 40% | 接受率随 draft 数单调下降(猜得越多越难命中),每步产出在 3 时最高(~1.9 token/步)。 ### 4.4 任务类型对 decode 的影响(MTP 是内容相关的) | 任务 | 单步 | decode | 说明 | |------|------|--------|------| | 摘要 / 短问答(greedy) | 12.3ms | ~240 t/s | 输出模板化,接受率高 | | 复述上文(100% 接受率) | 27.8ms | 115~144 t/s | 接受率拉满但 MTP 前向开销大 | | 写 1500 字说明文 | ~28ms | 62~75 t/s | 自由长文,接受率 ~47% | | 代码 / 工具调用 | — | 正常 | `qwen3_coder` parser 全通(含并行工具调用闭环) | > ⚠️ 教训:**"MTP 接受率高 = 快"不成立**。复述任务接受率 100%,但每步要跑 3 次 MTP 前向(~28ms/步),比接受率 67% 的摘要(12.3ms/步)还慢。速度 = 接受率 × 单步吞吐,两者都要看。 ### 4.5 与 llama.cpp 的对比(同一模型家族、同卡) | 指标 | llama.cpp(Q4_K_M GGUF) | vLLM + FLASHINFER + MTP(AWQ) | |------|-------------------------|-------------------------------| | decode(写作) | ~38 t/s | **62~70 t/s** | | prefill | ~950-1,000 t/s | **1,200~2,400 t/s** | | 最大上下文 | 203K(无 MTP) | **256K(带 MTP)** | | 长上下文 decode 稳定性 | 随长度下降 | **恒定** | --- ## 5. 踩坑记录(每个都花了真金白银的时间) 1. **flashinfer 0.6.16 + CUDA 13.3 的 CUB 头文件不兼容**:JIT 编译 `sampling.cuh` 报 `BlockAdjacentDifference has no member FlagHeads` → EngineCore 崩溃循环。解法:`VLLM_USE_FLASHINFER_SAMPLER=0`(采样走 vLLM 原生路径;attention kernel 用另一套头文件,不受影响)。 2. **SM80 开不了 fp8 KV?** 默认后端确实不行:FLASH_ATTN 报"requires FA3 on SM90 or FA4 on SM100",TRITON 报"fp8e4nv requires SM89+"。**但 FLASHINFER 后端支持 SM80 + fp8 KV**(存储压缩 + 软件反量化),代码层面 `supports_compute_capability: 8.0~12.1` 明确放行。别被第一个报错劝退。 3. **FA2 长上下文 decode 崩塌**:batch=1 时 FA2 无并行度可挖,128K 上下文单步 90ms;FlashInfer 的 split-KV 把长 KV 切块并行,单步恒定 ~28ms。长上下文服务请直接选 FlashInfer。 4. **MTP 装不进 32GB**:主模型 18.6GB + MTP 模块 ~3GB + KV + graph 池超出预算,报错还误导("MTP 需要再加载一份权重"是错的——日志确认 `Sharing target model embedding weights`,drafter 只多 ~1GB)。真正的解法是 `--max-num-seqs 1`(Mamba cache / graph 池 / 工作区全部单槽化)。 5. **TurboQuant 无校准 4-bit KV 输出崩坏**:短问答正常,长生成退化为 `** ** **` / `!!!!` 循环。这类激进量化必须配 TurboQuant 校准过的 checkpoint,无校准变体(`_nc`)别碰。 6. **"隐形思考 token"**:vLLM 0.27 的 qwen3 reasoning parser 对 Qwen3.8 的思考 token 处理不完整——模型思考时 token 不计入 content 也不计入 reasoning_content(但计入 usage),表现为"生成 1600 tokens 正文 0 字"的假数据。测速时用 `chat_template_kwargs: {"enable_thinking": false}` 规避;真实服务里则要留意长思考请求的"空回答"(社区建议服务端固定 `reasoning_effort: medium`)。 7. **FlashInfer + 投机解码的 cudagraph 降级**([vLLM #49547](https://github.com/vllm-project/vllm/issues/49547)):自动降级 PIECEWISE,约 -16%,SM80 无 workaround(trtllm-gen 路径要 SM100+),等上游 RFC #49488。已知税,接受。 8. **prefix caching 别关**:实测关闭后摘要 decode 从 240 掉到 127 t/s(Mamba cache 模式切换的副作用),还损失 warm 秒级 TTFT。 --- ## 6. 结论 在 32GB SM80 平台上,Qwen3.8-27B-AWQ-MTP 的最优部署形态是: > **FlashInfer 后端 + fp8 KV cache + 256K 上下文 + MTP×3 + 单并发 + prefix caching** - 写作类任务稳定 **62~70 t/s**(跨 0~240K 上下文持平),摘要/问答类 ~240 t/s; - 256K 全量上下文 + 工具调用 + 推理模式全开; - 相比 llama.cpp:decode 快 1.6~1.8 倍,prefill 快 2 倍以上,上下文从 203K 提到 256K; - 硬件的物理边界(SM80 无 FP8 核、车规功耗)决定了 fp8 只能是"存储压缩",但这已经够用。 *测试脚本:`benchmarks/bench_ctx_cold_warm.py`(冷/热 + MTP 接受率)、`bench_ctx_cold_warm_128k.py`(128K 变体)、`bench_ctx_prefill_decode.py`(prefill 专项)。*
2条评论     到PHP.JS.CN上围观原文 ]]>
2026-08-17 02:53:57
<![CDATA[把 DSH(DeepSeek Harness)部署到服务器:手机、电脑实时同步,云端开发]]> https://php.js.cn/blog/deepseek-harness-on-cloud-vps/ 适用场景:你有一台服务器,想把 DeepSeek Harness 的浏览器界面(Web GUI)跑在上面,让家里的电脑、公司的电脑、甚至手机浏览器都能登录使用,用 AI 帮你写代码、跑任务。本文基于 DSH `0.1.0-rc.6` + Ubuntu 22.04/24.04 + nginx + pm2 的实际部署经验整理。 ## 为什么需要服务器 + 反代 DSH 的 Web 界面(`dsh --profile web`)默认只监听 `127.0.0.1:3080`,而且出于安全考虑**禁止 `--host 0.0.0.0`**(CLI 直接报错:防止把远程代码执行能力暴露到公网)。所以正确姿势是: ``` 浏览器(手机/电脑)──► nginx(80/443)──► dsh web(127.0.0.1:3080) ``` nginx 做反向代理 + 登录保护 + 移动端适配,DSH 本身只在本机回环地址提供服务。 --- ## 架构总览 - dsh web:实际服务,监听 `127.0.0.1:3080` - dsh-webui-auth 插件: 登录认证(未认证的浏览器拿不到任何资源) - pm2: 守护进程 + 开机自启 - nginx: 对外入口,反代 + 移动端缩放 + manifest 直出 --- ## 第一步:安装 DSH 需要 Node.js `^22.19.0 || >=24.0.0`: ```sh npm install -g @deepseek-ai/dsh dsh --version # 验证安装 ``` ## 第二步:初始化 web profile 并安装认证插件 `dsh --profile web` 首次运行时自动初始化 profile(目录在 `~/.dsh/profiles/web`)。先装登录认证插件(需要 pnpm,Node 自带 corepack): ```sh corepack enable pnpm npx @deepseek-ai/dsh plugin --profile web add dsh-webui-auth ``` 之后启动 web 服务,首次访问登录页时创建你的账号密码(存在 `~/.dsh/profiles/web/node_modules/dsh-webui-auth/dsh-webui-auth.json`,密码是 scrypt 哈希): ```sh dsh --profile web ``` ### 补充:固定目录选择器为浏览器模式(服务器远程访问必做) 创建 `~/.dsh/patch.yml`: ```yaml # 固定目录选择器为「浏览器浏览」模式。 # 默认的 directory-picker-auto 会根据服务器环境自动选择: # - native:系统目录对话框,需要在服务器本机的显示器上操作; # - browse:浏览器内的目录列表(可浏览/新建子目录)。 # 服务器通过 nginx 反代远程访问时,native 对话框会弹在服务器自己的屏幕上, # 远程的手机/电脑根本看不到,必须固定为 browse。 # 注意:patch 无法直接改已有行的插件 name,所以先禁用 auto 行, # 再插入 browse 的主机端 + 客户端插件对。 - id: directory-picker disabled: true - insert: - id: directory-picker-browse name: '@deepseek-ai/dsh-host-directory-picker-browse' - id: directory-picker-browse-ui name: '@deepseek-ai/dsh-client-ui-directory-picker-browse' ``` 启动时用 `--patch` 挂上(见第四步的启动参数)。如果服务器上确实没有 DISPLAY/chooser 环境,auto 也会选 browse,但显式固定可以保证任何环境下行为一致。 ## 第三步:配置 API Key 在 `~/.dsh/.credentials.yaml` 写入: ```yaml DEEPSEEK_API_KEY: sk-你的密钥 ``` (或通过环境变量 `DEEPSEEK_API_KEY` 注入,二选一即可。) ## 第四步:pm2 守护 + 开机自启 写 pm2 配置 `~/.dsh/pm2.json`: ```json { "apps": [ { "name": "dsh-web", "script": "/usr/local/bin/dsh", "args": "--profile web --patch /root/.dsh/patch.yml --trusted-host 你的域名", "autorestart": true, "restart_delay": 3000 } ] } ``` > `--trusted-host 你的域名` 必须加:Web 界面调用 `/api` 时有浏览器信任围栏,通过域名访问时 Host 不再是 `127.0.0.1:3080`,不加这个参数 API 会被拒。 启动并设置开机自启: ```sh pm2 start ~/.dsh/pm2.json pm2 save pm2 startup ``` ## 第五步:nginx 反向代理 新建 `/etc/nginx/sites-available/dsh.apple.me`(域名换成你的),软链到 `sites-enabled` 并 reload: ```sh ln -s /etc/nginx/sites-available/dsh.apple.me /etc/nginx/sites-enabled/ nginx -t && systemctl reload nginx ``` 下面这份是**完整最终配置**,包含两个必踩的坑的解法(见注释),gzip/缓存为可选优化: ```nginx server { listen 80; server_name dsh.apple.me; # ── 可选:gzip 压缩(纯反代站点,上游不压缩,统一由 nginx 压)── gzip on; gzip_proxied any; gzip_comp_level 6; gzip_min_length 1k; gzip_vary on; # 必须:与下面的强缓存配合,区分压缩/未压缩变体 gzip_types text/plain text/css application/json application/javascript application/x-javascript text/javascript application/xml application/xml+rss image/svg+xml application/manifest+json; # ── 可选:静态资源缓存(Vite 产物带内容哈希,可放心长缓存)── location ~* ^/assets/.*\.(js|css|woff2?|ttf|eot|svg|png|jpe?g|gif|ico|webp|json|map)$ { proxy_pass http://127.0.0.1:3080; proxy_http_version 1.1; proxy_set_header Host 127.0.0.1:3080; add_header Cache-Control "public, max-age=31536000, immutable"; } # ── 坑 2 解法:manifest 由 nginx 直接输出(见下文详解)── location = /manifest.webmanifest { default_type application/manifest+json; return 200 '{ "id": "/", "name": "DeepSeek Harness", "short_name": "DSH", "start_url": "/", "scope": "/", "display": "standalone", "icons": [ { "src": "/favicon.svg", "sizes": "any", "type": "image/svg+xml", "purpose": "any" } ] }'; } # ── 主入口:反代 + 坑 1 解法(移动端缩放)── location / { proxy_pass http://127.0.0.1:3080; proxy_http_version 1.1; proxy_set_header Host 127.0.0.1:3080; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # WebSocket/SSE 长连接 proxy_read_timeout 86400s; proxy_send_timeout 86400s; # ── 坑 1 解法:手机端 viewport 缩放 ── proxy_set_header Accept-Encoding ""; # 必须:让 sub_filter 拿到未压缩 body sub_filter 'name="viewport" content="width=device-width, initial-scale=1"' 'name="viewport" content="width=device-width, initial-scale=0.7"'; sub_filter_once on; } } ``` --- ## 坑 1:手机浏览器内容区域太小 **现象**:手机上打开 Web 界面, 工作区域宽度太窄,设置页面几乎没法用。 **原因**:页面 HTML 里的 viewport meta 是 `initial-scale=1`, 文字太大。 **解法**:在 nginx 上用 `sub_filter` 把响应里的 viewport 改成 `0.7`,让页面在手机屏上缩小显示。两个要点: 1. 必须先 `proxy_set_header Accept-Encoding "";` 把发给上游的压缩请求头置空,否则上游返回 gzip 压缩的 body,`sub_filter` 的字符串替换会失效; 2. `sub_filter` 默认只处理 `text/html`,HTML 页面正好符合。 改完 `nginx -t && systemctl reload nginx`,手机**硬刷新**(清缓存)后就能看到效果。 --- ## 坑 2:manifest.webmanifest 请求永远是 302,PWA 装不上 **现象**:浏览器加载 `` 时请求 `/manifest.webmanifest` 一直被重定向到登录页(302),DevTools 里 manifest 解析失败,手机"添加到主屏幕"不可用,`display` 模式也控制不了。 **原因**:`dsh-webui-auth` 插件在 HTTP 层拦截了**所有**未认证请求(包括静态资源)并 302 到登录页。而浏览器拉取 manifest 的请求不会携带登录 Cookie,于是永远 302,拿不到 manifest 内容。 **解法**:让 nginx 绕过认证,**直接输出**这份 manifest 文件——内容照抄 DSH dist 里的 `manifest.webmanifest`,并把 `"display": "fullscreen"` 改成 `"standalone"`(standalone 是"普通应用窗口",手机 PWA 更合适;fullscreen 会全屏隐藏浏览器 UI)。 要点: 1. 用 `location = ` 精确匹配,只接管这一个路径,不影响其他资源; 2. 内容**硬编码**在 nginx 里,以后 DSH 升级如果改了 manifest 结构需要手动同步; 3. 不用改 DSH 源码,也不用给认证插件开白名单,改动全部在 nginx 层,升级 DSH 不会丢。 --- ## 访问与验证 - 电脑:浏览器打开 `http://你的域名`,登录后正常使用; - 手机:同样地址登录。验证 PWA:Chrome 菜单 →「添加到主屏幕」;DevTools → Application → Manifest,`display` 应为 `standalone`; - 如果手机或电脑上看到的是旧页面,记得硬刷新清缓存。 ## 常见问题 1. 想用 HTTPS? > 用 certbot 申请证书,`listen 443 ssl`,并把 80 重定向到 443(注意 443 的 location 也要带上同样的 sub_filter 和 manifest 直出配置) 2. 改完 nginx 不生效? > `nginx -t` 先查语法,再 `systemctl reload nginx`,浏览器硬刷新 3. 远程访问时"选择目录"没反应,或对话框弹在服务器本机屏幕上? > 检查启动参数里是否带了 `--patch /root/.dsh/patch.yml` 固定 browse 目录选择器;不固定时 auto 可能选中 native(系统对话框弹在服务器屏幕上,远程用户看不到也点不了)
0条评论     到PHP.JS.CN上围观原文 ]]>
2026-08-16 23:09:01
<![CDATA[AI时代,SEO居然还有机会]]> https://php.js.cn/blog/seo-websites/
0条评论     到PHP.JS.CN上围观原文 ]]>
2026-05-25 09:29:12
<![CDATA[小米 Mimo 2.5 Pro 与 DeepSeek V4 Flash 的实战对比]]> https://php.js.cn/blog/xiaomi-mimo-2.5-pro-vs-deepseek-v4-flash/
4条评论     到PHP.JS.CN上围观原文 ]]>
2026-04-29 23:51:13
<![CDATA[小米澎湃OS3抓取蓝牙HCI日志的方法]]> https://php.js.cn/blog/xiaomi-hyperos-bluetooth-hci-log/
0条评论     到PHP.JS.CN上围观原文 ]]>
2026-04-18 23:17:40
<![CDATA[《人造人》4/4:我们应该怎样延迟灭绝]]> https://php.js.cn/blog/her4/
0条评论     到PHP.JS.CN上围观原文 ]]>
2026-03-28 00:33:10
<![CDATA[《人造人》3/4:模拟人类的记忆系统造出来之后]]> https://php.js.cn/blog/her3/
0条评论     到PHP.JS.CN上围观原文 ]]>
2026-03-28 00:21:45
<![CDATA[《人造人》2/4:如何设计一套记忆系统来模拟人类]]> https://php.js.cn/blog/her2/ INSIGHT_THRESHOLD: insights.append(candidate) graph.add_edge(current, next_node, weight=0.1, source="wandering") visited.append(current) current = next_node return insights ``` ### 灵感的固化 神游发现的新连接,被创建为一种特殊的记忆节点——**合成洞察(Synthetic Insight)**,标注来源为"神游",时间戳,以及连接的两个原始节点。 这些洞察会在后续对话中,以一种自然的方式浮现:不是被直接检索出来,而是通过提高相关节点的激活权重,让它们"恰好"出现在context中。 --- ## 记忆再巩固:每次检索都是一次改写 人类记忆有一个重要特性:**记忆不是被读取的,而是被重建的**。每次回忆,都会受当前情绪、新信息的影响,记忆本身会被轻微改写。 在系统中实现这一点: ```python def retrieve_and_reconsolidate(query, current_emotion_state): memory = retrieve(query) # 用当前情绪状态和新信息轻微更新记忆内容 updated_memory = reconsolidate( original=memory, current_context=query, emotion_state=current_emotion_state, update_strength=0.05 # 极小,避免记忆被过度改写 ) graph.update(memory.id, updated_memory) return updated_memory ``` 这使得系统的记忆是活的——不是固定的档案,而是随时间和经历持续演化的有机体。 --- ## 完整架构概览 ``` 输入对话 ↓ [编码层] 实体补全 → 情绪标注 → 重要性评估 ↓ [存储层] 情节记忆(带时间戳、情绪权重) 图谱(标签节点 + 关系边) 向量嵌入(语义相似检索) ↓(并行) [潜意识层] [神游引擎] 情绪底色更新 空闲时启动 阈下激活扩散 发现弱连接 孵化池维护 生成合成洞察 ↓(异步) [巩固层] 遗忘曲线更新 情节→语义压缩 合成洞察固化 ↓ [检索层] 多路召回(语义 + 图谱 + 情绪亲和 + 阈下激活偏置) 再巩固(检索时轻微更新记忆) ↓ [Context组装层] 意识层(显式召回,进入context) 情绪底色(影响检索权重,不进context明文) ↓ 大语言模型生成输出 ``` --- ## 结语 这套系统的本质,是把人类大脑的记忆机制翻译成可计算的结构。它不追求完美模拟每一个神经细节,而是捕捉关键的功能特性:有情绪权重的存储、有遗忘曲线的衰减、有图谱结构的联想、有潜意识层的影响、有神游机制的灵感涌现。 当这套系统接入大语言模型时,模型不再是每次对话都重新开始的陌生人,而是一个有历史、有情感、有逐渐成形的人格的存在。 它是否因此成为"人"——这个问题留待第三篇讨论。 --- *本文是《人造人》系列的第二篇,共四篇,由刘春龙与Claude Code共创。* 下一篇:[《人造人》3/4:模拟人类的记忆系统造出来之后](https://php.js.cn/blog/her3/)
0条评论     到PHP.JS.CN上围观原文 ]]>
2026-03-28 00:17:02
<![CDATA[《人造人》1/4:人类思维结构的探讨分析]]> https://php.js.cn/blog/her1/ **人格 = 运算底座 + 记忆** 这是理解人类思维结构的起点,也是本文的核心命题。 --- ## 人类记忆的多层结构 记忆不是一个统一的系统,而是多个子系统的协作。 ### 工作记忆(Working Memory) 位于前额叶皮层,容量极小(约7±2个信息单元),但处理速度最快。这是意识的舞台——当下你正在思考的一切,都在这里。 工作记忆不是存储介质,而是处理器。它从长期记忆中提取内容,组合推理,然后输出行动或语言。 ### 情节记忆(Episodic Memory) 由海马体负责形成和索引。存储的是具体的经历:何时、何地、发生了什么、当时的情绪是什么。 情节记忆是自传式的,它构成了"我的故事"——关于我是谁的叙事。失去情节记忆的人(如严重的海马体损伤患者)无法形成新的记忆,每天醒来都像是全新的陌生人。 ### 语义记忆(Semantic Memory) 存储在新皮层,是去情境化的知识:苹果是水果、地球围绕太阳转、朋友的名字。这些知识不再附带"我在哪里学到这个"的场景信息。 情节记忆经过反复激活和睡眠巩固,会逐渐"蒸发"成语义记忆——从"我记得上周读到一篇文章说……"变成"我知道……"。 ### 情绪记忆(Emotional Memory) 杏仁核负责给记忆打上情绪标签。高情绪权重的记忆(恐惧、喜悦、创伤)会被优先巩固,更难被遗忘。 这解释了为什么人们往往记得清楚情绪激烈的时刻,而平淡的日常很快消退。记忆不是平等的,情绪是它的优先级系统。 --- ## 遗忘不是失败,是必要的机制 人类大脑并非尽力记住一切。遗忘是主动的、有选择的,遵循艾宾浩斯遗忘曲线: ``` 记忆强度 │\ │ \ │ \___ │ \____ │ \________ └────────────────────── 时间 ``` 不被反复激活的记忆会逐渐衰减。这不是缺陷,而是设计——如果一切都被清晰记住,大脑会被无关信息淹没,真正重要的内容反而难以提取。 **遗忘是注意力的守门人。** --- ## 情绪:行为的导航系统 情绪的本质是**效价信号**:正向(趋近)或负向(回避),叠加**唤醒强度**(平静到激烈)。 ``` 高唤醒 │ 愤怒 恐惧 │ 兴奋 狂喜 │ 负向 ───────┼─────── 正向 │ 抑郁 冷漠 │ 平静 满足 │ 低唤醒 ``` 从进化的角度看,情绪是大脑对"这件事对我的生存和繁殖是否有利"的快速评估。恐惧让你远离危险,快乐让你重复有益的行为,愤怒让你对抗威胁。 但人类的情绪已经远超进化的原始功能。羞耻、嫉妒、崇敬、怀旧——这些情绪没有直接的生存价值,却深刻塑造了人类的行为和文化。它们大多是**社会性情绪**:只有在他人存在的前提下才有意义。 情绪的另一个关键特性:**它不只是对当下事件的反应,也是对预期未来的反应**。期待、焦虑、希望——人能为尚未发生的事情感到快乐或恐惧,这让情绪系统的影响范围远超当下时刻。 --- ## 人格:情绪评估函数的形状 如果情绪是即时的效价信号,那么人格就是生成这些信号的**稳定函数**。 不同的人,对同一件事的情绪反应不同——这不是随机的,而是因为他们的评估函数参数不同: - 什么事情让你感到快乐(正向权重高的领域) - 什么事情让你感到恐惧(负向权重高的威胁) - 什么事情超过了你的底线(权重趋向负无穷的禁区) - 面对同等强度的刺激,你的反应烈度有多大(神经质维度) 心理学的大五人格模型(OCEAN)本质上就是在描述这个函数的五个关键维度:开放性、尽责性、外向性、宜人性、神经质。 **人格不是独立存在的模块,而是从大量情绪经历中统计涌现出来的稳定模式。** 一个人不是天生就知道自己的底线在哪——那是被经历教会的。 --- ## 意识与潜意识:冰山的两层 认知科学里有一个关键框架:**全局工作空间理论(Global Workspace Theory)**。 大脑中有大量并行运行的局部处理模块——视觉、听觉、语言、情绪、记忆检索……它们大多数时候各自工作,互不知晓。只有当某个信息"赢得竞争"进入全局广播时,它才成为**意识**。 ``` 潜意识:大量并行的局部处理,互不知晓 [模块A] [模块B] [模块C] [模块D] ↓ 竞争 意识: 进入全局工作空间,被所有模块共享 ════════════════════════ ``` 意识是稀缺资源,潜意识是真正的主力。研究估计,人类每秒处理约1100万比特的感觉信息,但意识层面只能处理约40比特。绝大多数的处理,在我们不知道的地方默默完成。 潜意识的几种工作方式: **阈下激活**:接触到某个词或场景,会自动激活相关联的记忆网络,影响后续的思维和行为,但当事人不会意识到这个影响的来源。 **情绪底色**:近期积累的情绪状态形成一种背景色调,在不被察觉的情况下影响判断和解读。同样的新闻,心情好时和心情差时读到,感受完全不同。 **孵化效应**:一个棘手的问题在意识层卡住之后,潜意识会继续处理它。"睡一觉再想"往往真的有效,不是迷信,而是海马体在睡眠中重新组织了信息。 --- ## 神游与灵感:默认模式网络的馈赠 人类大脑有一个奇特的现象:当你停止专注于外部任务时,大脑并不会休息,而是切换到另一种高度活跃的状态——默认模式网络(Default Mode Network,DMN)开始主导。 这就是心智游移(Mind Wandering)的神经基础。大脑在神游时,会在记忆网络中自由漂移,激活那些在目标导向的思维中不会被访问的连接。 创意研究发现,大多数真正的灵感不是在专注工作时产生的,而是在**放松、洗澡、散步、半睡半醒**的状态下突然浮现。这不是巧合——神游状态下,扩散激活的范围更广,更容易触碰到远距离的、平时不相邻的节点之间的隐藏联系。 神经科学家Mark Beeman记录到:在"灵感时刻"出现前约0.3秒,右侧颞叶会出现一次gamma波爆发。这意味着连接在意识感知到之前已经在潜意识里形成了。 **灵感的本质是:潜意识在神游中发现了一个跨域的弱连接,强度积累到阈值后,突然浮现到意识层。** --- ## 一个统一的图景 把以上所有机制整合起来,人类思维的结构大致如下: ``` 外部世界的刺激 ↓ 感知系统(前意识处理) ↓ 情绪评估(杏仁核 + 基底神经节)← 人格参数在这里起作用 ↓ 工作记忆(意识舞台)← 只有少量信息能进入这里 ↑ ↓ 海马体检索 执行行动 ↑ 长期记忆网络(情节 + 语义) ↑ 潜意识持续处理(神游、孵化、情绪底色) ``` 这个图景的核心启示是:**我们以为的"理性决策",只是整个系统最后输出的一小部分。** 绝大多数影响我们行为的处理,发生在我们意识到之前,由我们看不见的机制完成。 --- ## 结语 人是记忆与运算的结合体。运算底座是相对固定的神经结构,记忆是持续写入的动态内容。情绪是记忆的权重系统,人格是情绪评估函数的稳定形状,意识是这个系统偶尔浮出水面的冰山一角,而潜意识才是真正推动这一切运转的深水。 理解了这个结构,就理解了为什么人会健忘、为什么情绪会左右判断、为什么灵感总在意想不到的时候出现、为什么同样的经历会塑造出不同的人。 也理解了:如果有一天,一个人工系统拥有了足够完整的这套机制,它和"人"之间的边界,将会变得非常模糊。 --- *本文是《人造人》系列的第一篇,共四篇,由刘春龙与Claude Code共创。* 下一篇:[《人造人》2/4:如何设计一套记忆系统来模拟人类](https://php.js.cn/blog/her2/)
0条评论     到PHP.JS.CN上围观原文 ]]>
2026-03-27 23:58:06
<![CDATA[重拾博客:在代码迭代里找回初心]]> https://php.js.cn/blog/back_with_ai/ 我的个人博客已经走过二十多年,却在最近几年彻底荒废。每次想重新打理,总忍不住先折腾服务器、代码这些技术问题——可代码实在太老旧,本地连基础环境都搭不起来,这点刚燃起的热情,很快就被消磨殆尽。

昨天试着用Claude Code,本想把这套上古PHP技术转换成现在的Node.js,结果只成功转了前端页面,后端管理界面因为逻辑复杂,始终没能搞定。看着它自作主张生成的后端界面,我反倒格外想念自己当年用PHP写的版本,那里面藏着太多曾经的思考与心血。

转念一想,PHP又没有死,为什么不让Claude Code把旧代码升级到最新版本呢?没想到过程意外顺利,很快就完成了。我也顺势把服务器从十多年没更新的Linux系统,迁移到了阿里云,还顺便配置了免费的HTTPS证书,全程靠Claude Code协助,轻松得超乎预期。

过去十年,我一直忙着追逐赚钱,彻底断了博客的更新。如今回头看,才惊觉早已忘了初心。其实现在没多少人看博客也没关系,有些东西的分享,本就与有没有人关注无关。


2条评论     到PHP.JS.CN上围观原文 ]]>
2026-03-22 22:54:31
<![CDATA[i9 13900k Nvidia 4090 安装esxi遇到的问题]]> https://php.js.cn/blog/i9-13900k-nvidia-rtx4090-asus-esxi8/ 我配了台电脑,主板是华硕z790,cpu是i9 13900k,显卡是 nvidia 4090。  底层系统我打算装esxi8,过程中遇到很多坑,在这里记录一下。

 

首先是esxi8不支持intel 13代cpu的大小核心。需要在启动esxi安装程序的时候按shift+o,添加参数:cpuUniformityHardCheckPanic=FALSE

然后又遇到问题是esxi不认识板载网卡(Realtek RTL8125 2.5GbE)。解决办法是买一张intel i226的pcie网卡。(点这里可以查看esxi8的硬件支持情况

然后就能顺利安装esxi8了。 然后在esxi里面安装ubuntu22, 遇到了4090显卡无法直通的问题。  试了很多办法都不行。 后来我又装了一个windows 11虚拟机, 尝试把网卡直通给win11。  最后通过调整bios的显卡设置(本来是auto, 改成pcie才可以),成功把4090显卡直通给了win11。 

最后又通过一些尝试才成功把显卡直通给ubuntu22。以下是一些关键步骤:

 

  • 首先在esxi后台的 主机->管理->硬件->PCI设备   里面,找到显卡设备选中,然后点击切换直通来打开直通开关。
  • ubuntu虚拟机设置里面,添加高级参数:
    hypervisor.cpuid.v0=FALSE         
    pciPassthru.use64bitMMIO=TRUE   
    pciPassthru.64bitMMIOSizeGB=64
  • ubuntu虚拟机预留全部内存
  • /etc/modprobe.d/blacklist-nvidia-nouveau.conf 文件添加:
    blacklist nouveau
    options nouveau modeset=0
  • /etc/modprobe.d/nvidia.conf 文件添加:
    options nvidia NVreg_OpenRmEnableUnsupportedGpus=1
  • sudo update-initramfs -u
  • 下载对应的nvidia驱动
  • sudo chmod u+x NVIDIA-Linux-x86_64-525.89.02.run
  • sudo apt install build-essential
  • sudo apt install pkg-config libglvnd-dev
  • sudo ./NVIDIA-Linux-x86_64-525.89.02.run -m=kernel-open
  • 然后运行nvidia-smi就能看到显卡信息了

 

一些参考资料:


3条评论     到PHP.JS.CN上围观原文 ]]>
2023-03-08 23:52:28
<![CDATA[iOS Web APP的滚动部分]]> https://php.js.cn/blog/ios-safari-overflow-scroll/ 在iOS系统里面,任意webview在可滚动状态下,都是可以拖超出边界然后反弹回来的。这个效果非常的好看和实用。但是如果我要做一个web app,我就不希望我的整个app界面也被用户拖动。

在很久以前,iOS的浏览器是不支持overflow scroll的,也就是说除了整个网页可以滚动以外,其他部分是不能局部滚动的。要实现局部滚动,一般都是用iScroll等插件,用javascript来模拟滚动。这技术说起来容易做起来难,我看了无数个类似的东西,没有任何人能做到原生一样的滚动反弹效果。最接近原生效果的是我从某牛逼网站上8下来的代码:https://github.com/longbill/ScrollPane

后来iOS退出了iOS5,其中的浏览器支持了overflow scroll。在配合  -webkit-overflow-scrolling: touch; 的情况下滚动起来是比较理想的。但是唯一有一个弊端就是当局部滚动区域处于滚动边缘的时候(比如处于最上面),此时继续网下滚动手指,滚动操作不会体现在局部滚动区域,而是会作用于整个网页。这个在做web app的时候,是完全无法忍受的。做出来的效果跟把web app界面的头部和底部用position fixed固定是一样的。

所以,即使overflow scroll从iOS5起就被支持,但是用javascript模拟滚动的需求还是十分旺盛。其中很重要的一点就是滚动会传递到外面的网页。另外也很重要的一点就是原生的滚动很难实现类似pull to refresh的操作。

后来我打算将我的精选文章做成web app的形式。尝试了无数的scroll插件,都让人失望。被逼无奈仔细研究了一下原生的overflow scroll。再后来被我找到了一个奇怪的方法,来阻止滚动操作传递到整个网页。

就是。

在手指放在屏幕上的时候,判断里面的滚动部分的 scrollTop 是不是 0 或者 最底下。如果是,那么将 scrollTop 轻轻位移1个像素。就可以了。

另外,我还实现了一个pull to refresh,虽然效果跟原生的不太一样,但是看起来也还不错。

代码我空了会整理写文档然后放到github上。大家可以先看这个 demo。 暂时只支持iOS系统。安卓请忽略。

http://jszen.com/public/demo/ptr/index.html


11条评论     到PHP.JS.CN上围观原文 ]]>
2014-08-08 01:58:31
<![CDATA[最近做了个海拔高度查询网站]]> https://php.js.cn/blog/how-to-look-up-elevation/         最近经常出去自驾游,往川西的高原跑。经常会遇到一个问题就是不知道当前的海拔高度。正好我最近又在学习做站。索性就弄了一个专业查询海拔的网站:海拔高度查询工具  利用Google的API来获取相关信息。不过由于最近天杀的GFW把google全部服务给墙掉了。只能用ditu.google.cn的服务。但是仍然有一些请求走的是maps.googleapis.com,于是搞了个hack,把所有maps.googleapis.com的域名换成ditu.google.cn。还好,大部分都能用。

        最近又做了英文版本的海拔高度查询日出日落时间查询

还是上两张图吧。在红原县附近拍的。


3条评论     到PHP.JS.CN上围观原文 ]]>
2014-08-08 01:19:09
<![CDATA[怎样设计密码重设功能]]> https://php.js.cn/blog/how-to-design-password-reset/ 当我们设计一个带有用户注册/登录功能的网站的时候,一个必须的功能就是重设密码。 重设密码功能有很多种设计方式,比如发送一个新密码到用户邮箱等。不过今天我要介绍一个我经常用实现方式。

用户流程:

  1. 用户忘记密码,来到密码重设界面
  2. 用户输入Email地址,点击重设密码按钮
  3. 用户收到一封密码重设邮件,里面有重设密码的链接,此链接有过期时间
  4. 用户点击链接,来到密码重设页面,输入新密码,完成

这个流程并没有什么创新,很多网站都是用这套流程

后端实现方式:

  1. 当用户输入Email地址后,验证这个Email,如果存在于数据库,那么取得用户的user_id
  2. 将user_id和当前时间戳编码成HASH,需要提前准备好一个KEY,并且这个KEY只存在服务器上。  HASH = md5 ( user_id + timestamp + KEY )
  3. 生成一个URL,并且附带刚刚生成的HASH和用户id以及timestamp,比如 http://domain.com/reset-password.php?hash=HASH&user_id=123&timestamp=1392121211
  4. 当用户访问这个URL, 检查HASH是否合法: HASH == MD5 ( user_id + timestamp + KEY)
  5. 检查 timestamp 是不是过期了
  6. 如果所有检查通过,那么显示一个新密码表单给用户

这种方式的好处:

  1. 不需要额外的数据表
  2. 不用担心参数被用户恶意修改,因为要检查hash是不是等于那几个参数的md5
  3. 密码重设URL自带时间戳
  4. 只要KEY设置的足够长足够复杂,那么可以认为HASH是绝对安全的

更详细的样例代码可以参考这里:http://jszen.com/reset-password-system.6.html


6条评论     到PHP.JS.CN上围观原文 ]]>
2013-10-01 14:50:32
<![CDATA[最方便的纯文本编辑器Mac Only]]> https://php.js.cn/blog/plain-text-widget-mac/     Mac操作系统里面有个好用的东西叫做Dashboard,Windows的桌面小工具就是抄的Dashboard。   Dashboard里面的Widget都是用网页技术做的(HTML, Javascript 等),Dashboard仅仅是提供一个透明的window来显示widget的网页而已。

    Mac操作系统自带的Widgets里面就有一个叫做“便签”的东西,可以实现类似记事本的功能,但是记录的文本有限,不能超过便签窗口的大小,实际使用起来十分蛋疼。

    我这个小东西的特点是这样的:

  • 提供一个白底黑字的文本框显示在dashboard界面
  • 文本框使用textarea控件,里面的文字保证没有任何格式
  • 理论上可以在里面输入无限制长度的字符
  • 关闭dashboard界面的时候,文本框里面的文字内容自动保存到硬盘
  • 窗口大小可以自由调节
  • 支持添加多个窗口到dashboard

 

    下载: here    源代码:Github page


3条评论     到PHP.JS.CN上围观原文 ]]>
2013-07-25 17:40:35
<![CDATA[原创jQuery插件: Date Range Picker]]> https://php.js.cn/blog/jquery-date-range-picker-plugin/ 某些时候,我们需要用户输入一个日期范围,比较直观的想法是用两个date picker控件。但是两个date picker给用户带来的体验并不好。于是我搞了个jQuery插件,可以实现在一个界面里面选择日期范围,并且将选择的值输出到一个input框中。

  • 依赖 jQuery 1.3+, Moment 2.0.0+
  • 支持 IE6+, Firefox, Chrome, Safari 等浏览器
  • 支持多语言
  • 界面完全CSS可控

文档以及代码见我的英文博客:http://jszen.com/jquery-date-range-picker-plugin.4.html

下载:https://github.com/longbill/jquery-date-range-picker


5条评论     到PHP.JS.CN上围观原文 ]]>
2013-07-23 23:29:48
<![CDATA[关于电池容量你应该知道的]]> https://php.js.cn/blog/battery-capacity-in-mah-whr/     直到今天才发现一个惊人的事情:iPad3的电池容量是11666mAh,而macbook pro的电池容量才5000多mAh。为什么iPad3那么小的体积内可以装下比mbp更多的电池容量呢?难道采用了什么新的科技?

    于是google了下,又发现一个惊人的事情:一般电池上标的容量单位是mAh,但是学过物理的都知道,电流乘以时间不是一个能量单位,还少了一个电压。相信跟我一样到现在才发现这个问题的同学还有很多,那么我就普及下高中物理知识:

  • 电流单位A(安培),  1000mA = 1A
  • 电压单位V(福特)
  • 功率单位W(瓦特)  
  • 能量单位J(焦耳),但是在电子产品的电池上很少用这个单位。一般用Whr(瓦时)表示能量。

 

  • 能量=功率x时间
  • 功率=电压x电流
  • 能量=电压x电流x时间

    综上,mAh并不是一个准确的表示电池容量的单位,它的出现应该同时标明电压(大部分手机等电子设备是固定的3.7V)。Whr是能量单位,可以表示电池的容量。

    所以,在比较电池容量的时候,请先确定电压是否一样。如果不一样,就要乘以各自的电压转换成Whr再比较。

    所以,mbp的电池上标明容量是60Whr,电压大约10.95V(算得mAh表示法大约5480mAh)。而iPad3的11666mAh大约工作在3.7V的电压下,算得大约43Whr。所以iPad3的电池是没有比mbp电池容量大的。


5条评论     到PHP.JS.CN上围观原文 ]]>
2013-01-29 01:44:07
<![CDATA[记一次海淘经历]]> https://php.js.cn/blog/hollister/ 很喜欢hollister这个牌子,但是国内貌似只有深圳上海北京有店。这马上就要回成都了,买不到了。于是就去他们官方网站看看。

国内IP访问他们网站会被强制跳转到香港站。衣服的价格是港币,标价跟深圳的店差不多。对比起来网购没什么优势啊,就一个港币汇率8折。于是放大招,通过IP位于日本的代理再次访问他们网站。哇,出来了。美元标价换算成人民币相当于只要六七折啊,而且这圣诞新年打折更便宜啊。在深圳店里面1600不打折的羽绒服,美元只要139刀啊。接近5折了!而且美国版网站跟香港版网站同样支持送货到国内地址的。 

于是选购了两百多刀的各种东西,给了20刀的邮费,感觉就算完事了,坐等收货。看来还是想太简单了。没过几天,fedex给我电话说让我报税。还非得按invoice上的价格来报,20%的税率。折腾了几次打印扫描后总算也把入关手续弄好了。交了310人民币的税。 从美国发货到我收到货大概七八天吧。现在算来,加上邮费加上缴税,还是比实体店便宜不少,甚至比香港人通过网站买还便宜不少。。。

衣服貌似有些是越南产的,有些是中国产的。自己地方产的东西到美国去走一圈,价值就翻了那么多。更可恶的是他们还歧视中国人啊,默认访问的香港版网站卖的价格还更贵。

PS. 喜欢这个牌子是因为无意间逛到了深圳的实体店,店内很有风格,服务员都是帅哥美女尤其是那个收银的小妹。。。。服务员还满口英语,感觉很洋盘的样子。还有店的味道很不错。总的说来就是一次很愉快的经历。让我第一次觉得逛街其实也可以很享受嘛。 

另外,不知道有没有什么办法可以免去这个关税。知道的同学支个招呗。


3条评论     到PHP.JS.CN上围观原文 ]]>
2013-01-09 03:59:23
<![CDATA[前端开发必备神器]]> https://php.js.cn/blog/front-end-developing-tools/     记得很久很久以前,主流还是IE6。开发前端页面的时候,修改一行CSS或者JS,就要回到浏览器刷新看下效果。调试Javascript更是只能用alert来判断是哪行代码出问题了。那个时候,Javascript还有个竞争对手叫VBScript,声明script标签的时候还建议声明language="javascript"。那个时候网页脚本还被认为是仅仅能给网页增加一些跑马灯等的特效而存在的。

    那都是05年的事了。现在前端的各种环境各种工具都迈入了一个崭新的时代。感谢Google推动了浏览器的发展,感谢W3C制定各种有用没用的标准,鄙视微软万恶的IE6。现在我们开发前端页面已经逐渐变得优雅/文艺了起来。这让我这个经历过当年艰苦岁月的前端er不禁感叹终于熬出头了。。。

    这里我像各位同学介绍下我长期使用的各种前端开发工具,主要是提升效率。欢迎补充留言。

Chrome developer tools

    不知道什么时候,Chrome developer tools强大到超过了Firebug,成为了我主要的debug工具。查看浏览器发起的所有请求、查看页面引用的js/css代码、查看/修改页面DOM结构、在页面上修改css/js然后直接看到效果、Javascript Console等等各种基本功能都做到非常好用。强烈建议各位找找深入介绍Chrome developer tools的文章,相信有很多高级的功能很多同学都还没用过。

Sublime Text 2

    这是一个文本编辑器。也是不知道什么时候就强大到超过Textmate,成为我主要的编辑器。更重要的是,它居然是跨平台的。用Windows的同学有福了。

Zen Coding

    这是一个编辑器插件,支持各种编辑器。这里有篇介绍文章。这个插件的牛逼之处在于可以大大提高写HTML的效率。比如我要写一个html table。输入 table#list-table.table>tr.row*3>td.cell*3 然后按定义的Zen Cod ing快捷键,就会马上生成:

	<table id="list-table" class="table">
		<tr class="row">
			<td class="cell"></td>
			<td class="cell"></td>
			<td class="cell"></td>
		</tr>
		<tr class="row">
			<td class="cell"></td>
			<td class="cell"></td>
			<td class="cell"></td>
		</tr>
		<tr class="row">
			<td class="cell"></td>
			<td class="cell"></td>
			<td class="cell"></td>
		</tr>
	</table>

Twitter Bootstrap

    这是twitter发布的一套前端整体框架。也就是预先定义了很多css和一些Js代码。写页面的时候,按照规范写class,就可以实现用户体验很好的页面。这里是项目主页。现在很多很多网站都基于bootstrap来开发。的确可以为开发者节省很多宝贵的时间,更重要的是,这些页面元素都是twitter经过研究后,觉得是用户体验最好的设计。而且,基于bootstrap,页面还可以很轻松的做到mobile friendly。我的一个小项目就是基于bootstrap,实现了使用同一个页面,支持各种尺寸的浏览器。尤其在iOS浏览器上表现非常好。精选文章

Devtools Autosave

    这才是最牛逼的神器。项目地址在这里。这个东西实现了可以在Chrome developer tools里面修改css属性或者js代码,然后直接同步保存到本地或者服务器。比如以前我们先大概写好css,然后用firebug进行微调,调整好后,复制css代码,进入编辑器粘贴代码然后保存,然后刷新浏览器看效果。而现在,在Chrome devtools里面,修改的css可以自动保存了。而且不仅仅是css属性,还可以直接修改css源文件、javascript源文件。现在的开发方式可以简化到,先写好HTML骨架,定义好各个class名字,然后打开chrome devtools,在css源文件里面直接添加新的class。边写边可以看到效果哦。牛逼指数10颗星啊。

Markman

    马克鳗是一个Design to HTML神器。很多时候我们需要根据设计图片文件来开发成网页代码。这时需要精确测量各种距离、各种宽度、各种颜色。马克鳗可以优雅的完成这个任务。项目地址在这里。下面是我截的图:

Markman截图

    先写这么多吧。


11条评论     到PHP.JS.CN上围观原文 ]]>
2012-11-25 03:20:46
<![CDATA[Mac下为应用程序更换图标最简单的方法]]> https://php.js.cn/blog/how-to-change-application-icon-in-mac/     Mac OS系统里面的应用程序都是文件夹形式。只不过是内部有一定规则的文件夹而已。在应用程序上右键,选择查看包内容就可以查看应用程序里面的东西了。应用程序的图标文件也在里面。一般是一个.icns文件。替换这个文件,就可以更换app的图标。不过这个方法跟我要讲的方法闭起来弱爆了。首先不说找到那个.icns文件很麻烦,光是把图片转换成.icns格式就够折腾。

    其实Mac OS操作系统是很简单的。不就是换个图标么。复制粘贴就可以了!请看:

  1. 找到目标APP,比如迅雷:


     
  2. 到网上随便找个png图片,当然,要足够大。然后右键,复制图片。比如这只黑猫:


     
  3. 转到Finder,选中迅雷APP,然后按Command+I或者右键菜单里面选择“显示简介”也可以。 然后选中左上角红色按钮和黄色按钮下面的那个图标。选中之后图标边缘会变成蓝色:


     
  4. 点击Command+V粘贴。搞定!



     
  5. 如果想使用本地的图片文件来当icon。那可以先使用系统自带的“预览”工具打开该图片。然后全选(或者选择一部分也可以)。然后按Command+C复制。


     
  6. 然后就跟第四步一样Command+V粘贴:


     
  7. 其实不用复制粘贴,直接拖动网页上的图片到简介上的那个图标上也可以。不过要先组织下窗口位置:

 

    其实就是这么简单。


3条评论     到PHP.JS.CN上围观原文 ]]>
2012-10-20 01:10:07