refactor: 架构优化 - 移除重复代码并统一工具类模式
重大架构改进: 1. 移除重复的TocGeneratorAgent实现(585行),保留模块化的TocAgent 2. 修复LLMService模块级强制初始化问题,采用标准单例模式 3. 统一所有工具类的使用模式,提高架构一致性 具体更改: - 删除 src/bidmaster/agents/toc_generator.py(完全重复实现) - 移除 llm.py 中的模块级实例化(llm_service = LLMService()) - 更新 tools/__init__.py 导出LLMService类而非实例 - 更新使用方改为LLMService()调用(generate_sub_chapters.py, review_structure.py) - 清理agents/__init__.py和analysis.py中的旧版本引用 收益: - 减少约600行重复代码 - 解决模块导入时的配置加载错误 - 实现惰性加载,配置只在使用时加载 - 提高代码可维护性和架构一致性 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
c74ae0b418
commit
fb3e704bef
@ -1,14 +1,12 @@
|
||||
"""Agent层 - LangGraph编排"""
|
||||
|
||||
from .analysis import AnalysisAgent
|
||||
from .toc_generator import TocGeneratorAgent
|
||||
from .builders import TocAgentBuilder
|
||||
from .builders.toc_builder import TocAgent
|
||||
from .interaction import InteractionHandler, InteractionMode
|
||||
|
||||
__all__ = [
|
||||
"AnalysisAgent",
|
||||
"TocGeneratorAgent",
|
||||
"TocAgentBuilder",
|
||||
"TocAgent",
|
||||
"InteractionHandler",
|
||||
|
||||
@ -254,8 +254,8 @@ def parse_content_node(state: AnalysisAgentState) -> AnalysisAgentState:
|
||||
|
||||
|
||||
def generate_toc_with_agent_node(state: AnalysisAgentState) -> AnalysisAgentState:
|
||||
"""节点5:使用TocGeneratorAgent生成目录结构"""
|
||||
logger.info("开始使用TocGeneratorAgent生成目录...")
|
||||
"""节点5:使用TocAgent生成目录结构"""
|
||||
logger.info("开始使用TocAgent生成目录...")
|
||||
|
||||
try:
|
||||
technical_criteria = state["technical_criteria"]
|
||||
@ -306,7 +306,7 @@ def generate_toc_with_agent_node(state: AnalysisAgentState) -> AnalysisAgentStat
|
||||
# 更新状态
|
||||
state["preliminary_chapters"] = chapters
|
||||
state["technical_criteria"] = technical_criteria
|
||||
state["structure_review"] = {} # TocGeneratorAgent已包含审查
|
||||
state["structure_review"] = {} # TocAgent已包含审查
|
||||
state["current_step"] = "generate_toc"
|
||||
state["progress"] = 0.85
|
||||
|
||||
@ -336,7 +336,7 @@ def finalize_structure_node(state: AnalysisAgentState) -> AnalysisAgentState:
|
||||
project_name=f"标书项目-{Path(state['source_file']).stem}",
|
||||
scoring_criteria=technical_criteria,
|
||||
deviation_items=state["deviation_items"],
|
||||
chapters=preliminary_chapters, # 使用TocGeneratorAgent生成的章节
|
||||
chapters=preliminary_chapters, # 使用TocAgent生成的章节
|
||||
scoring_file=state["source_file"]
|
||||
)
|
||||
|
||||
|
||||
@ -1,585 +0,0 @@
|
||||
"""目录生成Agent - 专门负责生成标书目录结构
|
||||
|
||||
基于LangGraph实现的目录生成Agent,负责:
|
||||
1. 根据评分项类别生成一级章节
|
||||
2. AI智能生成二三级子标题
|
||||
3. 目录结构合理性审查与优化
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
from typing import List, Dict, Any, TypedDict, Optional
|
||||
|
||||
from langgraph.graph import StateGraph, END
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from ..tools.parser import ScoringCriteria, DocumentChapter
|
||||
from ..tools.llm import llm_service
|
||||
from ..config import get_settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 统一的类别名称映射
|
||||
CATEGORY_NAMES = {
|
||||
"compliance": "合规响应",
|
||||
"technical_solution": "技术方案",
|
||||
"equipment_spec": "设备规格",
|
||||
"quality_safety": "质量安全",
|
||||
"after_sales": "售后服务",
|
||||
"implementation": "实施方案"
|
||||
}
|
||||
|
||||
|
||||
class TocGeneratorState(TypedDict):
|
||||
"""目录生成Agent的状态定义"""
|
||||
|
||||
# 输入参数
|
||||
technical_criteria: List[ScoringCriteria]
|
||||
generation_mode: str # "ai" 或 "template"
|
||||
template_file: Optional[str]
|
||||
|
||||
# 执行状态
|
||||
current_step: str
|
||||
should_continue: bool
|
||||
|
||||
# 中间数据
|
||||
category_groups: Dict[str, List[ScoringCriteria]] # 按类别分组的评分项
|
||||
preliminary_chapters: List[DocumentChapter] # 初步生成的章节
|
||||
structure_review: Dict[str, Any] # AI审查结果
|
||||
|
||||
# 最终输出
|
||||
final_chapters: List[DocumentChapter]
|
||||
|
||||
# 错误处理
|
||||
error: str
|
||||
warnings: List[str]
|
||||
|
||||
|
||||
class TocGeneratorResult(BaseModel):
|
||||
"""目录生成结果"""
|
||||
|
||||
success: bool = Field(description="是否执行成功")
|
||||
chapters: List[DocumentChapter] = Field(default_factory=list, description="生成的章节结构")
|
||||
error_message: Optional[str] = Field(default=None, description="错误信息")
|
||||
warnings: List[str] = Field(default_factory=list, description="警告信息")
|
||||
|
||||
|
||||
# ========== LangGraph节点函数 ==========
|
||||
|
||||
def group_criteria_node(state: TocGeneratorState) -> TocGeneratorState:
|
||||
"""节点1:按类别对评分项分组"""
|
||||
logger.info("开始对评分项按类别分组...")
|
||||
|
||||
try:
|
||||
technical_criteria = state["technical_criteria"]
|
||||
|
||||
if not technical_criteria:
|
||||
raise ValueError("缺少技术评分项")
|
||||
|
||||
# 按类别分组
|
||||
category_groups = {
|
||||
"technical_solution": [],
|
||||
"equipment_spec": [],
|
||||
"implementation": [],
|
||||
"quality_safety": [],
|
||||
"after_sales": [],
|
||||
"compliance": []
|
||||
}
|
||||
|
||||
for criteria in technical_criteria:
|
||||
category_key = criteria.category.value
|
||||
if category_key in category_groups:
|
||||
category_groups[category_key].append(criteria)
|
||||
else:
|
||||
category_groups["technical_solution"].append(criteria)
|
||||
|
||||
# 只保留有评分项的类别
|
||||
category_groups = {k: v for k, v in category_groups.items() if v}
|
||||
|
||||
logger.info(f"分组完成: {len(category_groups)}个类别")
|
||||
state["category_groups"] = category_groups
|
||||
state["current_step"] = "group_criteria"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"评分项分组失败: {e}")
|
||||
state["error"] = str(e)
|
||||
state["should_continue"] = False
|
||||
|
||||
return state
|
||||
|
||||
|
||||
def generate_first_level_node(state: TocGeneratorState) -> TocGeneratorState:
|
||||
"""节点2:生成一级章节"""
|
||||
logger.info("开始生成一级章节...")
|
||||
|
||||
try:
|
||||
category_groups = state["category_groups"]
|
||||
technical_criteria = state["technical_criteria"]
|
||||
|
||||
chapters = []
|
||||
chapter_index = 1
|
||||
|
||||
# 按原始顺序确定章节顺序
|
||||
def get_category_first_index(category):
|
||||
for i, criteria in enumerate(technical_criteria):
|
||||
if criteria.category.value == category:
|
||||
return i
|
||||
return 999
|
||||
|
||||
sorted_categories = sorted(category_groups.keys(), key=get_category_first_index)
|
||||
|
||||
# 为每个类别创建一级章节
|
||||
for category in sorted_categories:
|
||||
criteria_list = category_groups[category]
|
||||
if not criteria_list:
|
||||
continue
|
||||
|
||||
total_score = sum(c.max_score for c in criteria_list)
|
||||
chapter_id = f"chapter_{chapter_index:02d}_{category}"
|
||||
category_name = CATEGORY_NAMES.get(category, category)
|
||||
chapter_title = category_name
|
||||
|
||||
if total_score > 0:
|
||||
chapter_title += f" ({total_score}分)"
|
||||
|
||||
chapter = DocumentChapter(
|
||||
id=chapter_id,
|
||||
title=chapter_title,
|
||||
level=1,
|
||||
score=total_score,
|
||||
template_placeholder=f"{{{{{chapter_id}_content}}}}"
|
||||
)
|
||||
|
||||
chapters.append(chapter)
|
||||
chapter_index += 1
|
||||
|
||||
logger.info(f"生成{len(chapters)}个一级章节")
|
||||
state["preliminary_chapters"] = chapters
|
||||
state["current_step"] = "generate_first_level"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"一级章节生成失败: {e}")
|
||||
state["error"] = str(e)
|
||||
state["should_continue"] = False
|
||||
|
||||
return state
|
||||
|
||||
|
||||
def generate_sub_chapters_node(state: TocGeneratorState) -> TocGeneratorState:
|
||||
"""节点3:生成二三级子标题"""
|
||||
logger.info("开始生成子标题...")
|
||||
|
||||
try:
|
||||
preliminary_chapters = state["preliminary_chapters"]
|
||||
technical_criteria = state["technical_criteria"]
|
||||
generation_mode = state.get("generation_mode", "ai")
|
||||
template_file = state.get("template_file")
|
||||
|
||||
enhanced_chapters = []
|
||||
|
||||
for chapter in preliminary_chapters:
|
||||
# 找到该章节对应的评分项
|
||||
# 从章节ID提取类别
|
||||
if "_" in chapter.id:
|
||||
parts = chapter.id.split("_")
|
||||
if len(parts) >= 3:
|
||||
category = "_".join(parts[2:])
|
||||
|
||||
# 找到该类别的所有评分项
|
||||
corresponding_criteria = [
|
||||
c for c in technical_criteria
|
||||
if c.category.value == category
|
||||
]
|
||||
|
||||
if corresponding_criteria:
|
||||
if generation_mode == "ai":
|
||||
sub_chapters = _generate_ai_sub_chapters(corresponding_criteria, chapter)
|
||||
else:
|
||||
sub_chapters = _generate_template_sub_chapters(
|
||||
corresponding_criteria[0], chapter, template_file
|
||||
)
|
||||
|
||||
chapter.children = sub_chapters
|
||||
logger.info(f"章节 {chapter.title} 生成了 {len(sub_chapters)} 个子标题")
|
||||
|
||||
enhanced_chapters.append(chapter)
|
||||
|
||||
state["preliminary_chapters"] = enhanced_chapters
|
||||
state["current_step"] = "generate_sub_chapters"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"子标题生成失败: {e}")
|
||||
state["error"] = str(e)
|
||||
state["should_continue"] = False
|
||||
|
||||
return state
|
||||
|
||||
|
||||
def review_structure_node(state: TocGeneratorState) -> TocGeneratorState:
|
||||
"""节点4:AI审查目录结构"""
|
||||
logger.info("开始AI审查目录结构...")
|
||||
|
||||
try:
|
||||
technical_criteria = state["technical_criteria"]
|
||||
preliminary_chapters = state["preliminary_chapters"]
|
||||
|
||||
# 构建审查提示词
|
||||
criteria_summary = _format_criteria_for_review(technical_criteria)
|
||||
chapters_summary = _format_chapters_for_review(preliminary_chapters)
|
||||
|
||||
review_prompt = f"""
|
||||
请审查这个标书目录结构的合理性和完整性。
|
||||
|
||||
【技术评分项分布】:
|
||||
{criteria_summary}
|
||||
|
||||
【当前生成的章节结构】:
|
||||
{chapters_summary}
|
||||
|
||||
【审查要求】:
|
||||
1. 是否缺少重要的标准章节?
|
||||
2. 章节顺序是否合理?
|
||||
3. 每个评分项是否都有对应章节?
|
||||
|
||||
返回JSON格式:
|
||||
{{
|
||||
"overall_assessment": "总体评价",
|
||||
"suggestions": [
|
||||
{{"type": "add/modify/reorder", "description": "建议内容", "priority": "high/medium/low"}}
|
||||
],
|
||||
"optimization_score": 85
|
||||
}}
|
||||
|
||||
只返回JSON:"""
|
||||
|
||||
# 使用统一的LLM服务
|
||||
response = llm_service.call(review_prompt)
|
||||
|
||||
if response:
|
||||
try:
|
||||
clean_response = response.strip()
|
||||
if clean_response.startswith("```json"):
|
||||
clean_response = clean_response[7:]
|
||||
if clean_response.endswith("```"):
|
||||
clean_response = clean_response[:-3]
|
||||
review_result = json.loads(clean_response.strip())
|
||||
except json.JSONDecodeError:
|
||||
review_result = {"overall_assessment": "解析失败", "suggestions": []}
|
||||
else:
|
||||
review_result = {"overall_assessment": "AI审查失败", "suggestions": []}
|
||||
|
||||
state["structure_review"] = review_result
|
||||
state["current_step"] = "review_structure"
|
||||
|
||||
# 根据审查结果添加警告
|
||||
if review_result.get("suggestions"):
|
||||
state["warnings"].append(f"AI审查: {len(review_result['suggestions'])}条优化建议")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"AI审查失败: {e}")
|
||||
state["warnings"].append(f"AI审查跳过: {str(e)}")
|
||||
state["structure_review"] = {}
|
||||
|
||||
return state
|
||||
|
||||
|
||||
def finalize_chapters_node(state: TocGeneratorState) -> TocGeneratorState:
|
||||
"""节点5:最终确定章节结构"""
|
||||
logger.info("最终确定章节结构...")
|
||||
|
||||
try:
|
||||
preliminary_chapters = state["preliminary_chapters"]
|
||||
structure_review = state.get("structure_review", {})
|
||||
|
||||
final_chapters = preliminary_chapters # 直接使用,不做防护编程
|
||||
|
||||
# 应用高优先级建议
|
||||
suggestions = structure_review.get("suggestions", [])
|
||||
for suggestion in suggestions:
|
||||
if suggestion.get("priority") == "high":
|
||||
# 这里可以根据建议类型进行调整
|
||||
logger.info(f"应用高优先级建议: {suggestion.get('description')}")
|
||||
|
||||
# 确保评标索引表存在(作为第一章)
|
||||
has_index = any("评标索引" in ch.title for ch in final_chapters)
|
||||
if not has_index:
|
||||
index_chapter = DocumentChapter(
|
||||
id="evaluation_index",
|
||||
title="评标索引表(技术评分完全对应)", # 不包含编号
|
||||
level=1,
|
||||
template_placeholder="{{evaluation_index_content}}"
|
||||
)
|
||||
final_chapters.insert(0, index_chapter)
|
||||
|
||||
state["final_chapters"] = final_chapters
|
||||
state["current_step"] = "finalize"
|
||||
state["should_continue"] = False
|
||||
|
||||
logger.info(f"最终生成{len(final_chapters)}个章节")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"章节最终确定失败: {e}")
|
||||
state["error"] = str(e)
|
||||
state["should_continue"] = False
|
||||
|
||||
return state
|
||||
|
||||
|
||||
# ========== 辅助函数 ==========
|
||||
|
||||
def _generate_ai_sub_chapters(criteria_list: List[ScoringCriteria],
|
||||
parent_chapter: DocumentChapter) -> List[DocumentChapter]:
|
||||
"""AI生成子标题"""
|
||||
try:
|
||||
criteria_info = []
|
||||
for criteria in criteria_list:
|
||||
criteria_info.append(f"- {criteria.item_name} ({criteria.max_score}分)")
|
||||
|
||||
prompt = f"""
|
||||
为以下大类别生成专业的标书子标题:
|
||||
|
||||
【大类别】: {parent_chapter.title}
|
||||
【评分项】:
|
||||
{chr(10).join(criteria_info)}
|
||||
|
||||
生成要求:
|
||||
1. 为每个评分项生成对应的子标题名称(不要包含编号)
|
||||
2. 重要评分项可添加三级子标题(不要包含编号)
|
||||
3. 只返回标题文本,编号由Word自动管理
|
||||
|
||||
返回JSON格式:
|
||||
{{
|
||||
"sub_chapters": [
|
||||
{{"title": "技术架构设计", "level": 2, "score": 5, "children": []}}
|
||||
]
|
||||
}}
|
||||
|
||||
只返回JSON:"""
|
||||
|
||||
# 使用统一的LLM服务
|
||||
response = llm_service.call(prompt)
|
||||
if not response:
|
||||
raise ValueError("AI生成子标题失败: API无响应")
|
||||
|
||||
try:
|
||||
clean_response = response.strip()
|
||||
if clean_response.startswith("```json"):
|
||||
clean_response = clean_response[7:]
|
||||
if clean_response.endswith("```"):
|
||||
clean_response = clean_response[:-3]
|
||||
|
||||
result_data = json.loads(clean_response.strip())
|
||||
sub_chapters_data = result_data.get("sub_chapters", [])
|
||||
|
||||
sub_chapters = []
|
||||
|
||||
for i, sub_data in enumerate(sub_chapters_data, 1):
|
||||
# 直接使用标题文本,不添加编号
|
||||
title = sub_data.get("title", f"子标题{i}")
|
||||
|
||||
sub_chapter = DocumentChapter(
|
||||
id=f"{parent_chapter.id}_sub_{i:02d}",
|
||||
title=title, # 不添加编号
|
||||
level=sub_data.get("level", 2),
|
||||
score=sub_data.get("score", 0),
|
||||
template_placeholder=f"{{{{{parent_chapter.id}_sub_{i:02d}_content}}}}"
|
||||
)
|
||||
|
||||
# 处理三级标题
|
||||
for j, child_data in enumerate(sub_data.get("children", []), 1):
|
||||
child_title = child_data.get("title", f"三级标题{j}")
|
||||
|
||||
child_chapter = DocumentChapter(
|
||||
id=f"{parent_chapter.id}_sub_{i:02d}_{j:02d}",
|
||||
title=child_title, # 不添加编号
|
||||
level=child_data.get("level", 3),
|
||||
template_placeholder=f"{{{{{parent_chapter.id}_sub_{i:02d}_{j:02d}_content}}}}"
|
||||
)
|
||||
sub_chapter.children.append(child_chapter)
|
||||
|
||||
sub_chapters.append(sub_chapter)
|
||||
|
||||
return sub_chapters
|
||||
|
||||
except (json.JSONDecodeError, KeyError) as e:
|
||||
logger.error(f"解析AI响应失败: {e}")
|
||||
raise ValueError(f"解析AI响应失败: {e}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"AI生成子标题失败: {e}")
|
||||
raise # 立即失败,不掩盖错误
|
||||
|
||||
|
||||
def _generate_template_sub_chapters(criteria: ScoringCriteria,
|
||||
parent_chapter: DocumentChapter,
|
||||
template_file: Optional[str]) -> List[DocumentChapter]:
|
||||
"""基于模板生成子标题"""
|
||||
# 提供默认结构(不包含编号)
|
||||
default_sub_chapters = [
|
||||
DocumentChapter(
|
||||
id=f"{parent_chapter.id}_def_01",
|
||||
title="方案概述", # 不包含编号
|
||||
level=2,
|
||||
template_placeholder=f"{{{{{parent_chapter.id}_def_01_content}}}}"
|
||||
),
|
||||
DocumentChapter(
|
||||
id=f"{parent_chapter.id}_def_02",
|
||||
title="具体实施", # 不包含编号
|
||||
level=2,
|
||||
template_placeholder=f"{{{{{parent_chapter.id}_def_02_content}}}}"
|
||||
),
|
||||
DocumentChapter(
|
||||
id=f"{parent_chapter.id}_def_03",
|
||||
title="保障措施", # 不包含编号
|
||||
level=2,
|
||||
template_placeholder=f"{{{{{parent_chapter.id}_def_03_content}}}}"
|
||||
)
|
||||
]
|
||||
|
||||
return default_sub_chapters
|
||||
|
||||
|
||||
def _format_criteria_for_review(technical_criteria: List[ScoringCriteria]) -> str:
|
||||
"""格式化评分项用于审查"""
|
||||
lines = []
|
||||
|
||||
category_groups = {}
|
||||
for criteria in technical_criteria:
|
||||
category = criteria.category.value
|
||||
if category not in category_groups:
|
||||
category_groups[category] = []
|
||||
category_groups[category].append(criteria)
|
||||
|
||||
for category, items in category_groups.items():
|
||||
category_name = CATEGORY_NAMES.get(category, category)
|
||||
lines.append(f"【{category_name}】({len(items)}项):")
|
||||
for item in items:
|
||||
lines.append(f" - {item.item_name} ({item.max_score}分)")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _format_chapters_for_review(chapters: List[DocumentChapter]) -> str:
|
||||
"""格式化章节用于审查"""
|
||||
lines = []
|
||||
for chapter in chapters:
|
||||
lines.append(chapter.title)
|
||||
for sub in chapter.children:
|
||||
lines.append(f" {sub.title}")
|
||||
for child in sub.children:
|
||||
lines.append(f" {child.title}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
# ========== 条件判断 ==========
|
||||
|
||||
def should_continue(state: TocGeneratorState) -> str:
|
||||
"""判断是否继续"""
|
||||
if not state.get("should_continue", True) or state.get("error"):
|
||||
return "end"
|
||||
return "continue"
|
||||
|
||||
|
||||
class TocGeneratorAgent:
|
||||
"""目录生成Agent"""
|
||||
|
||||
def __init__(self):
|
||||
self.settings = get_settings()
|
||||
self.graph = self._build_graph()
|
||||
|
||||
def _build_graph(self) -> StateGraph:
|
||||
"""构建工作流"""
|
||||
workflow = StateGraph(TocGeneratorState)
|
||||
|
||||
# 添加节点
|
||||
workflow.add_node("group_criteria", group_criteria_node)
|
||||
workflow.add_node("generate_first_level", generate_first_level_node)
|
||||
workflow.add_node("generate_sub_chapters", generate_sub_chapters_node)
|
||||
workflow.add_node("review_structure", review_structure_node)
|
||||
workflow.add_node("finalize_chapters", finalize_chapters_node)
|
||||
|
||||
# 设置入口
|
||||
workflow.set_entry_point("group_criteria")
|
||||
|
||||
# 添加边
|
||||
workflow.add_conditional_edges(
|
||||
"group_criteria",
|
||||
should_continue,
|
||||
{"continue": "generate_first_level", "end": END}
|
||||
)
|
||||
|
||||
workflow.add_conditional_edges(
|
||||
"generate_first_level",
|
||||
should_continue,
|
||||
{"continue": "generate_sub_chapters", "end": END}
|
||||
)
|
||||
|
||||
workflow.add_conditional_edges(
|
||||
"generate_sub_chapters",
|
||||
should_continue,
|
||||
{"continue": "review_structure", "end": END}
|
||||
)
|
||||
|
||||
workflow.add_conditional_edges(
|
||||
"review_structure",
|
||||
should_continue,
|
||||
{"continue": "finalize_chapters", "end": END}
|
||||
)
|
||||
|
||||
workflow.add_edge("finalize_chapters", END)
|
||||
|
||||
return workflow.compile()
|
||||
|
||||
async def generate(self,
|
||||
technical_criteria: List[ScoringCriteria],
|
||||
generation_mode: str = "ai",
|
||||
template_file: Optional[str] = None) -> TocGeneratorResult:
|
||||
"""生成目录结构"""
|
||||
logger.info("开始执行TocGeneratorAgent")
|
||||
|
||||
# 初始化状态
|
||||
initial_state = TocGeneratorState(
|
||||
technical_criteria=technical_criteria,
|
||||
generation_mode=generation_mode,
|
||||
template_file=template_file,
|
||||
current_step="",
|
||||
should_continue=True,
|
||||
category_groups={},
|
||||
preliminary_chapters=[],
|
||||
structure_review={},
|
||||
final_chapters=[],
|
||||
error="",
|
||||
warnings=[]
|
||||
)
|
||||
|
||||
try:
|
||||
# 执行工作流
|
||||
final_state = await self.graph.ainvoke(initial_state)
|
||||
|
||||
if final_state.get("error"):
|
||||
return TocGeneratorResult(
|
||||
success=False,
|
||||
error_message=final_state["error"],
|
||||
warnings=final_state.get("warnings", [])
|
||||
)
|
||||
|
||||
return TocGeneratorResult(
|
||||
success=True,
|
||||
chapters=final_state["final_chapters"],
|
||||
warnings=final_state.get("warnings", [])
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"TocGeneratorAgent执行异常: {e}")
|
||||
return TocGeneratorResult(
|
||||
success=False,
|
||||
error_message=str(e)
|
||||
)
|
||||
|
||||
def generate_sync(self,
|
||||
technical_criteria: List[ScoringCriteria],
|
||||
generation_mode: str = "ai",
|
||||
template_file: Optional[str] = None) -> TocGeneratorResult:
|
||||
"""同步接口"""
|
||||
return asyncio.run(self.generate(technical_criteria, generation_mode, template_file))
|
||||
@ -9,7 +9,7 @@ from typing import Dict, List, Any, Optional
|
||||
|
||||
from ..base import BaseNode, NodeContext
|
||||
from ...tools.parser import ScoringCriteria, DocumentChapter
|
||||
from ...tools.llm import llm_service
|
||||
from ...tools.llm import LLMService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -168,7 +168,7 @@ class GenerateSubChaptersNode(BaseNode):
|
||||
只返回JSON:"""
|
||||
|
||||
# 使用统一的LLM服务
|
||||
response = llm_service.call(prompt)
|
||||
response = LLMService().call(prompt)
|
||||
if not response:
|
||||
raise ValueError("AI生成子标题失败: API无响应")
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ from typing import Dict, List, Any
|
||||
|
||||
from ..base import BaseNode, NodeContext
|
||||
from ...tools.parser import ScoringCriteria, DocumentChapter
|
||||
from ...tools.llm import llm_service
|
||||
from ...tools.llm import LLMService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -114,7 +114,7 @@ class ReviewStructureNode(BaseNode):
|
||||
|
||||
try:
|
||||
# 使用统一的LLM服务
|
||||
response = llm_service.call(review_prompt)
|
||||
response = LLMService().call(review_prompt)
|
||||
|
||||
if response:
|
||||
return self._parse_review_response(response)
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
"""工具层 - 原子化工具集"""
|
||||
|
||||
from .llm import llm_service
|
||||
from .llm import LLMService
|
||||
from .parser import BidParser
|
||||
from .rag import RAGTool
|
||||
from .table import TableGenerator
|
||||
from .word import WordProcessor
|
||||
|
||||
__all__ = [
|
||||
"llm_service",
|
||||
"LLMService",
|
||||
"BidParser",
|
||||
"RAGTool",
|
||||
"TableGenerator",
|
||||
|
||||
@ -65,5 +65,4 @@ class LLMService:
|
||||
raise # 立即失败
|
||||
|
||||
|
||||
# 全局单例
|
||||
llm_service = LLMService()
|
||||
# 移除模块级实例化,使用标准单例模式:LLMService()
|
||||
Loading…
Reference in New Issue
Block a user