文档配置文件修改
This commit is contained in:
1 parent
4fbd0bb5c5
commit
8edd06fb67
3 files changed
+78
-8
No files matched your search
@@ -460,8 +460,9 @@ checkpointer:
|
|||||||
type: sqlite # sqlite | postgres | memory
|
type: sqlite # sqlite | postgres | memory
|
||||||
connection_string: .deer-flow/data/checkpoints.db
|
connection_string: .deer-flow/data/checkpoints.db
|
||||||
|
|
||||||
# 清理调度
|
# AI 写作子系统
|
||||||
ai_writing:
|
ai_writing:
|
||||||
|
# ── 清理调度 ─────────────────────────────────────────────
|
||||||
cleanup:
|
cleanup:
|
||||||
enabled: true
|
enabled: true
|
||||||
retention_days: 7
|
retention_days: 7
|
||||||
@@ -469,13 +470,78 @@ ai_writing:
|
|||||||
delete_only_finished: false
|
delete_only_finished: false
|
||||||
batch_size: 500
|
batch_size: 500
|
||||||
|
|
||||||
# (可选)素材检索 provider 配置
|
# ── 素材收集专家(researcher)专用配置 ──────────────────
|
||||||
search:
|
# 这两个模型名必须出现在顶层 models[] 段里;留空 / 不配则回退当前写作主模型。
|
||||||
provider: deerflow.agents.ai_writing.search.internet_search:WebSearchProvider
|
# 拆出来是为了让「检索词生成 / 素材排序」这种结构化抽取任务可以走更轻量、
|
||||||
...
|
# 不带思考输出的小模型,省钱省时间,也避开写作主模型的思考干扰。
|
||||||
|
keyword_model: qwen3-4b-instruct # 检索词生成(EXTRACT_KEYWORDS_*)
|
||||||
|
rank_model: qwen3-4b-instruct # 素材排序筛选(RANK_MATERIALS_*)
|
||||||
|
|
||||||
|
# 素材总量上限:合并去重后保留多少条素材进入大纲 / 草稿阶段
|
||||||
|
# 取值范围 [1, 100],非法值或缺省回退 20。
|
||||||
|
# 每个检索词分到的检索条数 = ceil(max_materials / keyword_count),
|
||||||
|
# 所以这个数越大,每个关键词向 provider 拉的条数越多,整体耗时也越长。
|
||||||
|
max_materials: 20
|
||||||
|
|
||||||
|
# ── 素材检索 provider ───────────────────────────────────
|
||||||
|
# internet(默认,DuckDuckGo) / intranet(内网 ES) / tavily / demo
|
||||||
|
search_provider: internet
|
||||||
|
|
||||||
|
# internet 模式:DuckDuckGo 区域代码(cn-zh / us-en / wt-wt 等)
|
||||||
|
ddg_region: "cn-zh"
|
||||||
|
|
||||||
|
# intranet 模式:对接内网知识库 ES 检索接口
|
||||||
|
# 接口契约(POST):
|
||||||
|
# payload = {"query": "...", "knowledge_base_name": "<intranet_knowledge_base>", "ts": "yes"}
|
||||||
|
# response = [{"page_content": "...", "metadata": {m_title, content, recUuid, m_publish, source1}}]
|
||||||
|
# 实现见 packages/harness/deerflow/agents/ai_writing/search/intranet_stub.py
|
||||||
|
intranet_search_url: http://10.106.57.180:7863/knowledge_base/search_docs_es
|
||||||
|
intranet_knowledge_base: samples # 默认 samples,按部署的实际知识库名改
|
||||||
```
|
```
|
||||||
|
|
||||||
`_ai_writing_config()` 函数从 `get_app_config().ai_writing` 里读 dict,节点通过 `config.configurable.ai_writing_config` 拿到。
|
### 配置项与代码的对应关系
|
||||||
|
|
||||||
|
| 配置键 | 默认值 | 取值范围 / 说明 | 读取位置 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `ai_writing.keyword_model` | 空(回退写作主模型) | 必须是 `models[]` 段里已声明的模型名 | `nodes/researcher.py` → `llm_json(..., model_name=keyword_model)` |
|
||||||
|
| `ai_writing.rank_model` | 空(回退写作主模型) | 同上 | `nodes/researcher.py` → 排序分支 `llm_json(..., model_name=rank_model)` |
|
||||||
|
| `ai_writing.max_materials` | `20` | `[1, 100]`,非法值回退 20;`_resolve_max_materials` 钳制 | `nodes/researcher.py:_DEFAULT_MAX_MATERIALS` |
|
||||||
|
| `ai_writing.search_provider` | `"internet"` | `internet` / `intranet` / `tavily` / `demo` | `search/__init__.py:get_search_provider` |
|
||||||
|
| `ai_writing.ddg_region` | `"cn-zh"` | DuckDuckGo 区域代码,仅 `internet` 模式生效 | 同上 |
|
||||||
|
| `ai_writing.intranet_search_url` | `http://10.106.57.180:7863/knowledge_base/search_docs_es` | 仅 `intranet` 模式生效,POST JSON 接口 | `search/intranet_stub.py:_DEFAULT_ENDPOINT` |
|
||||||
|
| `ai_writing.intranet_knowledge_base` | `"samples"` | 仅 `intranet` 模式生效,知识库 ID/名称 | 同上 |
|
||||||
|
|
||||||
|
### 配置如何传到节点
|
||||||
|
|
||||||
|
```
|
||||||
|
config.yaml
|
||||||
|
└─ ai_writing: { ... }
|
||||||
|
│
|
||||||
|
▼ _ai_writing_config() 取出整个 dict
|
||||||
|
routers/ai_writing.py:_make_config()
|
||||||
|
│ 注入到 config.configurable.ai_writing_config
|
||||||
|
▼
|
||||||
|
nodes/researcher.py
|
||||||
|
cfg = config.get("configurable", {})
|
||||||
|
ai_writing_config = cfg.get("ai_writing_config", {})
|
||||||
|
keyword_model = ai_writing_config.get("keyword_model")
|
||||||
|
rank_model = ai_writing_config.get("rank_model")
|
||||||
|
max_materials = _resolve_max_materials(ai_writing_config.get("max_materials"))
|
||||||
|
provider = get_search_provider(ai_writing_config) # ← search_provider 等也从这里读
|
||||||
|
```
|
||||||
|
|
||||||
|
### 切换内网检索的最小步骤
|
||||||
|
|
||||||
|
1. `config.yaml` 改 `ai_writing.search_provider: intranet`
|
||||||
|
2. 填 `intranet_search_url` 和 `intranet_knowledge_base`(部署侧给)
|
||||||
|
3. 内网 ES 接口若返回结构异常 / 网络抖动,researcher 节点会收集 `provider.errors` + `provider.raw_responses`,作为非致命 `notice` 事件推前端时间线(折叠显示原始响应体),**不会中断写作流程**
|
||||||
|
4. 健康检查:可通过 `IntranetSearchProvider.health_check()` 单测,或直接发一笔 `/start` 看 `research_progress` 是否报错
|
||||||
|
|
||||||
|
### 备注
|
||||||
|
|
||||||
|
- `keyword_model` / `rank_model` 只影响素材收集专家的 LLM 调用,**不影响**大纲、草稿、编辑审核三个节点(它们各自走自己的主模型)。
|
||||||
|
- `max_materials` 是「合并去重后的总量上限」,不是每个关键词的检索条数;每个词的检索数会按 `ceil(max_materials / keyword_count)` 均分。`keyword_count` 由前端启动写作时传入(1~10,默认 6)。
|
||||||
|
- `intranet` 模式不带 fallback;如果内网 ES 全挂,researcher 拿到空结果会直接进入「未检索到素材,可重新搜索或在无素材的情况下继续写作」分支。如果想让内网失败时退回互联网检索,需要在 `get_search_provider` 里手动用 `_FallbackSearchProvider(IntranetSearchProvider(...), DuckDuckGoSearchProvider(...))` 包一层。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export function AIWritingForm({ onSubmit, disabled }: AIWritingFormProps) {
|
|||||||
const [articleType, setArticleType] = useState('analysis');
|
const [articleType, setArticleType] = useState('analysis');
|
||||||
const [audience, setAudience] = useState('普通读者');
|
const [audience, setAudience] = useState('普通读者');
|
||||||
const [wordCountInput, setWordCountInput] = useState('800');
|
const [wordCountInput, setWordCountInput] = useState('800');
|
||||||
const [keywordCountInput, setKeywordCountInput] = useState('6');
|
const [keywordCountInput, setKeywordCountInput] = useState('1');
|
||||||
const [strictMode, setStrictMode] = useState(false);
|
const [strictMode, setStrictMode] = useState(false);
|
||||||
const [modelName, setModelName] = useState('');
|
const [modelName, setModelName] = useState('');
|
||||||
const [models, setModels] = useState<ModelOption[]>([]);
|
const [models, setModels] = useState<ModelOption[]>([]);
|
||||||
@@ -100,7 +100,7 @@ export function AIWritingForm({ onSubmit, disabled }: AIWritingFormProps) {
|
|||||||
function handleKeywordCountBlur() {
|
function handleKeywordCountBlur() {
|
||||||
const num = parseInt(keywordCountInput, 10);
|
const num = parseInt(keywordCountInput, 10);
|
||||||
if (isNaN(num)) {
|
if (isNaN(num)) {
|
||||||
setKeywordCountInput('6');
|
setKeywordCountInput('1');
|
||||||
} else {
|
} else {
|
||||||
setKeywordCountInput(String(Math.max(1, Math.min(10, num))));
|
setKeywordCountInput(String(Math.max(1, Math.min(10, num))));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,3 +185,7 @@ memory:
|
|||||||
block_invisible_unicode: true
|
block_invisible_unicode: true
|
||||||
# streaming_scrubber:预留字段,代码尚未实现 —— 待版本支持后取消注释。
|
# streaming_scrubber:预留字段,代码尚未实现 —— 待版本支持后取消注释。
|
||||||
# streaming_scrubber: true # SSE 流前清洗 <memory-context>
|
# streaming_scrubber: true # SSE 流前清洗 <memory-context>
|
||||||
|
|
||||||
|
keyword_model: deepseek-chat
|
||||||
|
rank_model: deepseek-chat
|
||||||
|
max_materials: 20
|
||||||
Reference in new issue
Block a user