feat: 添加结构化日志系统,更新LLM配置与全部文档
新增: - backend/logger.py — 集中日志模块 (JSON格式 + trace_id + 独立llm.log) - @log_node / @_log_route 装饰器覆盖17个节点和8个路由 改进: - backend/llm.py — _LLMLoggingWrapper 自动记录LLM输入输出 - backend/llm.py — API Key优先读ANTHROPIC_API_KEY,模型名改为MiniMax-M2.7 - backend/llm.py — get_llm() 新增caller参数标识调用来源 - backend/validation.py — 新增验证结果/连接失败日志 - backend/session.py — 新增会话创建/删除日志 - app.py — 新增用户交互日志 (输入/执行/异常/会话操作) - app.py — 提前导入torchvision抑制transformers懒加载报错 - .env.example — 新增LOG_DIR/LOG_LEVEL/ANTHROPIC_API_KEY等配置项 - .gitignore — 新增logs/和db/忽略规则 文档: - ROADMAP.md — 新增阶段四: 可观测性 - README.md — 补充日志架构/LLM配置/项目结构 - CLAUDE.md — 同步最新配置/日志/MAX_RETRY(3) - CODE_GUIDE.md — 新增第15章日志系统,更新架构图/LLM/配置
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
"""LangGraph JRXML 生成代理的状态图定义。"""
|
||||
|
||||
import functools
|
||||
import os
|
||||
from typing import Literal
|
||||
|
||||
@@ -25,14 +26,41 @@ from agent.nodes import (
|
||||
correct_jrxml,
|
||||
finalize,
|
||||
)
|
||||
from backend.logger import get_logger
|
||||
|
||||
load_dotenv()
|
||||
MAX_RETRY = int(os.getenv("MAX_RETRY", "3"))
|
||||
|
||||
_graph_log = get_logger("agent")
|
||||
|
||||
|
||||
def _log_route(route_name: str):
|
||||
"""装饰器:自动记录路由决策。"""
|
||||
def decorator(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(state: AgentState, *args, **kwargs):
|
||||
target = func(state, *args, **kwargs)
|
||||
_graph_log.info(
|
||||
f"[路由] {route_name} → {target}",
|
||||
extra={
|
||||
"route": route_name,
|
||||
"target": target,
|
||||
"session_id": state.get("session_id", ""),
|
||||
"intent": state.get("intent", ""),
|
||||
"status": state.get("status", ""),
|
||||
"has_jrxml": bool(state.get("current_jrxml", "").strip()),
|
||||
"retry_count": state.get("retry_count", 0),
|
||||
},
|
||||
)
|
||||
return target
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
# ============================================================
|
||||
# 路由函数
|
||||
# ============================================================
|
||||
|
||||
@_log_route("route_by_intent")
|
||||
def route_by_intent(state: AgentState) -> Literal[
|
||||
"retrieve", "modify_jrxml", "save_session",
|
||||
"handle_consult", "handle_undo", "handle_reset"
|
||||
@@ -59,18 +87,22 @@ def route_by_intent(state: AgentState) -> Literal[
|
||||
return "retrieve"
|
||||
|
||||
|
||||
@_log_route("route_after_generate")
|
||||
def route_after_generate(state: AgentState) -> Literal["save_session"]:
|
||||
return "save_session"
|
||||
|
||||
|
||||
@_log_route("route_after_modify")
|
||||
def route_after_modify(state: AgentState) -> Literal["save_session"]:
|
||||
return "save_session"
|
||||
|
||||
|
||||
@_log_route("route_after_undo")
|
||||
def route_after_undo(state: AgentState) -> Literal["save_session"]:
|
||||
return "save_session"
|
||||
|
||||
|
||||
@_log_route("route_after_save")
|
||||
def route_after_save(state: AgentState) -> Literal["validate", "finalize"]:
|
||||
# 预览/导出意图跳过验证,直接完成
|
||||
intent = state.get("intent", "")
|
||||
@@ -79,16 +111,19 @@ def route_after_save(state: AgentState) -> Literal["validate", "finalize"]:
|
||||
return "validate"
|
||||
|
||||
|
||||
@_log_route("route_after_validate")
|
||||
def route_after_validate(state: AgentState) -> Literal["finalize", "explain_error"]:
|
||||
if state.get("status") == "pass":
|
||||
return "finalize"
|
||||
return "explain_error"
|
||||
|
||||
|
||||
@_log_route("route_after_explain")
|
||||
def route_after_explain(state: AgentState) -> Literal["correct_jrxml"]:
|
||||
return "correct_jrxml"
|
||||
|
||||
|
||||
@_log_route("route_after_correct")
|
||||
def route_after_correct(state: AgentState) -> Literal["validate", "finalize"]:
|
||||
retry = state.get("retry_count", 0)
|
||||
if retry >= MAX_RETRY:
|
||||
|
||||
Reference in New Issue
Block a user