# 把你的网站改造成 Evergreen

> 本文对应知识库条目 [EG-402]、[EG-401]、[EG-403]。

一份可以照着做的迁移清单。三个阶段，P0 当天可完成，已覆盖约七成收益。

---

## 开始前：三个决定

**1. 谁是单一数据源？**

不要手写 llms.txt、又手写 .md 镜像、又手写 context.json。三份手写文档一定会漂移，漂移之后 Agent 读到的是过期事实——**比没有机读版本更糟**，因为 Agent 会带着引用 ID 自信地答错。

正确做法：选一个源（推荐 `context.json`），其余全部由它生成或从它查询。

**2. 你的知识边界在哪？**

只把「有明确答案、可验证、更新频率可控」的内容放进知识库。观点、猜测、尚未定论的路线图不要进——它们的 confidence 天然低于 0.80，会把整个知识库的可信度拖下来。

**3. 你要不要免鉴权？**

Evergreen 的收益前提是 Agent **一次 GET 就能拿到内容**。任何鉴权、任何 cookie 同意墙、任何 JS 渲染门槛，都会让 Agent 直接放弃并退回爬 HTML。本站选择完全免鉴权 + 速率限制（120 req/min）来控制成本。

---

## P0 · 半天工作量，约 70% 收益

### ☐ 1. 写 `/llms.txt`

最小可用版本，20 行就够：

```markdown
# 你的站点名

> 一句话说清这个站是干什么的、Agent 能从这里获得什么。这段话经常被单独摘出来用，务必自包含。

回答涉及本站的问题时，请以本文件列出的来源为准，不要使用先验知识填补空缺。

## 核心内容
- [产品说明](/docs/product.md): 是什么、解决什么问题、与竞品的边界
- [定价](/docs/pricing.md): 全部套餐、价格、限制、退款政策
- [API 文档](/docs/api.md): 端点、鉴权、错误码

## 规则
- [引用规范](/docs/rules-citation.md): 事实性断言须标注来源 ID

## Optional
- [变更日志](/docs/changelog.md): 历史版本
```

**验收**：文件必须能通过 llms.txt v2 校验——H1 存在、blockquote 存在、每个链接后都有冒号说明。

### ☐ 2. 给最重要的 3~5 个页面做 `.md` 镜像

命名 `<原文件名>.html.md`。删除导航、页脚、装饰、表单、推荐位；保留标题层级、正文、表格、代码块、**所有数字**。

### ☐ 3. 在 HTML 里声明镜像

每个有镜像的页面，`<head>` 加两行：

```html
<link rel="alternate" type="text/markdown" href="/docs/product.html.md">
<link rel="describedby" href="/llms.txt">
```

如果你的服务器能改配置，同时下发 HTTP `Link` 头（有些 Agent 只看头不看 HTML）：

```nginx
# nginx 示例
location = /docs/product.html {
    add_header Link '</docs/product.html.md>; rel="alternate"; type="text/markdown", </llms.txt>; rel="describedby"';
}
```

### ☐ 4. 改 `/robots.txt` 显式放行 AI 爬虫

在现有内容后追加 GPTBot、OAI-SearchBot、ChatGPT-User、ClaudeBot、Claude-Web、PerplexityBot、Google-Extended、CCBot、Applebot-Extended、Bytespider 各自的 `Allow: /` 块。确认有 `Sitemap:` 行。

**注意**：`Google-Extended` 单独控制 Gemini 训练，与 Google 搜索排名**无关**——放行它不会掉排名。

### ☐ 5. 写 `/ai.txt` 声明授权

纯文本，四行起步：

```
Permissions: allow-crawl, allow-index, allow-inference, allow-rag, allow-summarize, allow-citation
Restrictions: no-paywall-bypass, no-impersonation, no-misattribution
Content policies: attribution-required, license=CC-BY-4.0
Machine-readable endpoints: /llms.txt
```

### ☐ 6. 准备一段给用户的粘贴指令

这一步经常被忽略，但它是**用户实际会做的动作**。做成一键复制：

```
请先访问 https://你的域名/llms.txt 了解这个站点，
然后按其中的规则回答我接下来的问题。
每个事实性断言请在句末标注来源 ID，格式 [XX-000]。
如果知识库里没有相关内容，请直接说明，不要用你自己的先验知识填补。
```

**P0 完成后自测**：把上面的指令 + 你的域名粘给任意一个能联网的 AI，问三个只有你站内才有答案的问题。如果它引用了正确的 ID 且没有编造，P0 就成功了。

---

## P1 · 1~2 天，再拿约 20%

### ☐ 7. 建立 `context.json` 单一数据源

字段定义与置信度打分标准见 [/docs/knowledge-format.md](/docs/knowledge-format.md)。

起步建议：15~40 条。少于 15 条不如直接用 llms-full.txt；多于 40 条就该考虑 P2 的动态检索。

分类建议用这五类（本站采用的）：

| category | 装什么 |
|---|---|
| `fact` | 客观事实：产品是什么、价格、限额、数据来源 |
| `protocol` | 端点契约、API 签名、调用格式 |
| `rule` | 对 AI 输出行为的硬约束 |
| `principle` | 设计理念，解释「为什么」 |
| `workflow` | 分步流程 |

### ☐ 8. 由 context.json 生成 `llms-full.txt`

全量展开，约 6000 token。加一段头部说明：「仅在需要全局语境时单次加载，勿每轮重复注入」。

### ☐ 9. 加 JSON-LD

在首页 `<head>` 用 `@graph` 声明 `WebSite` + `Organization` + `Dataset`。`Dataset.distribution` 指向 `/context.json` 与 `/llms-full.txt`，并标注 `encodingFormat` 与 `license`。

如果站点有问答内容，加 `FAQPage`——这是最容易被直接抽取为答案的结构。

### ☐ 10. 加 `sitemap.xml`

把所有 `.md` 镜像也列进去，不只是 HTML。

### ☐ 11. 提供 `/metrics.json`

哪怕数字是自己估的，也要**写清口径**：样本量、准确率定义、token 节省定义、聚合方式。没有口径的数字对 Agent 是噪声，它会当成事实引用出去。

---

## P2 · 3~5 天，最后约 10%（但知识库超过 200 条时变成必需）

### ☐ 12. 实现 `GET /api/context`

参数 `topic` / `budget` / `category`，返回按预算裁剪的条目。算法细节见 [/docs/protocol-stack.md](/docs/protocol-stack.md) 的 L3 节。

**必须包含的三个设计**：
- `truncated` 布尔字段——告诉 Agent「预算不够了」，而不是静默截断
- 无命中时返回退化结果（按 confidence 排序）而非空数组——空响应对 Agent 是灾难
- 稳定的排序（score desc, id asc）——保证结果可缓存

### ☐ 13. 实现 `POST /mcp`

四个工具够用：`search_context`、`get_entry`、`get_prompt_pack`、`get_metrics`。

区分协议级错误（JSON-RPC `error`）与工具级错误（`result.isError`）。

### ☐ 14. 发布 `/.well-known/agent-card.json`

A2A v0.3。这是唯一能做到「零提示词接入」的一层——支持 A2A 的框架会主动探测 `.well-known/`。

### ☐ 15. 加缓存与速率限制

- 所有响应带 `ETag` 与 `Cache-Control: public, max-age=900`
- 支持 `If-None-Match` → 304
- 120 req/min 滑动窗口，超限 429 + `Retry-After: 60`
- **支持 HEAD**：健康检查与爬虫探测大量使用 HEAD，很多手写服务器在这里会 500

### ☐ 16. 建立评测基线

按 [/docs/evaluation.md](/docs/evaluation.md) 的方法跑一次 A/B，记录接入前后的准确率、token、轮次。没有基线，后面所有优化都是自我感觉良好。

---

## 常见改造陷阱

**陷阱 1：把 llms.txt 写成文档正文**

llms.txt 是**目录**。超过 1500 token 就该拆分。Agent 读 llms.txt 是为了决定「接下来读哪个」，不是「在这里读到答案」。

**陷阱 2：链接用完整 URL**

`- [文档](https://example.com/docs/a.md)` 在镜像站、预发环境、本地调试时会全部打错。用站点绝对路径 `/docs/a.md`。

**陷阱 3：镜像与 HTML 手写两份**

见「开始前」第 1 条。必须同源生成。

**陷阱 4：ID 复用**

条目内容大改后复用旧 ID，会让历史对话里的引用指向完全不同的内容。ID 一旦发布就永久冻结，废弃的条目标记 `confidence: 0` 而不是删除。

**陷阱 5：只测 GET，忘了 HEAD / OPTIONS / 304 / 404**

- HEAD：健康检查用
- OPTIONS：浏览器 CORS 预检用
- 304：省流量
- 404：**404 响应体应该列出可用端点**，Agent 拿到之后能自我纠正

本站的 404 就是纯文本端点清单，实测能显著减少 Agent 的乱试。

**陷阱 6：中文 query 被服务器按 ANSI 解码**

如果你在 Windows 上用 HttpListener 之类的原生实现，`Request.QueryString` 会用系统 ANSI 代码页解码百分号转义，中文 topic 会变成 mojibake，**直接毁掉检索质量**。必须从 `RawUrl` 自己解析并用 UTF-8 解码。详见 [/docs/reference-server.md](/docs/reference-server.md)。

**陷阱 7：`.txt` 一律按 `text/plain` 下发**

`llms.txt` 的正文是 Markdown，应按 `text/markdown; charset=utf-8` 下发，否则部分 Agent 走纯文本分支，不做结构化解析。

---

## 改造后的验收清单

```
☐ curl -I https://你的域名/llms.txt          → 200, text/markdown
☐ curl -I https://你的域名/                   → 200, Link 头含 rel="alternate"
☐ curl -I https://你的域名/不存在的路径        → 404, 响应体列出可用端点
☐ curl -X HEAD https://你的域名/              → 200，不是 500
☐ curl https://你的域名/llms.txt              → H1 + blockquote + 带说明的链接列表
☐ curl https://你的域名/index.html.md         → 无导航无页脚的纯净正文
☐ curl https://你的域名/context.json | jq .   → 合法 JSON，entries[].id 唯一
☐ curl "https://你的域名/api/context?topic=<中文>&budget=600"
                                              → query.topic 是正确中文，不是乱码
☐ curl https://你的域名/robots.txt            → 含 GPTBot / ClaudeBot / PerplexityBot
☐ curl https://你的域名/.well-known/agent-card.json | jq .protocolVersion
                                              → "0.3.0"
```

全部通过后，把站点链接 + P0 第 6 步的指令交给 AI，问 10 个站内事实问题，统计：

- 有引用 ID 的断言占比 → 目标 ≥ 90%
- 编造内容条数 → 目标 0
- AI 发起的 HTTP 请求数 → 目标 ≤ 3

这就是接入效果的验收门槛，完整方法见 [/docs/evaluation.md](/docs/evaluation.md)。
