Files
agent_jrxml/ARCHITECTURE.md
T

16 KiB
Raw Blame History

JRXML 生成代理 — 架构文档

概览

一个三层架构的桌面应用,通过自然语言多轮对话帮助非技术用户创建 JasperReports 模板(JRXML)。核心流程:用户输入 → 意图识别 → 模板检索 → LLM 生成/修改 → 自动验证修正 → 输出可编译的 JRXML。

┌──────────────────────────────────────────────────────────────┐
│                Vue 3 + Vite 前端 (:5173)                      │
│               frontend/ (聊天界面 + SSE 流式)                  │
│  聊天界面 / 会话管理 / JRXML 预览 / 下载 / 快捷操作            │
└─────────────────────┬────────────────────────────────────────┘
                      │ HTTP + SSE (/api/*)
                      ▼
┌──────────────────────────────────────────────────────────────┐
│               FastAPI SSE 后端 (:8000)                        │
│                    api_server.py                              │
│  REST: /api/sessions, /api/upload, /api/.../download/latest  │
│  SSE:  /api/sessions/{id}/chat (流式推送)                     │
│  事件: node_start | node_complete | stream_token              │
│        agent_complete | agent_error                           │
└─────────────────────┬────────────────────────────────────────┘
                      │ run_agent(user_input)
                      ▼
┌──────────────────────────────────────────────────────────────┐
│               LangGraph 状态机 (agent/)                       │
│                                                              │
│  load_session → process_input → manage_context               │
│     → save_state_snapshot → classify_intent                  │
│        │          │           │         │        │           │
│        ▼          ▼           ▼         ▼        ▼           │
│    retrieve   modify_jrxml  preview   consult  undo/reset    │
│        │          │         /export                          │
│        ▼          ▼                                         │
│     generate     save_session                                │
│        │          │                                          │
│        └────┬─────┘                                          │
│             ▼                                                │
│  (jrxml_reorder 自动规范化元素顺序)                            │
│             ▼                                                │
│         validate ──(fail)──► explain_error ──► correct_jrxml │
│            │                       ▲              │          │
│          (pass)                    └──(retry<N)───┘          │
│             ▼                                                │
│         finalize (失败版本 → jrxml_versions, 提示下载)         │
└──────────┬──────────────┬─────────────────────┬──────────────┘
           │              │                     │
           ▼              ▼                     ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────────────────┐
│  LLM 后端    │  │ 向量知识库   │  │  验证服务 (:8001)         │
│ backend/llm  │  │ ChromaDB +   │  │  FastAPI                  │
│              │  │ RAGSearcher  │  │  结构检查 + 严格 XSD 校验  │
│ Anthropic SDK│  │              │  │                           │
│ OpenAI SDK   │  │ Sentence-    │  │  /validate                │
│ Ollama       │  │ Transformer  │  │  /health                  │
└──────────────┘  └──────────────┘  └──────────────────────────┘

目录结构

agent_jrxml/
├── api_server.py                   # FastAPI SSE 后端(REST + 流式推送)
│
├── frontend/                       # Vue 3 + Vite 前端
│   └── src/
│       ├── api/client.ts           # SSE 客户端 + fetch 封装
│       ├── stores/                 # Pinia 状态管理(chat + session
│       └── components/             # 聊天界面组件
│
├── agent/                          # LangGraph 工作流层
│   ├── __init__.py
│   ├── state.py                    # AgentState TypedDict 定义(~28 字段)
│   ├── nodes.py                    # 18 个工作流节点(生成/修改/验证/修正/意图识别...)
│   └── graph.py                    # 状态图编译 + 路由逻辑 + 初始状态工厂
│
├── backend/                        # 基础设施层
│   ├── __init__.py
│   ├── llm.py                      # LLM 工厂:Anthropic(MiniMax) / OpenAI / Ollama
│   ├── embeddings.py               # 嵌入模型工厂:HuggingFace / OpenAI
│   ├── validation.py               # 验证服务 HTTP 客户端
│   ├── session.py                  # 会话持久化(JSON CRUD + flush/fsync
│   ├── jrxml_reorder.py            # JRXML 元素自动排序(匹配 XSD sequence
│   └── rag_adapter.py              # RAG 适配层:连接 ChromaDB 做语义搜索
│
├── validation_service/             # 独立验证微服务
│   ├── main.py                     # FastAPI 服务:结构检查 + 严格 XSD 校验
│   └── schemas/
│       └── jasperreport_7_0_6.xsd  # JasperReports 7.0.6 XSD286KB
│
├── scripts/
│   └── init_kb.py                  # 知识库初始化(预下载嵌入模型)
│
├── tests/
│   ├── __init__.py
│   ├── test_validation.py          # 验证服务单元测试
│   └── test_agent.py               # 代理集成测试
│
├── data/                           # 数据目录
│   ├── sample_templates/           # 示例 JRXML 模板
│   └── corrections/                # 错误修正案例
│
├── db/chroma/                      # ChromaDB 持久化存储
├── sessions/                       # 会话 JSON 文件存储
├── jrxml_versions/                 # 失败版本归档存储
├── rag/                            # RAG 子模块(独立管线)
├── requirements.txt                # Python 依赖
├── start_all.bat                   # 一键启动全部服务
├── start.bat                       # 启动脚本
├── stop.bat                        # 一键停止全部服务
├── .env.example                    # 环境变量模板
└── README.md                       # 使用说明

数据流详解

1. 请求生命周期

用户输入 "创建员工名册,包含 id、name、department"
  │
  ├─ load_session      从 sessions/{id}.json 恢复历史状态
  ├─ process_input     记录用户消息到 conversation_history
  ├─ manage_context    检查 token 数,超阈值则 LLM 压缩早期对话
  ├─ save_state_snapshot  保存当前状态快照(用于撤销)
  ├─ classify_intent   LLM 分类 → initial_generation
  ├─ retrieve          RAGSearcher.search_as_context() → 注入 prompt
  ├─ generate          LLM 生成初始 JRXML
  ├─ save_session      持久化到磁盘
  ├─ validate          调用 FastAPI 验证服务
  │   ├─ pass → finalize
  │   └─ fail → explain_error → correct_jrxml → validate (最多 5 次)
  └─ finalize          保存最终 JRXML,UI 展示结果

2. 意图路由(8 种意图)

意图 条件 路由目标
initial_generation 无现有报表 retrieve → generate
modify_report 有现有报表 modify_jrxml
preview_report 直接展示 current_jrxml
export_jrxml 触发下载
export_pdf 触发下载
consult_question handle_consult(独立回答)
undo_modification history_states 非空 恢复上一个快照
reset_session 清空所有报表状态

3. 自动修正循环

validate ──fail──► explain_error ──► correct_jrxml ──► validate
   ▲                                                       │
   └──────────── retry_count < MAX_RETRY (5) ──────────────┘

每次修正都会递增 retry_count,达到上限后直接 finalize(即使仍有错误),在 UI 上展示错误信息。

核心组件

AgentStateagent/state.py

class AgentState(TypedDict, total=False):
    # 工作流核心
    conversation_history: List[dict]     # 当前上下文的对话(可能被压缩裁剪)
    current_jrxml: str                   # 当前 JRXML 文本
    user_input: str                      # 本轮用户输入
    status: str                          # "pass" | "fail"
    error_msg: str                       # 验证错误信息
    natural_explanation: str             # 错误的人类可读解释
    retry_count: int                     # 当前修正尝试次数
    user_modification_request: str       # 修改请求文本
    final_jrxml: str                     # 最终验证通过的 JRXML
    stage: str                           # 当前阶段标识
    retrieved_context: str               # RAG 检索到的模板上下文

    # 上下文压缩
    full_conversation_history: List[dict]  # 完整对话(含时间戳)
    compressed_history: str                # 早期对话的压缩摘要
    current_token_count: int               # 当前估算 token 数

    # 会话持久化
    session_id: str
    session_name: str
    created_at: str
    updated_at: str

    # 意图识别 + 撤销
    intent: str                          # 8 种意图之一
    history_states: List[dict]           # 状态快照栈(最多 10 个)

工作流节点(agent/nodes.py

节点 职责 调用外部
load_session_node 从磁盘恢复会话状态 backend.session.load_session
process_input 记录用户输入到对话历史
manage_context token 超阈值时 LLM 压缩早期对话 get_llm()
save_state_snapshot 保存快照到 history_states
classify_intent LLM 分类用户意图(8 类) get_llm()
retrieve 从 ChromaDB 搜索相关模板 backend.rag_adapter.search_chunks
generate 首次生成 JRXML get_llm()
modify_jrxml 根据用户需求修改现有 JRXML get_llm()
validate 调用验证服务检查 JRXML backend.validation.validate_jrxml
explain_error LLM 将编译错误翻译为人话 get_llm()
correct_jrxml LLM 自动修正验证失败 get_llm()
finalize 保存最终 JRXML,标记完成
handle_consult 回答 JasperReports 咨询 get_llm()
handle_undo 从 history_states 恢复上一状态
handle_reset 清空报表,重置会话
save_session_node 持久化当前状态到磁盘 backend.session.save_session

LLM 工厂(backend/llm.py

get_llm()
  ├─ LLM_BACKEND=local  → langchain_ollama.ChatOllama
  └─ LLM_BACKEND=cloud
       ├─ LLM_PROVIDER=anthropic  → raw anthropic.Anthropic SDK
       │    适配 MiniMax Anthropic 兼容 API
       │    包装为 MiniMaxLLM(提供 .invoke() 接口)
       └─ LLM_PROVIDER=openai     → langchain_openai.ChatOpenAI

MiniMaxLLM 适配器:将 Anthropic SDK 的 client.messages.create() 包装成与 LangChain 兼容的 .invoke(prompt) → Response.content 接口,供所有节点统一调用。

RAG 适配层(backend/rag_adapter.py

search_chunks(query, k=5)
  └─ RAGSearcher(单例)
       ├─ 懒加载 SentenceTransformer 模型
       ├─ 懒连接 ChromaDB PersistentClient
       ├─ query → 向量编码 → collection.query() → top-k 结果
       └─ search_as_context() → 拼接带元数据标签的上下文字符串

验证服务(validation_service/main.py

独立的 FastAPI 进程(端口 8001),提供两级验证:

  1. 结构检查(始终执行):

    • XML 语法正确性
    • $F{field} 引用一致性(表达式 vs <field> 声明)
    • <queryString> 是否含有效 SQL SELECT
    • <jasperReport> 必需属性(pageWidth, pageHeight, name
  2. XSD Schema 校验(可选):

    • 需要 validation_service/schemas/jasperreport_7_0_6.xsd 文件
    • 使用 lxml.etree.XMLSchema 进行完整 schema 校验

会话持久化(backend/session.py

sessions/{session_id}.json
  {
    "session_id": "abc123def456",
    "session_name": "员工名册报表",
    "created_at": "2026-05-19T09:00:00+00:00",
    "updated_at": "2026-05-19T09:30:00+00:00",
    "agent_state": { ... }   // 完整的 AgentState 字段
  }

关键 Prompt 设计

Prompt 用途 输出约束
INTENT_CLASSIFY_PROMPT 8 分类意图识别 只输出意图名称
INITIAL_GENERATION_PROMPT 首次生成 JRXML 只输出 JRXML,无 markdown
MODIFICATION_PROMPT 修改现有 JRXML 只输出完整 JRXML
CORRECTION_PROMPT 自动修正错误 只输出修复后 JRXML
EXPLAIN_PROMPT 错误转人话 2-3 句话
COMPRESSION_PROMPT 对话压缩 ≤200 字摘要
CONSULT_PROMPT 咨询解答 简洁中文

配置参数(.env

参数 默认值 说明
LLM_BACKEND cloud cloud / local
LLM_PROVIDER openai openai / anthropic
OPENAI_API_KEY API 密钥
OPENAI_BASE_URL https://api.openai.com/v1 API 端点
LLM_MODEL gpt-4o 模型名称
LOCAL_LLM_MODEL qwen2.5-coder:7b Ollama 模型
EMBED_BACKEND local local / cloud
LOCAL_EMBED_MODEL Qwen/Qwen3-Embedding-0.6B 本地嵌入模型
VALIDATION_SERVICE_URL http://localhost:8001/validate 验证端点
CHROMA_PERSIST_DIR ./db/chroma ChromaDB 路径
MAX_RETRY 5 自动修正最大尝试次数
CONTEXT_MAX_TOKENS 6000 触发压缩的 token 阈值
CONTEXT_KEEP_RECENT 4 保留最近 N 轮完整对话
SESSIONS_DIR ./sessions 会话 JSON 存储目录
HISTORY_MAX_SNAPSHOTS 10 撤销快照保留数量

启动流程

# 1. 安装依赖
pip install -r requirements.txt

# 2. 配置环境
cp .env.example .env
# 编辑 .env 填入 API 密钥

# 3. 初始化知识库(预下载嵌入模型)
python scripts/init_kb.py --download-model

# 4. 启动验证服务(终端 1
python -m uvicorn validation_service.main:app --port 8001 --host 0.0.0.0

# 5. 启动 Streamlit 界面(终端 2
STREAMLIT_SERVER_HEADLESS=true streamlit run app.py --server.port 8501

# 6. 访问 http://localhost:8501

测试

pytest tests/test_validation.py -v    # 验证服务单元测试
pytest tests/test_agent.py -v         # 代理集成测试
pytest tests/ -v                      # 全部测试

技术栈

技术
UI Streamlit 1.57
工作流引擎 LangGraph 1.2
LLM 接入 Anthropic SDK / LangChain-OpenAI / LangChain-Ollama
向量数据库 ChromaDB 1.5
嵌入模型 Sentence-Transformers (HuggingFace)
验证服务 FastAPI + lxml XMLSchema
HTTP 客户端 httpx
Token 计算 tiktoken
持久化 JSON 文件 + ChromaDB PersistentClient