大模型输出数学公式出现乱码的解决方案
大模型输出数学公式出现乱码的解决方案
在 LLM 应用开发中,Markdown渲染器(如 react-markdown)与 LaTeX 公式语法的冲突是典型的工程痛点。本文归纳了导致乱码的核心原因,并给出基于 Unified 生态(Remark/Rehype)的工业级解决方案。
1. Root Cause Analysis (根因分析)
乱码现象通常表现为:公式源码显示为纯文本、反斜杠丢失、或部分符号被错误渲染为斜体/加粗。核心冲突在于 Markdown Parser 的贪婪解析:
- Escape Character Conflict: LaTeX 依赖
\(反斜杠) 转义,而 Markdown 引擎会优先将\消费掉(例如将\[解析为转义的[)。 - Syntax Ambiguity: LaTeX 中的下划线
_(下标) 会被 Markdown 解析为<i>(斜体)。 - LLM Uncertainty: 模型输出的不确定性(例如输出
\\frac而不是\frac,或者(与[混用)。
2. The Standard Stack (标准技术栈)
不推荐手写 Regex 进行 Mask/Unmask(维护成本极高且容易产生 Corner Case)。推荐使用 Unified 生态的插件链方案:
- Parser:
react-markdown(主渲染器) - Tokenizer Plugin:
remark-math(在 Markdown 解析阶段识别数学符号,保护其不被错误处理) - Renderer Plugin:
rehype-katex(将数学节点渲染为 HTML/CSS)
3. Implementation (核心代码)
以下是基于 React 的标准实现方案。重点在于 预处理 (Preprocessing) 和 插件配置。
3.1 预处理清洗 (The "Dirty" Fix)
LLM 经常会吐出不规范的 LaTeX 格式(比如双重转义 \\)。在送入组件前,必须进行一次清洗。
// utils/format.ts
export const preprocessLaTeX = (content: string) => {
if (!content) return '';
return content
// 1. 修复被转义的行内公式: \\( ... \\) -> $ ... $
.replace(/\\\((.*?)\\\)/g, (_, tex) => `$${tex}$`)
// 2. 修复被转义的块级公式: \\[ ... \\] -> $$ ... $$
.replace(/\\\[([\s\S]*?)\\\]/g, (_, tex) => `$$${tex}$$`)
// 3. 清洗不标准的转义字符 (Optional,视模型情况而定)
// .replace(/\\\\/g, '\\');
};
3.2 渲染组件封装
引入 katex 样式是必须的,否则公式没有 CSS 支撑。
import React from 'react';
import ReactMarkdown from 'react-markdown';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
import 'katex/dist/katex.min.css'; // 必须引入样式
// 针对特定场景的自定义组件(可选)
const components = {
// 可以在这里拦截特定标签进行定制
};
export const AIChatMessage = ({ rawContent }) => {
// 1. 清洗数据
const cleanContent = preprocessLaTeX(rawContent);
return (
<div className="markdown-body">
<ReactMarkdown
// 2. 配置 remark 插件:识别数学语法
remarkPlugins={[remarkMath]}
// 3. 配置 rehype 插件:使用 KaTeX 渲染
rehypePlugins={[rehypeKatex]}
components={components}
>
{cleanContent}
</ReactMarkdown>
</div>
);
};
4. Edge Cases & Troubleshooting
A. 流式输出时的“闪烁” (Flickering)
现象:当 LLM 正在输出公式时(如输出到 $$ \frac{ 时断开),渲染器会因为语法闭合不全而无法渲染,导致用户看到源码,直到公式输出完毕瞬间跳变。
解法:
这是 Markdown 渲染器的通病。可以通过检测“未闭合的公式标记”来临时补全,或者在 CSS 层做过渡动画,但通常接受这个 Trade-off。
B. remark-math 无法识别行内公式
原因:标准的 remark-math 默认可能只支持 $$。
解法:确保预处理函数将 \( 转换为 $,或者配置 remark-math 的 singleDollarTextMath 选项(取决于版本)。
5. Summary
不要试图用正则表达式去重写 Markdown 引擎。
Rule of Thumb:
- Trust the Plugins: 使用
remark-math+rehype-katex处理 AST。 - Sanitize Input: 在入口处用简单的 Replace 统一 LaTeX 格式(统一转为
$和$$)。 - CSS Matter: 别忘了 import katex.css。

浙公网安备 33010602011771号