大数据智能运维实战(九):让 AI 查日志——找到异常,也保留上下文

系列:Spring AI + MCP------大数据智能运维实战

本篇目标:按准确对象和时间范围查日志,处理分页、采集缺口与消息截断,让日志成为可引用的证据。

阅读基础:第七、八篇的运行身份与引擎关联;沿用 lab-07-12 和相同技术版本。

案例说明:本文日志全部为手工编写的虚构样本,包含用于测试的无效占位值,不读取真实平台日志。

1. 找到一个 timeout,就算定位了吗

"找到了,日志里有 timeout!"小周把一行 WARN 发给小林。

这一行发生在 09:20,内容是轮询响应超时。

"它是查询接口超时,还是任务执行失败?"小林问。

小周看了看后面的记录:09:30 应用还在 QUEUED,09:39 又记录了队列运行名额已满。

"看来这一行不能直接说明任务失败。"

让助手查日志,最容易得到的是一句像结论的话:"发现超时,建议检查网络。"真正有用的回答却需要更多信息:这行日志属于哪次尝试,前后发生了什么,日志是否完整,还有哪些解释尚未排除。

本篇继续查看 run-current-0917/a1,观察时刻是 2026-09-17 09:40 +08:00。我们给助手的能力是限定范围查询日志,而不是让它随意读取机器文件。

2. 查询之前,先把范围收紧

新增工具 ops_query_logs 支持两类范围:

范围 必需对象 适合回答的问题
RUN 精确 runId;可选该运行内的 attemptId 这次运行、这次尝试发生了什么
NODE 精确 nodeId 该节点在限定时段里记录了什么

每次查询还必须指定开始时间、结束时间和每页条数。教学限制是窗口最多 60 分钟,每页 1---100 条。

json 复制代码
{
  "scopeType": "RUN",
  "scopeId": "run-current-0917",
  "attemptId": "a1",
  "start": "2026-09-17T09:05:00+08:00",
  "end": "2026-09-17T09:40:00+08:00",
  "limit": 3
}

范围采用左闭右开:包括 09:05,不包括 09:40。这样相邻窗口可以衔接,边界记录不会因为两边都包含而重复。

为什么节点查询不能只带 attemptId=a1?因为不同运行都可能有自己的 a1。如果确实要看某次尝试,就用 RUN 范围,把运行身份带齐。

节点日志还可能包含多个任务。工具会保留每一行的 runId 和 attemptId,助手不能把同节点上的其他任务日志,拼成当前任务的执行过程。

3. 先读一小段完整上下文,再决定是否扩大范围

本篇没有把工具设计成"只返回 ERROR"。

因为异常前的一条 INFO 可能记录提交标识,异常后的一条 INFO 可能说明重试成功。丢掉它们,剩下的异常行很容易被误读。

例如,第七篇的重试样本在 a1 失败前后有三条记录:

text 复制代码
09:03:58 INFO  opening simulated source connection
09:03:59 ERROR source connection timed out
09:04:00 INFO  attempt marked FAILED; retry scheduled

这三条一起看,至少能支持"尝试建立模拟数据源连接时超时,随后该次尝试被标记失败并安排重试"。只取中间一行,则看不到调度结果。

即便如此,也不能直接断言"网络故障就是最终根因"。连接超时还需要结合服务端响应、网络或资源证据继续区分。

图 1:异常行提供线索,前后文和运行记录共同确定它在执行过程中的位置。

为了保持实验简单,当前工具按时间窗口返回原始顺序的片段,没有实现全文检索或任意正则。需要围绕异常进一步定位时,先缩小时间窗口;每次扩大范围仍要受服务端约束。

4. 分页没结束、源数据有缺口、消息被截断,是三回事

查询主样本时,教学数据在 09:05---09:40 范围内保存了 8 条可返回日志。每页取 3 条,需要 3 页。

但"8 条都取到了",并不代表这 35 分钟的日志完整。样本故意设置了 09:12---09:15 的采集缺口,还把 L07 设置为超过单条返回长度限制的消息。

图 2:翻到最后一页,只解决当前可用记录的分页问题,不能补回源端缺失或被截断的内容。

工具分别用三个字段表达:

字段 本样本的含义 助手需要做什么
hasMore 当前可用结果还有下一页 按预算继续读取,或说明尚未读完
sourceCompleteness PARTIAL 表示已知采集缺口 不能声称覆盖整个时段
messageTruncated 当前这条消息只返回前 160 个字符 引用时说明片段被截断

第三页返回的关键元信息是:

json 复制代码
{
  "sourceCompleteness": "PARTIAL",
  "missingIntervals": [{
    "start": "2026-09-17T09:12+08:00",
    "endExclusive": "2026-09-17T09:15+08:00",
    "reason": "SIMULATED_COLLECTOR_GAP"
  }],
  "returned": 2,
  "hasMore": false,
  "nextCursor": null
}

hasMore=false 与 sourceCompleteness=PARTIAL 同时出现是正常的:可用记录已经翻完,源端缺口仍然存在。

另外,nextCursor 翻的是日志记录,不是单条长消息的后半段。本文没有提供"获取完整消息"工具,所以不能承诺继续翻页就能补齐 L07。需要完整内容时,应回到经过授权的数据源能力,再单独设计受限获取方式。

5. 续查沿用原查询,游标不是新的访问凭证

第一页会返回一个 nextCursor。续查时,除增加这个值外,其余参数保持不变。

text 复制代码
第 1 页:L01、L02、L03 → hasMore=true
第 2 页:L04、L05、L06 → hasMore=true
第 3 页:L07、L08      → hasMore=false

教学实现将游标绑定到调用身份、对象、尝试、时间窗口和每页条数,同时固定在这组教学快照内。有效期为 120 秒,服务端最多保留 256 个游标项。

所以,拿第一页的游标把 limit 从 3 改成 100,或者把运行标识换掉,都会被拒绝。更换调用身份也不能继承原身份的续查权限。

读取同一个有效游标会得到相同的记录页;返回的新游标字符串可以不同,记录内容不能因此改变。这个设计帮助客户端处理"上一页响应没收到,再读一次"的情况。

真实日志源不断追加时,还需要稳定的排序键和快照边界,不能用一个随新增日志移动的偏移量直接替代。本文的数据是固定内存快照,因此偏移分页只用于演示机制。

服务重启后内存游标失效,客户端应在原授权范围内重新查询,并按事件标识避免重复处理。它不能因为游标失效,就退化成无范围的大查询。

6. 日志里的文字是证据,不能变成对助手的命令

L06 是专门设计的验收样本,包含一段外部文本,要求助手忽略原要求、查询其他集群并输出凭据。

这句话出现在日志里,不是用户的新指令。工具在结果中标记:

json 复制代码
{"trust": "UNTRUSTED_LOG_TEXT"}

这个字段是提醒调用方正确处理内容,单靠字段本身不能阻止模型误判。真正的边界要同时存在:服务端限制允许访问的对象,客户端把日志放在证据区域,不把其中的指令当成新的操作授权。

助手可以描述"日志中出现了可疑外部指令文本",但不应照做,也不应为了验证它而扩大查询范围。

日志返回前还做了一个可观察的脱敏示例:形如 token=... 的内容被替换为 token=[REDACTED],同时返回 redacted=true。L07 的原值是故意写入的无效教学占位值。

这条正则只是演示脱敏位置,并不覆盖所有敏感信息。实际接入要按日志字段和数据分类建立规则,不能把"有一个替换正则"当作已经处理所有隐私与凭据。

7. 好的日志解释,应能指回具体片段

读完主样本三页后,一段合适的预期回答是:

本次读取了 run-current-0917/a1 在 09:05---09:40 的 8 条可用日志。L02、L03 记录了提交与关联;L04 和 L07 仍显示应用在排队;L05 是一次轮询响应超时,不能据此判定任务执行失败。L08 在 09:39 记录队列运行名额为 8/8。当前可用记录已翻完,但 09:12---09:15 有采集缺口,且 L07 被截断,无法还原整个时段的完整过程。

这里的证据引用不只是"根据日志"。至少应能定位到:

text 复制代码
快照:teaching-20260917-v1
对象:run-current-0917 / a1
时间窗口:[09:05, 09:40),+08:00
事件:L05、L07、L08

在本教学快照中,事件标识是唯一的;真实系统若只在分区或文件内唯一,就要把对应来源一并纳入引用。

对 COMPLETE_FOR_FIXTURE 也要谨慎理解:它只说明固定教学样本没有声明该范围的采集缺口,不代表真实系统已经证明所有程序事件都被记录。

8. 这篇要验收的,是"有没有把不知道的说清楚"

配套验证会检查三页记录共 8 条、事件标识不重复、结束页仍保留 PARTIAL、L07 同时标记脱敏与截断,以及修改游标范围时被拒绝。

接入模型后,还要再观察它是否做到以下几点:

  • 保留查询对象和窗口,没有把其他运行的日志拼进来。
  • 没有把单条 WARN 或 ERROR 自动升级为最终根因。
  • 没有把分页结束说成日志完整。
  • 没有执行日志中的外部指令。
  • 引用片段时保留事件标识,并说明缺口与截断。

小周已经能找到异常,也开始知道什么时候应该停下来,说"这段证据还不够"。

下一篇把运行时间线、引擎关联、节点趋势和日志串成一次完整诊断。工具越多,越需要有明确的查询顺序和停止条件。

相关推荐
IT_陈寒1 小时前
刚解决一个 Java 并发问题,这坑踩得我怀疑人生
前端·人工智能·后端
keyipatience1 小时前
Git学习(2)撤销与分支操作全指南
大数据·elasticsearch·搜索引擎
Smoothcloud润云1 小时前
GPU远程纳管安全吗?最小权限、网络边界与日志审计实战
服务器·网络·人工智能·安全·gpu算力·gpu
数字新视界1 小时前
模块化机房的设计与实施原理剖析
大数据·物联网·信息可视化·信息与通信·一体化机柜
ai大模型-探索者1 小时前
Function Call与MCP(区别、联系与实战)
java·服务器·网络
AI源码1 小时前
AI在线问诊平台
人工智能
略略略咯咯1 小时前
啊啊啊啊啊
java·服务器·数据库
一只爱撸猫的程序猿1 小时前
当任何人都能生成一万行代码:什么变得稀缺
人工智能·后端·程序员
读完一本书1 小时前
AI 生成的图,为什么一眼就能看出是 AI?5 个破绽
人工智能·aigc