微服务日志智能诊断系统(九) 让 LLM 成为日志分析专家


项目地址gitee.com/guoxuezha/e...


1. LLM 在系统中的角色定位

在手动版(validate-prototypes)中,LLM 只在一个环节被调用:接收异常日志,输出诊断报告。这是一个简单的"单次调用"模式。

在 Agent 版(embabel-example)中,LLM 被深度嵌入了诊断流程的每一个关键决策点

调用场景 LLM 的角色 输入 输出类型
用户输入解析 信息提取专家 自然语言描述 FetchServiceLogInput (JSON)
日志质量评估 资深诊断专家 日志 + 元数据 + 问题描述 LogQualityAssessment (JSON)
重试策略生成 策略优化专家 历次评估结果 FetchServiceLogInput (JSON)
关键信息提取 日志分析专家 日志内容 ExtractedInfo (JSON)
根因分析 故障诊断专家 日志 + 提取信息 诊断报告文本
全链路分析 全链路分析专家 多服务日志 综合分析文本
RAG 检索指导 RAG 检索专家 搜索关键字 + RAG 工具 FetchServiceLogInput (JSON)

每个场景的 Prompt 都经过精心设计,遵循"角色定义 → 上下文注入 → 任务说明 → 输出约束"的统一范式。

2. Prompt 设计的核心原则

原则一:结构化输出,杜绝自由文本

LLM 的输出必须能被程序可靠解析。我们统一使用 createObject 模式,让 LLM 直接输出 JSON,由框架自动反序列化为 Java 对象:

java 复制代码
LogQualityAssessment assessment = ctx.ai()
        .withDefaultLlm()
        .createObject(prompt, LogQualityAssessment.class);

这比"让 LLM 输出 Markdown,再用正则解析"要可靠得多。Prompt 中必须明确指定 JSON 结构:

json 复制代码
【输出格式要求】
请严格按照以下 JSON 格式输出:
```json
{
  "qualityScore": 整数(0-10),
  "needsMoreContext": true/false,
  "extractedKeywords": ["关键字1", "关键字2"],
  "reasoning": "用中文说明评估理由"
}
markdown 复制代码
#### 原则二:注入足够上下文,让 LLM "知情决策"

日志质量评估的 Prompt 中,我们不仅传递了日志内容,还包括:
- 服务编码、服务器 IP、发生时间
- 当前抓取的日志文件名
- 执行的命令和是否成功
- 服务器上所有可用日志文件的列表(含类型、大小、更新时间)
- 用户的初步分析

这让 LLM 能做出更准确的判断。例如,当 LLM 看到"服务器上只有一个日志文件"时,就不会建议"切换到其他日志文件"。

#### 原则三:明确判断规则,减少"猜测"

LLM 容易在模糊场景下"瞎猜"。我们通过详细的判断规则来约束它的行为:

【关键判断规则】(必须严格遵守)

  1. switchFileRecommended 判断:

    • 如果 extractLogInfos 中只有一个日志文件 → 必须返回 false
    • 如果 extractLogInfos 中有多个日志文件,且当前日志不足以诊断 → 可以返回 true
  2. qualityScore 评分标准:

    • 0-3: 严重不足(缺少关键信息、日志截断、完全不相关)
    • 4-6: 基本可用(有部分信息但需要补充)
    • 7-10: 信息充分(有完整堆栈、上下文清晰、可直接解释问题发生原因)
perl 复制代码
#### 原则四:传递底层机制说明,让 LLM "理解工具"

重试策略 Prompt 中,我们详细说明了底层 grep 命令的工作原理:

日志抓取的底层 Linux 命令为: cat {logFile} | grep '{occurTime}' -B {upperBoundary} -A {lowerBoundary} | tail -n {maxLine}

其中:

  • occurTime: grep 的匹配关键字(通常是异常发生的时间戳)
  • upperBoundary: grep 的 -B 参数,表示匹配行之前显示的行数
  • lowerBoundary: grep 的 -A 参数,表示匹配行之后显示的行数
  • maxLine: tail 的参数,限制最终输出的最大行数
markdown 复制代码
LLM 理解了工具的工作原理后,能更精准地调整参数。例如:
- "堆栈被截断了" → 增大 `lowerBoundary`(显示更多后续行)
- "缺少发生前的上下文" → 增大 `upperBoundary`(显示更多前序行)
- "时间戳不匹配" → 偏移 `occurTime`(前后调整 5-30 秒)

### 3. 关键 Prompt 详解

#### 3.1 用户输入解析

这是 Agent 执行的第一个 Prompt,目标是从自然语言中提取结构化参数:

你是一名微服务异常诊断助手的信息提取专家。

【任务说明】 从用户输入的文本中提取关键信息,构造一个结构化的日志抓取请求对象。

【字段提取规则】

  1. serviceCode(必填): 服务编码,如 'his-doctor-service'
  2. occurTime(必填): 异常发生时间,格式 'yyyy-MM-dd HH:mm:ss'
    • 如果是相对时间(如'10分钟前'),需要转换为绝对时间
  3. keyWord(可选): 异常类名、业务ID等

【用户输入】 帮我看看his-doctor-service在2026-06-09 10:30:15左右报了个TooManyResultsException

【期望输出】 { "serviceCode": "his-doctor-service", "occurTime": "2026-06-09 10:30:15", "keyWord": "TooManyResultsException" }

markdown 复制代码
设计要点:
- 给出了具体的字段示例,降低 LLM 的理解成本。
- 对相对时间的处理做了特别说明(LLM 需要知道当前时间才能转换)。
- 明确了可选字段的处理方式(设为 null)。

#### 3.2 日志质量评估

这是整个 Prompt 工程中最复杂的部分,因为它需要 LLM 同时考虑多个维度:

**角色定义**:"你是一名资深的微服务异常诊断专家,擅长分析多服务日志关联和质量评估。"

**上下文注入**:
- 用户报告的问题
- 当前抓取到的日志元数据(服务编码、服务器IP、文件名等)
- 服务器上所有可用日志文件列表
- 实际日志内容

**判断规则**(9 条详细规则,如上文所述)

**输出格式**:包含 14 个字段的 JSON 结构

这个 Prompt 的长度约 1500 字,但正是这种详尽的描述,确保了 LLM 在各种边界场景下都能给出合理的评估。

#### 3.3 重试策略生成

这个 Prompt 的独特之处在于:它接收的是**历次评估结果的汇总**,需要在"历史信息"的基础上做出"前瞻性决策"。

【历史评估结果汇总】

--- 第 1 轮抓取 --- 抓取参数:

  • 服务编码: his-doctor-service
  • 发生时间: 2026-06-09 10:30:15
  • 关键字: 无 评估结果:
  • 质量评分: 3/10
  • 日志被截断: true
  • 需要更多上下文: true
  • 推荐行动: extendByKeyword
  • 评估理由: 日志只包含了部分错误信息,堆栈被截断...

--- 第 2 轮抓取 --- 抓取参数:

  • 关键字: TooManyResultsException
  • 上边界: 100
  • 下边界: 200 评估结果:
  • 质量评分: 6/10
  • ...
markdown 复制代码
LLM 基于这些历史数据,可以做出非常智能的决策:
- "第 1 轮时间戳匹配为空,第 2 轮用关键字匹配成功了" → 继续使用关键字。
- "堆栈仍然被截断" → 进一步增大 `lowerBoundary`。
- "评分从 3 提升到 6 了" → 方向正确,继续微调。

#### 3.4 根因分析

根因分析 Prompt 采用了 `generateText` 模式(而非 `createObject`),因为它需要输出较为自由的长篇分析报告:

【分析要求】

  1. 问题摘要:用1-2句话精准概括问题的核心
  2. 根因分析:详细说明问题的根本原因,包括:
    • 异常发生的直接原因
    • 潜在的深层原因(配置问题、代码缺陷、资源不足等)
    • 证据链支撑(引用日志中的关键行)
  3. 修复建议:按优先级(HIGH/MEDIUM/LOW)给出具体可行的修复方案
  4. 置信度评估:HIGH/MEDIUM/LOW

【置信度判断标准】

  • HIGH: 日志完整、异常堆栈清晰、根因明确
  • MEDIUM: 日志基本可用、能推断可能原因但证据不够充分
  • LOW: 日志缺失关键信息、只能猜测可能原因
scss 复制代码
对于根因分析的输出,我们使用 `LlmResponseParseUtil` 进行后处理------提取 Markdown 中的各个章节(问题摘要、根因分析、修复建议、置信度),解析为 `DiagnosisReport` 对象。

### 4. 多模型配置与动态切换

系统支持同时注册多个 LLM 提供商的多个模型,通过 `LlmInitConfig` 在启动时自动注册:

```java
public LlmInitConfig(LlmProperties llmProps, GenericApplicationContext context) {
    for (LlmProperties.LlmProvider llmProp : llmProps.getLlmOpenAi()) {
        String provider = llmProp.getProvider();
        for (String modelName : llmProp.getModels()) {
            // 创建 OpenAiApi(支持不同 provider 的 API 路径差异)
            OpenAiApi api = OpenAiApi.builder()
                    .apiKey(llmProp.getApiKey())
                    .baseUrl(llmProp.getBaseUrl())
                    .completionsPath("zhipu".equals(provider)
                        ? "/v4/chat/completions" : "/v1/chat/completions")
                    .build();

            // 创建 ChatModel
            OpenAiChatModel chatModel = OpenAiChatModel.builder()
                    .openAiApi(api)
                    .defaultOptions(OpenAiChatOptions.builder()
                            .model(modelName)
                            .temperature(0.2)
                            .build())
                    .build();

            // 包装为 SpringAiLlmService 并注册为 Bean
            SpringAiLlmService service = new SpringAiLlmService(modelName, provider, chatModel);
            context.registerBean("llm-" + modelName, SpringAiLlmService.class, () -> service);
        }
    }
}

配置文件示例:

yaml 复制代码
agent:
  llm-open-ai:
    - provider: deepseek
      api-key: ${DEEPSEEK_API_KEY}
      base-url: https://api.deepseek.com
      models:
        - deepseek-chat        # 通用对话
        - deepseek-reasoner    # 推理增强
        - deepseek-v4-flash    # 快速版(默认)
        - deepseek-v4-pro      # 专业版
    - provider: zhipu
      api-key: ${ZHIPU_API_KEY}
      base-url: https://open.bigmodel.cn/api/paas
      models:
        - glm-4.5-air
        - glm-4.7

在 Action 中,通过 withDefaultLlm() 使用默认模型(配置在 embabel.models.default-llm 中),也可以通过 withLlm("deepseek-v4-pro") 切换到指定模型。这种灵活性让我们可以为不同场景选择最合适的模型:

  • 日志质量评估 (快速判断):使用 deepseek-v4-flash,响应快、成本低。
  • 根因分析 (深度推理):使用 deepseek-v4-pro,推理能力更强。

5. createObject vs generateText

系统中两种 LLM 调用模式的选择策略:

模式 适用场景 优势 劣势
createObject 结构化输出(评估、参数生成) 自动反序列化,类型安全 受限于 JSON 格式
generateText 自由文本(分析报告) 输出灵活,可包含 Markdown 需要手动解析

在根因分析中,我们选择了 generateText + 手动解析,因为诊断报告需要包含代码片段、层级结构等复杂内容,不适合严格的 JSON 约束。而对于质量评估、参数生成等场景,createObject 的可靠性是不可替代的。

6. Prompt 演进与调优经验

在开发过程中,Prompt 经历了多轮迭代。以下是几个关键的调优经验:

问题一:LLM 总是给高分

  • 原因:评估 Prompt 中没有强调"与用户问题的相关性"。
  • 修复:添加规则------"即使异常堆栈信息完整,但不能解释用户遇到的问题,也不能打出高分"。

问题二:重试策略总是建议切换文件

  • 原因:LLM 不知道服务器上只有一个日志文件。
  • 修复:在 Prompt 中注入"可用日志文件列表",并添加规则------"只有一个文件时必须返回 false"。

问题三:JSON 中的代码片段导致解析失败

  • 原因:代码中的双引号破坏了 JSON 结构。
  • 修复:在 Prompt 中添加转义规则------"codeSnippet 中的双引号必须转义为 ""。

问题四:occurTime 格式不一致

  • 原因:LLM 有时输出 ISO 格式,有时输出自定义格式。
  • 修复:在 Prompt 中反复强调"必须为 yyyy-MM-dd HH:mm:ss 格式",并给出示例。

7. 温度与稳定性的平衡

所有 LLM 调用都设置了 temperature=0.2(通过 OpenAiChatOptions),这是一个偏低的温度值。在日志诊断场景中,我们需要的是稳定的、可预测的输出,而非"创造性"的回答。低温度确保了:

  • 相同输入产生相似的输出(可复现性)。
  • JSON 格式更稳定(减少格式错误)。
  • 评分标准更一致(不会忽高忽低)。

8. 小结

Prompt 工程是将 LLM 从"通用助手"塑造为"领域专家"的关键手段。在本项目中,我们通过 7 个精心设计的 Prompt,覆盖了诊断流程的每个决策点:信息提取、质量评估、策略优化、关键信息提取、根因分析、全链路分析和 RAG 检索指导。每个 Prompt 都遵循"角色-上下文-任务-约束"的统一范式,并通过多轮迭代不断优化。结合多模型配置和 createObject 的结构化输出机制,LLM 真正成为了系统的"大脑",驱动整个诊断流程的智能决策。


系列总结:从博客五到博客九,我们完整介绍了 Agent 版微服务日志诊断系统的核心架构:GOAP Agent 编排(博客五)、双路径策略(博客六)、RAG 引擎(博客七)、全链路追踪(博客八)和 Prompt 工程(博客九)。这套系统将 SSH 自动化、知识库关联、RAG 检索和 LLM 推理有机地融合在一起,实现了从"人肉排查"到"AI 自主诊断"的跨越。如果您对项目感兴趣,欢迎到 Gitee 上 Star 和提 Issue!


相关推荐
feelmylife591 小时前
AI系统测试实战指南——从确定性边界到非确定性输出,构建AI系统的分层测试体系
后端
想要成为糕糕手1 小时前
从 0 到 1 打造 Coding Agent——mini cursor(终篇):装上命令行手脚,造一个会"干活"的 AI 程序员
langchain·agent·ai编程
AliCloudROS1 小时前
使用 Skill 安装和管理 ECS 扩展程序
后端
用户298698530141 小时前
Python 实现 Excel 新旧格式互转:告别 Office 依赖的自动化方案
后端·python·excel
leeyi1 小时前
让 Agent 说中文:Prompt 模板怎么管理(第47篇-E33)
aigc·agent·ai编程
不好听6131 小时前
让 Agent 开口说话:用 Chalk 实现可视化终端
agent
JerrySir1 小时前
同一笔请求重来三次,业务只成功一次:技术面试里的幂等性怎么讲
后端
不好听6131 小时前
AI Agent 的四肢:Node.js 内置模块实战指南
agent
学渣超1 小时前
微服务日志智能诊断系统(七) 日志 RAG 引擎——蒸馏、索引与精准检索
java·后端·agent