news 2026/9/13 13:39:06

Data Formulator 多语言与 Agent 语言注入开发规范:从 Accept-Language 到 LLM Prompt 的完整链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Data Formulator 多语言与 Agent 语言注入开发规范:从 Accept-Language 到 LLM Prompt 的完整链路

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 的多语言处理分为两条链路,二者职责严格分离:

  1. LLM 输出语言约束:前端当前语言通过Accept-Language传给后端,后端构造language_instruction注入 Agent prompt,让 LLM 生成与用户界面语言一致的文本。
  2. 固定文案翻译:代码中的按钮、提示、错误等固定字符串不交给 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 prompt

1.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_instruction,route 使用compact模式
workspace-name已接入SimpleAgents接收language_instruction,生成 session/workspace 展示名使用full
nl-to-filter暂不注入当前返回结构化 JSON;未来若返回用户可见自然语言再接入
test-model明确豁免健康检查需要固定返回,不应被语言指令影响
rec_language_instruction已清理当前routes/agents.py未再保留该误导性参数
message_code/content_code/option_codes已落地Python 固定用户消息由前端翻译,后端保留英文 fallback
前端 i18n已有 en/zh 主链路LanguageSwitcherfetchWithIdentity()、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 -> 自然语言为主:mode="full" -> 代码 / 结构化 JSON / 短文本为主:mode="compact"

2.1 Route 层:读取 UI 语言并传给 Agent

在 route handler 中通过get_language_instruction()读取当前 UI 语言并构造指令。以SortDataAgent为例(py-src/data_formulator/routes/agents.py):

language_instruction = get_language_instruction(mode="compact") agent = SortDataAgent(client=client, language_instruction=language_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(), mode=mode)

注意这里的关键约束:语言必须来自每个请求的Accept-Language,而不是进程级环境变量,否则多用户、多语言并发场景下会串语言。在仓库中可以看到各 route 的实际用法:

  • SortDataAgentDataRecAgentDataTransformationAgentChartRestyleAgent相关 route 使用mode="compact"(见 routes/agents.py 与ChartRestyleAgent构造处 L774);
  • workspace-nameDataAgent等文本型场景使用mode="full"(见 L380、L630、L882)。

mode选择表

Mode适用场景
full文本型 Agent:探索、报告、解释、聊天、洞察、数据加载对话
compact代码生成、数据转换、排序、自动命名、短文本生成、结构化输出

建议模式对照

场景Mode
DataAgentChartInsightAgentInteractiveExploreAgentReportGenAgentfull
CodeExplanationAgentDataLoadingAgentfull
DataRecAgentDataTransformationAgentDataLoadAgentcompact
SortDataAgentChartRestyleAgentcompact
workspace-namefull
test-model、模型列表、纯状态检查不注入
nl-to-filterclassify-chart-intent不注入(纯结构化输出)

2.2 Agent 层:接收并注入语言指令

Agent 构造函数应接收language_instruction: str = "",并用inject_language_instruction()注入 system prompt:

from 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模式生成的是字段级明细规则:声明用户可见字段(titletakeawaystextgoaltagdisplay_instructionmessagesummaryexplanationdata_summarysuggested_table_namefield_display_names、报告 Markdown 全文等)必须使用目标语言,而内部字段(output_variableoutput_fieldschart_typeencodingsconfigsemantic_typefield_metadatareasondetailed_instructionthoughtdifficulty、所有 JSON key、Python 代码及注释)必须保持英文,同时明确"原始数据集列名不得翻译、新派生列在代码中使用 snake_case 英文、用户可见文本中使用目标语言描述"。
  • compact模式是面向代码生成 Agent 的三句精简指令:只要求display_instructionsuggested_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 + 翻译 code

Python 中固定的用户可见消息不能只靠language_instruction,因为它们不是 LLM 生成内容。后端应返回英文 fallback翻译 code,让前端翻译。

3.1 单条消息(error 事件)

yield { "type": "error", "message": "Output DataFrame is empty (0 rows).", "message_code": "agent.emptyDataframe", }

3.2 结果 content

result = { "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_paramscontent_paramstext_params,例如{"missing": "...", "available": "..."}
  • clarify事件使用questions[].text_codequestions[].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.clarifyExhaustedDataAgentclarify
agent.clarifyOptionContinue/Simplify/PresentDataAgentclarify options
agent.maxIterationsSummaryDataAgentcompletion summary
agent.emptyDataframeDataAgenterror event
agent.fieldsNotFoundDataAgentchart field validation
agent.llmApiErrorDataAgentLLM error
agent.llmEmptyResponseDataAgentempty model response
agent.parseActionFailedDataAgentaction parse failure
agent.unknownActionDataAgentaction dispatch
agent.noCodeBlockDataRecAgent/DataTransformationAgent
agent.unexpectedErrorDataRecAgentfallback
agent.codeExecErrorcode execution fallback
agent.unableExtractScriptDataLoadAgent/SortDataAgent
agent.errorCallingModelDataLoadingChatAgent

4. 前端消费后端消息:translateBackend()

前端使用translateBackend()(src/app/utils.tsx)消费后端消息。普通后端消息直接翻译;结构化澄清问题逐题翻译text_codelabel_code

import { 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?: Record<string, 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 字符串必须走 i18n:

import { 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。命名空间按现有文件选择:commonuploadchartmodelencodingmessagesnavigationdataLoadingerrors等。

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都配置完成的语言,才应出现在前端语言切换器中。

接入一门新语言的完整步骤:

  1. 在 agents/agent_language.py 的LANGUAGE_DISPLAY_NAMES中添加语言代码和显示名。
  2. 如有特殊要求,添加到LANGUAGE_EXTRA_RULES(例如中文的简体/繁体约束、日文的敬体约束)。
  3. src/i18n/locales/<lang>/添加完整翻译资源。
  4. 在服务端配置AVAILABLE_LANGUAGES,让前端语言切换器显示该语言。
  5. 验证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.ts

6.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 中的LanguageSwitcherserverConfig.AVAILABLE_LANGUAGES读取可选语言列表:

  • 若可用语言数量<= 1,切换器直接不渲染(return null);
  • 每个语言按钮展示LANGUAGE_LABELS中的短标签(如EN中文日本語한국어FRDE),未知语言回退为lang.toUpperCase()
  • 点击按钮调用i18n.changeLanguage(value)切换前端语言,随后所有/api/请求的Accept-Language头会随之改变(见下文第 7 节)。

7. 前端到后端的语言传递:fetchWithIdentity()

语言传递的起点是getAgentLanguage()(src/app/utils.tsx):

export 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-IdX-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()
  • 正确选择fullcompact
  • Python 固定用户消息带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 + code
  • code 在src/i18n/locales/en/messages.jsonzh/messages.json中都有翻译
  • 如属于错误处理体系,优先使用统一ErrorCode/AppError

Review 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.mdc
  • docs/dev-guides/1-streaming-protocol.md
  • docs/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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 13:38:25

多Agent系统可观测性实战:从埋点设计到故障排查的完整方法论

我们团队最近把三条业务线全部迁到了基于大模型的多Agent协作架构上&#xff0c;系统跑起来的那一瞬间&#xff0c;所有人都很兴奋。但等兴奋劲过了&#xff0c;真正让人头疼的事情才刚开始&#xff1a;系统在测试环境一切正常&#xff0c;一到生产环境就开始“抽风”&#xff…

作者头像 李华
网站建设 2026/9/13 13:37:46

基于1D CNN的锂电池故障诊断:从1×9特征输入到工程部署

简介&#xff1a;一份面向深度学习与电池健康管理研究者的CNN故障诊断示例资源&#xff0c;聚焦电池不一致性故障场景&#xff0c;展示如何用卷积神经网络对19维电池采集数据进行特征提取与状态分类&#xff0c;适合初学者对照学习卷积层、池化、Softmax等模块实现。包内共12个…

作者头像 李华
网站建设 2026/9/13 13:36:41

垃圾分选设备行业现状与技术发展趋势

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 13:33:13

Jetpack Compose单选多选列表:用ID集合管理状态,避免勾选丢失

简介&#xff1a;面向Android开发者的Kotlin Compose列表交互实现资源&#xff0c;集中展示单选与多选两种高频场景。基于声明式UI框架&#xff0c;通过LazyColumn高效渲染长列表&#xff0c;并配合RadioGroup、RadioButton与Checkbox完成选项状态管理&#xff0c;替代传统Recy…

作者头像 李华