首页
/ Understand-Anything 会话语言自动检测设计:`/understand` 的四级语言解析链与首跑确认门

Understand-Anything 会话语言自动检测设计:`/understand` 的四级语言解析链与首跑确认门

2026-09-06 11:36:32作者:戚魁泉Nursing

本文围绕 Understand-Anything 的设计文档 2026-06-03-language-auto-detection-design.md 展开,讲解 /understand 技能如何在不改动任何代码与 Schema 的前提下,通过重写 SKILL.md 的语言解析逻辑,实现"首次分析时自动检测用户会话语言、非英文才确认一次"的输出语言决策机制。读完你可以完整理解其四级解析链(flag > 存储配置 > 会话检测 > en 兜底)的设计动机、确认门(confirmation gate)的行为边界、全部边缘情形处理,以及仓库中该方案落地后的真实源码位置(SKILL.mdProjectConfig 类型、Dashboard 语言解析、locales/ 注入链)。

问题背景:静默的 en 默认值代价高昂

/understand 会生成全部 LLM 撰写的内容——节点摘要、标签、层级名称、导览(guided tours)、语言注释等——而默认全部输出为英文。改动前的行为由 SKILL.md 第 3.6 步控制:只有显式传入 --language <lang> 参数,或 .understand-anything/config.json 中存有 outputLanguage 时才生效,两者皆无则静默回落到英文

- If `--language` is NOT specified:
  - Check config.json for outputLanguage. If present, use that.
  - If no stored preference, default to `en` (English).

设计文档中记录的真实失败场景是:一位全程用中文对话的用户运行了最简单的 /understand 命令,拿到了一张全英文的知识图谱——而他只有在付完一整次分析的运行成本(时间 + token)之后才发现语言不对,只能带着 --language zh 重跑一遍。默认值既是静默的又是不可发现的:语言决策在真正要紧的时刻没有任何提示浮出。

这正是该设计的出发点:在项目首次分析时,从会话中推断用户的工作语言,并在消耗分析预算之前确认它——同时保证英文用户(项目核心受众)行为完全不变、非交互式调用不被阻塞。

目标与非目标

目标:首次分析时从会话推断用户语言并确认,代价是改动面极小——纯提示词逻辑(prompt-logic),因为 outputLanguage 字段本已存在于 ProjectConfig 中(见 types.ts):

// Project config (for auto-update opt-in and language preference)
export interface ProjectConfig {
  autoUpdate: boolean;
  outputLanguage?: string;
}

非目标(Non-Goals) 在设计文档中被明确列出,划定了严格的边界:

  • 不做并排双语输出——每张图谱仍是单语言;
  • 不改动其他生成类技能(understand-domainunderstand-knowledgeunderstand-explain 等),它们目前完全忽略 outputLanguage,属于留给后续 PR 的已知缺口;
  • 不改动自治自动更新钩子路径(understand-anything-plugin/hooks/auto-update-prompt.md)——它复用已有图谱、不解析语言,检测逻辑在那里永远不会触发;
  • 不做任何代码、Schema 或 TypeScript 改动。

方案选型:检测作为兜底,而非菜单

设计文档对比了三条路线,最终选择了 (B):

  • (A) 个人绕过(永远手动传 --language zh / 手改配置):对上游零价值,否决;
  • (B) 在 SKILL.md 中"检测作为兜底"(被选中):最小 diff,对非英文用户严格更好,对英文用户完全不可见。检测逻辑插入解析链中、位于 en 默认值之前,并由"仅首跑、仅非英文"的确认门把关;
  • (C) 每次运行都弹菜单:重新引入摩擦,也最容易被上游维护者否决。

选择"确认门"而非"静默应用检测值",是为了显式性,但被严格约束为绝不影响英文用户。值得强调的一个细节:SKILL.md 本身是一段由模型解释执行的提示词,所以技能文档中写的是确认的意图(一条指令),而不是硬编码一个字面提示框——问题文本由模型在运行时自行渲染。同时 SKILL.md 的指令文本保持英文,只有生成的内容才是目标语言。

详细设计:四级语言解析链

这是对 SKILL.md 第 3.6 步 if --language NOT specified 分支的重写。优先级从高到低:

  1. --language <lang> 参数存在 → 通过既有的友好名映射表归一化,持久化到 config.json 后使用。(行为不变)
  2. config.json 中存在 outputLanguage → 直接使用。(行为不变)
  3. 首跑(既无参数又无配置)→ 新增:检测会话语言
    • 推断当前会话中用户消息的主导语言 → $DETECTED_LANG(ISO 639-1 码,如 zhja);
    • $DETECTED_LANGen、无法自信判定、或会话混合/含糊 → 置 $OUTPUT_LANGUAGE = en,持久化,无提示直接进行(对核心受众精确保持现状);
    • $DETECTED_LANG ≠ en → 弹出下文确认门,解析出 $OUTPUT_LANGUAGE 并持久化。
  4. 所有分支最终都会把解析值写入 config.json{"outputLanguage": "<lang>"} 合并进既有配置),因此确认门每个项目至多触发一次

配套的友好名归一化映射(在检测与覆盖两个环节共用):

输入形式 归一化结果
chinese / japanese / korean / english / spanish / french / german / portuguese / russian / arabic zh / ja / ko / en / es / fr / de / pt / ru / ar
区域变体:zh-TWzh-HKzh-CNpt-BR 原样保留

确认门:只在"非英文 + 尚未选择"时出现

确认门在任何流水线阶段运行之前展示,指令要求模型做到三件事:

  • 说明检测到的语言,询问是否用它生成所有内容;
  • 接受 Enter / "yes" / 检测到的语言码作为确认 → $OUTPUT_LANGUAGE = $DETECTED_LANG
  • 接受任意其他语言码或友好名作为覆盖 → 经友好名映射归一化后使用。这一条同时充当逃生舱口——"我用中文聊天,但团队文档要英文"的场景。

边缘情形全覆盖

设计文档为每种边缘情形给出了明确的已决行为,不留模糊空间:

情形 行为
检测不确定 / 混合语言 en 处理,静默继续。绝不为猜测而阻塞。
非交互式调用(headless/CI,无人应答) 回落到 $DETECTED_LANG 并打一行提示,而非挂在确认门;确认是尽力而为(best-effort),永远不是硬阻塞。
自治自动更新钩子 不受影响——该路径根本不解析语言。
检测到的语言有 locales/<lang>.md 文件 第 4 步已有注入逻辑,无需改动。
检测到的语言没有 locale 文件 $LANGUAGE_DIRECTIVE 仍然生效(既有的"静默跳过"行为)。

仓库落地现状:从设计到已实现的源码证据

该设计已实现,且可以在仓库中逐条对照验证。

1. SKILL.md 第 3.6 步的现行文本。 SKILL.md 中的 "Language configuration" 小节与设计完全一致——"Stored preference wins → Otherwise detect (first run only) → If $DETECTED_LANGen, confirm once → Persist" 四步解析链已就位,非交互降级("skip the wait, use $DETECTED_LANG, and print a one-line notice instead of blocking")也原样写入:

- 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:** ...
  - **Persist** the resolved `$OUTPUT_LANGUAGE` (including `en`) into `config.json` so it never re-prompts for this project.

紧接其后的 $LANGUAGE_DIRECTIVE 模板(L161-L164)规定了语言指令的语义:所有文本内容(summaries、descriptions、tags、titles、languageNotes、languageLesson)以目标语言生成,保持母语级自然表达,且无标准译法的术语保留英文(如 "middleware"、"hook"、"barrel")。该模板被注入到多个阶段——项目扫描派发的 prompt(L251)、逐批文件分析(L310)、架构分析(L439)与导览生成(L516),保证一次决策覆盖全流水线。

2. 持久化层的既有支持。 配置落盘并不需要新代码:persistence/index.tsDEFAULT_CONFIG 已内置 outputLanguage: "en"persistence.test.ts 验证了"无配置文件时返回默认配置"与"配置损坏时回落到默认"两个用例——这正是"检测失败也绝不阻塞"的底层保障:即使 config.json 写坏了,系统也只是回到 en,而不是抛错。另外注意 SKILL.md 第 1.7 步的数据目录解析:若项目已有 .understand-anything/ 目录则沿用,否则使用新的 .ua/ 目录,配置始终写在 $UA_DIR/config.json

3. Dashboard 侧的语言联动。 --language 参数同时影响 Dashboard UI 的文案。从 locales/index.tsresolveLocaleKey 可以看到 UI 层支持的正是同一组语言键——enzhzh-TWjakoru,且做了大小写、下划线、区域码的归一化(如 zh-cnzh),未知值一律回落 en。这与 README 中 "Supported languages: en (default), zh, zh-TW, ja, ko, ru" 的声明相互印证。

4. locales/<lang>.md 注入链。 设计文档边缘情形表中"已有 locale 文件则注入"对应的是 SKILL.md 第 4 步的第 4 条(L424):当 $OUTPUT_LANGUAGE 不是 en 时,读取 ./locales/<language-code>.md 并以 ## Output Language Guidelines 头附加到分析 agent 的 prompt 之后;文件不存在则静默跳过。locales/zh.md 提供了具体的语言指导——标签中英混合策略(通用术语保留英文、描述性标签可用中文)、1-2 句摘要风格、术语保留清单(middlewareORMsingleton 等)、层级命名(API 层服务层 或保留英文 API Layer)。locales/ 目录下还配有 en.mdja.mdko.mdru.mdzh-TW.md,与 UI 侧支持的语言集合对齐。

5. README 用户文档。 设计要求的"一句话说明"已落在 README.md 的 Localized output 小节:首跑且未传 --language、未存语言时,/understand 会检测会话语言;非英文则询问确认或覆盖,英文会话不受影响;选择写入 .ua/config.json 并在后续每次运行复用。

验证策略:五个手工场景与"零回归"不变量

由于是提示词逻辑改动,技能行为没有单元测试钩子——这与既有 --language 参数的验证方式一致。配套的实现计划 2026-06-03-language-auto-detection.md 定义了逐场景推演验证(对编辑后的 3.6 步文本追踪,确认产生的 $OUTPUT_LANGUAGEconfig.json 写入正确):

# 场景(全新项目,无 config.json 预期结果
1 中文会话,运行 /understand 确认门出现 → 确认 → $OUTPUT_LANGUAGE=zhconfig.json 得到 "outputLanguage":"zh"
2 同项目重跑(配置已含 zh 无确认门(存储偏好优先);生成 zh
3 英文会话,运行 /understand 无确认门;$OUTPUT_LANGUAGE=en;英文输出(无回归)
4 全新项目传 --language ja 无确认门(参数优先);config.json 得到 "outputLanguage":"ja"
5 检测到 zh,用户在确认门输入 en $OUTPUT_LANGUAGE=enconfig.json 得到 "outputLanguage":"en"

其中场景 3 承载了实现计划中标注的**"零回归"不变量**:不存在任何代码路径会让"纯英文会话 + 无参数/无配置"产生提示。这是上游接受度最关键的一条性质。若想做真实冒烟测试:在一个无 .ua/config.json 的临时仓库中用中文简短对话后运行 /understand,确认确认门出现、确认后 config.json 写入 outputLanguage: "zh"(完整分析跑太贵时可跳过,场景推演已足够支撑 PR)。

改动面与上游风险控制

设计文档的 "Files Touched" 清单精确到两个文件,且再无其他文件——没有 Schema、代码或测试脚手架改动:

文件 责任 改动
SKILL.md /understand 技能提示词;第 3.6 步解析 $OUTPUT_LANGUAGE 重写 If --language is NOT specified 子块为四级解析链(主改动)
README.md 用户文档 Localized output 小节 增加一段首跑自动检测说明

主要审查风险是任何新增的交互性。设计内置了三重缓解:确认门仅首跑触发仅非英文触发非交互时优雅降级。PR 描述以此为核心主张:"英文用户零行为变化;确认门只在会话非英文且尚未选择语言时才出现。"

小结

这套语言自动检测的价值不在"检测"本身,而在其工程化的克制:它把整个语言决策收敛在 SKILL.md 第 3.6 步这一处,用"参数 > 配置 > 检测 > 兜底"的优先级链保证显式意图永远压过启发式推断;用"每项目至多一次"的持久化消除重复打扰;用"不确定即 en、非交互即降级"两条铁律保证检测永远不会成为阻塞点。对维护者而言,这是一个"零代码改动、只动提示词"却完整修复了真实用户痛点的范例——检测、确认、覆盖、持久化四个环节的行为边界,均可在 SKILL.mdtypes.tspersistence/index.tslocales/ 中逐条对照核实。

登录后查看全文
热门项目推荐
相关项目推荐