mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-05-23 00:16:48 +00:00
docs: complete all English and Chinese documentation pages
Agent-Logs-Url: https://github.com/bytedance/deer-flow/sessions/a5f192e7-8034-4e46-af22-60b90ee27d40 Co-authored-by: foreleven <4785594+foreleven@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
d71b452a34
commit
b62ac7672a
@@ -0,0 +1,48 @@
|
||||
import type { MetaRecord } from "nextra";
|
||||
|
||||
const meta: MetaRecord = {
|
||||
index: {
|
||||
title: "安装",
|
||||
},
|
||||
"quick-start": {
|
||||
title: "快速上手",
|
||||
},
|
||||
"design-principles": {
|
||||
title: "设计理念",
|
||||
},
|
||||
"lead-agent": {
|
||||
title: "Lead Agent",
|
||||
},
|
||||
middlewares: {
|
||||
title: "中间件",
|
||||
},
|
||||
configuration: {
|
||||
title: "配置",
|
||||
},
|
||||
memory: {
|
||||
title: "记忆系统",
|
||||
},
|
||||
tools: {
|
||||
title: "工具",
|
||||
},
|
||||
skills: {
|
||||
title: "技能",
|
||||
},
|
||||
sandbox: {
|
||||
title: "沙箱",
|
||||
},
|
||||
subagents: {
|
||||
title: "子 Agent",
|
||||
},
|
||||
mcp: {
|
||||
title: "MCP 集成",
|
||||
},
|
||||
customization: {
|
||||
title: "自定义与扩展",
|
||||
},
|
||||
"integration-guide": {
|
||||
title: "集成指南",
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
@@ -0,0 +1,154 @@
|
||||
import { Callout, Cards } from "nextra/components";
|
||||
|
||||
# 配置
|
||||
|
||||
<Callout type="info" emoji="⚙️">
|
||||
所有 DeerFlow Harness 行为都由 <code>config.yaml</code> 驱动。一个文件控制哪些模型可用、沙箱如何运行、加载哪些工具,以及每个子系统的行为。
|
||||
</Callout>
|
||||
|
||||
DeerFlow 的配置系统围绕一个目标设计:每一个有意义的行为都应该可以在配置文件中表达,而不是硬编码在应用程序中。这使部署可重现、可审计,并且易于按环境定制。
|
||||
|
||||
## 配置文件位置
|
||||
|
||||
DeerFlow 使用以下优先级顺序解析 `config.yaml`:
|
||||
|
||||
1. 显式传递给 `AppConfig.from_file(config_path)` 的路径。
|
||||
2. `DEER_FLOW_CONFIG_PATH` 环境变量。
|
||||
3. `backend/config.yaml`(相对于后端目录)。
|
||||
4. 仓库根目录中的 `config.yaml`。
|
||||
|
||||
如果这些路径都不存在,应用程序在启动时会报错。
|
||||
|
||||
要使用自定义位置:
|
||||
|
||||
```bash
|
||||
export DEER_FLOW_CONFIG_PATH=/path/to/my-config.yaml
|
||||
```
|
||||
|
||||
## 环境变量插值
|
||||
|
||||
任何字段值都可以使用 `$VAR_NAME` 语法引用环境变量:
|
||||
|
||||
```yaml
|
||||
models:
|
||||
- name: gpt-4o
|
||||
api_key: $OPENAI_API_KEY
|
||||
```
|
||||
|
||||
这使密钥不出现在配置文件本身中,变量在运行时从进程环境解析。
|
||||
|
||||
## `use` 字段
|
||||
|
||||
许多配置条目使用 `use:` 字段来指定要实例化的 Python 类或对象,格式为:
|
||||
|
||||
```
|
||||
package.subpackage.module:ClassName
|
||||
```
|
||||
|
||||
或对于模块级对象:
|
||||
|
||||
```
|
||||
package.subpackage.module:variable_name
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```yaml
|
||||
sandbox:
|
||||
use: deerflow.sandbox.local:LocalSandboxProvider
|
||||
|
||||
tools:
|
||||
- use: deerflow.community.tavily.tools:web_search_tool
|
||||
api_key: $TAVILY_API_KEY
|
||||
```
|
||||
|
||||
这是 DeerFlow 实现可插拔性而不硬编码类引用的方式。
|
||||
|
||||
## 额外字段透传
|
||||
|
||||
对于模型配置,`ModelConfig` 使用 `pydantic ConfigDict(extra="allow")`。这意味着你在模型条目下添加的任何额外字段都直接传递给模型构造函数。这允许提供商特定选项(如 `extra_body`、`reasoning` 或自定义超时键)无需修改 Harness 即可工作:
|
||||
|
||||
```yaml
|
||||
models:
|
||||
- name: my-model
|
||||
use: langchain_openai:ChatOpenAI
|
||||
model: gpt-4o
|
||||
api_key: $OPENAI_API_KEY
|
||||
some_provider_specific_option: value # 传递给 ChatOpenAI 构造函数
|
||||
```
|
||||
|
||||
## 配置版本
|
||||
|
||||
`config.yaml` 包含追踪 schema 版本的 `config_version` 字段:
|
||||
|
||||
```yaml
|
||||
config_version: 6
|
||||
```
|
||||
|
||||
当 schema 更改(新字段、重命名章节)时,此数字增加。如果你本地的 `config.yaml` 落后于当前版本,运行:
|
||||
|
||||
```bash
|
||||
make config-upgrade
|
||||
```
|
||||
|
||||
这将 `config.example.yaml` 中的新字段合并到你现有的 `config.yaml` 中,而不覆盖你的自定义内容。
|
||||
|
||||
## 模块配置速查表
|
||||
|
||||
下表将 `config.yaml` 中的每个顶层章节映射到其文档页面:
|
||||
|
||||
| 章节 | 描述 | 文档 |
|
||||
|---|---|---|
|
||||
| `log_level` | 日志级别(`debug`/`info`/`warning`/`error`) | — |
|
||||
| `models` | 可用的 LLM 模型 | [Lead Agent](/docs/harness/lead-agent) |
|
||||
| `token_usage` | 每次模型调用的 token 追踪 | [中间件](/docs/harness/middlewares) |
|
||||
| `tools` | 可用的 Agent 工具 | [工具](/docs/harness/tools) |
|
||||
| `tool_groups` | 工具的命名分组 | [工具](/docs/harness/tools) |
|
||||
| `tool_search` | 延迟/按需工具加载 | [工具](/docs/harness/tools) |
|
||||
| `sandbox` | 沙箱提供者和选项 | [沙箱](/docs/harness/sandbox) |
|
||||
| `skills` | 技能目录和容器路径 | [技能](/docs/harness/skills) |
|
||||
| `skill_evolution` | Agent 管理的技能创建 | [技能](/docs/harness/skills) |
|
||||
| `subagents` | 子 Agent 超时和最大轮次 | [子 Agent](/docs/harness/subagents) |
|
||||
| `acp_agents` | 外部 ACP Agent 集成 | [子 Agent](/docs/harness/subagents) |
|
||||
| `memory` | 跨会话记忆存储 | [记忆系统](/docs/harness/memory) |
|
||||
| `summarization` | 对话摘要压缩 | [中间件](/docs/harness/middlewares) |
|
||||
| `title` | 自动生成线程标题 | [中间件](/docs/harness/middlewares) |
|
||||
| `checkpointer` | 线程状态持久化 | [Agent 与线程](/docs/application/agents-and-threads) |
|
||||
| `guardrails` | 工具调用授权 | — |
|
||||
| `uploads` | 文件上传设置(PDF 转换器) | — |
|
||||
| `channels` | IM 频道集成(飞书、Slack 等) | — |
|
||||
|
||||
## 最小配置示例
|
||||
|
||||
最小有效的 `config.yaml` 至少需要一个模型和一个沙箱:
|
||||
|
||||
```yaml
|
||||
config_version: 6
|
||||
|
||||
models:
|
||||
- name: gpt-4o
|
||||
use: langchain_openai:ChatOpenAI
|
||||
model: gpt-4o
|
||||
api_key: $OPENAI_API_KEY
|
||||
request_timeout: 600.0
|
||||
max_retries: 2
|
||||
supports_vision: true
|
||||
|
||||
sandbox:
|
||||
use: deerflow.sandbox.local:LocalSandboxProvider
|
||||
|
||||
tools:
|
||||
- use: deerflow.community.ddg_search.tools:web_search_tool
|
||||
- use: deerflow.community.jina_ai.tools:web_fetch_tool
|
||||
- use: deerflow.sandbox.tools:ls_tool
|
||||
- use: deerflow.sandbox.tools:read_file_tool
|
||||
- use: deerflow.sandbox.tools:write_file_tool
|
||||
- use: deerflow.sandbox.tools:bash_tool
|
||||
```
|
||||
|
||||
从仓库根目录的 `config.example.yaml` 开始,取消注释你需要的章节。
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="部署指南" href="/docs/application/deployment-guide" />
|
||||
<Cards.Card title="应用配置" href="/docs/application/configuration" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,150 @@
|
||||
import { Callout, Cards } from "nextra/components";
|
||||
|
||||
# 自定义与扩展
|
||||
|
||||
<Callout type="info" emoji="🔧">
|
||||
DeerFlow 设计为可适配的。你可以通过编写自定义中间件、添加新工具、构建技能包以及通过 config.yaml 的 <code>use:</code> 字段替换任何内置组件来扩展 Agent 行为。
|
||||
</Callout>
|
||||
|
||||
DeerFlow 的可插拔架构意味着系统的大多数部分都可以在不 fork 核心的情况下被替换或扩展。本页面列举了扩展点,并解释如何使用每一个。
|
||||
|
||||
## 自定义中间件
|
||||
|
||||
中间件是为 Lead Agent 添加行为的主要扩展点。它们包裹每次 LLM 调用,可以在模型调用前后读取和修改 Agent 的状态。
|
||||
|
||||
添加自定义中间件:
|
||||
|
||||
1. 实现 `langchain.agents.middleware` 中的 `AgentMiddleware` 接口。
|
||||
2. 在构建 Agent 时通过 `custom_middlewares` 参数传入你的中间件。
|
||||
|
||||
```python
|
||||
from langchain.agents.middleware import AgentMiddleware
|
||||
from deerflow.agents.thread_state import ThreadState
|
||||
|
||||
class AuditMiddleware(AgentMiddleware):
|
||||
async def on_start(self, state: ThreadState, config):
|
||||
# 在每次模型调用前运行
|
||||
print(f"[审计] 轮次开始:上下文中有 {len(state.messages)} 条消息")
|
||||
return state, config
|
||||
|
||||
async def on_end(self, state: ThreadState, config):
|
||||
# 在每次模型调用后运行
|
||||
print(f"[审计] 轮次结束:最后一条消息类型 = {state.messages[-1].type}")
|
||||
return state, config
|
||||
```
|
||||
|
||||
自定义中间件在链末尾 `ClarificationMiddleware` 之前注入,后者始终最后运行。
|
||||
|
||||
## 自定义工具
|
||||
|
||||
在 `config.yaml` 的 `tools:` 下注册新工具,将其添加到 Agent:
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
- use: mypackage.tools:my_custom_tool
|
||||
api_key: $MY_TOOL_API_KEY
|
||||
```
|
||||
|
||||
你的工具必须是 LangChain `BaseTool` 或用 `@tool` 装饰的函数。它将使用 `use:` 类路径和配置条目中的任何额外字段实例化。
|
||||
|
||||
```python
|
||||
# mypackage/tools.py
|
||||
from langchain_core.tools import tool
|
||||
|
||||
@tool
|
||||
def my_custom_tool(query: str) -> str:
|
||||
"""搜索我的自定义数据源。"""
|
||||
return do_search(query)
|
||||
```
|
||||
|
||||
## 自定义沙箱提供者
|
||||
|
||||
沙箱可以通过实现 `SandboxProvider` 接口来替换:
|
||||
|
||||
```python
|
||||
from deerflow.sandbox.sandbox_provider import SandboxProvider
|
||||
|
||||
class MyCustomSandboxProvider(SandboxProvider):
|
||||
def acquire(self, thread_id: str | None = None) -> str:
|
||||
# 返回 sandbox_id
|
||||
...
|
||||
|
||||
def get(self, sandbox_id: str):
|
||||
# 返回此 id 的沙箱实例
|
||||
...
|
||||
|
||||
def release(self, sandbox_id: str) -> None:
|
||||
# 清理
|
||||
...
|
||||
```
|
||||
|
||||
然后在 `config.yaml` 中引用:
|
||||
|
||||
```yaml
|
||||
sandbox:
|
||||
use: mypackage.sandbox:MyCustomSandboxProvider
|
||||
```
|
||||
|
||||
## 自定义记忆存储
|
||||
|
||||
通过实现 `MemoryStorage` 将基于文件的记忆替换为任何持久化存储:
|
||||
|
||||
```python
|
||||
from deerflow.agents.memory.storage import MemoryStorage
|
||||
from typing import Any
|
||||
|
||||
class RedisMemoryStorage(MemoryStorage):
|
||||
def load(self, agent_name: str | None = None) -> dict[str, Any]:
|
||||
...
|
||||
|
||||
def reload(self, agent_name: str | None = None) -> dict[str, Any]:
|
||||
...
|
||||
|
||||
def save(self, memory_data: dict[str, Any], agent_name: str | None = None) -> bool:
|
||||
...
|
||||
```
|
||||
|
||||
在 `config.yaml` 中配置:
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
storage_class: mypackage.storage:RedisMemoryStorage
|
||||
```
|
||||
|
||||
## 自定义技能
|
||||
|
||||
技能是最简单的扩展点。在 `skills/custom/your-skill-name/` 下创建一个目录,并在其中添加 `SKILL.md` 文件。技能将在下次 `load_skills()` 调用时自动被发现。
|
||||
|
||||
参见[技能](/docs/harness/skills)页面了解完整的目录结构和 `SKILL.md` 格式。
|
||||
|
||||
## 自定义模型
|
||||
|
||||
任何与 LangChain 兼容的聊天模型都可以通过在 `use:` 字段中指定来使用:
|
||||
|
||||
```yaml
|
||||
models:
|
||||
- name: my-custom-model
|
||||
use: mypackage.models:MyCustomChatModel
|
||||
# 任何额外字段都作为 kwargs 传递给构造函数
|
||||
base_url: http://my-model-server:8080
|
||||
api_key: $MY_MODEL_API_KEY
|
||||
```
|
||||
|
||||
模型类必须实现 LangChain 的 `BaseChatModel` 接口。
|
||||
|
||||
## 自定义检查点
|
||||
|
||||
线程状态持久化可以使用任何与 LangGraph 兼容的检查点器:
|
||||
|
||||
```yaml
|
||||
checkpointer:
|
||||
type: sqlite
|
||||
connection_string: ./my-checkpoints.db
|
||||
```
|
||||
|
||||
对于自定义后端,实现 LangGraph 的 `BaseCheckpointSaver` 接口,并在初始化 `DeerFlowClient` 时以编程方式配置它。
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="集成指南" href="/docs/harness/integration-guide" />
|
||||
<Cards.Card title="配置" href="/docs/harness/configuration" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,112 @@
|
||||
import { Callout, Cards } from "nextra/components";
|
||||
|
||||
# 设计理念
|
||||
|
||||
<Callout type="info" emoji="🏗️">
|
||||
DeerFlow 围绕一个核心思想构建:Agent 行为应该由小型、可观察、可替换的组件组合而成——而不是硬编码到固定的工作流图中。
|
||||
</Callout>
|
||||
|
||||
了解 DeerFlow Harness 背后的设计理念,有助于你有效地使用它、自信地扩展它,并推断 Agent 在生产环境中的行为方式。
|
||||
|
||||
## 为什么是 Harness,而非 Framework
|
||||
|
||||
框架提供抽象和构建块,你负责组装各部分并编写连接它们的胶水代码。
|
||||
|
||||
**Harness** 更进一步。它打包了一个有主张的、可直接运行的运行时,让 Agent 无需你每次重建相同的基础设施就能完成真实工作。
|
||||
|
||||
DeerFlow 之所以是 Harness,是因为它内置了:
|
||||
|
||||
- 带有工具路由的 Lead Agent
|
||||
- 包裹每次 LLM 调用的中间件链
|
||||
- 用于文件和命令的沙箱执行
|
||||
- 按需加载专业能力的技能
|
||||
- 用于委派并行工作的子 Agent
|
||||
- 跨会话连续性的记忆
|
||||
- 控制这一切的配置系统
|
||||
|
||||
你不需要从头设计编排层——Harness 就是编排层。
|
||||
|
||||
## 长时序任务是主要使用场景
|
||||
|
||||
DeerFlow 专为需要不止一次提示-响应交互的任务而设计。一个有用的长时序 Agent 必须:
|
||||
|
||||
1. 制定计划
|
||||
2. 按顺序调用工具
|
||||
3. 检查和修改文件
|
||||
4. 在失败时恢复
|
||||
5. 当任务太宽泛时委派给子 Agent
|
||||
6. 最终返回具体的产出物
|
||||
|
||||
DeerFlow 中的每一个架构决策都以这个使用场景为标准进行评估。短暂、无状态的交互很简单。在真实世界压力下的长时序、多步骤工作流才是目标。
|
||||
|
||||
## 中间件链优于继承
|
||||
|
||||
DeerFlow 不要求你子类化 Agent 或覆盖方法来改变其行为。相反,它使用一个**中间件链**来包裹每次 LLM 调用。
|
||||
|
||||
每个中间件都是一个小型、专注的插件,可以在模型调用前后检查或修改 Agent 的状态。Lead Agent 的行为完全由活跃的中间件决定。
|
||||
|
||||
这种设计有几个优点:
|
||||
|
||||
- 各个行为(记忆、摘要、澄清、循环检测)相互隔离,可独立测试。
|
||||
- 可以扩展链而无需触碰 Agent 的核心逻辑。
|
||||
- 每个中间件的效果是可见且可审计的,因为它只触及其声明的状态。
|
||||
|
||||
详见[中间件](/docs/harness/middlewares)页面的完整列表和配置说明。
|
||||
|
||||
## 技能提供专业化但不污染上下文
|
||||
|
||||
**技能**是面向任务的能力包,包含指令、工作流、最佳实践以及让 Agent 在特定工作类型中有效的工具或资源。
|
||||
|
||||
关键设计决策是技能**按需加载**。基础 Agent 保持通用。当任务需要深度研究时,加载研究技能;当任务需要数据分析时,加载分析技能。
|
||||
|
||||
这很重要,因为它保持了基础 Agent 上下文的清晰。为撰写学术论文而设计的专业提示词不会污染专注于编码的会话。技能在相关时注入内容,仅此而已。
|
||||
|
||||
## 沙箱是执行环境
|
||||
|
||||
DeerFlow 为 Agent 提供一个**沙箱**:一个隔离的工作区,Agent 可以在其中读取文件、写入输出、运行命令并生成产出物。
|
||||
|
||||
这将 Agent 从文本生成器转变为能够真正完成工作的系统。Agent 不只是描述要写什么代码,而是可以写代码、运行代码并验证结果。
|
||||
|
||||
隔离性很重要,因为执行应该可重现且可控。沙箱是 DeerFlow 支持真实行动而不仅仅是对话的原因。
|
||||
|
||||
## 上下文工程让长时序任务可控
|
||||
|
||||
上下文压力是长时序 Agent 的主要挑战。如果所有内容无限期累积在上下文窗口中,Agent 会变得越来越慢、越来越嘈杂、越来越不可靠。
|
||||
|
||||
DeerFlow 通过**上下文工程**来解决这个问题——有意识地控制 Agent 在每个步骤中看到、记住和忽略什么:
|
||||
|
||||
- **摘要压缩**:当对话变得太长时,旧轮次被摘要替代。Agent 保留含义而不是全量内容。
|
||||
- **子 Agent 上下文隔离**:当工作委派给子 Agent 时,子 Agent 只接收完成其任务所需的信息,而不是完整的父历史。
|
||||
- **外部工作记忆**:任务产生的文件和产出物保存在磁盘上,而不在上下文窗口中。Agent 在需要时引用它们。
|
||||
- **记忆注入**:跨会话事实以受控的 token 预算注入到系统提示中。
|
||||
|
||||
这是 DeerFlow 中最重要的思想之一。好的 Agent 行为不仅仅是关于更强大的模型,也关于在正确时间给模型提供正确的工作集。
|
||||
|
||||
## 配置驱动行为
|
||||
|
||||
DeerFlow 中所有有意义的行为都通过 `config.yaml` 控制。系统的设计使运维人员无需触碰代码就能改变 Agent 的行为——使用哪些模型、是否启用摘要压缩、如何限制子 Agent、哪些工具可用。
|
||||
|
||||
这个设计原则有三个含义:
|
||||
|
||||
1. **可重现性**:一个配置文件在某时间点完整描述了 Agent 的行为。
|
||||
2. **可部署性**:相同的代码在不同环境中运行方式不同,因为配置不同。
|
||||
3. **可审计性**:Agent 能做什么和不能做什么在一处可见。
|
||||
|
||||
环境变量插值(`api_key: $OPENAI_API_KEY`)将密钥排除在提交的配置文件之外,同时保持相同的结构。
|
||||
|
||||
## 总结
|
||||
|
||||
| 设计原则 | 实践含义 |
|
||||
|---|---|
|
||||
| Harness 而非 Framework | 开箱即用的运行时,所有基础设施已预先连接 |
|
||||
| 长时序优先 | 架构假设多步骤、多工具、多轮次任务 |
|
||||
| 中间件优于继承 | 行为由小型、隔离的插件组合而成 |
|
||||
| 技能提供专业化 | 领域能力按需注入,保持基础干净 |
|
||||
| 沙箱用于执行 | 真实文件和命令操作的隔离工作区 |
|
||||
| 上下文工程 | 主动管理 Agent 所见内容以保持有效性 |
|
||||
| 配置驱动 | 所有关键行为通过 `config.yaml` 控制 |
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="Lead Agent" href="/docs/harness/lead-agent" />
|
||||
<Cards.Card title="中间件" href="/docs/harness/middlewares" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Callout, Cards } from "nextra/components";
|
||||
|
||||
# 安装 DeerFlow Harness
|
||||
|
||||
<Callout type="info" emoji="📦">
|
||||
DeerFlow Harness Python 包将以 <code>deerflow</code> 名称发布。目前尚未正式发布,安装方式<strong>即将推出</strong>。
|
||||
</Callout>
|
||||
|
||||
DeerFlow Harness 是构建自己 Super Agent 系统的 Python SDK 和运行时基础。
|
||||
|
||||
如果你想在自己的产品或工作流中整合技能、记忆、工具、沙箱和子 Agent 等 Agent 能力,这正是你需要的 DeerFlow 组件。
|
||||
|
||||
## 包名称
|
||||
|
||||
包名将是:
|
||||
|
||||
```bash
|
||||
pip install deerflow
|
||||
```
|
||||
|
||||
该包目前还未公开发布,但这是文档正式发布后将使用的安装路径。
|
||||
|
||||
## 当前状态
|
||||
|
||||
DeerFlow Harness 包**即将推出**。
|
||||
|
||||
目前,本章节的存在是为了建立 SDK 入口和包标识,同时公开分发流程正在最终确定中。
|
||||
|
||||
## Harness 将提供什么
|
||||
|
||||
Harness 专为想要在 DeerFlow 运行时模型之上构建自己 Agent 系统的开发者设计。
|
||||
|
||||
它将提供以下基础:
|
||||
|
||||
- 构建长时序 Agent
|
||||
- 组合运行时能力(记忆、工具、技能、子 Agent)
|
||||
- 在沙箱中执行 Agent
|
||||
- 通过配置和代码自定义 Agent 行为
|
||||
- 将 DeerFlow 集成到自己的应用架构中
|
||||
|
||||
## 下一步
|
||||
|
||||
在包正式发布之前,了解 DeerFlow Harness 的最佳方式是阅读本章节的概念和实现文档。
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="快速上手" href="/docs/harness/quick-start" />
|
||||
<Cards.Card title="配置" href="/docs/harness/configuration" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,157 @@
|
||||
import { Callout, Cards } from "nextra/components";
|
||||
|
||||
# 集成指南
|
||||
|
||||
<Callout type="info" emoji="🔌">
|
||||
DeerFlow Harness 可以嵌入任何 Python 应用程序。本指南涵盖在你自己的系统中将 DeerFlow 作为库使用的集成模式。
|
||||
</Callout>
|
||||
|
||||
DeerFlow Harness 不仅仅是一个独立应用程序——它是一个可以导入并在你自己的后端、API 服务器、自动化系统或多 Agent 协调器中使用的 Python 库。
|
||||
|
||||
## 嵌入 DeerFlowClient
|
||||
|
||||
主要集成点是 `DeerFlowClient`。它封装了 LangGraph 运行时,并提供一个简洁的 API,用于在任何 Python 应用中发送消息和流式传输响应。
|
||||
|
||||
```python
|
||||
from deerflow.client import DeerFlowClient
|
||||
from deerflow.config import load_config
|
||||
|
||||
# 加载配置(读取 config.yaml 或 DEER_FLOW_CONFIG_PATH)
|
||||
load_config()
|
||||
|
||||
client = DeerFlowClient()
|
||||
```
|
||||
|
||||
客户端是线程安全的,设计为实例化一次并在请求之间复用。
|
||||
|
||||
## 异步流式传输
|
||||
|
||||
推荐的集成模式是异步流式传输。这让你可以在 Agent 生成响应时实时访问每个 token 和事件:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
async def run_agent(thread_id: str, user_message: str):
|
||||
async for event in client.astream(
|
||||
thread_id=thread_id,
|
||||
message=user_message,
|
||||
config={
|
||||
"configurable": {
|
||||
"model_name": "gpt-4o",
|
||||
"subagent_enabled": True,
|
||||
}
|
||||
},
|
||||
):
|
||||
# 处理每个流式事件
|
||||
yield event
|
||||
|
||||
# 在 FastAPI 处理器中:
|
||||
# from fastapi.responses import StreamingResponse
|
||||
# return StreamingResponse(run_agent(thread_id, message), media_type="text/event-stream")
|
||||
```
|
||||
|
||||
## 非流式调用
|
||||
|
||||
对于批处理或只需要最终结果的场景:
|
||||
|
||||
```python
|
||||
async def run_agent_sync(thread_id: str, user_message: str) -> dict:
|
||||
result = await client.ainvoke(
|
||||
thread_id=thread_id,
|
||||
message=user_message,
|
||||
)
|
||||
return result
|
||||
```
|
||||
|
||||
## 线程管理
|
||||
|
||||
线程表示持久化对话。使用唯一线程 ID 隔离不同用户会话:
|
||||
|
||||
```python
|
||||
import uuid
|
||||
|
||||
# 新对话
|
||||
thread_id = str(uuid.uuid4())
|
||||
|
||||
# 继续已有对话(相同 thread_id)
|
||||
# 如果配置了检查点,Agent 将看到完整历史
|
||||
await client.ainvoke(thread_id=existing_thread_id, message="后续问题")
|
||||
```
|
||||
|
||||
## 自定义 Agent 配置
|
||||
|
||||
通过创建命名 Agent 配置并在运行时传入 `agent_name` 来构建领域特定 Agent:
|
||||
|
||||
```python
|
||||
# agents/research-assistant/config.yaml 必须存在并包含技能和工具配置
|
||||
|
||||
result = await client.ainvoke(
|
||||
thread_id=thread_id,
|
||||
message=user_message,
|
||||
config={
|
||||
"configurable": {
|
||||
"agent_name": "research-assistant",
|
||||
"model_name": "gpt-4o",
|
||||
}
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
## 与 FastAPI 集成
|
||||
|
||||
DeerFlow Gateway 本身是一个 FastAPI 应用程序。你可以将其作为子应用程序挂载:
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from deerflow.config import load_config
|
||||
|
||||
load_config()
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# 挂载 DeerFlow Gateway
|
||||
from deerflow.app.gateway.main import app as gateway_app
|
||||
app.mount("/deerflow", gateway_app)
|
||||
```
|
||||
|
||||
或者在你自己的 FastAPI 路由中直接使用 `DeerFlowClient` 进行流式传输:
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import StreamingResponse
|
||||
from deerflow.client import DeerFlowClient
|
||||
|
||||
app = FastAPI()
|
||||
client = DeerFlowClient()
|
||||
|
||||
@app.post("/chat/{thread_id}")
|
||||
async def chat(thread_id: str, body: dict):
|
||||
async def generate():
|
||||
async for event in client.astream(thread_id=thread_id, message=body["message"]):
|
||||
yield f"data: {event}\n\n"
|
||||
return StreamingResponse(generate(), media_type="text/event-stream")
|
||||
```
|
||||
|
||||
## 嵌入模式下的配置
|
||||
|
||||
当嵌入到另一个应用程序时,显式设置配置路径以避免歧义:
|
||||
|
||||
```python
|
||||
import os
|
||||
os.environ["DEER_FLOW_CONFIG_PATH"] = "/path/to/my-deerflow-config.yaml"
|
||||
|
||||
from deerflow.config import load_config
|
||||
load_config()
|
||||
```
|
||||
|
||||
或直接传递路径:
|
||||
|
||||
```python
|
||||
from deerflow.config import load_config
|
||||
load_config(config_path="/path/to/my-deerflow-config.yaml")
|
||||
```
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="自定义与扩展" href="/docs/harness/customization" />
|
||||
<Cards.Card title="配置" href="/docs/harness/configuration" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,126 @@
|
||||
import { Callout, Cards, Steps } from "nextra/components";
|
||||
|
||||
# Lead Agent
|
||||
|
||||
<Callout type="info" emoji="🧠">
|
||||
Lead Agent 是每个 DeerFlow 线程中的主要推理和编排单元。它决定要做什么、调用工具、委派子 Agent,并返回产出物。
|
||||
</Callout>
|
||||
|
||||
Lead Agent 是 DeerFlow 线程中的核心执行者。每个对话、任务和工作流都通过它进行。理解它的工作方式有助于你有效地配置它,并在需要时扩展它。
|
||||
|
||||
## Lead Agent 的职责
|
||||
|
||||
Lead Agent 负责:
|
||||
|
||||
- 接收用户消息并维护对话状态
|
||||
- 推断接下来要做什么(规划、工具选择、委派)
|
||||
- 调用工具——内置工具、社区工具、MCP 工具或技能工具
|
||||
- 通过 `task` 工具将子任务委派给子 Agent
|
||||
- 管理产出物(文件、输出、交付物)
|
||||
- 在计划模式下更新待办列表
|
||||
- 向用户返回最终响应或产出物
|
||||
|
||||
Lead Agent 不硬编码特定的工作流。它使用模型的推理能力来适应用户提供的任何任务,由系统提示和当前范围内的技能引导。
|
||||
|
||||
## 运行时基础
|
||||
|
||||
Lead Agent 基于 **LangGraph** 和 **LangChain Agent** 原语构建:
|
||||
|
||||
- `langchain.agents` 的 [`create_agent`](https://python.langchain.com/docs/concepts/agents/) 将 LLM 封装成工具调用 Agent 循环。
|
||||
- LangGraph 管理 `ThreadState`,提供检查点、流式传输和图执行模型。
|
||||
- **中间件链**包裹 Agent 循环的每一轮,提供记忆、摘要和澄清等跨领域能力。
|
||||
|
||||
## 执行流程
|
||||
|
||||
<Steps>
|
||||
|
||||
### 接收消息
|
||||
|
||||
用户消息到达并添加到 `ThreadState.messages`。`ThreadState` 保存完整的对话历史、任何活跃的待办列表、累积的产出物和运行时元数据。
|
||||
|
||||
### 中间件前处理
|
||||
|
||||
在调用模型之前,每个活跃的中间件都有机会修改状态。例如,`MemoryMiddleware` 将持久化的记忆事实注入到系统提示中,`SummarizationMiddleware` 在 token 预算超出时可能压缩旧消息。
|
||||
|
||||
### LLM 推理
|
||||
|
||||
模型接收当前消息(包括带有活跃技能指令的系统提示),并产生直接回复或一个或多个工具调用请求。
|
||||
|
||||
### 工具执行
|
||||
|
||||
如果请求了工具调用,它们会被分发到相应的处理器——用于文件和命令操作的沙箱工具、用于网络访问的社区工具,或用于子 Agent 委派的 `task` 工具。
|
||||
|
||||
### 中间件后处理
|
||||
|
||||
工具结果返回后、下一次模型调用之前,中间件再次运行。`TitleMiddleware` 可能在第一次交互后生成线程标题,`TodoMiddleware` 可能更新任务列表。
|
||||
|
||||
### 循环或响应
|
||||
|
||||
如果模型需要更多信息(例如,工具返回了部分结果),循环继续。当模型决定任务完成时,它产生最终消息,循环结束。
|
||||
|
||||
### 状态更新
|
||||
|
||||
`ThreadState` 更新为新消息、产出物和记忆队列。如果配置了检查点,状态将被持久化。
|
||||
|
||||
</Steps>
|
||||
|
||||
## 模型选择
|
||||
|
||||
Lead Agent 在运行时使用以下优先级顺序解析要使用的模型:
|
||||
|
||||
1. 每次请求配置中的 `model_name`(或 `model`),如果提供且有效。
|
||||
2. 活跃自定义 Agent 配置中的 `model` 字段,如果指定了 Agent。
|
||||
3. `config.yaml` 中 `models:` 列表的第一个模型(全局默认值)。
|
||||
|
||||
如果请求的模型名称在配置中找不到,系统回退到默认模型并记录警告。
|
||||
|
||||
```yaml
|
||||
models:
|
||||
- name: my-primary-model
|
||||
use: langchain_openai:ChatOpenAI
|
||||
model: gpt-4o
|
||||
api_key: $OPENAI_API_KEY
|
||||
request_timeout: 600.0
|
||||
max_retries: 2
|
||||
supports_vision: true
|
||||
|
||||
- name: my-fast-model
|
||||
use: langchain_openai:ChatOpenAI
|
||||
model: gpt-4o-mini
|
||||
api_key: $OPENAI_API_KEY
|
||||
```
|
||||
|
||||
第一个条目(`my-primary-model`)成为默认值。任何不指定模型或指定未知模型名称的请求都将使用它。
|
||||
|
||||
## 思考模式
|
||||
|
||||
如果模型支持扩展思考(例如 DeepSeek Reasoner、启用思考的 Doubao、Anthropic Claude 思考模式),Lead Agent 可以在**思考模式**下运行。在此模式下,模型的内部推理步骤在响应流中可见。
|
||||
|
||||
思考模式通过每次请求的 `thinking_enabled` 标志控制。如果启用了思考但配置的模型不支持,系统会优雅地回退并记录警告。
|
||||
|
||||
## 计划模式
|
||||
|
||||
当请求配置中将 `is_plan_mode` 设为 `true` 时,`TodoMiddleware` 被激活。Agent 然后维护一个结构化的任务列表,在处理复杂任务时将条目标记为 `in_progress`、`completed` 或 `pending`。这为用户提供了 Agent 进度的可见性。
|
||||
|
||||
计划模式适用于显示增量进度有价值的复杂、多步骤任务。对于简单请求,最好禁用它以避免不必要的开销。
|
||||
|
||||
## 自定义 Agent
|
||||
|
||||
相同的 Lead Agent 运行时同时为默认 Agent 和你创建的任何自定义 Agent 提供服务。自定义 Agent 的区别仅在于:
|
||||
|
||||
- 其**名称**(ASCII slug,从 `display_name` 自动派生)
|
||||
- 其**系统提示**或 Agent 特定指令
|
||||
- 它有权访问的**技能**
|
||||
- 它可以使用的**工具组**
|
||||
- 它默认使用的**模型**
|
||||
|
||||
自定义 Agent 通过 DeerFlow 应用界面或 `/api/agents` 端点创建。其配置存储在后端目录的 `agents/{name}/config.yaml` 中。
|
||||
|
||||
<Callout type="tip">
|
||||
当在线程中选择自定义 Agent 时,Lead Agent 在运行时加载该 Agent 的配置。为特定 Agent 切换模型或技能不需要重启服务器。
|
||||
</Callout>
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="中间件" href="/docs/harness/middlewares" />
|
||||
<Cards.Card title="工具" href="/docs/harness/tools" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,103 @@
|
||||
import { Callout, Cards, Steps } from "nextra/components";
|
||||
|
||||
# MCP 集成
|
||||
|
||||
<Callout type="info" emoji="🔌">
|
||||
Model Context Protocol(MCP)让 DeerFlow 能够连接任何外部工具服务器。连接后,MCP 工具与内置工具一样对 Lead Agent 可用。
|
||||
</Callout>
|
||||
|
||||
**Model Context Protocol(MCP)** 是连接语言模型与外部工具和数据源的开放标准。DeerFlow 的 MCP 集成允许你用任何实现了 MCP 协议的工具服务器扩展 Agent——无需修改 Harness 本身。
|
||||
|
||||
## 配置
|
||||
|
||||
MCP 服务器在 `extensions_config.json` 中配置,这个文件独立于 `config.yaml`。这种分离允许 MCP 和技能配置独立管理,并在运行时通过 Gateway API 更新。
|
||||
|
||||
默认位置是项目根目录(与 `config.yaml` 同一目录)。
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"my-server": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@my-org/my-mcp-server"],
|
||||
"enabled": true
|
||||
},
|
||||
"filesystem": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"],
|
||||
"enabled": true
|
||||
},
|
||||
"sqlite": {
|
||||
"command": "uvx",
|
||||
"args": ["mcp-server-sqlite", "--db-path", "/path/to/db.sqlite"],
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
每个服务器条目支持:
|
||||
- `command`:要运行的可执行文件(如 `npx`、`uvx`、`python`)
|
||||
- `args`:命令参数数组
|
||||
- `enabled`:服务器是否激活(可切换而无需删除条目)
|
||||
- `env`:可选地注入到服务器进程中的环境变量
|
||||
|
||||
## 工具如何加载
|
||||
|
||||
<Steps>
|
||||
|
||||
### 启动初始化
|
||||
|
||||
DeerFlow 服务器启动时调用 `initialize_mcp_tools()`。这连接到所有启用的 MCP 服务器,检索其工具 schema,并缓存结果。
|
||||
|
||||
### 缓存失效
|
||||
|
||||
MCP 工具缓存追踪 `extensions_config.json` 的修改时间(`mtime`)。当文件更改时——例如通过 Gateway API 启用或禁用服务器时——缓存被标记为过时,下次请求时重新加载工具。
|
||||
|
||||
这意味着 MCP 服务器更改无需重启 DeerFlow 服务器即可生效。
|
||||
|
||||
### 工具可用性
|
||||
|
||||
加载后,MCP 工具与内置和社区工具一起出现在 Lead Agent 的工具列表中。Agent 使用与其他工具相同的机制选择和调用它们。
|
||||
|
||||
</Steps>
|
||||
|
||||
## 工具搜索集成
|
||||
|
||||
当许多 MCP 服务器暴露大量工具时,预先将所有工具加载到 Agent 上下文中会增加 token 使用量并降低工具选择准确性。
|
||||
|
||||
启用**工具搜索**改为按需加载 MCP 工具:
|
||||
|
||||
```yaml
|
||||
# config.yaml
|
||||
tool_search:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
启用工具搜索后,MCP 工具按名称列在系统提示中,但不包含完整的工具 schema。Agent 使用 `tool_search` 内置工具发现它们,只将需要的工具加载到上下文中。
|
||||
|
||||
## OAuth 支持
|
||||
|
||||
某些 MCP 服务器需要 OAuth 认证。DeerFlow 的 `mcp/oauth.py` 处理声明了 OAuth 需求的服务器的 OAuth 流程。
|
||||
|
||||
当连接到受 OAuth 保护的 MCP 服务器时,DeerFlow 会:
|
||||
1. 从服务器能力头中检测 OAuth 需求
|
||||
2. 使用 `get_initial_oauth_headers()` 构建适当的授权头
|
||||
3. 通过 `build_oauth_tool_interceptor()` 用 OAuth 拦截器包装工具调用
|
||||
|
||||
OAuth 流程对 Lead Agent 是透明的——它只是调用工具,DeerFlow 处理认证。
|
||||
|
||||
## 管理 MCP 服务器
|
||||
|
||||
MCP 服务器可以通过多种方式管理:
|
||||
|
||||
- **通过 DeerFlow 应用界面**:扩展面板显示已连接的 MCP 服务器,允许你启用/禁用它们。
|
||||
- **通过 Gateway API**:`POST /api/extensions/mcp/{name}/enable` 和 `/disable`。
|
||||
- **直接编辑 `extensions_config.json`**:适用于脚本化或程序化配置。
|
||||
|
||||
由于基于文件 mtime 的缓存失效机制,更改会自动被检测到。
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="工具" href="/docs/harness/tools" />
|
||||
<Cards.Card title="配置" href="/docs/harness/configuration" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,116 @@
|
||||
import { Callout, Cards } from "nextra/components";
|
||||
|
||||
# 记忆系统
|
||||
|
||||
<Callout type="info" emoji="💾">
|
||||
记忆让 DeerFlow 在多个会话中保留有用信息。Agent 记住用户偏好、项目背景和反复出现的事实,这样它可以在不每次从零开始的情况下给出更好的响应。
|
||||
</Callout>
|
||||
|
||||
记忆是 DeerFlow Harness 的一个运行时功能。它不是简单的对话日志,而是跨多个独立会话持久化、在未来对话中影响 Agent 行为的结构化事实和上下文摘要存储。
|
||||
|
||||
## 记忆存储什么
|
||||
|
||||
记忆存储包含几类信息:
|
||||
|
||||
- **工作上下文**:用户正在进行的项目摘要、目标和反复出现的话题。
|
||||
- **个人上下文**:Agent 学到的偏好、沟通风格和其他用户特定细节。
|
||||
- **近期关注**:最近的关注领域和活跃任务。
|
||||
- **历史**:近几个月的上下文、早期背景和长期事实。
|
||||
- **事实**:Agent 从对话中提取的离散具体事实(例如偏好的工具、团队名称、项目约束)。
|
||||
|
||||
每个类别随着 Agent 从持续对话中学习而随时间更新。
|
||||
|
||||
## 工作原理
|
||||
|
||||
记忆由 `MemoryMiddleware` 管理,在每次 Lead Agent 轮次上运行:
|
||||
|
||||
1. **注入**:每次对话开始时,Agent 当前记忆以受控的 token 预算(`max_injection_tokens`)注入到系统提示中。
|
||||
2. **学习**:对话结束后,后台任务提取新事实并更新相关记忆类别。更新通过 `debounce_seconds` 防抖以批量处理快速变化。
|
||||
3. **按 Agent 记忆**:当自定义 Agent 激活时,其记忆独立于全局记忆存储。这保持不同 Agent 的知识隔离。
|
||||
|
||||
## 配置
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
enabled: true
|
||||
|
||||
# 全局记忆文件的存储路径。
|
||||
# 默认:{base_dir}/memory.json(解析为 backend/.deer-flow/memory.json)
|
||||
# 绝对路径按原样使用,相对路径相对于 base_dir 解析。
|
||||
storage_path: memory.json
|
||||
|
||||
# 存储类(默认:基于文件的 JSON 存储)
|
||||
storage_class: deerflow.agents.memory.storage.FileMemoryStorage
|
||||
|
||||
# 处理排队记忆更新前等待的秒数(防抖)
|
||||
debounce_seconds: 30
|
||||
|
||||
# 记忆更新提取使用的模型(null = 使用默认模型)
|
||||
model_name: null
|
||||
|
||||
# 要存储的最大事实数
|
||||
max_facts: 100
|
||||
|
||||
# 存储事实所需的最低置信度分数(0.0–1.0)
|
||||
fact_confidence_threshold: 0.7
|
||||
|
||||
# 是否将记忆注入到系统提示中
|
||||
injection_enabled: true
|
||||
|
||||
# 注入到系统提示的最大 token 数
|
||||
max_injection_tokens: 2000
|
||||
```
|
||||
|
||||
## 全局记忆与按 Agent 记忆
|
||||
|
||||
DeerFlow 支持两级记忆:
|
||||
|
||||
- **全局记忆**:存储在 `{base_dir}/memory.json`。在没有特定 Agent 激活或 Agent 没有按 Agent 记忆文件时使用。
|
||||
- **按 Agent 记忆**:存储在 `{base_dir}/agents/{agent_name}/memory.json`。当自定义 Agent 激活时使用,使该 Agent 学到的知识保持独立。
|
||||
|
||||
`MemoryMiddleware` 根据请求配置中的活跃 `agent_name` 自动选择正确的记忆文件。
|
||||
|
||||
用于记忆存储的 Agent 名称通过 `AGENT_NAME_PATTERN` 验证,以确保文件系统安全。
|
||||
|
||||
## 存储位置
|
||||
|
||||
默认情况下,记忆文件存储在后端基础目录下:
|
||||
|
||||
- 基础目录:`backend/.deer-flow/`
|
||||
- 全局记忆:`backend/.deer-flow/memory.json`
|
||||
- 按 Agent 记忆:`backend/.deer-flow/agents/{agent_name}/memory.json`
|
||||
|
||||
你可以用 `storage_path` 字段更改存储路径。相对路径相对于基础目录解析;使用绝对路径可以将记忆存储在自定义位置。
|
||||
|
||||
## 自定义存储后端
|
||||
|
||||
`storage_class` 字段允许你用自定义实现替换默认的基于文件的存储。任何继承 `MemoryStorage` 并实现 `load()`、`reload()` 和 `save()` 方法的类都可以使用:
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
storage_class: mypackage.storage.RedisMemoryStorage
|
||||
```
|
||||
|
||||
如果配置的类无法加载,系统回退到默认的 `FileMemoryStorage` 并记录错误。
|
||||
|
||||
## 禁用记忆
|
||||
|
||||
完全禁用记忆:
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
保留记忆存储但阻止注入到系统提示:
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
enabled: true
|
||||
injection_enabled: false
|
||||
```
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="配置" href="/docs/harness/configuration" />
|
||||
<Cards.Card title="中间件" href="/docs/harness/middlewares" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,196 @@
|
||||
import { Callout } from "nextra/components";
|
||||
|
||||
# 中间件
|
||||
|
||||
<Callout type="info" emoji="🔌">
|
||||
中间件包裹 Lead Agent 中的每次 LLM 调用。它们是添加跨领域行为(如记忆、摘要压缩、澄清和 token 追踪)的主要扩展点。
|
||||
</Callout>
|
||||
|
||||
每次 Lead Agent 调用 LLM 时,都会先后执行一条**中间件链**。中间件可以读取和修改 Agent 的状态、向系统提示注入内容、拦截工具调用,并对模型输出做出反应。
|
||||
|
||||
这种设计使 Agent 核心保持简单稳定,同时允许丰富的可组合行为分层叠加。
|
||||
|
||||
## 链的工作方式
|
||||
|
||||
中间件链在每次 Agent 调用时根据当前配置和请求参数构建一次。中间件按定义的顺序运行:
|
||||
|
||||
1. 运行时中间件(错误处理、线程数据、上传、悬空工具调用修补)
|
||||
2. `SummarizationMiddleware` — 上下文压缩(如果启用)
|
||||
3. `TodoMiddleware` — 任务列表管理(仅计划模式)
|
||||
4. `TokenUsageMiddleware` — token 追踪(如果启用)
|
||||
5. `TitleMiddleware` — 自动生成线程标题
|
||||
6. `MemoryMiddleware` — 跨会话记忆注入和队列
|
||||
7. `ViewImageMiddleware` — 图像细节注入(如果模型支持视觉)
|
||||
8. `DeferredToolFilterMiddleware` — 隐藏延迟工具 schema(如果启用工具搜索)
|
||||
9. `SubagentLimitMiddleware` — 限制并行子 Agent 调用(如果启用子 Agent)
|
||||
10. `LoopDetectionMiddleware` — 打破重复工具调用循环
|
||||
11. 自定义中间件(如有)
|
||||
12. `ClarificationMiddleware` — 拦截澄清请求(始终最后)
|
||||
|
||||
顺序很重要。摘要压缩在早期运行以在其他处理之前减少上下文。澄清总是最后运行,这样它可以在所有其他中间件完成后拦截。
|
||||
|
||||
## 中间件参考
|
||||
|
||||
### ClarificationMiddleware
|
||||
|
||||
拦截澄清工具调用,并将其转换为面向用户的信息请求。当模型决定在继续之前需要询问用户某事时,此中间件会将该请求呈现出来。
|
||||
|
||||
**配置**:由 `guardrails.clarification` 设置控制。
|
||||
|
||||
---
|
||||
|
||||
### LoopDetectionMiddleware
|
||||
|
||||
检测 Agent 是否在没有取得进展的情况下重复进行相同的工具调用。检测到循环时,中间件会介入打破循环,防止 Agent 无限消耗轮次。
|
||||
|
||||
**配置**:内置,无需用户配置。
|
||||
|
||||
---
|
||||
|
||||
### MemoryMiddleware
|
||||
|
||||
在每次对话开始时读取持久化记忆事实并将其注入到系统提示中。对话结束后,将后台更新排队,以将新信息纳入记忆存储。
|
||||
|
||||
**配置**:参见[记忆系统](/docs/harness/memory)页面和 `config.yaml` 中的 `memory:` 部分。
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
enabled: true
|
||||
injection_enabled: true
|
||||
max_injection_tokens: 2000
|
||||
debounce_seconds: 30
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SubagentLimitMiddleware
|
||||
|
||||
限制 Agent 在单次轮次中可以进行的并行子 Agent 任务调用数量。这防止 Agent 生成无限数量的并发子 Agent。
|
||||
|
||||
**配置**:每次请求配置中的 `subagent_enabled` 和 `max_concurrent_subagents`。
|
||||
|
||||
---
|
||||
|
||||
### TitleMiddleware
|
||||
|
||||
在第一次交互后自动为线程生成标题。标题从用户的第一条消息和 Agent 的响应中派生。
|
||||
|
||||
**配置**:`config.yaml` 中的 `title:` 部分。
|
||||
|
||||
```yaml
|
||||
title:
|
||||
enabled: true
|
||||
max_words: 6
|
||||
max_chars: 60
|
||||
model_name: null # 使用默认模型
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### TodoMiddleware
|
||||
|
||||
当计划模式激活时,维护一个对用户可见的结构化任务列表。Agent 使用 `write_todos` 工具,随着完成复杂目标,将任务标记为 `pending`、`in_progress` 或 `completed`。
|
||||
|
||||
**激活**:在请求配置中设置 `is_plan_mode: true` 时自动启用。不需要 `config.yaml` 条目。
|
||||
|
||||
---
|
||||
|
||||
### TokenUsageMiddleware
|
||||
|
||||
追踪每次模型调用的 LLM token 消耗,并以 `info` 级别记录。对于监控成本和了解长时序任务中 token 的使用位置很有帮助。
|
||||
|
||||
**配置**:`config.yaml` 中的 `token_usage:` 部分。
|
||||
|
||||
```yaml
|
||||
token_usage:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### SummarizationMiddleware
|
||||
|
||||
当对话变长时,对旧消息进行摘要以减少上下文大小。摘要被注入回对话,替代原始消息,在不需要完整 token 成本的情况下保留含义。
|
||||
|
||||
**配置**:`config.yaml` 中的 `summarization:` 部分。详见下方详细配置。
|
||||
|
||||
---
|
||||
|
||||
### ViewImageMiddleware
|
||||
|
||||
当当前模型支持视觉(`supports_vision: true`)时,此中间件拦截 `view_image` 工具调用,并将图像内容直接注入到模型的上下文中以便分析。
|
||||
|
||||
**激活**:当解析的模型具有 `supports_vision: true` 时自动启用。
|
||||
|
||||
---
|
||||
|
||||
### DeferredToolFilterMiddleware
|
||||
|
||||
当工具搜索启用时,此中间件从模型上下文中隐藏延迟工具 schema。工具通过 `tool_search` 工具按需发现,而不是预先全部列出,从而减少上下文使用。
|
||||
|
||||
**配置**:`config.yaml` 中的 `tool_search.enabled: true`。
|
||||
|
||||
## 摘要压缩配置详解
|
||||
|
||||
`SummarizationMiddleware` 是长时序任务中影响最大的中间件之一。完整配置参考如下:
|
||||
|
||||
```yaml
|
||||
summarization:
|
||||
enabled: true
|
||||
|
||||
# 摘要使用的模型(null = 使用默认模型)
|
||||
# 推荐使用轻量级、经济的模型,如 "gpt-4o-mini"
|
||||
model_name: null
|
||||
|
||||
# 触发条件——满足任意一个条件时运行摘要
|
||||
trigger:
|
||||
- type: tokens # 当上下文超过 N 个 token 时触发
|
||||
value: 15564
|
||||
# - type: messages # 当消息数超过 N 时触发
|
||||
# value: 50
|
||||
# - type: fraction # 当上下文达到模型最大输入的 X% 时触发
|
||||
# value: 0.8
|
||||
|
||||
# 摘要后保留多少最近历史
|
||||
keep:
|
||||
type: messages
|
||||
value: 10 # 保留最近 10 条消息
|
||||
# 或者按 token 保留:
|
||||
# type: tokens
|
||||
# value: 3000
|
||||
|
||||
# 为摘要器准备消息时要裁剪的最大 token 数
|
||||
trim_tokens_to_summarize: 15564
|
||||
|
||||
# 自定义摘要提示词(null = 使用默认 LangChain 提示词)
|
||||
summary_prompt: null
|
||||
```
|
||||
|
||||
**触发类型**:
|
||||
- `tokens`:当对话中总 token 数超过 `value` 时触发。
|
||||
- `messages`:当消息数超过 `value` 时触发。
|
||||
- `fraction`:当上下文达到模型最大输入 token 限制的 `value` 比例时触发。
|
||||
|
||||
**保留类型**:
|
||||
- `messages`:摘要后保留最后 `value` 条消息。
|
||||
- `tokens`:保留最近 `value` 个 token 的历史。
|
||||
- `fraction`:保留模型最大输入 token 限制的 `value` 比例的最近历史。
|
||||
|
||||
## 编写自定义中间件
|
||||
|
||||
自定义中间件可以注入到链中用于专业用途。中间件必须实现 `langchain.agents.middleware` 中的 `AgentMiddleware` 接口:
|
||||
|
||||
```python
|
||||
from langchain.agents.middleware import AgentMiddleware
|
||||
|
||||
class MyMiddleware(AgentMiddleware):
|
||||
async def on_start(self, state, config):
|
||||
# 在模型调用前运行
|
||||
return state, config
|
||||
|
||||
async def on_end(self, state, config):
|
||||
# 在模型调用后运行
|
||||
return state, config
|
||||
```
|
||||
|
||||
自定义中间件在链末尾 `ClarificationMiddleware` 之前注入。
|
||||
@@ -0,0 +1,151 @@
|
||||
import { Callout, Cards, Steps } from "nextra/components";
|
||||
|
||||
# 快速上手
|
||||
|
||||
<Callout type="info" emoji="🚀">
|
||||
本指南介绍如何以编程方式使用 DeerFlow Harness——不是通过应用界面,而是直接在 Python 中导入和调用 Harness。
|
||||
</Callout>
|
||||
|
||||
DeerFlow Harness 是 Python SDK 和运行时基础。本快速上手指南将带你了解运行 Agent、流式传输输出和使用线程的核心 API。
|
||||
|
||||
## 前置条件
|
||||
|
||||
DeerFlow Harness 需要 Python 3.12 或更高版本。该包是 `deerflow` 代码库的一部分,位于 `backend/packages/harness` 下。
|
||||
|
||||
如果你从仓库克隆开始:
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
uv sync
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
所有 Harness 行为由 `config.yaml` 驱动。至少需要配置一个模型:
|
||||
|
||||
```yaml
|
||||
# config.yaml
|
||||
config_version: 6
|
||||
|
||||
models:
|
||||
- name: gpt-4o
|
||||
use: langchain_openai:ChatOpenAI
|
||||
model: gpt-4o
|
||||
api_key: $OPENAI_API_KEY
|
||||
request_timeout: 600.0
|
||||
max_retries: 2
|
||||
|
||||
sandbox:
|
||||
use: deerflow.sandbox.local:LocalSandboxProvider
|
||||
|
||||
tools:
|
||||
- use: deerflow.community.ddg_search.tools:web_search_tool
|
||||
- use: deerflow.community.jina_ai.tools:web_fetch_tool
|
||||
- use: deerflow.sandbox.tools:ls_tool
|
||||
- use: deerflow.sandbox.tools:read_file_tool
|
||||
- use: deerflow.sandbox.tools:write_file_tool
|
||||
- use: deerflow.sandbox.tools:bash_tool
|
||||
```
|
||||
|
||||
将 `config.example.yaml` 复制到 `config.yaml` 并填写你的 API Key。
|
||||
|
||||
## 运行 Harness
|
||||
|
||||
DeerFlow Harness 的主要入口是 `DeerFlowClient`。它管理线程状态、调用 Lead Agent,并流式传输响应。
|
||||
|
||||
<Steps>
|
||||
|
||||
### 导入并配置
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from deerflow.client import DeerFlowClient
|
||||
from deerflow.config import load_config
|
||||
|
||||
# 从当前目录或 DEER_FLOW_CONFIG_PATH 加载 config.yaml
|
||||
load_config()
|
||||
|
||||
client = DeerFlowClient()
|
||||
```
|
||||
|
||||
### 创建线程
|
||||
|
||||
```python
|
||||
thread_id = "my-thread-001"
|
||||
```
|
||||
|
||||
线程 ID 是任意字符串。使用相同 ID 可以继续已有对话(需要配置检查点)。
|
||||
|
||||
### 发送消息并流式传输响应
|
||||
|
||||
```python
|
||||
async def run():
|
||||
async for event in client.astream(
|
||||
thread_id=thread_id,
|
||||
message="研究前三大开源 LLM 框架并进行总结。",
|
||||
config={
|
||||
"configurable": {
|
||||
"model_name": "gpt-4o",
|
||||
"thinking_enabled": False,
|
||||
"is_plan_mode": True,
|
||||
"subagent_enabled": True,
|
||||
}
|
||||
},
|
||||
):
|
||||
print(event)
|
||||
|
||||
asyncio.run(run())
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
## 可配置选项
|
||||
|
||||
`config.configurable` 字典控制每次请求的行为:
|
||||
|
||||
| 键 | 类型 | 默认值 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `model_name` | `str \| None` | 配置中第一个模型 | 本次请求使用的模型 |
|
||||
| `thinking_enabled` | `bool` | `True` | 启用扩展思考模式(如果支持) |
|
||||
| `reasoning_effort` | `str \| None` | `None` | 推理努力程度(特定模型参数) |
|
||||
| `is_plan_mode` | `bool` | `False` | 启用 TodoList 中间件进行任务跟踪 |
|
||||
| `subagent_enabled` | `bool` | `False` | 允许 Agent 委派子任务 |
|
||||
| `max_concurrent_subagents` | `int` | `3` | 每轮最大并行子 Agent 调用数 |
|
||||
| `agent_name` | `str \| None` | `None` | 要加载的自定义 Agent 名称 |
|
||||
|
||||
## 流式事件类型
|
||||
|
||||
`client.astream()` 从 LangGraph 运行时产生事件,主要事件类型如下:
|
||||
|
||||
| 事件类型 | 说明 |
|
||||
|---|---|
|
||||
| `messages` | 消息块(文本、思考过程、工具调用) |
|
||||
| `thread_state` | 线程状态更新(标题、产出物、待办列表) |
|
||||
|
||||
消息块包含 Agent 生成响应时的 token 流。
|
||||
|
||||
## 使用自定义 Agent
|
||||
|
||||
如果已定义自定义 Agent,在 configurable 中传入其 `name`:
|
||||
|
||||
```python
|
||||
async for event in client.astream(
|
||||
thread_id="thread-002",
|
||||
message="分析上传的 CSV 并生成摘要图表。",
|
||||
config={
|
||||
"configurable": {
|
||||
"agent_name": "data-analyst",
|
||||
"subagent_enabled": True,
|
||||
}
|
||||
},
|
||||
):
|
||||
...
|
||||
```
|
||||
|
||||
自定义 Agent 的配置(模型、技能、工具组)将从 `agents/data-analyst/config.yaml` 自动加载。
|
||||
|
||||
<Cards num={3}>
|
||||
<Cards.Card title="设计理念" href="/docs/harness/design-principles" />
|
||||
<Cards.Card title="Lead Agent" href="/docs/harness/lead-agent" />
|
||||
<Cards.Card title="配置" href="/docs/harness/configuration" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,139 @@
|
||||
import { Callout, Cards, Tabs } from "nextra/components";
|
||||
|
||||
# 沙箱
|
||||
|
||||
<Callout type="info" emoji="📦">
|
||||
沙箱是 Agent 进行文件和命令操作的隔离工作区。它让 DeerFlow 能够采取真实行动,而不仅仅是对话。
|
||||
</Callout>
|
||||
|
||||
沙箱为 Lead Agent 提供一个受控环境,在其中可以读取文件、写入输出、运行 Shell 命令并生成产出物。没有沙箱,Agent 只能生成文本;有了沙箱,它可以编写和执行代码、处理数据文件、生成图表并构建交付物。
|
||||
|
||||
## 沙箱模式
|
||||
|
||||
DeerFlow 支持三种沙箱模式,选择适合你部署的一种:
|
||||
|
||||
### LocalSandbox(默认)
|
||||
|
||||
命令直接在主机机器的文件系统上运行,没有容器隔离。
|
||||
|
||||
- **适合**:受信任的单用户本地开发工作流。
|
||||
- **风险**:Agent 可以访问主机文件系统。默认使用 `allow_host_bash: false` 防止任意命令执行。
|
||||
|
||||
```yaml
|
||||
sandbox:
|
||||
use: deerflow.sandbox.local:LocalSandboxProvider
|
||||
allow_host_bash: false # 默认;仅对完全受信任的工作流设置为 true
|
||||
```
|
||||
|
||||
### 基于容器的 AIO 沙箱
|
||||
|
||||
命令在隔离容器中运行(Linux/Windows 上的 Docker,macOS 上的 Apple Container)。每个沙箱会话获得一个全新的容器环境。
|
||||
|
||||
- **适合**:多用户环境、生产部署,或任何需要执行隔离的场景。
|
||||
|
||||
```yaml
|
||||
sandbox:
|
||||
use: deerflow.community.aio_sandbox:AioSandboxProvider
|
||||
|
||||
# 可选:容器镜像(下方显示默认值)
|
||||
image: enterprise-public-cn-beijing.cr.volces.com/vefaas-public/all-in-one-sandbox:latest
|
||||
|
||||
# 可选:最大并发容器数(默认:3,超出时 LRU 淘汰)
|
||||
replicas: 3
|
||||
|
||||
# 可选:空闲超时(秒,默认:600)
|
||||
idle_timeout: 600
|
||||
|
||||
# 可选:自定义挂载
|
||||
mounts:
|
||||
- host_path: /path/on/host
|
||||
container_path: /home/user/shared
|
||||
read_only: false
|
||||
```
|
||||
|
||||
安装:`cd backend && uv add 'deerflow-harness[aio-sandbox]'`
|
||||
|
||||
### Provisioner 管理的沙箱(Kubernetes)
|
||||
|
||||
每个沙箱在 Kubernetes 集群中获得一个专用 Pod,由 Provisioner 服务管理。这提供最强的隔离性,适合有多个并发用户的生产环境。
|
||||
|
||||
```yaml
|
||||
sandbox:
|
||||
use: deerflow.community.aio_sandbox:AioSandboxProvider
|
||||
provisioner_url: http://provisioner:8002
|
||||
```
|
||||
|
||||
## 路径映射
|
||||
|
||||
沙箱使用路径映射来桥接主机文件系统和容器的虚拟文件系统。始终配置两个关键映射:
|
||||
|
||||
| 主机路径 | 容器路径 | 访问权限 |
|
||||
|---|---|---|
|
||||
| `skills/`(来自 `skills.path`) | `/mnt/skills`(来自 `skills.container_path`) | 只读 |
|
||||
| `.deer-flow/threads/{thread_id}/user-data/` | `/mnt/user-data/` | 读写 |
|
||||
|
||||
技能目录始终以只读方式挂载。线程将其工作数据(上传文件、输出、中间文件)写入 `/mnt/user-data/`。
|
||||
|
||||
### 自定义挂载
|
||||
|
||||
你可以为本地沙箱使用 `mounts:` 配置添加额外挂载:
|
||||
|
||||
```yaml
|
||||
sandbox:
|
||||
use: deerflow.sandbox.local:LocalSandboxProvider
|
||||
mounts:
|
||||
- host_path: /home/user/my-project
|
||||
container_path: /mnt/my-project
|
||||
read_only: true
|
||||
```
|
||||
|
||||
<Callout type="warning">
|
||||
自定义挂载的 <code>container_path</code> 不能与保留前缀冲突:
|
||||
<code>/mnt/skills</code>、<code>/mnt/acp-workspace</code> 或 <code>/mnt/user-data</code>。
|
||||
</Callout>
|
||||
|
||||
## 输出截断
|
||||
|
||||
沙箱工具限制输出大小以保持 Agent 上下文可控。这些限制可配置:
|
||||
|
||||
```yaml
|
||||
sandbox:
|
||||
use: deerflow.sandbox.local:LocalSandboxProvider
|
||||
|
||||
# bash 使用中间截断(头部 + 尾部)
|
||||
bash_output_max_chars: 20000
|
||||
|
||||
# read_file 使用头部截断
|
||||
read_file_output_max_chars: 50000
|
||||
|
||||
# ls 使用头部截断
|
||||
ls_output_max_chars: 20000
|
||||
```
|
||||
|
||||
设置为 `0` 禁用截断。
|
||||
|
||||
## 安全性
|
||||
|
||||
### LocalSandbox
|
||||
|
||||
`LocalSandbox` 直接在主机上运行命令。默认情况下,`bash` 工具**被禁用**以防止任意主机命令执行。仅对完全受信任的单用户工作流启用它:
|
||||
|
||||
```yaml
|
||||
sandbox:
|
||||
allow_host_bash: true # 危险:授予 Agent 对你机器的 Shell 访问权限
|
||||
```
|
||||
|
||||
即使没有 `bash`,Agent 也可以通过专用文件工具读写文件。
|
||||
|
||||
### 容器沙箱
|
||||
|
||||
基于容器的沙箱提供文件系统和进程隔离。Agent 看不到或修改主机文件系统,除非通过显式挂载。Provisioner 管理模式增加了额外一层:每个线程获得自己的隔离 Pod。
|
||||
|
||||
### 审计中间件
|
||||
|
||||
`SandboxAuditMiddleware` 在每次 Agent 轮次上运行,记录所有沙箱操作,提供会话期间访问了哪些文件、运行了哪些命令的审计跟踪。
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="工具" href="/docs/harness/tools" />
|
||||
<Cards.Card title="子 Agent" href="/docs/harness/subagents" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,151 @@
|
||||
import { Callout, Cards, FileTree, Steps } from "nextra/components";
|
||||
|
||||
# 技能
|
||||
|
||||
<Callout type="info" emoji="🎯">
|
||||
技能是面向任务的能力包,教会 Agent 如何完成特定类型的工作。基础 Agent 保持通用;技能在需要时提供专业化。
|
||||
</Callout>
|
||||
|
||||
技能不仅仅是提示词。它是一个自包含的能力包,可以包含结构化指令、分步工作流、领域最佳实践、支撑资源和工具配置。技能按需加载——在任务需要时注入内容,否则不影响上下文。
|
||||
|
||||
## 技能包含什么
|
||||
|
||||
每个技能位于 `skills/public/`(或用户创建技能的 `skills/custom/`)下自己的子目录中。目录包含一个 `SKILL.md` 文件,定义技能的元数据、指令和工作流。
|
||||
|
||||
<FileTree>
|
||||
<FileTree.Folder name="skills/" defaultOpen>
|
||||
<FileTree.Folder name="public/" defaultOpen>
|
||||
<FileTree.Folder name="deep-research/" defaultOpen>
|
||||
<FileTree.File name="SKILL.md" />
|
||||
</FileTree.Folder>
|
||||
<FileTree.Folder name="data-analysis/">
|
||||
<FileTree.File name="SKILL.md" />
|
||||
</FileTree.Folder>
|
||||
</FileTree.Folder>
|
||||
<FileTree.Folder name="custom/">
|
||||
<FileTree.File name="(你的自定义技能放在这里)" />
|
||||
</FileTree.Folder>
|
||||
</FileTree.Folder>
|
||||
</FileTree>
|
||||
|
||||
`SKILL.md` 文件是技能的权威定义,由 `skills/parser.py` 解析以提取技能名称、描述、类别、指令以及任何依赖项或工具需求。
|
||||
|
||||
## 内置技能
|
||||
|
||||
DeerFlow 内置以下公共技能:
|
||||
|
||||
| 技能 | 描述 |
|
||||
|---|---|
|
||||
| `deep-research` | 带来源收集、交叉验证和结构化输出的多步骤研究 |
|
||||
| `data-analysis` | 数据探索、统计分析和洞察生成 |
|
||||
| `chart-visualization` | 从数据创建图表和可视化 |
|
||||
| `ppt-generation` | 演示文稿幻灯片生成 |
|
||||
| `image-generation` | AI 图像生成工作流 |
|
||||
| `code-documentation` | 自动化代码文档生成 |
|
||||
| `newsletter-generation` | 新闻简报内容创作 |
|
||||
| `podcast-generation` | 播客脚本和大纲生成 |
|
||||
| `academic-paper-review` | 结构化学术论文分析 |
|
||||
| `consulting-analysis` | 商业咨询框架和分析 |
|
||||
| `systematic-literature-review` | 文献综述方法论和综合 |
|
||||
| `github-deep-research` | 仓库和代码深度研究 |
|
||||
| `frontend-design` | 前端设计和 UI 工作流 |
|
||||
| `web-design-guidelines` | 网页设计标准和审查 |
|
||||
| `video-generation` | 视频内容规划和生成 |
|
||||
|
||||
## 技能生命周期
|
||||
|
||||
<Steps>
|
||||
|
||||
### 发现和加载
|
||||
|
||||
`skills/loader.py` 中的 `load_skills()` 扫描配置技能路径下的 `public/` 和 `custom/` 目录。它每次调用都重新读取 `ExtensionsConfig.from_file()`,这意味着通过 Gateway API 启用或禁用技能会立即在运行中的 LangGraph 服务器中生效,无需重启。
|
||||
|
||||
### 解析
|
||||
|
||||
`parser.py` 读取每个 `SKILL.md` 文件并提取结构化元数据:名称、描述、类别、指令以及任何工具或资源需求。
|
||||
|
||||
### 安全扫描
|
||||
|
||||
`security_scanner.py` 在技能内容加载到 Agent 上下文之前检查潜在危险模式,防止恶意技能内容被注入。
|
||||
|
||||
### 依赖安装
|
||||
|
||||
`installer.py` 处理技能声明的任何 Python 或系统依赖项,在技能首次加载时安装到运行时环境中。
|
||||
|
||||
### 上下文注入
|
||||
|
||||
当 Agent 以特定技能在范围内调用时,技能的指令被注入到系统提示中。Agent 在该对话期间可以访问技能的工作流、最佳实践和领域知识。
|
||||
|
||||
</Steps>
|
||||
|
||||
## 配置
|
||||
|
||||
技能系统在 `config.yaml` 的 `skills:` 下配置:
|
||||
|
||||
```yaml
|
||||
skills:
|
||||
# 主机上的技能目录路径。
|
||||
# 默认:相对于后端目录的 ../skills
|
||||
# 取消注释以自定义:
|
||||
# path: /absolute/path/to/custom/skills
|
||||
|
||||
# 在沙箱容器中挂载技能的路径
|
||||
container_path: /mnt/skills
|
||||
```
|
||||
|
||||
`container_path` 很重要:它告诉 Agent 在沙箱内哪里找到技能文件。Harness 自动将主机技能目录挂载到这个容器路径。
|
||||
|
||||
## 启用和禁用技能
|
||||
|
||||
技能可用性在 `extensions_config.json` 中跟踪(独立于 `config.yaml`)。你可以管理技能状态:
|
||||
|
||||
- **通过 DeerFlow 应用界面**:技能面板允许你切换技能的启用/禁用状态。
|
||||
- **通过 Gateway API**:`POST /api/extensions/skills/{name}/enable` 和 `/disable`。
|
||||
- **直接编辑 `extensions_config.json`**。
|
||||
|
||||
由于 `load_skills()` 每次调用都重新读取扩展配置,更改立即生效——无需重启服务器。
|
||||
|
||||
## 按自定义 Agent 限制技能
|
||||
|
||||
自定义 Agent 可以被限制为特定技能子集。在 Agent 的配置中(存储在 `agents/{name}/config.yaml`),设置 `skills` 列表:
|
||||
|
||||
```yaml
|
||||
# agents/my-researcher/config.yaml
|
||||
name: my-researcher
|
||||
skills:
|
||||
- deep-research
|
||||
- academic-paper-review
|
||||
```
|
||||
|
||||
- **省略或 null**:Agent 加载所有全局启用的技能。
|
||||
- **空列表 `[]`**:Agent 没有技能。
|
||||
- **命名列表**:Agent 只加载那些特定技能。
|
||||
|
||||
## 技能进化
|
||||
|
||||
DeerFlow 包含一个可选的**技能进化**功能,允许 Agent 在 `skills/custom/` 目录中自主创建和改进技能:
|
||||
|
||||
```yaml
|
||||
skill_evolution:
|
||||
enabled: false # 设为 true 允许 Agent 管理技能创建
|
||||
moderation_model_name: null # 安全扫描模型(null = 使用默认模型)
|
||||
```
|
||||
|
||||
<Callout type="warning">
|
||||
只在你信任 Agent 输出的环境中启用技能进化。新创建的技能在加载前会经过安全扫描,但该功能给予 Agent 对技能目录的写访问权限。
|
||||
</Callout>
|
||||
|
||||
## 编写自定义技能
|
||||
|
||||
要创建自定义技能:
|
||||
|
||||
1. 在 `skills/custom/your-skill-name/` 下创建新目录
|
||||
2. 添加定义技能元数据和指令的 `SKILL.md` 文件
|
||||
3. 技能将在下次 `load_skills()` 调用时自动被发现
|
||||
|
||||
`SKILL.md` 格式遵循与内置技能相同的结构。使用现有公共技能之一作为预期格式的参考。
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="沙箱" href="/docs/harness/sandbox" />
|
||||
<Cards.Card title="工具" href="/docs/harness/tools" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,119 @@
|
||||
import { Callout, Cards } from "nextra/components";
|
||||
|
||||
# 子 Agent
|
||||
|
||||
<Callout type="info" emoji="👥">
|
||||
子 Agent 是 Lead Agent 委派子任务的专注执行者。它们以隔离的上下文运行,在处理并行或专业工作的同时保持主对话清晰。
|
||||
</Callout>
|
||||
|
||||
当一个任务对单个推理线程来说太宽泛,或者部分任务可以并行完成时,Lead Agent 将工作委派给**子 Agent**。子 Agent 是一个独立的 Agent 调用,接收特定任务、执行并返回结果。
|
||||
|
||||
## 为什么子 Agent 很重要
|
||||
|
||||
子 Agent 解决了长时序工作流中的两个关键问题:
|
||||
|
||||
1. **上下文隔离**:子 Agent 只看到完成其任务所需的信息,而不是整个父对话。这保持了每个 Agent 的工作上下文专注且可控。
|
||||
2. **并行性**:多个子 Agent 可以并发运行,允许任务的独立部分(例如同时研究多个话题)并行处理。
|
||||
|
||||
## 内置子 Agent
|
||||
|
||||
DeerFlow 内置两个子 Agent:
|
||||
|
||||
### general-purpose
|
||||
|
||||
通用推理和执行 Agent,适合委派需要多步骤推理、网络搜索、文件操作和产出物生成的复杂子任务。
|
||||
|
||||
- **默认超时**:900 秒(15 分钟)
|
||||
- **默认最大轮次**:160
|
||||
|
||||
### bash
|
||||
|
||||
专门用于在沙箱内执行命令行任务的子 Agent,适合脚本编写、数据处理、文件转换和环境设置任务。
|
||||
|
||||
- **默认超时**:900 秒(15 分钟)
|
||||
- **默认最大轮次**:80
|
||||
- **可用性**:仅当沙箱的 `bash` 工具可用时才暴露(`allow_host_bash: true` 或配置了容器沙箱)
|
||||
|
||||
## 委派流程
|
||||
|
||||
Lead Agent 使用内置 `task` 工具将工作委派给子 Agent:
|
||||
|
||||
```
|
||||
task(
|
||||
agent="general-purpose",
|
||||
task="研究 Acme Corp 的前 5 个竞争对手并总结其定价",
|
||||
context="专注于 B2B SaaS 定价模型"
|
||||
)
|
||||
```
|
||||
|
||||
运行时然后:
|
||||
|
||||
1. 从注册表查找子 Agent 配置,应用任何 `config.yaml` 覆盖。
|
||||
2. 用子 Agent 自己的提示词和工具创建新的 Agent 调用。
|
||||
3. 将子 Agent 运行到完成(或直到超时/最大轮次)。
|
||||
4. 将子 Agent 的最终输出作为工具结果返回给 Lead Agent。
|
||||
|
||||
## 配置
|
||||
|
||||
子 Agent 超时和最大轮次通过 `config.yaml` 中的 `subagents:` 部分控制:
|
||||
|
||||
```yaml
|
||||
subagents:
|
||||
# 所有子 Agent 的默认超时(秒,默认:900 = 15 分钟)
|
||||
timeout_seconds: 900
|
||||
|
||||
# 可选:覆盖所有子 Agent 的最大轮次
|
||||
# max_turns: 120
|
||||
|
||||
# 可选:按 Agent 覆盖
|
||||
agents:
|
||||
general-purpose:
|
||||
timeout_seconds: 1800 # 复杂任务 30 分钟
|
||||
max_turns: 160
|
||||
bash:
|
||||
timeout_seconds: 300 # 快速命令 5 分钟
|
||||
max_turns: 80
|
||||
```
|
||||
|
||||
按 Agent 覆盖优先于全局 `timeout_seconds` 和 `max_turns` 设置。
|
||||
|
||||
## 并发限制
|
||||
|
||||
`SubagentLimitMiddleware` 控制 Lead Agent 在单次轮次中可以并行调用多少个子 Agent,通过每次请求的配置控制:
|
||||
|
||||
- `subagent_enabled`:是否为此会话激活子 Agent 委派
|
||||
- `max_concurrent_subagents`:单次轮次中最大并行任务调用数(默认:3)
|
||||
|
||||
如果 Agent 尝试调用超过限制的子 Agent,中间件会裁剪多余的调用。
|
||||
|
||||
## ACP Agent(外部 Agent)
|
||||
|
||||
除内置子 Agent 外,DeerFlow 还通过 **Agent Connect Protocol (ACP)** 支持委派给外部 Agent。ACP 允许 DeerFlow 调用作为独立进程运行的 Agent(包括用 ACP 适配器包装的第三方 CLI 工具)。
|
||||
|
||||
在 `config.yaml` 中配置 ACP Agent:
|
||||
|
||||
```yaml
|
||||
acp_agents:
|
||||
claude_code:
|
||||
command: npx
|
||||
args: ["-y", "@zed-industries/claude-agent-acp"]
|
||||
description: 用于实现、重构和调试的 Claude Code
|
||||
model: null
|
||||
|
||||
codex:
|
||||
command: npx
|
||||
args: ["-y", "@zed-industries/codex-acp"]
|
||||
description: 用于仓库任务和代码生成的 Codex CLI
|
||||
model: null
|
||||
```
|
||||
|
||||
Lead Agent 通过 `invoke_acp_agent` 内置工具调用 ACP Agent。
|
||||
|
||||
<Callout type="tip">
|
||||
ACP Agent 作为 DeerFlow 管理的子进程运行,通过 ACP 协议通信。标准 CLI 工具(如原始的 `claude` 或 `codex` 命令)默认不兼容 ACP——请使用上面列出的适配器包或兼容的 ACP 封装器。
|
||||
</Callout>
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="沙箱" href="/docs/harness/sandbox" />
|
||||
<Cards.Card title="MCP 集成" href="/docs/harness/mcp" />
|
||||
</Cards>
|
||||
@@ -0,0 +1,205 @@
|
||||
import { Callout, Cards, Tabs } from "nextra/components";
|
||||
|
||||
# 工具
|
||||
|
||||
<Callout type="info" emoji="🔧">
|
||||
工具是 Lead Agent 可以采取的行动。DeerFlow 提供内置工具、社区集成、MCP 工具和技能工具——全部通过 <code>config.yaml</code> 控制。
|
||||
</Callout>
|
||||
|
||||
Lead Agent 是一个工具调用 Agent。工具是它与世界交互的方式:搜索网络、读写文件、运行命令、委派任务以及向用户呈现输出。
|
||||
|
||||
DeerFlow 将工具分为四类:
|
||||
|
||||
1. **内置工具** — 核心运行时能力,始终对 Agent 可用
|
||||
2. **社区工具** — 与外部搜索、抓取和图像服务的集成
|
||||
3. **MCP 工具** — 由外部 Model Context Protocol 服务器提供的工具
|
||||
4. **技能工具** — 与特定技能包捆绑的工具
|
||||
|
||||
## 内置工具
|
||||
|
||||
内置工具是 Harness 的一部分,无需配置即可使用。
|
||||
|
||||
### task
|
||||
|
||||
将子任务委派给子 Agent。当任务对单个推理线程来说太宽泛,或并行工作有利时,Lead Agent 使用此工具。
|
||||
|
||||
```
|
||||
task(agent="general-purpose", task="...", context="...")
|
||||
```
|
||||
|
||||
参见[子 Agent](/docs/harness/subagents)页面了解子 Agent 的配置方式。
|
||||
|
||||
---
|
||||
|
||||
### present_files
|
||||
|
||||
将输出文件作为产出物呈现给用户。Agent 在生成文件(报告、图表、代码等)后调用此工具,将其显示在对话中。
|
||||
|
||||
---
|
||||
|
||||
### view_image
|
||||
|
||||
读取图像文件并将其内容注入到模型的上下文中进行视觉分析。仅当活跃模型具有 `supports_vision: true` 时可用。
|
||||
|
||||
---
|
||||
|
||||
### clarification
|
||||
|
||||
在继续之前向用户提问。当模型认为没有足够信息来行动时,由 `ClarificationMiddleware` 触发。
|
||||
|
||||
---
|
||||
|
||||
### setup_agent
|
||||
|
||||
动态配置当前 Agent 会话。在设置新自定义 Agent 的引导流程中使用。
|
||||
|
||||
---
|
||||
|
||||
### invoke_acp_agent
|
||||
|
||||
使用 [Agent Connect Protocol (ACP)](https://agentconnectprotocol.org/) 调用外部 Agent。需要在 `config.yaml` 中配置 `acp_agents:`。参见[子 Agent](/docs/harness/subagents)页面了解 ACP 配置。
|
||||
|
||||
---
|
||||
|
||||
### tool_search
|
||||
|
||||
按名称或描述搜索工具,并按需将其加载到 Agent 上下文中。仅当 `config.yaml` 中 `tool_search.enabled: true` 时激活。当 MCP 或其他工具集暴露大量工具且你希望减少上下文使用时很有用。
|
||||
|
||||
## 沙箱文件工具
|
||||
|
||||
以下工具与沙箱文件系统交互,需要配置并激活沙箱。
|
||||
|
||||
| 工具 | 描述 |
|
||||
|---|---|
|
||||
| `ls` | 列出目录中的文件 |
|
||||
| `read_file` | 读取文件内容 |
|
||||
| `glob` | 查找匹配模式的文件 |
|
||||
| `grep` | 搜索文件内容 |
|
||||
| `write_file` | 向文件写入内容 |
|
||||
| `str_replace` | 替换文件中的字符串 |
|
||||
| `bash` | 执行 Shell 命令(需要 `allow_host_bash: true` 或容器沙箱) |
|
||||
|
||||
在 `config.yaml` 的 `tools:` 下配置:
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
- use: deerflow.sandbox.tools:ls_tool
|
||||
- use: deerflow.sandbox.tools:read_file_tool
|
||||
- use: deerflow.sandbox.tools:glob_tool
|
||||
- use: deerflow.sandbox.tools:grep_tool
|
||||
- use: deerflow.sandbox.tools:write_file_tool
|
||||
- use: deerflow.sandbox.tools:str_replace_tool
|
||||
- use: deerflow.sandbox.tools:bash_tool
|
||||
```
|
||||
|
||||
## 社区工具
|
||||
|
||||
社区工具将 Agent 连接到外部服务。在 `config.yaml` 的 `tools:` 下使用 `use:` 字段指定实现来配置。
|
||||
|
||||
### 网络搜索
|
||||
|
||||
<Tabs items={["DuckDuckGo(默认)", "Tavily", "Exa", "Firecrawl"]}>
|
||||
<Tabs.Tab>
|
||||
```yaml
|
||||
tools:
|
||||
- use: deerflow.community.ddg_search.tools:web_search_tool
|
||||
```
|
||||
无需 API Key。默认配置,适合开发和通用用途。
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab>
|
||||
```yaml
|
||||
tools:
|
||||
- use: deerflow.community.tavily.tools:web_search_tool
|
||||
api_key: $TAVILY_API_KEY
|
||||
```
|
||||
高质量搜索,带结构化结果。需要 [Tavily](https://tavily.com) API Key。
|
||||
|
||||
安装:`cd backend && uv add 'deerflow-harness[tavily]'`
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab>
|
||||
```yaml
|
||||
tools:
|
||||
- use: deerflow.community.exa.tools:web_search_tool
|
||||
api_key: $EXA_API_KEY
|
||||
```
|
||||
带神经检索的语义搜索。需要 [Exa](https://exa.ai) API Key。
|
||||
|
||||
安装:`cd backend && uv add 'deerflow-harness[exa]'`
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab>
|
||||
```yaml
|
||||
tools:
|
||||
- use: deerflow.community.firecrawl.tools:web_search_tool
|
||||
api_key: $FIRECRAWL_API_KEY
|
||||
```
|
||||
Firecrawl 驱动的搜索和爬取。需要 [Firecrawl](https://firecrawl.dev) API Key。
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
|
||||
### 网页内容抓取
|
||||
|
||||
<Tabs items={["Jina AI(默认)", "Exa"]}>
|
||||
<Tabs.Tab>
|
||||
```yaml
|
||||
tools:
|
||||
- use: deerflow.community.jina_ai.tools:web_fetch_tool
|
||||
api_key: $JINA_API_KEY # 可选;匿名使用有速率限制
|
||||
```
|
||||
将网页转换为干净的 Markdown。无 API Key 也可使用,但有更严格的速率限制。
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab>
|
||||
```yaml
|
||||
tools:
|
||||
- use: deerflow.community.exa.tools:web_fetch_tool
|
||||
api_key: $EXA_API_KEY
|
||||
```
|
||||
</Tabs.Tab>
|
||||
</Tabs>
|
||||
|
||||
### 图像搜索
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
- use: deerflow.community.image_search.tools:image_search_tool
|
||||
```
|
||||
|
||||
## 工具组
|
||||
|
||||
工具组允许你将工具组织为命名集合,并限制自定义 Agent 可以访问哪些组:
|
||||
|
||||
```yaml
|
||||
tool_groups:
|
||||
- name: research
|
||||
tools:
|
||||
- web_search
|
||||
- web_fetch
|
||||
- image_search
|
||||
- name: coding
|
||||
tools:
|
||||
- bash
|
||||
- read_file
|
||||
- write_file
|
||||
- str_replace
|
||||
- glob
|
||||
- grep
|
||||
```
|
||||
|
||||
自定义 Agent 然后可以在其配置中按名称引用组,将其工具访问限制为仅相关集合。
|
||||
|
||||
## 工具搜索(延迟加载)
|
||||
|
||||
当有许多工具时(特别是来自多个 MCP 服务器),预先加载所有工具会增加上下文使用量并可能混淆模型。工具搜索功能解决了这个问题:
|
||||
|
||||
```yaml
|
||||
tool_search:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
启用后,工具不会直接列在模型上下文中。相反,它们在运行时通过 `tool_search` 内置工具按需发现,Agent 按名称或描述搜索,匹配的工具按需加载到上下文中。
|
||||
|
||||
当 MCP 服务器暴露数十个工具时特别有用。
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="MCP 集成" href="/docs/harness/mcp" />
|
||||
<Cards.Card title="技能" href="/docs/harness/skills" />
|
||||
</Cards>
|
||||
Reference in New Issue
Block a user