文档修改

This commit is contained in:
董宏凯 committed 2026-05-19 13:00:40 +08:00
1 parent b8adefbb88
commit 294d06f22b
9 files changed
+83 -3

No files matched your search

+14
View File
@@ -32,6 +32,20 @@ ai_writing:
---
## 1.5 检索关键词数量
素材专家的检索词数量由**用户在写作表单中指定**(「检索关键词数量」输入框,
范围 `1~10`,默认 `6`)。数量越多素材越全面,但检索与排序更耗时。
- 该参数随 `POST /api/ai-writing/start` 的 `keyword_count` 字段传入,写入 `AIWritingState.keyword_count`。
- `researcher_node` 用它决定让 LLM 生成多少个检索词、并发检索多少个方向
(`EXTRACT_KEYWORDS_USER` prompt 按该数量格式化,`search_keywords = keywords[:keyword_count]`)。
- 非法值(缺省 / 越界 / 非数字)由前后端双重兜底:后端 `_resolve_keyword_count()`
规整到 `[1, 10]`,越界回退默认 `6`。
- 补充搜索(`re_search`)时用户额外添加的关键词不会被该上限截断。
---
## 2. 内网接口规格
- **地址**:`http://10.106.57.180:7863/knowledge_base/search_docs_es`
@@ -21,6 +21,7 @@ export async function startWritingSession(req: AIWritingRequest): Promise<string
target_audience: req.targetAudience,
word_count_target: req.wordCountTarget,
model_name: req.modelName ?? '',
keyword_count: req.keywordCount,
}),
});
if (!resp.ok) throw new Error(`启动失败: ${resp.status}`);
@@ -36,6 +36,7 @@ export function AIWritingForm({ onSubmit, disabled }: AIWritingFormProps) {
const [articleType, setArticleType] = useState('analysis');
const [audience, setAudience] = useState('普通读者');
const [wordCountInput, setWordCountInput] = useState('800');
const [keywordCountInput, setKeywordCountInput] = useState('6');
const [modelName, setModelName] = useState('');
const [models, setModels] = useState<ModelOption[]>([]);
@@ -94,15 +95,27 @@ export function AIWritingForm({ onSubmit, disabled }: AIWritingFormProps) {
}
}
// 检索关键词数量限定 1~10,非法值回退默认 6
function handleKeywordCountBlur() {
const num = parseInt(keywordCountInput, 10);
if (isNaN(num)) {
setKeywordCountInput('6');
} else {
setKeywordCountInput(String(Math.max(1, Math.min(10, num))));
}
}
function handleSubmit(e: React.FormEvent) {
e.preventDefault();
if (!intent.trim()) return;
const wordCount = Math.max(100, parseInt(wordCountInput, 10) || 800);
const keywordCount = Math.max(1, Math.min(10, parseInt(keywordCountInput, 10) || 6));
onSubmit({
userIntent: intent.trim(),
articleType,
targetAudience: audience.trim() || '普通读者',
wordCountTarget: wordCount,
keywordCount,
modelName: modelName || undefined,
});
}
@@ -158,6 +171,25 @@ export function AIWritingForm({ onSubmit, disabled }: AIWritingFormProps) {
</div>
</div>
<div className="space-y-1.5">
<label className="text-xs font-medium text-muted-foreground">检索关键词数量(1~10)</label>
<input
type="number"
min={1}
max={10}
step={1}
className={INPUT_CLASS}
placeholder="6"
value={keywordCountInput}
onChange={(e) => setKeywordCountInput(e.target.value)}
onBlur={handleKeywordCountBlur}
disabled={disabled}
/>
<p className="text-[11px] text-muted-foreground/70">
素材收集专家用几个关键词检索,越多素材越全面但耗时更长。
</p>
</div>
<div className="space-y-1.5">
<label className="text-xs font-medium text-muted-foreground">目标读者</label>
<input
@@ -425,6 +425,9 @@ export function AIWritingPanel() {
<ReqRow label="目标字数">
<span className="text-muted-foreground">{state.request.wordCountTarget} 字</span>
</ReqRow>
<ReqRow label="检索关键词数量">
<span className="text-muted-foreground">{state.request.keywordCount} 个</span>
</ReqRow>
{state.request.modelName && (
<ReqRow label="写作模型">
<span className="text-muted-foreground">{state.request.modelName}</span>
@@ -135,6 +135,8 @@ export interface AIWritingRequest {
targetAudience: string;
wordCountTarget: number;
modelName?: string;
/** 素材检索关键词数量(1~10,默认 6) */
keywordCount: number;
}
// ── 流式审核条目 ──────────────────────────────────────────────────────────────
@@ -40,6 +40,8 @@ class StartWritingRequest(BaseModel):
target_audience: str = "普通读者"
word_count_target: int = 800
model_name: str = ""
# 素材检索关键词数量:用户指定用几个关键词检索(1~10,默认 6)
keyword_count: int = 6
class StartWritingResponse(BaseModel):
@@ -230,6 +232,8 @@ async def start_writing(body: StartWritingRequest, request: Request):
"article_type": body.article_type,
"target_audience": body.target_audience,
"word_count_target": body.word_count_target,
# 规整到 [1, 10],非法值回退默认 6
"keyword_count": max(1, min(10, body.keyword_count)),
"revision_count": 0,
"max_revisions": 3,
"status": "researching",
@@ -20,6 +20,19 @@ logger = logging.getLogger(__name__)
_MAX_MATERIALS = 12
# 素材检索关键词数量边界:用户可指定 1~10 个,非法值回退默认 6
_DEFAULT_KEYWORD_COUNT = 6
_MAX_KEYWORD_COUNT = 10
def _resolve_keyword_count(raw: object) -> int:
"""把用户传入的检索关键词数量规整到 [1, _MAX_KEYWORD_COUNT],非法值回退默认 6。"""
try:
n = int(raw) # type: ignore[arg-type]
except (TypeError, ValueError):
return _DEFAULT_KEYWORD_COUNT
return max(1, min(_MAX_KEYWORD_COUNT, n))
def _notice(title: str, detail: str, raw: str = "") -> dict:
"""构造一个非致命告警事件,前端在时间线显示「标题 + 真实原因」,不打断写作流程。
@@ -41,6 +54,9 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
intervention = state.get("last_user_intervention") or {}
extra_keywords: list[str] = intervention.get("_extra_keywords") or intervention.get("extra_keywords") or []
# 用户指定的检索关键词数量(1~10),决定生成多少个检索词、检索多少个方向
keyword_count = _resolve_keyword_count(state.get("keyword_count"))
# SSE 实时进度推送(与 outline/draft 节点共用 sse_queue 机制)
cfg = config.get("configurable", {})
sse_queue = cfg.get("sse_queue")
@@ -68,6 +84,7 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
user_intent=intent,
article_type=article_type,
target_audience=target_audience,
keyword_count=keyword_count,
),
fallback={"keywords": [intent]},
config=config,
@@ -80,7 +97,11 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
# Step 2: 并发搜索
provider = get_search_provider(ai_writing_config)
search_keywords = keywords[:6]
# 按用户指定的关键词数量截断;补充搜索时不截断用户额外添加的关键词
search_limit = keyword_count
if extra_keywords:
search_limit = max(search_limit, len(keywords))
search_keywords = keywords[:search_limit]
total = len(search_keywords)
await _emit(f"检索词已生成,开始检索 {total} 个方向…")
@@ -3,7 +3,7 @@ EXTRACT_KEYWORDS_SYSTEM = """你是一名专业情报研究员(素材收集专
你的工作背景:你在一家权威媒体机构任职,熟悉各类信息源的可信度评估。
你只能做以下事情:
1. 从写作意图中提取 3-6 个搜索关键词
1. 从写作意图中按要求的数量提取搜索关键词
你不能写文章,不能评价内容好坏,只做关键词提取。
【严禁思考】
@@ -25,7 +25,8 @@ EXTRACT_KEYWORDS_USER = """写作意图:{user_intent}
文章类型:{article_type}
目标读者:{target_audience}
请提取 3-6 个搜索关键词,用于搜集相关素材。只输出 JSON:
请提取 {keyword_count} 个搜索关键词,用于搜集相关素材。
关键词数量必须为 {keyword_count} 个,不多不少。只输出 JSON:
{{"keywords": ["关键词1", "关键词2"]}}"""
RANK_MATERIALS_SYSTEM = """你是一名专业情报研究员(素材收集专家)。
@@ -84,6 +84,8 @@ class AIWritingState(TypedDict):
article_type: str
target_audience: str
word_count_target: int
# 素材检索关键词数量(用户指定,1~10,默认 6)
keyword_count: int
# Agent A 输出
material_package: Optional[MaterialPackage]