
假设现在手里有 3 个函数1获取 Pod 状态主要通过describe 查看 k8s podget_pod_statusPod 是否 Running有没有 CrashLoopBackOff重启了多少次最近事件里有没有探针失败、OOM、镜像拉取失败2获取业务日志通过调用日志平台接口获取对应日志get_business_log接口为什么返回 500有没有空指针有没有数据库超时有没有调用下游失败3获取操作系统监控数据通过调用prometheus获取底层监控get_system_metricsCPU 是否打满内存是否不足磁盘是否写满网络流量是否异常函数描述获取 Kubernetes Pod 的状态、重启次数和事件信息用于排查 Pod 启动失败、异常重启、探针失败等问题获取业务服务日志用于排查接口报错、代码异常、数据库超时等问题获取节点操作系统监控数据用于排查 CPU、内存、磁盘、网络资源瓶颈问题函数描述非常重要LLM主要靠它来指导模型决策以及函数选取定义三个函数import json from datetime import datetime, timedelta def get_pod_status(namespace: str default, pod_name: str ): return { namespace: namespace, pod_name: pod_name, status: CrashLoopBackOff, restart_count: 5, node: 10.10.1.23, events: [ 2026-04-20 11:42:11 Readiness probe failed: connection refused, 2026-04-20 11:42:25 Container restarted, 2026-04-20 11:42:25 Last State: Terminated, Reason: OOMKilled ] } def get_business_log(service_name: str , start_time: str , end_time: str ): if not start_time: start_time (datetime.now() - timedelta(minutes30)).strftime(%Y-%m-%d %H:%M:%S) if not end_time: end_time datetime.now().strftime(%Y-%m-%d %H:%M:%S) return { service_name: service_name, time_range: { start_time: start_time, end_time: end_time }, logs: [ 2026-04-20 11:41:02 [ERROR] order-service create order failed: java.lang.NullPointerException, 2026-04-20 11:41:03 [ERROR] order-service db timeout when inserting order record, 2026-04-20 11:41:04 [WARN] order-service retry failed, return HTTP 500 ] } def get_system_metrics(node_ip: str , start_time: str , end_time: str ): if not start_time: start_time (datetime.now() - timedelta(minutes30)).strftime(%Y-%m-%d %H:%M:%S) if not end_time: end_time datetime.now().strftime(%Y-%m-%d %H:%M:%S) return { node_ip: node_ip, time_range: { start_time: start_time, end_time: end_time }, metrics: { cpu_usage: 91%, memory_usage: 93%, disk_usage: 58%, network_rx: 110MB/s, network_tx: 76MB/s } } TOOL_MAP { get_pod_status: get_pod_status, get_business_log: get_business_log, get_system_metrics: get_system_metrics, }定义工具描述tools [ { type: function, function: { name: get_pod_status, description: 获取 Kubernetes Pod 的运行状态、重启次数和事件信息用于排查 Pod 异常重启、启动失败、探针失败、CrashLoopBackOff 等问题。, parameters: { type: object, properties: { namespace: { type: string, description: Pod 所在命名空间默认 default }, pod_name: { type: string, description: Pod 名称或者工作负载名称 } }, required: [pod_name] } } }, { type: function, function: { name: get_business_log, description: 获取业务服务日志用于排查接口报错、HTTP 500、代码异常、数据库超时、调用下游失败等问题。, parameters: { type: object, properties: { service_name: { type: string, description: 服务名称比如 order-service }, start_time: { type: string, description: 查询开始时间格式 YYYY-MM-DD HH:MM:SS }, end_time: { type: string, description: 查询结束时间格式 YYYY-MM-DD HH:MM:SS } }, required: [service_name] } } }, { type: function, function: { name: get_system_metrics, description: 获取节点操作系统监控数据包括 CPU、内存、磁盘和网络使用情况用于排查节点负载高、资源瓶颈、系统卡顿等问题。, parameters: { type: object, properties: { node_ip: { type: string, description: 节点 IP 地址 }, start_time: { type: string, description: 查询开始时间格式 YYYY-MM-DD HH:MM:SS }, end_time: { type: string, description: 查询结束时间格式 YYYY-MM-DD HH:MM:SS } }, required: [node_ip] } } } ]模型决定调用下面这段代码是整篇文章最核心的部分。把用户问题和工具列表发给模型如果模型决定调用函数就执行对应函数把函数执行结果再喂给模型让它输出最终结论import json from litellm import completion def run_agent(user_query: str): messages [ { role: system, content: ( 你是一个线上故障排查助手。 请根据用户问题自主选择最合适的工具。 如果一个工具不足以定位问题可以继续调用其他工具。 回答时要基于工具返回的事实不要编造。 ) }, { role: user, content: user_query } ] while True: response completion( modeldoubao-seed-2.0-pro, messagesmessages, toolstools, tool_choiceauto ) message response.choices[0].message tool_calls message.tool_calls if not tool_calls: return message.content messages.append(message) for tool_call in tool_calls: tool_name tool_call.function.name tool_args json.loads(tool_call.function.arguments or {}) print(f[TOOL] {tool_name} args{tool_args}) tool_func TOOL_MAP[tool_name] tool_result tool_func(**tool_args) messages.append( { role: tool, tool_call_id: tool_call.id, name: tool_name, content: json.dumps(tool_result, ensure_asciiFalse) } )验证结果选取了4个不同的问题查看llm调用函数的情况if __name__ __main__: test_queries [ 我的 order-service Pod 一直重启帮我看看怎么回事, 下单接口一直返回 500帮我查一下日志, 节点 10.10.1.23 最近特别卡帮我看下是不是资源打满了, order-service 返回 500而且 Pod 也反复重启帮我整体分析一下 ] for idx, query in enumerate(test_queries, start1): print(f\n 测试 {idx} ) print(f[USER] {query}) answer run_agent(query) print(f[FINAL] {answer})参考输出并不是每一次运行都是同样的内容这里只展现本次运行llm的输出 测试 1 [USER] 我的 order-service Pod 一直重启帮我看看怎么回事 [TOOL] get_pod_status args{pod_name: order-service} [TOOL] get_business_log args{service_name: order-service, start_time: 2026-04-20 11:30:00, end_time: 2026-04-20 11:45:00} [TOOL] get_system_metrics args{node_ip: 10.10.1.23, start_time: 2026-04-20 11:30:00, end_time: 2026-04-20 11:45:00} [FINAL] 经过排查order-service Pod 持续重启的原因如下 ### 根因分析 1. **Pod 进程被强制终止**Pod 状态为 CrashLoopBackOff累计重启5次进程终止原因是 OOMKilled内存溢出被系统Kill进程退出后导致就 绪探针探测失败报 connection refused触发自动重启。 2. **业务代码异常**服务运行时存在业务报错包括空指针异常、订单数据插入数据库超时、重试失败返回HTTP 500这类异常会导致服务资源占用异 常升高是引发内存溢出的诱因之一。 3. **节点资源瓶颈**Pod 所在节点10.10.1.23在故障时间段CPU使用率达91%、内存使用率达93%节点本身负载极高进一步加剧了Pod的资源紧张问题 加速触发OOMKill。 ### 修复建议 1. 优先修复业务代码中的空指针异常、数据库超时问题优化资源占用逻辑 2. 调整 order-service Pod 的内存limit配置适当调高内存上限 3. 可将该Pod临时调度到其他低负载节点运行同时对10.10.1.23节点进行资源扩容或者清理节点上多余的负载。 测试 2 [USER] 下单接口一直返回 500帮我查一下日志 [TOOL] get_business_log args{service_name: order-service} [FINAL] 根据查询order-service服务的业务日志下单接口返回500的原因已经定位到 1. 订单创建逻辑触发了Java空指针异常NullPointerException 2. 插入订单记录到数据库时出现数据库超时问题 3. 超时重试多次失败最终接口返回HTTP 500错误 如果需要进一步排查数据库超时的根因可以提供数据库所在节点的IP查询系统资源负载也可以查询order-service服务的Pod运行状态确认是否存在服务本身资源不足、异常重启等问题。 测试 3 [USER] 节点 10.10.1.23 最近特别卡帮我看下是不是资源打满了 [TOOL] get_system_metrics args{node_ip: 10.10.1.23} [FINAL] 根据查询到的节点10.10.1.23最近30分钟的系统监控数据 1. CPU使用率达91%内存使用率达93%二者均处于极高负载状态这是导致节点卡顿的核心原因 2. 磁盘使用率为58%处于正常水平 3. 网络入流量110MB/s、出流量76MB/s也处于较高负载水平 当前该节点确实是CPU和内存资源几乎被打满导致运行卡顿建议尽快排查占用资源过高的进程或Pod进行资源扩容或者异常进程查杀。 测试 4 [USER] order-service 返回 500而且 Pod 也反复重启帮我整体分析一下 [TOOL] get_pod_status args{pod_name: order-service} [TOOL] get_business_log args{service_name: order-service, start_time: 2026-04-20 11:30:00, end_time: 2026-04-20 11:45:00} [TOOL] get_system_metrics args{node_ip: 10.10.1.23, start_time: 2026-04-20 11:30:00, end_time: 2026-04-20 11:45:00} [FINAL] ### 故障整体分析结论 #### 1. Pod反复重启原因 order-service的Pod当前处于CrashLoopBackOff状态累计重启5次直接原因是**内存溢出被系统杀死OOMKilled**同时Pod就绪探针检测失败 连接被拒绝进一步触发了Pod反复重启。 所在节点10.10.1.23的资源水位极高CPU使用率91%、内存使用率93%节点资源瓶颈是触发Pod OOM的重要诱因。 #### 2. 接口返回500原因 业务日志显示故障时间段内存在两类错误 - 代码层面存在空指针异常java.lang.NullPointerException - 订单插入操作触发数据库超时重试失败后直接返回HTTP 500错误。 #### 临时恢复建议 1. 优先调整order-service的容器内存配额同时调度到资源充足的节点 2. 修复代码空指针问题优化数据库插入逻辑增加超时时间/分库分表/异步插入 3. 对10.10.1.23节点进行负载清退降低节点资源使用率。4组问题llm选择了不同的、它自主决策的函数来解决对应的问题。在多函数场景里模型并不是瞎选而是很像运维工程师排查问题一样先判断问题在哪一层再决定调哪个工具如果证据不够就继续补证据最后基于事实做总结原理解析LLM 语义匹配LLM 在多函数场景下的选择逻辑本质上是拿用户问题的语义去匹配函数描述的语义LLM会关注用户当前到底在问什么每个函数的作用、输入参数、适 用场景分别是什么然后模型会判断哪个函数最像解决这个问题的工具需不需要调用函数调用时参数该怎么补齐如果一个函数不够后面还要不要继续调别的函数function call 的关键不只是有没有函数更关键的是怎么描述函数函数写得像说明书模型就选得准函数写得像谜语人模型就容易整活到这里有为老哥可能还会继续追问所谓的语义匹配到底匹配的是啥模型在决策时通常会综合下面几个维度问题里的关键词和上下文“Pod 重启” 更容易命中get_pod_status“接口 500” 更容易命中get_business_log“节点很卡” 更容易命中get_system_metrics函数 description 的场景描述如果你把“用于排查什么问题”写得清楚模型就更容易做出准确判断参数是否容易从当前上下文中提取比如用户明确说了10.10.1.23等操作系统类的资源那模型就更容易触发监控工具系统提示词里的行为约束如果你在 system prompt 里明确要求先查事实再下结论必要时可以多次调用工具模型一般会严谨许多function call 的效果不是只取决于模型本身也取决于你的工具定义和提示词设计让模型更聪明如果你发现模型老是选错函数先排查下面几个点1description 写得太短这是最常见的问题不要只写获取日志获取监控而要写成获取业务服务日志用于排查接口报错、代码异常、数据库超时等问题获取节点操作系统监控数据用于排查 CPU、内存、磁盘、网络资源瓶颈问题2函数边界不清晰如果两个函数看起来都像什么都能查模型就容易纠结所以工具设计最好做到每个函数负责一类证据不同函数之间边界清楚尽量不要让多个函数 description 大面积重叠3参数名太抽象像这种参数idnametarget看着万能实际上很坑应该改为具体指某一类资源实在有重名那就疯狂叠下划线pod_nameservice_namenode_ip参数名越具体模型越不容易理解歪。4提示词没告诉模型可以连续调用多个工具如果 system prompt 没写这句话模型有时会保守只调一个函数就停所以建议明确告诉它如果一个工具不足以定位问题可以继续调用其他工具