Skip to content

yiccyy/devops_agent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Enterprise Agent

面向 DevOps 场景的企业级 LLM Agent 系统 —— 集成 MCP 协议工具调用、意图路由(4 分类规则引擎)、混合检索 RAG(稠密 + BM25 + RRF 融合)、分层记忆体系(短期 Redis + 长期 PGVector 三层模型)、多模型接入工厂模式(DeepSeek / OpenAI / Anthropic)、场景分级架构(PRO 主对话 + FLASH 轻量辅助)、格式感知分块(Markdown/CSV/JSON 三策略)、双存储结构(semantic_text 检索 + raw_content LLM 使用)、PDF 结构化提取、查询改写(两级策略)、Rerank 精排、流式 SSE 对话与知识库全生命周期管理。


目录


项目概述

Enterprise Agent 是一个面向企业 DevOps 场景的智能助手系统。它将 LLM 的自然语言理解能力与外部系统操作能力结合,让用户通过自然语言完成日志查询、监控排查、缓存操作、知识问答等任务。

系统解决的核心问题是:传统运维工具交互割裂、信息分散——用户不再需要在日志平台、监控系统、缓存管理台等 N 个系统间反复切换,只需用自然语言描述需求,Agent 自动完成意图识别 → 工具规划 → 数据获取 → 结果整合的全流程。

系统的设计哲学是 "按需连接、证据驱动、不编造数据":只有外部数据/操作类意图才建立 MCP 连接,知识类问题直接回答;当工具不可用时明确告知用户而非产生幻觉。


功能特点

1. MCP 协议工具调用

是什么: 基于 MCP(Model Context Protocol) 的 SSE 客户端实现,通过 JSON-RPC 2.0 协议动态发现并调用远程工具(日志查询 search_logs、监控指标 query_metrics、链路追踪 get_trace、缓存检查 inspect_cache_key 等)。每个 MCP 工具被自动包装为 LangChain BaseTool,无缝接入 Agent 的 tool-calling 循环。

为什么需要: 企业运维环境中,数据分散在 ELK 日志平台、Prometheus/Grafana 监控系统、Redis 缓存集群、Jaeger 链路追踪等异构系统中。传统做法是为每个系统开发专用集成代码,维护成本高且扩展困难。MCP 协议提供标准化的工具发现与调用机制,新增一个数据源只需部署对应的 MCP Server,Agent 端零改动即可接入。

解决了什么问题:

  • 工具接入的扩展性问题——从"1 对 N 定制集成"变为"N 对 1 标准协议",新增数据源只需部署 MCP Server
  • 工具发现的手动配置问题——MCP 协议支持运行时通过 tools/list 动态拉取工具列表及 JSON Schema
  • 连接不稳定问题——内置断线检测与自动重连机制(_try_reconnect_mcp),工具调用失败时自动尝试重连对应 Server 并刷新工具列表

2. 意图路由与工具规划

2.1 意图识别(4 分类规则引擎)

是什么: 基于关键词+正则的四分类意图识别器,将用户输入分为:

意图 含义 示例
external_data 需要从外部系统获取真实数据 "查下最近15分钟的错误日志"
external_action 需要对外部系统执行操作 "重启 user-service"
knowledge 知识问答、分析推理 "Python 协程和线程有什么区别?"
chat 闲聊、问候 "你好"

优先级:action > data > chat > knowledge。

为什么需要: 并非所有用户输入都需要调用外部工具。知识问题 LLM 自身就能回答;外部数据查询才需要连接 MCP Server。如果不做意图区分,每次对话都尝试连接 MCP,既浪费资源又增加延迟。更重要的是,当无外部工具可用时,需要明确告知用户"当前未连接数据源",而不是让 LLM 编造虚假数据。

解决了什么问题:

  • 资源浪费——知识问答和闲聊无需建立 MCP 连接,按需连接节省开销
  • 响应延迟——跳过不必要的工具准备步骤,知识类问题直接回答
  • 幻觉防控——当意图需要外部能力但工具不可用时,直接告知用户而非编造数据

2.2 工具规划器(ToolPlanner)

是什么: 基于规则的 Ops 场景工具规划器,根据意图和关键词为每轮对话选择最优工具子集,并生成结构化的回答约束(answer_contract:证据→根因→SOP→处置)。

为什么需要: 运维排障场景中,不同类型的问题有固定的排查路径——链路问题先查 trace 再补指标和日志,缓存问题先查 key 和命中率再看发布记录。如果让 LLM 从全部工具中自由选择,容易走弯路或遗漏关键证据。

解决了什么问题:

  • 工具选择盲目性——从"暴露全部工具给 LLM"变为"按场景推荐有序工具链"
  • 证据收集不完整——通过 preferred_tools + fallback_tools 两级兜底确保关键工具不被遗漏
  • 回答结构不一致——answer_contract 强制四段式输出(证据/根因/SOP/处置)

2.3 控制环辅助(Control Loop Helpers)

是什么: 一组纯函数工具,从用户输入中提取结构化参数:

  • 服务推断find_service_hint):根据关键词映射到服务名(如"登录"→auth-gateway
  • Trace ID 提取find_trace_id):正则匹配 trace-id: xxx 等格式
  • 用户 ID 提取find_user_id):正则匹配 uid: xxx 等格式
  • 缓存 Key 推断find_cache_key):从 Redis/缓存相关描述中提取 key
  • 时间窗口推断infer_query_window):将"最近15分钟"→15m今天today
  • 指标名推断infer_metric_name):将"延迟高"→p95_ms错误率error_rate

为什么需要: 用户描述问题时往往使用口语化表达("登录一直转圈"),而工具参数需要精确值(service=auth-gateway)。这些辅助函数将自然语言参数转化为工具可用的结构化参数,减少 LLM 推理负担。


3. 混合检索 RAG

是什么: 检索阶段同时使用稠密向量检索(语义相似度)和 BM25 稀疏检索(关键词匹配),通过 RRF(Reciprocal Rank Fusion)倒数排名融合算法统一两种不同量纲的分数,再经短 chunk 惩罚 → 来源去重 → Rerank 精排 → 双存储重建,最终返回 Top-K 结果。

检索漏斗:dense 召回 k×3 → BM25 召回 k×3 → RRF 融合到 k×4 → 来源去重 → Rerank 精排到 k。

为什么需要: 单一检索方式存在固有缺陷:

检索方式 优势 劣势
稠密向量 理解语义("服务慢"≈"延迟高") 关键词精确匹配差
BM25 稀疏 关键词精确匹配强 语义盲区("RT变高"和"响应时间升高"无关)

RRF 融合算法用排名(而非原始分数)来合并结果,天然解决了分数量纲不一致的问题。

解决了什么问题:

  • 稠密检索的关键词丢失——BM25 补充精确匹配能力(默认 dense=0.8, BM25=0.2)
  • 稀疏检索的语义盲区——向量检索补充语义理解能力
  • 单一文档垄断 Top-K——来源去重(每个 source 最多 3 条),确保结果多样性
  • 短 chunk 噪声——< 50 字符的碎片施加惩罚,降低其排序权重
  • 排序精度不足——Rerank 精排(BAAI/bge-reranker-v2-m3 交叉编码器)显著提升最终排序质量

4. 格式感知分块体系

是什么: 根据文档格式自动选择最优分块策略,采用策略模式 + 工厂模式:

格式 分块器 策略
Markdown / TXT / PDF / DOCX / PPTX / HTML / RST MarkdownChunker 标题段落 → 语义 → 固定 三层降级
CSV CSVChunker 一行一 chunk + 双存储结构
JSON / YAML JSONChunker 递归展开叶子节点 + 双存储结构

为什么需要: 不同格式的文档有完全不同的结构特征:

  • Markdown/PDF 等非结构化文档:有标题层级、段落边界、代码块,固定长度分块会粗暴切断这些自然边界
  • CSV 表格数据:一行是一个完整的业务记录,按字符数切分会把一行拆散
  • JSON 配置/API 定义:嵌套层级深,数组元素独立性强,需要递归展开才能保证每个 chunk 的自洽性

解决了什么问题:

  • 格式不适配——每种格式都有专用分块器,不再"一把尺子量所有"
  • 语义完整性破坏——Markdown 分块以标题为自然段落边界,代码块被保护不被切断
  • 业务记录断裂——CSV 一行 = 一个 chunk,JSON 一个 API/配置项 = 一个 chunk

5. 双存储结构(Dual Storage)

是什么: 结构化文档(CSV/JSON)的每个 chunk 同时维护两份数据:

  • page_content(semantic_text):高语义密度的自然语言描述,参与 embedding 向量化,用于检索匹配
  • metadata.raw_content:原始结构化数据(Markdown 表格 / 原始 JSON),不参与 embedding,检索命中后拼接给 LLM 使用

以 CSV 为例:

semantic_text: "[表格: servers] 实例类型 m6i.2xlarge,CPU核数 8,内存 32GB,IP 192.168.1.10,端口 8080"
raw_content:    "| type | cpu | memory | ip | port |\n| m6i.2xlarge | 8 | 32GB | 192.168.1.10 | 8080 |"

为什么需要: 结构化数据的原始文本对 embedding 模型来说语义稀疏——列名缩写、缺少上下文、难以被自然语言查询命中。但如果把它改写成自然语言描述用于检索,又丢失了 LLM 需要的结构化细节。

双存储结构让检索和使用各取所需:检索时用语义丰富的 natural language,LLM 用时拿到完整的结构化原文

解决了什么问题:

  • 结构化数据检索困难——semantic_text 包含同义词扩展、字段名→自然语言映射,大幅提升召回率
  • LLM 输入信息损失——raw_content 保留完整原始数据,LLM 可以看到精确值和结构
  • Rerank 干扰——Rerank 仅基于 semantic_text 打分,避免 raw_content 中的噪声影响精排精度

6. PDF 结构化提取

是什么: 利用 pdfplumber 的字符级元信息(字号、字体、加粗、坐标),重建 PDF 文档的逻辑结构,将平铺文本还原为带 Markdown 标记的结构化文本:

  • 标题识别:字号 ≥ 正文 × 1.15 且加粗 → 判定为标题,按倍率区分 H1-H4 层级
  • 表格提取extract_tables() 自动检测表格区域,转为 Markdown 表格格式
  • 代码块标记:检测等宽字体区域(Courier/Consolas 等),用围栏代码块包裹
  • 目录页过滤:智能识别目录页(TOC)并跳过
  • 跨页合并:同一逻辑段落跨页时自动合并

失败时降级到 pypdf 纯文本提取。

为什么需要: PDF 是企业知识库中最常见的文档格式,但 PDF 本质是排版描述而非结构化文档。传统纯文本提取只能得到一串平铺文字,标题、正文、表格、代码全部混在一起,后续分块质量极差。

解决了什么问题:

  • 标题丢失——通过字号+加粗还原 Markdown 标题层级
  • 表格变乱码——表格转为标准 Markdown 格式,保留行列结构
  • 代码被切碎——等宽字体区域整体保留
  • 目录污染——目录页被过滤,避免无效内容进入知识库

7. 入库管线与后处理

7.1 入库管线编排

是什么: DocumentIngestion 编排完整处理管线:

加载(Loader) → PDF结构增强 → 清洗(Cleaner) → 分块(Chunker) → 后处理(PostProcessor) → 上下文注入(ContextInjector) → 向量化存储

管线不是"所有能力固定全开"的线性流程,而是根据文档类型和实验开关做场景化门控——CSV/JSON 默认跳过清洗和语义分块,含 raw_content 的 chunk 不参与合并和上下文注入。

为什么需要: 管线模式将每个步骤解耦为独立的处理器,可以单独开关、单独测试、按文档类型条件触发。

7.2 文本清洗(TextCleaner)

4 步清洗管线:Unicode 规范化(NFKC) → 控制字符清除 → 页码去除 → 空白归一化。

为什么需要: PDF/网页提取的文本常包含全角字符、NULL 控制符、页码行等噪声,这些噪声进入 embedding 会稀释有效语义。

7.3 分块后处理(ChunkPostProcessor)

碎片过滤 + 短 chunk 合并:过滤 < 30 字符的噪声碎片,合并相邻短 chunk(< 150 字符),含 raw_content 的 chunk 不参与合并。

为什么需要: 分块器常产出超短片段和相邻短 chunk,短 chunk 的 embedding 不稳定,相邻短 chunk 分别检索导致上下文割裂。

7.4 上下文注入(ContextInjector)

为非结构化 chunk 注入所属章节的 H1 标题前缀,如 [Redis 运维指南] 如何排查缓存穿透...

为什么需要: 分块后的 chunk 脱离了原始文档上下文,注入标题前缀后 embedding 能捕获关键上下文信息,提升检索准确性。

7.5 文档注册表(DocumentRegistry)

通过 MD5 哈希追踪已入库文档,支持增量更新检测:

  • 新文档 → 入库并注册
  • 文档未变更 → 跳过(避免重复入库)
  • 文档有变更 → 删除旧分块后重新入库

为什么需要: 知识库文档会持续更新,没有变更检测就无法判断是否需要重新入库,导致重复分块或遗漏更新。


8. 分层记忆体系

8.1 短期记忆(Short-Term Memory — Redis)

是什么: 基于 Redis List + Hash 的对话历史管理:

  • List(messages):RPUSH 增量追加每条消息 JSON,TTL 24h
  • Hash(meta):轮计数 + 压缩摘要 + 最后更新时间
  • 滑动窗口:保留最近 N 轮(默认 10 轮)完整对话
  • 轮级压缩:超出窗口时丢弃最旧 M 轮(默认 2 轮),用 Flash LLM 生成摘要

为什么需要: LLM 上下文窗口有限,运维排障对话往往持续多轮,历史消息很快超出窗口。直接丢弃旧消息会丢失关键上下文,导致 Agent 反复询问相同信息。

解决了什么问题:

  • 上下文窗口溢出——滑动窗口 + 摘要压缩,始终保持在窗口内
  • 增量写入效率——RPUSH 追加写入 O(1),避免整存整取
  • Redis 降级——Redis 不可用时自动降级到内存字典,保证开发环境可用

8.2 长期记忆(Long-Term Memory — PGVector 三层模型)

是什么: 将用户信息按类型分为三层存储,每次对话前自动召回相关记忆注入 Prompt:

层级 存储结构 特点 示例
Profile 画像 PG 表(key-value) UPSERT 覆盖,高频注入 tech_stack: Java/Spring Boot
Semantic 语义 PGVector(embedding) 向量相似召回,去重存储 "用户正在研究 LangGraph"
Episodic 事件 PG 表(时间序列) 按时间记录,可追溯 "完成了 RAG 知识库搭建"

工作流程:

用户输入 → MemoryAnalyzer(LLM判断是否值得记忆 + 分类 + 评分)
         ↓ 重要性 ≥ 0.3
    Profile → upsert key-value
    Semantic → embedding + 去重(cosine > 0.92) + 存储
    Episodic → 标题 + 摘要 + 详情 存储

用户提问 → MemoryRetriever(Profile 全量 + Semantic 向量召回 Top-K)
         ↓ MemoryPromptBuilder 组装 Prompt 片段
    → 注入 Agent System Prompt 中

为什么需要: 短期记忆有 TTL(24h),会话结束后自动清除。但用户的长期信息(技术栈偏好、职业方向、项目经验)在后续会话中仍然有价值。如果每次新会话都要重新告知 Agent,体验极差。

解决了什么问题:

  • 重复告知成本——Profile 画像每次对话自动注入
  • 记忆淹没——重要性评分阈值(0.3)过滤低价值内容
  • 重复存储——Semantic 记忆内置去重(cosine > 0.92)
  • 无关干扰——Semantic 记忆只在相关时才召回,避免无关信息污染 Prompt

9. 多模型接入与场景分级

是什么: 通过 ModelProfile(数据类定义 provider/model/temperature)+ LLM Factory(工厂方法按 provider 创建 LangChain ChatModel 实例)的架构,支持 DeepSeek / OpenAI / Anthropic 三家提供商的热切换。模型使用分为两个场景级别:

Profile 使用场景 要求 默认 temperature
PRO 主对话 Agent 的 tool-calling 循环 必须支持 function calling 0.3
FLASH 标题生成、对话摘要压缩、长期记忆分析 速度快、成本低 0.1

为什么需要:

  1. 提供商多样性:DeepSeek 性价比高、GPT-4o 工具调用稳定、Claude 长上下文能力强,企业需要灵活切换
  2. 成本优化:标题生成、摘要压缩、记忆分析等辅助任务用轻量模型即可,全部使用顶级模型造成成本浪费
  3. 原来硬编码的问题:切换模型需要改动多处代码,容易遗漏

解决了什么问题:

  • 提供商锁定——修改 llm/config.py 即可切换,零侵入业务代码
  • 成本优化——PRO 用强模型保质量,FLASH 用轻量模型省成本
  • 配置职责分离——settings.py 管 API Key、config.py 管功能开关、llm/config.py 管模型选择
  • 扩展性——新增提供商只需在 factory.py 加一个 if 分支

10. 流式对话与工具调用可视化

是什么: 基于 SSE(Server-Sent Events)的流式聊天接口:

事件类型 说明
conversation_id 会话 ID(首条事件)
text LLM 回复的文本片段(逐 token 流式输出)
tool_call 工具调用开始(含工具名和参数)
tool_result 工具执行结果返回
title 首轮问答后自动生成的会话标题
done 完整回复结束
error 错误信息

为什么需要: LLM 生成回复通常需要数秒到数十秒,一次排障可能串行调用 3-5 个工具,总耗时可达 30-60 秒。没有流式输出和中间过程展示,用户无法判断 Agent 是否在工作。

解决了什么问题:

  • 长等待焦虑——逐 token 流式输出让用户实时看到思考过程
  • 工具调用黑盒——tool_call/tool_result 事件让前端渲染工具卡片,过程透明可审计
  • 会话管理便利——首轮问答后异步生成标题,侧边栏即时显示

11. 会话持久化与标题生成

是什么: 基于 MySQL InnoDB 的完整对话历史存储,支持多会话 CRUD、消息持久化(user/assistant/tool 三种角色)、首轮问答后自动调用 Flash LLM 生成中文标题。

为什么需要: 短期记忆(Redis)有 TTL 限制(24h),过期后对话历史丢失。但运维排障对话往往有回溯价值,需要能翻阅历史对话。

解决了什么问题:

  • 对话永久保存——Redis 过期后仍可从 MySQL 加载完整历史
  • 多会话管理——前端侧边栏列出所有历史会话
  • 命名自动化——无需手动命名,首轮问答后自动生成语义准确的标题

12. 安全与权限

是什么: 多层次安全防护:

  • 防提示注入:用户输入用 <user_query> XML 标签包裹,与系统指令完全隔离
  • 能力边界动态注入<capability_status> 在每轮对话中动态注入当前工具状态
  • 角色鉴权:上游网关注入 X-User-IdX-User-Role Header,知识库管理操作仅 admin 可执行
  • XML 防逃逸:用户输入中的 < > 字符在包装前转义

为什么需要: LLM 面临提示注入攻击风险,企业环境中知识库操作权限也必须受控。


13. 配置分层设计

是什么: 配置严格分为三个文件:

文件 职责 是否含敏感信息
app/settings.py 环境相关配置(API Key、数据库连接串)
app/config.py 功能开关与常量(阈值、ENABLE_* 开关)
app/llm/config.py 模型选择档案(provider、model、temperature)

为什么需要: 将 API Key(敏感)和功能开关(非敏感)混在同一文件中,既不利于安全也不利于维护。模型选择抽离后,切换模型只需改 llm/config.py。

解决了什么问题:

  • 安全隐患——settings.py 可安全加入 .gitignore
  • 变更风险隔离——调功能开关不会误改数据库连接
  • 团队协作友好——开发者各自维护 settings.py,共享 config.py

14. 实验消融开关

是什么: 所有 RAG 优化模块均可通过 IngestionTogglesRetrievalToggles 两个 frozen dataclass 独立开关:

入库侧: clean_text / pdf_structure / format_aware_chunking / semantic_chunking / postprocess / context_injection

检索侧: hybrid / source_diversity / short_chunk_penalty / rerank / query_rewrite(light/llm/both 三级)/ bm25_weight / rrf_k

为什么需要: RAG 系统效果优化是持续迭代过程。没有开关控制,就无法做消融实验来量化每个模块的真实贡献。开关还支持按文档类型的条件门控——CSV/JSON 默认跳过清洗和语义分块。

解决了什么问题:

  • 效果归因困难——逐一关闭模块观察效果变化
  • 场景化门控——"对该类文档是否启用"的精细化控制
  • 快速回滚——某个模块引入回归时,一键关闭即可恢复基线

15. 控制环安全预算

是什么: Agent 的 tool-calling 循环内置四重安全预算,防止单次请求失控:

预算维度 默认值 说明
AGENT_MAX_MODEL_TURNS 6 单次请求最多允许模型推理轮数
AGENT_MAX_TOOL_CALLS 8 单次请求最多允许执行的工具调用数
AGENT_MAX_REPEATED_TOOL_CALLS 1 同一工具+相同参数最多执行次数
AGENT_MAX_RUNTIME_SECONDS 60 单次请求控制环最长运行时间

为什么需要: LLM 在工具调用循环中可能陷入死循环——反复调用同一工具、无限追问、或因工具返回异常而持续重试。没有预算限制,一次请求可能消耗大量 Token 和时间。

解决了什么问题:

  • 无限循环——模型推理轮数和工具调用次数双重上限
  • 重复调用——同一工具+参数去重,防止 LLM 重复执行相同查询
  • 超时失控——运行时间上限确保请求不会无限挂起

16. 运行观测与后续验收规划

当前已落地: 系统已基于 MySQL 自建 agent_runagent_run_event 两张观测表,记录一次 Agent run 的主信息与阶段事件。后端通过 RunObserverchat_stream 链路中写入运行开始、阶段开始/结束、路由决策、工具调用、Token 统计、异常和运行结束等事件;前端提供“观测中心”页面,支持按 run_id / conversation_id / user_id 查询运行记录,查看事件时间线、诊断结论、输入/输出摘要、Token、耗时、模型轮次、工具调用次数和单个事件的原始载荷。

为什么采用自建表: 这个项目优先解决的是"按一次 run 精确复盘现场",而不是通用平台级监控。自建表能直接围绕 Agent 的业务语义建模,例如 direct / rag / mcp / external_tool_unavailable 路由、控制环预算、工具调用、Token 使用和异常原因,便于在页面和 SQL 中按 run_id 还原问题现场。LangSmith、OpenTelemetry、Prometheus 等方案后续可以接入,但不作为第一层依赖。

当前诊断层: 在原始事件之上,系统已增加轻量诊断层,用于把事件解释成“正常 / 告警 / 异常 / 拦截 / 预算耗尽”等可读结论,并给出根因提示和建议动作。它解决的是“这一步是否值得关注、可能为什么、下一步怎么处理”的问题,比单纯事件流水账更适合排障。

当前边界: 诊断建议不能简单理解为“都需要人工重试”。工具超时、限流、临时网络失败这类问题可以走自动重试;工具缺失、鉴权失败、权限不足、外部写操作、高风险动作才更适合人工介入。当前版本的诊断层仍偏“过程诊断”,能解释局部事件,但还不能严格证明整次任务是否真的完成。

后续规划:任务验收层。 下一步应在过程层和诊断层之上增加“验收层”,用于判断 Agent 不是“看起来执行成功”,而是真的完成了用户目标。验收层需要回答四个问题:

问题 含义
任务目标是什么 本次 run 要完成的用户意图,例如查询数据、执行操作、给出排障结论
成功标准是什么 什么条件下算完成,例如查到有效数据、返回明确确认、给出带证据的根因
有哪些证据支持 工具结果、RAG 命中文档、最终回答引用、外部系统确认信息
最终判定是什么 completed / partial / failed / unverifiable / needs_human

后续可在 run 级别补充这些派生字段:task_goalsuccess_criteriaverification_signalsverdictconfidenceevidenceunresolved_risksrecommended_resolution。前端观测中心则展示“完成判定”“关键证据”“未解决风险”“下一步处理方式”,让排障人员不仅能看到发生了什么,也能判断这次 Agent 运行是否已经结案。

当前版本已经完成了 Agent 运行链路的可记录、可查询、可诊断;后续不追求堆更多事件,而是补齐“结果验收”和“处置闭环”。这体现的是生产化 Agent 的核心思路:不仅要能调用工具,还要能证明任务完成、识别不确定性,并在不能自动完成时给出清晰的人机协作边界。


架构特征

整体架构

┌──────────────────────────────────────────────────────────────────────┐
│                        Frontend (React + TypeScript + Vite)          │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌────────────────────┐  │
│  │ ChatView │  │ Sidebar  │  │Knowledge │  │  ToolCallCard      │  │
│  │ (SSE流式) │  │ (会话管理)│  │  Base    │  │  (工具调用可视化)  │  │
│  └─────┬────┘  └─────┬────┘  └─────┬────┘  └────────┬───────────┘  │
│        └──────────────┴─────────────┴────────────────┘               │
│                              │ SSE / REST                           │
└──────────────────────────────┼──────────────────────────────────────┘
                               │
┌──────────────────────────────┼──────────────────────────────────────┐
│                     FastAPI HTTP Server (Uvicorn)                   │
│                              │                                      │
│  ┌───────────────────────────┼──────────────────────────────────┐   │
│  │                   Enterprise Agent                            │   │
│  │                                                               │   │
│  │  ┌─────────────┐  ┌──────────────┐  ┌─────────────────────┐  │   │
│  │  │ Intent Router│  │ Tool Planner │  │ Control Loop        │  │   │
│  │  │ (4分类规则)  │  │ (Ops场景)    │  │ (≤6轮/≤8次工具调用) │  │   │
│  │  └──────┬──────┘  └──────┬───────┘  └──────────┬──────────┘  │   │
│  │         └───────────────┴─────────────────────┘               │   │
│  │                           │                                   │   │
│  │  ┌────────────────────────┴──────────────────────────────┐   │   │
│  │  │              Context Builder (Prompt Assembly)         │   │   │
│  │  │                                                      │   │   │
│  │  │  System Prompt → Capability Status → Tool Plan        │   │   │
│  │  │  → 历史摘要 → 长期记忆 → 最近N轮对话 → User Input    │   │   │
│  │  └──────────────────────────────────────────────────────┘   │   │
│  └───────────────────────────────────────────────────────────────┘   │
│                                                                       │
│  ┌──────────────┐  ┌──────────────────┐  ┌────────────────────────┐  │
│  │  MCP Client  │  │  RAG Engine      │  │    Memory System       │  │
│  │  (SSE/JSON-  │  │                  │  │ ┌──────┐ ┌──────────┐ │  │
│  │   RPC 2.0)   │  │  Retriever       │  │ │短期  │ │长期三层  │ │  │
│  │              │  │  Dense+BM25      │  │ │Redis │ │PGVector  │ │  │
│  │  · 发现工具  │  │  +RRF+Rerank     │  │ │TTL24h│ │Profile   │ │  │
│  │  · 调用工具  │  │                  │  │ │      │ │Semantic  │ │  │
│  │  · 自动重连  │  │  Ingestion       │  │ │      │ │Episodic  │ │  │
│  │              │  │  Pipeline        │  │ └──────┘ └──────────┘ │  │
│  └──────┬───────┘  └────────┬─────────┘  └────────────────────────┘  │
│         │                   │                                          │
│  ┌──────┴───────────────────┴──────────────────────────────────────┐  │
│  │                    LLM Layer (Factory Pattern)                   │  │
│  │  ┌────────────────────────┐  ┌──────────────────────────────┐  │  │
│  │  │ PRO (主对话/工具调用)    │  │ FLASH (轻量辅助任务)          │  │  │
│  │  │ DeepSeek / GPT-4o /    │  │ DeepSeek / GPT-4o-mini /    │  │  │
│  │  │ Claude Sonnet          │  │ Claude Haiku                 │  │  │
│  │  └────────────────────────┘  └──────────────────────────────┘  │  │
│  └────────────────────────────────────────────────────────────────┘  │
└──────────┼──────────────────────────┼─────────────────────────────────┘
           │                          │
           ▼                          ▼
    ┌──────────────┐          ┌──────────────┐
    │  MCP Server  │          │  PostgreSQL  │
    │  (外部工具)   │          │  + pgvector  │
    └──────────────┘          │  (向量+记忆)  │
                             └──────┬───────┘
                                    │
                               ┌────┴────┐
                               │  MySQL  │
                               │ (会话)  │
                               └─────────┘

关键设计决策

决策维度 选择 原因
工具协议 MCP (SSE + JSON-RPC 2.0) 标准化工具发现与调用,新增数据源零改动
意图识别 规则引擎(关键词+正则) 四分类场景规则足够准确,延迟 < 1ms,无需额外 LLM 调用
LLM 接入 Factory + ModelProfile 解耦提供商与业务代码,PRO/FLASH 分级降低成本
分块策略 格式感知(策略模式+工厂) CSV/JSON/Markdown 各有专属分块器
向量检索 混合(Dense + BM25 + RRF) 互补两种检索方式的短板
精排 BGE Reranker v2-m3 交叉编码器成对打分远优于单向 encoder 余弦相似度
记忆存储 Redis(短期) + PGVector(长期) Redis 高吞吐适合实时对话,PGVector 支持向量检索
配置分层 settings / config / llm-config 安全隔离 + 功能隔离 + 模型隔离
实验可控 frozen dataclass 开关 每个优化模块独立可关,支持消融实验
控制环 四重安全预算 防止 LLM 工具调用死循环
运行观测 MySQL 自建 run/event 表 按 run_id 还原 Agent 执行链路,保留后续验收层扩展空间

数据流:单次请求完整生命周期

用户输入: "查下 user-service 最近 15 分钟的错误日志"
    │
    ▼
[1] IntentRouter.classify() → Intent.EXTERNAL_DATA
    │
    ▼
[2] requires_external_system() → True → 建立 MCP 连接(按需)
    │
    ▼
[3] ToolPlanner.plan() → preferred=[search_logs, query_metrics]
    │
    ▼
[4] ContextBuilder._build_context()
    ├── System Prompt (YAML)
    ├── <capability_status> "已连接: search_logs, query_metrics..."
    ├── <tool_plan> "意图: external_data, 优先工具: search_logs→query_metrics"
    ├── 长期记忆 (Profile: Java后端 + Semantic: 最近在排查性能问题)
    ├── 短期记忆 (最近 10 轮对话)
    └── <user_query> "查下 user-service 最近 15 分钟的错误日志"
    │
    ▼
[5] LLM.invoke(messages) → tool_call: search_logs(service="user-service", ...)
    │
    ▼
[6] MCPClient.call_tool("search_logs", {...}) → 返回日志结果
    │
    ▼
[7] LLM.invoke(messages + ToolMessage) → tool_call: query_metrics(...)
    │
    ▼
[8] MCPClient.call_tool("query_metrics", {...}) → 返回指标数据
    │
    ▼
[9] LLM.invoke(messages + 2个ToolMessage) → 最终回复 (SSE text 事件流)
    │
    ▼
[10] ConversationStore.insert_message() → MySQL 持久化
    ShortTermMemory.append_message() → Redis 追加
    MemoryManager.store() → 长期记忆分析+存储(异步)

项目结构

devops_agent/
├── app/                              # 应用主包
│   ├── main.py                       # Uvicorn 入口
│   ├── settings.py                   # 环境相关配置(API Key、数据库连接)
│   ├── config.py                     # 功能配置(开关、常量、阈值)
│   │
│   ├── agent/                        # Agent 核心
│   │   ├── agent_core.py             # EnterpriseAgent 主类(生命周期/聊天/工具循环/记忆/上下文构建)
│   │   ├── intent.py                 # 意图识别(4分类规则引擎 + 关键词表)
│   │   ├── control_loop.py           # 控制环辅助(服务推断/trace_id/时间窗口/指标名提取)
│   │   ├── tool_planner.py           # Ops 场景工具规划器(证据优先级/回答契约)
│   │   └── prompts.yaml              # 系统提示词模板(XML结构化/防注入/能力边界)
│   │
│   ├── llm/                          # LLM 抽象层
│   │   ├── __init__.py               # 导出 create_pro / create_flash / ModelProfile
│   │   ├── config.py                 # ModelProfile 定义(PRO / FLASH)
│   │   └── factory.py                # LLM 工厂(DeepSeek/OpenAI/Anthropic 动态创建)
│   │
│   ├── memory/                       # 记忆系统
│   │   ├── short_term.py             # 短期记忆(Redis List+Hash,滑动窗口+压缩)
│   │   ├── summarizer.py             # 对话摘要(Flash LLM 压缩)
│   │   ├── long_term.py              # 长期记忆导出
│   │   └── long_term/                # 长期记忆(PGVector 三层模型)
│   │       ├── manager.py            # MemoryManager 门面(写入/查询/删除/Prompt 构建)
│   │       ├── analyzer.py           # 记忆分析器(LLM 判断是否值得记忆+分类+评分)
│   │       ├── retriever.py          # 记忆召回(Profile 全量 + Semantic 向量检索)
│   │       ├── prompt_builder.py     # 长期记忆 Prompt 组装
│   │       ├── profile_service.py    # Profile 画像(key-value UPSERT)
│   │       ├── semantic_service.py   # Semantic 语义记忆(embedding + 去重)
│   │       ├── episodic_service.py   # Episodic 事件记忆(时间序列)
│   │       └── repository.py         # 底层数据访问(PG SQL)
│   │
│   ├── rag/                          # RAG 知识库引擎
│   │   ├── experiment_controls.py    # 消融实验开关(IngestionToggles / RetrievalToggles)
│   │   ├── tool.py                   # search_knowledge_base LangChain 工具封装
│   │   │
│   │   ├── chunker/                  # 分块策略(策略模式 + 工厂模式)
│   │   │   ├── __init__.py           # 工厂函数 get_chunker(ext)
│   │   │   ├── base.py               # BaseChunker 抽象基类
│   │   │   ├── markdown_chunker.py   # Markdown 分块(标题段落→语义→固定 三层降级)
│   │   │   ├── csv_chunker.py        # CSV 分块(一行一 chunk + 双存储结构)
│   │   │   ├── json_chunker.py       # JSON 分块(递归展开 + 双存储 + 语义生成)
│   │   │   └── postprocess.py        # 后处理(碎片过滤 + 短 chunk 合并)
│   │   │
│   │   ├── ingestion/                # 入库管线
│   │   │   ├── pipeline.py           # 入库编排(加载→清洗→分块→后处理→上下文注入→存储)
│   │   │   ├── loader.py             # 多格式文档加载器(PDF/DOCX/PPTX/HTML/CSV/JSON/TXT)
│   │   │   ├── cleaner.py            # 文本清洗(NFKC/控字符/页码/空白归一化)
│   │   │   ├── pdf_extractor.py      # PDF 结构化提取(标题/表格/代码块/目录过滤)
│   │   │   └── context_injector.py   # 上下文注入(H1 标题前缀)
│   │   │
│   │   ├── retrieval/                # 检索管线
│   │   │   ├── retriever.py          # 检索编排(Dense→BM25→RRF→惩罚→去重→Rerank→双存储重建)
│   │   │   ├── reranker.py           # Rerank 精排(SiliconFlow 云端 API / 本地 BGE)
│   │   │   └── query_rewriter.py     # 查询改写(轻量同义词扩展 + LLM 语义改写)
│   │   │
│   │   └── store/                    # 存储层
│   │       ├── vector_store.py       # PGVectorStore 管理(建表/增删/计数)
│   │       ├── embeddings.py         # Embedding 封装(SiliconFlow 云端 / 本地 BGE)
│   │       └── document_registry.py  # 文档注册表(MD5 变更检测/增量更新)
│   │
│   ├── tools/                        # 外部工具集成
│   │   ├── mcp_client.py             # MCP SSE 客户端(连接/发现/调用/重连)
│   │   ├── mock_mcp_server.py        # Mock MCP Server(开发测试用)
│   │   └── test_mcp.py               # MCP 集成测试
│   │
│   ├── observability/                # 运行观测
│   │   ├── tracer.py                 # RunObserver(run/event/span/token/异常记录)
│   │   └── diagnosis.py              # 诊断层(事件解释、根因提示、建议动作)
│   │
│   ├── api/                          # API 层
│   │   ├── http_server.py            # FastAPI HTTP 服务(SSE聊天/会话/知识库/记忆/静态文件)
│   │   └── grpc_server.py            # gRPC 服务(预留)
│   │
│   ├── persistence/                  # 持久化
│   │   ├── conversation_store.py     # MySQL 会话存储(CRUD + 消息持久化)
│   │   ├── observability_store.py    # MySQL 运行观测存储(agent_run / agent_run_event)
│   │   └── title_generator.py        # 会话标题生成(Flash LLM)
│   │
│   └── utils/
│       └── text_processing.py        # 文本处理工具函数
│
├── scripts/                          # CLI 工具脚本
│   ├── ingest_knowledge_base.py      # 知识库入库 CLI(目录/单个文件/统计/重建/清理)
│   └── mock_mcp_server.py            # Mock MCP Server 启动脚本
│
├── tests/                            # 测试套件
│   ├── conftest.py                   # Pytest 配置与共享 fixture
│   ├── test_chunker.py               # 分块器测试
│   ├── test_cleaner.py               # 清洗器测试
│   ├── test_postprocess.py           # 后处理器测试
│   ├── test_context_injector.py      # 上下文注入测试
│   ├── test_pdf_extractor.py         # PDF 提取测试
│   ├── test_experiment_toggles.py    # 实验开关测试
│   ├── test_control_loop.py          # 控制环辅助测试
│   ├── test_tool_planner.py          # 工具规划器测试
│   ├── test_structured_retrieval.py  # 结构化检索测试
│   ├── test_e2e_pipeline.py          # 端到端管线测试
│   ├── test_agent_decision_metrics.py # Agent 决策指标测试
│   └── test_retrieval_ceiling_diagnosis.py # 检索天花板诊断测试
│
├── eval/                             # 评估套件
│   ├── run_rag_ablation_matrix.py    # RAG 消融矩阵评估
│   ├── run_ops_benchmark.py          # Ops 场景基准测试
│   ├── run_ops_benchmark_live.py     # Ops 在线基准测试
│   ├── run_agent_benchmark_live.py   # Agent 在线基准测试
│   ├── diagnose_retrieval_ceiling.py # 检索天花板诊断
│   ├── diagnose_recall.py            # 召回率诊断
│   ├── diagnose_from_data.py         # 数据驱动诊断
│   ├── verify_query_rewriter.py      # 查询改写验证
│   ├── generate_test_set.py          # 测试集生成
│   ├── report_profiles.py            # 评估报告生成
│   ├── check_api_quota.py            # API 配额检查
│   ├── run_layer2_eval.py            # Layer2 评估
│   ├── run_layer2_eval_v3.py         # Layer2 评估 v3
│   ├── analyze_layer2.py             # Layer2 分析
│   ├── analyze_layer2_full.py        # Layer2 完整分析
│   └── agent_decision_metrics.py     # Agent 决策指标
│
├── frontend/                         # React 前端
│   ├── src/                          # 源码
│   │   ├── App.tsx                   # 主应用组件
│   │   ├── main.tsx                  # 入口
│   │   ├── types.ts                  # 类型定义
│   │   ├── components/               # UI 组件
│   │   │   ├── ChatView.tsx          # 聊天主视图
│   │   │   ├── Sidebar.tsx           # 侧边栏(会话列表)
│   │   │   ├── MessageBubble.tsx     # 消息气泡
│   │   │   ├── InputArea.tsx         # 输入区域
│   │   │   ├── ToolCallCard.tsx      # 工具调用卡片
│   │   │   ├── KnowledgeBase.tsx     # 知识库管理
│   │   │   └── ObservabilityCenter.tsx # 观测中心(运行列表/详情/诊断/事件载荷)
│   │   └── hooks/                    # React Hooks
│   │       ├── useChat.ts            # 聊天逻辑
│   │       ├── useConversations.ts   # 会话管理
│   │       └── useSession.ts         # 会话状态
│   ├── dist/                         # 构建产物
│   ├── package.json
│   ├── vite.config.ts
│   └── tsconfig.json
│
├── knowledge_base_testdoc/           # 测试知识库文档
│
├── docker-compose.yml                # Docker Compose(PostgreSQL + MySQL)
├── pyproject.toml                    # Python 项目配置与依赖
├── .gitignore                        # Git 忽略规则(.env)
└── README.md                         # 本文件

技术栈

技术 说明
LLM DeepSeek / OpenAI / Anthropic 通过 LLM Factory 按场景分级接入
Embedding SiliconFlow (BAAI/bge-large-zh-v1.5) 1024 维向量,云端 API,可选本地模型
Reranker SiliconFlow (BAAI/bge-reranker-v2-m3) 交叉编码器精排,可选本地模型
向量数据库 PostgreSQL + pgvector IVFFlat 索引,RAG + 长期记忆共用
短期记忆 Redis List + Hash 结构,TTL 24h,不可用时降级到内存
会话存储 MySQL 8.0 InnoDB,外键级联删除
后端框架 FastAPI + Uvicorn SSE 流式输出,CORS,静态文件托管
LLM SDK langchain-deepseek / langchain-openai / langchain-anthropic Factory 模式动态加载
文档解析 pdfplumber / pypdf / python-docx / python-pptx / BeautifulSoup 多格式统一加载
分块 LangChain RecursiveCharacterTextSplitter + 自研语义分块 三层降级策略
工具协议 MCP (SSE + JSON-RPC 2.0) 标准化工具发现与调用
前端 React + TypeScript + Vite 深色/浅色主题,响应式布局
部署 Docker Compose PostgreSQL + MySQL 一键启动

快速开始

1. 启动基础设施

docker compose up -d

启动 PostgreSQL (pgvector, 端口 5432) + MySQL 8.0 (端口 3306)。

2. 配置环境变量

# LLM API Key(至少配置你使用的提供商,默认 DeepSeek)
export DEEPSEEK_API_KEY="your-deepseek-api-key"
# export OPENAI_API_KEY="sk-xxxxxxxx"        # 切换 OpenAI 时需要
# export ANTHROPIC_API_KEY="sk-ant-xxxxxxxx"  # 切换 Claude 时需要

# SiliconFlow(Embedding + Reranker,必填)
export SILICONFLOW_API_KEY="your-siliconflow-api-key"

# 可选配置(以下为默认值)
export REDIS_HOST="127.0.0.1"
export REDIS_PORT="6379"

3. 安装依赖

# 使用 uv(推荐)
pip install uv
uv sync

# 或使用 pip
pip install -e .

4. 启动后端

python -m app.main

服务启动在 http://0.0.0.0:8000

5. 启动前端(开发模式)

cd frontend
npm install
npm run dev

前端开发服务器启动在 http://localhost:5173

6. 构建前端(生产模式)

cd frontend
npm run build

构建产物在 frontend/dist/,后端自动托管静态文件,访问 http://localhost:8000 即可使用。

7. 知识库入库(CLI)

# 查看统计
python -m scripts.ingest_knowledge_base --stats

# 入库默认目录
python -m scripts.ingest_knowledge_base

# 入库指定目录
python -m scripts.ingest_knowledge_base /path/to/docs

# 入库单个文件
python -m scripts.ingest_knowledge_base --file /path/to/doc.md

# 重建索引
python -m scripts.ingest_knowledge_base --reindex /path/to/doc.md

# 删除指定来源的所有分块
python -m scripts.ingest_knowledge_base --clear-source /path/to/doc.md

配置说明

settings.py(环境相关配置)

所有值可通过环境变量覆盖。此文件包含敏感信息,不应提交到 Git

环境变量 默认值 说明
DEEPSEEK_API_KEY DeepSeek API Key
OPENAI_API_KEY OpenAI API Key
ANTHROPIC_API_KEY Anthropic API Key
SILICONFLOW_API_KEY 硅基流动 API Key(Embedding + Reranker,必填
SILICONFLOW_BASE_URL https://api.siliconflow.cn/v1 硅基流动 API 地址
SILICONFLOW_EMBEDDING_MODEL BAAI/bge-large-zh-v1.5 Embedding 模型
SILICONFLOW_RERANKER_MODEL BAAI/bge-reranker-v2-m3 Reranker 模型
REDIS_HOST 127.0.0.1 Redis 地址
REDIS_PORT 6379 Redis 端口
PGVECTOR_CONNECTION postgresql+psycopg://agent:agent123@127.0.0.1:5432/agent_knowledge PGVector 连接串
MYSQL_CONNECTION mysql+pymysql://agent:agent123@127.0.0.1:3306/agent_conversations MySQL 连接串
AUTH_USER_HEADER X-User-Id 上游网关注入的用户身份 Header
AUTH_ROLE_HEADER X-User-Role 上游网关注入的角色 Header
USER_ID default 当前用户标识

config.py(功能配置)

配置项 默认值 说明
MEMORY_TTL 86400 短期记忆 TTL(秒),默认 24h
MEMORY_MAX_ROUNDS 10 滑动窗口保留轮数
MEMORY_DISCARD_ROUNDS 2 每次压缩丢弃轮数
AGENT_MAX_MODEL_TURNS 6 单次请求最大模型推理轮数
AGENT_MAX_TOOL_CALLS 8 单次请求最大工具调用次数
AGENT_MAX_REPEATED_TOOL_CALLS 1 同一工具+参数最大执行次数
AGENT_MAX_RUNTIME_SECONDS 60 单次请求控制环最长运行时间
KNOWLEDGE_BASE_DIR ./knowledge_base_testdoc 知识库文档目录
CHUNK_SIZE 500 固定分块大小(字符数)
CHUNK_OVERLAP 50 分块重叠(字符数)
RAG_TOP_K 5 RAG 检索返回文档数
EMBEDDING_PROVIDER "siliconflow" Embedding 提供商(siliconflow / local
RERANKER_PROVIDER "siliconflow" Reranker 提供商(siliconflow / local
LONG_TERM_MEMORY_ENABLED True 是否启用长期记忆
MEMORY_IMPORTANCE_THRESHOLD 0.3 长期记忆重要性阈值
MEMORY_DEDUP_THRESHOLD 0.92 Semantic 记忆去重余弦相似度阈值

RAG 实验开关:

开关 默认值 说明
ENABLE_CLEANING True 文本清洗(仅非结构化文档)
ENABLE_PDF_STRUCTURE_ENHANCEMENT True PDF 结构化提取
ENABLE_FORMAT_AWARE_CHUNKING True 格式感知分块
ENABLE_SEMANTIC_CHUNKING True 语义分块(仅非结构化文档)
ENABLE_POSTPROCESS True 分块后处理(碎片过滤+合并)
ENABLE_CONTEXT_INJECTION True 上下文注入
ENABLE_HYBRID True 混合检索(Dense + BM25 + RRF)
ENABLE_SHORT_CHUNK_PENALTY True 短 chunk 惩罚
ENABLE_SOURCE_DIVERSITY True 来源去重
ENABLE_RERANK True Rerank 精排
ENABLE_QUERY_REWRITE False 查询改写(默认关闭)
QUERY_REWRITE_LEVEL "light" 查询改写级别(light/llm/both)

llm/config.py(模型选择)

Profile 默认 Provider 默认 Model Temperature 使用场景
PRO deepseek deepseek-chat 0.3 主对话 Agent、tool-calling 循环
FLASH deepseek deepseek-chat 0.1 标题生成、摘要压缩、记忆分析

切换 LLM 提供商

系统默认使用 DeepSeek,但你可以在 DeepSeek / OpenAI / Anthropic 之间自由切换,且 PRO 和 FLASH 可以使用不同的提供商。

第一步:设置 API Key

# DeepSeek(默认)
export DEEPSEEK_API_KEY="sk-xxxxxxxx"

# OpenAI
export OPENAI_API_KEY="sk-xxxxxxxx"

# Anthropic / Claude
export ANTHROPIC_API_KEY="sk-ant-xxxxxxxx"

第二步:修改 app/llm/config.py

# ===== PRO: 主对话模型 =====
PRO = ModelProfile(
    # provider="deepseek",        # 默认
    # model="deepseek-chat",      # 默认

    # → 切换到 OpenAI GPT-4o:
    provider="openai",
    model="gpt-4o",

    # → 或切换到 Anthropic Claude:
    # provider="anthropic",
    # model="claude-sonnet-4-6",

    temperature=0.3,
)

# ===== FLASH: 轻量辅助模型 =====
FLASH = ModelProfile(
    # provider="deepseek",        # 默认
    # model="deepseek-chat",      # 默认

    # → 切换到 OpenAI GPT-4o-mini(省钱):
    provider="openai",
    model="gpt-4o-mini",

    # → 或切换到 Anthropic Claude Haiku(极速):
    # provider="anthropic",
    # model="claude-haiku-4-5",

    temperature=0.1,
)

第三步:确认 provider 名称

provider 字段只能是以下三个值之一(定义在 factory.py):

provider 值 实际服务 对应 SDK
"deepseek" DeepSeek langchain_deepseek
"openai" OpenAI langchain_openai
"anthropic" Anthropic langchain_anthropic

写错会启动时报 ValueError: Unsupported provider

成本优化建议

策略 PRO FLASH 预估节省
同提供商高低搭配 deepseek-chat deepseek-chat (同模型) 0%(温度差异微小)
跨提供商优化 deepseek-chat (主) gpt-4o-mini (辅) ~60% 辅助任务成本
极致成本 gpt-4o-mini gpt-4o-mini 质量可能下降

注意: FLASH 模型的唯一要求是"不需要 function calling",因为它只用于单轮指令跟随任务(生成标题、压缩摘要、分析记忆)。


API 接口

聊天

POST /api/chat
Content-Type: application/json

{
  "message": "查一下最近15分钟的错误日志",
  "conversation_id": "可选,不传则创建新会话"
}

Response: SSE 流
  event: conversation_id  → {"conversation_id": "uuid"}
  event: tool_call        → {"name": "search_logs", "args": {...}}
  event: tool_result      → {"name": "search_logs", "result": "..."}
  event: text             → {"content": "根据日志分析..."}  (多次)
  event: title            → {"title": "user-service 错误日志排查"}  (首次问答)
  event: done             → {}
  event: error            → {"message": "..."}

会话管理

POST   /api/conversations              创建新会话
GET    /api/conversations?limit=50&offset=0  列出会话(分页)
GET    /api/conversations/{id}         获取会话详情 + 消息列表
PATCH  /api/conversations/{id}         更新会话标题 Body: {"title": "新标题"}
DELETE /api/conversations/{id}         删除会话及其消息

知识库管理

POST   /api/knowledge/upload           上传文档(multipart/form-data,MD5 增量入库)
GET    /api/knowledge/documents?offset=0&limit=10  列出文档(分页)
GET    /api/knowledge/documents/{source}/chunks  查看文档的实际分块内容
DELETE /api/knowledge/documents/{source}         删除文档及其所有分块(需 admin 角色)
POST   /api/knowledge/documents/{source}/reindex  重建索引(忽略 MD5,强制重新分块)
GET    /api/knowledge/permissions      查询当前用户权限

长期记忆

POST   /api/memory/store               存储记忆 Body: {"user_id": "...", "content": "..."}
POST   /api/memory/search              搜索记忆 Body: {"user_id": "...", "query": "...", "top_k": 5}
GET    /api/memory/profile/{user_id}   获取用户画像
DELETE /api/memory/{type}/{id}         删除记忆(type: profile/semantic/episodic)

其他

GET    /api/session                    Agent 状态(就绪?/工具列表/Server 列表)
GET    /api/health                     健康检查
GET    //*                              前端 SPA fallback(frontend/dist/index.html)

RAG 管线详解

入库管线(Ingestion Pipeline)

原始文件(bytes)
    │
    ▼
[1] Loader.load_document()
    ├─ .md/.txt/.rst/.yaml → UTF-8 解码
    ├─ .pdf → pdfplumber 提取文本(fallback pypdf)
    ├─ .docx → python-docx(段落 + 表格→Markdown)
    ├─ .pptx → python-pptx(幻灯片文本)
    ├─ .html → BeautifulSoup(去除 script/style/nav)
    ├─ .csv → 原始文本
    └─ .json → 原始文本
    │
    ▼
[2a] PDF Structure Extractor (仅 .pdf)
    ├─ 字号+加粗 → 标题层级 (H1-H4)
    ├─ extract_tables() → Markdown 表格
    ├─ 等宽字体 → 围栏代码块
    └─ 目录页检测 → 跳过
    │
    ▼
[2b] Text Cleaner (仅非结构化文档)
    ├─ Unicode NFKC 规范化
    ├─ 控制字符清除(保留 \n \t)
    ├─ 页码行去除
    └─ 空白归一化
    │
    ▼
[3] Chunker.split() (格式感知)
    ├─ .md/.txt/.pdf/.html/.docx/.pptx/.rst → MarkdownChunker
    │   ├─ Tier 1: 标题段落分块(# ## ### 自然边界)
    │   ├─ Tier 2: 语义分块(句子 embedding 相似度断句)
    │   └─ Tier 3: 固定分块兜底(RecursiveCharacterTextSplitter)
    ├─ .csv → CSVChunker (一行一 chunk + dual storage)
    └─ .json → JSONChunker (递归展开 + dual storage)
    │
    ▼
[4] PostProcessor.process()
    ├─ 过滤噪声 (<30 chars 无意义碎片)
    ├─ 合并短 chunk (<150 chars, 同 source/section)
    └─ 重索引 (chunk_index + content_hash)
    │
    ▼
[5] ContextInjector.inject_document_context()
    └─ 为非结构化 chunk 注入 [H1标题] 前缀
    │
    ▼
[6] VectorStore.add_documents()
    └─ Embedding → PGVector 存储

检索管线(Retrieval Pipeline)

用户查询: "Redis 缓存击穿怎么排查"
    │
    ▼
[1] QueryRewriter.rewrite() (可选, ENABLE_QUERY_REWRITE=True)
    ├─ Level 1 (light): 同义词扩展 + 短查询领域补充
    └─ Level 2 (LLM): Flash 模型语义改写
    │
    ▼
[2] Dense Search (余弦相似度, top_k × 3)
    └─ PGVector similarity_search_with_score(query, top_k=k*3)
    │
    ▼
[3] BM25 Search (词频统计, top_k × 3)
    ├─ 从 DB 加载全部 chunks 构建 BM25 索引(懒构建)
    ├─ 中文逐字切分 + 英文按词切分
    └─ BM25+ 公式打分
    │
    ▼
[4] RRF Fusion (倒数排名融合)
    └─ score = dense_w/(rrf_k+rank_dense) + bm25_w/(rrf_k+rank_bm25)
       (dense_w=0.8, bm25_w=0.2, rrf_k=60)
    │
    ▼
[5] Short Chunk Penalty
    └─ content_length < 50 → 扣分(基于分数范围的相对惩罚)
    │
    ▼
[6] Source Diversity (来源去重)
    └─ 每个 source 最多保留 max_per_source 条(默认 3)
    │
    ▼
[7] Rerank 精排 (BAAI/bge-reranker-v2-m3)
    └─ 对 top_k × 4 候选做 query-doc 成对交叉编码打分
    └─ 取 Top-K 最终结果
    │
    ▼
[8] Dual Storage 重建
    ├─ 有 raw_content → 用 raw_content 替换 page_content(LLM 看到结构化原文)
    └─ 无 raw_content → 保持 page_content 不变
    │
    ▼
[9] 返回格式化结果
    └─ [{source, score, content}, ...]

About

企业级智能体(Enterprise Agent) —— 面向 DevOps 场景的 LLM Agent 系统,集成 MCP 协议工具调用、意图路由、混合检索 RAG、分层记忆体系与流式对话前端。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors