关于使用本地部署deepseek结合联网搜索的尝试说明

0.先说结论

标题这个做法在有插件的帮助下成功了,在没有插件帮助的情况下没有成功。

但转变为使用Deepseek的API后不使用插件也成功了。

了解了一些关于smolagents的东西

启发文章:微信公众平台

1.个人尝试

先是使用了ollama下的本地deepseek-r1:1.5b 尝试给它加上联网功能,用网上的Page Assist套件很快成功了。且使用国内网络可以访问

以上做法的参考文章:本地Deepseek添加个人知识库(Page Assist/AnythingLLM)_deepseek知识库-CSDN博客

之后尝试离开web插件,在本地终端能否使用联网的方法

找了一阵,大致有几种联网的工具可以使用, Bing API、 Google API、 DuckDuckGO可供使用

其中,Bing API 申请API Key那里有点问题,怎么搞都申请不下来,不知道是不是操作的问题

Google API 需要付费,且需要国外代理才能使用,优先级最低

DuckDuckGo是免费的联网工具,虽然也需要代理,但简单易用,不用申请API,

问题来了,DDG要国外代理,ollama serve只要一遇到国外代理就会request 502 显示 积极拒绝连接 直接水火不相容了

所以解决办法要么是把DDG弄成国内网络能访问,或者寻找国内平替还是镜像之类的(没找到)要么是将ollama serve和代理不相容的问题解决,使得在开代理的情况下,ollama serve也能使用服务。

网上有一个关于以上问题的解决办法,个人使用后没有解决这个问题,贴下来供与参考:解决ollama在开启系统代理后无法访问的问题 | 天澄拾光

主要这个方法好像属于linux那边的范畴,不太懂怎么用,搜索类似问题就按着这个关键词搜索就行。

以下开始第二种尝试了,上面那条路子就走到这了

逛着逛着找到了一篇文章:https://zhuanlan.zhihu.com/p/16417392406

想着这种方法也可以尝试一下,有以下代码:

from smolagents import LiteLLMModel, DuckDuckGoSearchTool
from smolagents import CodeAgent

# 使用 Ollama API
model = LiteLLMModel(
    model_id="ollama/deepseek-r1:1.5b",
    api_base="http://127.0.0.1:11434",
    api_key="ollama",
)

# 设置最大步数为 5
agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=model, max_steps=5)

# 运行测试
agent.run("唱、跳、rap、篮球、说的是哪位故人?")

# 结果是 和上面的方法一样的,开了代理ollama拒绝连接,不开代理联网搜索无法完成。那这个做法就失去了意义

这里找了很久都没有对应的解法

发现smolagents也可以使用大模型API,所以死马当活马医去找了deepseek的API,但又不想花钱,然后无意了解到了Groq里面带有一个70b的deepseek-r1模型,此处有申请key的方法和测试方法:https://blog.csdn.net/wuhanwhite/article/details/145399570 (需要代理)

那么代码就变成了:

from smolagents import LiteLLMModel, DuckDuckGoSearchTool
from smolagents import CodeAgent

model = LiteLLMModel(
    model_id="openai/deepseek-r1-distill-llama-70b",
    api_base="https://api.groq.com/openai/v1",
    api_key=os.getenv("申请的key"), # 这里不要这样写,会报错
    user_continue_message={
        "role": "user",
        "content": "Please continue",
    },
)

agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=model, max_steps=5)

# 测试智能体
result = agent.run("唱、跳、rap、篮球、说的是哪位故人?")

print(f'result:{result}')

# 但是报错:
# litellm.BadRequestError: OpenAIException - Error code: 400 - {'error': {'message': "'messages.0' : for 'role:system' the following must be satisfied[('messages.0.content' : value must be a string)]", 'type': 'invalid_request_error'}}

实际以上遇到的问题就是以下这个BUG提交上写的问题:[BUG] Groq API incompatible with smolagents system messages when using OpenAI endpoint via LiteLLMModel · Issue #429 · huggingface/smolagents

对这个报告下的回复做法进行逐一尝试,最后使用该报告下某层楼回复中的方法解决了问题。

Bugfix: Groq via LiteLLM 🚅 by JGalego · Pull Request #605 · huggingface/smolagents

于是在Groq和DuckDuckGO两者都需要代理的条件下,代码跑起来了:(负负得正了属于是)

"""
smolagents meets Groq via LiteLLM
Adapted from https://github.com/huggingface/smolagents/issues/429
"""

from smolagents import CodeAgent, LiteLLMModel, DuckDuckGoSearchTool

# Initialize the model with Groq
model = LiteLLMModel(
    "groq/deepseek-r1-distill-llama-70b",
    api_base="https://api.groq.com/openai/v1",
    api_key="申请的key" # 这里不使用报告的做法中的os.getenv,会报错
)

# Create a minimal agent
agent = CodeAgent(
    tools=[DuckDuckGoSearchTool()],  # 如果你不想使用联网搜索,这里就空着
    model=model,
    add_base_tools=False,
    verbosity_level=1, #有0(直接输出)、1(基本日志)、2(详细日志)三项可选,亲测该问题下用1会准一点,虽然不知道是什么原因
    max_steps=5        #代理在执行任务时最多允许的思考/推理步数。 
)

# Try to run a simple task
try:
    result = agent.run("唱、跳、rap,篮球,说的是哪位偶像练习生?")
    print(result)
except Exception as e:  # pylint: disable=broad-exception-caught
    print(f"Error: {str(e)}")

输出答案:

┌────────────────────────────────── New run ──────────────────────────────────┐
│                                                                             │
│ 唱、跳、rap,篮球,说的是哪位偶像练习生?                                   │
│                                                                             │
└─ LiteLLMModel - groq/deepseek-r1-distill-llama-70b ─────────────────────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 ─ Executing parsed code: ──────────────────────────────────────────────────── 
  # 使用web_search工具搜索相关信息                                             
  search_results = web_search(query="唱跳rap篮球 偶像练习生")                  
  print(search_results)                                                        
 ───────────────────────────────────────────────────────────────────────────── 
Execution logs:
## Search Results

[蔡徐坤打篮球原版#ikun #只因你太美 #偶像练习生 #唱跳rap篮球 #蔡徐坤 - 
抖音](https://www.douyin.com/video/7141337825047301376)
蔡徐坤打篮球原版#ikun #只因你太美 #偶像练习生 #唱跳rap篮球 #蔡徐坤 ... 
全民制作人们大家好 我是练习时长两年半的 喜欢唱跳rap篮球 9 让我如此蠢蠢欲动 
Cause Igot a cush on you mho yon 在今后的节目中我还准备了 很多我自己作词作曲 
100 期待的话请多多为我投票吧 蔡 ...

[蔡徐坤唱跳rap篮球原视频 #偶像练习生 #蔡徐坤ikun #唱跳rap篮球 - 
抖音](https://www.douyin.com/video/7185388522256207165)
蔡徐坤唱跳rap篮球原视频 #偶像练习生 #蔡徐坤ikun #唱跳rap篮球 - 
小代D于20230106发布在抖音,已经收获了10.6万个喜欢,来抖音,记录美好生活! 
蔡徐坤唱跳rap篮球原视频 #偶像练习生 #蔡徐坤ikun #唱跳rap篮球 - 抖音

[蔡徐坤的爆梗合集!鲲流为何永不过时? - 
知乎专栏](https://zhuanlan.zhihu.com/p/639845397)
"全民制作人们大家好,我是练习时长两年半的个人练习生蔡徐坤,我喜欢唱、跳、rap、
篮球。 ... 华夏有一极恶之兽,二足二手,顶生白发。擅唱,跳,rap。 ... 
【不知道怎么会有人一直黑他,纯路,真的觉得没必要这么黑蔡徐坤,蔡徐坤是优质偶像 
...

[蔡徐坤唱跳rap和篮球是什么梗?唱跳rap篮球什么意思?](http://www.hxnews.com/news
/yule/201905/08/1748283.shtml)
唱跳rap和篮球是什么梗 
"唱跳rap和篮球"出自蔡徐坤,蔡徐坤在参加偶像练习生的时候自我介绍是"喜欢唱跳,rap
和篮球",本来挺正常的一句话 ...

下面还有几条,都是坤坤的,节省篇幅就不放了

Out: None
[Step 1: Duration 16.21 seconds| Input tokens: 2,036 | Output tokens: 702]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 2 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 ─ Executing parsed code: ──────────────────────────────────────────────────── 
  final_answer("蔡徐坤")                                                       
 ───────────────────────────────────────────────────────────────────────────── 
Out - Final answer: 蔡徐坤
[Step 2: Duration 3.36 seconds| Input tokens: 5,721 | Output tokens: 1,171]
蔡徐坤

进程已结束,退出代码0

可以看到推理是很成功的(虽然测了几次也会认为是王力宏,周杰伦等人...但至少对过,没有联网压根就猜不出来)

2.收获了什么

本地ollama小模型经过rag和联网,是可以变得聪明一点的,虽然聪明不到哪里去,但有一个结论,之后在应用上会方便一点(?

smolagents的用法,其实也就看了一点皮毛,这一块可以研究一下,它关于tool的介绍似乎是可以定制化的说

deepseek其实也没那么蠢

3.附录

怎么本地deepseek实现RAG?(其实在上面提到过的PageAssist也可以实现,但是以下还是一个不借助插件的方法)

本思路参考的是该文章:使用langchain ollama gradio搭建一个本地基于deepseek r1的RAG问答系统_gradio deepseek-CSDN博客

其实gradio在这里只起到 web UI 的作用,不用也可以

其中对RAG起到帮助的是faiss和nomic-embed-text,其中前者负责将向量生成成文件,后者将喂进来的文本转化为向量

这里的代码是喂过gpt的,增加了一个功能是:将生成的向量做成一个文件存储在本地文件夹,之后每次运行代码,如果还是处理这个知识库的话,就只要加载向量文件就行了,节省了加载时间,毕竟如果你喂给它的文件比较大,然后你又切成小块,那就每次都要等个几到十几分钟才能访问了。

当然也可以让gpt给你做一个增量的写法,但是这里没体现。

以下代码有个bug是:跑起来之后,打开gradio,输入问题,它输出的回答是空白的,但是你在pycharm运行终端那里是可以看到答案的,这个还没看怎么弄,凑合凑合得了,又不是真的要用它的UI

import os
from langchain_ollama import OllamaEmbeddings, OllamaLLM 
from langchain.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA
from langchain.docstore.document import Document
# from langchain.tools import WebSearchTool
import gradio as gr

FAISS_DB_PATH = "faiss_index"

# 初始化 embedding 和 LLM
embedder = OllamaEmbeddings(model="nomic-embed-text:latest")
llm = OllamaLLM(model="deepseek-r1:1.5b") 

# 如果 FAISS 索引存在,则直接加载,否则重新生成
if os.path.exists(FAISS_DB_PATH):
    print("🔄 发现已有向量存储,正在加载...")
    vector_store = FAISS.load_local(FAISS_DB_PATH, embedder, allow_dangerous_deserialization=True)  
else:
    print("📄 未找到向量存储,正在创建...")
    with open("content.txt", "r", encoding="utf-8") as file:
        content = file.read()
    document = Document(page_content=content)

    # 文档切割
    splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
    split_docs = splitter.split_documents([document])

    # 创建向量存储
    vector_store = FAISS.from_documents(split_docs, embedder)

    # 保存 FAISS 索引
    vector_store.save_local(FAISS_DB_PATH)
    print("✅ 向量数据库已保存到本地!")

# 创建检索器
retriever = vector_store.as_retriever(search_type="similarity", search_kwargs={"k": 3})

# QA 逻辑
qa_chain = RetrievalQA.from_llm(
    llm=llm,
    retriever=retriever,
    prompt=PromptTemplate(
        input_variables=["context", "question"],
        template="""
        请根据上下文回答问题。若无法从上下文获取答案,请你用你的所知道的知识尽可能回答一个正确的答案,但前提是你无法从上下文获取答案的情况下。
        上下文:{context}
        问题:{question}
        回答:
        """
    )
)

# Gradio 聊天接口
def chat(message, history):
    result = qa_chain.run(message)
    print(result)
    return result

gr.ChatInterface(fn=chat, title="deepseek-r1").launch()

4.补充

噢,刚刚还发现一个问题:关于联网的那个方案的

litellm.RateLimitError: RateLimitError: GroqException - 
{"error":{"message":"Rate limit reached for model 
`deepseek-r1-distill-llama-70b` in organization 
`org_01jnte7cf9fp9aq3mv77qyhrda` service tier `on_demand` on tokens per minute 
(TPM): Limit 6000, Used 4193, Requested 5978. Please try again in 41.702s. Need
more tokens? Upgrade to Dev Tier today at 
https://console.groq.com/settings/billing","type":"tokens","code":"rate_limit_e
xceeded"}}

简单说就是Groq免费的API有流量限制(每分钟),不要用的太频繁。

加了一个测试:

try:
    result = agent.run("牢大指的是哪一位篮球明星?")
    print(result)
except Exception as e:  # pylint: disable=broad-exception-caught
    print(f"Error: {str(e)}")
 
其中它在第三次思考的时候给出了正确答案
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Step 3 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Error in code parsing:
Your code snippet is invalid, because the regex pattern 
```(?:py|python)?\n(.*?)\n``` was not found in it.
Here is your code snippet:
<think>
好吧,我现在需要解决的问题是“牢大指的是哪位篮球明星?”。首先,我会思考这个问题
。根据我的了解,“牢大”可能是一个昵称,或者是某个篮球明星的别名。由于这是一个中
文的问题,我可能需要查找相关的中文资料或者网络资源来确定这个昵称指的是谁。

接下来,我想到可以使用网络搜索工具来查找相关的信息。我会搜索关键词“牢大 
篮球明星”,看看有哪些结果。根据搜索结果,我可以找到相关的网页、论坛讨论或者社交
媒体上的内容,从而了解“牢大”指的是哪位篮球明星。

在搜索过程中,我可能会遇到一些结果指向科比·布莱恩特,因为科比在中文网络中有时会
被昵称为“牢大”。这是因为“科比”发音接近“牢大”这个词语,可能是网友们对他的昵称。
另外,科比·布莱恩特是非常著名的篮球运动员,曾在NBA效力多年,赢得了多个冠军和奖
项,因此他有很多昵称和称号。

此外,我还需要确认是否有其他篮球明星也被称为“牢大”,以避免混淆。通过进一步的搜
索和阅读相关的文章,我可以更准确地确定“牢大”指的是科比·布莱恩特,而不是其他篮球
运动员。

总结一下,我的思考过程是:首先通过网络搜索获取相关信息,然后分析搜索结果,确认“
牢大”指的是科比·布莱恩特,最后得出结论。
</think>

“牢大”是指著名篮球明星科比·布莱恩特(Kobe 
Bryant)。这个昵称源于科比名字的中文音译“科比”与“牢大”发音的相似,因此在中文网
络中被广泛使用。科比·布莱恩特是NBA历史上最伟大的球员之一,赢得了五次NBA总冠军和
多次个人荣誉。因此,“牢大”成为科比的别称,象征着他在篮球界的地位和影响力。

**步骤解释:**

1. **网络搜索**:使用网络搜索工具查找“牢大 篮球明星”,获取相关信息。
2. **分析结果**:查看搜索结果,发现多个网页指出“牢大”指的是科比·布莱恩特。
3. 
**确认信息**:通过阅读相关文章和百科内容,确认“牢大”确实指的是科比·布莱恩特。
4. **总结结论**:得出“牢大”指的是科比·布莱恩特,并解释昵称的来源。

**最终答案**:牢大指的是篮球明星科比·布莱恩特(Kobe Bryant)。
Make sure to include code with the correct pattern, for instance:
Thoughts: Your thoughts
Code:
```py
# Your python code here
```<end_code>
Make sure to provide correct code blobs.
[Step 3: Duration 4.56 seconds| Input tokens: 7,852 | Output tokens: 2,895]

就写到这吧,后面有要补充的再更新

posted @ 2025-03-08 20:37  Akimizuss101  阅读(350)  评论(0)    收藏  举报