magic 发布的文章

2天后收入对比

数据已经有了基础网站后,google 隔天就可以查询到网站的关于页面
Xnip2024-09-18_10-27-19.jpg

而baidu还显示1年前的内容
Xnip2024-09-18_10-28-08.jpg

没有显示收录网页的日期,预计是个死火山,从不喷发

搜索引擎已经被玩出花了

官网认证:3000/年(标准版)

企业名片:3600/年(标准版)

商标认证:上传企业经营信息,展示企业品牌形象 2000元/年

搜索引擎作为信息时代的核心工具,互联网一个公共信息资源,国内普通乡村孩子查询资料的几乎唯一引擎, 竟然把信息分为三六九等,造成认知偏差。

1. 信息获取的不平等

  • 优质资源受限:如果搜索引擎优先展示某些类型的信息,而乡村孩子可能无法接触到这些优质资源,导致他们在学习过程中缺乏必要的支持。
  • 信息偏见:搜索引擎的排序算法可能会偏向于某些城市或发达地区的信息,导致乡村孩子接触到的信息存在偏见,影响他们的认知和判断。

2. 教育资源的匮乏

  • 教育资源不均衡:乡村地区的教育资源本身就相对匮乏,如果搜索引擎进一步限制了优质教育资源的获取,乡村孩子的学习机会将更加受限。
  • 学习工具受限:乡村孩子可能无法接触到最新的学习工具和资源,如在线课程、教育软件等,影响他们的学习效果和兴趣。

3. 知识获取的局限性

  • 知识面狭窄:搜索引擎的信息分级可能导致乡村孩子接触到的知识面更加狭窄,无法全面了解各个领域的知识,影响他们的综合素质发展。
  • 创新能力受限:知识获取的局限性可能会限制乡村孩子的创新能力和思维方式,使他们在未来的竞争中处于不利地位。

4. 心理影响

  • 自信心受挫:如果乡村孩子发现自己无法获取与城市孩子同等质量的信息和资源,可能会产生自卑感,影响他们的自信心和学习动力。
  • 社会认知偏差:信息的不平等可能导致乡村孩子对社会的认知存在偏差,影响他们的人生观和价值观。

5. 社会流动性的阻碍

  • 机会不平等:信息的不平等可能导致乡村孩子在升学、就业等方面面临更多挑战,阻碍他们的社会流动性,影响他们的未来发展。
  • 代际传递:信息的不平等可能会导致贫困的代际传递,使乡村孩子难以摆脱贫困的循环。

6. 教育公平性的破坏

  • 教育公平受损:搜索引擎的信息分级可能会加剧城乡教育的不公平,使乡村孩子在教育资源和机会上更加落后,违背了教育公平的原则。
  • 社会不公:信息的不平等可能会导致社会不公,影响社会的和谐与稳定。

baidu提交链接

主要是快速收录工具,这个工具是收费的,其他提交几乎是徒劳,哪怕这个工具,2024年 又提高了门槛,升级为快速抓取

Xnip2024-09-18_10-41-55.jpg

快速抓取,需要升级VIP俱乐部,搜索资源平台VIP俱乐部 申请规则

Xnip2024-09-18_10-24-32.jpg

其中对日均流量有限制,也就是低于多少访问的资料,不应该出现在社会上。导致信息多样化减少,阻碍社会进步,再次内卷加重,例如青霉素等科学研究,当年都是从一些小众资料出来的,如果社会只有今天哪个明星带货,谁又演唱会,哪个小区门口又出现恶犬,哪只猫咪又成为网红猫,都是一些引流的话题网站,对社会进步是一个损失。 社会也只是国内社会的损失,像海外一些引擎,信息资料不分高地贵贱之分,才能更好的提供社会科技进步

这个是AI对社会信息资源区分贵贱的说明

1. 信息多样性的减少

  • 小众信息缺失:低流量网站通常包含一些小众、特定领域的信息,如地方新闻、社区活动、非主流观点等。如果这些网站不被收录,这些信息将难以被公众获取,导致信息多样性的减少。
  • 长尾信息流失:搜索引擎的“长尾效应”指的是大量低流量但有价值的信息。如果这些信息不被收录,用户将难以找到那些不常见但有用的信息。

2. 社会资源的浪费

  • 内容创作者的积极性受挫:许多低流量网站是由个人或小型组织创建的,他们可能投入了大量时间和精力来创作内容。如果这些内容不被搜索引擎收录,创作者的积极性可能会受到打击,导致社会资源的浪费。
  • 知识积累的损失:低流量网站可能包含一些独特的知识、经验或研究成果,如果这些内容不被收录,这些知识将难以积累和传播,影响社会的知识储备。

3. 社会透明度的降低

  • 地方信息的缺失:许多低流量网站提供地方新闻、社区活动、地方政策等信息,这些信息对于当地居民非常重要。如果这些网站不被收录,地方信息的透明度将降低,影响居民的知情权和参与度。
  • 非主流观点的消失:低流量网站可能包含一些非主流观点、独立研究或批判性分析,这些信息对于社会的多元化和批判性思维非常重要。如果这些信息不被收录,社会的思想多样性将受到影响。

4. 教育资源的匮乏

  • 教育资源的分散:许多低流量网站提供教育资源,如在线课程、学习资料、教学视频等。如果这些网站不被收录,学生和教师将难以找到这些资源,影响教育资源的普及和利用。
  • 自学机会的减少:低流量网站可能包含一些自学资源,如编程教程、艺术指导、语言学习等。如果这些资源不被收录,自学者的学习机会将减少,影响终身学习的发展。

5. 创新能力的限制

  • 创新信息的流失:许多低流量网站包含创新信息,如新技术、新产品、新商业模式等。如果这些信息不被收录,创新者将难以获取这些信息,影响创新能力的提升。
  • 创业支持的减少:低流量网站可能提供创业支持,如市场调研、行业分析、创业指导等。如果这些信息不被收录,创业者将难以找到这些支持,影响创业生态的发展。

6. 社会信任的下降

  • 信息可信度的降低:如果搜索引擎只收录高流量网站,用户可能会认为这些信息更可信,而忽视其他来源的信息。这种偏见可能导致社会对信息的信任度下降,影响社会的整体信任水平。
  • 信息垄断的风险:搜索引擎对低流量网站的不收录可能导致信息垄断,少数高流量网站控制了大部分信息资源,影响信息的公平获取和传播。

baidu 后台只要不是付费功能也是经常有问题

例如一个https 检测,按理几秒就可以检测出来,如果每天上亿的网址需要判断,也不会超过1天,提示说一天内,然而后台显示目前已经过去了5天
Xnip2024-09-18_11-03-42.jpg

博客数据单节点,防止数据丢失,这里写一个shell脚本,几小时执行一次,保留7天数据

简单的 MySQL 备份 Shell 脚本,它会备份指定的数据库,并将备份文件保留最近 7 天的数据。脚本会每天运行一次,删除超过 7 天的备份文件。

脚本内容

#!/bin/bash

# 配置数据库信息
DB_USER="your_db_user"
DB_PASSWORD="your_db_password"
DB_NAME="your_db_name"
BACKUP_DIR="/path/to/backup/directory"
DATE=$(date +%Y%m%d)

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份数据库
mysqldump -u $DB_USER -p$DB_PASSWORD $DB_NAME > $BACKUP_DIR/$DB_NAME-$DATE.sql

# 压缩备份文件
gzip $BACKUP_DIR/$DB_NAME-$DATE.sql

# 删除超过 7 天的备份文件
find $BACKUP_DIR -type f -name "*.sql.gz" -mtime +7 -exec rm -f {} \;

echo "Database backup completed: $BACKUP_DIR/$DB_NAME-$DATE.sql.gz"

解释

  1. 配置数据库信息

    • DB_USER:数据库用户名。
    • DB_PASSWORD:数据库密码。
    • DB_NAME:要备份的数据库名称。
    • BACKUP_DIR:备份文件存储的目录。
    • DATE:当前日期,格式为 YYYYMMDD
  2. 创建备份目录

    • mkdir -p $BACKUP_DIR:如果备份目录不存在,则创建它。
  3. 备份数据库

    • mysqldump -u $DB_USER -p$DB_PASSWORD $DB_NAME > $BACKUP_DIR/$DB_NAME-$DATE.sql:使用 mysqldump 命令备份数据库,并将备份文件保存到指定目录。
  4. 压缩备份文件

    • gzip $BACKUP_DIR/$DB_NAME-$DATE.sql:使用 gzip 命令压缩备份文件。
  5. 删除超过 7 天的备份文件

    • find $BACKUP_DIR -type f -name "*.sql.gz" -mtime +7 -exec rm -f {} \;:使用 find 命令查找并删除超过 7 天的备份文件。
  6. 输出备份完成信息

    • echo "Database backup completed: $BACKUP_DIR/$DB_NAME-$DATE.sql.gz":输出备份完成信息。

设置定时任务

你可以使用 cron 来设置每天自动运行这个脚本。

  1. 打开 cron 编辑器:

    bash

    复制

    crontab -e
  2. 添加以下行来设置每天凌晨 2 点运行备份脚本:

    bash

    复制

    0 2 * * * /path/to/your/backup_script.sh

总结

通过这个脚本,你可以每天自动备份 MySQL 数据库,并保留最近 7 天的备份文件。超过 7 天的备份文件会被自动删除,以节省存储空间。

最近开发了基于CHATGPT的AI给开发者使用,通过设置一些有趣的prompt 可以有一些很好的玩法,但在长期的使用过程中遇到一些问题,需要解决。

正好发现目前关于向量数据库的搭建开发资料极度稀缺,更没完整的教程,准备把这次开发过程记录下来。

普通AI遇到的问题
1.token超标,为了能让AI回复客户问题,有连续性,AI理解上面已经答过的问题,我们会把用户的每次回复都传给chatGPT,当连续交互几次,会出现次数过多,或者字数超出触发chatGPT的警告

chatGPT错误内容

2.记忆力失去,例如在10个会话前,我告诉AI,你是小美,等10次会话后,我再问AI,你叫啥,他不知道

3.放飞自我,有时候一些回答跟我们问的问题毫无相关,放飞自我。

4.学习能力,例如AI我问他一些最近微信小程序开发的规则,他是无法知道的,或者问某个大公司今年的财报等等,一些较新的内容。

5.私有文库能力,例如我们某汽车公司有一份产品使用说明,可能几千页,当我们遇到这款汽车遇到某个故障,想跟客服人员一样,立刻得到正确的结果,chatGPT是很难回答正确。

解决方案:向量数据库
遇到这些问题,行业里的解决方案就是使用向量数据库,向量数据库在图像搜索、自然语言处理、推荐系统已经非常成熟。 与传统的数据库(关系、非关系数据库)相比,你可以理解为传统数据库主要记录数据,而向量数据库主要记录特征,既然是特征这也就是说他很少会用到完全匹配说法,核心概念就是相似的特征,相似比例多少,想象目前行业的应用图片搜索,推荐系统是否都是搜索相似性特性。

向量数据库选择,Milvus、Zilliz、pinecone、腾讯云、阿里云,除了腾讯云的2023年08月发布,其他的都可以使用了。为了降低成本,我们就自己搭建Milvus,接下来教程也会教一步一步搭建Milvus向量数据库。

主要的场景

  • 搜索(其中结果按与查询字符串的相关性排序)
  • 聚类(其中文本字符串按相似性分组)
  • 建议(推荐带有相关文本字符串的项目)
  • 异常检测(识别出关系很小的异常值)
  • 多样性测量(分析相似性分布)
  • 分类(其中文本字符串按其最相似的标签进行分类)

我们这次用的是搜索场景

初步设想代码实现过程

整体实现思路
接下来的文章,基本会按照这个思路来逐步实现最终结果。

1. 安装和配置Milvus:

Milvus是一个开源向量数据库,用于存储和检索高维向量。首先,需要安装并配置Milvus,以便将知识库中的文本转换为向量,并能够高效地检索相关的信息。

这里会涉及到Milvus的使用,增删改查,Milvus相关工具的使用教程

2. 构建本地知识库:

创建一个本地知识库,其中包含问题和对应的答案。每个问题都应该有一个唯一的ID,并且答案可以是任何形式的文本。

本地文件处理,PDF切个,文件投喂AI,拿到向量值,写入数据库

3. 使用Golang开发问答系统的后端:

在Golang中编写一个后端服务,用于接收用户的问题,并通过ChatGPT和Milvus来查找最合适的答案。

实现第二步的后端代码

4. 集成ChatGPT API:

使用OpenAI的ChatGPT API,将用户的问题传递给ChatGPT模型,以获取对应的回答。你可以通过发送HTTP请求到ChatGPT API来实现这一点,我使用的模型是text-embedding-ada-002

拿到最终prompt 去跟AI提问

5. 文本向量化:

当用户提出问题时,需要对该问题进行向量化,以便与知识库中的问题向量进行匹配。使用ChatGPT模型的词嵌入(Word Embeddings)来将问题转换为向量。

使用chatGPT 的text-embedding-ada-002模型来把文档变成向量值

6. 利用Milvus进行快速检索:

将所有知识库中的问题向量加载到Milvus中,并设置适当的索引以加快检索速度。当用户提问时,将向量化的问题与Milvus中的向量进行相似度匹配,找到最相似的问题。

用户问题,先查询Milvus

7. 返回答案:

通过ChatGPT获得的回答可能不是最终的答案,因为ChatGPT是一个生成式模型,它可以自由生成文本。将ChatGPT生成的回答与Milvus中找到的答案结合起来,然后将最终的答案返回给用户。

8. 错误处理和反馈:

考虑到ChatGPT可能会产生错误的回答,实现一些错误处理机制,例如询问用户是否满意回答,并将用户的反馈用于改进系统。

9. 用户界面:

开发一个用户界面,允许用户输入问题,并从后端获取回答展示给用户。

代码流程
代码主要分为2个大流程,一个是数据训练,把客户上传的文档数据进行训练,生成特征数据保存到向量数据库,另一个用户提问搜索流程,下面是2个流程图

数据训练流程

数据查询流程

下一篇就是安装和配置Milvus,已经Milvus的使用相关问题。

上一节,我们已经把Milvus 向量数据库搭建完成,由于milvus\_cli 工具2年没更新,不是太完善,我们需要使用SDK 来操作Milvus数据库, 因为我们服务都是基于Golang 开发,这里我用Golang来测试Milvus 数据库的插入与查询以保证,代码对数据库的基本操作没问题

我们根据官方文档,自己写一个结构体 MilvusClient , 下面是完整代码

package main

import (
    "context"
    "fmt"
    "github.com/milvus-io/milvus-sdk-go/v2/client"
    "github.com/milvus-io/milvus-sdk-go/v2/entity"
    "log"
    "math/rand"
    "time"
)

// 定义 Milvus 客户端结构体
type MilvusClient struct {
    milvusClient client.Client
}

func main() {
    fmt.Println("进入main函数")

    MilvusClient, err := NewMilvusClient()
    if err != nil {
        fmt.Println("GetMilvusDb", err.Error())
        return
    }

    //MilvusClient.CreateMilvusDb()
    //MilvusClient.InsertData()
    MilvusClient.SearchResultData()
    //MilvusClient.CreateIndex()
    MilvusClient.DescribeIndex()
}

// 向量场创建一个索引
func (M *MilvusClient) CreateIndex() {

    var milvusClient = M.milvusClient
    // 创建 IndexIvfFlat 索引对象
    idx, err := entity.NewIndexIvfFlat(
        entity.L2,
        1024,
    )
    if err != nil {
        log.Fatal("fail to create ivf flat index parameter:", err.Error())
    }
    // 在 Milvus 中创建索引
    err = milvusClient.CreateIndex(
        context.Background(),
        "book",
        "book_intro",
        idx,
        false,
    )
    if err != nil {
        log.Fatal("fail to create index:", err.Error())
    }

}

// 此方法获取索引的详细信息
func (M *MilvusClient) DescribeIndex() {
    var milvusClient = M.milvusClient

    // 获取索引的详细信息
    indexInfo, err := milvusClient.DescribeIndex(
        context.Background(),
        "book",       // 指定集合名称
        "book_intro", // 指定向量字段名称
    )
    if err != nil {
        log.Fatal("fail to describe index:", err.Error())
    }
    log.Println(indexInfo)
}

// 集合加载到内存中
func (M *MilvusClient) ReleaseCollectionData() {
    var milvusClient = M.milvusClient
    // 释放集合的内存
    err := milvusClient.ReleaseCollection(
        context.Background(),
        "book",
    )
    if err != nil {
        fmt.Println("failed to release collection:", err.Error())
    }
}

// 集合加载到内存中
func (M *MilvusClient) LoadCollectionData() {

    var milvusClient = M.milvusClient

    err := milvusClient.LoadCollection(
        context.Background(),
        "book",
        false,
    )
    if err != nil {
        fmt.Println("failed to load collection:", err.Error())
    }
    fmt.Println("loading ok")
}

// 搜索数据
func (M *MilvusClient) SearchResultData() {
    var err error
    var milvusClient = M.milvusClient

    M.LoadCollectionData()

    defer M.ReleaseCollectionData()

    sp, _ := entity.NewIndexIvfFlatSearchParam( // NewIndex*SearchParam func
        2, // searchParam
    )

    searchResult, err := milvusClient.Search(
        context.Background(), // ctx
        "book",               // CollectionName
        []string{},           // partitionNames
        "",                   // expr
        []string{"book_id"},  // outputFields
        []entity.Vector{entity.FloatVector([]float32{0.1, 0.2})}, // vectors
        "book_intro", // vectorField
        entity.L2,    // metricType
        2,            // topK
        sp,           // sp
    )
    if err != nil {
        fmt.Println("failed search data:", err.Error())
    }
    fmt.Printf("%#v\n", searchResult)
    for _, sr := range searchResult {
        fmt.Println("id", sr.IDs)
        fmt.Println("Scores", sr.Scores)
    }
}

// 插入数据
func (M *MilvusClient) InsertData() {
    var err error
    var milvusClient = M.milvusClient
    bookIDs := make([]int64, 0, 2000)
    wordCounts := make([]int64, 0, 2000)
    bookIntros := make([][]float32, 0, 2000)
    for i := 0; i < 2000; i++ {
        bookIDs = append(bookIDs, int64(i))
        wordCounts = append(wordCounts, int64(i+10000))
        v := make([]float32, 0, 2)
        for j := 0; j < 2; j++ {
            v = append(v, rand.Float32())
        }
        bookIntros = append(bookIntros, v)
    }
    idColumn := entity.NewColumnInt64("book_id", bookIDs)
    wordColumn := entity.NewColumnInt64("word_count", wordCounts)
    introColumn := entity.NewColumnFloatVector("book_intro", 2, bookIntros)

    _, err = milvusClient.Insert(
        context.Background(), // ctx
        "book",               // CollectionName
        "",                   // partitionName
        idColumn,             // columnarData
        wordColumn,           // columnarData
        introColumn,          // columnarData
    )
    if err != nil {
        fmt.Println("failed to insert data:", err.Error())
        return
    }
    //fmt.Println("xxx", idColumn)
}
func (M *MilvusClient) CreateMilvusDb() {
    var err error
    var milvusClient = M.milvusClient
    var (
        collectionName = "test"
    )
    schema := &entity.Schema{
        CollectionName: collectionName,
        Description:    "Test book search",
        Fields: []*entity.Field{
            {
                Name:       "book_id",
                DataType:   entity.FieldTypeInt64,
                PrimaryKey: true,
                AutoID:     false,
            },
            {
                Name:       "word_count",
                DataType:   entity.FieldTypeInt64,
                PrimaryKey: false,
                AutoID:     false,
            },
            {
                Name:     "book_intro",
                DataType: entity.FieldTypeFloatVector,
                TypeParams: map[string]string{
                    "dim": "2",
                },
            },
        },
        EnableDynamicField: true,
    }

    err = milvusClient.CreateCollection(
        context.Background(), // ctx
        schema,
        2, // shardNum
    )
    if err != nil {
        fmt.Println("创建数据库失败:", err)
        return
    }

    defer milvusClient.Close()
}

// Milvus 客户端对象,用于连接 Milvus 服务器
func NewMilvusClient() (m *MilvusClient, err error) {
    // Milvus 服务器的地址和端口
    host := "127.0.0.1"
    port := "19530"

    // 设置超时时间为10秒
    ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
    defer cancel()

    // 创建一个 Milvus 客户端
    milvusClient, err := client.NewClient(ctx, client.Config{
        Address: fmt.Sprintf("http://%s:%s", host, port),
    })
    fmt.Println("sss")
    if err != nil {
        fmt.Println("sss", err.Error())
        fmt.Errorf("创建 Milvus 客户端失败: %v", err)
        return
    }

    // 使用 defer 语句来关闭 `milvusClient` 对象
    //defer milvusClient.Close()

    // 列出所有数据库
    dbs, err := milvusClient.ListDatabases(ctx)
    if err != nil {
        fmt.Errorf("获取数据库列表失败: %v", err)
        return
    }

    // 输出数据库列表
    fmt.Println("数据库列表:")
    for _, db := range dbs {
        fmt.Println("-", db)
    }
    var s = &MilvusClient{
        milvusClient: milvusClient,
    }

    return s, nil
}

代码的结构比较简单,主要包含一个 Milvus 客户端结构体,以及该结构体的若干方法,每个方法都对应了 Milvus SDK 中的一个操作。

上面各个方法的功能和实现

  1. NewMilvusClient: 创建 Milvus 客户端对象,用于连接 Milvus 服务器。
  2. CreateIndex: 在 Milvus 中创建索引。
  3. DescribeIndex: 获取索引的详细信息。
  4. ReleaseCollectionData: 释放集合的内存。
  5. LoadCollectionData: 加载集合数据到内存。
  6. SearchResultData: 在 Milvus 中搜索数据。

我们先创建一个表book

MilvusClient, err := NewMilvusClient()
    if err != nil {
        fmt.Println("GetMilvusDb", err.Error())
        return
    }
// 创建表结构
MilvusClient.CreateMilvusDb()

执行代码,得到效果


执行测试数据插入

MilvusClient.InsertData()

这里插入2000条数据


查询数据

我们查询向量字段book\_intro


到这里,数据库的操作基本没有什么问题,这里需要注意的是,Milvus数据库查询前需要先把数据加载到内存,查询完,释放掉内存

加载到内存
M.LoadCollectionData()

查询执行完释放内存
defer M.ReleaseCollectionData()

Golang操作Milvus基本没什么问题,下一步就是设计数据库,把向量数据写入进去。