Understand-Anything 实现指南:/understand 首次运行的会话语言自动检测(从 SKILL.md 提示逻辑到 config.json 持久化)
本文基于 Understand-Anything 仓库中的实施计划 2026-06-03-language-auto-detection.md 展开。该计划的目标是:在项目内第一次运行 /understand 时,自动检测用户对话所使用的语言并加以确认,然后再开始生成知识图谱内容——同时保证英语用户的体验完全不变。读完本文,你能理解这套"纯提示词逻辑"改动是如何通过四级语言解析链(--language 参数 > 已存配置 > 会话语言检测 > en 默认值)落地的,并能对照仓库源码验证检测结果的持久化位置与消费路径(config.json → 持久化层 → Dashboard 国际化)。
背景与问题:静默的 en 默认值
在改动之前,/understand 生成的所有 LLM 撰写内容(节点摘要、标签、层级名称、引导式游览、语言笔记)默认全部是英语。输出语言只由两个来源控制:显式的 --language <lang> 参数,或 .understand-anything/config.json(新版数据目录为 .ua/config.json)中先前存储的 outputLanguage 字段。配套设计文档 2026-06-03-language-auto-detection-design.md 中记录的观察到的失败场景是:一位全程用中文对话的用户运行了最简单的 /understand 命令,拿到了一张全英文的知识图谱——他只在付完一整次分析运行的时间 + token 成本之后才发现语言不匹配,随后不得不带 --language zh 重新运行。这个默认值是静默的、不可发现的,语言决策在最关键的时点(开始花钱分析之前)没有任何提示。
而改动前的 SKILL.md 步骤 3.6 中,--language 未指定时的分支只有两行:检查 config.json 里有没有 outputLanguage,有则用;没有就 default to en。计划文档将这两行视为"锚点文本",并要求实施者先原样核对再动刀。
设计决策:检测作为兜底,而非每次弹窗
设计文档对比了三个备选方案,最终选定"B:在 SKILL.md 中做检测兜底":
| 方案 | 结论 |
|---|---|
A. 个人 workaround(总是传 --language zh / 手改 config) |
拒绝——对上游零价值,目标是一个可提交的修复 |
| B. 在 SKILL.md 中做检测兜底(选定) | 最小 diff,对非英语用户严格更好,对英语用户完全不可见 |
| C. 每次运行都弹出语言菜单 | 拒绝——重新引入摩擦,最可能被上游维护者拒绝 |
具体设计要点:
- 检测只是解析链中的新插入项,位于
en默认值之前:--language参数 >config.json中的outputLanguage> 首次运行检测会话语言 >en。 - 确认门(confirmation gate)双条件限定:只在"首次运行(无参数、无已存配置)且检测到非英语语言"时出现;英语对话走与原先完全相同的静默
en路径。 - 全分支持久化:无论哪条分支解析出的值(包括
en)都写入config.json({"outputLanguage": "<lang>"}合并进已有配置),因此门每个项目至多触发一次。 - 不确认就静默应用被用户明确要求改为"先确认再分析",但确认被严格约束为不影响英语用户,且是非阻塞的(非交互场景降级为单行提示)。
- 纯提示词改动,不碰代码:没有 schema、TypeScript 或测试钩子的改动——
outputLanguage字段在ProjectConfig中早已存在,locales/<lang>.md的注入也早已接线,本次只是把"决定$OUTPUT_LANGUAGE取值"的提示词逻辑扩写。
文件结构:两个文件的改动边界
计划文档给出的改动范围严格限定为两个文件:
| 文件 | 职责 | 改动 |
|---|---|---|
| understand-anything-plugin/skills/understand/SKILL.md | /understand 技能提示词;步骤 3.6 负责解析 $OUTPUT_LANGUAGE |
重写 If --language is NOT specified 子块(计划撰写时为第 142–144 行,行号可能漂移) |
| README.md | 面向用户的文档;Localized output 一节 | 增加一段描述首次运行自动检测的文字 |
其余相关文件明确不改,这在源码中可以逐一印证:
outputLanguage字段已存在于 types.ts 的ProjectConfig接口中(outputLanguage?: string;计划撰写时引用的是types.ts:119,当前仓库中该行已随文件增长下移,可视为行号漂移的正常现象);$LANGUAGE_DIRECTIVE模板与locales/<lang>.md注入位于 SKILL.md 步骤 3.6 末尾及 Phase 4 的输出语言注入(第 424 行附近),均保持原样;- 非英语用户最终消费这条语言链的位置是 Dashboard:App.tsx 启动时
fetch项目的config.json,config?.outputLanguage存在时驱动<I18nProvider language={...}>(App.tsx#L261)。也就是说,技能侧把语言"写进配置"这一步完成后,Dashboard 的 UI 语言由既有代码自动接管,无需为本次功能新增任何前端逻辑。
这正是本计划"锦上添花"之处:一个只改 Markdown 提示词的 feature,其持久化、容错与消费链路全部由既有 TypeScript 代码承担。
Task 1:扩写 SKILL.md 的语言解析分支
Step 1:先核对锚点文本
计划要求先运行:
sed -n '142,144p' understand-anything-plugin/skills/understand/SKILL.md
并期望看到改动前的三行原文:
- If `--language` is NOT specified:
- Check `$PROJECT_ROOT/.understand-anything/config.json` for an existing `outputLanguage` field. If present, use that.
- If no stored preference, default to `en` (English).
如果文本不一致,说明行号已漂移,应先重读步骤 3.6 定位等价代码块再编辑,而不是硬套行号。
Step 2:替换为四级解析链
用精确的 old_string / new_string 编辑替换上述三行。计划特意说明:新文本描述的是确认的意图,而不是硬编码一个字面量提示框——因为 SKILL.md 是供模型解释执行的提示词,运行时由模型自行渲染询问语句。替换后的新块为:
- If `--language` is NOT specified:
- **Stored preference wins.** If `$UA_DIR/config.json` has an `outputLanguage` field, set `$OUTPUT_LANGUAGE` to it and skip the rest.
- **Otherwise detect (first run only).** Infer the predominant language of the user's conversation as an ISO 639-1 code (`$DETECTED_LANG`). If it is `en` or cannot be confidently determined, set `$OUTPUT_LANGUAGE=en` and proceed silently — no prompt (English users see no change).
- **If `$DETECTED_LANG` ≠ `en`, confirm once before analyzing:** tell the user you detected `<language>` and ask whether to generate all content in it; they press Enter/"yes" to accept, or type another language code/name to override (normalize via the friendly-name map above). If running non-interactively (no reply possible), skip the wait, use `$DETECTED_LANG`, and print a one-line notice instead of blocking.
- **Persist** the resolved `$OUTPUT_LANGUAGE` (including `en`) into `config.json` so it never re-prompts for this project.
四条规则各自承担一个职责:
- 已存配置优先:有
outputLanguage就直接用并跳过后续全部逻辑——这保证了"门每个项目至多触发一次"; - 检测仅在首次运行时发生:把对话的主导语言推断为 ISO 639-1 码
$DETECTED_LANG;若是en、或无法有把握地判定(混合/含糊对话),直接静默置en,不弹任何提示; - 非英语才弹确认门:告知用户检测到的
<language>,询问是否用它生成全部内容;用户按 Enter/yes接受,或输入其他语言代码/名称覆盖(覆盖值通过 3.6 上方既有的 friendly-name 映射表归一化,如chinese→zh、japanese→ja,locale 变体如zh-TW、pt-BR原样保留);非交互运行(headless/CI,无人应答)则跳过等待、直接用$DETECTED_LANG并打印一行提示,绝不挂起; - 持久化:把解析出的
$OUTPUT_LANGUAGE(包括en)写入config.json。
注意新块中的 $UA_DIR 而非改动前的 $PROJECT_ROOT/.understand-anything——这符合 SKILL.md Phase 0 步骤 1.7 对数据目录的解析规则:项目已有 .understand-anything/ 则沿用(存量项目零迁移),否则用新的 .ua/。README.md 对这一兼容性有面向用户的表述:"Projects that already have a .understand-anything/ directory keep using it."
"用中文对话但想要英文文档给团队"这个逃生通道由确认门的覆盖输入承担:检测出 zh 但用户在门里输入 en,最终输出即为英文。
Step 3:验证编辑落位且格式正确
sed -n '142,170p' understand-anything-plugin/skills/understand/SKILL.md
grep -c 'default to `en`' understand-anything-plugin/skills/understand/SKILL.md
第一条确认新多级块存在,且其后紧跟着未改动的 - If --language IS specified: 行;第二条期望输出 0——旧的独立 default to en 行已消失,新措辞是 "set $OUTPUT_LANGUAGE to en"。
Step 4:提交
计划给出的提交信息(保留了原计划中的措辞):
git add understand-anything-plugin/skills/understand/SKILL.md
git commit -m "feat(understand): detect conversation language on first run
Expand SKILL.md step 3.6 with conversation-language detection as a
fallback before the en default, gated behind a first-run-only,
non-English-only confirmation. Resolved value is persisted to
config.json so the gate fires at most once. English users see no change."
源码佐证:持久化一侧的既有设施
值得从源码层面确认的是,提示词中"Persist into config.json"这一句背后的读写基础设施是现成且带容错的:
- persistence/index.ts 定义了
DEFAULT_CONFIG: ProjectConfig = { autoUpdate: false, outputLanguage: "en" },saveConfig/loadConfig负责config.json的读写; loadConfig在文件缺失或 JSON 损坏时都安全回退到默认配置(outputLanguage: "en"),因此即使 config 被写坏,语言解析也不会抛异常——最坏情况退回本次改动之前的行为;- persistence.test.ts 覆盖了三个场景:配置往返一致、无文件返回默认(含
outputLanguage: "en")、config.json内容损坏时返回默认; - 从源码结构看,服务端的兜底同样存在:vite.config.ts 与 viewer.mjs 在直接请求
config.json失败时会返回{ autoUpdate: false, outputLanguage: "en" }作为默认响应。
这些事实说明:本计划的"只改提示词"边界之所以成立,是因为写端(技能执行时写配置)和读端(core 持久化层、Dashboard)都早已按 outputLanguage 契约工作。
Task 2:README 文档化
在 README.md 的 Localized output 一节、锚点行 The \--language` parameter affects:` 之前插入一段说明。计划给出的验证与插入命令:
grep -n 'The `--language` parameter affects:' README.md # 期望在 ~130 行附近命中一行
插入的段落(old_string 为锚点行,new_string 为新段落 + 锚点行):
On the **first run** in a project — when you don't pass `--language` and no language is stored yet — `/understand` detects the language you're conversing in. If it isn't English, it asks you to confirm (or override) before generating; English conversations are unaffected. Your choice is saved to `.understand-anything/config.json` and reused on every later run.
The `--language` parameter affects:
验证:
grep -n 'first run' README.md
期望命中的新句子正好位于 "The --language parameter affects:" 上方。当前仓库中该段落已落地于 README.md#L141(措辞随数据目录更名更新为 .ua/config.json),其上下文还包含既有的 --language 用法示例(/understand --language zh,支持 en(默认)、zh、zh-TW、ja、ko、ru)。随后的提交:
git add README.md
git commit -m "docs: note first-run conversation-language auto-detection"
Task 3:手工验证(无自动化测试钩子)
计划明确指出:技能提示词行为没有单元测试框架可挂(这与既有 --language 参数的验证方式一致),因此验证方式是对照编辑后的 3.6 文本逐场景推演,确认提示词逻辑产生正确的 $OUTPUT_LANGUAGE 与 config.json 写入,并把每个场景的结果记录进 PR 描述。五个场景与预期:
| # | 情境(全新项目,无 config.json) | 预期结果 |
|---|---|---|
| 1 | 中文对话,运行 /understand |
确认门出现 → 用户确认 → $OUTPUT_LANGUAGE=zh;config.json 写入 "outputLanguage":"zh" |
| 2 | 同项目再运行(config 已有 zh) |
无门(已存配置优先);直接生成 zh |
| 3 | 英语对话,运行 /understand |
无门;$OUTPUT_LANGUAGE=en;英语输出(无回归) |
| 4 | 全新项目传 --language ja |
无门(参数优先);config.json 写入 "outputLanguage":"ja" |
| 5 | 检测到 zh,用户在门里输入 en |
$OUTPUT_LANGUAGE=en;config.json 写入 "outputLanguage":"en" |
此外还有两个必须确认的性质:
- 无回归不变量(计划称之为"上游接受与否最关键的一条属性"):重读编辑后的代码块,确认不存在任何"纯英语对话 + 无参数 + 无配置却弹出提示"的路径——场景 3 必须保持静默。
- 可选的实盘冒烟测试:在一个丢弃型仓库(无
.understand-anything/config.json)中用中文简短对话、运行/understand,确认确认门出现、确认后config.json被写入outputLanguage: "zh"。若完整分析运行成本太高可跳过——Step 1 的推演对 PR 已足够。
边缘情形的完整行为在设计文档中有对照表(检测不确定/混合语言 → 按 en 静默处理,绝不为猜测而阻塞;非交互调用 → 回退到检测值并附单行提示;自动更新钩子路径不受影响——它不复用语言解析;检测语言有 locales/<lang>.md 文件 → Phase 4 既有注入直接生效,如 locales/zh.md 提供的标签命名与摘要风格指引;没有 locale 文件 → $LANGUAGE_DIRECTIVE 照常生效,走"静默跳过"行为)。
Task 4:开 PR 与上游话术
推分支后创建 PR,计划给出了完整的 PR 描述模板,其结构值得借鉴(面向"任何新增交互都会被 reviewer 警惕"这一上游现实):
- What:首次
/understand(无--language、无已存outputLanguage)时,技能检测对话语言,且仅在非英语时请求确认或覆盖;选择持久化到.understand-anything/config.json,门永不再触发。 - Why:输出语言默认静默为英语,中文用户要付完全量分析成本才发现语言不匹配,还得带
--language zh重跑。 - Zero change for English users:确认门只在"检测到非英语且尚未选择过语言"时出现;英语对话走与之前完全相同的静默
en路径;--language参数与已存配置均优先于检测。 - Scope:只动了 SKILL.md 步骤 3.6 加一句 README;无代码/schema 改动;其他技能与自动更新钩子未动(是另外的已知缺口);非交互调用降级为检测值 + 提示。
计划自检:覆盖度、占位符与命名一致性
计划文档末尾附了一份 Self-Review,是这类"提示词即代码"改动质量的重要保障,包含三个维度:
- Spec 覆盖:解析链(参数 > 配置 > 检测 > en)、"仅非英语 + 仅首次"的门、含
en在内的值持久化、不确定/混合对话按en静默处理、非交互回退、自动更新钩子不受影响、locales/<lang>.md已接线无需改动、README 一句话、五个手工验证场景——逐条对应到 Task 1–3 的具体步骤,全部打勾。 - 占位符扫描:文中没有留下模糊的 "TBD/TODO/handle edge cases",每个边缘情形都有明确解析后的行为;确认门里的
<language>/<code>是技能运行时要填充的模板占位符,属有意为之,不是计划缺口。 - 命名一致性:全文四个变量名保持稳定——
$OUTPUT_LANGUAGE(解析结果)、$DETECTED_LANG(检测值)、outputLanguage(config 键名)、--language(CLI 参数),且与 SKILL.md 步骤 3.6 中既有命名完全一致。这四个名字在当前仓库中均可检索印证:$OUTPUT_LANGUAGE/$DETECTED_LANG出现在 SKILL.md,outputLanguage出现在 types.ts、persistence/index.ts 与 App.tsx,--language出现在 SKILL.md 的 Options 一节。
小结
这份计划展示了 Understand-Anything 中一类值得参考的实现路径:当功能本身是"给模型的指令"而非"给机器的代码"时,一个完整 feature 可以被压缩为对 SKILL.md 单个步骤的块级重写加一句 README 说明,同时用"锚点文本先核对、grep 负断言验证、五场景手工推演 + 无回归不变量"替代不存在的自动化测试钩子,并以持久化契约(config.json 的 outputLanguage 键,读写与容错由 @understand-anything/core 既有代码承担)保证行为跨运行一致。对英语用户零变化、对非英语用户首次确认后零再扰动的双约束,是这类"引入交互"改动通过上游审查的关键设计。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00