简介
Perplexity Sonar 在 markdown 答案里嵌内联引用标记如 [1]、[2],加上一个单独的 citations URL 数组。要把这个变成精致 UI 需要:解析标记、按索引挂到 URL、渲染成可点上标脚注、最好还有 hover 预览。这个 skill 是 React + Markdown 模式做完四件事。适合任何在 UI 里展示 Sonar 答案的产品。兼容 react-markdown、remark/rehype、任何 Markdown 渲染器。装机时间 15 分钟。
React 组件
import ReactMarkdown from "react-markdown";
interface Props { content: string; citations: string[] }
export function SonarAnswer({ content, citations }: Props) {
// 把 [1] [2] 等替换为 HTML 上标锚点
const withFootnotes = content.replace(/\[(\d+)\]/g, (_, n) => {
const idx = parseInt(n) - 1;
const url = citations[idx];
if (!url) return `[${n}]`;
return `<sup><a href="${url}" target="_blank" rel="noopener noreferrer" title="${url}">[${n}]</a></sup>`;
});
return (
<div className="prose">
<ReactMarkdown
components={{ a: ({ node, ...props }) => <a {...props} className="text-blue-600 hover:underline" /> }}
rehypePlugins={[]}
skipHtml={false}
>
{withFootnotes}
</ReactMarkdown>
<h3 className="mt-6 text-sm font-semibold">来源</h3>
<ol className="text-sm">
{citations.map((url, i) => (
<li key={i}>
<span className="text-gray-500">[{i + 1}]</span>
<a href={url} target="_blank" rel="noopener noreferrer" className="ml-2">{new URL(url).hostname}</a>
</li>
))}
</ol>
</div>
);
}Hover 预览 tooltip(可选)
import { Tooltip } from "@radix-ui/react-tooltip";
function CitationSup({ n, url }: { n: number; url: string }) {
return (
<Tooltip>
<Tooltip.Trigger asChild>
<sup>
<a href={url} target="_blank" rel="noopener noreferrer">[{n}]</a>
</sup>
</Tooltip.Trigger>
<Tooltip.Content className="bg-black text-white px-2 py-1 rounded text-xs">
{new URL(url).hostname} —— 点开
</Tooltip.Content>
</Tooltip>
);
}链接安全清单
target="_blank"+rel="noopener noreferrer"—— 防反向 tabnabbing- Sanitize URL —— 拒绝
javascript:/data:/ 任何非 http(s) - 未经同意别服务端自动抓源 —— 隐私
- 单独记点击,让分析能把流量归因到 Sonar
要处理的边缘情况
| 情况 | 处理 |
|---|---|
标记 [42] 但只有 5 个引用 |
渲染成纯 [42](不带链接) |
| 同一引用引了 3 次 | 同一编号;Sources 列表去重 |
| 引用 URL 带追踪参数 | 显示前剥 utm_* |
| 非 HTTP URL | 丢弃或显纯文本 |
FAQ
Q: 标记没对应引用怎办? A: 渲染裸标记不带链接。别报错 —— 有时 Sonar 指的是用户已知的内联上下文。记录不匹配便于以后调试。
Q: 要预拉源页面吗?
A: 别 —— 隐私 + 成本问题。让用户点过去。要更丰富预览,单独抓源 URL 的 og:image + og:description 加缓存。
Q: 能服务端拿结构化引用吗?
A: Sonar Pro 在 citations 之外返回 search_results 数组,含 title + URL + last_updated。这就是结构化形式,方便更丰富渲染。