欢迎光临
我们一直在努力

把CPU、内存、网络流量同时丢给TimechoAI,做交叉分析

把CPU、内存、网络流量同时丢给TimechoAI,做交叉分析

在这里插入图片描述

上一次我们聊了怎么把一条时间序列数据塞给TimechoAI。我们造了一个CPU的假数据,让它帮我们找出了那个突刺的点。

但是呢,你回到真实的干活场景里想一想。现实情况往往比那个复杂得多。你光看一个CPU指标,很多时候是看不出个所以然来的。你看到了CPU飙到了90%,然后呢?你不知道为什么飙高啊。你总不能直接跑去跟老板说,老板,CPU高了。老板肯定会问你,那到底是为什么高?

所以今天这篇,我们要往前再走一步。我们要把多条不同的时序数据,同时喂给这个大模型。我们要让它帮我们做交叉分析。也就是看看这几个指标之间,到底有没有什么勾连关系。

一、 为什么单指标分析在实际中经常翻车

1.1 老板的真实需求不是找异常点

我们很多做技术的,有个习惯。就是看到报警了,赶紧去查指标。看到CPU报警了,就盯着CPU的折线图看。看完了,确认确实是高了,就把这个截图发到群里。

其实老板看到这个截图,心里是没底的。他想要知道的,不是“出了什么问题”,而是“为什么会出这个问题,以及怎么解决”。这两个东西差别很大。

你光告诉他CPU高了,这仅仅只是一个现象。现象背后的原因,往往藏在别的地方。这就是单指标分析经常翻车的原因。你分析得很准,确实找出了最高点在哪,但是对解决问题毫无帮助。

1.2 举个例子:CPU高不一定是因为CPU的毛病

那我们举个最常见的例子。你发现一台服务器的CPU使用率突然从20%飙到了90%,并且持续了十分钟。

如果你只看CPU这一条线,你能猜出原因吗?猜不出来的。因为导致CPU高的原因太多了。

可能的情况是什么呢?可能是内存泄漏了。内存泄漏了,这是一个问题。那为什么会引起CPU高呢?因为程序没有内存可用了,它就会疯狂地触发垃圾回收机制,也就是GC。这个垃圾回收动作本身是非常吃CPU的。所以表现出来就是CPU很高。

还有一种可能。可能是网络流量突然被打满了。网络打满了之后,大量的请求堆积在队列里。CPU得不断地去切换上下文,去处理这些排队等待的线程。这样一来,CPU也会被拉高。

你看,同样都是CPU高,但是根因完全不一样。一个是内存的问题,一个是网络的问题。如果你不把内存和网络的拉过来一起看,你根本就无从下手。

二、 多条数据怎么在代码里组织

2.1 还是老办法,自己造几份假数据

既然要测交叉分析,我们手里得有三份数据。分别是CPU使用率、内存使用率、还有网络流入流量。

我们接着用上一次那个造数据的思路。不过这次我们要让这三份数据产生联动。我们要人为地制造一个“内存泄漏导致CPU高”的场景。

打开你的代码编辑器,我们把生成数据的函数稍微改复杂一点。

import random

def generate_multi_metrics_data():
cpu_data = []
mem_data = []
net_data = []

base_time = "2023-10-24 10:00:"

for i in range(100):
time_str = base_time + str(i * 60).zfill(2)

# 默认正常状态
cpu_val = random.randint(20, 30)
mem_val = random.randint(40, 50)
net_val = random.randint(100, 200) # 假设单位是MB

# 制造联动异常:从第50个点开始,内存缓慢泄漏
if i >= 50:
# 内存一点点往上爬
mem_val = 50 + (i 50) * 2 + random.randint(5, 5)
if mem_val > 95:
mem_val = 95 # 到顶了

# 当内存高到一定程度(比如第60个点开始),触发频繁GC,导致CPU飙升
if i >= 60:
cpu_val = random.randint(75, 95)

# 内存都在忙活GC了,处理正常网络请求的能力下降,网络流量反而跌了
if i >= 60:
net_val = random.randint(20, 50)

cpu_data.append(f"{time_str}, CPU使用率, {cpu_val}%")
mem_data.append(f"{time_str}, 内存使用率, {mem_val}%")
net_data.append(f"{time_str}, 网络流入流量, {net_val}MB")

return cpu_data, mem_data, net_data

你看这段代码,我写了三个列表来存数据。重点在中间那个 if i >= 50 的逻辑里面。

我先让内存从第50个点开始涨。它不是一下子暴涨,是一点点爬。这很符合内存泄漏的真实表现。然后我加了个判断,当内存涨到一定高度,也就是到了第60个点的时候,我让CPU跟着飙上去。同时我让网络流量掉下来。

这就模拟了一个非常经典的故障链路。你把这段逻辑看懂了,就知道我们等会儿要让大模型分析什么东西了。我们要看它能不能把这个“内存先涨,然后CPU跟着涨,同时网络掉下去”的先后顺序给理出来。

2.2 数据的文本格式该怎么排版

数据造好了,下一个问题来了。我们有三组数据,怎么拼成一个字符串丢给模型呢?

你不能把它们全混在一个列表里。比如第一行是CPU,第二行是内存,第三行又回到CPU。这样排布太乱了,大模型看瞎了也找不出规律。

通常来说,我们要做分组。用一些明显的分隔符,或者空行,把不同指标的数据隔开。

我们可以写一个专门的函数来干这个排版的事。

def format_multi_data(cpu_list, mem_list, net_list):
# 把每个列表拼成多行字符串
cpu_str = "\\n".join(cpu_list)
mem_str = "\\n".join(mem_list)
net_str = "\\n".join(net_list)

# 用大段的分隔符把它们隔开
final_text = f"""
===第1组指标数据===
{cpu_str}

===第2组指标数据===
{mem_str}

===第3组指标数据===
{net_str}
"""

return final_text

你注意看这里,我用了 ===第X组指标数据=== 这种很醒目的标题。然后在每组数据之间留了一个空行。

为什么要这么干呢?其实说白了,就是在降低大模型的阅读负担。你把结构理得越清楚,它就越不容易把内存的数据错看成CPU的数据。这个排版的工作,本来应该是前端或者数据工程师做的,现在在我们这个测试代码里,只能自己手动拼。

三、 提示词该怎么写才能引导它做交叉对比

3.1 别只说“帮我分析一下”,要给具体的对比方向

数据格式化好之后,就到了最关键的一步,写Prompt。

很多新手到了这一步,就直接写:“下面是三组数据,帮我分析一下。”。你这么写,大模型大概率会分别给你总结一下这三组数据各自的平均值和异常点。它不会主动去帮你找它们之间的联系。因为它没有接到“找联系”的指令。

我们得把要求写得更具体一点。我们要明确告诉它,我们要看时间线上的先后顺序。

def build_cross_prompt(formatted_data_text):
prompt = f"""
你现在是一个资深的运维专家。下面给你提供了同一台服务器在同一时间段内的三组监控数据。
格式是:时间, 指标名称, 数值。

第1组是CPU使用率。第2组是内存使用率。第3组是网络流入流量。

请你仔细对比这三组数据在时间线上的变化趋势。不要孤立地看每一个指标。
你的任务是:
1. 找出所有发生明显异常波动的具体时间点。
2. 重点分析这些异常点之间是否存在先后发生的关系。比如是不是A指标先变,然后B指标跟着变。
3. 根据这种先后顺序,推测一下最有可能的故障根因是什么。

数据如下:
{formatted_data_text}
"""

return prompt

你看我这段提示词。我先是给它设定了一个角色,“资深的运维专家”。这个的话,其实就是在约束它回答的口吻。不然它可能回答得像个教科书。

然后我明确告诉它这三组数据分别是什么。接着我列了三个任务。特别是第二个任务,我强调了“先后发生的关系”。这就是引导它去做交叉分析的核心指令。没有这句话,它可能就只做横向对比,不做纵向的时间轴追踪了。

3.2 在示例页面先测一下提示词

在用代码跑之前,我强烈建议你先去这个页面试一下:https://ai.timecho.com/realtime

你可以手动复制几十行我们造的数据,加上这段提示词,扔到那个网页聊天框里。看看它怎么回。

为什么要多这一步呢?因为调接口是要消耗时间和额度的。如果你提示词写得不对,你用代码跑一遍要等十几秒。你在网页上跑,几秒钟就能看到结果。发现不对,马上改提示词,改到满意了,再搬到代码里去。

这其实是一个很实用的工作流。别一上来就死磕代码。先把业务逻辑和提示词在轻量级的环境里验证通了,再写成自动化脚本。

四、 改造代码把三组数据发出去

4.1 把之前的单变量函数改成多变量

前面的准备工作都做完了,现在我们把主流程串起来。其实改动非常小,也就是把原来调一个生成函数,改成调三个,然后拼起来。

import requests

# 这里省略掉前面写的 generate_multi_metrics_data、format_multi_data、build_cross_prompt 这三个函数
# 假设它们已经写在上面了

def ask_timecho_ai(question, api_key):
url = "https://ai.timecho.com/v1/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
payload = {
"model": "timecho-model",
"messages": [
{
"role": "user",
"content": question
}
]
}

try:
# 数据量变大了,timeout给到60秒比较稳妥
response = requests.post(url, headers=headers, json=payload, timeout=60)
response.raise_for_status()
result_dict = response.json()
answer = result_dict['choices'][0]['message']['content']
return answer
except Exception as e:
return f"发生错误了:{e}"

if __name__ == "__main__":
my_key = "sk-你的真实KEY粘贴在这里"

print("正在生成三组联动假数据…")
cpu_list, mem_list, net_list = generate_multi_metrics_data()

print("正在排版数据格式…")
formatted_text = format_multi_data(cpu_list, mem_list, net_list)

print("正在构造交叉分析提示词…")
my_prompt = build_cross_prompt(formatted_text)

# 如果你好奇拼出来的东西到底有多长,可以把下面这行注释打开看看
# print(my_prompt)

print("正在请求TimechoAI接口,数据量大,请耐心等待…\\n")
final_answer = ask_timecho_ai(my_prompt, my_key)

print("=== 多指标交叉分析结果 ===")
print(final_answer)

你对比一下上一篇的代码,核心的请求函数 ask_timecho_ai 一点都没变。变的全都是外面的数据准备逻辑。

另外注意看,我把 timeout 从30秒改到了60秒。为什么呢?因为这次我们发过去的数据量大概是上一次的三倍。大模型读的数据多了,思考的时间肯定就长了。如果你还是给30秒,很可能它刚想到一半,你这边就强行掐断连接了。那你就只能收到一个超时的报错。

4.2 跑一下看看它能不能找出“内存泄漏”这个假设

现在你可以去运行这段代码了。去倒杯水,等个半分钟,结果就会出来。

如果一切顺利,你看到的结果应该会非常惊艳。它大概会给你返回类似这样的内容:

“经过对比三组数据在时间轴上的变化,我发现了一个明显的先后异常链条:

  • 首先,在第50分钟左右(10:50:00),第2组指标(内存使用率)开始出现异常,呈现出持续上升的趋势,偏离了原来40%-50%的正常区间。
  • 接着,到了第60分钟左右(11:00:00),随着内存压力的增大,第1组指标(CPU使用率)突然从20%-30%飙升至80%以上。
  • 与此同时,在第60分钟后,第3组指标(网络流入流量)出现了断崖式下跌,从100-200MB跌到了20-50MB。
  • 根因推测:
    这是非常典型的内存泄漏导致的问题。内存先发生泄漏并持续增长。当内存水位达到一定阈值时,触发了应用程序频繁的Full GC(垃圾回收)。GC过程会占用大量的CPU资源,导致CPU使用率飙升。由于CPU被GC任务占满,无法及时处理正常的网络I/O请求,导致网络流入流量大幅下降。”

    你看,它把我们在代码里埋的那个逻辑,完完整整地给挖出来了。它不仅找出了三个异常点,最关键的是,它理清了“内存先变 -> CPU后变 -> 网络跟着变”这个时间顺序。

    如果你把这段分析报告发给老板,老板一看就懂了。他会马上让开发去查是不是有内存泄漏的代码。这就是多指标交叉分析的价值。它帮你把散落的线索串成了一条完整的证据链。

    五、 如果它分析跑偏了怎么办

    5.1 大模型“瞎编”关联性的情况

    当然,大模型也不是万能的。有时候你给它三组其实毫无关系的数据,它为了完成你“找关联”的任务,可能会硬编出一个逻辑出来。

    比如内存其实只是正常波动,CPU也只是碰巧高了一下。它可能也会给你分析出一堆因果关系。这种情况在业内叫作“幻觉”。它不知道,但是它装作知道。

    那怎么避免这种情况呢?这就需要我们在提示词里加上限制条件。

    5.2 调整Prompt的技巧:加入否定指令

    你不能光让它找,你得告诉它,如果找不到,就直说。我们把刚才的 build_cross_prompt 函数稍微改几句话。

    def build_cross_prompt_safe(formatted_data_text):
    prompt = f"""
    你是一个严谨的运维专家。下面是同一台服务器的三组监控数据。

    请对比这三组数据在时间线上的变化。
    注意:只有当某个指标的异常明显发生在另一个指标异常之前(比如相差两三个时间点以上),并且逻辑上存在合理的因果关系时,你才可以将它们关联起来分析。
    如果三个指标的异常是同时发生的,或者没有明显的时间先后顺序,请不要强行建立因果关联,只需分别列出它们各自的异常情况即可。
    严禁在没有时间先后证据的情况下猜测根因。

    数据如下:
    {formatted_data_text}
    """

    return prompt

    你看这次,我加了很多“只有当…才…”、“请不要强行…”、“严禁…”这样的词。这就是在给它上紧箍咒。

    你告诉它了,必须要有时间差,必须要逻辑合理。如果没有,就老老实实分开报。这么一改,它乱编的概率就会大大降低。

    写提示词其实就跟带新员工一样。你指令越模糊,他干得越走样。你得把边界划得清清楚楚,哪些能干,哪些不能干,它才能干好。

    六、 再聊聊Token消耗和成本的问题

    6.1 数据量翻倍,Token也翻倍

    把三组数据丢进去,效果是好了,但是有一个很现实的问题我们躲不开。那就是钱。

    我们前面提到过Token的概念。你发过去的字数越多,消耗的输入Token就越多。你要求它做复杂的交叉分析,它生成的回答也会变长,消耗的输出Token也就越多。

    三组数据,每组100条。这就好几千个Token了。如果你要分析100台机器,每台机器三组数据,那你跑一次脚本消耗的Token量是非常惊人的。

    所以,你在去 https://ai.timecho.com/settings/keys 这个后台看账单的时候,一定要心里有数。不要写个死循环无限次地去调。一定要在代码里做好异常拦截,避免发了无效的请求还在傻傻等。

    6.2 压缩数据文本的小技巧

    既然Token要花钱,那我们能不能在不影响分析效果的前提下,把发过去的文本缩短一点呢?当然可以。

    你看我们现在的数据格式:“2023-10-24 10:00:00, CPU使用率, 25%”

    这里面其实有很多废话。比如“2023-10-24”这个日期,如果我们的数据都是在同一天的,那这个日期部分就完全多余了。大模型又不需要知道今天是几月几号,它只需要知道时间点的先后顺序。

    我们可以把格式简化成这样:“00:00:00, CPU, 25”。你看,省了多少个字符。

    如果是在同一个小时间段里,比如都在10点到12点之间,你甚至可以把小时去掉,只保留分钟和秒:“00分00秒, CPU, 25”。

    你别小看省下来的这几个字。乘上几百条数据,再乘上三组指标,省下来的Token可能就有上千个了。长年累月下来,这也是不少钱。

    我们在代码里改一下拼接的逻辑就行了。

    # 极简版的数据生成
    for i in range(100):
    # 只保留分和秒,或者直接用序号代表时间先后
    time_label = f"第{i}分钟"
    cpu_data.append(f"{time_label}, CPU, {cpu_val}%")
    # …其他的类似

    这种极简格式,大模型依然能看懂。它依然能根据“第50分钟”、“第60分钟”这种标签来判断先后顺序。但是你传输的成本就降下来了。这也是在实际业务里写代码必须要考虑的优化点。

    七、 总结与下期预告

    7.1 今天学到了什么核心逻辑

    今天这篇内容信息量比较大。我们解决了一个核心痛点,就是怎么让大模型做关联分析。

    我们知道了单指标分析往往找不到根因。我们学会了在代码里造有联动关系的假数据。我们掌握了多组数据的排版技巧,要用明显的分隔符把它们隔开。

    更重要的是,我们学习了怎么通过写提示词里的具体要求,去引导大模型关注“时间轴上的先后顺序”。我们还学了怎么加限制条件,防止它乱编因果关系。

    最后我们也聊到了成本控制的问题。知道了可以通过简化时间戳的格式来压缩Token。

    这些其实都是干货。你把这套多指标交叉分析的代码跑通了,你其实已经可以拿它去处理很多真实的运维报警了。你只要把造数据的部分换成你从真实数据库里查出来的数据,它就能直接出报告。

    7.2 下一期我们玩点更高级的

    不过呢,我们现在还是在自己造假数据玩。真实情况里,数据都是存在数据库里的。比如IoTDB,比如MySQL。

    总不能每次分析,你都先写个脚本把数据导出来成txt,然后再读进Python里去调接口吧。那样太繁琐了。

    所以在下一篇文章里,我们打算引入真实的数据库查询。我们来看看怎么在代码里直接连上数据库,把SQL查出来的结果直接扔给大模型。让整个流程变成一个全自动的闭环。

    这个的话,就会涉及到一些数据库驱动安装的东西了。如果你对这一块感兴趣,那就继续跟着往下看吧。我们下期见。

    赞(0)
    未经允许不得转载:171主机测评 » 把CPU、内存、网络流量同时丢给TimechoAI,做交叉分析
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址