代码修改
This commit is contained in:
1 parent
79d87ad661
commit
3eae4a0f45
3 files changed
+84
-4
No files matched your search
+9
-1
@@ -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,
|
||||
)
|
||||
|
||||
+3
-3
@@ -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`:见下方可选类型;不确定就留空。
|
||||
|
||||
+72
@@ -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)
|
||||
Reference in new issue
Block a user