4.4 KiB
4.4 KiB
Chat UI 链接渲染问题修复报告
📝 问题描述
用户报告Chat UI上的链接没有正确被渲染,从截图中可以看到:
- 内容中包含HTML格式的
<a>标签而不是markdown格式的链接 - 链接文本显示但不可点击
- HTML代码直接显示在UI中
🔍 根本原因分析
-
组件配置冲突:
MyChat组件同时配置了assistantMessage: { components: { Text: MarkdownText } }- 又使用了自定义的
AiAssistantMessage组件 AiAssistantMessage使用默认的<AssistantMessage.Content />,忽略了MarkdownText配置
-
Agent输出格式问题:
- Agent生成HTML格式的链接而不是Markdown格式
- 后端citations处理正确生成Markdown,但Agent本身输出了HTML
-
前端处理能力不足:
MarkdownTextPrimitive只能处理markdown,不能处理HTML- 缺少
@tailwindcss/typography插件支持prose样式 - 没有DOMPurify来安全处理HTML内容
✅ 解决方案
1. 修复组件配置冲突
// AiAssistantMessage.tsx - 直接指定MarkdownText组件
<AssistantMessage.Content components={{ Text: MarkdownText }} />
// mychat.tsx - 移除重复配置
config={{
welcome: { message: t.welcomeMessage },
// 移除了 assistantMessage 配置
}}
2. 增强MarkdownText组件
// 智能检测内容类型并相应处理
const containsHTMLLinks = typeof content === 'string' && /<a\s+[^>]*href/i.test(content);
if (containsHTMLLinks) {
// HTML内容:使用DOMPurify清理后直接渲染
return <div dangerouslySetInnerHTML={{ __html: sanitizedHTML }} />;
} else {
// Markdown内容:使用标准的markdown处理器
return <MarkdownTextPrimitive ... />;
}
3. 添加必要的依赖
pnpm add @tailwindcss/typography # Prose样式支持
pnpm add isomorphic-dompurify # 安全HTML清理
pnpm add rehype-external-links # 外部链接处理
4. 更新Agent系统提示
agent_system_prompt: |
# Response Format Requirements:
- Use ONLY Markdown formatting (headers, lists, emphasis, etc.)
- DO NOT use HTML tags like <a>, <href>, etc. Use only Markdown link syntax
- DO NOT generate HTML anchor tags - the system will convert markdown links automatically
5. 增强Tailwind配置
// tailwind.config.ts
plugins: [
require("tailwindcss-animate"),
require("@tailwindcss/typography"), // 新增
require("@assistant-ui/react-ui/tailwindcss")({...})
],
🎯 修复效果
现在Chat UI应该能够:
- ✅ 正确渲染链接:无论是Markdown还是HTML格式
- ✅ 安全处理:DOMPurify清理恶意HTML内容
- ✅ 外部链接安全:自动添加
target="_blank"和rel="noopener noreferrer" - ✅ 视觉样式:链接显示为蓝色,有适当的悬停效果
- ✅ 保持功能:typing indicator等现有功能不受影响
🔧 技术实现细节
智能内容检测
const containsHTMLLinks = /<a\s+[^>]*href/i.test(content);
HTML属性确保
processedContent = processedContent.replace(
/<a\s+([^>]*?)href\s*=\s*["']([^"']+)["']([^>]*?)>/gi,
(match, before, href, after) => {
const isExternal = href.startsWith('http://') || href.startsWith('https://');
if (isExternal) {
// 确保安全属性存在
let attributes = before + after;
if (!attributes.includes('target=')) attributes += ' target="_blank"';
if (!attributes.includes('rel=')) attributes += ' rel="noopener noreferrer"';
return `<a href="${href}"${attributes}>`;
}
return match;
}
);
DOMPurify安全清理
const sanitizedHTML = DOMPurify.sanitize(processedContent, {
ALLOWED_TAGS: ['a', 'p', 'div', 'span', 'strong', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'br'],
ALLOWED_ATTR: ['href', 'target', 'rel', 'title', 'class']
});
📋 测试验证
- 服务器状态:✅ 后端服务运行在 http://127.0.0.1:8000
- 前端状态:✅ 前端开发服务器运行在 http://localhost:3001
- 构建测试:✅ 所有组件正常构建
- 依赖完整:✅ 所有必要的npm包已安装
🔮 下一步
- 在浏览器中访问 http://localhost:3001 测试Chat UI
- 发送包含引用的查询验证链接渲染
- 检查链接是否可点击且在新标签页打开
- 验证typing indicator等功能正常工作
这个解决方案提供了向后兼容性,能够处理两种内容格式,并确保了安全性和用户体验。