代码修改

This commit is contained in:
fengxiangdebaozi committed 2026-06-03 16:34:17 +08:00
1 parent 79d87ad661
commit 3eae4a0f45
3 files changed
+84 -4

No files matched your search

@@ -26,6 +26,9 @@ from deerflow.models import create_chat_model
logger = logging.getLogger(__name__)
# 写作配置 Q&A:意图澄清最多几轮(一条用户消息 = 一轮),到顶强制提交配置卡。
WRITING_SETUP_MAX_ROUNDS = 3
def _get_runtime_config(config: RunnableConfig) -> dict:
"""Merge legacy configurable options with LangGraph runtime context."""
@@ -454,12 +457,17 @@ def _make_lead_agent(config: RunnableConfig, *, app_config: AppConfig):
# 写作配置 Q&A:最小化 agent —— **只挂 setup_writing 一个工具** + 一份职责单一的独立提示。
# 关键:绝不给全套工具、绝不复用 lead 超级体提示,否则模型会把「新能源汽车市场分析」之类
# 长得像任务的输入直接做掉,而不是转成写作配置提交。
# 末尾追加 WritingSetupRoundCapMiddleware:澄清最多 3 轮,到顶强制提交配置卡。
from deerflow.agents.lead_agent.prompt import build_writing_setup_prompt
from deerflow.agents.middlewares.writing_setup_round_cap_middleware import WritingSetupRoundCapMiddleware
return create_agent(
model=create_chat_model(name=model_name, thinking_enabled=thinking_enabled, app_config=resolved_app_config),
tools=[setup_writing],
middleware=_build_middlewares(config, model_name=model_name, app_config=resolved_app_config),
middleware=[
*_build_middlewares(config, model_name=model_name, app_config=resolved_app_config),
WritingSetupRoundCapMiddleware(max_rounds=WRITING_SETUP_MAX_ROUNDS),
],
system_prompt=build_writing_setup_prompt(writing_setup_article_types),
state_schema=ThreadState,
)
@@ -927,9 +927,9 @@ def build_writing_setup_prompt(article_types: list[dict] | None = None) -> str:
- 你能做的动作只有两个:① 用自然语言向用户提问或确认;② 调用 `setup_writing` 工具。**除此之外你没有任何其它工具**,也不要假装调用别的工具、不要做检索、不要做研究。
- 不要在回复里输出文章段落、要点清单或大纲(用户主动粘贴的大纲除外——原样放进 `outline` 参数)。
【工作流程】
1. 读用户输入。如果「写什么」已经明确,关键信息(文章类型、字数、读者)即使缺失也可以用合理默认补全——**信息基本够了就直接进入第 3 步,不要为了凑齐而反复追问**。
2. 只有当「写什么」本身都不清楚时,才用一句话问 1-2 个最关键的问题(最多一轮)。
【工作流程】(与用户交互确认,但最多 3 轮内必须提交)
1. 读用户输入,先用一两句话回应并和用户**确认写作意图**;就缺失或模糊的关键项(文章类型、目标字数、目标读者)提问澄清,一次最多问 1-2 个最关键的问题。
2. 与用户的澄清来回**最多 2 次**。一旦关键信息明确、或已经问过 2 次,就**立即进入第 3 步提交**,缺失字段用合理默认值,绝不无休止追问。
3. 调用 `setup_writing` 提交配置:
- `user_intent`:精炼成一句话的写作目标(必填)。
- `article_type`:见下方可选类型;不确定就留空。
@@ -0,0 +1,72 @@
"""写作配置 Q&A 的「轮数上限」中间件。
意图阶段允许与用户来回澄清确认,但**最多 N 轮后必须出结果**:到上限时,在模型请求里
注入强制指令 + 用 ``tool_choice`` 锁定 ``setup_writing``,逼模型立刻提交配置卡,不再提问。
「一轮」= 一条用户消息(HumanMessage)。达到 ``max_rounds`` 条用户消息时强制提交。
"""
from __future__ import annotations
from collections.abc import Awaitable, Callable
from typing import override
from langchain.agents import AgentState
from langchain.agents.middleware import AgentMiddleware
from langchain.agents.middleware.types import ModelCallResult, ModelRequest, ModelResponse
from langchain_core.messages import HumanMessage, SystemMessage
class WritingSetupRoundCapMiddleware(AgentMiddleware[AgentState]):
"""达到澄清轮数上限时,强制模型调用 ``setup_writing`` 提交。
软约束(注入 SystemMessage)+ 硬约束(``tool_choice`` 锁定工具)双保险:即使个别模型
无视提示,``tool_choice`` 也会逼它产出一次 ``setup_writing`` 调用。
"""
def __init__(self, max_rounds: int = 3, tool_name: str = "setup_writing") -> None:
super().__init__()
self._max_rounds = max(1, max_rounds)
self._tool_name = tool_name
def _should_force(self, messages: list) -> bool:
human_count = sum(1 for m in messages if isinstance(m, HumanMessage))
return human_count >= self._max_rounds
def _reminder(self) -> SystemMessage:
return SystemMessage(
content=(
f"【系统强制】意图澄清已达 {self._max_rounds} 轮上限。"
"现在必须立即调用 setup_writing 提交写作配置,禁止再向用户提任何问题。"
"缺失或不确定的字段一律用合理默认值:"
"word_count_target 默认 800、target_audience 默认「普通读者」、"
"writing_mode 默认 loose、material_source 默认 knowledge_base、"
"article_type 不确定就留空。"
)
)
def _patch(self, request: ModelRequest) -> ModelRequest:
return request.override(
messages=[*request.messages, self._reminder()],
tool_choice=self._tool_name,
)
@override
def wrap_model_call(
self,
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse],
) -> ModelCallResult:
if self._should_force(request.messages):
request = self._patch(request)
return handler(request)
@override
async def awrap_model_call(
self,
request: ModelRequest,
handler: Callable[[ModelRequest], Awaitable[ModelResponse]],
) -> ModelCallResult:
if self._should_force(request.messages):
request = self._patch(request)
return await handler(request)