Data Formulator 多语言与 Agent 语言注入开发规范:从 Accept-Language 到 LLM Prompt 的完整链路
发布时间:2026/9/13 13:39:51 作者:尧图编辑部 阅读量:1,286

Data Formulator 多语言与 Agent 语言注入开发规范从 Accept-Language 到 LLM Prompt 的完整链路【免费下载链接】data-formulator Data Formulator is an interactive AI-powered data analysis system makes it easy to connect, explore and visualize data.项目地址: https://gitcode.com/GitHub_Trending/da/data-formulator导读Data Formulator 是一个交互式 AI 数据分析系统Agent 需要根据用户界面语言生成图表标题、洞察结论、澄清问题等自然语言内容。本规范文档docs/dev-guides/6-i18n-language-injection.md定义了LLM 输出语言约束 固定文案翻译两条多语言链路前端通过Accept-Language头把当前 UI 语言传给后端后端构造language_instruction注入 Agent 的 system prompt而按钮、错误提示等固定字符串则通过message_code/content_code交给前端 i18n 翻译。读完本文你将掌握 Data Formulator 中 Agent prompt 语言注入的full/compact模式选择、后端固定消息的 code 化协议、前端translateBackend()消费路径以及如何为系统接入一门新语言。1. 架构概览两条互不混淆的多语言链路Data Formulator 的多语言处理分为两条链路二者职责严格分离LLM 输出语言约束前端当前语言通过Accept-Language传给后端后端构造language_instruction注入 Agent prompt让 LLM 生成与用户界面语言一致的文本。固定文案翻译代码中的按钮、提示、错误等固定字符串不交给 LLM 翻译必须通过前端 i18n 或message_code/content_code由前端翻译。完整的请求链路如下frontend i18n.language - fetchWithIdentity() sets Accept-Language - routes/agents.py get_language_instruction() - agents/agent_language.py build_language_instruction() - Agent prompt1.1 核心模块与职责模块职责src/app/utils.tsxgetAgentLanguage()、fetchWithIdentity()、translateBackend()src/app/App.tsxLanguageSwitcher基于AVAILABLE_LANGUAGES切换前端语言py-src/data_formulator/routes/agents.py_get_ui_lang()、get_language_instruction()py-src/data_formulator/agents/agent_language.pybuild_language_instruction()、inject_language_instruction()src/i18n/locales/{en,zh}/前端翻译资源1.2 当前代码对照状态从原设计文档迁移时已按当前代码重新核对以下状态以当前仓库为准不能把早期计划里的状态原样视为事实项目当前状态说明SortDataAgent已接入构造函数接收language_instructionroute 使用compact模式workspace-name已接入SimpleAgents接收language_instruction生成 session/workspace 展示名使用fullnl-to-filter暂不注入当前返回结构化 JSON未来若返回用户可见自然语言再接入test-model明确豁免健康检查需要固定返回不应被语言指令影响rec_language_instruction已清理当前routes/agents.py未再保留该误导性参数message_code/content_code/option_codes已落地Python 固定用户消息由前端翻译后端保留英文 fallback前端 i18n已有 en/zh 主链路LanguageSwitcher、fetchWithIdentity()、locale 资源已接入静态检查 / CI未落地scripts/check_language_injection.py、pre-commit 强制检查仍是未来项2. Agent Prompt 语言注入新增或修改会调用 LLM 的 Agent route 时先判断输出是否面向用户展示再决定是否注入语言指令输出类型是否注入说明用户可读解释、建议、报告、对话、自动命名是必须跟随 UI 语言生成代码、JSON key、字段名、变量名部分使用compact只约束用户可见字段纯健康检查 / 固定连通性测试否例如test-model保持固定英文更稳定纯结构化 JSON 且不展示自然语言通常否例如当前nl-to-filter未来若返回用户文案再接入决策树新增 LLM 调用 - 输出是否面向用户展示 - 否健康检查、内部工具调用、日志不注入 - 是 - 独立 Agent 类构造函数添加 language_instruction用 inject_language_instruction() - 内联 LLM 调用route 中直接把 language_instruction 放入 system prompt - 自然语言为主modefull - 代码 / 结构化 JSON / 短文本为主modecompact2.1 Route 层读取 UI 语言并传给 Agent在 route handler 中通过get_language_instruction()读取当前 UI 语言并构造指令。以SortDataAgent为例py-src/data_formulator/routes/agents.pylanguage_instruction get_language_instruction(modecompact) agent SortDataAgent(clientclient, language_instructionlanguage_instruction)底层实现中_get_ui_lang()直接从每个请求的Accept-Language头提取主语言代码def _get_ui_lang() - str: Extract the primary language code from the Accept-Language header. return request.headers.get(Accept-Language, en).split(,)[0].split(-)[0].strip().lower() def get_language_instruction(*, mode: str full) - str: Read the UI language from the Accept-Language header and build the prompt instruction. return build_language_instruction(_get_ui_lang(), modemode)注意这里的关键约束语言必须来自每个请求的Accept-Language而不是进程级环境变量否则多用户、多语言并发场景下会串语言。在仓库中可以看到各 route 的实际用法SortDataAgent、DataRecAgent、DataTransformationAgent、ChartRestyleAgent相关 route 使用modecompact见 routes/agents.py 与ChartRestyleAgent构造处 L774workspace-name、DataAgent等文本型场景使用modefull见 L380、L630、L882。mode选择表Mode适用场景full文本型 Agent探索、报告、解释、聊天、洞察、数据加载对话compact代码生成、数据转换、排序、自动命名、短文本生成、结构化输出建议模式对照场景ModeDataAgent、ChartInsightAgent、InteractiveExploreAgent、ReportGenAgentfullCodeExplanationAgent、DataLoadingAgentfullDataRecAgent、DataTransformationAgent、DataLoadAgentcompactSortDataAgent、ChartRestyleAgentcompactworkspace-namefulltest-model、模型列表、纯状态检查不注入nl-to-filter、classify-chart-intent不注入纯结构化输出2.2 Agent 层接收并注入语言指令Agent 构造函数应接收language_instruction: str 并用inject_language_instruction()注入 system promptfrom data_formulator.agents.agent_language import inject_language_instruction system_prompt inject_language_instruction(system_prompt, language_instruction)inject_language_instruction()的实现py-src/data_formulator/agents/agent_language.py支持两种插入策略def inject_language_instruction( system_prompt: str, language_instruction: str, *, marker: str | None None, ) - str: if not language_instruction: return system_prompt if marker: idx system_prompt.find(marker) if idx 0: return ( system_prompt[:idx] language_instruction \n\n system_prompt[idx:] ) return system_prompt \n\n language_instruction复杂 prompt 可以指定marker把语言指令插入到技术细节之前system_prompt inject_language_instruction( system_prompt, language_instruction, marker**About the execution environment:**, )注入位置策略策略适用场景marker 前插入复杂 prompt需要在技术细节前声明语言要求末尾追加简单 prompt或者动态构建的 system prompt这两种策略都可以接受不需要为了形式统一而重构所有 Agent。2.3 必须遵守的硬性规则不要在 prompt 中硬编码回答请使用中文之类的语言要求。不要用进程级环境变量决定语言语言必须来自每个请求的Accept-Language。不要新增并行的MessageBuilder或 LLM client 全局拦截器。不要跳过get_language_instruction()在 route 中直接调用build_language_instruction()。不要把语言指令塞进 user message语言约束应放在 system prompt。build_language_instruction(en)返回空字符串英文用户不需要额外 prompt见下方实现细节。2.4build_language_instruction()的底层实现py-src/data_formulator/agents/agent_language.py 中def build_language_instruction(language: str, *, mode: str full) - str: lang ((language or ).strip().lower()) or DEFAULT_LANGUAGE.lower() if lang en: return display_name LANGUAGE_DISPLAY_NAMES.get(lang, lang) extra LANGUAGE_EXTRA_RULES.get(lang, ) if mode compact: return _build_compact(display_name, extra) return _build_full(display_name, extra)几个关键行为英文返回空字符串en是默认语言不需要向 prompt 注入任何额外指令这也解释了为何inject_language_instruction()对空指令直接 no-op。未识别语言代码例如xx仍会返回非空指令块并使用原始 code 作为显示名LANGUAGE_DISPLAY_NAMES.get(lang, lang)保证任何语言下 LLM 都有明确的输出约束。full模式生成的是字段级明细规则声明用户可见字段title、takeaways、text、goal、tag、display_instruction、message、summary、explanation、data_summary、suggested_table_name、field_display_names、报告 Markdown 全文等必须使用目标语言而内部字段output_variable、output_fields、chart_type、encodings、config、semantic_type、field_metadata、reason、detailed_instruction、thought、difficulty、所有 JSON key、Python 代码及注释必须保持英文同时明确原始数据集列名不得翻译、新派生列在代码中使用 snake_case 英文、用户可见文本中使用目标语言描述。compact模式是面向代码生成 Agent 的三句精简指令只要求display_instruction和suggested_table_name使用目标语言其余 JSON 字段、Python 代码、变量名、列引用与注释保持英文并强调不得翻译原始数据集列名——这样额外文本不会干扰模型编写正确代码。此外模块内置了 20 种语言的显示名注册表LANGUAGE_DISPLAY_NAMES含 en/zh/ja/ko/fr/de/es/pt/ru/ar/hi/th/vi/it/nl/pl/tr/id/ms/sv以及按语言定制的额外规则LANGUAGE_EXTRA_RULES例如中文要求使用简体而非繁体、日文要求用户可见文本使用です/ます体敬体。3. 后端用户可见消息英文 fallback 翻译 codePython 中固定的用户可见消息不能只靠language_instruction因为它们不是 LLM 生成内容。后端应返回英文 fallback和翻译 code让前端翻译。3.1 单条消息error 事件yield { type: error, message: Output DataFrame is empty (0 rows)., message_code: agent.emptyDataframe, }3.2 结果 contentresult { status: error, content: No code block found in the response., content_code: agent.noCodeBlock, }3.3 结构化澄清问题clarify 事件event { type: clarify, questions: [{ id: continue_after_tool_rounds, text: How would you like to proceed?, text_code: agent.clarifyExhausted, text_params: {steps: steps_desc}, responseType: single_choice, options: [ { id: continue, label: Continue exploring, label_code: agent.clarifyOptionContinue, }, { id: simplify, label: Simplify the task, label_code: agent.clarifyOptionSimplify, }, ], }], }3.4 命名规则与协议约束Agent 相关 key 放在messages.agent.*。后端字段中只写agent.emptyDataframe前端会拼成messages.agent.emptyDataframe。有参数时使用message_params、content_params、text_params例如{missing: ..., available: ...}。clarify事件使用questions[].text_code和questions[].options[].label_code不要再新增顶层message/options/option_codes协议。LLM 根据当前 UI 语言生成的问题和选项通常只需要text/label固定后端文案才需要同时提供 fallback 文本和 code。questions[].options[]的翻译只作用于当前问题的选项不要把多个问题的选项合并到同一个数组。不要新增 Python 侧翻译表或agent_messages.py早期设计中的该方案已由前端message_code翻译模式取代。后端普通 HTTP 响应优先走统一错误处理的ErrorCode/AppError详见 docs/dev-guides/7-unified-error-handling.md还未纳入统一错误体系的jsonify(message...)不应宣称已经全部完成国际化。3.5 已迁移的 Agent 消息 key当前第一批高频 Agent 固定消息已经在 src/i18n/locales/en/messages.json 和 src/i18n/locales/zh/messages.json 中提供翻译Key来源agent.clarifyExhaustedDataAgentclarifyagent.clarifyOptionContinue/Simplify/PresentDataAgentclarify optionsagent.maxIterationsSummaryDataAgentcompletion summaryagent.emptyDataframeDataAgenterror eventagent.fieldsNotFoundDataAgentchart field validationagent.llmApiErrorDataAgentLLM erroragent.llmEmptyResponseDataAgentempty model responseagent.parseActionFailedDataAgentaction parse failureagent.unknownActionDataAgentaction dispatchagent.noCodeBlockDataRecAgent/DataTransformationAgentagent.unexpectedErrorDataRecAgentfallbackagent.codeExecErrorcode execution fallbackagent.unableExtractScriptDataLoadAgent/SortDataAgentagent.errorCallingModelDataLoadingChatAgent4. 前端消费后端消息translateBackend()前端使用translateBackend()src/app/utils.tsx消费后端消息。普通后端消息直接翻译结构化澄清问题逐题翻译text_code和label_codeimport { translateBackend } from ../app/utils; const message translateBackend( event.message, event.message_code, event.message_params, ); const questionText translateBackend( question.text, question.text_code, question.text_params, ); const optionLabel translateBackend(option.label, option.label_code);translateBackend()的实现非常简洁核心是fallback 优先export function translateBackend( fallback: string, code?: string, params?: Recordstring, unknown, ): string { if (!code) return fallback; const key messages.${code}; const translated i18n.t(key, { ...params, defaultValue: fallback }); return translated; }如果没有 code 或没有翻译函数会回退到后端英文 fallback保证缺翻译时界面不会空白。前端还有配套的translateBackendOptions(options, codes)用于平行翻译一组选项 label 数组。澄清面板自己的固定 UI 文案例如标题、按钮、占位符和直接说明标签放在 src/i18n/locales/{en,zh}/common.json 的chartRec下不要从后端事件里下发这些前端壳层文案。5. 前端 UI 文案所有用户可见字符串必须走 i18n所有用户可见 UI 字符串必须走 i18nimport { useTranslation } from react-i18next; const { t } useTranslation(); return Button{t(common.save)}/Button;必须翻译按钮、菜单、tooltip、placeholder、dialog 标题toast/snackbar 文案空状态、加载状态、错误提示表格列头、面板标题、说明文字可以不翻译console.log/ debug 日志CSS class、test id、内部常量跨前后端共享的 sentinel value例如内部状态 marker翻译文件位于 src/i18n/locales/en/ 与 src/i18n/locales/zh/。新增 key 时必须同时更新 en 和 zh。命名空间按现有文件选择common、upload、chart、model、encoding、messages、navigation、dataLoading、errors等。5.1 翻译 key 命名规范优先使用现有 namespace。大量独立功能文案可以新建 namespace但必须同时添加 en/zh 资源并注册到 locale index例如 src/i18n/locales/index.ts 中的import en from ./en; import zh from ./zh; export { en, zh };。命名模式namespace.component-or-feature.element dataLoading.toolLabels.readingFile dataLoading.actions.loadTable dataLoading.placeholder.describeData common.actions.close messages.error.failedToOpenWorkspace设计文档中曾列出一批前端硬编码审计结果迁移到本规范后这些清单不再作为当前待办事实维护。开发时以.cursor/rules/i18n-no-hardcoded-strings.mdc和本节规则为准发现新增或修改的用户可见文案时就地迁移到 i18n。6. 新语言接入指南agent_language.py支持的 20 种 LLM 输出语言不等于前端 UI 已完整翻译 20 种语言。只有 locale 文件和AVAILABLE_LANGUAGES都配置完成的语言才应出现在前端语言切换器中。接入一门新语言的完整步骤在 agents/agent_language.py 的LANGUAGE_DISPLAY_NAMES中添加语言代码和显示名。如有特殊要求添加到LANGUAGE_EXTRA_RULES例如中文的简体/繁体约束、日文的敬体约束。在src/i18n/locales/lang/添加完整翻译资源。在服务端配置AVAILABLE_LANGUAGES让前端语言切换器显示该语言。验证fetchWithIdentity()请求头、Agent 输出、固定 UI 文案都使用新语言。每种新语言至少需要与 en/zh 等价的 locale 结构src/i18n/locales/lang/ ├── common.json ├── upload.json ├── chart.json ├── model.json ├── encoding.json ├── messages.json ├── navigation.json ├── dataLoading.json ├── errors.json ├── loader.json └── index.ts6.1AVAILABLE_LANGUAGES的服务端配置服务端在 py-src/data_formulator/app.py 中读取该配置默认值为[en, zh]同时支持通过环境变量AVAILABLE_LANGUAGES默认en,zh逗号分隔或--available_languages命令行参数覆盖见 app.py 与 L383。6.2 前端语言切换器的联动逻辑src/app/App.tsx 中的LanguageSwitcher从serverConfig.AVAILABLE_LANGUAGES读取可选语言列表若可用语言数量 1切换器直接不渲染return null每个语言按钮展示LANGUAGE_LABELS中的短标签如EN、中文、日本語、한국어、FR、DE未知语言回退为lang.toUpperCase()点击按钮调用i18n.changeLanguage(value)切换前端语言随后所有/api/请求的Accept-Language头会随之改变见下文第 7 节。7. 前端到后端的语言传递fetchWithIdentity()语言传递的起点是getAgentLanguage()src/app/utils.tsxexport function getAgentLanguage(): string { return i18n.language.split(-)[0]; }它把i18n.language可能是zh-CN这种带 region 的完整标签裁剪成 BCP-47 主语言代码zh。随后fetchWithIdentity()包装所有/api/请求utils.tsx在构建 Headers 时设置headers.set(Accept-Language, getAgentLanguage());同时还会附加X-Identity-Id、X-Workspace-Id头并在前端认证模式下附加Authorization: Bearer token若后端返回 401会尝试一次静默 OIDC token 刷新并重试请求。后端_get_ui_lang()正是解析这个Accept-Language头来得到语言见第 2.1 节由此完成前端语言 → HTTP 头 → LLM prompt的闭环。8. 自动化现状与未来约束当前已有前端fetchWithIdentity测试覆盖身份和认证 header 行为。前端 error code/i18n 映射测试覆盖结构化错误翻译。后端 Agent 和 error handler 测试覆盖部分message_code/ warning 事件。当前未作为已完成能力声明没有专门的scripts/check_language_injection.py静态检查脚本。没有 pre-commit/CI 强制扫描所有新增 LLM 调用点。普通后端 HTTP 响应消息仍在逐步迁移到 error code / message code 体系。如果后续实现自动化检查应更新本文档和相关 Cursor rules。建议的未来自动化后端 AST 检查扫描新增用户可见 Agent route 是否调用get_language_instruction()。前端 ESLint启用i18next/no-literal-string初期可设为warn逐步提高到error。PR checklist要求新增 Agent、route、后端 message code、前端文案都按本文档检查。这些内容是未来约束不是当前已完成能力。9. 新模块开发 Checklist新增 Agent构造函数接收language_instruction: str system prompt 使用inject_language_instruction()route 层调用get_language_instruction()正确选择full或compactPython 固定用户消息带message_code/content_code新增 Agent Route读取Accept-Language派生语言指令test-model这类健康检查明确记录为不注入nl-to-filter这类纯结构化 JSON route 若新增自然语言输出需要重新评估注入流式事件中的错误、clarify、summary 使用 message code前端消费路径调用translateBackend()新增前端组件使用useTranslation()和t()en/zh 都添加翻译 key不翻译内部 sentinel value后端 message code 用translateBackend()消费新增后端固定消息判断消息是否用户可见用户可见则提供英文 fallback codecode 在src/i18n/locales/en/messages.json和zh/messages.json中都有翻译如属于错误处理体系优先使用统一ErrorCode/AppErrorReview Checklist没有进程级默认语言或硬编码中文/英文 prompt 约束没有新增 Python 侧翻译字典没有在 user message 中注入语言要求没有新增未翻译的用户可见 TSX 字符串英文 fallback 存在缺翻译时不会空白10. 相关规范文档.cursor/skills/language-injection/SKILL.md.cursor/rules/language-injection-conventions.mdc.cursor/rules/i18n-no-hardcoded-strings.mdcdocs/dev-guides/1-streaming-protocol.mddocs/dev-guides/7-unified-error-handling.md【免费下载链接】data-formulator Data Formulator is an interactive AI-powered data analysis system makes it easy to connect, explore and visualize data.项目地址: https://gitcode.com/GitHub_Trending/da/data-formulator创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考