Files
catonline_ai/vw-agentic-rag/docs/topics/CHAT_UI_LINK_FIX.md
2025-09-26 17:15:54 +08:00

4.4 KiB
Raw Permalink Blame History

Chat UI 链接渲染问题修复报告

📝 问题描述

用户报告Chat UI上的链接没有正确被渲染从截图中可以看到

  • 内容中包含HTML格式的<a>标签而不是markdown格式的链接
  • 链接文本显示但不可点击
  • HTML代码直接显示在UI中

🔍 根本原因分析

  1. 组件配置冲突

    • MyChat组件同时配置了assistantMessage: { components: { Text: MarkdownText } }
    • 又使用了自定义的AiAssistantMessage组件
    • AiAssistantMessage使用默认的<AssistantMessage.Content />忽略了MarkdownText配置
  2. Agent输出格式问题

    • Agent生成HTML格式的链接而不是Markdown格式
    • 后端citations处理正确生成Markdown但Agent本身输出了HTML
  3. 前端处理能力不足

    • 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应该能够

  1. 正确渲染链接无论是Markdown还是HTML格式
  2. 安全处理DOMPurify清理恶意HTML内容
  3. 外部链接安全:自动添加target="_blank"rel="noopener noreferrer"
  4. 视觉样式:链接显示为蓝色,有适当的悬停效果
  5. 保持功能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']
});

📋 测试验证

  1. 服务器状态 后端服务运行在 http://127.0.0.1:8000
  2. 前端状态 前端开发服务器运行在 http://localhost:3001
  3. 构建测试 所有组件正常构建
  4. 依赖完整 所有必要的npm包已安装

🔮 下一步

  1. 在浏览器中访问 http://localhost:3001 测试Chat UI
  2. 发送包含引用的查询验证链接渲染
  3. 检查链接是否可点击且在新标签页打开
  4. 验证typing indicator等功能正常工作

这个解决方案提供了向后兼容性,能够处理两种内容格式,并确保了安全性和用户体验。