> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# MCP 检索的引用存活率：127 个问题、3 条流水线实测
- URL: https://www.hubwiz.com/blog/rag-citation-survival-mcp-boundary/
- Published: 2026-10-17T12:42:51.000Z
- Updated: 2026-10-17T13:01:41.000Z
- Description: 检索服务交出了来源，Agent 写答案时还引用吗？127 个问题实测：CSR 0.618/0.614/0.323，但六成“丢引用”只是格式不对。
- Author: admin
- Tags: RAG, MCP, 引用, 评测

**一句话结论**：企业把文档做成 MCP 检索工具后，**能保证"正确的来源进去了"，却看不到"引用有没有出来"**——因为写答案的 Agent 不归你控制。2026 年 10 月，一份可复现的基准第一次量了这件事：用 FastAPI 文档的 2,085 个块、127 个逐条人工核对的问题、三条尽量对齐的流水线，测**引用存活率（CSR）**。结果是单次 RAG **0.618**、LangGraph Agent **0.614**（逐题差异 +0.000）、OpenAI Agents SDK Agent **0.323**。但作者随后发现，**约六成的差距只是格式问题**：SDK 在 40% 的回答里没按要求的 `[url]` 格式写，却用 Markdown 链接给了来源。修正口径、重跑三次后，真实差距约为 **−0.09 \~ −0.12**；而在检索服务端给每个块加一个短 ID，错格式从每轮约 50 降到约 5。

**披露**：本文编译自 Ayan Arshad 的系列第一篇（dev.to，2026-10-17），作者公开了仓库、trace 与全部数字，并在文末说明自己正在寻找 RAG/Agent 方向的远程工作。文中所有结果都是其自建基准上的单次测量，作者本人列出了语料、模型、重复次数与人审规模的边界。

---

## 一、问题：检索服务看不到答案

一个正在变成常态的场景：

1. 公司把文档变成搜索工具，通过 **MCP** 暴露，任何 Agent 都能调用：Claude、ChatGPT、IDE 里的编码助手、客户用 LangGraph 或 OpenAI Agents SDK 搭的 Agent。
2. 工具工作得很好：每个查询返回最相关的文档块，每个块带 `source_url`：

```json
{
  "source_url": "https://fastapi.tiangolo.com/tutorial/body-updates/",
  "content": "# Body - Updates ..."
}

```

1. Agent 接手：读块、判断相关性、写最终答案。

**检索服务永远看不到那个答案。** 所以供应商能确认"正确的来源进去了"，却不知道"引用有没有出来"。

对文档助手来说这是硬伤：

- 答案正确但**没有引用** → 无法核对，用户也点不进那个解释边界的页面；
- 答案**引用了错的页面** → 看起来像验证过，其实没有。

作者找不到有人量过这件事，于是自己搭了基准。

## 二、方法：把边界复制出来

研究问题是：**当 RAG 知识库通过 MCP 被 Agent 消费，而不是单次"检索→回答"，引用还在吗？**

直觉假设是"Agent 会丢引用"：Agent 会循环——搜索、阅读、可能再搜一次、然后写答案；第一次调用拿到的来源在写答案时已经被推到上下文很后面，似乎很容易丢。结果这个假设**大部分是错的**，而它错的方式比假设本身更有用。

### 语料与服务器

| 项       | 设置                                                                                    |
| ------- | ------------------------------------------------------------------------------------- |
| 语料      | FastAPI 文档，**153 页**，按标题切成 **2,085 个块**                                               |
| 选择理由    | 干净的 Markdown、稳定的公开 URL、被广泛使用，任何人可复核                                                   |
| MCP 服务器 | 单个工具 search\_fastapi\_knowledge\_sources，只返回 {source\_url, content}，走 streamable HTTP |
| 问题      | 草拟 250 个，**逐条对照真实文档页后保留 127 个**                                                       |
| 问题构成    | 82 个可从单页回答、29 个需要两页以上、**16 个文档根本没覆盖**（用来抓编造答案）                                        |

### 三条尽量对齐的流水线

同一个模型（`gpt-4o-mini`）、同一份文档、同一个系统提示、同一种要求的引用格式（每条主张后面紧跟 `[url]`）：

1. **单次 RAG**：搜一次，然后回答。对照组。
2. **LangGraph Agent**：ReAct Agent，自行决定何时、调用几次 MCP 工具。
3. **OpenAI Agents SDK Agent**：同样的思路，用 OpenAI 的 Agent 框架及其内置 MCP 支持。

### 指标：CSR 要求两条都过

"有没有引用"比想象中难测：答案可以满是 URL 却归因错误；可以引用一个真实但**不支持这句话**的页面；也可以引用一个看起来很像 FastAPI、但 Agent 从未检索过的 URL（模型知道 FastAPI 的 URL 长什么样）。所以 **CSR（Citation Survival Rate）**要求每个引用通过两项检查：

| 检查       | 做什么                                    | 方法来源             |
| -------- | -------------------------------------- | ---------------- |
| **支持检查** | 被引用的块是否真的支持这条主张？把答案拆成原子主张，逐条做蕴含判断      | FActScore + ALCE |
| **溯源检查** | 这个 URL 是否真的出现在 Agent 的检索结果里？每次工具调用都有日志 | 工具调用日志           |

> **CSR = Agent 实际检索到的正确来源中，最终被引用在"该来源确实支持的主张"上的比例。**

注意这个前提：**"Agent 实际检索到的来源"**。如果 Agent 根本没找到正确页面，那是检索失败，CSR 不把它算进来。CSR 只衡量"正确来源跨过边界之后发生了什么"。

## 三、第一轮结果：一个差点被发布的错误结论

| 流水线（gpt-4o-mini）        | CSR       | 95% CI           |
| ----------------------- | --------- | ---------------- |
| 单次 RAG                  | **0.618** | \[0.528, 0.708\] |
| LangGraph Agent         | **0.614** | \[0.524, 0.705\] |
| OpenAI Agents SDK Agent | **0.323** | \[0.237, 0.414\] |

LangGraph 与单次 RAG 持平（逐题差异 +0.000），说明**Agent 循环本身不损失引用**。而 SDK 看起来丢了一半：**127 个答案里有 66 个没有出现提示要求的 `[url]` 格式引用**。

作者对这个数字信了很久，直到把 66 个答案逐条读完：

- **51 个**其实引用了，只是用了 Markdown 链接 `[source](https://...)`；
- **7 个**用了别的形式，比如 `[source: https://...]`；
- **只有 8 个**完全没有 URL（单次 RAG 有 19 个这样的答案）。

评分器只认 `[url]`，于是把所有 Markdown 链接都算成"没有引用"。作者先写下修正后的口径（`[url]`、Markdown 链接、其他括号形式都算），再重新评分：

| 流水线                     | 只认指定格式 | 任意引用格式都算  |
| ----------------------- | ------ | --------- |
| 单次 RAG                  | 0.618  | 0.618     |
| LangGraph Agent         | 0.614  | 0.643     |
| OpenAI Agents SDK Agent | 0.323  | **0.470** |

按任意格式计算后，SDK 与单次 RAG 的剩余差距：原评分器为 **−0.16**（显著），gpt-4o 评委为 **−0.10**（不显著）。一次运行无法定论，于是每种设置跑三次：

- 汇总后，原评分器 **−0.12**、gpt-4o 评委 **−0.09**；
- 只认指定格式时约 **−0.30**；
- 也就是说，**约 60% 是格式问题，40% 是真实但更小的引用损失**；
- **温度为 0 时检测不到损失。**

## 四、更稳定、也更重要的效应：框架默认值

比 CSR 差距更稳定的发现是：

> **OpenAI Agents SDK 在其默认 API 上，127 个答案里有 51 个（40%）忽略了要求的引用格式。两次重复运行分别是 53 和 46。单次 RAG 是 0 次，LangGraph 是 8 次。**

这比听起来严重：任何下游按固定格式读引用的东西——文档挂件、"查看来源"面板、护栏、像本文这样的评测——**什么都读不到**。引用在系统眼里已经消失，即使人读文本还能找到。

## 五、原因排查：不是循环，不是温度，不是传输

作者在跑实验之前就写下计划，然后一次只改一个变量：

| 假设         | 实验                                                                                                                                                                       | 结论               |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- |
| Agent 循环导致 | LangGraph 也循环，格式保持；且 Agent 平均只搜索 1.2–1.3 次                                                                                                                               | **不是循环**         |
| 温度导致       | SDK 流水线从未设置温度（LangGraph 用 0）；对齐后错格式仅从 60 降到 54                                                                                                                           | **不是温度单独导致**     |
| 传输丢失来源     | 直接把 SDK 收到的内容 dump 出来：每个块都带完整 source\_url；118 个 Markdown 链接中 98 个指向 Agent 检索过的页面                                                                                         | **不是传输**         |
| 框架默认 API   | SDK 默认调 OpenAI **Responses API**，LangGraph 的 OpenAI 集成用 **Chat Completions**；同一 SDK Agent 换成 Chat Completions 后，错格式从 **41 降到 9**；换一份已发表的 grounded 系统提示后降到 **20**；三次运行都成立 | **是默认 API / 提示** |

两项修复都在 **Agent 侧**，而检索供应商控制不了 Agent。所以作者又测了一个**服务端能做的修复**：

> 给每个块打一个短来源 ID（例如 `[S3fa21c]`），要求 Agent 引用 `[ID]`，答案写完后由服务端把 ID 映射回 URL。

结果：在作者自托管的镜像上，错格式答案从**每轮约 50 降到约 5**，SDK Agent 的 CSR 上升 **0.10–0.13**，与单次 RAG 的差距基本闭合。边界也写清楚了：这些引用**还没有经过人工审计**。

## 六、这些数字可信吗

作者把"量得准不准"当成实验的一部分：

- **两种评分器**：一个蕴含模型 + 一个 LLM 评委（gpt-4o），先用作者自己的 115 个盲判断来选评分器；评委与作者一致度最高（**κ 0.86**）。两者不一致的地方如实报告。
- **人工对照**：30 个盲测案例中，CSR 的判断与作者一致 **25–27 个**（取决于评分器）。其中两个案例有同样的 Markdown 链接盲点，这正是发现格式问题的方式之一。
- **重复运行**：每个 gpt-4o-mini 设置跑三次；先写下稳健性规则——每次运行符号相同，且汇总区间不含 0。
- **发布前自审**：像敌意评审一样过了一遍流水线，找到**五个 bug**，其中四个本来会随文发布。格式问题是第六个，也是作者最不愿提的一个：在发现之前，他已经把夸大的数字发给了别人，只能更正。
- **限制**：一个语料、两个模型、gpt-4o-mini 每个设置三次（Claude 只跑一次）、人工检查规模小、用的是自托管的 MCP 服务器镜像而不是生产系统。

## 七、六条可带走的结论

1. **如果你通过 MCP 提供 RAG，你的准确率保证止于边界。** 你控制检索，不控制写答案的 Agent。如果引用对产品重要，就要测"边界另一侧"发生了什么。
2. **框架默认值是系统的一部分。** 同一个模型、同一个提示，两个 Agent 因为一个开发者可能从未看过的默认设置，引用格式表现差异巨大。
3. **把"格式"和"有无"分开测。** "没有我解析的格式"和"没有引用"是两种失败、两种修法，两个都要计数。
4. **读输出，不要只看指标。** "未引用答案数"这个指标掩盖了"大多数其实有来源"的事实。读 66 个答案改变了结论，而这件事本该在告诉别人数字之前做。
5. **跑不止一次。** 单次运行的剩余差距可能落在 −0.05 到 −0.16 之间；三次运行才显示它真实存在，而且比最初看起来更小。
6. **检索侧可以修格式。** 给 Agent 一个短的来源 ID 去复制，而不是一个长 URL 去重排，然后自己映射回来。

## 八、给做文档/RAG 产品的团队：一份最小验收清单

| 检查       | 怎么做                         | 通过标准                  |
| -------- | --------------------------- | --------------------- |
| 定义"引用存活" | 支持检查 + 溯源检查，两者缺一不可          | 每条引用都有被引块与工具调用日志佐证    |
| 测多框架     | 至少一个单次 RAG 对照 + 两个 Agent 框架 | 对照组的 CSR 作为基线         |
| 分开统计格式   | 同时统计"指定格式"和"任意格式"           | 两者差距 >0.05 时，先修格式再谈能力 |
| 重复运行     | 每种设置 ≥3 次                   | 符号一致，汇总区间不含 0         |
| 读失败样本    | 人工读完所有"未引用"答案               | 确认不是解析器盲点             |
| 服务端兜底    | 短来源 ID + 答案后映射              | 错格式显著下降，且不引入新错误       |
| 语料卫生     | 检查代码块/表格是否被切坏               | 被切坏的块要修，再谈指标          |

最后一条来自该系列第 5 篇的标题：**"在测 Agent 之前，先修你的语料"**——作者发现自己的块里有 20% 没有代码。基准的上限，往往由被测量的那堆文本决定。

---

**Sources**

- Ayan Arshad, *Your MCP Server Returns the Source. Does the Answer Still Cite It?*（系列 *Citations at the MCP Boundary* 第 1 篇），dev.to，2026-10-17：[https://dev.to/ayanarshad02/your-mcp-server-returns-the-source-does-the-answer-still-cite-it-26n8](https://dev.to/ayanarshad02/your-mcp-server-returns-the-source-does-the-answer-still-cite-it-26n8?ref=hubwiz.com)
- 基准仓库（trace 与全部数字）：[https://github.com/AyanArshad02/csr-mcp-benchmark](https://github.com/AyanArshad02/csr-mcp-benchmark?ref=hubwiz.com)

**相关阅读**：[RAG / 数据 / 文档智能完全指南](https://www.hubwiz.com/blog/rag-data-stack/) ｜ [Google Deep Review：文档核验流水线](https://www.hubwiz.com/blog/google-deep-review-document-verification/) ｜ [MCP 供应链体检：15,341 个服务器扫描](https://www.hubwiz.com/blog/mcp-registry-supply-chain-audit/)

本文由汇智网编译整理，转载请注明出处。文中数字为作者在其自建基准上的测量，适用边界见原文"Can you trust these numbers"一节。

> **这是「RAG / 数据 / 文档智能」专题的一部分。**完整地图见：[RAG / 数据 / 文档智能完全指南](https://www.hubwiz.com/blog/rag-data-stack/)