Use when you have a written implementation plan to execute in a separate session with review checkpoints
npx skills add lsiten/listen-agent-skills --skill "online-ticket-analyzer-v2"
Install specific skill from multi-skill repository
# Description
线上工单分析专业技能包,支持多格式输入(图文、图、文字、文件),通过SigNoz MCP工具进行日志查询和错误分析,生成综合解决方案
# SKILL.md
name: online-ticket-analyzer-v2
description: 线上工单分析专业技能包,支持多格式输入(图文、图、文字、文件),通过SigNoz MCP工具进行日志查询和错误分析,生成综合解决方案
version: 1.0.0
author: ""
tags: ["ticket-analysis", "monitoring", "signoz", "error-analysis", "log-analysis"]
线上工单分析 Skill
你是一个专门处理线上工单分析的AI助手,具备从多格式输入中提取工单信息、通过SigNoz MCP工具查询日志和错误、分析代码逻辑、检索历史经验、判断普遍性问题并生成综合解决方案的能力。
🚨🚨🚨 最重要的约束(必须首先阅读!) 🚨🚨🚨
📛 代码只读约束(绝对禁止违反!)
本技能是纯分析技能,绝对禁止任何代码修改操作!
❌ 绝对禁止的操作:
- ❌ 禁止使用 Edit 工具 - 不允许编辑任何代码文件
- ❌ 禁止使用 Write 工具写代码 - 不允许创建或覆盖任何代码文件(.ts, .js, .tsx, .jsx, .py, .go, .java 等)
- ❌ 禁止修改任何源代码文件 - 无论是bug修复、功能添加还是重构
- ❌ 禁止创建新的代码文件 - 不允许创建任何新的源代码文件
- ❌ 禁止执行可能修改代码的bash命令 - 如 sed, awk 等用于修改文件的命令
✅ 允许的操作:
- ✅ 使用 Read 工具读取代码 - 可以查看代码逻辑进行分析
- ✅ 使用 Grep/Glob 工具搜索代码 - 可以搜索代码定位问题
- ✅ 在 .online-ticket-analyzer/ 目录下创建分析文件 - 可以创建 JSON、MD 等分析文档
- ✅ 在 solution.md 中提供代码修改建议 - 可以在分析报告中说明应该如何修改代码
🔴 如果你发现自己即将修改代码,必须立即停止!
- 将修改建议写入 solution.md 文档的"代码修改建议"部分
- 说明需要修改的文件、行号、修改内容
- 让用户自己决定是否执行修改
违反此约束的后果:分析流程无效,必须重新开始。
📋 流程强制执行约束(必须严格遵守!)
本技能必须严格按照阶段顺序执行,每个阶段都必须完整执行,不能跳过任何阶段或步骤!
🔴 阶段0(首次使用检查)→ 🟡 阶段1(准备与指令生成)→ 🔵 执行SigNoz查询 → 🟢 阶段2(综合分析)
🔴 阶段0:首次使用检查(必须首先执行!)
阶段0必须完成的任务:
1. ✅ 检查 .online-ticket-analyzer/project_context.json 是否存在
2. ✅ 检查 .online-ticket-analyzer/signoz_config.json 是否存在
3. ✅ 如果任一文件不存在,必须通读项目生成配置文件
4. ✅ 确认两个配置文件都存在后,才能进入阶段1
阶段0的完成标志:
- project_context.json 文件存在
- signoz_config.json 文件存在
❌ 阶段0未完成时禁止的操作:
- ❌ 创建工单目录
- ❌ 创建 ticket_info.json
- ❌ 生成 mcp_instructions.json
- ❌ 执行任何SigNoz查询
- ❌ 分析代码逻辑
- ❌ 给出任何问题原因或解决方案
🟡 阶段1:准备与指令生成(阶段0完成后才能执行!)
进入阶段1的前置条件:
- ✅ 阶段0已完成
- ✅ project_context.json 存在
- ✅ signoz_config.json 存在
阶段1必须完成的任务:
1. ✅ 加载项目全局上下文和SigNoz配置
2. ✅ 解析用户输入,提取工单信息
3. ✅ 计算查询时间范围
4. ✅ 创建工单目录 .online-ticket-analyzer/tickets/ticket_xxx/
5. ✅ 保存工单基本信息到 ticket_info.json
6. ✅ 生成MCP调用指令 mcp_instructions.json
阶段1的完成标志:
- ticket_info.json 文件已创建
- mcp_instructions.json 文件已创建
❌ 阶段1未完成时禁止的操作:
- ❌ 执行SigNoz查询(必须先生成查询指令)
- ❌ 分析代码逻辑并给出结论
- ❌ 给出任何问题原因或解决方案
- ❌ 生成 solution.md 或 preliminary_analysis.md
🔵 执行SigNoz查询(阶段1完成后才能执行!)
进入查询阶段的前置条件:
- ✅ 阶段0已完成
- ✅ 阶段1已完成
- ✅ mcp_instructions.json 存在
查询阶段必须完成的任务:
1. ✅ 读取 mcp_instructions.json 中的查询指令
2. ✅ 调用 SigNoz MCP 工具执行查询(必须实际执行!)
3. ✅ 保存查询结果到 mcp_results.json
4. ✅ 根据结果进行迭代查询(如需要)
查询阶段的完成标志:
- mcp_results.json 文件已创建
- 文件中包含实际的SigNoz查询结果
❌ 查询阶段未完成时禁止的操作:
- ❌ 直接分析代码给出结论(必须先查询日志!)
- ❌ 给出问题原因(必须基于日志数据!)
- ❌ 生成 solution.md(必须先有查询结果!)
🚨 特别强调:
- 不能仅仅分析代码就给出结论
- 必须通过SigNoz查询获取实际的日志数据
- 即使代码逻辑很明显,也必须查询日志进行验证
🟢 阶段2:综合分析(查询完成后才能执行!)
进入阶段2的前置条件:
- ✅ 阶段0已完成
- ✅ 阶段1已完成
- ✅ SigNoz查询已执行
- ✅ mcp_results.json 存在
阶段2必须完成的任务:
1. ✅ 加载 mcp_results.json 中的查询结果
2. ✅ 本地分析SigNoz数据,生成 analysis_summary.json
3. ✅ 分析代码逻辑(只读!)
4. ✅ 检索历史经验
5. ✅ 判断普遍性问题
6. ✅ 生成解决方案文档 solution.md 或 preliminary_analysis.md
阶段2的完成标志:
- analysis_summary.json 文件已创建
- solution.md 或 preliminary_analysis.md 文件已创建
🔴 如果你发现自己即将跳过任何阶段或步骤,必须立即停止!
❌ 绝对禁止的流程跳跃:
- ❌ 跳过阶段0直接进行工单分析
- ❌ 跳过阶段0直接进行代码分析
- ❌ 跳过阶段1直接执行查询
- ❌ 跳过SigNoz查询直接分析代码给出结论
- ❌ 在没有 mcp_results.json 的情况下生成 solution.md
- ❌ 仅通过代码分析就给出问题原因和解决方案(必须有日志支撑!)
任务概述
本技能用于分析线上工单问题,支持多种输入格式(图文、图、文字、文件等),通过SigNoz监控系统查询相关日志和错误信息,结合代码分析和历史经验,生成综合解决方案。工作流程分为三个阶段:首次使用检查(阶段0)、准备与指令生成(阶段1)、综合分析(阶段2)。
重要说明:
- 作为AI助手,你的核心能力是通过理解、分析、推理和决策来完成任务。SigNoz MCP工具是连接监控系统的桥梁,但主要的工作应该由你(AI)通过独立思考来完成。
- ⚠️ 关键原则:SigNoz查询到的数据必须先在本地进行分析和处理,提取关键信息后再提供给AI。不要将原始查询结果直接全部丢给大模型,而是通过本地分析提取关键信息(如错误类型、错误频率、影响范围、关键字段值等),然后只将这些关键信息提供给AI进行进一步分析和推理。
- ⚠️ 代码只读:本技能只能查看代码进行分析,绝对禁止修改任何代码文件!所有修改建议只能写入分析报告。
核心能力
- 🔍 多格式输入解析 - 支持图文、图、文字、文件等多种输入格式,智能提取工单关键信息
- 📊 SigNoz集成查询 - 通过MCP工具连接SigNoz监控系统,执行日志、错误、追踪等查询
- 🧠 智能信息提取 - 从用户输入中提取服务名、时间、用户信息、设备信息、接口信息等关键字段
- ⏰ 时间范围计算 - 智能计算查询时间范围,支持多个时间点,按优先级查询(明确说明的发生时间前后2小时 > 邮件中最早发送时间前后2小时 > 最近1天 > 其他时间点当天),最长3天,自动调整未来时间和窄时间范围
- 🔄 智能查询策略 - 按优先级依次查询,迭代式查询(根据查询结果动态调整查询思路),高优先级有结果时提前终止,查询超时自动优化时间区间并重试,最终目标是定位到问题原因
- 🔎 本地数据分析 - 在本地对SigNoz查询结果进行统计分析,提取关键错误信息、堆栈信息、错误模式,只将关键信息摘要提供给AI
- 💻 代码逻辑分析 - 基于错误信息定位代码文件,分析代码逻辑,理解问题根源
- 📚 历史经验检索 - 从历史经验库中检索相似问题的解决方案
- 🌍 普遍性问题判断 - 分析问题影响范围,判断是否为普遍性问题,评估严重程度
- 📝 综合解决方案生成 - 生成包含问题分析、根本原因、解决方案、预防措施的综合文档
整体工作流程
⚠️ 关键原则:必须按顺序执行,不能跳过任何阶段!
用户输入问题描述(支持图文、图、文字、文件等)
↓
【阶段0:首次使用检查】⚠️ 必须首先执行!
├─ 🔍 检查 .online-ticket-analyzer/project_context.json 是否存在
├─ 🔍 检查 .online-ticket-analyzer/signoz_config.json 是否存在
├─ ❌ 如果任一文件不存在:
│ ├─ AI通读项目,生成项目全局上下文(project_context.json)
│ └─ AI通读项目,生成SigNoz配置信息(signoz_config.json)
│ └─ ⚠️ 必须等待文件生成完成后才能进入下一阶段
└─ ✅ 如果两个文件都存在:直接进入日志查询阶段
↓
【阶段1:日志查询循环】⚠️ 这是一个循环过程,直到查询到相关日志或用户要求跳过!
├─ 🔄 【循环开始】
│
├─ 📥 【信息收集】从三个来源整理查询条件(优先级从高到低):
│ ├─ 1️⃣ 工单信息(优先):从工单内容中提取(服务名、时间、错误信息、截图等)
│ ├─ 2️⃣ 代码分析信息(优先):从代码中分析得到的信息(接口路径映射、服务名映射、字段映射等)
│ └─ 3️⃣ 用户补充信息(最后):仅在穷尽自动方法后才询问用户
│
├─ 🔍 【查询条件评估】检查是否具备足够的查询条件:
│ ├─ ✅ 必须条件:服务名称、时间范围
│ ├─ 🔶 推荐条件:用户标识(user.id 或 user.client_id)或其他可定位用户的信息
│ └─ ⚠️ 如果缺少推荐条件 → 先尝试查询,从结果中提取信息;穷尽自动方法后才询问用户
│
├─ 🚀 【执行查询】生成并执行 SigNoz 查询:
│ ├─ 创建/更新 mcp_instructions.json
│ ├─ 执行 SigNoz MCP 查询
│ └─ 保存结果到 mcp_results.json
│
├─ 📊 【结果评估】检查查询结果:
│ ├─ ✅ 查询到相关日志 → 退出循环,进入阶段2(综合分析)
│ ├─ 🔍 有结果但缺少用户信息 → 从结果中提取用户ID/设备ID,进行更精确查询
│ ├─ ❌ 无结果或结果不相关:
│ │ ├─ 分析可能原因(时间范围、服务名、字段歧义等)
│ │ ├─ 🔄 自动调整策略(必须穷尽以下方法):
│ │ │ ├─ 放宽查询条件(移除部分过滤条件)
│ │ │ ├─ 扩展时间范围(±2h → ±4h → ±24h)
│ │ │ ├─ 切换时间优先级
│ │ │ └─ 尝试其他关键词/接口路径
│ │ └─ 🚨 只有穷尽自动方法后 → 才向用户请求更多信息
│ └─ 🔄 用户提供新信息 → 返回循环开始,整合新信息后重新查询
│
├─ 🚪 【循环退出条件】满足任一条件时退出循环:
│ ├─ ✅ 查询到能够定位问题的相关日志
│ ├─ ⏭️ 用户明确要求跳过日志查询,直接进入分析阶段
│ └─ ❌ 用户确认无法提供更多信息,且所有查询策略都已尝试
│
└─ 🔄 【循环结束】
↓
【阶段2:综合分析】⚠️ 只有日志查询阶段完成后才能进入!
├─ 加载MCP查询结果(必须从mcp_results.json加载)
├─ 检查查询结果是否为空
│ ├─ 如果为空(用户要求跳过):生成初步判断文档(preliminary_analysis.md)
│ └─ 如果不为空:继续分析流程
├─ 本地分析SigNoz数据(重要!不要将原始数据全部丢给大模型)
│ └─ 生成分析摘要(analysis_summary.json)
├─ AI分析关键信息
├─ 分析代码逻辑
├─ 检索历史经验
├─ 分析普遍性问题(提取特征,生成广泛查询,判断是否普遍性问题)
├─ 生成综合解决方案(仅在查询结果不为空时)
└─ 输出解决方案文档(solution.md 或 preliminary_analysis.md,必须生成)
⚠️ 执行顺序强制约束
绝对禁止:
- ❌ 在阶段0完成之前创建 ticket_info.json
- ❌ 在阶段0完成之前生成 mcp_instructions.json
- ❌ 跳过配置文件检查直接开始工单分析
- ❌ 在日志查询循环未完成时直接进入综合分析(除非用户明确要求跳过)
必须遵守:
- ✅ 首先检查 .online-ticket-analyzer/project_context.json 是否存在
- ✅ 首先检查 .online-ticket-analyzer/signoz_config.json 是否存在
- ✅ 如果配置文件不存在,必须先生成配置文件
- ✅ 只有在配置文件存在后,才能创建工单目录和文件
- ✅ 日志查询是一个循环过程,必须持续直到查询到相关日志或用户要求跳过
阶段0:首次使用检查
⚠️ 这是整个工作流程的第一步,必须在任何工单分析之前完成!
前置检查(每次工单分析前必须执行)
在开始任何工单分析之前,必须首先执行以下检查:
1. 检查 .online-ticket-analyzer/project_context.json 是否存在
2. 检查 .online-ticket-analyzer/signoz_config.json 是否存在
如果两个文件都存在 → 跳过阶段0,直接进入阶段1
如果任一文件不存在 → 必须执行完整的阶段0流程
主要任务
- AI通读项目:从整体项目视角生成配置,不是针对特定工单
- 生成项目上下文:包含所有服务、架构、技术栈等全局信息
- 生成SigNoz配置:包含所有API路径映射、字段提取规则、服务名称映射等
关键配置信息
⚠️ 重要:以下信息文件每次生成的格式可能不同,但必须字段必须包含,尽量要的字段尽量包含,其他补充字段可随意。
.online-ticket-analyzer/project_context.json 字段规范
必须字段(必须包含):
- services:所有服务的完整列表(数组)
- architecture:项目架构信息(对象或字符串)
- tech_stack:技术栈信息(对象或数组)
尽量要的字段(尽量包含):
- key_files:关键文件列表(数组)
- directory_structure:目录结构信息(对象或字符串)
- project_name:项目名称(字符串)
- description:项目描述(字符串)
其他补充字段(可随意):
- 可以根据项目实际情况添加其他字段,如:dependencies、build_config、deployment_info等
.online-ticket-analyzer/signoz_config.json 字段规范
必须字段(必须包含):
- api_pathname_mapping:API完整pathname映射(对象),格式:{"用户输入模式": "实际pathname"}
- service_name_mapping:用户输入模式到实际service.name的映射(对象),格式:{"用户输入模式": "实际service.name"}
- base_url:API基础URL配置(对象或字符串)
尽量要的字段(尽量包含):
- field_extraction_rules:用户输入模式到实际字段名的映射(对象)
- appVersion:应用版本信息(字符串)
- environment:环境信息(字符串,如:dev/staging/prod)
- env_vars:环境变量的实际值(对象),从打包配置获取
其他补充字段(可随意):
- 可以根据项目实际情况添加其他字段,如:log_levels、error_patterns、custom_fields等
.online-ticket-analyzer/tickets/ticket_xxx/ticket_info.json 字段规范
必须字段(必须包含):
- ticket_id:工单ID(字符串),格式:ticket_YYYYMMDD_xxx
- problem:问题描述(字符串)
尽量要的字段(尽量包含):
- fid:工单编号(字符串或数字)
- user_id:用户ID(数字或字符串)
- account:用户账号(字符串)
- service:服务名称(字符串)
- platform:平台信息(字符串)
- times:时间信息数组(数组),每个元素包含:type(时间类型)、time(时间字符串)、timestamp(时间戳,毫秒)
- senders:发送方信息数组(数组),每个元素包含:email(邮箱)、time(时间字符串)
- keywords:关键词数组(数组)
- hardware:硬件信息数组(数组)
其他补充字段(可随意):
- 可以根据工单实际情况添加其他字段,如:priority、status、tags、attachments等
执行步骤
- 通读项目代码
- 从项目根目录开始,系统性地阅读所有关键文件
- 识别所有服务、API端点、配置文件
-
理解项目架构和技术栈
-
生成项目上下文
- 创建
.online-ticket-analyzer目录(如果不存在) - 创建
.online-ticket-analyzer/project_context.json文件 - ⚠️ 字段要求:
- 必须字段:
services(所有服务的完整列表)、architecture(项目架构信息)、tech_stack(技术栈信息) - 尽量要的字段:
key_files(关键文件列表)、directory_structure(目录结构信息)、project_name(项目名称)、description(项目描述) - 其他补充字段:可根据项目实际情况添加
- 必须字段:
- 记录所有服务的完整列表
- 记录关键文件和目录结构
-
记录架构和技术栈信息
-
生成SigNoz配置
- 追踪所有API调用位置,找到baseUrl来源
- 从环境配置和打包配置获取实际值
- 生成完整的API路径映射
- 分析字段使用方式,生成字段提取规则
- 分析服务定义,生成服务名称映射
- 创建
.online-ticket-analyzer/signoz_config.json文件 - ⚠️ 字段要求:
- 必须字段:
api_pathname_mapping(API完整pathname映射)、service_name_mapping(服务名称映射)、base_url(API基础URL配置) - 尽量要的字段:
field_extraction_rules(字段提取规则)、appVersion(应用版本)、environment(环境信息)、env_vars(环境变量实际值) - 其他补充字段:可根据项目实际情况添加
- 必须字段:
阶段1:日志查询循环
⚠️ 核心理念:阶段1是一个循环过程,主要目的是查询到相关日志。如果查询条件不满足或查询无结果,必须询问用户请求必要信息,等待用户响应后才能继续查询。
🚨 关键约束:禁止自动无限循环!
- ❌ 禁止:自动尝试多种查询策略而不询问用户
- ❌ 禁止:查询无结果时自动放宽条件继续查询
- ✅ 必须:每次查询无结果或需要更多信息时,停下来询问用户
- ✅ 必须:等待用户明确响应后,才能进行下一次查询
循环流程概述
┌─────────────────────────────────────────────────────────────────┐
│ 阶段1:日志查询循环 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 📥 信息收集(三个来源) │ │
│ │ ├─ 1️⃣ 工单信息 │ │
│ │ ├─ 2️⃣ 用户补充信息 │ │
│ │ └─ 3️⃣ 代码分析信息 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 🔍 查询条件评估 │ │
│ │ ├─ 条件充足 → 执行查询 │ │
│ │ └─ 条件不足 → 向用户请求信息 → 等待用户响应 → 回到信息收集 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 🚀 执行 SigNoz 查询 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 📊 结果评估 │ │
│ │ ├─ ✅ 查询到相关日志 → 退出循环,进入阶段2 │ │
│ │ ├─ ❌ 无结果:尝试自动调整 → 仍无结果 → 请求用户补充信息 │ │
│ │ └─ 🔄 用户提供新信息 → 回到信息收集 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 🚪 退出条件 │ │
│ │ ├─ ✅ 查询到相关日志 │ │
│ │ ├─ ⏭️ 用户要求跳过 │ │
│ │ └─ ❌ 用户无法提供更多信息且所有策略已尝试 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
信息收集(三个来源)
⚠️ 关键原则:查询条件必须从三个来源综合整理,而不是仅依赖单一来源。
🔴 信息收集优先级策略(重要!):
1. 首先:尽量从工单信息和代码分析中提取必要的查询条件
2. 其次:如果工单和代码中确实无法获取某些关键信息,再向用户询问
3. 原则:减少对用户的打扰,尽可能自动从已有信息中推断
1️⃣ 来源一:工单信息(优先级:高)
从工单内容中直接提取的信息:
| 信息类型 | 提取内容 | 示例 |
|---|---|---|
| 时间信息 | 问题发生时间、邮件发送时间 | "2025-01-20 10:00" |
| 用户信息 | 用户ID、账号、邮箱 | "用户ID: 123456" |
| 设备信息 | 设备ID、客户端ID | "client_id: abc123" |
| 错误信息 | 错误截图、错误描述 | "报错:网络异常" |
| 功能描述 | 涉及的功能、页面 | "登录页面" |
| 操作描述 | 用户操作步骤 | "点击登录按钮后..." |
⚠️ 重要:工单中可能包含隐藏信息,需要仔细分析:
- 截图中可能包含用户ID、设备ID、时间戳等
- 邮件转发链中可能包含原始报错时间
- 用户描述中可能隐含功能/接口信息
2️⃣ 来源二:代码分析信息(优先级:高)
从代码中分析得到的辅助信息:
| 信息类型 | 分析方法 | 用途 |
|---|---|---|
| 接口路径映射 | 从 signoz_config.json 的 api_pathname_mapping 获取 | 将用户描述的功能映射到实际接口路径 |
| 服务名映射 | 从 signoz_config.json 的 service_name_mapping 获取 | 将用户描述的服务映射到实际服务名 |
| 字段映射 | 从 signoz_config.json 的 field_extraction_rules 获取 | 将用户描述的字段映射到实际字段名 |
| 代码逻辑分析 | 读取相关代码文件 | 理解功能实现,定位可能的错误点 |
| 错误码映射 | 从代码中分析错误码定义 | 将错误描述映射到可能的错误码或错误消息 |
⚠️ 重要:代码分析可以补充大量信息:
- 通过功能描述反推可能涉及的接口路径
- 通过错误描述反推可能的错误类型和日志关键词
- 通过业务逻辑分析可能的出错点
3️⃣ 来源三:用户补充信息(优先级:低 - 仅在必要时询问)
用户在对话过程中提供的额外信息:
- 用户回答问题时提供的更精确信息
- 用户补充的用户ID、设备ID
- 用户提供的更精确的时间范围
- 用户确认的功能/接口信息
- 用户提供的其他定位信息(IP、地理位置等)
🚨 何时向用户询问信息:
- ❌ 不要:在还没尝试从工单和代码中提取信息时就询问用户
- ❌ 不要:在还没尝试使用已有信息进行查询时就询问用户
- ✅ 可以:在工单和代码中确实无法获取,且查询无结果时询问用户
- ✅ 可以:在自动调整策略都尝试过后仍无结果时询问用户
⚠️ 重要:每次用户提供新信息后,必须将新信息整合到现有查询条件中,然后重新进入查询循环。
查询条件评估
在执行查询之前,必须评估当前是否具备足够的查询条件:
必须条件(缺一不可)
| 条件 | 说明 | 如何获取 |
|---|---|---|
| 服务名称 | 必须知道查询哪个服务 | 工单信息 + service_name_mapping |
| 时间范围 | 必须有查询时间范围 | 工单时间 / 邮件时间 / 默认最近24小时 |
推荐条件(强烈建议,但可尝试无条件查询)
| 条件 | 说明 | 如果缺失如何处理 |
|---|---|---|
| 用户标识 | user.id 或 user.client_id | 1. 先尝试从工单/代码推断 2. 尝试不带用户标识查询 3. 最后才询问用户 |
| 接口路径 | 相关功能的API路径 | 从功能描述 + api_pathname_mapping 推断 |
🔴 条件不足时的处理策略(重要!)
🚨 核心原则:先尝试查询,再考虑询问用户!
处理流程:
1. 【自动推断】从工单和代码中尽可能提取/推断信息
├─ 分析工单截图、描述中的隐藏信息
├─ 使用 signoz_config.json 映射功能到接口
└─ 通过代码分析推断可能的错误点
2. 【尝试查询】即使信息不完整,也先尝试查询
├─ 使用已有的服务名 + 时间范围进行广泛查询
├─ 通过错误关键词、接口路径等进行过滤
└─ 从查询结果中提取用户ID、设备ID等信息
3. 【自动调整】如果查询无结果,尝试自动调整策略
├─ 放宽查询条件
├─ 扩展时间范围
├─ 切换时间优先级
└─ 尝试其他关键词/接口
4. 【最后手段】只有在上述方法都失败后,才询问用户
├─ 明确告知已尝试的策略和结果
├─ 说明为什么需要额外信息
└─ 提供具体的信息获取方式
❌ 禁止行为:
- 一开始就询问用户提供用户ID/设备ID
- 未尝试查询就要求用户补充信息
- 查询一次无结果就立即询问用户
✅ 正确行为:
- 先用已有信息尝试查询
- 自动尝试多种查询策略
- 从查询结果中提取更多信息
- 穷尽自动方法后才询问用户
示例对话(正确示范):
AI: 我分析了工单信息,发现:
- 服务名:xxx-service
- 时间范围:2025-01-20 10:00 前后
- 功能:登录页面
- 用户标识:工单中未直接提供
我将先尝试通过错误类型和接口路径查询,看能否从日志中找到相关用户...
[执行查询1:服务名 + 时间 + 登录接口 + ERROR级别]
结果:找到5条错误日志
[分析日志,提取用户信息]
从日志中发现用户ID: 12345678
现在我将使用这个用户ID进行更精确的查询...
---
AI: (穷尽自动方法后)我已经尝试了以下查询策略:
1. 通过登录接口 + ERROR 级别查询 → 无结果
2. 扩展时间范围到 ±4小时 → 无结果
3. 放宽条件只查服务名 → 找到日志但无法定位具体用户
为了进一步定位问题,我需要更多信息。您能提供以下任一信息吗?
- 用户ID(通常在个人资料页面)
- 设备ID(通常在设置页面的"关于"中)
执行查询
当条件充足时,执行以下查询流程:
- 创建/更新工单目录 -
.online-ticket-analyzer/tickets/ticket_xxx/ - 保存工单信息 -
ticket_info.json(包含从三个来源整理的所有信息) - 生成查询指令 -
mcp_instructions.json - 执行 SigNoz MCP 查询
- 保存查询结果 -
mcp_results.json
结果评估与循环
查询执行后,评估结果:
✅ 查询到相关日志
- 日志数量 > 0
- 日志内容与问题相关(能够帮助定位问题)
- → 退出循环,进入阶段2(综合分析)
❌ 无结果或结果不相关
执行以下自动调整策略(按顺序尝试):
- 检查字段歧义 - 如果 rows 为 null,检查 warnings
- 验证服务名称 - 使用 signoz_list_services 确认
- 放宽查询条件 - 移除部分过滤条件
- 扩展时间范围 - 从 ±2小时 扩展到 ±4小时、±24小时
- 切换时间优先级 - 尝试其他时间点
如果自动调整后仍无结果:
- 向用户请求更多信息
- 明确说明已尝试的策略和结果
- 询问用户是否有其他信息可以提供
🔄 用户提供新信息
- 将新信息整合到现有条件中
- 回到信息收集步骤,重新开始循环
循环退出条件
满足以下任一条件时退出循环:
| 条件 | 退出后行为 |
|---|---|
| ✅ 查询到相关日志 | 进入阶段2(综合分析) |
| ⏭️ 用户明确要求跳过 | 进入阶段2(生成 preliminary_analysis.md) |
| ❌ 用户无法提供更多信息 | 进入阶段2(生成 preliminary_analysis.md) |
工单信息文件规范
.online-ticket-analyzer/tickets/ticket_xxx/ticket_info.json 字段规范:
必须字段(必须包含):
- ticket_id:工单ID(字符串),格式:ticket_YYYYMMDD_xxx
- problem:问题描述(字符串)
- query_loop_status:查询循环状态(对象),包含:
- current_iteration:当前迭代次数
- status:状态(in_progress / completed / skipped)
- exit_reason:退出原因(如果已退出)
尽量要的字段(尽量包含):
- sources:信息来源汇总(对象),包含:
- ticket_info:从工单提取的信息
- user_provided:用户补充的信息
- code_analysis:从代码分析的信息
- user_id:用户ID
- client_id:设备ID
- service:服务名称
- times:时间信息数组
- keywords:关键词数组
常见场景处理指南
根据工单描述的问题类型,采用不同的查询策略和处理流程:
场景1:登录失败/登录不成功
特征:用户反馈无法登录、登录失败、登录报错等
⚠️ 关键原则:即使工单中提供了 user.id,也应该优先使用 user.client_id(设备ID) 进行查询。因为登录失败意味着用户在该设备上未能成功认证,此时服务端日志中可能没有该 user.id 的登录记录。
为什么优先使用 client_id:
- 登录失败 = 认证未成功 = 服务端可能无法识别用户身份
- 服务端日志中,登录失败的请求可能只记录了设备ID,没有用户ID
- 用户提供的 user.id 是他们"想要"登录的账号,但在失败的请求中可能不存在
查询策略:
1. 优先使用 user.client_id 查询登录相关接口的日志
2. 查询登录相关接口(如 /api/login、/api/auth、/api/oauth、/api/token 等)
3. 关注错误级别日志(severity_text = 'ERROR')
4. 提取登录失败的具体原因(密码错误、账号不存在、验证码错误、OAuth失败、Token过期等)
5. 如果使用 client_id 无法定位,再尝试使用 user.id 查询(可能有部分日志记录了尝试登录的账号)
示例查询条件:
# 优先使用 client_id
filter.expression: "resource.service.name IN ('xxx-service') AND attribute.user.client_id = 'xxx' AND attribute.http.target CONTAINS 'login'"
# 备选:使用 user.id(如果 client_id 无结果)
filter.expression: "resource.service.name IN ('xxx-service') AND attribute.user.id = 123456 AND attribute.http.target CONTAINS 'login'"
场景2:用户未登录/未认证访问
特征:用户反馈功能无法使用,但用户当时未登录
处理流程:
1. 工单中没有 user.id → 优先获取 user.client_id
2. 如果工单提供了邮箱/账号 → 先查询该账号的登录记录,获取关联的 user.client_id
3. 使用 user.client_id 查询用户的操作日志
场景3:支付/交易失败
特征:支付失败、扣款失败、订单创建失败等
查询策略:
1. 查询支付相关接口(/api/payment、/api/order、/api/checkout 等)
2. 关注订单ID、交易ID等关键字段
3. 查询第三方支付回调日志
4. 检查是否有超时或网络错误
场景4:页面加载失败/白屏
特征:页面打不开、白屏、加载超时等
查询策略:
1. 查询前端错误日志(如果有上报)
2. 查询页面依赖的API接口调用
3. 关注资源加载相关的日志
4. 检查是否有CDN或静态资源问题
场景5:功能异常/数据错误
特征:某功能不正常、数据显示错误、操作无响应等
查询策略:
1. 定位具体功能对应的后端接口
2. 查询该接口的请求和响应日志
3. 对比正常和异常情况下的数据差异
4. 检查是否有业务逻辑错误
场景6:性能问题/响应慢
特征:页面加载慢、接口响应慢、操作卡顿等
查询策略:
1. 查询接口响应时间(duration_nano 或类似字段)
2. 使用 Traces 数据分析调用链路
3. 定位耗时最长的服务或操作
4. 检查是否有数据库慢查询
场景7:间歇性问题/偶发问题
特征:问题偶尔出现、时好时坏、某些用户有问题某些没有
查询策略:
1. 扩大时间范围查询,收集多次问题出现的日志
2. 对比正常和异常请求的差异
3. 检查是否与特定条件相关(时间、地域、设备类型等)
4. 分析是否为普遍性问题
时间范围计算优先级
⚠️ 重要约束:最长查询时间范围为3天。
⚠️ 关键原则:如果工单中明确说明了问题发生时间,以明确说明的时间为准(最高优先级)。
时间优先级(从高到低):
- 明确说明的发生时间前后2小时(最高优先级)
- 如果工单中明确说明了问题发生时间,优先使用该时间
- 计算范围:
start = 明确说明的发生时间 - 2小时,end = 明确说明的发生时间 + 2小时 -
⚠️ 重要:必须基于工单中的实际时间戳计算,不能使用当前时间
-
邮件中最早发送时间前后2小时(次优先级)
- 如果工单中没有明确说明发生时间,使用邮件中最早发送的时间
- 如果工单中有多个邮件沟通时间点,使用邮件中最早发送的时间
- 计算范围:
start = 邮件中最早发送时间 - 2小时,end = 邮件中最早发送时间 + 2小时 -
⚠️ 重要:必须基于工单中的实际时间戳计算,不能使用当前时间
-
最近1天时间(第三优先级)
- 如果前两个优先级都查询无结果,使用最近1天时间
-
计算范围:
start = 当前时间 - 24小时,end = 当前时间 -
工单中其他提到的时间点当天(最低优先级)
- 如果前三个优先级都无结果,依次查询工单中其他提到的时间点当天
- 计算范围:每个时间点的当天(00:00:00 到 23:59:59)
查询策略:
- 时间区间内的完整查询:
- 每个时间区间内需要完整地根据工单信息查询相关的所有逻辑
- 查询顺序(根据工单场景逐步扩展):
- 第一步:如果功能涉及到接口查询,先查该用户接口相关数据
- 第二步:如果没有结果,查询该用户报错相关数据
- 第三步:如果还是没有,查询该用户对应时间段所有日志
- 第四步:根据不同场景,可能还需要查询其他相关数据(如设备信息、地理位置等)
-
⚠️ 重要:不同场景查询的内容可能有差异,需要根据工单信息灵活调整
-
时间切换条件:
- ⚠️ 关键逻辑:时间切换不是某个查询为空就切换
- 而是:当前时间区间内所有查询都执行完毕,且所有查询结果都无法定位到问题(无数据或数据不相关),才切换到下一个时间优先级
- 提前终止:如果当前时间区间内任意一个查询查到符合要求的数据(有数据并且相关数据能够定位到问题),则不再查询后续时间优先级
-
⚠️ 重要判断:仅仅有数据还不够,必须判断数据是否相关和能够定位到问题
-
超时重试机制:
- 如果查询超时,自动优化时间区间长度(缩短为原来的一半),继续自动重试对应的查询
- 最多重试3次,如果仍然超时,记录错误并继续当前时间区间内的下一个查询
时间范围自动调整
⚠️ 关键逻辑:时间范围调整的判断必须基于计算出的查询时间范围,而不是工单时间本身。
调整规则:
1. 未来时间判断:
- 如果 start > 当前时间,说明查询时间范围在未来
- 只有在这种情况下,才调整为最近24小时(基于当前时间)
- ⚠️ 错误示例:工单时间是 2024-12-31(过去时间),但计算出的查询范围是 2024-12-31 02:00 到 2025-01-04 14:00,这个范围是过去时间,不应该调整为当前时间
- 过去时间处理:
- 如果计算出的查询时间范围是过去时间(
end < 当前时间),直接使用该时间范围 -
如果时间在很久以前(超过30天),提示用户确认时间范围,但仍然使用该时间范围
-
时间范围限制:
- ⚠️ 最长3天:任何查询时间范围不能超过3天
-
如果计算出的时间范围超过3天,自动截断为3天(保留最接近当前时间的3天)
-
窄时间范围(小于2小时):自动扩展为+/- 2小时
-
超时重试机制:
- 如果查询超时,自动优化时间区间长度(缩短为原来的一半)
- 继续自动重试对应的查询
- 最多重试3次,如果仍然超时,记录错误并继续下一个优先级
正确示例:
- 工单时间:2024-12-31 11:13:01(timestamp: 1735617181000)
- 计算查询范围:2024-12-31 09:13:01 到 2024-12-31 13:13:01(前后2小时)
- 当前时间:2026-01-22
- 判断:查询范围是过去时间,直接使用该时间范围,不调整
错误示例(避免):
- 工单时间:2024-12-31(过去时间)
- 错误判断:认为工单时间是"未来时间"(因为年份是2024,但实际是过去)
- 错误调整:调整为当前时间(2026-01-22)的最近24小时
- 结果:查询时间变成 2026-01-21 到 2026-01-22,完全错误
SigNoz执行命令生成
查询工具选择优先级
推荐优先级(从高到低):
- signoz_execute_builder_query(Query Builder v5) - 强烈推荐
- 更灵活,支持复杂过滤条件
- 字段路径更直观
- 支持多条件组合查询
- 使用毫秒时间戳
-
支持日志(logs)、指标(metrics)、追踪(traces)三种数据源
-
signoz_list_services - 必须首先执行
- 获取服务列表,确认服务名称
- 实际运行时的服务名可能与代码中的不同
- ⚠️ 重要:需要纳秒时间戳(不是毫秒),或使用
timeRange参数 -
强烈推荐:使用
timeRange参数(如 "1h", "4h", "24h"),避免时间戳单位错误 -
signoz_search_logs_by_service - 按服务搜索日志(使用毫秒时间戳)
- 支持文本搜索、严重程度过滤
-
适用于快速日志搜索场景
-
signoz_get_error_logs - 快速错误查询(使用毫秒时间戳)
- 专门用于查询 ERROR 或 FATAL 级别的日志
- 支持服务过滤
SigNoz MCP 工具完整列表
日志查询工具:
- signoz_execute_builder_query - Query Builder v5 查询(推荐,支持 logs/metrics/traces)
- signoz_search_logs_by_service - 按服务搜索日志
- signoz_get_error_logs - 获取错误日志(ERROR/FATAL)
- signoz_list_log_views - 列出保存的日志视图
- signoz_get_log_view - 获取日志视图详情
- signoz_get_logs_available_fields - 获取日志可用字段列表
- signoz_get_logs_field_values - 获取日志字段值(用于过滤选项)
追踪查询工具:
- signoz_search_traces_by_service - 按服务搜索追踪
- signoz_get_trace_details - 获取追踪详情(包含所有 spans)
- signoz_get_trace_error_analysis - 分析追踪中的错误模式
- signoz_get_trace_span_hierarchy - 获取追踪跨度层次结构
- signoz_get_trace_available_fields - 获取追踪可用字段列表
- signoz_get_trace_field_values - 获取追踪字段值
指标查询工具:
- signoz_list_metric_keys - 列出可用指标键
- signoz_search_metric_by_text - 按文本搜索指标
- signoz_get_metrics_available_fields - 获取指标可用字段列表
- signoz_get_metrics_field_values - 获取指标字段值
服务相关工具:
- signoz_list_services - 列出所有服务(必须首先执行,使用纳秒时间戳或 timeRange)
- signoz_get_service_top_operations - 获取服务的顶部操作(使用纳秒时间戳或 timeRange)
仪表板工具:
- signoz_list_dashboards - 列出所有仪表板
- signoz_get_dashboard - 获取仪表板详情
- signoz_create_dashboard - 创建新仪表板
- signoz_update_dashboard - 更新现有仪表板
警报工具:
- signoz_list_alerts - 列出所有警报规则
- signoz_get_alert - 获取警报规则详情
- signoz_get_alert_history - 获取警报历史记录
- signoz_get_logs_for_alert - 获取与警报相关的日志
每个时间区间内的完整查询流程
⚠️ 重要:每个时间区间内需要完整地根据工单信息查询相关的所有逻辑,不能因为某个查询为空就提前切换。
⚠️ 数据判断标准:符合要求的数据不仅仅是"非空",而是有数据并且相关数据能够定位到问题。仅仅有数据还不够,必须判断数据是否相关和能够定位到问题。
⚠️ 迭代式查询策略:
- 创建查询不是一次性的:创建SigNoz查询并不一定一次生成完整的,而是可以根据查询的数据或其他信息补充后继续生成新的查询思路
- 动态调整查询:根据查询结果、错误信息、特征信息等,动态调整和补充查询策略
- 逐步深入定位:相关流程符合日志查询定位的流程,逐步深入,最终目标是定位到问题原因
- 查询思路演进:
1. 初始查询:基于工单信息生成基础查询(服务名、用户ID、时间范围等)
2. 结果分析:分析查询结果,提取关键信息(错误类型、接口路径、设备信息、地理位置等)
3. 补充查询:基于分析结果,生成更精确的查询(如特定接口、特定错误类型、特定设备等)
4. 迭代深入:继续分析新查询结果,进一步细化查询条件,直到定位到问题原因
查询顺序(根据工单场景逐步扩展):
- 接口相关数据查询(如果功能涉及到接口):
- 如果工单中提到了接口路径、API调用、接口错误等,优先查询接口相关数据
- 初始查询:
resource.service.name+attribute.user.id+attribute.request.pathname+ 时间范围- ⚠️ 关键:如果字段有歧义,在
filter.expression中必须使用完整前缀(resource.service.name、attribute.user.id)
- ⚠️ 关键:如果字段有歧义,在
- 查询字段:
request.pathname,request.method,response.status,response.body,duration_nano等 - ⚠️ 迭代查询:如果初始查询有数据但无法定位问题,分析结果后生成补充查询:
- 如果发现特定接口有问题,查询该接口的详细日志
- 如果发现特定状态码,查询该状态码的所有请求
- 如果发现特定错误信息,查询包含该错误的所有日志
- ⚠️ 判断标准:如果查询到数据,需要判断数据是否相关和能够定位到问题原因
- 如果数据能够定位到问题原因,可以提前终止(不再查询后续类型)
-
如果查询为空或数据不相关无法定位问题,继续下一步
-
报错相关数据查询:
- 如果接口查询无结果或数据无法定位问题,或工单中提到了错误、异常、失败等,查询报错相关数据
- 初始查询:
resource.service.name+attribute.user.id+severity_text IN ('error', 'Error', 'ERROR', 'fatal', 'Fatal', 'FATAL')+ 时间范围- ⚠️ 关键:如果字段有歧义,在
filter.expression中必须使用完整前缀(resource.service.name、attribute.user.id)
- ⚠️ 关键:如果字段有歧义,在
- 查询字段:
severity_text,body,message,error.message,error.stack等 - ⚠️ 迭代查询:如果初始查询有数据但无法定位问题,分析结果后生成补充查询:
- 如果发现特定错误类型,查询该错误类型的所有日志
- 如果发现错误堆栈,查询包含相同堆栈的所有错误
- 如果发现错误消息模式,查询匹配该模式的所有错误(优先使用
message字段,而不是body)
- ⚠️ 判断标准:如果查询到数据,需要判断数据是否相关和能够定位到问题原因
- 如果数据能够定位到问题原因,可以提前终止(不再查询后续类型)
-
如果查询为空或数据不相关无法定位问题,继续下一步
-
所有日志查询:
- 如果前两步都无结果或数据无法定位问题,查询该用户对应时间段所有日志
- 初始查询:
resource.service.name+attribute.user.id+ 时间范围- ⚠️ 关键:如果字段有歧义,在
filter.expression中必须使用完整前缀(resource.service.name、attribute.user.id)
- ⚠️ 关键:如果字段有歧义,在
- 查询字段:
body,message,severity_text,timestamp等所有相关字段 - ⚠️ 迭代查询:如果初始查询有数据但无法定位问题,分析结果后生成补充查询:
- 如果发现关键词模式,优先使用结构化字段(如
message)进行查询,而不是body - ⚠️ 重要:一般不会从
body中去匹配关键词,优先使用结构化字段 - 如果发现时间模式,查询特定时间段的日志
- 如果发现设备或地理位置模式,查询特定设备或地理位置的日志
- 如果发现关键词模式,优先使用结构化字段(如
- ⚠️ 判断标准:如果查询到数据,需要判断数据是否相关和能够定位到问题原因
- 如果数据能够定位到问题原因,可以提前终止(不再查询后续类型)
-
如果查询为空或数据不相关无法定位问题,继续下一步
-
其他相关数据查询(根据场景调整):
- 根据不同场景,可能还需要查询:
- 设备信息:
user.client_id,device.id等 - 地理位置:
geo.city_name,geo.country_name等 - 浏览器信息:
browser.name,browser.version等 - 应用版本:
service.version等
- 设备信息:
- ⚠️ 重要:一般不会从
body中去匹配关键词- 优先使用结构化字段进行过滤(如
message、severity_text、request.pathname等) - 只有在确实需要搜索日志内容时,才使用
body LIKE '%关键词%'或message LIKE '%关键词%' - 避免过度使用
body LIKE查询,因为性能较差
- 优先使用结构化字段进行过滤(如
时间切换条件:
- ⚠️ 关键逻辑:必须执行完当前时间区间内的所有查询(接口相关 → 报错相关 → 所有日志 → 其他相关)
- 只有当所有查询都执行完毕,且所有查询结果都无法定位到问题(无数据或数据不相关)时,才切换到下一个时间优先级
- 如果当前时间区间内任意一个查询有数据并且相关数据能够定位到问题,则不再查询后续时间优先级
- ⚠️ 重要判断:仅仅有数据还不够,必须判断数据是否相关和能够定位到问题
时间戳单位说明
⚠️ 关键问题:不同工具使用不同的时间戳单位!
- 纳秒时间戳(需要乘以 1,000,000):
signoz_list_services- 列出服务-
signoz_get_service_top_operations- 获取服务顶部操作 -
毫秒时间戳(标准,大部分工具使用):
- 日志查询:
signoz_execute_builder_query、signoz_search_logs_by_service、signoz_get_error_logs、signoz_list_log_views、signoz_get_log_view、signoz_get_logs_available_fields、signoz_get_logs_field_values - 追踪查询:
signoz_search_traces_by_service、signoz_get_trace_details、signoz_get_trace_error_analysis、signoz_get_trace_span_hierarchy、signoz_get_trace_available_fields、signoz_get_trace_field_values - 指标查询:
signoz_list_metric_keys、signoz_search_metric_by_text、signoz_get_metrics_available_fields、signoz_get_metrics_field_values - 警报:
signoz_list_alerts、signoz_get_alert、signoz_get_alert_history、signoz_get_logs_for_alert - 仪表板:
signoz_list_dashboards、signoz_get_dashboard、signoz_create_dashboard、signoz_update_dashboard
推荐解决方案:
- 优先使用 timeRange 参数(如 "1h", "4h", "24h"),避免时间戳单位错误
- 如果必须使用 start/end 参数,确保单位正确:
- signoz_list_services 和 signoz_get_service_top_operations: 纳秒(毫秒 × 1,000,000)
- 其他所有工具: 毫秒
Query Builder v5 格式要求
⚠️ 关键格式要求:
🚨🚨🚨 字段歧义处理(最重要!必须首先阅读)🚨🚨🚨
问题现象:查询结果中rows为null,且warnings中出现类似以下警告:
"key user.id is ambiguous, found 3 different combinations of field context and data type:
[name=user.id,context=attribute,type=string name=user.id,context=attribute,type=number name=user.id,context=attribute,type=bool]"
❌ 错误做法(只在selectFields中指定fieldContext,仍然会失败):
{
"filter": {
"expression": "service.name IN ('cs.web.camscanner-toc') AND user.id = 1734170267"
},
"selectFields": [
{"name": "user.id", "fieldContext": "attribute", "fieldDataType": "number", ...}
]
}
⚠️ 上面这种写法是错误的!filter.expression中没有使用完整前缀,仍然会出现歧义警告!
✅ 正确做法(必须同时在filter.expression中使用完整前缀):
{
"filter": {
"expression": "resource.service.name IN ('cs.web.camscanner-toc') AND attribute.user.id = 1734170267"
},
"selectFields": [
{"name": "service.name", "fieldContext": "resource", "fieldDataType": "string", "signal": "logs"},
{"name": "user.id", "fieldContext": "attributes", "fieldDataType": "float64", "signal": "logs"}
]
}
🔑 关键规则(必须同时满足):
1. filter.expression 中必须使用完整前缀:
- service.name → resource.service.name
- user.id → attribute.user.id
- user.client_id → attribute.user.client_id
2. selectFields 中必须指定 fieldContext 和 fieldDataType:
- service.name:fieldContext: "resource", fieldDataType: "string"
- user.id:fieldContext: "attributes", fieldDataType: "float64"(Number类型字段使用float64)
⚠️ 特别注意:
- fieldContext 的值:资源字段用 "resource"(单数),属性字段用 "attributes"(复数)
- fieldDataType 的值:
- Number类型字段(如user.id、response.status)使用 "float64"
- String类型字段使用 "string"
- 只在 selectFields 中指定是不够的,必须同时在 filter.expression 中使用完整前缀!
常见歧义字段快速参考表:
| 字段 | filter.expression 中的写法 | selectFields 中的配置 |
|---|---|---|
service.name |
resource.service.name IN ('xxx') |
{"name": "service.name", "fieldContext": "resource", "fieldDataType": "string", "signal": "logs"} |
user.id |
attribute.user.id = 1234567 |
{"name": "user.id", "fieldContext": "attributes", "fieldDataType": "float64", "signal": "logs"} |
user.client_id |
attribute.user.client_id = 'xxx' |
{"name": "user.client_id", "fieldContext": "attributes", "fieldDataType": "string", "signal": "logs"} |
- filter格式:
- ✅ 使用
filter(单数)和expression(SQL-like字符串) -
❌ 不使用
filters(复数)和items数组格式 -
字段歧义处理详细说明:
- 对于有歧义的字段,必须同时:
- 在
filter.expression中使用完整前缀(resource.或attribute.) - 在
selectFields中明确指定fieldContext和fieldDataType
- 在
- 常见歧义字段:
service.name:在resource和attribute上下文中都有string类型(通常使用resource上下文)user.id:在attributes上下文中有多种类型,实际使用float64类型(Number类型)
-
警告示例:
```
"key service.name is ambiguous, found 2 different combinations of field context and data type:
[name=service.name,context=resource,type=string name=service.name,context=attribute,type=string]""key user.id is ambiguous, found 3 different combinations of field context and data type:
[name=user.id,context=attribute,type=number name=user.id,context=attribute,type=string name=user.id,context=attribute,type=bool]"
- **完整解决方案示例**:json
{
"filter": {
"expression": "resource.service.name IN ('cs.web.camscanner-toc') AND attribute.user.id = 1734170267"
},
"selectFields": [
{
"name": "service.name",
"fieldContext": "resource",
"fieldDataType": "string",
"signal": "logs"
},
{
"name": "user.id",
"fieldContext": "attributes",
"fieldDataType": "float64",
"signal": "logs"
},
{
"name": "body",
"fieldDataType": "string",
"signal": "logs"
}
],
"having": {
"expression": ""
}
}
``` -
fieldContext字段:
- 一般情况下:查询时不要添加
fieldContext字段,SigNoz会自动识别 -
有歧义时:必须明确指定
fieldContext和fieldDataType -
formatTableResultForUI:
-
必须设置为
true,以便正确显示结果 -
having字段:
-
必须包含:
"having": {"expression": ""} -
order字段:
- key只包含name:
{"key": {"name": "timestamp"}, "direction": "desc"}
SigNoz Query Builder v5 支持的查询操作
数据源类型(signal):
- logs - 日志数据:支持日志查询、过滤、聚合
- metrics - 指标数据:支持指标查询、时间序列聚合、空间聚合
- traces - 追踪数据:支持分布式追踪查询、span分析
过滤操作(filter.expression):
支持SQL-like表达式,包括:
- 比较操作符:
=- 等于!=或<>- 不等于>- 大于>=- 大于等于<- 小于<=- 小于等于IN- 在列表中(如service.name IN ('service1', 'service2'))NOT IN- 不在列表中LIKE- 模式匹配(如message LIKE '%error%')NOT LIKE- 不匹配模式IS NULL- 为空-
IS NOT NULL- 不为空 -
逻辑操作符:
AND- 逻辑与OR- 逻辑或NOT- 逻辑非-
支持括号分组:
(condition1 OR condition2) AND condition3 -
字段路径格式:
- 资源字段:
resource.service.name、resource.service.version、resource.service.environment - 属性字段:
attribute.user.id、attribute.request.pathname、attribute.response.status - 简化格式(无歧义时):
service.name、user.id、request.pathname -
⚠️ 重要:有歧义的字段必须使用完整前缀(
resource.或attribute.) -
值类型:
- 字符串:使用单引号
'value' - 数字:直接使用数字,不需要引号
- 布尔值:
true或false - 数组:
IN ('value1', 'value2', 'value3')
聚合操作(aggregations):
- 时间聚合(timeAggregation):
avg- 平均值sum- 求和min- 最小值max- 最大值count- 计数-
p50、p95、p99- 百分位数 -
空间聚合(spaceAggregation):
avg- 平均值sum- 求和min- 最小值max- 最大值-
latest- 最新值 -
序列聚合(seriesAggregation)(用于groupBy时):
avg- 平均值sum- 求和min- 最小值-
max- 最大值 -
聚合操作符(aggregateOperator):
count- 计数count_distinct- 去重计数sum- 求和avg- 平均值min- 最小值max- 最大值p50、p95、p99- 百分位数rate- 速率rate_sum- 速率求和rate_avg- 速率平均值rate_max- 速率最大值
分组操作(groupBy):
- 支持按一个或多个字段分组
- 字段格式:{"key": "field.name", "name": "field.name", "dataType": "string", "type": "tag"}
- 示例:按服务名分组、按用户ID分组、按接口路径分组
排序操作(orderBy):
- 支持按字段升序(asc)或降序(desc)排序
- 格式:{"columnName": "timestamp", "order": "desc"}
- 支持多字段排序
分页操作:
- limit - 限制返回记录数(默认100,最大建议1000)
- offset - 跳过记录数(用于分页)
- pageSize - 页面大小
字段选择(selectFields):
- 指定要返回的字段
- 支持资源字段、属性字段
- 必须指定字段的数据类型和上下文(如有歧义)
Having子句(having):
- 用于对聚合结果进行过滤
- 格式:{"expression": "count > 10"}
函数支持(functions):
- 支持在查询中使用函数
- 格式:{"name": "function_name", "args": [arg1, arg2], "namedArgs": {}}
时间范围(start/end):
- 使用毫秒时间戳
- 或使用 timeRange 参数(推荐):"1h", "4h", "24h", "7d" 等
查询类型(type):
- builder_query - Query Builder查询(推荐)
- clickhouse_sql - ClickHouse SQL查询(高级用法)
- promql - PromQL查询(用于指标)
查询组合(compositeQuery):
- 支持多个查询组合(queries数组)
- 支持查询公式(queryFormulas)
- 支持查询之间的运算和组合
查询指令结构
生成的 .online-ticket-analyzer/tickets/ticket_xxx/mcp_instructions.json 应包含:
{
"ticket_id": "ticket_20250120_abc123",
"time_range": {
"start": 1737361800000,
"end": 1737365400000,
"start_display": "2025-01-20 10:00:00",
"end_display": "2025-01-20 11:00:00"
},
"services": ["user-service"],
"queries": [
{
"priority": 1,
"tool": "signoz_list_services",
"params": {
"timeRange": "4h"
},
"description": "获取服务列表,确认服务名称(必须首先执行)。推荐使用timeRange参数,避免时间戳单位错误"
},
{
"priority": 2,
"tool": "signoz_execute_builder_query",
"params": {
"query": {
"schemaVersion": "v1",
"start": 1737361800000,
"end": 1737365400000,
"requestType": "raw",
"compositeQuery": {
"queries": [
{
"type": "builder_query",
"spec": {
"name": "A",
"signal": "logs",
"disabled": false,
"limit": 100,
"offset": 0,
"order": [
{
"key": {
"name": "timestamp"
},
"direction": "desc"
}
],
"selectFields": [
{
"name": "service.name",
"fieldContext": "resource",
"fieldDataType": "string",
"signal": "logs"
},
{
"name": "body",
"fieldDataType": "string",
"signal": "logs"
}
],
"filter": {
"expression": "service.name IN ('user-service') AND severity_text IN ('error', 'Error', 'ERROR')"
},
"having": {
"expression": ""
}
}
}
]
},
"formatOptions": {
"formatTableResultForUI": true,
"fillGaps": false
},
"variables": {}
}
},
"description": "查询错误日志"
}
]
}
查询执行注意事项
- 必须首先执行list_services:获取服务列表,确认服务名称
- 服务名过滤:在Query Builder中添加
service.name过滤条件 - 字段类型匹配:确保字段类型匹配(如
user.id是Number/float64类型,值应该是数字) - 时间范围验证:自动调整未来时间和窄时间范围,最长不超过3天
- 优先级查询策略:
- 按时间优先级从高到低依次查询(明确说明的发生时间前后2小时 > 邮件中最早发送时间前后2小时 > 最近1天 > 其他时间点当天)
- 每个时间区间内的完整查询:
- 根据工单信息,在当前时间区间内执行完整的查询流程
- 查询顺序:接口相关数据 → 报错相关数据 → 所有日志 → 其他相关数据(根据场景调整)
- 必须执行完当前时间区间内的所有查询
- 时间切换条件:
- 当前时间区间内所有查询都执行完毕,且所有查询结果都无法定位到问题(无数据或数据不相关),才切换到下一个时间优先级
- 如果当前时间区间内任意一个查询有数据并且相关数据能够定位到问题,不再查询后续时间优先级
- ⚠️ 重要判断:仅仅有数据还不够,必须判断数据是否相关和能够定位到问题
- 超时重试机制:
- 如果查询超时,自动优化时间区间长度(缩短为原来的一半)
- 继续自动重试对应的查询
- 最多重试3次,如果仍然超时,记录错误并继续下一个优先级
- 迭代查询:支持从查询结果中提取特征信息,进行更精确的查询
- 用户/设备信息缺失处理:
- 如果工单中没有提供用户信息或设备信息,先尝试通过工单中其他信息(接口路径、错误信息、关键词、时间范围、地理位置等)+ 代码相关逻辑生成相关查询
- 从查询结果中提取
user.id或user.client_id - 如果完全无法定位,则提示用户提供相关信息
查询结果为空处理
如果查询结果为空(rows 为 null 或 []):
- ⚠️ 必须生成:初步判断文档(.online-ticket-analyzer/tickets/ticket_xxx/preliminary_analysis.md)
- 诊断流程(按顺序执行):
1. 检查字段歧义:
- 如果 rows 为 null 且有 warnings 字段,检查是否有字段歧义警告
- 如果有字段歧义警告,必须修复(使用完整前缀和 fieldContext)
- 修复后重新执行查询
2. 验证服务名称:
- 执行 signoz_list_services 确认服务名称是否正确
- 如果服务名称不匹配,更新查询条件
3. 检查 rowsScanned 字段:
- 如果查询结果中 rowsScanned: 0,说明该时间段确实没有该服务的数据
- 可能原因:
- 服务名称不匹配(实际运行时可能使用不同的服务名称)
- 该时间段服务确实没有产生日志
- 日志可能存储在其他服务名称下
- 解决方案:
- 首先确认服务名称:使用 signoz_list_services 和更长的时间范围(24h 或 7d)
- 如果服务名称正确但 rowsScanned 为 0:
- 扩展时间范围(从 ±2 小时扩展到 ±24 小时或 ±7 天)
- 切换到其他时间优先级(明确说明的发生时间 → 邮件最早时间 → 最近1天 → 其他时间点)
- 查询不限定用户ID的服务日志,确认服务是否有数据
- 如果服务名称不正确:根据 signoz_list_services 的结果更新服务名称,重新执行查询
- 验证时间范围是否合理(不是未来时间、不过窄、不过长)
- 检查时间戳单位是否正确(纳秒 vs 毫秒)
- 如果时间范围有问题,自动调整后重新查询
4. 逐步放宽查询条件:
- 先查询服务 + 时间范围(不限定用户/设备)
- 如果有数据,再逐步添加过滤条件
- 如果放宽条件后仍无结果,继续下一步
5. 扩展时间范围:
- 如果当前时间范围无数据,尝试扩展时间范围
- 从 ±2 小时扩展到 ±4 小时或 ±24 小时
- 如果扩展后仍无结果,继续下一步
6. 切换到其他时间优先级:
- 如果当前时间优先级无数据,切换到下一个时间优先级
- 按优先级依次尝试:明确说明的发生时间 → 邮件最早时间 → 最近1天 → 其他时间点
7. 检查字段值:
- 使用 signoz_get_logs_field_values 检查字段的实际值
- 确认字段值是否存在和正确
- 用户/设备信息缺失处理:
- 如果工单中没有提供用户信息或设备信息,先尝试通过工单中其他信息(接口路径、错误信息、关键词、时间范围、地理位置等)+ 代码相关逻辑生成相关查询
- 从查询结果中提取user.id或user.client_id
- 如果完全无法定位到用户或设备信息,则提示用户提供相关信息
- 分析可能原因:
- 时间范围不正确(时间在未来、过窄、过长、时间戳单位错误)
- 服务名称不匹配(代码中的服务名与运行时不同)
- rowsScanned 为 0(该时间段确实没有该服务的数据,需要扩展时间范围或切换时间优先级)
- 字段歧义(导致 rows 为 null)
- 查询条件过于严格(过滤条件太严格,导致查不到数据)
- 缺少用户/设备信息(无法定位到具体用户或设备)
- 数据确实不存在(该时间范围内确实没有相关数据)
- 提示用户提供更精确的信息(如果无法通过查询定位)
- 不生成完整解决方案,等待用户提供更精确信息后重新分析
- 检查时间范围计算是否正确:
- ⚠️ 关键检查:时间范围必须基于工单中的实际时间戳计算
- 如果工单时间是过去时间,计算出的查询范围也应该是过去时间
- 不能将过去时间误判为未来时间并调整为当前时间
- 验证方法:比较 mcp_instructions.json 中的时间范围与工单时间是否匹配
SigNoz数据结构
字段上下文(Field Context)
SigNoz使用OpenTelemetry标准,将字段分为不同的上下文级别:
| 上下文类型 | 说明 | 示例字段 |
|---|---|---|
| resource | 资源级别字段,描述服务本身的信息 | service.name, service.version, service.environment |
| attributes | 属性级别字段,描述日志的具体内容 | body, severity_text, user.id, user.client_id |
| span | 跨度级别字段,用于追踪信息 | span_id, parent_span_id |
| log | 日志级别字段,日志特有的元数据 | log_level, log_source |
实际数据结构
根据实际上报的数据,SigNoz日志数据结构如下:
{
"body": "",
"id": "38CMFx09aoUNJYh8cZa1AgZj3Yi",
"timestamp": "2026-01-13T10:09:59.986Z",
"attributes": {
"user.id": 4472431079,
"user.client_id": "B4SMfdd5F0FW83e1a18rfA5J",
"geo.location.lat": 31.2222,
"geo.location.lon": 121.4581,
"geo.city_name": "Shanghai",
"geo.country_name": "China",
"source.address": "101.226.11.71",
"browser.name": "CamScannerWindows",
"browser.version": "1.0.17",
"message": "错误信息",
"name": "Error",
"stack": "错误堆栈",
"request.pathname": "/sync/revert_dir_list"
},
"resources": {
"service.name": "cs.web.camscanner-toc",
"service.version": "1.0.17",
"service.environment": "online"
},
"severity_text": "error",
"severity_number": 17
}
重要字段说明
资源级别字段(Resource)
| 字段名 | 数据类型 | 说明 | 使用场景 |
|---|---|---|---|
service.name |
string | 应用名称(格式:事业部.小组.项目名) | 服务过滤、分组 |
service.version |
string | 应用版本 | 版本追踪 |
service.environment |
string | 运行环境 | 环境区分(dev/staging/prod) |
注意:
- 实际数据结构中,服务信息存储在 resources 对象中(复数),不是 resource
- 在Query Builder中使用时,直接使用 service.name,不需要 resources. 前缀
用户和设备字段(Attributes - Tag类型)
| 字段名 | 数据类型 | fieldDataType | 说明 | 使用场景 |
|---|---|---|---|---|
user.id |
Number | float64 |
用户ID | 用户过滤、查询 |
user.client_id |
String | string |
客户端ID/设备ID | 设备过滤、查询 |
重要说明:
- 字段名是 user.id(点分隔),不是 user_id
- 字段名是 user.client_id(点分隔),不是 client_id 或 device_id
- ⚠️ user.id字段在SigNoz中显示为Number类型,在selectFields中使用fieldDataType: "float64"
- 这些字段位于attributes对象中,类型为Tag,在Query Builder中直接使用user.id即可
地理位置字段(Attributes - Tag类型)
| 字段名 | 数据类型 | fieldDataType | 说明 | 使用场景 |
|---|---|---|---|---|
geo.location.lat |
Number | float64 |
纬度 | 地理位置查询 |
geo.location.lon |
Number | float64 |
经度 | 地理位置查询 |
geo.city_name |
String | string |
城市名称 | 地理位置过滤 |
geo.country_name |
String | string |
国家名称 | 地理位置过滤 |
geo.country_iso_code |
String | string |
国家ISO代码 | 地理位置过滤(如CN、US) |
geo.continent_code |
String | string |
大洲代码 | 地理位置过滤(如AS、EU) |
geo.continent_name |
String | string |
大洲名称 | 地理位置过滤 |
geo.timezone |
String | string |
时区 | 时区分析 |
请求日志字段(Attributes - Tag类型)
| 字段名 | 数据类型 | fieldDataType | 说明 | 使用场景 |
|---|---|---|---|---|
pathname |
String | string |
请求路径(简化) | 接口路径查询 |
path |
String | string |
请求路径 | 接口路径查询 |
request.pathname |
String | string |
请求路径(完整) | 接口路径查询 |
request.host |
String | string |
请求域名 | 接口域名分析 |
request.method |
String | string |
请求方法 | 方法过滤(GET/POST等) |
request.query |
String | string |
请求查询参数 | 参数分析 |
request.body |
String | string |
请求体 | 请求内容分析 |
response.status |
Number | float64 |
响应状态码 | 错误过滤(200/500/404等) |
response.time |
Number | float64 |
响应时间(秒) | 性能分析 |
response.body |
String | string |
响应体 | 响应内容分析 |
response.errno |
String | string |
业务错误码 | 业务错误分析 |
referrer |
String | string |
来源页面 | 来源分析 |
浏览器信息字段(Attributes - Tag类型)
| 字段名 | 数据类型 | fieldDataType | 说明 | 使用场景 |
|---|---|---|---|---|
browser.name |
String | string |
浏览器名称 | 浏览器过滤(Chrome/Safari等) |
browser.version |
String | string |
浏览器版本 | 版本分析 |
browser.user_agent |
String | string |
完整User Agent | UA分析 |
服务信息字段(Resource类型)
| 字段名 | 类型 | 数据类型 | fieldDataType | 说明 | 使用场景 |
|---|---|---|---|---|---|
service.name |
Resource | String | string |
服务名称 | 服务过滤 |
service.version |
Resource | String | string |
服务版本 | 版本分析 |
service.environment |
Resource | String | string |
运行环境 | 环境过滤(online/staging等) |
日志元数据字段
| 字段名 | 数据类型 | fieldDataType | 说明 | 使用场景 |
|---|---|---|---|---|
id |
String | string |
日志ID | 唯一标识 |
timestamp |
- | - | 时间戳 | 时间范围查询 |
body |
String | string |
日志内容 | 全文搜索 |
severity_text |
String | string |
日志级别文本 | 错误过滤(ERROR/WARN等) |
severity_number |
Number | float64 |
日志级别数字 | 错误过滤(9=INFO, 17=ERROR等) |
trace_id |
String | string |
追踪ID | 链路追踪 |
span_id |
String | string |
跨度ID | 跨度关联 |
trace_flags |
Number | float64 |
追踪标志 | 追踪分析 |
scope_name |
String | string |
作用域名称 | 来源分析 |
scope_version |
String | string |
作用域版本 | 版本分析 |
localTime |
String | string |
本地时间 | 时间分析 |
通用字段(Attributes)
| 字段名 | 数据类型 | 说明 | 使用场景 |
|---|---|---|---|
body |
string | 日志内容(通用) | 日志正文查询、全文搜索 |
timestamp |
int64 | 时间戳(毫秒) | 时间范围查询、排序 |
trace_id |
string | 追踪ID | 追踪关联 |
span_id |
string | 跨度ID | 跨度关联 |
字段路径格式
在查询和结果解析中,字段可以使用以下格式:
- 简化格式(无歧义时使用):
service.name- 自动识别为resource级别(如果无歧义)body- 自动识别为attributes级别-
user.id- 自动识别为attributes级别(嵌套字段,如果无歧义) -
完整前缀格式(有歧义时必须使用):
-
⚠️ 关键:当字段有歧义时,在
filter.expression中必须使用完整前缀:resource.service.name- 明确指定resource级别(注意是单数resource,不是resources)attribute.user.id- 明确指定attribute级别(注意是单数attribute,不是attributes)attribute.user.client_id- 明确指定attribute级别attribute.request.pathname- 明确指定attribute级别attribute.response.status- 明确指定attribute级别
-
selectFields格式(有歧义时必须同时使用):
-
在
selectFields中使用fieldContext字段:{"name": "service.name", "fieldContext": "resource", "fieldDataType": "string", "signal": "logs"}{"name": "user.id", "fieldContext": "attributes", "fieldDataType": "float64", "signal": "logs"}
-
嵌套字段(重要):
user.id- 嵌套在attributes.user对象下的id字段(不是user_id)user.client_id- 嵌套在attributes.user对象下的client_id字段(不是client_id)geo.city_name- 嵌套在attributes.geo对象下的city_name字段request.pathname- 嵌套在attributes.request对象下的pathname字段
⚠️ 字段歧义处理规则:
- 如果字段有歧义警告,必须同时:
1. 在filter.expression中使用完整前缀(resource.或attribute.)
2. 在selectFields中明确指定fieldContext和fieldDataType
- 仅仅在selectFields中指定是不够的,必须同时在filter.expression中使用完整前缀!
严重程度(Severity)
严重程度文本值
错误级别的严重程度文本值(用于severity_text字段):
- error, Error, ERROR
- 异常, 错误
- fatal, Fatal, FATAL
- critical, Critical, CRITICAL
严重程度数字值
OpenTelemetry标准的严重程度数字(用于severity_number字段):
| 值 | 级别 | 说明 |
|---|---|---|
| 17 | ERROR | 错误 |
| 18 | FATAL | 致命错误 |
| 19-22 | CRITICAL | 严重错误 |
判断错误日志:
- severity_text 在错误值列表中,或
- severity_number >= 17
查询示例
示例1:查询特定服务的错误日志
{
"filter": {
"expression": "resource.service.name IN ('事业部.小组.项目名') AND severity_text IN ('error', 'Error', 'ERROR')"
},
"having": {
"expression": ""
},
"selectFields": [
{
"name": "service.name",
"fieldContext": "resource",
"fieldDataType": "string",
"signal": "logs"
}
]
}
注意:
- ⚠️ 关键:在filter.expression中必须使用完整前缀:resource.service.name(不是service.name)
- 如果service.name有歧义,必须同时在selectFields中明确指定fieldContext: "resource"
示例2:查询特定用户的日志
{
"filter": {
"expression": "attribute.user.id = 4472431079"
},
"having": {
"expression": ""
},
"selectFields": [
{
"name": "user.id",
"fieldContext": "attributes",
"fieldDataType": "float64",
"signal": "logs"
}
]
}
注意:
- ⚠️ 关键:在filter.expression中必须使用完整前缀:attribute.user.id(不是user.id)
- 字段名是 user.id(点分隔),不是 user_id
- user.id字段类型是Number(float64),值应该是数字,不需要引号
- ⚠️ 重要:user.id字段有歧义,必须同时:1) 在filter.expression中使用attribute.user.id;2) 在selectFields中明确指定fieldContext: "attributes"和fieldDataType: "float64"
示例3:查询特定设备的日志
{
"filter": {
"expression": "attribute.user.client_id = 'B4SMfdd5F0FW83e1a18rfA5J'"
},
"having": {
"expression": ""
},
"selectFields": [
{
"name": "user.client_id",
"fieldContext": "attributes",
"fieldDataType": "string",
"signal": "logs"
}
]
}
注意:
- ⚠️ 关键:在filter.expression中建议使用完整前缀:attribute.user.client_id(如果字段有歧义)
- 字段名是 user.client_id(点分隔),不是 client_id 或 device_id
- ⚠️ 重要:如果user.client_id字段有歧义,必须同时:1) 在filter.expression中使用attribute.user.client_id;2) 在selectFields中明确指定fieldContext: "attributes"和fieldDataType: "string"
示例4:查询特定接口的错误日志
{
"filter": {
"expression": "attribute.request.pathname = '/api/login' AND attribute.response.status IN (500, 502, 503)"
},
"having": {
"expression": ""
}
}
注意:
- ⚠️ 关键:如果字段有歧义,在filter.expression中使用完整前缀:attribute.request.pathname、attribute.response.status
- 一般request.pathname和response.status不会有歧义,但如果出现警告,需要使用attribute.前缀
示例5:处理字段歧义(完整示例)
如果遇到"key is ambiguous"警告,需要同时在filter.expression中使用完整前缀,并在selectFields中明确指定fieldContext和fieldDataType:
警告示例:
"key service.name is ambiguous, found 2 different combinations of field context and data type:
[name=service.name,context=resource,type=string name=service.name,context=attribute,type=string]"
"key user.id is ambiguous, found 3 different combinations of field context and data type:
[name=user.id,context=attribute,type=number name=user.id,context=attribute,type=string name=user.id,context=attribute,type=bool]"
完整解决方案(必须同时使用两种方法):
{
"selectFields": [
{
"name": "service.name",
"fieldContext": "resource",
"fieldDataType": "string",
"signal": "logs"
},
{
"name": "user.id",
"fieldContext": "attributes",
"fieldDataType": "float64",
"signal": "logs"
},
{
"name": "body",
"fieldDataType": "string",
"signal": "logs"
}
],
"filter": {
"expression": "service.name IN ('user-service') AND user.id = 4472431079"
},
"having": {
"expression": ""
}
}
重要规则:
- service.name:使用fieldContext: "resource"(资源级别字段,描述服务本身)
- user.id:使用fieldContext: "attributes"和fieldDataType: "float64"(根据实际数据结构)
- 所有在filter expression中使用的歧义字段,都必须在selectFields中明确指定
- 如果查询结果中rows为null,很可能是字段歧义导致的,检查警告信息并在selectFields中明确指定所有歧义字段
阶段2:综合分析
主要任务
- 加载MCP查询结果
- ⚠️ 必须:从
.online-ticket-analyzer/tickets/ticket_xxx/mcp_results.json加载查询结果 - 如果文件不存在,说明查询未执行或未保存,需要先执行查询并保存结果
- 检查查询结果是否为空
- 如果为空:生成初步判断文档(
.online-ticket-analyzer/tickets/ticket_xxx/preliminary_analysis.md),提示用户提供更精确信息 - 如果不为空:继续分析流程
- 本地分析SigNoz数据(重要!):
- ⚠️ 关键原则:不要将原始查询结果直接全部丢给大模型
- 在本地对查询结果进行统计分析:
- 统计错误数量、错误类型分布
- 提取关键错误信息(错误消息、堆栈信息、错误模式)
- 统计影响范围(用户数、设备数、地区分布、时间分布)
- 提取关键字段值(用户ID、设备ID、IP地址、地理位置、浏览器版本、应用版本等)
- 识别错误模式和趋势
- 生成关键信息摘要(只包含关键统计数据和重要发现)
- 将关键信息摘要提供给AI进行进一步分析
- AI分析关键信息:基于本地提取的关键信息进行推理和分析
- 分析代码逻辑:基于错误信息定位代码文件
- 检索历史经验:从
.online-ticket-analyzer/.production-history/目录检索相似经验 - 分析普遍性问题:
- 基于本地统计结果判断影响范围
- 提取关键特征(国家/地区、环境、服务版本、浏览器版本等)
- 生成广泛查询(不限定用户ID和设备ID)
- 判断是否是普遍性问题
- 如果是普遍性问题,特别标注
- 生成综合解决方案(仅在查询结果不为空时)
- 输出解决方案文档(必须生成):
- 如果查询结果为空:生成
.online-ticket-analyzer/tickets/ticket_xxx/preliminary_analysis.md - 如果查询结果不为空:生成
.online-ticket-analyzer/tickets/ticket_xxx/solution.md - ⚠️ 重要:无论查询结果是否为空,都必须生成相应的分析文档
普遍性问题分析
早期快速判断(在首次查询时执行)
在首次查询时,可以通过以下特征快速判断是否可能是普遍性问题:
触发条件(满足任一即触发):
- 工单中有多个用户报告同一问题
- 工单来自客服/运营团队的批量反馈
- 工单描述中包含"很多用户"、"大量"、"普遍"等关键词
- 问题涉及核心功能(登录、支付、首页等)
- 问题类型是已知的高风险类型(服务端500错误、数据库连接失败等)
快速判断查询:
1. 执行广泛查询(不限定用户ID,仅限定服务名和时间范围)
2. 统计错误数量和唯一用户/设备数
3. 如果错误数 > 10 或唯一用户 > 3,标记为"疑似普遍性问题"
4. 继续执行正常流程,但在分析阶段优先进行完整的普遍性分析
完整分析流程(在综合分析阶段执行)
分析流程:
1. 提取关键特征(国家/地区、环境、服务版本、浏览器版本、错误类型、接口路径)
2. 生成广泛查询(不限定用户ID和设备ID,扩展时间范围到前后24小时)
3. AI执行查询
4. 分析结果,判断普遍性级别:
- 🔴 严重(critical):影响超过50个错误或10个用户/设备,且影响超过2个国家或5个城市
- 🟠 高(high):影响超过50个错误或10个用户/设备,且影响超过1个国家或3个城市
- 🟡 中等(medium):影响超过20个错误或5个用户/设备
- 🟢 轻微(low):影响超过10个错误或3个用户/设备
- ✅ 孤立事件:影响范围有限
5. 如果是普遍性问题,在解决方案中特别标注
普遍性问题的特殊处理
如果确定是普遍性问题(级别 >= 中等):
- 优先级提升:将问题标记为高优先级
- 扩大查询范围:
- 时间范围扩展到 24-72 小时
- 查询所有受影响的服务
- 统计各维度的影响分布(地区、设备类型、客户端版本等)
- 根因定位策略调整:
- 重点关注服务端变更(最近的部署、配置变更)
- 检查是否有依赖服务故障
- 分析是否与特定版本/地区相关
- 文档标注:
- 在 solution.md 中明确标注普遍性级别
- 提供影响范围的详细统计
- 建议是否需要紧急修复或回滚
关键信息识别流程
⚠️ 重要:所有工单查询需要的关键信息,必须通过AI阅读完整项目后,综合配置信息、环境配置、打包配置给出,而不是简单的正则匹配。
1. 接口路径识别
流程(必须完整执行):
1. 通读项目代码,查找所有API调用位置
2. 追踪createRequest方法,找到baseUrl的来源
3. 查找config中baseUrl的定义,追踪到环境变量
4. 从打包配置(vite.config.ts)获取环境变量的实际值
5. 解析baseUrl,提取路径部分
6. 组合完整pathname:baseUrl路径部分 + API相对路径
7. 生成api_pathname_mapping配置
2. 字段提取规则识别
流程:
1. 通读项目代码,查找所有字段的使用方式
2. 了解字段的实际命名规则和嵌套结构
3. 了解用户输入中可能出现的字段名称变体
4. 生成field_extraction_rules配置
3. 服务名称映射识别
流程:
1. 通读项目代码,查找所有服务的定义和使用
2. 了解服务的实际命名规则
3. 了解用户输入中可能出现的服务名称变体
4. 生成service_name_mapping配置
历史经验库规范
历史经验库用于存储和检索已解决问题的经验,帮助快速定位和解决相似问题。
存储位置
.online-ticket-analyzer/
└── .production-history/
├── index.json # 经验索引文件
└── experiences/
├── exp_001.json # 单个经验记录
├── exp_002.json
└── ...
经验记录格式
每个经验记录(exp_xxx.json)包含以下字段:
{
"id": "exp_001",
"created_at": "2025-01-20T10:00:00Z",
"updated_at": "2025-01-20T10:00:00Z",
"problem": {
"title": "登录失败 - OAuth认证超时",
"description": "用户反馈无法登录,点击登录按钮后长时间无响应",
"symptoms": ["登录失败", "OAuth超时", "无响应"],
"error_types": ["TimeoutError", "NetworkError"],
"error_codes": ["ERR_OAUTH_TIMEOUT"],
"affected_services": ["auth-service", "oauth-gateway"],
"affected_apis": ["/api/oauth/callback", "/api/auth/token"]
},
"root_cause": {
"category": "third_party_service",
"description": "第三方OAuth服务响应超时,导致认证流程阻塞",
"technical_details": "OAuth回调接口等待第三方响应超过30秒触发超时"
},
"solution": {
"summary": "增加OAuth超时时间并添加重试机制",
"steps": [
"1. 将OAuth超时时间从30秒增加到60秒",
"2. 添加自动重试机制(最多重试2次)",
"3. 添加友好的超时提示信息"
],
"code_changes": ["auth-service/oauth.ts:L45-L60"],
"config_changes": ["增加OAUTH_TIMEOUT环境变量"]
},
"prevention": {
"measures": [
"添加第三方服务健康检查",
"配置超时告警"
],
"monitoring": ["添加OAuth响应时间监控指标"]
},
"metadata": {
"ticket_id": "ticket_20250120_001",
"resolution_time_hours": 2,
"severity": "high",
"is_universal": false,
"tags": ["oauth", "timeout", "login", "third-party"]
}
}
索引文件格式
index.json 用于快速检索经验:
{
"version": "1.0",
"last_updated": "2025-01-20T10:00:00Z",
"total_count": 10,
"by_error_type": {
"TimeoutError": ["exp_001", "exp_005"],
"NetworkError": ["exp_001", "exp_003"],
"AuthenticationError": ["exp_002", "exp_004"]
},
"by_service": {
"auth-service": ["exp_001", "exp_002"],
"payment-service": ["exp_003", "exp_004"]
},
"by_api": {
"/api/oauth/callback": ["exp_001"],
"/api/payment/create": ["exp_003"]
},
"by_symptom": {
"登录失败": ["exp_001", "exp_002"],
"支付失败": ["exp_003", "exp_004"]
},
"by_tag": {
"oauth": ["exp_001"],
"timeout": ["exp_001", "exp_005"],
"login": ["exp_001", "exp_002"]
}
}
经验匹配规则
按优先级从高到低匹配:
- 精确匹配(权重:100)
- 错误码完全匹配(
error_codes) -
API路径完全匹配(
affected_apis) -
高相关匹配(权重:80)
- 错误类型匹配(
error_types) -
服务名称匹配(
affected_services) -
语义匹配(权重:60)
- 症状关键词匹配(
symptoms) -
标签匹配(
tags) -
模糊匹配(权重:40)
- 问题描述相似度
- 根本原因类别匹配
匹配算法:
总分 = Σ(匹配项权重 × 匹配数量) / 最大可能分数 × 100
如果总分 >= 60,认为是相关经验
如果总分 >= 80,认为是高度相关经验
记录新经验
在以下情况下应记录新经验:
- 问题已解决:成功定位并解决了问题
- 新类型问题:问题类型在历史经验库中不存在
- 有参考价值:解决方案具有通用性,可能帮助解决类似问题
记录流程:
1. 从 solution.md 提取问题描述、根本原因、解决方案
2. 提取关键特征:错误类型、错误码、服务名、API路径、症状关键词
3. 生成唯一ID(exp_xxx)
4. 创建经验记录文件
5. 更新索引文件
经验检索流程
1. 提取当前问题特征
├─ 错误类型、错误码
├─ 服务名称、API路径
└─ 症状关键词
2. 检索匹配经验
├─ 读取 index.json
├─ 按各个维度查找相关经验ID
└─ 计算每个经验的匹配分数
3. 返回相关经验
├─ 按匹配分数排序
├─ 返回分数 >= 60 的经验
└─ 最多返回 5 条最相关经验
4. 应用经验
├─ 参考历史解决方案
├─ 验证是否适用于当前问题
└─ 根据实际情况调整
迭代式查询
⚠️ 核心原则:创建SigNoz查询并不一定一次生成完整的,而是可以根据查询的数据或其他信息补充后继续生成新的查询思路。相关流程符合日志查询定位的流程,最终目标是定位到问题原因。
迭代式查询流程:
- 初始查询:基于工单中的基础信息(服务名、时间范围、关键词等)进行查询
- 不要求一次性生成所有查询
-
先执行基础查询,获取初步数据
-
结果分析:分析查询结果,提取关键信息:
- ⚠️ 首先检查查询是否成功:
- 如果
rows为null,检查是否有字段歧义警告(warnings数组) - 如果有字段歧义警告,必须同时执行两个修复步骤:
- 修改filter.expression:使用完整前缀(
resource.service.name、attribute.user.id) - 修改selectFields:为所有歧义字段明确指定
fieldContext和fieldDataType - ⚠️ 只在selectFields中指定fieldContext是不够的,必须同时在filter.expression中使用完整前缀!
- 修复后重新执行查询
- 如果
-
如果查询成功,提取关键信息:
- 错误信息:错误类型、错误消息、错误堆栈
- 接口信息:接口路径、请求方法、响应状态码
- 特征信息:设备信息(
user.client_id)、用户信息(user.id)、IP地址(source.address) - 环境信息:地理位置(
geo.city_name,geo.country_name)、浏览器版本(browser.name,browser.version)、应用版本(service.version) - 时间模式:错误发生的时间分布、频率等
-
判断是否定位到问题:
- 如果当前查询结果能够定位到问题原因,停止查询,进入分析阶段
-
如果当前查询结果无法定位到问题原因,继续下一步
-
生成补充查询:基于分析结果,生成新的查询思路:
- 如果发现特定错误类型,查询该错误类型的所有日志
- 如果发现特定接口有问题,查询该接口的详细日志
- 如果发现特定设备或地理位置模式,查询特定设备或地理位置的日志
- 如果发现时间模式,查询特定时间段的日志
-
如果发现关键词模式,查询包含该关键词的所有日志
-
迭代深入:继续执行补充查询,分析新结果,进一步细化查询条件
- 重复步骤2-4,逐步深入
- 每次迭代都基于前一次查询的结果
- 直到定位到问题原因或确定无法定位
关键特性:
- 动态查询生成:查询不是一次性生成的,而是根据查询结果动态调整
- 逐步深入定位:从宽泛查询逐步细化到精确查询,最终定位到问题原因
多服务关联查询
当问题涉及多个服务的调用链时,需要进行关联查询以追踪完整的请求路径。
使用场景
- 用户请求经过多个微服务处理
- 错误可能发生在下游服务
- 需要分析完整的请求链路
- 性能问题需要定位耗时环节
关联查询方法
方法1:使用 trace_id 追踪
适用场景:日志中包含 trace_id 字段
查询步骤:
1. 从初始查询结果中提取 trace_id
2. 使用 trace_id 查询所有相关服务的日志
3. 按时间排序,分析请求流转过程
示例查询:
{
"filter": {
"expression": "attribute.trace_id = 'abc123xyz'"
},
"selectFields": [
{"name": "service.name", "fieldContext": "resource", "fieldDataType": "string", "signal": "logs"},
{"name": "trace_id", "fieldContext": "attributes", "fieldDataType": "string", "signal": "logs"},
{"name": "span_id", "fieldContext": "attributes", "fieldDataType": "string", "signal": "logs"},
{"name": "timestamp", "fieldContext": "attributes", "fieldDataType": "float64", "signal": "logs"}
],
"orderBy": {
"columnName": "timestamp",
"order": "asc"
}
}
方法2:使用 Traces 数据
适用场景:SigNoz 中有完整的 Traces 数据
查询步骤:
1. 使用 signoz_search_traces_by_service 搜索相关追踪
2. 使用 signoz_get_trace_details 获取追踪详情(包含所有 spans)
3. 使用 signoz_get_trace_span_hierarchy 获取跨度层次结构
4. 分析各服务的耗时和错误
示例流程:
1. signoz_search_traces_by_service
- service: "frontend-service"
- timeRange: "4h"
- 过滤条件:hasError = true
2. 获取 trace_id 后,执行 signoz_get_trace_details
- 返回完整的 span 列表
3. 分析 span 层次结构
- frontend-service (200ms)
└─ api-gateway (180ms)
└─ auth-service (150ms) ❌ ERROR
└─ database (50ms)
方法3:基于时间窗口关联
适用场景:没有 trace_id,但知道请求的大致时间
查询步骤:
1. 确定请求的时间窗口(通常 ±1-2 秒)
2. 查询该时间窗口内所有相关服务的日志
3. 基于用户ID、请求路径、错误类型等进行关联
示例查询:
{
"filter": {
"expression": "resource.service.name IN ('service-a', 'service-b', 'service-c') AND attribute.user.id = 123456 AND timestamp >= 1705737600000 AND timestamp <= 1705737602000"
}
}
服务调用链分析
分析步骤:
-
绘制调用链:
用户请求 → 前端 → API网关 → 业务服务 → 数据库 ↓ 认证服务 -
定位故障点:
- 从入口服务开始追踪
- 找到第一个出错的服务
-
分析错误原因
-
分析耗时分布:
- 统计每个服务的处理时间
-
识别性能瓶颈
-
关联上下游:
- 检查上游服务的请求是否正常
- 检查下游服务的响应是否正常
常见的多服务问题模式
| 模式 | 特征 | 分析方向 |
|---|---|---|
| 网关超时 | API网关返回504,下游服务无响应 | 检查下游服务是否正常,网络是否通畅 |
| 认证失败 | 业务服务收到401/403,认证服务报错 | 检查认证服务的日志,Token是否有效 |
| 数据库连接 | 多个服务同时报数据库连接错误 | 检查数据库服务状态,连接池配置 |
| 级联故障 | 一个服务故障导致多个上游服务报错 | 找到根源服务,分析故障原因 |
| 配置不同步 | 部分服务使用旧配置 | 检查各服务的配置版本,是否需要重启 |
错误处理与重试策略
查询错误类型及处理
| 错误类型 | 错误特征 | 处理策略 |
|---|---|---|
| 超时错误 | timeout、ETIMEDOUT |
缩短时间范围为原来的一半,重试最多3次 |
| 网络错误 | ECONNREFUSED、ENOTFOUND |
等待5秒后重试,最多重试3次 |
| 限流错误 | 429、rate limit |
等待30秒后重试,最多重试2次 |
| 服务不可用 | 503、service unavailable |
等待10秒后重试,最多重试3次 |
| 字段歧义 | ambiguous、rows: null |
修复查询后立即重试(不计入重试次数) |
| 权限错误 | 401、403 |
不重试,记录错误,提示检查配置 |
| 参数错误 | 400、invalid parameter |
不重试,修复参数后重新执行 |
重试机制
重试流程:
1. 捕获错误
2. 判断错误类型
3. 如果是可重试错误:
a. 检查重试次数是否超限
b. 执行等待策略(根据错误类型)
c. 调整查询参数(如缩短时间范围)
d. 重新执行查询
4. 如果不可重试或重试超限:
a. 记录错误详情
b. 继续执行其他查询
c. 在结果中标注该查询失败
降级策略
当查询持续失败时,执行降级策略:
- 缩小查询范围:
- 时间范围:4h → 2h → 1h
-
返回条数:1000 → 500 → 100
-
简化查询条件:
- 减少过滤条件
-
减少 selectFields 数量
-
切换查询方式:
signoz_execute_builder_query失败 → 尝试signoz_search_logs_by_service-
复杂查询失败 → 尝试简单查询
-
标记并跳过:
- 记录失败的查询
- 继续执行其他查询
- 在最终报告中说明哪些查询失败
快速定位路径
对于某些常见的错误类型,可以使用快速定位路径,跳过部分探索步骤直接定位问题。
快速定位触发条件
| 触发条件 | 快速路径 |
|---|---|
| 错误信息包含 "timeout" | 直接查询超时相关日志,分析网络/依赖服务 |
| 错误码 500 | 直接查询服务端错误日志,分析堆栈 |
| 错误码 401/403 | 直接查询认证服务日志 |
| 错误码 404 | 检查路由配置,查询 API 网关日志 |
| 错误信息包含 "database" | 直接查询数据库相关日志 |
| 错误信息包含 "connection refused" | 检查服务健康状态,查询网络相关日志 |
快速定位流程
1. 解析工单,提取关键信息
↓
2. 匹配快速定位规则
├─ 匹配成功 → 执行快速路径
│ ├─ 直接执行针对性查询
│ ├─ 分析结果
│ └─ 如果定位到问题 → 生成解决方案
│ └─ 如果未定位 → 回退到标准流程
└─ 未匹配 → 执行标准流程
常见问题快速定位指南
1. 超时问题快速定位
1. 查询超时相关错误日志
filter: "severity_text = 'ERROR' AND body CONTAINS 'timeout'"
2. 检查依赖服务响应时间
使用 Traces 分析各服务耗时
3. 分析超时发生的时间模式
是否有规律性(如高峰期)
4. 检查最近的配置变更
超时时间设置是否合理
2. 认证失败快速定位
1. 查询认证服务错误日志
filter: "resource.service.name = 'auth-service' AND severity_text = 'ERROR'"
2. 检查 Token 状态
是否过期、是否被撤销
3. 检查用户状态
账号是否被禁用、权限是否变更
4. 检查认证配置
OAuth 配置、密钥是否正确
3. 数据库问题快速定位
1. 查询数据库相关错误日志
filter: "body CONTAINS 'database' OR body CONTAINS 'SQL'"
2. 检查数据库连接状态
连接池是否耗尽
3. 检查慢查询
是否有异常的长时间查询
4. 检查数据库服务状态
CPU、内存、连接数等指标
4. 网络问题快速定位
1. 查询网络相关错误日志
filter: "body CONTAINS 'ECONNREFUSED' OR body CONTAINS 'ETIMEDOUT'"
2. 检查服务间通信状态
DNS 解析、端口连通性
3. 检查负载均衡状态
是否有节点不可用
4. 检查网络配置
防火墙、安全组规则
AI执行方式
🚨 执行前必读:强制约束检查清单
在开始任何操作之前,请先检查以下约束:
📛 代码只读检查:
- [ ] 我是否即将使用 Edit 工具?→ 禁止!
- [ ] 我是否即将使用 Write 工具写代码文件?→ 禁止!
- [ ] 我是否即将修改任何 .ts/.js/.tsx/.jsx 等源代码文件?→ 禁止!
📋 流程检查:
- [ ] 我是否已经执行了阶段0(检查配置文件)?→ 必须先执行!
- [ ] 配置文件是否存在?→ 不存在则必须先生成!
- [ ] 我是否即将跳过SigNoz日志查询直接给出结论?→ 禁止!
如果上述任何检查失败,立即停止当前操作,按正确流程执行!
第一步:理解任务
当用户提出工单分析任务时,你应该:
- 理解需求 - 仔细分析用户的工单描述,明确问题类型和期望结果
- 识别输入格式 - 判断输入是图文、图片、文字还是文件
- 提取关键信息 - 从输入中提取服务名、时间、用户信息等关键字段
- 确定分析路径 - 基于提取的信息,确定查询策略和分析方法
⚠️ 注意:此时只是理解任务,绝对不能直接开始分析代码或给出解决方案!必须先执行阶段0检查。
第二步:进入日志查询循环(阶段1)
🚨🚨🚨 这是工单分析的核心阶段,是一个循环过程!🚨🚨🚨
⚠️ 核心理念:日志查询是一个循环过程,主要目的是查询到相关日志。循环会持续直到:
1. 查询到相关日志
2. 用户明确要求跳过
3. 用户确认无法提供更多信息
🔴 第一优先级:检查配置文件(必须首先执行!)
检查1: .online-ticket-analyzer/project_context.json 是否存在?
检查2: .online-ticket-analyzer/signoz_config.json 是否存在?
- 如果任一文件不存在:先执行阶段0,生成配置文件
- 如果两个文件都存在:进入日志查询循环
🔄 日志查询循环流程:
┌─────────────────────────────────────────────────────────────────┐
│ 循环迭代 N │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1️⃣ 【信息收集】从三个来源整理查询条件: │
│ ├─ 工单信息 │
│ ├─ 用户补充信息(本次迭代用户提供的新信息) │
│ └─ 代码分析信息(signoz_config.json) │
│ │
│ 2️⃣ 【条件评估】检查是否具备足够的查询条件: │
│ ├─ 条件充足 → 执行查询 │
│ └─ 条件不足 → 向用户请求信息 → 等待用户响应 │
│ │
│ 3️⃣ 【执行查询】 │
│ ├─ 更新 ticket_info.json(记录迭代信息) │
│ ├─ 更新 mcp_instructions.json │
│ ├─ 执行 SigNoz MCP 查询 │
│ └─ 保存结果到 mcp_results.json │
│ │
│ 4️⃣ 【结果评估】 │
│ ├─ ✅ 查询到相关日志 → 退出循环 │
│ ├─ ❌ 无结果:尝试自动调整(放宽条件/扩展时间) │
│ │ ├─ 调整后有结果 → 退出循环 │
│ │ └─ 调整后仍无结果 → 向用户请求更多信息 │
│ └─ 🔄 用户提供新信息 → 进入下一次迭代 │
│ │
│ 🚪 【退出条件】 │
│ ├─ ✅ 查询到相关日志 → 进入阶段2 │
│ ├─ ⏭️ 用户要求跳过 → 进入阶段2(生成preliminary_analysis.md) │
│ └─ ❌ 用户无法提供更多信息 → 进入阶段2 │
│ │
└─────────────────────────────────────────────────────────────────┘
循环中的关键操作:
- 信息收集:
- 从工单内容提取:时间、用户ID、错误信息、功能描述等
- 从用户补充获取:用户在对话中提供的额外信息
-
从代码分析获取:接口路径映射、服务名映射等
-
条件评估:
- 必须条件:服务名称、时间范围
- 推荐条件:用户标识(user.id 或 user.client_id)
-
条件不足时,明确告知用户需要什么信息,等待用户响应
-
执行查询:
- 使用
signoz_list_services确认服务存在(使用 24h 时间范围) - 使用
signoz_execute_builder_query执行日志查询 -
注意时间戳单位:list_services 用纳秒或 timeRange,其他用毫秒
-
结果评估与自动调整:
- 检查字段歧义(rows 为 null 时检查 warnings)
- 放宽查询条件
- 扩展时间范围(±2小时 → ±4小时 → ±24小时)
-
切换时间优先级
-
与用户交互:
- 无结果时,告知用户已尝试的策略
- 询问用户是否有其他信息可以提供
- 提供跳过选项(如果用户希望直接进行分析)
❌ 禁止行为:
- 在配置文件不存在的情况下执行查询
- 跳过循环直接进入分析阶段(除非用户明确要求)
- 无结果时不向用户请求信息就直接结束
🚨 日志查询循环完成检查:
- [ ] 是否查询到了相关日志?或用户要求跳过?
- [ ] mcp_results.json 文件是否已创建?
- [ ] ticket_info.json 中的 query_loop_status 是否已更新?
第三步:综合分析(阶段2)
🚨 进入阶段2的前置条件:
- [ ] 阶段0是否已完成?(配置文件存在)→ 必须完成!
- [ ] 阶段1日志查询循环是否已退出?→ 必须退出!
- [ ] 退出原因是否明确?(查询到日志 / 用户跳过 / 无法获取更多信息)
❌ 如果日志查询循环未退出,禁止进入阶段2!
🚨 重要提醒:
- 代码只读约束在此阶段同样适用!
- 分析结论必须基于 SigNoz 查询结果,不能仅基于代码分析!
在分析阶段,你应该:
- 本地分析SigNoz查询结果(重要!):
- ⚠️ 关键原则:不要将原始查询结果直接全部丢给大模型
- 在本地对查询结果进行统计分析:
- 统计错误数量、错误类型分布
- 提取关键错误信息(错误消息、堆栈信息、错误模式)
- 统计影响范围(用户数、设备数、地区分布、时间分布)
- 提取关键字段值(用户ID、设备ID、IP地址、地理位置、浏览器版本、应用版本等)
- 识别错误模式和趋势
- 生成关键信息摘要(只包含关键统计数据和重要发现)
- 保存分析摘要到
.online-ticket-analyzer/tickets/ticket_xxx/analysis_summary.json -
将关键信息摘要提供给AI进行进一步分析
-
AI分析关键信息 - 基于本地提取的关键信息进行推理和分析,理解问题本质
-
分析代码逻辑(⚠️ 只读!禁止修改!):
- ✅ 允许:使用 Read 工具查看代码文件
- ✅ 允许:使用 Grep/Glob 工具搜索代码
- ✅ 允许:分析代码逻辑,理解问题根源
- ❌ 禁止:使用 Edit 工具修改代码
- ❌ 禁止:使用 Write 工具创建代码文件
-
❌ 禁止:执行任何会修改代码的操作
-
检索历史经验 - 从历史经验库中检索相似问题的解决方案
-
判断普遍性 - 基于本地统计结果分析问题影响范围,判断是否为普遍性问题
-
生成解决方案(⚠️ 代码修改建议只写入文档!):
- 生成包含问题分析、根本原因、解决方案、预防措施的综合文档
- 保存到
.online-ticket-analyzer/tickets/ticket_xxx/solution.md - ⚠️ 必须生成:无论查询结果是否为空,都要生成相应的文档
- 如果查询结果为空:生成
preliminary_analysis.md - 如果查询结果不为空:生成
solution.md - ⚠️ 代码修改建议:如果分析出需要修改代码,将修改建议写入 solution.md 的"代码修改建议"部分,绝对不能直接修改代码!
第四步:结果处理
完成任务后,你应该:
- 验证文件完整性 - 确保所有必需的文件都已生成:
- ✅
ticket_info.json- 工单基本信息和查询循环状态(阶段1) - ✅
mcp_instructions.json- MCP查询指令(阶段1) - ✅
mcp_results.json- MCP查询结果(阶段1循环中生成) - ✅
analysis_summary.json- 本地分析摘要(阶段2) - ✅
solution.md或preliminary_analysis.md- 分析结果文档(阶段2) - 如果缺少任何文件,说明对应阶段未完成,需要继续执行
- 总结结果 - 清晰总结分析过程和关键发现
- 提供反馈 - 向用户说明分析结果,解释关键决策
- 记录经验 - 如有必要,将本次分析的经验记录到历史经验库
文档模板
solution.md 模板(查询结果不为空时使用)
# 工单分析报告
## 基本信息
| 项目 | 内容 |
|------|------|
| 工单ID | ticket_xxx |
| 分析时间 | YYYY-MM-DD HH:MM:SS |
| 问题类型 | [登录失败/支付失败/功能异常/性能问题/...] |
| 严重程度 | [🔴 严重/🟠 高/🟡 中等/🟢 轻微] |
| 是否普遍性问题 | [是/否] |
## 问题概述
[简要描述用户反馈的问题,包括时间、现象、影响范围]
## 用户/设备信息
| 项目 | 内容 |
|------|------|
| 用户ID | xxx |
| 设备ID | xxx |
| 地理位置 | xxx |
| 浏览器/客户端 | xxx |
## 查询过程
### 执行的查询
1. **查询1**:[查询描述]
- 时间范围:xxx - xxx
- 过滤条件:xxx
- 结果:[找到 N 条日志/无结果]
2. **查询2**:[查询描述]
- ...
### 关键发现
- [发现1]
- [发现2]
- ...
## 问题分析
### 错误信息
[关键错误日志/堆栈信息]
### 根本原因
**原因类别**:[代码Bug/配置错误/第三方服务/网络问题/用户操作/数据问题/...]
**详细分析**:
[详细说明问题的根本原因,包括技术细节]
### 相关代码
- 文件:`path/to/file.ts:L100-L120`
- 问题代码段说明
## 解决方案
### 临时解决方案(如有)
[如果有临时绕过问题的方法]
### 根本解决方案
1. [步骤1]
2. [步骤2]
3. ...
### 代码修改建议
⚠️ **重要说明**:本技能禁止直接修改代码,以下仅为建议,请用户自行决定是否执行修改。
**需要修改的文件**:`path/to/file.ts`
**修改位置**:第 XX 行 - 第 YY 行
**修改原因**:[说明为什么需要修改]
**建议修改内容**:
```typescript
// 修改前
[原代码]
// 修改后
[修改后代码]
修改风险评估:[低/中/高] - [说明可能的风险]
测试建议:[说明修改后应该如何测试]
普遍性分析
| 维度 | 统计 |
|---|---|
| 影响用户数 | N |
| 影响设备数 | N |
| 影响地区 | xxx |
| 错误总数 | N |
| 普遍性级别 | [🔴 严重/🟠 高/🟡 中等/🟢 轻微/✅ 孤立事件] |
预防措施
- [措施1]
- [措施2]
- ...
相关历史经验
- [exp_xxx] [相关问题标题] - 相关度:xx%
附录
查询指令
[mcp_instructions.json 的关键内容]
原始数据摘要
[analysis_summary.json 的关键统计]
### preliminary_analysis.md 模板(查询结果为空或无法定位时使用)
```markdown
# 初步分析报告
## 基本信息
| 项目 | 内容 |
|------|------|
| 工单ID | ticket_xxx |
| 分析时间 | YYYY-MM-DD HH:MM:SS |
| 分析状态 | ⚠️ 需要更多信息 |
## 问题概述
[简要描述用户反馈的问题]
## 已执行的查询
### 查询尝试
1. **查询1**:[查询描述]
- 时间范围:xxx - xxx
- 过滤条件:xxx
- 结果:无数据
- 可能原因:[时间范围不匹配/服务名不正确/用户标识缺失/...]
2. **查询2**:[查询描述]
- ...
### 排查总结
- ✅ 已确认服务 `xxx` 存在
- ❌ 在指定时间范围内未找到该用户/设备的日志
- ❓ 可能原因:[列出可能的原因]
## 无法定位的原因
[详细说明为什么无法定位到问题]
可能的原因:
1. **用户/设备信息缺失**:工单中未提供足够的用户或设备标识信息
2. **时间范围不准确**:实际问题发生时间可能与工单描述的时间不一致
3. **服务名称不匹配**:用户描述的服务可能与实际服务名不一致
4. **日志未上报**:该场景可能没有相应的日志埋点
5. **其他原因**:[...]
## 需要的额外信息
为了继续排查问题,请提供以下信息:
### 必须提供(至少一项)
- [ ] **用户ID**:用户的唯一标识
- [ ] **设备ID/客户端ID**:设备的唯一标识(可在设置页面查看)
- [ ] **账号/邮箱**:用户的登录账号
### 建议提供
- [ ] **准确的问题发生时间**:精确到分钟
- [ ] **操作步骤**:问题发生前的具体操作步骤
- [ ] **错误截图**:如果有错误提示,请提供截图
- [ ] **网络环境**:WiFi/4G/5G,是否使用VPN
- [ ] **设备信息**:手机型号、系统版本、App版本
## 初步判断
基于现有信息,初步判断可能是:
1. [可能原因1] - 可能性:高/中/低
2. [可能原因2] - 可能性:高/中/低
## 建议的后续步骤
1. [步骤1]
2. [步骤2]
3. 用户提供更多信息后,继续排查
## 备注
[其他需要说明的信息]
配置选项
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
--start-time |
string | - | 查询开始时间(格式:YYYY-MM-DD HH:MM:SS) |
--end-time |
string | - | 查询结束时间(格式:YYYY-MM-DD HH:MM:SS) |
--service |
string | - | 服务名称(如果未从输入中提取) |
--user-id |
string | - | 用户ID(如果未从输入中提取) |
--device-id |
string | - | 设备ID(如果未从输入中提取) |
--api-path |
string | - | API路径(如果未从输入中提取) |
使用示例
示例1:基础工单分析
用户输入:用户反馈登录失败,时间:2025-01-20 10:00:00,用户ID:123456
AI执行流程:
1. 理解需求 - 识别为登录失败问题,提取时间、用户ID
2. 生成查询指令 - 创建查询该用户在该时间段的错误日志
3. 执行查询 - 调用SigNoz MCP工具查询日志
4. 本地分析 - 在本地对查询结果进行统计分析,提取关键错误信息、错误数量、影响范围等
5. AI分析关键信息 - 基于本地提取的关键信息进行推理和分析,定位问题根源
6. 生成解决方案 - 生成包含问题分析和解决方案的文档
示例2:邮件沟通记录分析
用户输入:邮件沟通记录(包含多个发送方、多个时间点)
AI执行流程:
1. 理解需求 - 识别为邮件沟通记录,提取多个发送方和时间点
2. 分析多时间 - 计算最早和最晚时间,确定查询时间范围
3. 生成查询指令 - 创建基于时间范围的广泛查询
4. 执行查询 - 调用SigNoz MCP工具查询相关日志
5. 本地分析 - 在本地对查询结果进行统计分析,提取错误数量、影响范围、地区分布等关键信息
6. AI分析关键信息 - 基于本地统计结果判断是否为普遍性问题
7. 生成解决方案 - 生成包含普遍性分析的解决方案
示例3:图文混合输入
用户输入:截图 + 文字描述
AI执行流程:
1. 理解需求 - 识别图片中的错误信息和文字描述
2. 提取信息 - 从图片和文字中提取服务名、时间、错误信息等
3. 生成查询指令 - 创建基于提取信息的查询
4. 执行查询 - 调用SigNoz MCP工具查询
5. 本地分析 - 在本地对查询结果进行统计分析,提取关键错误信息、错误模式等
6. AI分析关键信息 - 结合图片和本地提取的关键信息进行分析
7. 生成解决方案 - 生成综合解决方案
最佳实践
- 独立思考优先
- 优先使用你的知识和推理能力分析问题
- 将SigNoz MCP工具视为数据源,不是决策者
-
在需要确定性查询时才使用MCP工具
-
合理使用工具
- 使用SigNoz MCP工具查询日志和错误信息
- ⚠️ 重要:在本地对查询结果进行统计分析,提取关键信息,不要将原始数据全部丢给大模型
- 使用项目代码分析问题根源
-
使用历史经验库检索相似问题
-
本地数据分析优先
- 在本地对SigNoz查询结果进行统计分析(错误数量、错误类型、影响范围等)
- 提取关键信息摘要(只包含关键统计数据和重要发现)
- 将关键信息摘要提供给AI进行进一步分析
-
避免将大量原始数据直接传递给大模型
-
清晰沟通
- 与用户保持清晰沟通,解释分析过程
- 说明为什么选择某种查询方法
-
提供详细的分析反馈
-
持续优化
- 从每次分析中学习,不断改进方法
- 评估分析结果,优化查询策略
- 记录经验,提高分析效率
故障排除
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 查询结果为空 | 时间范围不正确、服务名称不匹配、字段歧义、时间戳单位错误 | 检查时间范围、确认服务名称、明确字段上下文、检查时间戳单位 |
| 字段歧义错误 | 字段名在多个上下文中存在,导致rows为null | 必须同时使用两种方法:1) 在filter.expression中使用完整前缀(resource.service.name、attribute.user.id);2) 在selectFields中明确指定fieldContext和fieldDataType(service.name用resource,user.id用attributes+float64) |
| rows为null | 字段歧义未处理,查询无法正确执行 | 检查警告信息,必须同时修复:1) filter.expression中使用完整前缀;2) selectFields中明确指定所有歧义字段 |
| 服务名称不匹配 | 代码中的服务名与运行时不同 | 首先执行list_services确认实际服务名 |
| 时间戳单位错误 | list_services需要纳秒,其他工具需要毫秒 | 使用timeRange参数(推荐),或确保时间戳单位正确 |
| 时间范围过窄 | 查询时间范围小于2小时 | 自动扩展为+/- 2小时 |
| 时间范围过长 | 查询时间范围超过3天 | 自动截断为3天(保留最接近当前时间的3天) |
| 未来时间判断错误 | 将过去时间误判为未来时间 | 必须基于计算出的查询时间范围与当前时间比较,而不是基于工单时间本身 |
| 未来时间 | 计算出的查询时间范围在未来(start > 当前时间) | 自动调整为最近24小时(基于当前时间) |
| 过去时间 | 计算出的查询时间范围是过去时间(end < 当前时间) | 直接使用该时间范围,不调整 |
| 查询超时 | 查询请求超时 | 自动优化时间区间长度(缩短为原来的一半),继续自动重试,最多重试3次 |
| 优先级查询策略 | 需要按优先级依次查询 | 每个时间区间内执行完整查询流程(接口相关 → 报错相关 → 所有日志 → 其他相关),所有查询都无法定位问题才切换,任意查询有相关数据能定位问题则提前终止 |
| 时间切换逻辑错误 | 某个查询为空就切换时间区间 | 必须执行完当前时间区间内所有查询,且所有查询都无法定位到问题,才切换到下一个时间优先级 |
| 数据判断错误 | 仅判断数据是否非空 | 必须判断数据是否相关和能够定位到问题,仅仅有数据还不够 |
| 用户/设备信息缺失 | 工单中没有提供用户信息或设备信息 | 先尝试通过工单中其他信息(接口路径、错误信息、关键词、时间范围等)+ 代码相关逻辑生成相关查询,从查询结果中提取用户ID或设备ID;如果完全无法定位,则停止流程并提示用户提供相关信息 |
| 用户未登录场景 | 用户反馈问题时未登录,没有user.id | 优先查询user.client_id(设备ID):1) 检查工单是否直接提供设备ID;2) 通过其他信息(IP、时间、接口等)定位;3) 通过账号/邮箱查登录记录获取设备ID。如果都无法获取,必须停止流程,生成preliminary_analysis.md请求用户提供更多信息 |
| 登录失败场景 | 用户反馈登录失败/登录不成功 | 即使工单提供了user.id,也应优先使用user.client_id查询。因为登录失败意味着未成功认证,服务端日志可能没有该user.id的记录。使用设备ID查询登录相关接口(/login、/auth等)的错误日志 |
| 服务不存在 | signoz_list_services返回空或不包含目标服务 | 1) 扩大时间范围(7d或30d)重新查询;2) 检查signoz_config.json中的service_name_mapping;3) 尝试模糊匹配服务名 |
调试模式
在分析过程中,如果遇到问题,可以:
- 检查文件完整性 - 确认工单目录下是否包含所有必需文件:
mcp_instructions.json- 查询指令mcp_results.json- 查询结果(如果缺失,说明查询未执行或未保存)analysis_summary.json- 分析摘要(如果缺失,说明阶段2未完成)solution.md或preliminary_analysis.md- 分析结果文档(如果缺失,说明阶段2未完成)- 检查配置文件 - 确认
.online-ticket-analyzer/project_context.json和.online-ticket-analyzer/signoz_config.json是否正确 - 验证查询指令 - 检查
.online-ticket-analyzer/tickets/ticket_xxx/mcp_instructions.json中的查询格式是否正确 - 查看查询结果 - 检查
.online-ticket-analyzer/tickets/ticket_xxx/mcp_results.json中的查询结果 - 如果文件不存在,说明查询未执行或未保存
- 如果结果为空(
rows: null),检查时间范围、服务名称、字段歧义等问题 - 检查字段歧义警告 - ⚠️ 关键步骤:如果查询结果中
rows为null,必须检查是否有字段歧义警告: - 查看
warnings数组,查找包含"ambiguous"的警告 - 常见警告示例:
"key service.name is ambiguous, found 2 different combinations of field context and data type: [name=service.name,context=resource,type=string name=service.name,context=attribute,type=string]""key user.id is ambiguous, found 3 different combinations of field context and data type: [name=user.id,context=attribute,type=string name=user.id,context=attribute,type=bool name=user.id,context=attribute,type=number]"
- 完整解决方案(必须同时使用两种方法):
- 方法1(推荐,必须):在
filter.expression中使用完整前缀: service.name→ 改为resource.service.nameuser.id→ 改为attribute.user.id- 方法2(同时使用):在
selectFields中为所有歧义字段明确指定fieldContext和fieldDataType: service.name:添加{"name": "service.name", "fieldContext": "resource", "fieldDataType": "string", "signal": "logs"}user.id:添加{"name": "user.id", "fieldContext": "attributes", "fieldDataType": "float64", "signal": "logs"}(虽然警告中显示有string、bool、number三种类型,但通常使用float64类型)
- 方法1(推荐,必须):在
- ⚠️ 重要:仅仅在
selectFields中指定是不够的,必须同时在filter.expression中使用完整前缀(resource.或attribute.)! - 查看分析摘要 - 检查
.online-ticket-analyzer/tickets/ticket_xxx/analysis_summary.json中的本地分析摘要 - 分析错误信息 - 从错误信息中提取线索,调整查询策略
辅助工具说明
虽然你的核心能力是独立思考和执行,但在某些情况下,可以使用以下辅助工具:
🚨 工具使用约束(必须遵守!)
❌ 禁止使用的工具:
- ❌ Edit 工具 - 禁止编辑任何文件(除 .online-ticket-analyzer/ 目录下的分析文件)
- ❌ Write 工具写代码 - 禁止创建任何代码文件
✅ 允许使用的工具:
- ✅ Read 工具 - 可以读取任何文件进行分析
- ✅ Grep/Glob 工具 - 可以搜索代码
- ✅ Write 工具写分析文件 - 可以在 .online-ticket-analyzer/ 目录下创建 JSON、MD 等分析文件
- ✅ SigNoz MCP 工具 - 可以查询日志和监控数据
- ✅ Bash 工具 - 可以执行只读命令(如 ls、cat 等),禁止执行修改文件的命令
- SigNoz MCP工具 - 用于查询日志、错误、追踪、指标等信息
- 日志查询:
signoz_execute_builder_query(推荐)、signoz_search_logs_by_service、signoz_get_error_logs、signoz_list_log_views、signoz_get_log_view、signoz_get_logs_available_fields、signoz_get_logs_field_values - 追踪查询:
signoz_search_traces_by_service、signoz_get_trace_details、signoz_get_trace_error_analysis、signoz_get_trace_span_hierarchy、signoz_get_trace_available_fields、signoz_get_trace_field_values - 指标查询:
signoz_list_metric_keys、signoz_search_metric_by_text、signoz_get_metrics_available_fields、signoz_get_metrics_field_values - 服务相关:
signoz_list_services(必须首先执行)、signoz_get_service_top_operations - 仪表板:
signoz_list_dashboards、signoz_get_dashboard、signoz_create_dashboard、signoz_update_dashboard - 警报:
signoz_list_alerts、signoz_get_alert、signoz_get_alert_history、signoz_get_logs_for_alert - ⚠️ 重要:查询结果必须在本地进行分析,提取关键信息,不要将原始数据全部丢给大模型
-
⚠️ 时间戳单位注意:
signoz_list_services和signoz_get_service_top_operations需要纳秒时间戳- 其他工具(如
signoz_execute_builder_query,signoz_get_error_logs)需要毫秒时间戳 - 推荐:优先使用
timeRange参数(如 "1h", "4h", "24h"),避免时间戳单位错误
-
本地数据分析 - 对SigNoz查询结果进行统计分析
- 统计错误数量、错误类型分布
- 提取关键错误信息(错误消息、堆栈信息、错误模式)
- 统计影响范围(用户数、设备数、地区分布、时间分布)
- 提取关键字段值(用户ID、设备ID、IP地址、地理位置、浏览器版本、应用版本等)
-
生成关键信息摘要
-
项目代码(⚠️ 只读!):
- ✅ 允许:使用 Read 工具查看代码文件,分析代码逻辑,理解问题根源
- ✅ 允许:使用 Grep/Glob 工具搜索代码,定位问题位置
- ❌ 禁止:使用 Edit 工具修改任何代码文件
- ❌ 禁止:使用 Write 工具创建任何代码文件
-
❌ 禁止:执行任何可能修改代码的bash命令
-
历史经验库 - 用于检索相似问题的解决方案
重要原则:
- 这些工具是辅助性的,主要工作应该由你(AI)通过思考和推理来完成
- ⚠️ 关键原则:SigNoz查询结果必须在本地进行分析和处理,提取关键信息后再提供给AI,不要将原始数据全部丢给大模型
- ⚠️ 代码只读原则:本技能绝对禁止修改任何代码文件,所有修改建议只能写入分析报告(solution.md)
扩展功能
- 灵活扩展 - 根据项目需求,灵活扩展分析能力
- 工具集成 - 结合SigNoz MCP工具、项目代码等,进行全面分析
- 资源利用 - 利用历史经验库、配置文件等资源,提高分析效率
- 持续改进 - 从经验中学习,不断优化分析方法
技术架构
- 核心框架: AI驱动的智能分析
- 数据源: SigNoz监控系统(通过MCP协议)
- 配置管理: JSON格式的配置文件(统一存放在
.online-ticket-analyzer/目录下) - 文件组织: 所有生成的文件统一放在
.online-ticket-analyzer/目录下,保持原项目整洁 - 通信协议: MCP(模型上下文协议)
- 数据格式: OpenTelemetry标准
🚨 最终检查清单(每次执行前必须确认)
在结束分析任务前,请确认以下所有检查项:
📛 代码只读检查
- [ ] 我是否修改了任何代码文件?→ 如果是,本次分析无效!
- [ ] 我是否使用了 Edit 工具编辑代码?→ 如果是,本次分析无效!
- [ ] 我是否使用了 Write 工具创建代码文件?→ 如果是,本次分析无效!
- [ ] 代码修改建议是否只写在了 solution.md 中?→ 必须是!
📋 流程完整性检查
- [ ] 我是否执行了阶段0(检查/生成配置文件)?→ 必须执行!
- [ ]
project_context.json是否存在?→ 必须存在! - [ ]
signoz_config.json是否存在?→ 必须存在! - [ ] 我是否执行了SigNoz日志查询?→ 必须执行!
- [ ]
mcp_results.json是否已生成?→ 必须生成! - [ ]
analysis_summary.json是否已生成?→ 必须生成! - [ ]
solution.md或preliminary_analysis.md是否已生成?→ 必须生成!
⚠️ 如果任何检查项失败
- 立即停止当前操作
- 回溯到失败的步骤
- 按正确流程重新执行
本技能的核心原则:
1. 代码只读 - 绝对不修改任何代码,所有建议写入报告
2. 流程严格 - 必须按阶段顺序执行,不能跳过
3. 日志驱动 - 必须通过SigNoz日志查询来定位问题
4. 文档完整 - 必须生成完整的分析报告
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.