用Accept头为AI代理提供Markdown内容

本文介绍如何通过HTTP内容协商,让网站向AI代理提供Markdown版本内容,减少token消耗、提升检索质量、降低延迟,并附有快速配置指南。
为什么AI代理需要Markdown?
当AI代理(如聊天机器人的浏览工具)访问你的网站时,它通常需要解析HTML中的导航、脚本和布局代码,才能提取正文。这不仅浪费token(上下文窗口有限),还会因为广告、相关推荐等干扰元素降低内容检索的准确性。
其实,你的网站内容已经存在,只是默认以HTML形式输出。通过HTTP内容协商,让服务器在检测到客户端请求Accept: text/markdown时,返回一个干净的Markdown版本,就能让AI代理直接读取正文。
三大核心优势
1. 更少的Token消耗
Markdown去掉了导航、样式、脚本和布局包装,字节数大幅减少。AI代理可以把宝贵的上下文窗口用在你的内容上,而不是解析DOM结构。对于长文页面,这种差异尤其明显。
2. 更高的检索信噪比
当RAG(检索增强生成)管道需要将网页内容嵌入向量数据库时,Markdown版本没有广告、相关推荐模块或弹窗的干扰。这意味着嵌入的文本更纯净,检索结果的相关性更高。
3. 更低的延迟
从服务器返回的数据量更小,解析更快,AI代理能更快获得首个token并开始推理。对于实时交互场景,这种延迟优化能显著提升用户体验。
快速上手:最小配置
最简单的实现方式是三步:
- 在服务器上为每个URL准备一个Markdown版本(可以动态生成,也可以静态预置)。
- 检测请求头中的
Accept字段,如果包含text/markdown,则返回Markdown内容,并设置Content-Type: text/markdown。 - 对于不支持Markdown的客户端,照常返回HTML。
下面是一个概念性的Node.js/Express示例:
app.get('/post/:id', (req, res) => {
const post = getPost(req.params.id);
if (req.accepts('text/markdown')) {
res.type('text/markdown').send(post.markdown);
} else {
res.type('html').send(post.html);
}
});
进阶配置与注意事项
正确设置Vary头
为了确保缓存代理不会错误地复用HTML版本给Markdown客户端,必须在响应中设置Vary: Accept。否则,CDN或浏览器缓存可能导致AI代理拿到错误的格式。
处理q-values和406状态
HTTP内容协商支持q-values(如Accept: text/markdown;q=0.9, text/html;q=0.8),表示客户端的偏好程度。如果服务器无法提供客户端可接受的格式,应返回406 Not Acceptable,而不是忽略协商。
缓存策略
Markdown版本通常比HTML更稳定,可以设置更长的缓存时间。但要注意,如果内容更新,两者需要同步失效。
Cloudflare零配置捷径
如果你使用Cloudflare,其Worker或边缘规则可以自动处理内容协商,无需修改源服务器代码。具体配置可参考官方文档。
现成的配方
项目提供了多种服务器和框架的复制粘贴配置,包括:
- Nginx:通过
map指令和try_files实现。 - Caddy:利用
handle块和header指令。 - WordPress:添加一个插件或主题函数。
- Laravel:中间件中检查
Accept头。 - Rails:使用
respond_to块。 - Next.js:在API路由或中间件中处理。
- Astro:使用端点函数。
- Express:如上述示例。
- Go:标准库的
http.Handler。
AI代理支持情况
并非所有AI代理都会发送Accept: text/markdown头。项目维护了一个支持矩阵,列出哪些浏览或抓取工具会发送该头。如果你正在开发AI代理,建议在请求中主动加上这个头,以利用网站的Markdown版本。
参考标准
- RFC 9110(HTTP语义和内容协商)
- RFC 7763(text/markdown媒体类型)
这些标准定义了内容协商的机制和Markdown的媒体类型,实现时应确保符合规范。
总结
为AI代理提供Markdown版本,不仅能节省token、提高检索质量,还能降低延迟。实现并不复杂,只需处理一个请求头。如果你的网站面向AI流量(如被RAG系统引用),这绝对值得投入。