使用ollama快速本地集成deepseek并构建你的知识库
前置条件
ollama
安装地址:github.com/ollama/olla…
安装完成后可以通过ollama run model启动相应模型,如下常用模型
| 模型 | 参数 | 大小 | 运行命令 |
|---|---|---|---|
| DeepSeek-R1 | 7B | 4.7GB | ollama run deepseek-r1 |
| DeepSeek-R1 | 671B | 404GB | ollama run deepseek-r1:671b |
| Llama 3.3 | 70B | 43GB | ollama run llama3.3 |
| Llama 3.2 | 3B | 2.0GB | ollama run llama3.2 |
| Llama 3.2 | 1B | 1.3GB | ollama run llama3.2:1b |
| Llama 3.2 Vision | 11B | 7.9GB | ollama run llama3.2-vision |
具体的模型列表可参见:ollama.com/library
docker
安装地址:www.docker.com/get-started…
知识库构建
环境准备
这里我们使用mongo存储员工薪资数据,调用ollama实现问答 使用dokcer启动一个mongo容器
docker run -d --name mongo \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=admin \
-p 27017:27017 \
mongo
使用ollama运行deepseek-r1,本地部署会占用端口11434
ollama run deepseek-r1:7b
模拟数据
生成相应的json数据,存储在文件中,在init中将文件写入mongo
✅ MongoDB 连接成功!
✅ JSON 数据已生成!
✅ employees 集合已清空
✅ 员工数据已成功写入 MongoDB!
查询数据
查询数据并且按切片返回
func queryEmployees() ([]string, error) {
collection := mongoClient.Database("company").Collection("employees")
// 查询所有员工
cursor, err := collection.Find(context.TODO(), bson.M{})
if err != nil {
return nil, fmt.Errorf("查询 MongoDB 失败: %v", err)
}
defer cursor.Close(context.TODO())
var results []string
for cursor.Next(context.TODO()) {
var emp Employee
if err := cursor.Decode(&emp); err != nil {
return nil, fmt.Errorf("解码失败: %v", err)
}
// 格式化员工信息为字符串
empStr := fmt.Sprintf("ID: %d, 姓名: %s, 年龄: %d, 性别: %s, 薪资: %.2f",
emp.ID, emp.Name, emp.Age, emp.Gender, emp.Salary)
results = append(results, empStr)
}
// 检查游标错误
if err := cursor.Err(); err != nil {
return nil, fmt.Errorf("遍历游标失败: %v", err)
}
return results, nil
}
调用模型回答问题
func TestLocalDeepSeek(t *testing.T) {
// 查询 MongoDB 中的数据
data, err := queryEmployees()
if err != nil {
log.Fatal("查询 MongoDB 失败:", err)
}
//构建消息
messages := []llms.MessageContent{}
messages = append(messages, llms.MessageContent{
Role: llms.ChatMessageTypeSystem,
Parts: []llms.ContentPart{llms.TextContent{backGround}},
})
for _, s := range data {
messages = append(messages, llms.MessageContent{
Role: llms.ChatMessageTypeSystem,
Parts: []llms.ContentPart{llms.TextContent{s}},
})
}
question := "20-30岁员工中,薪资最高和最低的分别是谁?"
messages = append(messages, llms.MessageContent{
Role: llms.ChatMessageTypeHuman,
Parts: []llms.ContentPart{llms.TextContent{question}},
})
ctx := context.Background()
answer, err := deepSeek.GenerateContent(ctx, messages)
if err != nil {
log.Fatal("deepseek err:", err)
}
choices := answer.Choices
for i := 0; i < len(choices); i++ {
log.Fatal(choices[i].Content)
}
}
效果如下,根据查询的内容,给出了正确的答案
完整代码
package deepseek
import (
"context"
"encoding/json"
"fmt"
"github.com/tmc/langchaingo/llms"
"github.com/tmc/langchaingo/llms/ollama"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"log"
"os"
"testing"
)
// Employee 结构体
type Employee struct {
ID int `json:"id" bson:"id"`
Name string `json:"name" bson:"name"`
Age int `json:"age" bson:"age"`
Gender string `json:"gender" bson:"gender"`
Salary float64 `json:"salary" bson:"salary"`
}
var mongoClient *mongo.Client
var deepSeek *ollama.LLM
var backGround = "你是一个ai助手, 请根据给定的内容回答问题, 直接给出最终的答案,不要给出思考过程"
// init 初始化 MongoDB deepseek
func init() {
var err error
mongoURI := "mongodb://admin:admin@localhost:27017/?authSource=admin" //docker启动时设置用户密码
clientOptions := options.Client().ApplyURI(mongoURI)
// 连接 MongoDB
mongoClient, err = mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal("MongoDB 连接失败:", err)
}
// 检查连接
err = mongoClient.Ping(context.TODO(), nil)
if err != nil {
log.Fatal("无法连接到 MongoDB:", err)
}
fmt.Println("✅ MongoDB 连接成功!")
err = mockData()
if err != nil {
log.Fatal("写入 MongoDB 失败:", err)
}
model := "deepseek-r1:7b"
deepSeekUrl := "http://127.0.0.1:11434"
deepSeek, err = ollama.New(ollama.WithModel(model), ollama.WithServerURL(deepSeekUrl))
if err != nil {
log.Fatal("初始化DeepSeek失败:", err)
}
_, err = deepSeek.CreateEmbedding(context.Background(), []string{backGround})
if err != nil {
log.Fatal("无法连接DeepSeek:", err)
}
fmt.Println("✅ DeepSeek 初始化连接成功!")
}
// generateJSON 生成 JSON 数据并保存到文件
func generateJSON(filename string) error {
employees := []Employee{
{ID: 1, Name: "Alice", Age: 30, Gender: "Female", Salary: 80000},
{ID: 2, Name: "Bob", Age: 35, Gender: "Male", Salary: 90000},
{ID: 3, Name: "Charlie", Age: 40, Gender: "Male", Salary: 100000},
{ID: 4, Name: "Diana", Age: 28, Gender: "Female", Salary: 75000},
{ID: 5, Name: "Ethan", Age: 32, Gender: "Male", Salary: 85000},
{ID: 6, Name: "Jhon", Age: 27, Gender: "Male", Salary: 12000},
{ID: 7, Name: "Mike", Age: 21, Gender: "Male", Salary: 5000},
{ID: 8, Name: "Heinz", Age: 28, Gender: "Male", Salary: 100000},
{ID: 9, Name: "Adolf", Age: 27, Gender: "Male", Salary: 88000},
{ID: 10, Name: "Rudolf", Age: 26, Gender: "Male", Salary: 89000},
}
// 转换为 JSON 并写入文件
data, err := json.MarshalIndent(employees, "", " ")
if err != nil {
return err
}
return os.WriteFile(filename, data, 0644)
}
// readAndInsertToMongo 读取 JSON 并插入 MongoDB
func readAndInsertToMongo(filename string) error {
// 读取 JSON 文件
data, err := os.ReadFile(filename)
if err != nil {
return err
}
var employees []Employee
err = json.Unmarshal(data, &employees)
if err != nil {
return err
}
// 选择数据库和集合
collection := mongoClient.Database("company").Collection("employees")
// 清空 employees 集合
_, err = collection.DeleteMany(context.TODO(), bson.M{})
if err != nil {
return fmt.Errorf("清空 employees 失败: %v", err)
}
fmt.Println("✅ employees 集合已清空")
// 将数据插入 MongoDB
var docs []interface{}
for _, emp := range employees {
docs = append(docs, emp)
}
_, err = collection.InsertMany(context.TODO(), docs)
if err != nil {
return err
}
fmt.Println("✅ 员工数据已成功写入 MongoDB!")
return nil
}
// mockData 写入数据
func mockData() error {
jsonFile := "employees.json"
// 生成 JSON 数据
err := generateJSON(jsonFile)
if err != nil {
log.Fatal("生成 JSON 失败:", err)
}
fmt.Println("✅ JSON 数据已生成!")
// 读取 JSON 并写入 MongoDB
err = readAndInsertToMongo(jsonFile)
if err != nil {
log.Fatal("写入 MongoDB 失败:", err)
}
return err
}
// queryEmployees 查询 MongoDB 中的员工数据
func queryEmployees() ([]string, error) {
collection := mongoClient.Database("company").Collection("employees")
// 查询所有员工
cursor, err := collection.Find(context.TODO(), bson.M{})
if err != nil {
return nil, fmt.Errorf("查询 MongoDB 失败: %v", err)
}
defer cursor.Close(context.TODO())
var results []string
for cursor.Next(context.TODO()) {
var emp Employee
if err := cursor.Decode(&emp); err != nil {
return nil, fmt.Errorf("解码失败: %v", err)
}
// 格式化员工信息为字符串
empStr := fmt.Sprintf("ID: %d, 姓名: %s, 年龄: %d, 性别: %s, 薪资: %.2f",
emp.ID, emp.Name, emp.Age, emp.Gender, emp.Salary)
results = append(results, empStr)
}
// 检查游标错误
if err := cursor.Err(); err != nil {
return nil, fmt.Errorf("遍历游标失败: %v", err)
}
return results, nil
}
func TestLocalDeepSeek(t *testing.T) {
// 查询 MongoDB 中的数据
data, err := queryEmployees()
if err != nil {
log.Fatal("查询 MongoDB 失败:", err)
}
//构建消息
messages := []llms.MessageContent{}
messages = append(messages, llms.MessageContent{
Role: llms.ChatMessageTypeSystem,
Parts: []llms.ContentPart{llms.TextContent{backGround}},
})
for _, s := range data {
messages = append(messages, llms.MessageContent{
Role: llms.ChatMessageTypeSystem,
Parts: []llms.ContentPart{llms.TextContent{s}},
})
}
question := "20-30岁员工中,薪资最高和最低的分别是谁?"
messages = append(messages, llms.MessageContent{
Role: llms.ChatMessageTypeHuman,
Parts: []llms.ContentPart{llms.TextContent{question}},
})
ctx := context.Background()
answer, err := deepSeek.GenerateContent(ctx, messages)
if err != nil {
log.Fatal("deepseek err:", err)
}
choices := answer.Choices
for i := 0; i < len(choices); i++ {
log.Fatal(choices[i].Content)
}
}