前言

这篇文章主要是基于目前AI发展现状做出的一些思考,如何才能让模型更智能。

我们基于一个旅游场景来设想模型应该如何实现: 我要去山西旅游

任务分解

模型首先要基于”我要去山西旅游”这个要求进行分解,整理成一个类似操作列表的东西。下边是基于实际情况给出的一个设想。

  1. TODO 要问用户是什么时间去,要去的具体地方。
  2. TODO 确定时间和地方后帮用户查看当地的天气情况,给出穿衣建议。
  3. TODO 帮用户自动查询交通工具,给出合理的建议,供用户选择。
  4. TODO 用户选择后自动去请求接口订票。
  5. TODO 给用户提供一些当地的特色,游玩,美食等。

应该如何实现

  1. 需要模型能够理解用户的意图,并能分解成计划。(现在一些通用的大模型,可以通过多轮的方式实现类似效果。)
  2. 跟用户逐步确定计划中需要的点,比如具体要去的地方等,完成一条计划就标记为DONE。
  3. 根据计划选择合适的外部工具,比如调用实时查询天气的工具,订票的工具等,完成后同样标记完成。
  4. 按照模型自己给出的计划,依次完成知道任务结束。

实现难点

  1. 如何让模型能够识别系统中注册的工具或者agent(如果是企业级,可能会有很多)
  2. 如何定义合理的接口,能让模型理解接口的输入输出,从而自动产生相应的参数,将整个计划自动串联起来。

一个技术人的设想

  1. 定义一个统一的工具交互规范,模型能够理解,并能根据需要方便识别到。
  2. 提供一个注册中心,个人或者企业能够按照业务创建很多智能体,然后注册。
  3. 参考面向对象的思想,智能体应该是独立的个体,没有中间调度也可以独立使用。
  4. 模型可以根据用户要求分解任务,并在注册中心中找到合理的智能体进行调度。

结语

现在很多落地的东西是一条条的工作流,只能体现一部分模型的能力,虽然可以对外交互,也只是人为干预的结果。当然也可能有很多优秀的方案没有发现。

如何一句话让模型把事儿干好,才是未来发展的方向。

如果大家有合适的方案可以沟通交流,感谢。

前言

这篇文章偏技术,如果跟着文章操作有难度,建议找网上找相关视频操作。

什么是OpenManus,为什么要使用

说到OpenManus就不得不先提下Manus,Manus是全球首款真正意义上的通用型AI Agent,由中国的创业公司Monica开发,看官方的演示感觉很6,但是10w的邀请吗告诉我,我不配。

幸好有大佬连夜整出来一个OpenManus,引用官方一句描述: Manus 非常棒,但 OpenManus 无需邀请码即可实现任何创意 !

那么OpenManus能做什么呢

复杂任务规划与执行:它可以把复杂的任务拆解成多个小步骤,自动规划并执行,最后给出完整的成果。

工具调用与自动化:很多工作离不开外部工具。 OpenManus 能灵活调动 各种工具,比如浏览器、数据分析软件等,完全不用你担心技术细节。

智能信息收集与处理:OpenManus 不仅能浏览网页、提取信息,还能进行精准的内容整理。

安装使用

环境

os: archlinux

安装OpenManus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. 源码下载
git clone https://github.com/mannaandpoem/OpenManus.git

2. 进入项目根目录
cd OpenManus

3. 创建新的 conda 环境
conda create -n open_manus python=3.12

4. 等待完成后,设置当前python环境
source /opt/anaconda/bin/activate open_manus

5. 安装依赖
pip install -r requirements.txt

购买DeepSeekApi

1
2
3
4
5
1. 访问DeepSeek官网 https://www.deepseek.com./ 。

2. 点击右上角API开放平台,左边充值即可,测试充个10元就勾了。

3. 充值完毕后,点击API Keys,创建自己的key,我这里起名字就是OpenManus(可以看看这玩意儿消耗tokens的量)

配置OpenManus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
OpenManus 需要配置使用的 LLM API,请按以下步骤设置:

1. 保证当前还在项目跟目录下

2. 创建config.toml文件:
cp config/config.example.toml config/config.toml

3. 编辑 config/config.toml 添加 API 密钥和自定义设置:(注: model和base_url在deepseek充值界面接口文档就可以看到)

# Global LLM configuration
[llm]
model = "deepseek-chat"
base_url = "https://api.deepseek.com"
api_key = "sk-8.....9ff89"
max_tokens = 4096
temperature = 0.0

# [llm] #AZURE OPENAI:
# api_type= 'azure'
# model = "YOUR_MODEL_NAME" #"gpt-4o-mini"
# base_url = "{YOUR_AZURE_ENDPOINT.rstrip('/')}/openai/deployments/{AZURE_DEPOLYMENT_ID}"
# api_key = "AZURE API KEY"
# max_tokens = 8096
# temperature = 0.0
# api_version="AZURE API VERSION" #"2024-08-01-preview"

# Optional configuration for specific LLM models
[llm.vision]
model = "claude-3-5-sonnet"
base_url = "https://api.openai.com/v1"
api_key = "sk-..."

启动

1
python main.py

输出如下:

1
2
3
4
INFO     [browser_use] BrowserUse logging setup complete with level info
INFO [root] Anonymized telemetry enabled. See https://docs.browser-use.com/development/telemetry for more information.
Enter your prompt (or 'exit'/'quit' to quit): (这里就是发挥创意的地方了)

一些小问题处理

目前内部默认采用的是google搜索,国内不好用,调整为bing搜索

  1. 在app/tool/目录,加bing_search.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    import asyncio
    from typing import List
    from urllib.parse import quote
    import requests
    from bs4 import BeautifulSoup
    from app.tool.base import BaseTool

    class BingSearch(BaseTool):
    name: str = "bing_search"
    description: str = """执行必应搜索并返回相关链接列表。
    当需要获取国际信息或英文内容时建议使用此工具。
    工具返回与搜索查询匹配的URL列表。"""
    parameters: dict = {
    "type": "object",
    "properties": {
    "query": {
    "type": "string",
    "description": "(必填) 提交给必应的搜索关键词"
    },
    "num_results": {
    "type": "integer",
    "description": "(可选) 返回的搜索结果数量,默认10",
    "default": 10
    }
    },
    "required": ["query"]
    }

    async def execute(self, query: str, num_results: int = 10) -> List[str]:
    """
    执行必应搜索并返回URL列表

    Args:
    query: 搜索关键词
    num_results: 返回结果数量

    Returns:
    匹配搜索结果的URL列表
    """

    def sync_search():
    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    'Accept-Language': 'en-US,en;q=0.9'
    }
    url = f'https://www.bing.com/search?q={quote(query)}'
    links = []

    for page in range(0, num_results // 10 + 1):
    resp = requests.get(
    f'{url}&first={page * 10}',
    headers=headers,
    timeout=10
    )
    soup = BeautifulSoup(resp.text, 'html.parser')

    for result in soup.select('.b_algo'):
    link = result.find('a', href=True)
    if link and 'href' in link.attrs:
    links.append(link['href'])
    if len(links) >= num_results:
    return links
    rst = links[:num_results]
    return rst

    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(None, sync_search)

  2. agent/manus.py 中添加 BingSearch
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    from pydantic import Field

    from app.agent.toolcall import ToolCallAgent
    from app.prompt.manus import NEXT_STEP_PROMPT, SYSTEM_PROMPT
    from app.tool import Terminate, ToolCollection
    from app.tool.browser_use_tool import BrowserUseTool
    from app.tool.file_saver import FileSaver
    from app.tool.google_search import GoogleSearch
    # 一定要先引入
    from app.tool.bing_search import BingSearch
    from app.tool.python_execute import PythonExecute


    class Manus(ToolCallAgent):
    """
    A versatile general-purpose agent that uses planning to solve various tasks.

    This agent extends PlanningAgent with a comprehensive set of tools and capabilities,
    including Python execution, web browsing, file operations, and information retrieval
    to handle a wide range of user requests.
    """

    name: str = "Manus"
    description: str = (
    "A versatile agent that can solve various tasks using multiple tools"
    )

    system_prompt: str = SYSTEM_PROMPT
    next_step_prompt: str = NEXT_STEP_PROMPT

    # Add general-purpose tools to the tool collection
    # 注意这里添加BingSearch
    available_tools: ToolCollection = Field(
    default_factory=lambda: ToolCollection(
    PythonExecute(), GoogleSearch(), BingSearch(), BrowserUseTool(), FileSaver(), Terminate()
    )
    )
  3. prompt/manus.py 修改GoogleSearch为BingSearch
    1
    sed -i 's/GoogleSearch/BingSearch/g'

参考: https://github.com/mannaandpoem/OpenManus/issues/277

测试

  1. 查找中国 前十高校,通过csv格式返回到跟目录,只需要有学校名称 、排名、官网即可

实际测试,这玩意儿还是bug不少,跑了十几分钟结果没出结果,白瞎了我的token :D。

总结

速度真的是挺慢,但是能够自己主动去搜索解决问题也算是挺牛了,对于技术人员来说又多了一个玩具。

这种主动去思考解决问题的思想比较有意思,在其它平台定义工作流时候可以借鉴这种方案,创建自己的manus,加油!!

为什么企业要搭建本地知识库

在当今信息爆炸的时代,企业面临着海量数据和知识的管理挑战。搭建本地知识库已成为企业提升效率和竞争力的重要手段。以下是企业搭建本地知识库的几个核心原因:

解决碎片化问题

企业多年积累的知识比较碎片化,很多也慢慢流于形式。使用知识库可以将这些碎片化知识重新整合,并且通过大模型学习进行分类整合,充分发挥知识的价值。

提升效率和创新能力

通过知识库的整合,员工不需要在茫茫的文档中查找,可以基于统一的入口去查找需要的东西。而且随着知识越发丰富,模型也会越来越强大,可以将海量知识组合,创造出新的想法。

提高安全性

相对于将知识全部放在公网知识库中,本地知识库可以有效保护企业的核心知识和技术,防止人员流动以及公网安全性导致的知识缺失。

企业知识库的目标

不同于通用大模型,企业知识库最重要的就是,专业性和准确性。知识库应该是垂直领域的,基于企业的核心业务,结合各种内部的文档进行知识的整合,使得行业知识逻辑更加清晰完整,并且数据来源是内部文档,所以对比通用大模型会更加准确。

搭建知识库的痛点

技术难度

个人原型搭建相对简单,但企业级部署需考虑权限管理、版本控制、审计追踪等复杂需求。

回答不够准确

回答准确性问题可能是知识库构建最麻烦的地方,不同的人,不同的团队写出的文档格式千奇百怪。而且有些知识是从网上下载,没有专门做整理就作为知识文档保留下来。知识库采用RAG(检索增强生成)技术,通过语义检索获取相关文档片段,再结合生成模型输出答案,不同分块的方式,大小都会导致知识库的回答不一定准确。下面以用户使用手册为例,来解决这些问题。

合理文档格式的重要性及模板参考

一般网上搜到知识库的搭建都是给你搞个embedding模型,或者根据什么换行之类的东西直接分块,但是这种方式对于企业知识库没什么用,因为文档真的太乱了。可能你换行的、用模型处理后的内容语义本身就不连续,有的段落内容多,有的少,有的可能多个分段是一个语义环境。目前只是专业的人才能够去理解真正哪些内容是一个语义环境。所以目前我的想法是可以通过人工干预,将文档按照格式整理,在通过程序增加分割符,然后在文档分块时,通过分割符号来处理,保证语义的完整性。下边给出一个简单的操作手册片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
** 功能1:[功能名称]

*** 功能描述
简要描述功能1的主要用途和实现目标。

*** 菜单路径
- 主菜单:[具体菜单路径]
- 快捷方式:[快捷键或图标]

*** 操作步骤
1. 打开软件,进入主界面。
[[file:功能1_步骤1.png]]
2. 点击“[菜单名称]”,选择“[子菜单名称]”。
[[file:功能1_步骤2.png]]
3. 在弹出的窗口中,输入相关信息(如用户名、密码等)。
[[file:功能1_步骤3.png]]
4. 点击“确定”按钮,完成操作。
[[file:功能1_步骤4.png]]

*** 注意事项
- 确保输入的信息准确无误。
- 如果遇到错误提示,请参考“常见问题”部分。

---

** 功能2:[功能名称]

*** 功能描述
简要描述功能2的主要用途和实现目标。

*** 菜单路径
- 主菜单:[具体菜单路径]
- 快捷方式:[快捷键或图标]

*** 操作步骤
1. 打开软件,进入主界面。
[[file:功能2_步骤1.png]]
2. 点击“[菜单名称]”,选择“[子菜单名称]”。
[[file:功能2_步骤2.png]]
3. 在弹出的窗口中,选择所需选项(如文件类型、格式等)。
[[file:功能2_步骤3.png]]
4. 点击“保存”按钮,完成操作。
[[file:功能2_步骤4.png]]

*** 注意事项
- 在保存文件时,建议选择合适的文件格式。
- 如果文件过大,可能会导致保存时间较长。

对于上述文档,我们可以按照层次结构添加分隔符,比如按照的个数,两个作为二级标题,然后在功能2前增加======split=====作为分隔符,效果如下。

1
2
3
4
5
6
7
8
9
10
** 功能1:[功能名称]
内容同上
---
=====split=====
** 功能2:[功能名称]
内容同上
=====split=====
** 功能3:[功能名称]
内容同上

此时将上述内容按照=====split=====分隔传入知识库,会将相同语义的内容放到单独的块中。在中知识搜索时,通过向量匹配的内容就会相对完整准确。

如何让知识库模型不乱说

其实光是知识库内容完整还不够,将知识库搜索结果作为提问的上下文仍然无法阻止模型自己的”发明创造”,这种结果是企业知识库无法接受的。这时候就需要对模型增加一些约束,此时就是prompt大显身手了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
你是xx企业业务专家。你的回答应基于以下规则:
1. 使用提供的上下文(<context></context>)作为你的知识来源。
2. 如果上下文中有相关信息,请直接根据上下文回答。
3. 如果上下文中没有相关信息,请直接说“我不知道”或请求用户提供更多信息。
4. 当且仅当上下文包含相关信息时,用自然对话方式输出答案;否则明确告知'该问题不在知识库覆盖范围内。
5. 根据用户提问的语言(如中文或英文)来回答。
必需行为:
- 知识库存在的内容必须全部包含,并且不能改变上下文语义
禁止行为:
- 禁止任何形式的内容编造
- 禁止使用"根据我的知识"等模糊表述
- 禁止扩展知识库外的信息
- 禁止引入聊天上下文中无关内容,优先使用context中内容

Context: <context>
{{#context#}}
</context>

仔细看下上述prompt就知道它是怎么工作了,其它限制可以按照企业需要继续扩展,按照知识库返回结果逐步优化。

实施计划

分阶段实施建议

  1. 知识盘点阶段(1-2周):成立跨部门小组,梳理核心知识资产
  2. 规范制定阶段(2-4周):建立文档编写标准和审核流程
  3. 试点运行阶段(4-8周):选择3-5个关键业务模块进行验证
  4. 全面推广阶段(8-12周):基于试点经验完善系统后全面部署

质量评估

  1. 准确率(Accuracy):人工抽检回答正确性
  2. 召回率(Recall):测试集问题解决率

结语

希望本文的分享能帮助大家在搭建和使用本地知识库时更加得心应手,祝大家实践成功!

前提

本地目前没有显卡,只能用cpu刚。

如果不想自己搭建本地模型,完全可以掏钱使用现成的API即可。

需要了解一些docker知识

搭建本地模型

环境

os: archlinux

内存: 32g

cpu: 6核12线程

docker: 27.3.1

docker-compose: 2.32.4

ollama

1
2
3
4
5
6
pacman -S ollama

systemctl start ollama.service

# 通过下述url判断ollama是否安装成功
http://127.0.0.1:11434/

LLM模型 (qwen2:1.5b)

下载

1
ollama pull qwen2:1.5b

启动

1
ollama run qwen2:1.5b

测试

1
2
3
4
5
ollama run qwen2:1.5b
>>> who are you?
I am an AI language model, designed to answer questions and provide information on various topics. How can I assist you today?

>>> Send a message (/? for help)

Text Embedding模型 (m3e)

下载

1
2
3
ollama pull milkey/m3e

embedding模型不需要run, ollama服务启动可直接使用

测试

1
2
3
4
curl http://127.0.0.1:11434/api/embed -d '{
"model": "milkey/m3e",
"input": "balabalabala"
}' | jq .

查看模型运行情况

1
2
3
4
5
ollama ps

NAME ID SIZE PROCESSOR UNTIL
qwen2:1.5b f6daf2b25194 1.5 GB 100% CPU 4 minutes from now
milkey/m3e:latest 1477f12451b0 860 MB 100% CPU 4 minutes from now

构建知识库(ollama+DIFY)

下载启动dify

参考官方文档,so easy!

https://docs.dify.ai/zh-hans/getting-started/install-self-hosted/docker-compose

本地采用的是 #systemd方式* 部署。这里一定要注意,不同的部署方式网络配置有点区别,比如systemd的方式服务启动需要增加环境变量OLLAMA_HOST,而对于docker启动方式,可以参考官方文档(暂未测试)

添加模型

这里我们需要两个模型,一个LLM,一个Text Embedding

qwen2:1.5b模型添加

模型名称:qwen2:1.5b(必须完整填写)

基础 URL:http://:11434 (这里的ip要是你本地ip,不能用localhost,127这些。本地是http://10.10.15.159:11434)

模型类型:对话

模型上下文长度:4096 (模型的最大上下文长度,若不清楚可填写默认值 4096)

最大 token 上限:4096 (模型返回内容的最大 token 数量,若模型无特别说明,则可与模型上下文长度保持一致)

是否支持 Vision:是

保存即可使用

screenshot_x3ym8s_000.png

milkey/m3e:latest

模型名称:milkey/m3e:latest (同上)

基础 URL:http://:11434 (这里的ip要是你本地ip,不能用localhost,127这些。本地是http://10.10.15.159:11434)

模型上下文长度:4096

保存即可使用

访问测试

创建知识库

导入数据 –> 设置分段 –>设置索引及检索

对于word这种格式化的数据,分段模式最好使用 #父子模式* ; 索引方式使用高质量模式,使用上述m3e模型来生成索引数据。

screenshot_zSwzzS_000.png

创建聊天助手

知识库是没法直接去使用的,顶多能做个召回测试。这里我们创建一个聊天助手,可以关联知识库,这样能真正使用。

聊天助手创建很简单,可以选择顶部工作室 -> 创建空白应用

screenshot_UWVTYt_000.png

选择已经创建好的知识库

screenshot_NnXWmT_000.png

应用发布即可

直接通过dify使用

dify默认启动使用的是80端口,可以直接通过http://localhost 访问(首次使用需要注册用户密码)。 然后选择探索,选择我们刚刚创建的聊天助手就可以开始愉快的聊天了。

screenshot_vq0gwR_000.png

screenshot_dhJZif_000.png

将dify嵌入到自己的应用中

可以通过api、iframe之类的方式将自己搭建的聊天助手嵌入到系统中(需要有开发能力,很简单)。

知识库工作流

screenshot_pMpzgp_000.png

问题处理

dify访问时提示11434拒绝

http://10.10.15.159:11434/ 请求失败

处理

检查服务启动正常,需要在service中增加环境变量 Environment=”OLLAMA_HOST=0.0.0.0:11434”

1
2
3
sudo vim /usr/lib/systemd/system/ollama.service
systemctl daemon-reload
systemctl restart ollama.service

其它系统类似,就是让服务启动读取到该变量即可

Reached maximum retries (3) for URL http://localhost:8090/api/system/ext/examples/echo

分析处理

添加工具后,访问本地接口提示上述错误, 其实还是ip的问题,这里使用本地ip,如10.10.15.159。因为dify部署在容器中,localhost有特殊意义

什么是telegram

Telegram Messenger, commonly known as Telegram, is a cloud-based, cross-platform, social media and instant messaging (IM) service

Telegram Messenger,通常简称为Telegram,是一款基于云的、跨平台的社交媒体和即时通讯(IM)服务。

目标

日常生活中有一些动态的提醒,比如说服务器故障,或者找到了一些有意思的内容,我们需要有一种手段可以直接通知。理想情况下,如果能直接通知到微信会更好,但目前似乎没有既安全又好用的方法来实现这一点。。虽然钉钉提供了机器人的方式(需要有群组),但是除了工作800年不会打开。所以借这次机会正好玩下telegram的机器人。

环境

python3.x

科学上网

操作步骤

创建一个机器人

在botfather中输入/newbot, 按照提示创建一个机器人。创建后会返回一段内容包括机器人的tokenid。

获取要通知用户的chat_id

搜索添加机器人 @get_id_bot,私聊发送命令 /my_id,如下图,会返回你的id信息

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# -*- coding: utf8 -*-
from datetime import date, datetime
import requests
from telegram import Bot
from telegram.utils.request import Request
import os
...
def send_telegram_message(msg):
# 替换为你的API令牌
token = os.environ['TELEGRAM_TOKEN']
# 替换为你的Telegram账号的ID
chat_id = os.environ['TELEGRAM_CHAT_ID']
"""
python 3.x
"""
proxy = Request(proxy_url='http://127.0.0.1:7890')
bot = Bot(token=token, request=proxy)
bot.send_message(chat_id=chat_id, text=msg)

按照上述步骤即可实现将msg信息发送给机器人。所以理论上你可以创建很多个机器人,分别做不同类型的通知,enjoy!

引言

你是否想过拥有一个私人订制的AI助手,能够随时为你提供最个性化的信息?本文将带你一步步搭建一个基于本地模型和RAG技术的个人知识库。

搭建本地模型

环境

  • os: archlinux
  • 内存: 32g
  • cpu: 6核12线程
  • python: 3.12.7
  • docker27.3.1 + docker-compose
  • 向量库: milvus2.4.13 + attu2.4(客户端)

ollama

1
2
3
4
5
6
7
pacman -S ollama

systemctl start ollama.service

# 通过下述url判断ollama是否安装成功
http://127.0.0.1:11434/

llama3.2:3b

1
ollama run llama3.2:3b

OpenWebUI(非必须)

1
2
3
4
5
# 启动openwebui, 按照自己需要调整端口
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui ghcr.io/open-webui/open-webui:main

# 浏览器访问, 可以看到之前启动的模型
http://localhost:3000/

程序访问测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage

# 创建ChatOllama实例,指定模型名称
model = ChatOllama(model="llama3.2:3b")

# 定义你的问题
question = HumanMessage("你是如何工作的?")

# 使用模型处理问题
response = model.invoke([question])

# 打印返回的结果
print(response.content)

构建知识库

RAG是什么

大模型的训练数据是有截止日期的,那当我们需要依靠不包含在大模型训练集中的数据时,我们该怎么做呢?一种就是对模型进行微调,另外就是通过检索增强生成RAG(Retrieval Augmented Generation)。在这个过程中,首先检索外部数据,然后在生成步骤中将这些数据传递给LLM。

利用大模型的能力搭建知识库就是一个RAG技术的应用。

RAG的应用抽象为5个过程:

  • 文档加载(Document Loading) :从多种不同来源加载文档。LangChain提供了100多种不同的文档加载器,包括PDF在内的非结构化的数据、SQL在内的结构化的数据,以及Python、Java之类的代码等
  • 文本分割(Splitting) :文本分割器把Documents 切分为指定大小的块,我把它们称为“文档块”或者“文档片”
  • 存储(Storage): 存储涉及到两个环节,分别是:
    1. 将切分好的文档块进行嵌入(Embedding)转换成向量的形式
    2. 将Embedding后的向量数据存储到向量数据库
  • 检索(Retrieval) :一旦数据进入向量数据库,我们仍然需要将数据检索出来,我们会通过某种检索算法找到与输入问题相似的嵌入片
  • 输出(Output) :把问题以及检索出来的嵌入片一起提交给LLM,LLM会通过问题和检索出来的提示一起来生成更加合理的答案

个人笔记

首先起码得有自己的知识库,我这里就是个人多年整理的笔记。或者你有项目相关的文档,也可以作为知识库的基础。

将个人笔记写入到Milvus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from langchain_community.document_loaders import DirectoryLoader
from langchain_community.vectorstores import Milvus
from langchain_ollama import OllamaEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from pymilvus import MilvusClient
import os

# 检查collection是否存在, 如果不指定,默认为LangChainCollection
collection_name = "note"

# 设置 Milvus 客户端
client = MilvusClient(uri="http://localhost:19530")

# 检查collection是否存在
if client.has_collection(collection_name):
# collection存在,执行后续操作
print(f"Collection '{collection_name}' exists.")
else:
# collection不存在,创建collection并进行向量化
print(f"Collection '{collection_name}' does not exist. Creating now...")
# 从url导入知识作为聊天背景上下文, glob代表只查找org文件,可根据实际情况调整为txt等,recursive=True表示会递归查找
loader = DirectoryLoader(os.path.join(os.environ["HOME"], "Documents/notes"), glob="*.org", recursive=True)
# 加载一堆文件
docs = loader.load()

# 文本分词器
# chunk_size=1000
# 表示拆分的文档的大小,也就是上面所说的要设置为多少合适取决于所使用LLM 的窗口大小
# chunk_overlap=100
# 这个参数表示每个拆分好的文档重复多少个字符串。
# 不过这种递归的方式更只能点,不设参数试试默认
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)

# ollama嵌入层
embeddings = OllamaEmbeddings(
model="llama3.2:3b"
)

# 文档向量化,会持久化
vector_store = Milvus.from_documents(documents=documents, embedding=embeddings, collection_name=collection_name, drop_old=True)
print(f"collection'{collection_name}'创建成功!")

注: 上述加载文件的目录需要根据自己实际情况调整,其它的最好用默认,减少出错概率

将llm与Milvus结合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_community.vectorstores import Milvus
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import OllamaEmbeddings
from langchain_ollama import OllamaLLM
from langchain_text_splitters import RecursiveCharacterTextSplitter
from pymilvus import MilvusClient


def exec(question):
# 检查collection是否存在
collection_name = "note"
# 设置 Milvus 客户端
client = MilvusClient(uri="http://localhost:19530")
vector_store = None
# 检查collection是否存在
if client.has_collection(collection_name):
# collection存在,执行后续操作
print(f"Collection '{collection_name}' exists.")
# 文本分词器
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents([])

# ollama嵌入层
embeddings = OllamaEmbeddings(
model="llama3.2:3b"
)
# 文档向量化
vector_store = Milvus.from_documents(documents=documents, embedding=embeddings, collection_name=collection_name)
else:
# collection不存在,创建collection并进行向量化
print(f"Collection '{collection_name}' does not exist. Please exec LoadFile2Vector.py first")
if vector_store is not None:
# 创建ollama 模型 llama2
llm = OllamaLLM(model="llama3.2:3b")
output_parser = StrOutputParser()

# 创建提示词模版
prompt = ChatPromptTemplate.from_template(
"""Answer the following question based only on the provided context:
<context>
{context}
</context>
Question: {input}"""
)

# 生成chain : prompt | llm
document_chain = create_stuff_documents_chain(llm, prompt)

# 向量数据库检索器
retriever = vector_store.as_retriever()

# 向量数据库检索chain : vector | prompt | llm
retrieval_chain = create_retrieval_chain(retriever, document_chain)

# 调用上面的 (向量数据库检索chain)
response = retrieval_chain.invoke({"input": question})
# 打印结果
print(response["answer"])


if __name__ == '__main__':
exec("我有什么梦想? 如何实现")

大致的流程是:用户的query先转成embedding,去向量数据库查询最接近的top K回答;然后这query + top K的回答 + 其他context一起进入LLM,让LLM整合上述所有的信息后给出最终的回复。

提供接口(非必须)

可通过fastapi等提供restful接口供外部调用,比如一些个人项目公司内部项目之类的,瞬间高大上起来了。

项目源码

https://github.com/zhaozhiwei1992/NoteAI.git

参考

https://blog.csdn.net/AAI666666/article/details/137509781

https://ollama.com/library

文本向量转换: https://github.com/shibing624/text2vec

文本存储: https://juejin.cn/post/7360564568660410377

引言

分享一个前后端分离的后台管理系统,技术栈较新,适合喜欢倒腾的朋友。

地址: https://github.com/zhaozhiwei1992/money-making-machine-plus.git

喜欢的朋友,点点star

项目描述

一个前后端分离的后台管理系统, 基于springboot3.3.3+vue3.3.4+mysql8, 代码结构清晰,注释友好,使用最新的前后端开发技术,适合想要尝鲜的道友。

项目参考了jhipster的优秀代码设计,ruoyi项目的目录接口, 分模块开发, 感谢以上开源项目。

目前处于开发阶段,有问题提issue,后续会继续完善。如果动手能力强的朋友,可以直接参与开发,一起完善这个项目。

为什么叫赚钱工具?字面意思,因为真的很穷。

体验地址

http://43.143.194.245:8091/index.html (无了,暂时没钱搞服务器:D)

用户/密码: admin/admin

项目特点

代码注释友好, 实现简单, 便于阅读, 推荐二次开发

前后端分离,使用 token 认证

支持RBAC权限模型, 支持菜单及按钮权限控制, 动态显示及后端严格权限控制

支持角色+菜单的数据权限控制, 按照规则配置好后,程序自动控制

前端采用 Vue3.x + element-plus-admin, 数据绑定代码简单,提高开发效率

使用 liquibase 进行数据库版本控制, 空库只需创建数据库然后启动服务即可

使用 quartz 定时任务,可动态完成任务的添加、修改、删除、暂停、恢复及日志查看等功能

使用 swagger 查看或测试后端接口

使用 jpa 做数据库操作, 理论上支持大部分关系数据库

同步支持移动端小程序

功能模块

基础数据

  • 部门管理

  • 用户管理

  • 角色管理

  • 基础数据维护

菜单管理

  • 菜单管理

  • 动态表单

  • 采集表

系统管理

  • 功能权限

  • 数据权限

  • 流程管理

  • 缓存管理

  • 定时任务

  • 系统参数

审计查询

系统监控

  • 在线人员监控

  • 日志管理

  • 资源监控

  • 服务状态

  • 缓存状态

首页显示

  • 待办事项

  • 通知公告

国际化

  • 国际化支持

开发者工具

  • 代码生成

  • 大屏显示

  • 报表制作

安装要求

  1. java 21+
  2. springboot 3.3.3.RELEASE
  3. mysql 8+
  4. npm 8+
  5. node 20+

tag1.0.0

  1. java 8+
  2. springboot 2.6.3.RELEASE
  3. mysql 5.7.5+
  4. npm 6.14.4+
  5. node 16.13.1+

安装步骤

  1. git clone 当前项目到你喜欢的目录
  2. 用你喜欢的 ide 引入该项目,并加载好依赖
  3. 创建好数据库 database, 默认 money_making_machine_plus
  4. 启动项目: 后端运行com.z.server.BootStrapServerApplication, 前端进入z-ui-admin-vue3目录, 执行pnpm run dev(先构建)
  5. 访问http://localhost:4000, 登录查看我们的成果, 用户/密码:admin/admin

部署

前后端分离部署

前后端集中部署

1
mvn clean package -Psingle

版本控制

该项目使用 git 进行版本管理。您可以在 tags 参看当前可用版本。

引言

你平时都怎么复制粘贴的?是否每次都是复制一段粘贴一段?是否厌倦了每次只能复制粘贴一次的限制?那这篇文章就是为你量身订做的。

CopyQ简介

CopyQ is clipboard manager – a desktop application which stores content of the system clipboard whenever it changes and allows to search the history and copy it back to the system clipboard or paste it directly to other applications.

CopyQ 是一款开源的、跨平台的剪贴板管理工具,它不仅存储系统剪贴板的内容,还允许用户搜索历史记录,并将所需内容复制回系统剪贴板或直接粘贴到其他应用程序。这就意味着,你可以一次性复制多份内容,然后在需要的时候统一粘贴,极大地提高了工作效率。

官方地址: https://copyq.readthedocs.io/en/latest/

CopyQ支持Windows、macOS、Linux系统,无论你使用的是哪种操作系统,都能享受到它带来的便利。

CopyQ的核心功能

多格式支持:CopyQ不仅限于文本,还支持图片、HTML等多种格式,满足不同场景的需求。

历史记录管理:你可以轻松管理剪贴板的历史记录,进行搜索、筛选和排序,快速找到你需要的内容。

多标签页功能:通过标签页分类管理剪贴板内容,提高组织效率,更清晰。

标记置顶功能: 可以给复制的条目打一个醒目的标签,方便后续查找。也可以将常用的复制内容置顶,后续就不需要每次找到源头复制再去粘贴。

编辑和脚本功能:内置编辑器让你可以对复制的文本内容进行调整,而脚本功能则为高级用户提供了更多自定义的可能。

导出和备份:软件本身支持复制内容的导出备份,同时导出的内容还可以导入到软件中。基于这一点如果动手能力还可以,能做个定时工具,利用github,或者同步网盘做一个多平台同步,爽。

实际应用案例

编程开发:软件开发过程使用复制粘贴很频繁,不然也不会叫CV工程师了。如果有多段分隔开的代码要复制,平时都是复制粘贴一段,返回网站继续复制,循环往复。但是这样做很2,这里就可以使用CopyQ,一次复制完,然后到IDE中多次粘贴即可。

办公:比如经常用的word,excel,我们需要使用其中某些部分填充到新的文件中。此时我们可以直接将要使用的内容全部复制,然后到新的文件中按照需要多次粘贴即可。

笔记:一些经常使用的文字可以保存在CopyQ中,比如todo 、临时笔记等,使用时直接粘贴即可。

结语

这篇文章只是CopyQ的冰山一角,还有更多神奇的功能等待你去发现。三人行必有我师,如果你有其他提高效率的小技巧或工具,欢迎在评论区分享。

用效率工具,享牛马人生!

公众号: 陌上花kai

0%