Skills2026年5月11日·1 分钟阅读

Perplexity Citations — Render Source Footnotes in Your UI

Parse Perplexity inline citation markers ([1][2][3]) + the citations URL array into clickable footnote UI. Markdown render, hover preview.

Agent 就绪

这个资产可以被 Agent 直接读取和安装

TokRepo 同时提供通用 CLI 命令、安装契约、metadata JSON、按适配器生成的安装计划和原始内容链接,方便 Agent 判断适配度、风险和下一步动作。

Native · 98/100策略:允许
Agent 入口
任意 MCP/CLI Agent
类型
Skill
安装
Single
信任
信任等级:New
入口
Asset
通用 CLI 安装命令
npx tokrepo install dd02260f-0044-4e5a-8e2d-5849c95fd587

简介

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。这就是结构化形式,方便更丰富渲染。


🙏

来源与感谢

Pattern compiled from Perplexity API docs + react-markdown.

remarkjs/react-markdown — ⭐ 13,000+

讨论

登录后参与讨论。
还没有评论,来写第一条吧。

相关资产