带有 Web 搜索的 RAG

2025-06-07

带有 Web 搜索的 RAG

检索增强生成 (RAG) 是一种将现有或专有数据与大型语言模型 (LLM) 结合使用的常用方法。许多文章描述了如何执行 RAG。通常,它们涉及将数据编码为向量,并将向量存储在数据库中。查询数据库,并将数据置于上下文中,并在其中进行标记化(转换为向量),同时将提示符发送到 LLM。简而言之,RAG 就是将数据放入提示符中,供 LLM 处理。

从实际意义上讲,互联网就是世界的数据库,我们可以使用搜索引擎进行查询,因为搜索引擎拥有返回相关结果的方法。听起来很熟悉?我们可以利用搜索功能来驱动 RAG 应用程序。

在这个例子中,我们将使用 DuckDuckGo 进行搜索,使用 Langchain 检索网页并处理数据,并选择具有开源 LLM 的 Ollama 或像 OpenAI 这样的 LLM 服务。

对于没有耐心的人,代码

首先,将包导入到您的环境中。



pip install -r requirements.txt


Enter fullscreen mode Exit fullscreen mode

让我们深入研究代码!查询 DuckDuckGo、检索网页以及格式化以插入提示都由这三个函数完成。ddg_search函数查询 DuckDuckGo。get_page函数使用 Langchain 的文档加载器从搜索中检索页面,仅提取p带有 的 HTML 标签之间的文本,并返回 Langchain文档BeautifulSoupTransformer列表

ddg_search函数从文档中提取文本并截断它们,以确保它们适合LLM的上下文窗口。最近的LLM具有更大的上下文窗口,您可以通过更改值来更改截断量和截断位置。例如,您可能希望捕获文本的结尾,其中包括结论和摘要。每个文档中处理后的文本将以列表形式返回。



def ddg_search(query):
    results = DDGS().text(query, max_results=5)
    print(results)
    urls = []
    for result in results:
        url = result['href']
        urls.append(url)

    docs = get_page(urls)

    content = []
    for doc in docs:
        page_text = re.sub("\n\n+", "\n", doc.page_content)
        text = truncate(page_text)
        content.append(text)

    return content

def get_page(urls):
    loader = AsyncChromiumLoader(urls)
    html = loader.load()

    bs_transformer = BeautifulSoupTransformer()
    docs_transformed = bs_transformer.transform_documents(html, tags_to_extract=["p"], remove_unwanted_tags=["a"])

    return docs_transformed

def truncate(text):
    words = text.split()
    truncated = " ".join(words[:400])

    return truncated 


Enter fullscreen mode Exit fullscreen mode

以下部分将创建一个提示。目前,没有标准的提示格式,每个 LLM 都实现了自己的提示格式。以下部分演示了如何为 llama2 或 llama3 LLM 以及 OpenAI LLM 创建提示。请注意其prompt构造有何不同。



def create_prompt_ollama(llm_query, search_results):
    content_start = (
        "Answer the question using only the context below.\n\n"+
        "Context:\n"
    )

    content_end = (
        f"\n\nQuestion: {llm_query}\nAnswer:"
    )

    content = (
        content_start + "\n\n---\n\n".join(search_results) + 
        content_end
    )

    prompt = [{'role': 'user', 'content': content }]

    return prompt

def create_prompt_openai(llm_request, search_results):
    prompt_start = (
        "Answer the question using only the context below.\n\n"+
        "Context:\n"
    )

    prompt_end = (
        f"\n\nQuestion: {llm_request}\nAnswer:"
    )

    prompt = (
        prompt_start + "\n\n---\n\n".join(search_results) + 
        prompt_end
    )

    return prompt


Enter fullscreen mode Exit fullscreen mode

为每个 LLM 创建完成(或响应)也不同。



# use ollama with llama3 foundation model
def create_completion_ollama(prompt):
    completion = ollama.chat(model='llama3', messages=prompt)

    return completion['message']['content']

# use openai's foundation models
def create_completion_openai(prompt):
    res = client.completions.create(
        model="gpt-3.5-turbo-instruct",
        prompt=prompt,
        temperature=0,
        max_tokens=1000,
        top_p=1,
        frequency_penalty=0,
        presence_penalty=0,
        stop=None
    )

    return res.choices[0].text


Enter fullscreen mode Exit fullscreen mode

该应用程序使用 Streamlit 搜索 DuckDuckGo,将结果发送给 LLM,并显示完成情况。



# ui
with st.form("prompt_form"):
    result =""
    prompt = ""
    search_query = st.text_area("DuckDuckGo search:", None)
    llm_query = st.text_area("LLM prompt:", None)
    submitted = st.form_submit_button("Send")
    if submitted:
        search_results = ddg_search(search_query)
        # prompt = create_prompt_ollama(llm_query,search_results)
        # result = create_completion_ollama(prompt)
        prompt = create_prompt_openai(llm_query,search_results)
        result = create_completion_openai(prompt)

    e = st.expander("LLM prompt created:")
    e.write(prompt)
    st.write(result)


Enter fullscreen mode Exit fullscreen mode

这是一个使用 OpenAI 的 GPT3.5 对泰勒·斯威夫特的新专辑《Tortured Poets Department》进行评价的示例查询。哎哟!有点苛刻。

RAG 网络搜索 UI

思考

这可以改进吗?当然!大多数搜索引擎都支持搜索特定站点或排除站点的操作符。例如,搜索 Kubernetes 的容器网络接口 (CNI) 时,可以将其限制在 kubernetes.io,而不是所有其他涉及 CNI 的站点。BeautifulSoupTransformer 支持按标签提取或排除文本,并且truncate可以扩展该功能以从某些部分(例如结论和摘要所在的末尾)提取文本。您还可以将 LLM 从通用聊天模型更改为指导模型,并将其用作编码助手。

拥有法学硕士学位的学生可以使用网页搜索功能,从而获得更精准的搜索结果和摘要。请务必查看Github上的代码。

文章来源:https://dev.to/spara_50/rag-with-web-search-2c3e
PREV
如何使用 Express 在 Node.js 中配置 CORS
NEXT
零知识证明编码入门