SDK文档站llms.txt三件套,Cursor读错入口
导语:Sensory 给 TrulyNatural SDK 文档站配了 llms.txt + manifest.json + llms-full.txt 三件套,代理找页面的路径通了,但 Cursor 从一开始就没读进去——它把 llms.txt 当成一个普通网页,而不是链接清单。
背景:代理不是没资料,是走错入口
TrulyNatural 是跑在嵌入式设备上的本地语音识别 SDK,文档覆盖 C 语系、Java、Python、Android、iOS 五套绑定,外加模型目录、命令行工具、设置项字典。这类文档站的结构性问题是:页面多、层级深、术语密度高,模型抓到概述页就能说出一堆"看起来对"的结论,真到集成环节就答偏。
站点在文档里写得很直白,配 llms.txt 的目标是让三个典型问题直接落到正确页面:
how do I push audio?(推流式音频 / 接第三方 ASR)add Sensory to my CMake build(构建集成)enroll a UDT in Java(Java 注册用户自定义唤醒词)
换句话说,这不是为了"被 AI 搜到",而是为了让在编辑器里干活的编码代理少走两跳导航。这也是 llms.txt 与 sitemap、robots 的根本区别:后两者服务搜索引擎,前者服务"读进去就要改代码"的代理。
落地清单
1. 文件位置与路由:跟着版本来,不跟站点走
Sensory 的文档站是按 SDK 版本发布文档树的,当前是 /tnl/7.8/,三件套全部放在版本根目录下:
https://doc.sensory.com/tnl/7.8/llms.txt # 约有 27 KiB,面向代理的索引 https://doc.sensory.com/tnl/7.8/manifest.json # 机器索引,schema version 3 https://doc.sensory.com/tnl/7.8/llms-full.txt # 约 1.3 MiB,全量 Markdown 拼接 https://doc.sensory.com/tnl/7.8/agent-docs.zip # 同内容的打包版,供离线/气隙环境 https://doc.sensory.com/tnl/7.8/api/inference.md # 单页 Markdown 镜像(每页都有)
另设 /tnl/latest/llms.txt 作为跟随最新版的别名。这个设计有个容易被忽略的运维动作:升级 SDK 后必须重钉 URL。llms.txt 的内容是"这一版的 API 长什么样",如果代理还挂在 7.7 的索引上,它会给你的新代码里塞旧签名——比没有 llms.txt 更糟。
2. llms.txt 原文片段(真实、脱敏)
下面是站点 llms.txt 的开头部分,结构可以直接抄:H1 + blockquote 摘要 + 版本声明 + 阅读规则 + 机器索引 + 按任务分组的链接清单。
# TrulyNatural SDK -- agent documentation (Markdown bundle) > On-device speech recognition SDK for embedded systems, mobile apps, and desktop > software. Wake words, command sets, LVCSR, and STT — runs locally with C, Java, > and Python bindings (Android Kotlin uses the Java binding). > This file is the agent-oriented Markdown index of that documentation: the same > content as the themed HTML site, rendered as Markdown with stable link targets, > packaged for coding agents, RAG pipelines, and other LLM tools. > Register this file's URL in a documentation index and ingest the linked `.md` > pages on this host (same content as the paired `HTML:` URLs below). Canonical HTML site: https://doc.sensory.com/tnl/7.8/ Version: 7.8.0 · Latest: https://doc.sensory.com/tnl/latest/llms.txt ## How to read this file - Every entry below is `- [title](markdown_url): summary (HTML: html_url)`. Fetch the `.md` URL for ingestion or the `HTML:` URL for the rendered page; both reach the same content. - **Do not synthesize URLs by stripping `.md` and appending `/`.** Follow the explicit links above instead. Trailing-slash heuristics are not reliable. - **Ingestion:** fetch individual `.md` pages (use `manifest.json` `bytes` to budget context). Reserve llms-full.txt for bulk offline indexing, not as default chat context. - **Priority (drop first under a tight context budget):** the lowest-value sections to skip are `## Symbols`, the per-file source mirrors under `## C examples` / `## Java examples`, `## Changes`, and `## Licenses`. Keep `## Common tasks`, `## Start here`, `## API reference`, `## Setting keys`, and `## Models`. ## Machine index - [manifest.json](https://doc.sensory.com/tnl/7.8/manifest.json): JSON index of every member with `path`, `source_path`, `bytes`, `title`, `canonical_url`, optional `headings`, optional `last_modified`; top-level `symbols`. - [llms-full.txt](https://doc.sensory.com/tnl/7.8/llms-full.txt): every Markdown page concatenated into a single file, one HTML-comment header per page. ## Common tasks - [First wake-word program](.../getting-started/your-first-program.md): Write your first program with the Session API in C, Java, Python, Android, or iOS. - [Integrate into your build](.../api/build-system.md): Add the SDK to a CMake, Make, Java, Python/uv, Gradle (Android), or Xcode (iOS) build. - [Push audio / third-party ASR](.../api/sample/c/push-audio.md): Push audio from your own source through the recognizer with VAD. - [Setting keys reference](.../api/setting-keys/index.md): Look up setting keys for configuration, events, iterators, results, runtime, and library info.
三个细节值得单独圈出来:
## Common tasks的标题直接用用户的口语(push audio、build integration、enroll a UDT in Java),而不是文档目录名("音频输入"、"构建系统")。代理是按语义匹配段落的,用目录名等于让它自己翻译一遍,翻译就会错。显式写"降级顺序":上下文不够时先丢符号表和源码镜像,保留任务路由和 API 参考。多数 llms.txt 只告诉代理"有什么",没告诉它"不够时丢什么",结果代理一超预算就随机截断,恰好把 Common tasks 丢掉。
每个 H2/H3/H4 都有稳定锚点,
## Symbols段把 C/Java/Python 每个入口函数和它的#fragment绑在一起,窄问题直接贴片段而不是整页。
3. llms-full.txt 怎么分块:一页一个文件头
1.3 MiB 的全量文件不是给聊天窗口用的,它是批量离线索引用的。分块方式很朴素但够用:每页拼接前插一个 HTML 注释头,保留原始路径,便于切片后回链。
<!-- FILE: api/inference.md | canonical: https://doc.sensory.com/tnl/7.8/api/inference/ --> # Session API ... <!-- FILE: api/build-system.md | canonical: https://doc.sensory.com/tnl/7.8/api/build-system/ --> # Integrate into your build ...
站点对"放什么不放什么"的态度是明确的:放文档正文、示例代码、设置项字典;不放站内搜索页、登录后内容、构建产物。llms-full.txt 一旦混进导航噪音,切片检索的命中率会明显下降。
4. manifest.json:给"会写代码的代理"准备的第二入口
这是这套方案里最容易被忽略的一层。llms.txt 是给人/模型读的自然语言索引,manifest.json 是给程序读的结构化索引,schema version 3:
| 字段 | 用途 |
|---|---|
path / source_path | 松散镜像路径与 HTML 源路径的对应关系 |
bytes | 精确控制上下文预算,按体积挑页 |
title | 无需先抓页面就能做相关性筛选 |
canonical_url | 跨镜像、manifest、llms-full 的统一 join key |
headings | 参考页的 H2/H3 大纲,用于定位片段 |
last_modified | ISO 8601 UTC,支持增量重摄取 |
symbols | 每个符号在 C/Java/Python 三种绑定下的标识符 |
官方给出的摄取示例(原文,可直接跑):
import json, urllib.request
base = "https://doc.sensory.com/tnl/7.8/llms.txt".rsplit("/", 1)[0]
with urllib.request.urlopen(f"{base}/manifest.json") as r:
manifest = json.load(r)
# manifest["version"] == 3; manifest["entries"] is a list of dicts.
# manifest["symbols"] maps concept names to per-binding identifiers.
for page in manifest["entries"]:
if page["bytes"] < 8192: # small reference page
with urllib.request.urlopen(f"{base}/{page['path']}") as r:
text = r.read().decode("utf-8")
# ingest `text` keyed on page["canonical_url"]注意最后那行注释:用 canonical_url 做入库主键。同一篇内容有 HTML、.md、llms-full 切片、zip 四个副本,只有 canonical_url 在四者之间是同一个字符串,拿 path 做主键迟早会重复入库。
5. robots / 爬虫放行配合项
放行这一层没有花活,但必须确认。站点根目录的 robots.txt 实测(2026-11-04)就三行:
# Allow all crawlers. Served at the origin root only (RFC 9309). User-agent: * Disallow:
含义是全放行,包括 ClaudeBot、GPTBot、OAI-SearchBot、Google-Extended。这里有两个容易翻车的点:
robots.txt 必须放在域名根(
https://doc.sensory.com/robots.txt),放在/tnl/7.8/robots.txt对爬虫无效——这是 RFC 9309 的硬规则。版本化文档树要一并放行:如果只放行
/tnl/latest/,而 llms.txt 里全是/tnl/7.8/的绝对链接,代理顺着清单抓会一路 404。Sensory 的做法是全站通配放行,省掉这类逐版本白名单维护。
结果:能读的和读不进去的
站点没有公开引用次数、工单量或 Lighthouse 得分,所以这里只给可核对的事实和定性观察,不编数字。
可核对的事实(采集于 2026-11-04)
| 项目 | 观测值 | 口径 |
|---|---|---|
| llms.txt 体积 | 约 27 KiB | 站点自述 + 实际响应长度 |
| llms-full.txt 体积 | 约 1.3 MiB | 站点自述,官方建议仅用于批量离线索引 |
| manifest.json | schema version 3,含 symbols 跨语言绑定 | 抓取原文 |
| robots.txt | 全通配放行,位于域名根 | 实际抓取 |
定性观察
官方对效果的表述是"注册一次索引,之后三类高频提问无需额外配置即可落到正确页面"。注意这是站点自述的路由效果,不是准确率提升的量化结论。
真正的坑出现在 Cursor:它 2026 年仍不把 llms.txt 的链接清单当作抓取种子。在 Settings → Indexing & Docs → Add Doc 里贴
.../llms.txt,它只索引这一个文件就停了——因为被链接的页面是 llms.txt 的同级兄弟,不在llms.txt/这个路径前缀下。正确做法是注册渲染后的 HTML 站点根https://doc.sensory.com/tnl/7.8/,让它顺着 MkDocs 导航爬;再单独把llms-full.txt作为一个命名文档加进去兜底。从工具兼容性看,按站点自己的分类:Claude Code、Codex、Aider、Continue、Cline 及多数 RAG 客户端吃 llms.txt 约定;Cursor 走 HTML 索引;写程序的团队走 manifest.json。一个入口喂所有人是行不通的。
外部口径参考:写了不等于被读
EZY Research 在 2026 年 7 月公布过一组 83 个已上线 llms.txt 站点、连续 12 周的服务器日志统计:GPTBot 抓取 llms.txt 仅 7 次,同期抓 robots.txt 3,990 次;ClaudeBot 9 次 vs 3,120 次;PerplexityBot 0 次 vs 775 次;Googlebot 67 次 vs 5,125 次;Meta-ExternalAgent 193 次 vs 172 次。
口径说明:该数据为研究机构自述的日志统计,非第三方复现,样本为 83 个站点,不能外推为全行业比例。它至少说明一件事——llms.txt 现在的价值主要在"代理愿意读它的那部分场景"(编辑器类代理、RAG 摄取),不是 AI 搜索排名开关。把 llms.txt 当排名手段来做,预期会落空。
复盘
三条可直接抄的配置项
三文件分工写进文件里:llms.txt 做路由(约 20–30 KiB),manifest.json 做程序索引(带 bytes 和 last_modified),llms-full.txt 只做批量离线(一页一个
<!-- FILE: -->头)。别把全量内容塞进 llms.txt。按任务口语分组,并写明降级顺序:第一段就是
## Common tasks,用用户会问的原话做链接标题;再明确"预算不足时先丢符号表/源码镜像/历史变更"。这条比多写 100 个链接有用。给 Cursor 单独留一个入口:llms.txt 里直接写清"Cursor 请注册 HTML 站点根",并把站点根 URL 放在显眼位置。省掉每个用户来问一次。
两条踩坑提醒
别用"剥掉 .md 拼斜杠"的启发式构造 URL。Sensory 专门在文件里加了一行禁令:目录根用
/index.md配/index.html,叶子页用x.md配x/index.html,规则不统一,尾斜杠推断必错。索引里给绝对链接,别让代理猜。版本化文档站要重钉索引。SDK/API 升级后,llms.txt 的绝对链接和签名一起变;代理若缓存旧索引,会拿着过期 API 生成代码。把"升级版本 → 更新 llms.txt → 通知团队重钉编辑器入口"写进发版清单。
标注
llms.txt 版本:本次落地采用 v1 结构(H1 + blockquote 摘要 + 分节链接清单 + 可选
## Optional)。文中提到的 v2 写法(<link rel="alternate" type="text/markdown">、rel="describedby")属社区扩展建议,Sensory 站点未对此做公开说明,本文不作为已生效配置引用。规范状态:llms.txt 是 2024 年由 Answer.AI 提出的社区提案,未被 OpenAI、Anthropic、Google 官方确认为抓取标准,各厂商读取行为以其自身实现为准(Cursor 不读即是例证)。
来源:Sensory TrulyNatural SDK 文档站「Coding agents」页与
/tnl/7.8/llms.txt、/tnl/7.8/robots.txt,均于 2026-11-04 抓取;服务器日志数据来自 EZY Research 2026-07-27 发布的 83 站点 12 周统计(研究机构自述)。复盘时间:2026-11-04。
标签:llms.txt、AI可见度、AIWO、结构化暴露、嵌入式SDK