MoreRSS

site iconSunZhongWei | 孙仲维 修改

博客名「大象笔记」,全干程序员一名,曾在金山,DNSPod,腾讯云,常驻烟台。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

SunZhongWei | 孙仲维 的 RSS 预览

尝试我的第一个 Github Copilot instruction, 告别重复输入编码提示词

2026-04-09 17:17:09

用 GitHub Copilot 来开发确实很方便,把需求跟 AI 说明白,基本功能代码就自动实现了。
但是也有一些困扰,比如一些重新性的功能,需要反复说明一些细节。例如,我要实现一个 Excel 导出功能,需要在 Chat 窗口里,输入大量的细节说明,如下:

- 待办列表的导出 Excel 功能
  - 实现代码放到 controllers/todo.go 中,函数命名为 ExportTodoExcel
  - 列头:序号(从1开始,顺序显示数字),员工类型,所属公司(公司简称),姓名,省份证号,事业部,一级部门,二级部门,三级部门,岗位,年龄,入职日期,合同/协议到期日,合同类型,续签次数,合同期限(固定/无固定),续签(数据空出来就行),续签期限起,续签期限止,备注,员工编号,待办描述,待办状态,待办事项,截止日期
  - 支持跟待办列表接口一样的过滤条件
  - Excel 的每一列添加过滤器,方便 HR 同事在 Excel 里进行筛选。Deadline (截止日期)列、入职时间、合同/协议到期日、续签期限起、续签期限止,需要转换为日期格式“yyyy-mm-dd", 方便 Excel 过滤器进行年月过滤。注意时区问题,确保转换后的日期是中国时区的日期
  - 参考 ExportStaffExcel 接口的实现方式,来实现导出待办列表的 Excel 功能
  - 表头配色优化,参考 ExportStaffExcel
  - 函数需要添加 Swagger 注释,说明这个接口的功能和参数。主要是方便前端同事理解
  - 返回的下载链接需要添加 token 验证,参考 ExportStaffExcel 接口的实现方式,来实现下载链接的安全验证

如果我希望每次添加类似的 Excel 接口时,都参考上面这个规范,而不需要每次都在 Chat 窗口里输入这些细节,那么我应该怎么做呢?

使用 skill 还是 instruction

问了一下 DeepSeek, 回答是:

“每次添加类似的 Excel 接口时,都参考下面的规范”。这说明你需要的是一个持续性、基准性的开发指南,而非一个需要手动触发的复杂任务流。这正是 Custom Instructions(自定义指令) 的典型应用场景。

看看官方的概念定义:

https://github.com/github/awesome-copilot

  • Instructions: Coding standards applied automatically by file pattern。即针对特定文件自动应用的编码标准
  • Skills: Self-contained folders with instructions and bundled assets。即包含指令和相关资源的独立文件夹

其实我还是有点没有头绪,虽然概念大概了解了。但是到底应该怎么操作呢?我找了 github 官方的一个仓库 Awesome GitHub Copilot,里面有一些示例。

golang instrunction 的示例

https://awesome-copilot.github.com/instructions/?extension=.go

这里可以搜索到各种语言的 instrunction 示例,特地加了 .go 后缀的限制,即只看 golang 的示例。

在网页上直接点击 install 就能自动唤起 VSCode 安装到指定的目录,即可以安装到个人的全局,也可以安装到当前项目中。
我暂时选择了当前项目中。

Awesome GitHub Copilot golang instrunction

具体的路径:

.github\instructions\go.instructions.md

之所以没有放全局,我觉得不同项目的代码风格还是有区别的。例如:

  • 有的要求用中文注释,有的用英文
  • 有的需要写 swagger 文档,有的不需要

Excel 那段 instruction 是否适合放到 golang 的大段 instruction 中

如以这个为例:

https://github.com/github/awesome-copilot/blob/main/.github/copilot-instructions.md

看起来混杂在一起也不是问题。

但是,这么多字,会不会占用对话的上下文?还是说 GitHub copilot 在本地会先提取相关的 instruction,发送到大模型的只是一小部分?

添加示例:

## Excel 导出功能规范
- 支持跟对应列表接口一样的过滤条件
- Excel 的每一列添加过滤器,方便在 Excel 里进行筛选。日期需要转换为日期格式“yyyy-mm-dd", 方便 Excel 过滤器进行年月过滤。注意时区问题,确保转换后的日期是中国时区的日期
- 表头配色要有区分度
- 函数需要添加 Swagger 注释,说明这个接口的功能和参数。主要是方便前端同事理解
- 返回的下载链接需要添加 token 验证,来实现下载链接的安全验证

这个还没测试,不知道具体效果如何。下面试试比较容易测试的 git instruction。

git instruction

我一直有个困扰,就是 VSCode 里用 AI 自动生成 git 提交注释时,总是用英文。
作为土鳖,我还是更喜欢用中文。一直不知道怎么设置成中文,于是在 GitHub copilot chat 对话框里,输入 /create 找到 /create-instructions,然后输入需求就行了。

/create-instructions 提交 git commit 时,请使用中文的描述

然后 GitHub copilot 就自动给我创建好了一个 instruction 文件

.github\instructions\git.instructions.md

目录结构如下:

> tree .github/
.github/
└── instructions
    ├── git.instructions.md
    └── go.instructions.md

1 directory, 2 files

内容如下:

# Git Commit Instructions

## Commit Message Language
- Always use **Chinese** for git commit messages.
- 提交 git commit 时,请始终使用**中文**进行描述。

## Commit Style
- Keep descriptions concise and meaningful.
- 描述应当简洁且有意义。

看起来言简意赅,也没有什么复杂的配置。就是习惯了用参数配置,突然用起自然语言,感觉非常得不适应,也不确定是否靠谱。。。

测试了一下,倒是确实把自动生成的 git 提交注释变成了中文。

git instruction 中文

非常好,instruction 技能已掌握。感觉自己又专业了许多!

但是,又试了一次,又变成英文的了,垃圾。。。

原来这个配置是在 Settings 里,搜索 git commit message, 参考官方 issue:

https://github.com/microsoft/vscode-copilot-release/issues/526

vscode setting git commit message

可以指定文件,或者自然语言配置都可以。例如:

    "github.copilot.chat.commitMessageGeneration.instructions": [
        {
            "text": "请始终使用中文进行描述。"
        }
    ]

github copilot Instruction 的原理

GitHub Copilot Instruction 的核心原理是 “上下文注入”(Context Injection)。它并非通过某种特殊机制去“训练”AI模型,而是将你写下的Markdown指令,在每次发起Copilot Chat对话时,自动作为系统提示词(System Prompt) 的一部分,悄无声息地“注入”到发送给大语言模型(LLM)的完整请求中

Ant Design Pro 管理后台更新版本时的浏览器缓存问题

2026-04-01 10:01:02

这是困扰我很久的一个问题,每次更新 Ant Design Pro 开发的管理后台前端版本后,浏览器总是会缓存旧的文件,导致用户看到的仍然是旧版本的界面。
或者某个子功能更新,更新后,如果用户没有刷新页面,直接访问这个功能,直接白屏报错。只有当用户手动刷新页面后才能看到更新后的界面。这个体验非常的不好。

之前没怎么当回事,要么是因为后台更新频率不高,要么是后台用的人少,现在遇到了几个系统,用户量比较大,更新频率也比较高,这个问题就变得非常突出,必须要解决。

解决思路

问了一下 DeepSeek, 他说这个问题的根源在于浏览器缓存了旧的 index.html 文件,虽然其他静态资源(js、css)文件名里都带了哈希(例如,app.123456.js),理论上应该是不会被缓存的,但 index.html 没有带哈希,所以浏览器会一直缓存旧的 index.html 文件,导致用户看到的界面一直是旧版本的。

处理前的请求返回

HTTP/1.1 304 Not Modified
Server: nginx/1.24.0 (Ubuntu)
Date: Tue, 31 Mar 2026 09:06:17 GMT
Last-Modified: Mon, 02 Feb 2026 08:35:01 GMT
Connection: keep-alive
ETag: "698061b5-1881"

新的 Nginx 配置

server {
    listen       80;
    server_name  _;

    client_max_body_size 8M;

    # 前端静态文件根目录(提到 server 层)
    root   /home/some_user/some_project/frontend/dist;
    index  index.html index.htm;

    # API 请求转发到后端 golang 服务
    location /api/ {
        proxy_set_header X-Forward-For $remote_addr;
        proxy_set_header  X-real-ip $remote_addr;
        proxy_pass http://127.0.0.1:9999/api/;
    }

    # 所有 HTML 文件强制不缓存。存在子功能对应目录也包含 index.html 的情况,所以不能只针对根目录的 index.html 进行处理。
    location ~* \.html$ {
        add_header Cache-Control "no-cache, no-store, must-revalidate";
        add_header Pragma "no-cache";
        add_header Expires 0;
        try_files $uri =404;
    }

    # SPA 路由处理:其他所有请求返回 index.html
    location / {
        try_files $uri $uri/ /index.html =404;
    }
}

检查 Nginx 配置,并 reload Nginx:

sudo nginx -t
sudo nginx -s reload

处理后的请求返回

HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Date: Tue, 31 Mar 2026 08:33:30 GMT
Content-Type: text/html
Last-Modified: Mon, 02 Feb 2026 08:35:01 GMT
Transfer-Encoding: chunked
Connection: keep-alive
ETag: W/"698061b5-1881"
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Content-Encoding: gzip

项目目录结构参考

我发现 Ant Design Pro 的前端项目目录结构中,index.html 文件是放在 dist 目录下的,同时每个子功能也有对应的子目录,里面也包含一个 index.html 文件。

而 Vue Element 则只有一个根目录的 index.html 文件,没有子功能目录下的 index.html 文件,其他都在 js 目录下。

修改后文件的 etag 是不同的,为啥还会被缓存呢?

虽然 index.html 文件的缓存问题解决了,但是我不太理解,为何修改前的返回里,也有文件的 etag 和修改时间等信息,且 etag 也不一样了,但浏览器还是会缓存旧的 index.html 文件呢?

原因是没有设置 Cache-Control: no-cache 等响应头,浏览器依然可能使用旧的缓存,而不会主动向服务器验证。

当浏览器缓存了一个资源(比如 index.html),再次请求时,是否发送验证请求取决于缓存响应的 Cache-Control 和 Expires 头。

如果响应头中带有 Cache-Control: no-cache(或 must-revalidate)。浏览器每次都会向服务器发送验证请求(带上 If-None-Match 或 If-Modified-Since),服务器根据 ETag 或 Last-Modified 决定返回 200(新内容)还是 304(未修改,使用缓存)。

如果没有 Cache-Control 或 Expires 明确指示。浏览器会使用启发式缓存(Heuristic Caching)。例如,根据 Last-Modified 时间,浏览器可能认为资源在 (当前时间 - 上次修改时间) * 10% 的时间内是新鲜的,期间根本不会发送请求,直接使用本地缓存。这就会导致即使服务器上的文件已更新(ETag 变了),浏览器也不去验证,用户看到的还是旧页面。

而用户刷新页面(F5 或 Ctrl+R):浏览器通常会忽略启发式缓存,强制发送验证请求(带上 If-None-Match),这时 ETag 不同就会返回新内容。

ETag 的作用

ETag 本身并不控制是否验证,它只用于验证时的比较。如果没有验证,ETag 再变也无用。因此,对于 index.html 这类必须实时更新的文件,必须设置 Cache-Control: no-cache(或其他强制验证的指令),让浏览器每次都必须向服务器询问,确保及时拿到最新版本。

Nginx 默认的 ETag 格式:

ETag = {文件最后修改时间的十六进制} - {文件内容长度的十六进制}

详情参考:Golang Gin Static 缓存大坑:embed 文件无法被 CDN 和浏览器缓存

Cocos 4 及 PinK 与 Cocos Creator 3.8.8 的关系

2026-03-29 22:13:40

今天吐槽了一下 Cocos Creator 3.8.8 并不支持 MCP,导致 AI 不能自动操作场景中的节点,参见前文:第一次用 AI 开发 Cocos 小游戏,我才认识到 MCP 的重要性。然后,发到小红书后,有个大佬说可以看看 Cocos 4。果然在官方论坛里找到一个关于 Cocos 4 的介绍。

https://forum.cocos.org/t/topic/172915

Cocos 4 及 PinK 与 Cocos Creator 3.8.8 的关系

以前的“Cocos Creator”是一个包含引擎+编辑器的整体,而现在它被拆分成了两个独立的部分:

  • Cocos 4:底层的游戏引擎(纯核心,已开源)。https://github.com/cocos/cocos4
  • Pink:全新的可视化编辑器/IDE(包含AI功能,界面类似VS Code)。这里引入了 AI 的支持。这部分并不开源。而且未来可能会收费。如果 AI 相关功能收费倒是可以理解。

同时还有一个 Cocos CLI 的支持: https://github.com/cocos/cocos-cli
其实就是游戏引擎跟编辑器的剥离。

PinK 还没有正式版

今天看到 PinK 0.0.1.12 Alpha 版本发布,这版本号看起来是远没有到正式版的地步。而且官方也不推荐用到生产环境。
对于我这种新手来说,更没有必要去踩坑了。老老实实去用 Cocos Creator 3.8.8 好了。

Cocos 4

Cocos 4 变成了一个纯粹的游戏引擎,是在 Cocos Creator 3.8.8 的引擎基础上进行开发的。

怎么选择

我还是老老实实先用 Creator 3.8 开发界面吧,即便未来真的用上了 PinK,那些基础概念还是需要了解的。

第一次用 AI 开发 Cocos 小游戏,我才认识到 MCP 的重要性

2026-03-29 12:30:32

周末尝试用 Github Copilot 中的 GPT 5.4 开发我的第一款 Cocos 小游戏,我发现高达 400k 上下文的 GPT 5.4 确实强的可怕。无论是 Plan 还是代码实现,都非常专业。但是有一点遗憾,就是需要在 Cocos Creator 场景编辑器里手工创建节点层级、挂组件、绑定按钮事件。这部分 AI 没法帮你自动完成。我不是很理解,难道这些不是类似一下 XML 的配置项么?为啥不能自动完成绑定和设置。

如果有 MCP 会怎样

MCP 的全称是 Model Context Protocol(模型上下文协议)。有了 MCP,AI 就可以“动手”去自动创建节点、修改属性、运行项目。

Cocos MCP

我查了一下,有一款三方实现的 Cocos MCP 三方插件:

https://github.com/DaxianLee/cocos-mcp-server

一个适用于 Cocos Creator 3.8+ 的综合性 MCP(模型上下文协议)服务器插件,使 AI 助手能够通过标准化协议与 Cocos Creator 编辑器进行交互。一键安装和使用,省去所有繁琐环境和配置。已经测试过Claude客户端Claude CLI和Cursor,其他的编辑器理论上也完美支持。🚀 现在提供 50 个强力融合工具,实现99%的编辑器控制!

Cocos dashboard 中有对应的付费版本,如下图:

cocos mcp 插件

为何没有官方版本的 MCP

这是我最不能理解的地方,这样重要的功能居然不是官方支持的,而是由一个三方插件实现的。我甚至开始怀疑 Cocos 要跑路了,对我自己的选型有点动摇了。我这周尝试了一下 Google Stitch,就是用 AI 出设计稿,简直强的可怕。

这也是我第一次感受到 MCP 的重要性,如果所有的开发工具都支持 MCP,那确实可以大大提升效率。之前主要是担心数据安全性问题,没有尝试 MySQL MCP 和 Chrome MCP。现在来看有点过于谨慎了,如果做好备份和账号隔离,还是可以规避风险的。

被 HR 上了一课,原来我的全日制第一学历理解是错的

2026-03-27 14:47:59

今天同事反馈人事系统导出花名册 Excel 时,员工的全日制第一学历信息提取错误。
搞得我一头雾水。。。😓 当初就不应该接这个人事系统的项目,坑又多,又没有成就感。

现在还原一下这个问题的来龙去脉。

当事人的教育经历

例如,这个员工的教育经历如下:

  • 高中,全日制,就读于湘北高中
  • 大学本科,全日制,就读于西北大学
  • 硕士研究生,全日制,就读于东北大学

而我在导出时,把全日制第一学历提取成了高中学历。人事说这个人的全日制第一学历应该是研究生,同时,这个人的最高学历也是研究生。

什么是全日制第一学历?

我表示很疑惑,我以为这个人的全日制第一学历应该是大学本科。。。

我问了以下 DeepSeek, AI 也说我的理解没啥问题(印象中我在 VSCode 中让 AI 做 Code Review 也没有发现问题)。但是在知乎上看一些职业 HR 说全日制第一学历其实指的是全日制的最高学历。
也就是说,这个人的全日制第一学历应该是研究生,而不是大学本科。

全日制第一学历跟最高学历不一样的情况

还有另外一种情况,例如另外一个人的教育经历如下:

  • 高中,全日制,就读于湘北高中
  • 大学本科,全日制,就读于西北大学
  • 硕士研究生,非全日制,就读于东南大学

那么这种情况,这个人的全日制第一学历应该是大学本科,而不是研究生。因为这个人的研究生学历是非全日制的。
但是,其最高学历是研究生,虽然不是全日制。

非全日制包含哪些

  • 成人教育
  • 自考
  • 函授

当然,这三个,我完全看不出有什么区别。。。

同一篇文章,同时存在中文版本和英文版本,如何设置页面 SEO 信息,防止被搜索引擎认定为重复内容

2026-03-26 20:54:24

最近增加了博客新功能,中文版自动翻译为英文,基于 Github Copilot SDK 的免费 gpt 5 mini 模型。但是,今天看了 Bing Web Master 里的一篇文章,说这种翻译行为,也会被认定为重复内容。参考下文:

https://blogs.bing.com/webmaster/December-2025/Does-Duplicate-Content-Hurt-SEO-and-AI-Search-Visibility

Localization creates duplicate content when regional or language pages are nearly identical and do not provide meaningful differences for users in each market.

那么如果一个网站内,同一篇文章,同时存在中文版本和英文版本,如何设置页面信息,防止被搜索引擎认定为重复内容?

解决方案

判断如果为中文 , 且已翻译为英文:

在中文版页面的头部添加:

<link rel="alternate" hreflang="zh-CN" href="https://www.sunzhongwei.com/xxx" />
<link rel="alternate" hreflang="en" href="https://www.sunzhongwei.com/xxx-en" />
<link rel="alternate" hreflang="x-default" href="https://www.sunzhongwei.com/xxx-en" />

判断如果文章内容为英文,在英文版页面的头部添加:

<link rel="alternate" hreflang="zh-CN" href="https://www.sunzhongwei.com/xxx" />
<link rel="alternate" hreflang="en" href="https://www.sunzhongwei.com/xxx-en" />
<link rel="alternate" hreflang="x-default" href="https://www.sunzhongwei.com/xxx-en" />

参数解析说明

  • hreflang=“zh-CN”:表示该链接指向简体中文版本。
  • hreflang=“en”:表示该链接指向英文版本。
  • hreflang=“x-default”:这是一个特殊的代码,用于指定当用户的语言不在你支持的语言列表中时,或者搜索引擎无法确定语言偏好时,应该索引哪个页面。通常指向你的主版本或默认首页。

rel=“alternate” hreflang 的作用

用于向搜索引擎(尤其是 Google、Bing 等)说明:当前网页存在其他语言或地区的替代版本。帮助搜索引擎理解多语言/多地区网站的结构,从而在搜索结果中根据用户的语言偏好或地理位置,自动展示最合适的页面版本,同时避免因内容相似而导致的“重复内容”问题。

晚上吃完饭,在博客上增加了这个逻辑处理。但是,感觉页面增加的逻辑越来越多了,以后会不会不好维护 😓