样式修改
This commit is contained in:
1 parent
ca13a9199f
commit
065bd8f28a
2 files changed
+112
-38
No files matched your search
+62
-29
@@ -19,8 +19,8 @@ from ._utils import llm_json, safe_get_stream_writer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 素材总量上限边界:config.yaml 的 ai_writing.max_materials,非法值回退默认 20
|
||||
_DEFAULT_MAX_MATERIALS = 20
|
||||
# 素材总量上限边界:config.yaml 的 ai_writing.max_materials,非法值回退默认 50
|
||||
_DEFAULT_MAX_MATERIALS = 50
|
||||
_MIN_MAX_MATERIALS = 1
|
||||
_MAX_MAX_MATERIALS = 100
|
||||
|
||||
@@ -93,12 +93,18 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
|
||||
article_type = state.get("article_type", "analysis")
|
||||
target_audience = state.get("target_audience", "普通读者")
|
||||
|
||||
# 检查是否是补充搜索(PAUSE-1 re_search action)
|
||||
# 检查干预模式(PAUSE-1 素材确认 / 素材不足求助)
|
||||
intervention = state.get("last_user_intervention") or {}
|
||||
extra_keywords: list[str] = intervention.get("_extra_keywords") or intervention.get("extra_keywords") or []
|
||||
action = intervention.get("action")
|
||||
|
||||
# 素材不足求助点触发的「补充检索」:保留原大纲,检索完直接回写作、不走素材确认/大纲
|
||||
is_supplement = intervention.get("action") == "supplement_search"
|
||||
is_supplement = action == "supplement_search"
|
||||
# PAUSE-1 素材确认卡用户点「追加检索」并填了新关键词:
|
||||
# - 跳过 LLM 重新生成检索词(节省一次调用 + 尊重用户意图)
|
||||
# - 只检索 extra_keywords 这几个新词,不重检索之前 LLM 出过的词
|
||||
# - 保留 existing material_package,按 URL 去重合并
|
||||
is_append_only = action == "re_search" and bool(extra_keywords)
|
||||
|
||||
# 用户指定的检索关键词数量(1~10),决定生成多少个检索词、检索多少个方向
|
||||
keyword_count = _resolve_keyword_count(state.get("keyword_count"))
|
||||
@@ -119,32 +125,43 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
|
||||
writer({"type": "research_progress", "message": message})
|
||||
|
||||
# Step 1: 提取关键词
|
||||
_emit("正在生成检索词…")
|
||||
kw_result = await llm_json(
|
||||
EXTRACT_KEYWORDS_SYSTEM,
|
||||
EXTRACT_KEYWORDS_USER.format(
|
||||
user_intent=intent,
|
||||
article_type=article_type,
|
||||
target_audience=target_audience,
|
||||
keyword_count=keyword_count,
|
||||
),
|
||||
fallback={"keywords": [intent]},
|
||||
config=config,
|
||||
model_name=keyword_model,
|
||||
)
|
||||
# 清洗关键词:剔除占位符 / 空值,全空时回退写作意图
|
||||
keywords: list[str] = _clean_keywords(kw_result.get("keywords"), intent)
|
||||
if extra_keywords:
|
||||
keywords = list(dict.fromkeys(keywords + extra_keywords))
|
||||
kw_result: dict = {} # 走追加分支时跳过 LLM 调用,但下方 notice 拼接需要兜底值
|
||||
if is_append_only:
|
||||
# 追加模式:直接用用户填的关键词,不再调 LLM
|
||||
keywords: list[str] = _clean_keywords(extra_keywords, intent)
|
||||
_emit(f"追加检索 {len(keywords)} 个关键词…")
|
||||
else:
|
||||
_emit("正在生成检索词…")
|
||||
kw_result = await llm_json(
|
||||
EXTRACT_KEYWORDS_SYSTEM,
|
||||
EXTRACT_KEYWORDS_USER.format(
|
||||
user_intent=intent,
|
||||
article_type=article_type,
|
||||
target_audience=target_audience,
|
||||
keyword_count=keyword_count,
|
||||
),
|
||||
fallback={"keywords": [intent]},
|
||||
config=config,
|
||||
model_name=keyword_model,
|
||||
)
|
||||
# 清洗关键词:剔除占位符 / 空值,全空时回退写作意图
|
||||
keywords = _clean_keywords(kw_result.get("keywords"), intent)
|
||||
if extra_keywords:
|
||||
keywords = list(dict.fromkeys(keywords + extra_keywords))
|
||||
|
||||
# Step 2: 并发搜索
|
||||
provider = get_search_provider(ai_writing_config)
|
||||
|
||||
# 按用户指定的关键词数量截断;补充搜索时不截断用户额外添加的关键词
|
||||
search_limit = keyword_count
|
||||
if extra_keywords:
|
||||
search_limit = max(search_limit, len(keywords))
|
||||
search_keywords = keywords[:search_limit]
|
||||
# 按用户指定的关键词数量截断。
|
||||
# 追加模式:keywords 本身就是用户填的,全部检索不截断(用户填 N 个就搜 N 个)。
|
||||
# 其他模式:受 keyword_count 限制,但 extra_keywords 在内时上限放宽到 keywords 总数。
|
||||
if is_append_only:
|
||||
search_keywords = keywords
|
||||
else:
|
||||
search_limit = keyword_count
|
||||
if extra_keywords:
|
||||
search_limit = max(search_limit, len(keywords))
|
||||
search_keywords = keywords[:search_limit]
|
||||
total = len(search_keywords)
|
||||
# 每个检索词分到的检索条数 = 总量上限 / 检索词数(向上取整)
|
||||
per_keyword = _per_keyword_limit(max_materials, total)
|
||||
@@ -168,10 +185,14 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
|
||||
all_results_nested: list[list[SearchResult]] = await asyncio.gather(*search_tasks, return_exceptions=True)
|
||||
|
||||
# 合并去重
|
||||
# - 首次检索 / 普通 re_search(不带 extra_keywords,用户只想 LLM 重出):旧素材丢弃
|
||||
# - 素材不足求助 supplement_search:保留旧素材 + 追加新检索结果
|
||||
# - PAUSE-1 追加检索 is_append_only:保留旧素材 + 仅检索新关键词
|
||||
seen_urls: set[str] = set()
|
||||
raw_materials: list[Material] = []
|
||||
existing_pkg = state.get("material_package")
|
||||
if existing_pkg and intervention.get("action") != "re_search":
|
||||
preserve_existing = existing_pkg and (is_supplement or is_append_only)
|
||||
if preserve_existing:
|
||||
for m in existing_pkg.get("materials", []):
|
||||
seen_urls.add(m.get("url", ""))
|
||||
raw_materials.append(m)
|
||||
@@ -235,7 +256,13 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
|
||||
if not materials:
|
||||
summary = "未检索到相关素材,可重新搜索或在无素材的情况下继续写作"
|
||||
|
||||
pkg = MaterialPackage(keywords=keywords, materials=materials, summary=summary)
|
||||
# 追加模式下,pkg.keywords 体现到目前为止累积的检索词(旧 + 新追加),
|
||||
# 让前端列表 / 历史回显能看到完整的搜索路径。
|
||||
pkg_keywords = keywords
|
||||
if is_append_only and existing_pkg:
|
||||
old_kws = list(existing_pkg.get("keywords") or [])
|
||||
pkg_keywords = list(dict.fromkeys(old_kws + keywords))
|
||||
pkg = MaterialPackage(keywords=pkg_keywords, materials=materials, summary=summary)
|
||||
|
||||
# 容错告警:检索接口 / 模型调用出错时以非致命 notice 提示用户,不打断写作流程
|
||||
notices: list[dict] = []
|
||||
@@ -253,12 +280,18 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
|
||||
raw="\n\n----------\n\n".join(raw_dumps[:3]),
|
||||
))
|
||||
|
||||
# 进度事件文案:追加模式下让用户看到只搜了哪几个新词
|
||||
step_start_msg = (
|
||||
f"追加检索关键词:{', '.join(keywords[:3])}"
|
||||
if is_append_only
|
||||
else f"搜索关键词:{', '.join(keywords[:3])}"
|
||||
)
|
||||
return {
|
||||
"material_package": pkg,
|
||||
# 补充检索:直接回写作(沿用原大纲);常规检索:进入素材确认暂停点
|
||||
"status": "writing_draft" if is_supplement else "awaiting_material_confirm",
|
||||
"progress_events": [
|
||||
{"type": "step_start", "agent_name": "素材收集专家", "message": f"搜索关键词:{', '.join(keywords[:3])}"},
|
||||
{"type": "step_start", "agent_name": "素材收集专家", "message": step_start_msg},
|
||||
*notices,
|
||||
{"type": "materials_ready", "agent_name": "素材收集专家", "message": summary},
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user