Project Icon

paper-qa

基于文档的智能问答系统 实现精准信息检索和回答生成

paper-qa是一款轻量级文档问答工具包,专门从PDF和文本文件中提取信息并生成回答。通过文档嵌入、向量搜索和摘要生成等技术,结合大型语言模型,paper-qa能够提供高质量且有据可依的回答。支持OpenAI、Anthropic等多种嵌入和语言模型,并可集成本地托管模型。工具提供异步API,支持自定义文档添加和引用格式推断,还可整合外部向量存储。这些特性使paper-qa成为科研和信息检索领域的实用解决方案。

PaperQA

GitHub tests PyPI version

这是一个用于对PDF或文本文件(可以是原始HTML)进行问答的简洁软件包。它致力于通过在文本中引用来源,提供非常优质的答案,避免产生幻觉。

默认情况下,它使用OpenAI Embeddings和一个简单的numpy向量数据库来嵌入和搜索文档。然而,通过langchain,你也可以使用开源模型或嵌入(详情见下文)。

paper-qa使用以下流程:

  1. 将文档嵌入为向量
  2. 将查询嵌入为向量
  3. 在文档中搜索前k个相关段落
  4. 为每个与查询相关的段落创建摘要
  5. 使用LLM重新评分并仅选择相关摘要
  6. 将摘要放入提示中
  7. 用提示生成答案

更多详情请参阅我们的论文:

@article{lala2023paperqa,
  title={PaperQA: Retrieval-Augmented Generative Agent for Scientific Research},
  author={L{\'a}la, Jakub and O'Donoghue, Odhran and Shtedritski, Aleksandar and Cox, Sam and Rodriques, Samuel G and White, Andrew D},
  journal={arXiv preprint arXiv:2312.07559},
  year={2023}
}

输出示例

问题:如何大规模制造碳纳米管?

碳纳米管可以使用电弧技术进行大规模制造(Journet6644)。这种技术涉及在氦气氛围的反应器中,在两个电极之间产生电弧,并在阳极中使用金属催化剂和石墨粉的混合物。这种方法可以获得80%的缠绕碳纤维产率,这些纤维由较小的对齐单壁碳纳米管(SWNTs)自组装成束状晶体(Journet6644)。此外,碳纳米管还可以通过各种方法合成和自组装,如DNA介导的自组装、纳米颗粒辅助对齐、化学自组装和电寻址功能化(Tulevski2007)。这些方法已被用于制造大面积纳米结构阵列、高密度集成和自立网络(Tulevski2007)。还可以使用98%的半导体碳纳米管网络溶液,该溶液通过密度梯度超离心方法从金属纳米管中分离出来(Chen2014)。将基板浸入溶液中,然后用去离子水冲洗并用N2气枪吹干,留下均匀的碳网络(Chen2014)。

参考文献

Journet6644: Journet, Catherine, et al. "Large-scale production of single-walled carbon nanotubes by the electric-arc technique." nature 388.6644 (1997): 756-758.

Tulevski2007: Tulevski, George S., et al. "Chemically assisted directed assembly of carbon nanotubes for the fabrication of large-scale device arrays." Journal of the American Chemical Society 129.39 (2007): 11964-11968.

Chen2014: Chen, Haitian, et al. "Large-scale complementary macroelectronics using hybrid integration of carbon nanotubes and IGZO thin-film transistors." Nature communications 5.1 (2014): 4097.

最新更新

版本4移除了langchain包,因为它不再支持序列化。这也简化了软件包,特别是提示部分。Langchain仍然可以使用,但不是必需的。你可以使用langchain中的任何LLMs,但需要使用LangchainLLMModel类来包装模型。

安装

使用pip安装:

pip install paper-qa

你需要有一个LLM来使用paper-qa。你可以使用OpenAI、llama.cpp(通过服务器)或langchain中的任何LLMs。只要你设置了OpenAI API密钥(export OPENAI_API_KEY=sk-...),OpenAI就可以直接使用。其他LLMs的使用说明见下文。

使用方法

要使用paper-qa,你需要有一个路径/文件/URL列表(有效扩展名包括:.pdf, .txt)。然后你可以使用Docs类来添加文档并进行查询。Docs会尝试从文件内容中猜测引用格式,但你也可以自己提供。

from paperqa import Docs

my_docs = ...  # 获取路径列表

docs = Docs()
for d in my_docs:
    docs.add(d)

answer = docs.query(
    "双特异性抗体制造面临哪些独特的挑战?"
)
print(answer.formatted_answer)

answer对象具有以下属性:formatted_answeranswer(仅答案)、questioncontext(用于回答的段落摘要)。

异步

paper-qa被设计为异步使用。同步API只是异步的包装器。以下是方法及其异步等效项:

同步异步
Docs.addDocs.aadd
Docs.add_fileDocs.aadd_file
Docs.add_urlDocs.aadd_url
Docs.get_evidenceDocs.aget_evidence
Docs.queryDocs.aquery

同步版本只是在循环中调用异步版本。大多数现代Python环境原生支持异步(包括Jupyter笔记本!)。因此,你可以在Jupyter笔记本中这样做:

from paperqa import Docs

my_docs = ...  # 获取路径列表

docs = Docs()
for d in my_docs:
    await docs.aadd(d)

answer = await docs.aquery(
    "双特异性抗体制造面临哪些独特的挑战?"
)

添加文档

add将从路径添加。你也可以使用add_file(需要一个文件对象)或add_url来处理其他来源。

选择模型

默认情况下,它使用OpenAI模型,结合了gpt-4o-mini(用于重新排序和摘要步骤,summary_llm参数)和gpt-4-turbo(用于回答步骤,llm参数)。你可以调整这个设置:

docs = Docs(llm="gpt-4o-mini", summary_llm="gpt-4o")

你可以通过指定Anthropic客户端来使用Anthropic模型:

from paperqa import Docs
from anthropic import AsyncAnthropic

docs = Docs(
    llm="claude-3-5-sonnet-20240620",
    summary_llm="claude-3-5-sonnet-20240620",
    client=AsyncAnthropic(),
)

或者你可以使用langchain中可用的任何其他模型:

from paperqa import Docs
from langchain_community.chat_models import ChatAnthropic

docs = Docs(llm="langchain", client=ChatAnthropic())

注意,我们将模型分为包装器和client,这里的clientChatAnthropic。这是因为client存储了不可序列化的部分,而langchain LLMs有时只能序列化/序列化。paper-qa的Docs必须始终可序列化。因此,我们将模型分为两部分。

import pickle

docs = Docs(llm="langchain", client=ChatAnthropic())
model_str = pickle.dumps(docs)
docs = pickle.loads(model_str)
# 但你必须在加载后设置客户端
docs.set_client(ChatAnthropic())

我们还支持使用Anyscale来利用托管的开源模型。要使用它,你只需设置ANYSCALE_API_KEYANYSCALE_BASE_URL环境变量,或使用从Anyscale初始化的OpenAI客户端,并提供api_keybase_url参数。

本地托管

你可以使用llama.cpp作为LLM。请注意,你应该使用相对较大的模型,因为paper-qa需要遵循很多指令。7B模型的性能不会很好。

最简单的设置方法是下载一个llama文件并用-cb -np 4 -a my-llm-model --embedding执行它,这将启用连续批处理和嵌入。

from paperqa import Docs, LlamaEmbeddingModel
from openai import AsyncOpenAI

# 启动llama.cpp客户端

local_client = AsyncOpenAI(
    base_url="http://localhost:8080/v1", api_key="sk-no-key-required"
)

docs = Docs(
    client=local_client,
    docs_index=NumpyVectorStore(embedding_model=LlamaEmbeddingModel()),
    texts_index=NumpyVectorStore(embedding_model=LlamaEmbeddingModel()),
    llm_model=OpenAILLMModel(
        config=dict(
            model="my-llm-model", temperature=0.1, frequency_penalty=1.5, max_tokens=512
        )
    ),
)

更改嵌入模型

paper-qa默认使用OpenAI(text-embedding-3-small)嵌入,但对向量存储和嵌入选择都有灵活的选项。更改嵌入的最简单方法是通过Docs对象构造函数的embedding参数:

from paperqa import Docs

docs = Docs(embedding="text-embedding-3-large")

embedding接受:

  • 任何OpenAI嵌入模型名称
  • VoyageAI模型名称(如果安装了voyageai并设置了VOYAGE_API_KEY可用)
  • "sentence-transformers"使用Sentence Transformersmulti-qa-MiniLM-L6-cos-v1
  • "hybrid-<model_name>",例如"hybrid-text-embedding-3-small"使用混合稀疏关键词(基于令牌模数嵌入)和密集向量嵌入,任何OpenAI或VoyageAI模型都可以用作密集模型名称
  • "sparse"仅使用稀疏关键词嵌入

对于更深入的嵌入自定义,可以单独构建嵌入模型和向量存储,然后传递给Docs对象。嵌入模型用于创建paper-qa的文档引用嵌入向量索引(docs_index参数)以及全文嵌入向量(texts_index参数)。在创建新的Docs对象时,可以将它们都指定为参数。你可以使用任何实现paper-qa的EmbeddingModel类的嵌入模型。例如,使用text-embedding-3-large

from paperqa import Docs, NumpyVectorStore, OpenAIEmbeddingModel

docs = Docs(
    docs_index=NumpyVectorStore(
        embedding_model=OpenAIEmbeddingModel(name="text-embedding-3-large")
    ),
    texts_index=NumpyVectorStore(
        embedding_model=OpenAIEmbeddingModel(name="text-embedding-3-large")
    ),
)

请注意,嵌入模型被指定为paper-qa的VectorStore基类的属性。NumpyVectorStore是最好的起点,它是一个简单的内存存储,没有索引。如果需要大于内存的向量存储,你可以这样使用LangchainVectorStore

from langchain_community.vectorstores.faiss import FAISS
from langchain_openai import OpenAIEmbeddings
from paperqa import Docs, LangchainVectorStore

docs = Docs(
    docs_index=LangchainVectorStore(cls=FAISS, embedding_model=OpenAIEmbeddings()),
    texts_index=LangchainVectorStore(cls=FAISS, embedding_model=OpenAIEmbeddings()),
)

我们支持本地langchain嵌入模型和SentenceTransformer模型。例如:

from paperqa import Docs, SentenceTransformerEmbeddingModel
from openai import AsyncOpenAI

# 启动llama.cpp客户端

local_client = AsyncOpenAI(
    base_url="http://localhost:8080/v1", api_key="sk-no-key-required"
)

docs = Docs(
    client=local_client,
    docs_index=NumpyVectorStore(embedding_model=SentenceTransformerEmbeddingModel()),
    texts_index=NumpyVectorStore(embedding_model=SentenceTransformerEmbeddingModel()),
    llm_model=OpenAILLMModel(
        config=dict(
            model="my-llm-model", temperature=0.1, frequency_penalty=1.5, max_tokens=512
        )
    ),
)

我们还支持混合关键词(稀疏令牌模数向量)和密集嵌入向量。它们可以这样指定:

from paperqa import Docs, HybridEmbeddingModel, SparseEmbeddingModel, NumpyVectorStore

model = HybridEmbeddingModel(models=[OpenAIEmbeddingModel(), SparseEmbeddingModel()])
docs = Docs(
    docs_index=NumpyVectorStore(embedding_model=model),
    texts_index=NumpyVectorStore(embedding_model=model),
)

稀疏嵌入(关键词)模型默认有256个维度,但可以通过ndim参数指定。

调整源数量

你可以调整源(文本段落)的数量以减少令牌使用或添加更多上下文。k指的是最相关和多样化(可能来自不同源)的前k个段落。每个段落都会被发送给LLM进行总结,或确定是否无关。在此步骤之后,应用max_sources限制,以便最终答案能够适应LLM上下文窗口。因此,k > max_sources,而max_sources是最终答案中使用的源数量。

docs.query(
    "双特异性抗体特有的制造挑战是什么?",
    k=5,
    max_sources=2,
)

使用代码或HTML

你不需要使用论文 - 你可以使用代码或原始HTML。请注意,这个工具专注于回答问题,所以它在编写代码方面表现不佳。需要注意的是,该工具无法从代码中推断引用,所以你需要自己提供它们。

import glob

source_files = glob.glob("**/*.js")

docs = Docs()
for f in source_files:
    # 这假设代码中的文件名是唯一的
    docs.add(f, citation="文件 " + os.path.name(f), docname=os.path.name(f))
answer = docs.query("页眉中的搜索栏在哪里定义?")
print(answer)

使用外部数据库/向量数据库和缓存

你可能想在外部数据库或文件中缓存解析的文本和嵌入。然后你可以直接从这些构建Docs对象:

docs = Docs()

for ... in my_docs:
    doc = Doc(docname=..., citation=..., dockey=..., citation=...)
    texts = [Text(text=..., name=..., doc=doc) for ... in my_texts]
    docs.add_texts(texts, doc)

如果你想使用外部向量存储,也可以通过langchain直接实现。例如,使用langchain的FAISS向量存储:

from paperqa import LangchainVectorStore, Docs
from langchain_community.vector_store import FAISS
from langchain_openai import OpenAIEmbeddings

docs = Docs(
    texts_index=LangchainVectorStore(cls=FAISS, embedding_model=OpenAIEmbeddings()),
    docs_index=LangchainVectorStore(cls=FAISS, embedding_model=OpenAIEmbeddings()),
)

我从哪里获取论文?

这是一个很好的问题!最好的方法可能是下载你认为有助于回答问题的论文的PDF,然后从那里开始。

Zotero

如果你使用Zotero来组织你的个人参考文献,你可以使用paperqa.contrib.ZoteroDB从你的库中查询论文,它依赖于pyzotero

安装pyzotero以使用此功能:

pip install pyzotero

首先,请注意paperqa解析论文的PDF以存储在数据库中,所以所有相关论文都应该在你的数据库中存储PDF。你可以让Zotero自动执行此操作,方法是高亮显示你想检索的参考文献,右键单击,然后选择"查找可用的PDF"。你也可以手动将PDF拖放到每个参考文献上。

要下载论文,你需要获取你账户的API密钥。

  1. 获取您的图书馆ID,并将其设置为环境变量 ZOTERO_USER_ID
    • 对于个人图书馆,该ID可在此处找到,位于"您在API调用中使用的userID为XXXXXX"部分。
    • 对于群组图书馆,请访问您的群组页面 https://www.zotero.org/groups/groupname,将鼠标悬停在设置链接上。ID是/groups/后的整数。(感谢pyzotero提供的提示!)
  2. 此处创建一个新的API密钥,并将其设置为环境变量 ZOTERO_API_KEY
    • 该密钥需要对图书馆有读取权限。

有了这些,我们就可以从我们的图书馆下载论文并将它们添加到 paperqa 中:

from paperqa.contrib import ZoteroDB

docs = paperqa.Docs()
zotero = ZoteroDB(library_type="user")  # 如果是群组图书馆,则为"group"

for item in zotero.iterate(limit=20):
    if item.num_pages > 30:
        continue  # 跳过长篇论文
    docs.add(item.pdf, docname=item.key)

这将下载Zotero数据库中的前20篇论文并将它们添加到 Docs 对象中。

我们还可以对Zotero图书馆进行特定查询并遍历结果:

for item in zotero.iterate(
    q="large language models",
    qmode="everything",
    sort="date",
    direction="desc",
    limit=100,
):
    print("正在添加", item.title)
    docs.add(item.pdf, docname=item.key)

您可以在IPython中输入 zotero.iterate? 以了解更多关于搜索语法的信息。

论文抓取器

如果您想搜索自己收藏之外的论文,我发现了一个名为paper-scraper的无关项目,看起来可能会有帮助。但请注意,该项目似乎使用了一些可能违反出版商权利或处于法律灰色地带的抓取工具。

keyword_search = "bispecific antibody manufacture"
papers = paperscraper.search_papers(keyword_search)
docs = paperqa.Docs()
for path, data in papers.items():
    try:
        docs.add(path)
    except ValueError as e:
        # 有时如果PDF未下载或无法读取会发生这种情况
        print("无法读取", path, e)
answer = docs.query(
    "双特异性抗体制造有哪些独特的挑战?"
)
print(answer)

PDF阅读选项

默认情况下使用PyPDF,因为它是纯Python实现且易于安装。为了更快的PDF阅读,paper-qa会检测并使用PymuPDF (fitz)

pip install pymupdf

回调工厂

要在LLM完成的每个块上执行函数,您需要提供一个函数,该函数在被调用时会根据步骤名称生成要在每个块上执行的函数列表。例如,要获得完成内容的打字机视图,您可以这样做:

def make_typewriter(step_name):
    def typewriter(chunk):
        print(chunk, end="")

    return [typewriter]  # <- 注意这是一个函数列表


...
docs.query(
    "双特异性抗体制造有哪些独特的挑战?",
    get_callbacks=make_typewriter,
)

缓存嵌入

通常,无论您使用什么向量存储,当您pickle一个 Docs 时,嵌入都会被缓存。有关更明确管理它们的详细信息,请参见上文。

自定义提示

您可以使用 PromptCollection 类自定义任何提示。例如,如果您想更改问题的提示,可以这样做:

from paperqa import Docs, Answer, PromptCollection

my_qaprompt = (
    "回答问题'{question}' "
    "如果有帮助,请使用下面的上下文。"
    "您可以使用键来引用上下文 "
    "例如(Example2012)。"
    "如果上下文不足,请写一首诗 "
    "描述您无法回答的情况。\n\n"
    "上下文:{context}\n\n"
)
prompts = PromptCollection(qa=my_qaprompt)
docs = Docs(prompts=prompts)

前置和后置提示

按照上面的语法,您还可以包含在查询之前和之后执行的提示。例如,您可以使用它来对答案进行评论。

常见问题

这与LlamaIndex有何不同?

它并没有太大的不同!这类似于LlamaIndex中的树响应方法。我只是包含了一些我认为有用的提示,能提供页码/行号的阅读器,并专注于一个任务 - 用引用源回答技术问题。

这与LangChain有何不同?

LangChain在检索器方面做了一些很棒的工作,你可以说这是一个基于LLM重新排序和上下文摘要的检索器的例子。

我可以保存或加载吗?

Docs 类可以被pickle和unpickle。如果您想保存文档的嵌入,然后稍后加载它们,这会很有用。

import pickle

# 保存
with open("my_docs.pkl", "wb") as f:
    pickle.dump(docs, f)

# 加载
with open("my_docs.pkl", "rb") as f:
    docs = pickle.load(f)

docs.set_client()  # 默认使用OpenAI
项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

白日梦AI

白日梦AI提供专注于AI视频生成的多样化功能,包括文生视频、动态画面和形象生成等,帮助用户快速上手,创造专业级内容。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

讯飞绘镜

讯飞绘镜是一个支持从创意到完整视频创作的智能平台,用户可以快速生成视频素材并创作独特的音乐视频和故事。平台提供多样化的主题和精选作品,帮助用户探索创意灵感。

Project Cover

讯飞文书

讯飞文书依托讯飞星火大模型,为文书写作者提供从素材筹备到稿件撰写及审稿的全程支持。通过录音智记和以稿写稿等功能,满足事务性工作的高频需求,帮助撰稿人节省精力,提高效率,优化工作与生活。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号