关于 citations-retrieval
Citations & Retrieval Skill 提供基于文档的引用与检索增强生成(RAG)实现指导,面向需要让 AI 回答可追溯、可核验的应用开发者。内容涵盖引用类型、检索流程、格式化与完整性验证。
主要功能
- 01支持文本、PDF 与内容块引用
- 02介绍基础 RAG 流程与上下文检索
- 03提供多文档问答模式
- 04说明学术引用格式化
- 05包含引用完整性验证建议
- 06涵盖文档分块与缓存实践
适用场景
- 01为文档问答添加来源标注
- 02构建基于文档的 RAG 应用
- 03核验回答引用是否对应原文
- 04整理多文档研究答案
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ thelobbi/ claude --skill citations-retrieval安装后在 Claude Code 中输入/citations-retrieval确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
OUTLINE.mdQUICK-REFERENCE.mdREADME.mdRESEARCH-SUMMARY.md详细介绍
引用与检索技能
实现基于文档的引用和 RAG 模式,生成有依据、可验证的 AI 响应。
何时使用此技能
- 带来源归属的文档问答
- RAG(检索增强生成)系统
- 基于所提供文档生成有依据的响应
- 构建值得信赖的 AI 应用
- 带引用的研究与分析
核心概念
引用类型
| 类型 | 用途 | 格式 |
|---|---|---|
char_location | 文本文档 | 字符范围 |
page_location | 页码 | |
content_block_location | 自定义内容 | 内容块索引 |
基本引用
启用引用
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
documents=[
{
"type": "document",
"source": {
"type": "text",
"media_type": "text/plain",
"data": "The company was founded in 2020. Revenue reached $10M in 2023."
},
"title": "Company Overview",
"citations": {"enabled": True} # Enable citations!
}
],
messages=[{"role": "user", "content": "When was the company founded and what was the revenue?"}]
)
# Extract citations from response
for block in response.content:
if block.type == "text":
for citation in block.citations:
print(f"Cited: {citation.document_title}")
print(f"Location: chars {citation.start_char_index}-{citation.end_char_index}")
自定义内容块
# Fine-grained control over citation granularity
documents = [{
"type": "document",
"source": {
"type": "content",
"content": [
{"type": "text", "text": "Section 1: Introduction..."},
{"type": "text", "text": "Section 2: Methods..."},
{"type": "text", "text": "Section 3: Results..."}
]
},
"title": "Research Paper",
"citations": {"enabled": True}
}]
RAG 实现
基本 RAG 流水线
from sentence_transformers import SentenceTransformer
import numpy as np
# 1. Embed documents
embedder = SentenceTransformer('all-MiniLM-L6-v2')
def embed_documents(documents):
chunks = []
embeddings = []
for doc in documents:
# Chunk the document
doc_chunks = chunk_document(doc, chunk_size=512)
chunks.extend(doc_chunks)
embeddings.extend(embedder.encode(doc_chunks))
return chunks, np.array(embeddings)
# 2. Retrieve relevant chunks
def retrieve(query, chunks, embeddings, top_k=5):
query_embedding = embedder.encode([query])[0]
similarities = np.dot(embeddings, query_embedding)
top_indices = np.argsort(similarities)[-top_k:][::-1]
return [chunks[i] for i in top_indices]
# 3. Generate with retrieved context
def rag_query(query, chunks, embeddings):
relevant_chunks = retrieve(query, chunks, embeddings)
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
documents=[{
"type": "document",
"source": {"type": "text", "media_type": "text/plain", "data": chunk},
"title": f"Source {i+1}",
"citations": {"enabled": True}
} for i, chunk in enumerate(relevant_chunks)],
messages=[{"role": "user", "content": query}]
)
return response
上下文检索(效果提升 49-67%)
# Add context to each chunk before embedding
def add_chunk_context(chunk, full_document):
"""Prepend context to improve retrieval accuracy by 49-67%"""
context_prompt = f"""<document>
{full_document}
</document>
Please provide a short, succinct context for this chunk that will help with retrieval:
<chunk>
{chunk}
</chunk>
Context:"""
response = client.messages.create(
model="claude-haiku-4-5", # Fast, cheap
max_tokens=100,
messages=[{"role": "user", "content": context_prompt}]
)
context = response.content[0].text
return f"{context}\n\n{chunk}"
# Apply to all chunks
contextual_chunks = [add_chunk_context(chunk, full_doc) for chunk in chunks]
引用格式
格式化为编号参考文献
def format_with_citations(response):
"""Format response with numbered inline citations"""
text = ""
citations = []
citation_map = {}
for block in response.content:
if block.type == "text":
current_text = block.text
for citation in block.citations:
key = (citation.document_title, citation.start_char_index)
if key not in citation_map:
citation_map[key] = len(citations) + 1
citations.append(citation)
# Insert citation number
ref_num = citation_map[key]
current_text += f" [{ref_num}]"
text += current_text
# Add references section
text += "\n\n## References\n"
for i, citation in enumerate(citations, 1):
text += f"[{i}] {citation.document_title}\n"
return text
学术引用格式
def format_apa(author, year, title, source):
"""APA format: Author (Year). Title. Source."""
return f"{author} ({year}). {title}. {source}."
def format_mla(author, title, source, year):
"""MLA format: Author. "Title." Source, Year."""
return f'{author}. "{title}." {source}, {year}.'
def format_chicago(author, title, source, year):
"""Chicago format: Author. Title. Source, Year."""
return f"{author}. {title}. {source}, {year}."
多文档问答
def multi_doc_qa(question, documents):
"""Answer questions across multiple documents with citations"""
doc_inputs = []
for i, doc in enumerate(documents):
doc_inputs.append({
"type": "document",
"source": {
"type": "text",
"media_type": "text/plain",
"data": doc["content"]
},
"title": doc.get("title", f"Document {i+1}"),
"citations": {"enabled": True}
})
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=2048,
documents=doc_inputs,
messages=[{
"role": "user",
"content": f"Answer this question based on the provided documents. Cite your sources.\n\nQuestion: {question}"
}]
)
return response
RAG 的提示词缓存
# Cache static documents for repeated queries
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
documents=[{
"type": "document",
"source": {"type": "text", "media_type": "text/plain", "data": large_document},
"title": "Knowledge Base",
"citations": {"enabled": True},
"cache_control": {"type": "ephemeral"} # Cache this document!
}],
messages=[{"role": "user", "content": query}]
)
错误处理与验证
验证引用完整性
def validate_citations(response, documents):
"""Ensure all citations reference provided documents"""
cited_titles = set()
for block in response.content:
if block.type == "text":
for citation in block.citations:
cited_titles.add(citation.document_title)
provided_titles = {doc.get("title") for doc in documents}
# Check for invalid citations
invalid = cited_titles - provided_titles
if invalid:
raise ValueError(f"Citations reference unknown documents: {invalid}")
return True
def extract_citation_spans(response):
"""Extract text spans for each citation"""
citation_data = []
for block in response.content:
if block.type == "text":
text = block.text
for citation in block.citations:
span = text[citation.start_char_index:citation.end_char_index]
citation_data.append({
"text": span,
"document": citation.document_title,
"start": citation.start_char_index,
"end": citation.end_char_index
})
return citation_data
最佳实践
应做:
- 为所有基于文档的查询启用引用
- 使用上下文检索提高准确性(+49-67%)
- 使用 cache_control 缓存静态文档
- 为文档提供清晰的标题以标明来源
- 适当拆分文档(512-1024 个 token)
- 使用响应前验证引用完整性
- 统一引用格式(APA、MLA、Chicago)
- 在生产系统中测试引用提取
不应做:
- 未启用引用就依赖引用
- 使用过小的分块(<100 个 token)
- 忽略生产环境中的引用验证
- 跳过文档预处理
- 在同一文档中混用引用格式
- 假设所有大模型响应默认都带引用
- 未进行引用验证测试就部署
故障排除
未返回引用
# Ensure citations are enabled
documents = [{
"type": "document",
"source": {"type": "text", "media_type": "text/plain", "data": content},
"citations": {"enabled": True} # Must be explicit!
}]
引用指向了错误的文本
# Verify character indexes match actual text
text = block.text
cited_text = text[citation.start_char_index:citation.end_char_index]
print(f"Cited text: {cited_text}")
print(f"Expected: {expected_text}")
大型文档的性能
# Use chunking for large documents
def chunk_with_overlap(text, chunk_size=1024, overlap=256):
chunks = []
for i in range(0, len(text), chunk_size - overlap):
chunks.append(text[i:i + chunk_size])
return chunks
# Pass chunks individually for better retrieval
large_chunks = chunk_with_overlap(large_text)
集成示例
#!/usr/bin/env python3
"""Complete RAG + Citations example"""
import anthropic
from sentence_transformers import SentenceTransformer
import numpy as np
def create_rag_system():
"""Initialize RAG system with citations"""
client = anthropic.Anthropic()
embedder = SentenceTransformer('all-MiniLM-L6-v2')
# Sample documents
documents = [
{
"title": "Python Guide",
"content": "Python 3.11 introduced exception groups..."
},
{
"title": "Web Standards",
"content": "HTTP/2 introduced multiplexing capabilities..."
}
]
# Embed documents
chunks = []
embeddings = []
for doc in documents:
# Add document title as context
chunk = f"[{doc['title']}]\n{doc['content']}"
chunks.append(chunk)
embeddings.append(embedder.encode(chunk))
embeddings = np.array(embeddings)
# Query function
def query(question):
# Retrieve relevant chunks
query_emb = embedder.encode(question)
similarities = np.dot(embeddings, query_emb)
top_idx = np.argmax(similarities)
relevant_chunk = chunks[top_idx]
# Get cited answer
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
documents=[{
"type": "document",
"source": {
"type": "text",
"media_type": "text/plain",
"data": relevant_chunk
},
"title": documents[top_idx]["title"],
"citations": {"enabled": True}
}],
messages=[{
"role": "user",
"content": question
}]
)
return response
return query
if __name__ == "__main__":
query_fn = create_rag_system()
response = query_fn("What is Python 3.11?")
# Display with citations
for block in response.content:
if block.type == "text":
print(f"Answer: {block.text}")
for citation in block.citations:
print(f" - Cited from: {citation.document_title}")
性能提示
- 批量处理查询以提高吞吐量(10-20 个并发请求)
- 使用提示词缓存缓存常用文档
- 使用 Haiku 生成上下文(更快、更省钱)
- 策略性地拆分内容(按句子/段落边界)
- 监控 token 用量以了解引用开销(约 5-10%)
限制
- 引用仅来自所提供的文档
- 字符索引引用要求文本完全匹配
- PDF 支持需要结构化解析
- 提取引用会消耗 token(约 5-10% 的开销)
- 不支持对带引用的响应执行批处理操作
另请参阅
- [[llm-integration]] - API 基础知识与身份验证
- [[prompt-caching]] - 缓存文档以节省成本
- [[vision-multimodal]] - PDF 和图像处理
- [[complex-reasoning]] - 带引用的扩展思考
评论
支持 Markdown