季兴 发布的文章

需求如下,产品团队高频要求翻译团队给出符合标准的翻译件,比如翻译产品文档,其中又有大量的术语,比如3D结构光、扫码头、主屏、客显屏、立式等(在公司内有统一的标准叫法),使用市面通用的翻译产品需要自己修改。看效果
翻译效果.jpg

原理如图
Retrieval.png

openai负责文档Retrieval,flowise负责功能补充,同时做了一次封装,gradio负责提供展示页面,方便用户交互

gradio_run.py

import gradio as gr
import requests
import json

def call_api(question):
    url = "https://xxxx.com/api/v1/prediction/asdasce1-5a7b-4d9e-9ed6-21a9aaaab2"
    headers = {"Content-Type": "application/json"}
    data = {"question": question}
    response = requests.post(url, headers=headers, data=json.dumps(data))
    return response.json().get("text", "No response text found.")

iface = gr.Interface(
    fn=call_api,
    inputs="text",
    outputs="text",
)

iface.launch()

一直有个需求,企业内私有知识库RAG,“陪产假怎么申请?”,“公司发票抬头是啥?”等问题,解放行政、人事的部分人力。偶然发现钉钉“智能员工”非常契合。零代码开发、配置简单。看效果,支持单聊群聊。目前免费!
RAG-01.jpg
RAG-02.jpg

配置方式,登录钉钉开发者-数字员工,类似flowise编辑langchain的每个环节,别担心,有模板只需要简单修改!在知识库贴钉文档的链接。文档准备需要注意以下几点

  1. 主题、内容紧密相关
  2. 段落清晰,一段文字不超过500字,长文本可以拆成多段
  3. QA优先级最高
  4. 用标准中文,反对“互联网黑话”
  5. 单文件不超10mb
  6. 通义模型基于中文,中文提示词效果更好
  7. 温度尽可能低,0.1

钉钉AI.jpg

产品名: No English - 不学英语 https://chat.openai.com/g/g-kkrKOWa1E-no-english

产品概览: No English - 您的个人化英语学习伙伴

产品定位:
在语言学习的长河中,No English 站在了技术与教育的交汇点,提供了一个创新的、用户友好的英语学习解决方案。我们的平台运用最新的人工智能技术,致力于提升英语学习效率,同时保持学习过程的趣味性和参与度。

核心功能:

  1. 每日单词学习: 我们的系统每天精选实用词汇,配以例句和上下文,确保用户不仅记住单词,而且理解其应用。
  2. 定制化复习计划: 基于先进的记忆算法,No English 会提供个性化的复习计划,帮助用户巩固记忆,减少遗忘。
  3. 每日英语句型: 别名:"每天学点装比词汇😄 ",从日常对话到商务沟通,我们提供广泛的句型训练,以强化用户的实际应用能力。
  4. 学习动力激励: 别名:“今天踏马不想学了😕”,针对学习疲劳的用户,No English 提供及时的正能量和学习建议,激发学习激情。

知识资源库:
No English 配备了一系列的英语学习文件,涵盖商务英语和各类英语测试标准,如TEM-8、CET-4和CET-6,可供用户根据个人需要下载并学习。

技术能力:

  • 网页浏览: 无缝接入互联网资源,支持用户在学习中实时查询和获取信息。
  • DALL·E图像生成: 利用尖端的图像生成技术,为学习内容添加视觉元素,提高记忆点。
  • 代码解释器: 高级代码解释功能,为用户提供编程学习中的实时反馈。

用户动作与互动:
用户询问当日新闻时,会从指定接口请求,本app使用京东的汇聚新闻接口。

使用推荐:
No English 针对希望在移动设备上学习的用户进行了优化设计,特别推荐使用手机应用来体验我们的语音互动特性,这能够为用户提供更加沉浸式的学习环境。 手机端前两天还支持,现在已经不行了

app.jpg
app2.jpg

  1. GPT-4 Turbo模型登场,将上下文长度提升至128k,知识库更新到2023年4月!
  2. function call 提供线性调用
  3. 新增“seed” parameter,确保模型每次返回固定答案!
  4. 原生支持基于文档的知识“投喂”
  5. TTS中的所有音色都提供API
  6. 多模态,同一会话中集成dalle、Advanced Data Analysis、插件等
  7. GPT4支持微调,响应更快,费用更低
  8. 预示AI将能执行愈加复杂的任务,全民“技术平权”的时代到来

相信大家或多或少体验过大模型的魅力,有一定门槛的chatGPT(包含各种套壳的chat_bot),还有文心、通义千问等等。我总结有以下小缺陷

  1. 知识库有截止时间,比如GPT当前在21年9月
  2. 生成代码场景需要在本地手动执行、验证,反复贴报错最终得到一份可用的代码
  3. 无法理解私域任务,比如你们公司每天要做服务器安全巡检
  4. 准确度,在一些计算场景会乱答

打个比方大模型是大脑,AI agent给了模型“双手”。常见的autoGPT、babyGPT、本文介绍来自微软的autogen (https://microsoft.github.io/autogen/)
autogen官网.jpg

代码执行
先看效果,“请求https://www.baidu.com 50次,2秒间隔,记录每次的状态码、网络延迟,结果记录下来。并且生成图片,保存到当前目录下”

- 阅读剩余部分 -

近期在尝试大数据在企业内的应用,两个需求:

  • 用户输入自然语言后返回代码模版,最好能够进一步推理
  • 用户输入自然语言返回给定答案,不要扩展

两种方向:向量库+大模型、模型微调。
方向选择.jpg

以下给出openai模型微调的详细过程,目前官方推荐gpt-3.5-turbo,gpt4的微调将在年底推出

  • 数据预处理:准备至少10条数据,质量越高且数量越多,效果越好。如果没有就人工老老实实的标记几十条高质量数据,比大量低质数据更好。格式如下
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}

我的数据源是csv,第一列问题,第二列答案,用以下脚本处理

import pandas as pd
import json


def convert_csv_to_jsonl(input_csv, output_jsonl):
    # Read the CSV file
    df = pd.read_csv(input_csv)

    with open(output_jsonl, 'w', encoding='utf-8') as f:
        for _, row in df.iterrows():
            jsonl_data = {
                "messages": [
                    {"role": "system", "content": "SunSun is an internal knowledge base communication robot."},
                    {"role": "user", "content": row['Generated Questions']},
                    {"role": "assistant", "content": row['source']}
                ]
            }
            f.write(json.dumps(jsonl_data, ensure_ascii=False) + '\n')


# Usage
# convert_csv_to_jsonl('path_to_your_csv_file.csv', 'desired_output_file.jsonl')
if __name__ == "__main__":
    convert_csv_to_jsonl('/Users/jixing/Downloads/export_result0925.csv',
                         '/Users/jixing/Downloads/export_result0925.jsonl')
  • 上传文件至openai
import openai

# 替换你的key
openai.api_key = "sk-40LIdYxxxxxxx"
training_file = openai.File.create(
    file=open("export_result0925.jsonl", "rb"),
    purpose='fine-tune'
)
# 记录文件id,下一步需要使用
print(training_file.id)
  • 开始微调
import openai

# 你的key
openai.api_key = "sk-40LIdYIwxxxxx"

# 刚才的文件id
openai.FineTuningJob.create(training_file="file-0ACDKAM7xxxxxx", model="gpt-3.5-turbo")

    最近在看大模型和运维行业的关联,初步想法是标记监控数据,配合混沌工程,给出故障数据进行多元线性回归,根据最佳曲线来预测故障。实际进行过程中发现困难重重,还在尝试标记数据。
    最近有个很火的词儿叫“数字孪生”,又叫数字骨灰盒:),大意是通过大量的文字痕迹训练已有模型,让模型从“扮演”到“重塑”你。受启发于 https://greatdk.com/1908.html,并做了些许优化,效果还是挺好玩的,或许这才是数字世界的你?!😄

看疗效
微调前1.jpg微调前2.jpg!微调.jpg
思路步骤:

  • 使用wechatExporter导出微信聊天记录,纯文本格式
  • 手动挑选适合训练的数据,对聊天记录众多的群聊进行排除
  • 自动数据清洗,合并聊天记录,记录历史
  • 使用ChatGLM2进行微调、推演
  • 启动web_demo就可以体验了😄

优化项目:

  • 兼容一问一答外,大多数人的聊天习惯是连续发出多条信息,当然我们回消息也可能是多条。比如张三问,1明天有空没? 2我想找你喝点 3别带媳妇,我回复:1有呀 2必须喝白的 3当然不带 4哈哈哈。我做了合并最终效果,
    {"prompt": "明天有空没?,我想找你喝点,别带媳妇", "response": "有呀,必须喝白的,当然不带,哈哈哈", "history": []}
  • 保留历史会话,沟通都是有上下文的,我这里简单粗暴的认为当天的会话都有关联,记录在history中
    {"prompt": "我去找你?", "response": "你开车了没", "history": [["?", "?"], ["忙完了", "怎么说"], ["吃饭打台球?", "行"]]}

python清洗脚本

import os
import re
import json

# 定义源文件夹和目标文件
source_folder = '/Users/jixing/Downloads/wechat_history'
output_file_path = '/Users/jixing/Downloads/0811output.txt'


# Regular expression patterns for extracting dates, usernames, and messages
date_pattern = re.compile(r"\((\d{4}-\d{2}-\d{2}) \d{2}:\d{2}:\d{2}\)")
user_msg_pattern = re.compile(r"^(.+?) \(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\):(.+)$")

# 遍历文件夹中的所有.txt文件
for filename in os.listdir(source_folder):
    if filename.endswith('.txt'):
        with open(os.path.join(source_folder, filename), 'r', encoding='utf-8') as source_file:
            content = source_file.readlines()

            # Parsing the chat data
            conversations = []
            current_date = None
            current_convo = []
            for line in content:
                # Check for date
                date_match = date_pattern.search(line)
                if date_match:
                    date = date_match.group(1)
                    if current_date != date and current_convo:
                        conversations.append(current_convo)
                        current_convo = []
                    current_date = date

                # Extracting user and message
                user_msg_match = user_msg_pattern.match(line)
                if user_msg_match:
                    user, msg = user_msg_match.groups()
                    if current_convo and current_convo[-1][0] == user:
                        current_convo[-1][5] += f",{msg.strip()}"
                    else:
                        current_convo.append([user, msg.strip()])

            # Adding the last conversation if any
            if current_convo:
                conversations.append(current_convo)

            # Formatting conversations
            adjusted_conversations = []
            for convo in conversations:
                history = []
                for i in range(0, len(convo) - 1, 2):  # Increment by 2 to ensure one question and one answer
                    prompt = convo[i][6]
                    response = convo[i + 1][7] if i + 1 < len(convo) else None
                    if response:  # Only add to the list if there's a response
                        adjusted_conversations.append({
                            "prompt": prompt,
                            "response": response,
                            "history": history.copy()
                        })
                        history.append([prompt, response])

            # Appending the results to output.txt, one object per line
            with open(output_file_path, 'a', encoding='utf-8') as output_file:
                for convo in adjusted_conversations:
                    json.dump(convo, output_file, ensure_ascii=False)
                    output_file.write('\n')

清洗后数据,可以看到已经有非常完整的逻辑关系了
cleaned_data.jpg

我在训练时使用了70%的训练集,30%作为测试集。3000条数据在我的2080显卡需要10小时!都去试试看效果吧:)

OPA是一种开源通用策略引擎,可在整个堆栈中实现统一的、上下文感知的策略实施。该项目于2018年4月被CNCF沙箱接受,2021年2月4日正式毕业于CNCF。来自大约 30 个组织的 90 多人为 OPA 做出了贡献,维护者来自包括 Google、Microsoft、VMware 和 Styra。

简单来说,是在服务上抽象一层,统一控制、审计,本文讨论仅限在Kubernetes中的gatekeeper,对容器创建进行安全约束,确保符合运维规范。

opa-gatekeeper.png

  1. 安装过程略 https://www.openpolicyagent.org/docs/latest/kubernetes-introduction/
  2. 文件结构,规则、范围一一对应。例:default命名空间必须设置探针,规则名 k8srequiredprobes.yaml ,应用范围名 default_ns_must_have_probes.yaml

- 阅读剩余部分 -

上次的数据库故障余波未平。老服务整改周期内仍有可能增高,有没什么方法限制单个pod只能建立一定数量的数据库连接,把事故控制在一定范围内

  • 首先是数据库层面,可以在配置文件中限制连接数,但基于容器的环境IP会有变化 pass
  • 其次想到的是服务网格,因为是业务标配+出色的流量控制,应该可以从这里入手。看了圈文档,Istio更多关注的是进方向
  • 再次想到kubernetes本身的网络插件也有限流的功能,calico具备对进出方向端口的限制,但没找到连接数的

陷入僵局,最笨用iptables限制,但还能实时发现pod的重启更换IP,难道要复杂化,监控结合脚本的方式吗?忽然灵光一闪,initContainers阶段不是可以做很多事情嘛

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  initContainers:
  - name: init-iptables
    image: my-iptables-image
    command: ['sh', '-c', 'iptables -A OUTPUT -p tcp --dport 3306 -m connlimit --connlimit-above 20 -j REJECT']
  containers:
  - name: my-container
    image: my-image

😅未验证,原理可行- -

某日读写分离中间件报警,有大量非业务IP连接涌入,新连接无法建立。查询数据库连接有大量的”unauthenticated user 1.2.3.4:37414 NULL Connect NULL Reading from net NULL”。一时间大量用户报障,“登录失效”、“设备断连”、“影响产线生产”等等
解决过程倒不复杂,跳过中间件恢复。售后工程师承认是中间件设计问题,释放连接逻辑bug,也提到了有大量连接时可能触发!

反观自身,架构设计阶段把过多的压力放在主库,19年上线的读写分离中间件就是“业务迭代优先,没时间基础设施改造”、“历史包袱”背景下的缓兵之计。阿里云的问题有几点
1.中间件控制台无法显示真实IP,故障后对方研发回复“日志因升级规格消失?”
2.假死后控制台无法重启
3.控制台监控不准确,使用者无法准确选择
4.1.2版本释放连接逻辑bug
主因是内部某服务突然建立了大量连接,进而引发的故障。

  • 开发阶段的考虑对运维阶段的影响:

开发阶段把更多的重点放在功能实现和业务迭代上,而忽略了基础设施的可扩展性。这可能会造成短期内的业务顺利进行,但长期看来,如果基础设施不能跟上业务的发展,最终可能会形成技术债务,导致在运维阶段遇到无法解决或者处理复杂度高的问题。

  • 对云服务商SLA的信任问题:

云服务提供商的SLA(服务等级协议)是我们选择使用其服务的一个重要依据,但是是否100%信任SLA,我们需要结合自身的业务情况和对服务提供商的了解来决定。在应急情况下,我们可能需要更具备自主的故障应对能力,而不是完全依赖服务提供商的SLA。