function call 实战:让 LLM 自动判断 pod 异常、调用日志工具并完成故障分析
如果需要排查就要求 LLM 调用get_pod_logs工具拿日志再让 LLM 基于日志输出问题原因、根因分析和修复建议OpenAI 客户端初始化这部分代码的作用是初始化模型客户端并从环境变量里读取模型名和接口地址from openai import OpenAI import json import os client OpenAI( api_keyos.getenv(OPENAI_API_KEY), base_urlos.getenv(API_BASE_URL) ) model os.getenv(DEFAULT_MODEL)工具定义声明可供模型调用的函数工具tools [ { type: function, function: { name: get_pod_logs, description: 获取Pod日志用于排查问题, parameters: { type: object, properties: { pod_name: {type: string}, namespace: {type: string} }, required: [pod_name] } } } ]有一个叫get_pod_logs的工具这个工具是用来获取 Pod 日志的它需要什么参数哪个参数是必填的function call 的本质不是让模型直接跑 python而是让模型知道有什么工具可以调用外部世界的接口获取 Pod 状态和日志接下来这两个函数是本地实现的模拟逻辑后期可以接入正式环境的数据这里先用模拟数据def get_pod_state(pod_name, namespace): # 可以用 kubectl 或 k8s API, 返回Running / CrashLoopBackOff / OOMKilled 等 return CrashLoopBackOff def get_pod_logs(pod_name, namespacedefault): # 去日志平台上获取对应的日志即可 return ERROR: database connection failed\nException: timeout让 LLM 先判断是否有异常下面这段代码是第一次调用模型。messages [ { role: system, content: 你是Kubernetes运维专家。 判断 Pod 状态 - 如果是 Running / 正常 → 返回 OK - 如果是 CrashLoopBackOff / OOMKilled / Error → 返回 NEED_DEBUG 只返回 OK 或 NEED_DEBUG }, { role: user, content: fPod状态是: {pod_state} } ] resp client.chat.completions.create( modelmodel, messagesmessages ) decision resp.choices[0].message.content.strip()LLM 调工具拿日志如果真的有问题调用预定义的函数获取相关信息messages [ { role: system, content: 你是一个Kubernetes故障诊断专家。 当Pod异常时 1. 必须调用 get_pod_logs 获取日志 2. 根据日志分析问题 3. 输出 - 问题原因 - 根因分析 - 修复建议 }, { role: user, content: fPod {pod_name} 状态是 {pod_state}请排查问题 } ] response client.chat.completions.create( modelmodel, messagesmessages, toolstools )这里和第一轮最大的区别就是多传了一个toolstools这意味着模型此时知道自己可以发起函数调用随后代码会检查模型是否真的触发了工具调用msg response.choices[0].message if msg.tool_calls: tool_call msg.tool_calls[0] args json.loads(tool_call.function.arguments)拿到工具调用后再由本地 Python 去真正执行logs get_pod_logs(**args)然后把工具执行结果再喂回模型让它基于日志继续完成最终分析final_resp client.chat.completions.create( modelmodel, messages[ *messages, msg, { role: tool, tool_call_id: tool_call.id, content: logs[:3000] } ] )执行链路获取 Pod 状态 ↓ LLM 判断OK / NEED_DEBUG ↓ 如果 NEED_DEBUG ↓ LLM 发起 tool callget_pod_logs(pod_name, namespace) ↓ 本地函数执行拿到日志 ↓ 日志作为 tool message 回填给 LLM ↓ LLM 输出问题原因 根因分析 修复建议这里为什么不用 if-else很多老哥看到这里肯定会问既然Running就是正常CrashLoopBackOff就是异常那直接 if-else 不香吗如果场景足够简单当然可以直接写 if-else。甚至在这个场景中第一段判断逻辑严格来说也确实可以用规则替代像下面这样if pod_state in [Running, Succeeded]: decision OK else: decision NEED_DEBUG这么写没毛病而且更便宜、更稳定、更可控那为什么还要引入 LLM因为真实线上环境往往没这么简单线上判断一个 Pod 是否异常很多时候不是看一个字段就能拍板而是要综合很多信息一起看1状态看起来正常但其实已经不正常了 Pod 状态还是Running但实际上业务已经挂了比如readiness probe 一直失败接口 RT 飙升错误率升高日志持续报错下游数据库连接频繁超时CPU 不高但线程池已经卡死这时候如果你只写if pod_state Running: return OK2状态异常但未必需要立刻排查pod 状态Completed灰度发布期间有短暂重建HPA 扩缩容带来的短时波动节点维护导致的瞬时漂移这时候你如果只根据状态值机械判断就很容易误报3真正有价值的判断往往依赖多维信号Pod 当前 状态restart 次数最近 5 分钟日志CPU / Memory 使用率OOM 事件节点状态发布记录同服务其他副本是否也异常Prometheus 指标波动这个时候用 if-else 纯流程化的判断模式对于事件的判断就不太合适了。if-else 擅长处理边界清晰、模式稳定的场景而LLM 更适合处理需要综合上下文、模糊判断以及不固定条件的综合判断所以这里采用LLM 的表达能力和归纳能力会更方便总结通过 Function Call 获取外部数据最后让 LLM 输出总结性的建议以及处理方案至于为什么不用 if-else简单场景当然可以用固定流程但当判断开始依赖多维数据、日志语义和上下文综合

相关新闻