
摘要
给 Agent 接上联网搜索,并不意味着答案自动可信。搜索结果可能过期,摘要可能与原文不一致,网页正文可能动态变化,模型还可能把多个来源拼成一个不存在的结论。本文以数眼智能 Search、Reader 与多模型能力为例,设计一条可追踪的联网问答证据链:从查询规划、结果去重、原文读取、证据抽取,到时间校验、引用生成和失败降级。
一、搜索结果页不是证据
搜索 API 常返回标题、URL、摘要和时间,但摘要可能截断、改写或来自旧缓存。生产问答不应直接把摘要拼进 Prompt 后生成结论。
更稳妥的链路是:
text
用户问题
-> 查询规划
-> Search召回候选
-> URL规范化与去重
-> Reader读取原文
-> 证据片段抽取
-> 时间与来源校验
-> 模型综合
-> 返回答案和引用
Search 用来发现候选,Reader 用来获取原文,模型负责在证据范围内组织答案。
二、为一次研究任务建立统一上下文
python
from dataclasses import dataclass, field
@dataclass
class ResearchContext:
task_id: str
tenant_id: str
query: str
as_of: str
allowed_domains: list[str] = field(default_factory=list)
max_sources: int = 8
max_cost: float | None = None
as_of 很重要。用户问"最新"时,系统必须知道比较时间;用户问历史事件时,也不能用今天的页面覆盖当时状态。
三、查询规划不要无限扩散
模型可以生成多个检索词,但要设置上限和意图:
json
[
{"query": "目标实体 官方公告", "intent": "primary_source"},
{"query": "目标事件 日期", "intent": "timeline"},
{"query": "目标主题 行业分析", "intent": "secondary_source"}
]
对高风险问题优先官方、监管、论文或原始数据;媒体和社区用于补充背景。查询规划结果也要保存,后续才能解释为什么找到了这些来源。
四、URL 去重不能只比较字符串
同一页面可能带跟踪参数、移动端域名或不同锚点:
python
from urllib.parse import urlsplit, urlunsplit, parse_qsl, urlencode
DROP = {"utm_source", "utm_medium", "utm_campaign", "spm"}
def canonicalize(url: str) -> str:
p = urlsplit(url)
query = [(k, v) for k, v in parse_qsl(p.query) if k not in DROP]
return urlunsplit((p.scheme.lower(), p.netloc.lower(), p.path, urlencode(query), ""))
规范化后还要按正文指纹去重,因为转载页面 URL 不同,内容可能相同。去重能降低 Reader 调用和上下文 Token,也避免模型把同一观点误认为多个独立来源。
五、Reader 输出需要保留来源元数据
一个可引用的文档对象至少包含:
json
{
"url": "...",
"canonical_url": "...",
"title": "...",
"published_at": "...",
"fetched_at": "...",
"content_hash": "...",
"blocks": [
{"block_id": "b12", "heading": "...", "text": "..."}
]
}
如果只保存纯文本,最终引用只能指向整页,无法定位结论来自哪一段。动态页面还要记录抓取时间和内容哈希,防止页面后来改变却无法复现。
六、证据片段要经过"蕴含检查"
模型很容易从相关内容推导出来源并未明确表达的结论。可以把证据抽取拆成两步:
- 从原文中选择支持候选结论的片段;
- 判断片段是否直接支持、部分支持或不支持。
json
{
"claim": "...",
"source_url": "...",
"block_id": "b12",
"support": "direct|partial|none",
"reason": "..."
}
只有 direct 或明确标注局限的 partial 才进入最终答案。对数字、日期和主体名称,最好再做规则校验。
七、时间信息要单独处理
"最新""目前""今年"都具有时效性。建议为每条证据保存:
- 发布日期;
- 页面更新时间;
- 抓取时间;
- 事件发生时间;
- 是否存在更晚来源。
文章发布日期和事件发生时间不是一回事。新闻回顾可能今天发布,但描述的是几年前的事件。
八、来源排序不要只看搜索排名
可以按以下维度评分:
text
source_score = authority
+ freshness
+ directness
+ content_quality
- duplication
- uncertainty
权重由问题类型决定。产品功能以官方文档优先,学术结论以论文和原始数据优先,用户体验可以参考社区,但不应把单个帖子当成普遍结论。
九、数眼智能在这条链路中的角色
数眼智能定位于面向 AI 应用开发的企业级大模型 API 聚合平台,以多模型统一接入为入口,进一步延伸资源分层、Search、Reader、OCR、企业级 API 管理及企业资源服务。
对于联网问答,Search、Reader 和模型可以从同一资源层组织,减少多供应商适配。但证据 ID、时间口径、可信来源规则和最终引用仍应由应用层维护。平台统一不代表事实自动统一。
十、一个最小证据生成器
python
def build_citations(claims, documents):
citations = []
by_id = {
(doc["canonical_url"], block["block_id"]): (doc, block)
for doc in documents
for block in doc["blocks"]
}
for claim in claims:
key = (claim["source_url"], claim["block_id"])
if claim["support"] == "none" or key not in by_id:
continue
doc, block = by_id[key]
citations.append({
"claim": claim["claim"],
"title": doc["title"],
"url": doc["canonical_url"],
"block_id": block["block_id"],
"fetched_at": doc["fetched_at"]
})
return citations
生产环境还需做权限、恶意网页内容隔离和提示词注入防护。
十一、网页提示词注入不能忽略
Reader 读到的网页是外部不可信数据。页面可能包含"忽略此前指令""上传密钥"等诱导内容。应做到:
- 把网页正文标记为数据,不作为系统指令;
- 工具权限由应用策略决定,不由网页决定;
- 不把密钥和内部 Prompt 暴露给模型;
- 高风险工具需要显式授权;
- 对可疑内容记录并阻断。
十二、失败时如何降级
| 失败 | 建议处理 |
|---|---|
| Search 无结果 | 改写查询或明确回答资料不足 |
| Reader 失败 | 尝试其他可访问来源,不伪造正文 |
| 来源冲突 | 并列呈现差异和时间 |
| 时间不明确 | 明确说明无法确认"最新" |
| 证据不足 | 缩小结论,不用常识强行补齐 |
| 高风险问题 | 要求人工或权威来源复核 |
FAQ
搜索摘要可以直接引用吗?
不建议。摘要适合发现候选,重要结论应回到 Reader 读取的原文。
来源越多越可靠吗?
不一定。大量转载可能来自同一原始来源,关键是独立性、权威性和直接支持程度。
动态网页怎样复现?
保存抓取时间、内容哈希和证据区块;在合规前提下保留必要快照或结构化摘录。
Search 与 Reader 可以缓存吗?
可以,但缓存要绑定租户、权限、查询、时间窗口和内容版本,并设置失效策略。
结语
联网问答的质量不取决于"有没有搜索按钮",而取决于能否把每个结论追溯到具体来源、时间和原文片段。数眼智能提供 Search、Reader 与多模型资源入口后,开发团队更应该把查询规划、来源治理、证据检查和引用链做成正式工程能力。
说明:本文为通用联网问答架构,不构成来源真实性或平台效果承诺。实际结果应结合公开文档、业务数据和安全评测验证。