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
JeffJiang
parent
716cae20c6
commit
814a488bcb
@@ -1,3 +1,170 @@
|
||||
import { Callout, Cards } from "nextra/components";
|
||||
|
||||
# Customization
|
||||
|
||||
TBD
|
||||
<Callout type="info" emoji="🔧">
|
||||
DeerFlow is designed to be adapted. You can extend agent behavior by writing
|
||||
custom middlewares, adding new tools, building skill packs, and replacing any
|
||||
built-in component through the config.yaml <code>use:</code> field.
|
||||
</Callout>
|
||||
|
||||
DeerFlow's pluggable architecture means most parts of the system can be replaced or extended without forking the core. This page maps the extension points and explains how to use each one.
|
||||
|
||||
## Custom middlewares
|
||||
|
||||
Middlewares are the primary extension point for adding behavior to the Lead Agent. They wrap every LLM turn and can read and modify the agent's state before or after the model call.
|
||||
|
||||
To add a custom middleware:
|
||||
|
||||
1. Implement the `AgentMiddleware` interface from `langchain.agents.middleware`.
|
||||
2. Pass your middleware to the `custom_middlewares` parameter when building the agent.
|
||||
|
||||
```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):
|
||||
# Runs before each model call
|
||||
print(f"[audit] turn starts: {len(state.messages)} messages in context")
|
||||
return state, config
|
||||
|
||||
async def on_end(self, state: ThreadState, config):
|
||||
# Runs after each model call
|
||||
print(f"[audit] turn ends: last message type = {state.messages[-1].type}")
|
||||
return state, config
|
||||
```
|
||||
|
||||
Custom middlewares are injected into the chain immediately before `ClarificationMiddleware`, which always runs last.
|
||||
|
||||
## Custom tools
|
||||
|
||||
Add new tools to the agent by registering them in `config.yaml` under `tools:`:
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
- use: mypackage.tools:my_custom_tool
|
||||
api_key: $MY_TOOL_API_KEY
|
||||
```
|
||||
|
||||
Your tool must be a LangChain `BaseTool` or a function decorated with `@tool`. It will be instantiated using the `use:` class path and any additional fields from the config entry.
|
||||
|
||||
For community-style tools, the pattern is a module-level function or class that returns a `BaseTool`:
|
||||
|
||||
```python
|
||||
# mypackage/tools.py
|
||||
from langchain_core.tools import tool
|
||||
|
||||
@tool
|
||||
def my_custom_tool(query: str) -> str:
|
||||
"""Search my custom data source."""
|
||||
return do_search(query)
|
||||
```
|
||||
|
||||
## Custom sandbox provider
|
||||
|
||||
The sandbox can be replaced by implementing the `SandboxProvider` interface:
|
||||
|
||||
```python
|
||||
from deerflow.sandbox.sandbox_provider import SandboxProvider
|
||||
from deerflow.sandbox.sandbox import Sandbox
|
||||
|
||||
class MyCustomSandboxProvider(SandboxProvider):
|
||||
def acquire(self, thread_id: str | None = None) -> str:
|
||||
# Return a sandbox_id
|
||||
...
|
||||
|
||||
def get(self, sandbox_id: str) -> Sandbox | None:
|
||||
# Return the sandbox instance for this id
|
||||
...
|
||||
|
||||
def release(self, sandbox_id: str) -> None:
|
||||
# Cleanup
|
||||
...
|
||||
```
|
||||
|
||||
Then reference it in `config.yaml`:
|
||||
|
||||
```yaml
|
||||
sandbox:
|
||||
use: mypackage.sandbox:MyCustomSandboxProvider
|
||||
```
|
||||
|
||||
## Custom memory storage
|
||||
|
||||
Replace the file-based memory with any persistent store by implementing `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:
|
||||
...
|
||||
```
|
||||
|
||||
Configure it in `config.yaml`:
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
storage_class: mypackage.storage:RedisMemoryStorage
|
||||
```
|
||||
|
||||
## Custom skills
|
||||
|
||||
Skills are the easiest extension point. Create a directory under `skills/custom/your-skill-name/` with a `SKILL.md` file. The skill is discovered automatically on the next `load_skills()` call.
|
||||
|
||||
See [Skills](/docs/harness/skills) for the full directory structure and `SKILL.md` format.
|
||||
|
||||
## Custom models
|
||||
|
||||
Any LangChain-compatible chat model can be used by specifying it in the `use:` field:
|
||||
|
||||
```yaml
|
||||
models:
|
||||
- name: my-custom-model
|
||||
use: mypackage.models:MyCustomChatModel
|
||||
# Any extra fields are passed as kwargs to the constructor
|
||||
base_url: http://my-model-server:8080
|
||||
api_key: $MY_MODEL_API_KEY
|
||||
```
|
||||
|
||||
The model class must implement the LangChain `BaseChatModel` interface.
|
||||
|
||||
## Custom checkpointer
|
||||
|
||||
Thread state persistence can use any LangGraph-compatible checkpointer:
|
||||
|
||||
```yaml
|
||||
checkpointer:
|
||||
type: sqlite
|
||||
connection_string: ./my-checkpoints.db
|
||||
```
|
||||
|
||||
For custom backends, implement the LangGraph `BaseCheckpointSaver` interface and configure it programmatically when initializing the `DeerFlowClient`.
|
||||
|
||||
## Guardrails
|
||||
|
||||
Add pre-execution authorization for tool calls through the `guardrails:` config:
|
||||
|
||||
```yaml
|
||||
guardrails:
|
||||
enabled: true
|
||||
provider:
|
||||
use: deerflow.guardrails.builtin:AllowlistProvider
|
||||
config:
|
||||
denied_tools: ["bash", "write_file"]
|
||||
```
|
||||
|
||||
For custom guardrail logic, implement a class with `evaluate()` and `aevaluate()` methods and reference it via `use:`.
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="Integration Guide" href="/docs/harness/integration-guide" />
|
||||
<Cards.Card title="Configuration" href="/docs/harness/configuration" />
|
||||
</Cards>
|
||||
|
||||
@@ -1,3 +1,175 @@
|
||||
import { Callout, Cards } from "nextra/components";
|
||||
|
||||
# Integration Guide
|
||||
|
||||
TBD
|
||||
<Callout type="info" emoji="🔌">
|
||||
DeerFlow Harness can be embedded into any Python application. This guide
|
||||
covers the integration patterns for using DeerFlow as a library inside your
|
||||
own system.
|
||||
</Callout>
|
||||
|
||||
DeerFlow Harness is not only a standalone application. It is a Python library you can import and use inside your own backend, API server, automation system, or multi-agent orchestrator.
|
||||
|
||||
## Embedding DeerFlowClient
|
||||
|
||||
The primary integration point is `DeerFlowClient`. It wraps the LangGraph runtime and exposes a clean API for sending messages and streaming responses from any Python application.
|
||||
|
||||
```python
|
||||
from deerflow.client import DeerFlowClient
|
||||
from deerflow.config import load_config
|
||||
|
||||
# Load configuration (reads config.yaml or DEER_FLOW_CONFIG_PATH)
|
||||
load_config()
|
||||
|
||||
client = DeerFlowClient()
|
||||
```
|
||||
|
||||
The client is thread-safe and designed to be instantiated once and reused across requests.
|
||||
|
||||
## Async streaming
|
||||
|
||||
The recommended integration pattern is async streaming. This gives you real-time access to each token and event as the agent produces it:
|
||||
|
||||
```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,
|
||||
}
|
||||
},
|
||||
):
|
||||
# Process each streaming event
|
||||
yield event
|
||||
|
||||
# In a FastAPI handler:
|
||||
# from fastapi.responses import StreamingResponse
|
||||
# return StreamingResponse(run_agent(thread_id, message), media_type="text/event-stream")
|
||||
```
|
||||
|
||||
## Non-streaming invocation
|
||||
|
||||
For batch processing or when you only need the final result:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
## Thread management
|
||||
|
||||
Threads represent persistent conversations. Use unique thread IDs to isolate different user sessions:
|
||||
|
||||
```python
|
||||
import uuid
|
||||
|
||||
# New conversation
|
||||
thread_id = str(uuid.uuid4())
|
||||
|
||||
# Continuing an existing conversation (same thread_id)
|
||||
# The agent will see the full history if a checkpointer is configured
|
||||
await client.ainvoke(thread_id=existing_thread_id, message="Follow up question")
|
||||
```
|
||||
|
||||
## Custom per-agent configuration
|
||||
|
||||
Build domain-specific agents by creating named agent configs and passing the `agent_name` at runtime:
|
||||
|
||||
```python
|
||||
# agents/research-assistant/config.yaml must exist with skills and tool config
|
||||
|
||||
result = await client.ainvoke(
|
||||
thread_id=thread_id,
|
||||
message=user_message,
|
||||
config={
|
||||
"configurable": {
|
||||
"agent_name": "research-assistant",
|
||||
"model_name": "gpt-4o",
|
||||
}
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
## Integrating with FastAPI
|
||||
|
||||
DeerFlow Gateway is itself a FastAPI application. You can mount it as a sub-application or router:
|
||||
|
||||
```python
|
||||
from fastapi import FastAPI
|
||||
from deerflow.config import load_config
|
||||
|
||||
load_config()
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# Mount the DeerFlow gateway router
|
||||
from deerflow.app.gateway.main import app as gateway_app
|
||||
app.mount("/deerflow", gateway_app)
|
||||
```
|
||||
|
||||
Or use `DeerFlowClient` directly in your own FastAPI routes with streaming:
|
||||
|
||||
```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")
|
||||
```
|
||||
|
||||
## Integrating with LangGraph
|
||||
|
||||
DeerFlow Harness is built on LangGraph. The Lead Agent is a standard LangGraph graph. You can compose it with your own LangGraph nodes and graphs:
|
||||
|
||||
```python
|
||||
from deerflow.agents.lead_agent.agent import make_lead_agent
|
||||
from langgraph.graph import StateGraph
|
||||
|
||||
# Access the underlying LangGraph agent factory
|
||||
agent = make_lead_agent(config)
|
||||
```
|
||||
|
||||
## Configuration in embedded mode
|
||||
|
||||
When embedded in another application, set the config path explicitly to avoid ambiguity:
|
||||
|
||||
```python
|
||||
import os
|
||||
os.environ["DEER_FLOW_CONFIG_PATH"] = "/path/to/my-deerflow-config.yaml"
|
||||
|
||||
from deerflow.config import load_config
|
||||
load_config()
|
||||
```
|
||||
|
||||
Or pass the path directly:
|
||||
|
||||
```python
|
||||
from deerflow.config import load_config
|
||||
load_config(config_path="/path/to/my-deerflow-config.yaml")
|
||||
```
|
||||
|
||||
## MCP server integration
|
||||
|
||||
DeerFlow can expose its agent as an MCP server, allowing other MCP-compatible systems to call it as a tool. Refer to the DeerFlow repository for MCP server integration examples.
|
||||
|
||||
<Cards num={2}>
|
||||
<Cards.Card title="Customization" href="/docs/harness/customization" />
|
||||
<Cards.Card title="Configuration" href="/docs/harness/configuration" />
|
||||
</Cards>
|
||||
|
||||
@@ -1,3 +1,155 @@
|
||||
import { Callout, Cards, Steps } from "nextra/components";
|
||||
|
||||
# Quick Start
|
||||
|
||||
TBD
|
||||
<Callout type="info" emoji="🚀">
|
||||
This guide shows you how to use the DeerFlow Harness programmatically — not
|
||||
through the App UI, but by importing and calling the harness directly in
|
||||
Python.
|
||||
</Callout>
|
||||
|
||||
The DeerFlow Harness is the Python SDK and runtime foundation. This quick start walks you through the key APIs for running an agent, streaming its output, and working with threads.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
DeerFlow Harness requires Python 3.12 or later. The package is part of the `deerflow` repository under `backend/packages/harness`.
|
||||
|
||||
If you are working from the repository clone:
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
uv sync
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
All harness behaviors are driven by `config.yaml`. At minimum, you need at least one model configured:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Copy `config.example.yaml` to `config.yaml` and fill in your API key.
|
||||
|
||||
## Running the harness
|
||||
|
||||
The primary entry point for the DeerFlow Harness is `DeerFlowClient`. It manages thread state, invokes the Lead Agent, and streams the response.
|
||||
|
||||
<Steps>
|
||||
|
||||
### Import and configure
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from deerflow.client import DeerFlowClient
|
||||
from deerflow.config import load_config
|
||||
|
||||
# Load config.yaml from the current directory or DEER_FLOW_CONFIG_PATH
|
||||
load_config()
|
||||
|
||||
client = DeerFlowClient()
|
||||
```
|
||||
|
||||
### Create a thread
|
||||
|
||||
```python
|
||||
thread_id = "my-thread-001"
|
||||
```
|
||||
|
||||
Thread IDs are arbitrary strings. Reusing the same ID continues the existing conversation (if a checkpointer is configured).
|
||||
|
||||
### Send a message and stream the response
|
||||
|
||||
```python
|
||||
async def run():
|
||||
async for event in client.astream(
|
||||
thread_id=thread_id,
|
||||
message="Research the top 3 open-source LLM frameworks and summarize them.",
|
||||
config={
|
||||
"configurable": {
|
||||
"model_name": "gpt-4o",
|
||||
"thinking_enabled": False,
|
||||
"is_plan_mode": True,
|
||||
"subagent_enabled": True,
|
||||
}
|
||||
},
|
||||
):
|
||||
print(event)
|
||||
|
||||
asyncio.run(run())
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
## Configurable options
|
||||
|
||||
The `config.configurable` dict controls per-request behavior:
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `model_name` | `str \| None` | first model in config | Model to use for this request |
|
||||
| `thinking_enabled` | `bool` | `True` | Enable extended thinking mode (if supported) |
|
||||
| `reasoning_effort` | `str \| None` | `None` | Reasoning effort level (model-specific) |
|
||||
| `is_plan_mode` | `bool` | `False` | Enable TodoList middleware for task tracking |
|
||||
| `subagent_enabled` | `bool` | `False` | Allow the agent to delegate subtasks |
|
||||
| `max_concurrent_subagents` | `int` | `3` | Maximum parallel subagent calls per turn |
|
||||
| `agent_name` | `str \| None` | `None` | Name of a custom agent to load |
|
||||
|
||||
## Streaming event types
|
||||
|
||||
`client.astream()` yields events from the LangGraph runtime. The key event types are:
|
||||
|
||||
| Event type | Description |
|
||||
|---|---|
|
||||
| `messages` | Individual message chunks (text, thinking, tool calls) |
|
||||
| `thread_state` | Thread state updates (title, artifacts, todo list) |
|
||||
|
||||
Message chunks contain the token stream as the agent generates its response.
|
||||
|
||||
## Working with a custom agent
|
||||
|
||||
If you have defined a custom agent, pass its `name` in the configurable:
|
||||
|
||||
```python
|
||||
async for event in client.astream(
|
||||
thread_id="thread-002",
|
||||
message="Analyze the attached CSV and generate a summary chart.",
|
||||
config={
|
||||
"configurable": {
|
||||
"agent_name": "data-analyst",
|
||||
"subagent_enabled": True,
|
||||
}
|
||||
},
|
||||
):
|
||||
...
|
||||
```
|
||||
|
||||
The custom agent's configuration (model, skills, tool groups) is loaded automatically from `agents/data-analyst/config.yaml`.
|
||||
|
||||
## Next steps
|
||||
|
||||
<Cards num={3}>
|
||||
<Cards.Card title="Design Principles" href="/docs/harness/design-principles" />
|
||||
<Cards.Card title="Lead Agent" href="/docs/harness/lead-agent" />
|
||||
<Cards.Card title="Configuration" href="/docs/harness/configuration" />
|
||||
</Cards>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Callout } from "nextra/components";
|
||||
|
||||
# API / Gateway Reference
|
||||
|
||||
<Callout type="info">
|
||||
@@ -39,21 +41,13 @@ http://localhost:2026/api
|
||||
|
||||
### Threads and memory
|
||||
|
||||
| Method | Path | Description |
|
||||
| -------- | ----------------------------- | -------------------------------------------------- |
|
||||
| `GET` | `/api/threads` | List threads |
|
||||
| `DELETE` | `/api/threads/{thread_id}` | Delete a thread |
|
||||
| `GET` | `/api/memory` | Get global memory data (context + facts) |
|
||||
| `DELETE` | `/api/memory` | Clear all memory data |
|
||||
| `POST` | `/api/memory/reload` | Reload memory from storage file |
|
||||
| `GET` | `/api/memory/facts` | (included in `/api/memory` response `facts` array) |
|
||||
| `POST` | `/api/memory/facts` | Create a memory fact |
|
||||
| `PATCH` | `/api/memory/facts/{fact_id}` | Update a memory fact |
|
||||
| `DELETE` | `/api/memory/facts/{fact_id}` | Delete a memory fact |
|
||||
| `GET` | `/api/memory/export` | Export memory data as JSON |
|
||||
| `POST` | `/api/memory/import` | Import and overwrite memory data |
|
||||
| `GET` | `/api/memory/config` | Get memory configuration |
|
||||
| `GET` | `/api/memory/status` | Get memory config + data in one request |
|
||||
| Method | Path | Description |
|
||||
| -------- | -------------------------- | ------------------------- |
|
||||
| `GET` | `/api/threads` | List threads |
|
||||
| `DELETE` | `/api/threads/{thread_id}` | Delete a thread |
|
||||
| `GET` | `/api/memory` | Get global memory |
|
||||
| `GET` | `/api/memory/{agent_name}` | Get agent-specific memory |
|
||||
| `DELETE` | `/api/memory` | Clear global memory |
|
||||
|
||||
### Extensions
|
||||
|
||||
|
||||
@@ -1,3 +1,67 @@
|
||||
import { Callout } from "nextra/components";
|
||||
|
||||
# Concepts Glossary
|
||||
|
||||
TBD
|
||||
This glossary defines the core terms used throughout the DeerFlow documentation.
|
||||
|
||||
---
|
||||
|
||||
## Agent
|
||||
|
||||
In DeerFlow, an agent is the primary processing unit that receives user messages, decides what actions to take (tool calls or direct responses), and generates output. DeerFlow uses a two-tier architecture with a **Lead Agent** and **Subagents**.
|
||||
|
||||
## Artifact
|
||||
|
||||
A file produced by the agent — a report, chart, code file, or other deliverable. Artifacts are exposed via the `present_files` tool and persisted in the thread's user-data directory.
|
||||
|
||||
## Checkpoint
|
||||
|
||||
A persisted snapshot of thread state, saved after each agent turn. Checkpoints allow conversations to resume after server restarts and support state management for long-horizon tasks.
|
||||
|
||||
## Context Engineering
|
||||
|
||||
The practice of controlling what the agent sees, remembers, and ignores at each step — through summarization, scoped subagent contexts, and external file memory — to keep the agent effective over long-horizon tasks.
|
||||
|
||||
## Harness
|
||||
|
||||
An opinionated agent runtime that packages tool access, skill loading, sandbox execution, memory, subagent coordination, and context management — rather than just exposing abstractions.
|
||||
|
||||
## Lead Agent
|
||||
|
||||
The primary executor in each DeerFlow thread, responsible for planning, tool calls, and response generation. Built on LangGraph + LangChain Agent, augmented by the middleware chain.
|
||||
|
||||
## Long-horizon Agent
|
||||
|
||||
An agent that remains useful across a chain of actions — making plans, calling tools many times, managing intermediate files, and producing a final artifact — rather than producing only a single answer.
|
||||
|
||||
## Memory
|
||||
|
||||
Structured facts and user context that persists across independent conversation sessions, injected into the agent's system prompt in subsequent sessions.
|
||||
|
||||
## Middleware
|
||||
|
||||
A plugin that wraps every LLM call, able to read and modify agent state before and after the model invocation. DeerFlow uses middleware for memory, summarization, title generation, and other cross-cutting behaviors.
|
||||
|
||||
## MCP (Model Context Protocol)
|
||||
|
||||
An open standard for connecting language models to external tools and data sources. DeerFlow's MCP integration allows connection to any compatible tool server.
|
||||
|
||||
## Sandbox
|
||||
|
||||
The isolated execution environment where the agent performs file and command-based work. DeerFlow supports local (`LocalSandboxProvider`) and container-based (`AioSandboxProvider`) sandbox modes.
|
||||
|
||||
## Skill
|
||||
|
||||
A task-oriented capability pack containing structured instructions, workflows, and best practices, loaded into the agent's context on demand. Skills provide specialization without polluting the general agent context.
|
||||
|
||||
## Subagent
|
||||
|
||||
A focused worker that handles a delegated subtask, running with an isolated context that contains only the information needed to complete its assigned work.
|
||||
|
||||
## Thread
|
||||
|
||||
The complete encapsulation of a conversation and all its associated state — message history, artifacts, todo list, and checkpoint data.
|
||||
|
||||
## ThreadState
|
||||
|
||||
The LangGraph-managed state object in DeerFlow, containing `messages`, `artifacts`, `todo_list`, and runtime metadata.
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Callout } from "nextra/components";
|
||||
|
||||
# Configuration Reference
|
||||
|
||||
This page is the complete reference for all top-level fields in `config.yaml`.
|
||||
@@ -43,11 +45,8 @@ models:
|
||||
base_url: null # Optional: custom endpoint URL
|
||||
request_timeout: 600.0 # Request timeout in seconds
|
||||
max_retries: 2 # Number of retries on failure
|
||||
supports_vision: true # Whether the model accepts image inputs
|
||||
supports_thinking: false # Whether the model supports extended thinking
|
||||
# thinking: {} # Optional thinking config (passed when thinking is active)
|
||||
# when_thinking_enabled: {} # Optional overrides applied when thinking is enabled
|
||||
# when_thinking_disabled: {} # Optional overrides applied when thinking is disabled
|
||||
supports_vision: true # Whether to enable vision capabilities
|
||||
thinking_enabled: false # Whether to enable extended thinking
|
||||
# Any additional fields are passed through to the model constructor
|
||||
```
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ These options are passed via `config.configurable` (for programmatic use) or sel
|
||||
|
||||
Set in the model configuration in `config.yaml`:
|
||||
|
||||
| Flag | Type | Description |
|
||||
| ------------------- | ------ | ------------------------------------- |
|
||||
| `supports_vision` | `bool` | Model accepts image inputs |
|
||||
| `supports_thinking` | `bool` | Model supports extended thinking mode |
|
||||
| Flag | Type | Description |
|
||||
| ------------------ | ------ | ------------------------------------- |
|
||||
| `supports_vision` | `bool` | Model accepts image inputs |
|
||||
| `thinking_enabled` | `bool` | Model supports extended thinking mode |
|
||||
|
||||
@@ -14,7 +14,7 @@ backend/
|
||||
│ │ ├── memory.py # Memory read/clear
|
||||
│ │ ├── threads.py # Thread management
|
||||
│ │ └── uploads.py # File uploads
|
||||
│ └── app.py # FastAPI app entry point (create_app())
|
||||
│ └── main.py # FastAPI app entry point
|
||||
│
|
||||
└── packages/harness/deerflow/
|
||||
├── agents/
|
||||
@@ -85,4 +85,4 @@ frontend/src/
|
||||
| Skill loading (hot reload) | `skills/loader.py` |
|
||||
| MCP tool cache | `mcp/cache.py` |
|
||||
| File upload handling | `uploads/manager.py` |
|
||||
| Gateway app factory | `app/gateway/app.py` |
|
||||
| Gateway main router | `app/gateway/main.py` |
|
||||
|
||||
@@ -1,3 +1,99 @@
|
||||
import { Callout, Steps } from "nextra/components";
|
||||
|
||||
# Create Your First Harness
|
||||
|
||||
TBD
|
||||
This tutorial shows you how to use the DeerFlow Harness programmatically — importing and using DeerFlow directly in your Python code rather than through the web interface.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.12+
|
||||
- `uv` installed
|
||||
- DeerFlow repository cloned
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
cd deer-flow/backend
|
||||
uv sync
|
||||
```
|
||||
|
||||
## Create configuration
|
||||
|
||||
Create a minimal `config.yaml`:
|
||||
|
||||
```yaml
|
||||
config_version: 6
|
||||
|
||||
models:
|
||||
- name: gpt-4o
|
||||
use: langchain_openai:ChatOpenAI
|
||||
model: gpt-4o
|
||||
api_key: $OPENAI_API_KEY
|
||||
|
||||
sandbox:
|
||||
use: deerflow.sandbox.local:LocalSandboxProvider
|
||||
|
||||
tools:
|
||||
- use: deerflow.community.ddg_search.tools:web_search_tool
|
||||
- use: deerflow.sandbox.tools:read_file_tool
|
||||
- use: deerflow.sandbox.tools:write_file_tool
|
||||
```
|
||||
|
||||
## Write the code
|
||||
|
||||
<Steps>
|
||||
|
||||
### Create a Python file
|
||||
|
||||
Create `my_agent.py` in the `backend/` directory:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
import os
|
||||
from deerflow.client import DeerFlowClient
|
||||
from deerflow.config import load_config
|
||||
|
||||
os.environ["OPENAI_API_KEY"] = "sk-..."
|
||||
|
||||
# Load config.yaml
|
||||
load_config()
|
||||
|
||||
client = DeerFlowClient()
|
||||
|
||||
async def main():
|
||||
async for event in client.astream(
|
||||
thread_id="my-first-thread",
|
||||
message="Write a Python fibonacci function with a docstring",
|
||||
config={
|
||||
"configurable": {
|
||||
"model_name": "gpt-4o",
|
||||
}
|
||||
},
|
||||
):
|
||||
print(event)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### Run it
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
uv run python my_agent.py
|
||||
```
|
||||
|
||||
</Steps>
|
||||
|
||||
## What the events look like
|
||||
|
||||
The stream yields events like:
|
||||
|
||||
```python
|
||||
{"type": "messages", "data": {"content": "def fibonacci..."}}
|
||||
{"type": "thread_state", "data": {"title": "Python Fibonacci Function"}}
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Use Tools and Skills](/docs/tutorials/use-tools-and-skills)
|
||||
- [Harness Quick Start](/docs/harness/quick-start)
|
||||
|
||||
@@ -1,3 +1,74 @@
|
||||
import { Callout, Steps } from "nextra/components";
|
||||
|
||||
# Deploy Your Own DeerFlow
|
||||
|
||||
TBD
|
||||
This tutorial guides you through deploying DeerFlow to a production environment using Docker Compose for multi-user access.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker and Docker Compose installed
|
||||
- A server or VM (Linux recommended)
|
||||
- LLM API key
|
||||
|
||||
## Steps
|
||||
|
||||
<Steps>
|
||||
|
||||
### Clone the repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/bytedance/deer-flow.git
|
||||
cd deer-flow
|
||||
```
|
||||
|
||||
### Create the configuration file
|
||||
|
||||
```bash
|
||||
cp config.example.yaml config.yaml
|
||||
```
|
||||
|
||||
Edit `config.yaml` to add your model configuration.
|
||||
|
||||
### Create the environment variables file
|
||||
|
||||
```bash
|
||||
cat > .env << EOF
|
||||
OPENAI_API_KEY=sk-your-key-here
|
||||
DEER_FLOW_ROOT=$(pwd)
|
||||
BETTER_AUTH_SECRET=$(openssl rand -base64 32)
|
||||
BETTER_AUTH_URL=https://your-domain.com
|
||||
EOF
|
||||
```
|
||||
|
||||
### Start the services
|
||||
|
||||
```bash
|
||||
docker compose -f docker/docker-compose-dev.yaml up -d
|
||||
```
|
||||
|
||||
### Verify the deployment
|
||||
|
||||
```bash
|
||||
# Check all services are healthy
|
||||
curl http://localhost:2026/api/models
|
||||
|
||||
# Follow logs
|
||||
docker compose -f docker/docker-compose-dev.yaml logs -f
|
||||
```
|
||||
|
||||
Open `http://your-server:2026` in your browser.
|
||||
|
||||
</Steps>
|
||||
|
||||
## Production checklist
|
||||
|
||||
- Configure HTTPS/TLS for nginx
|
||||
- Set `BETTER_AUTH_SECRET` to a strong random string (minimum 32 characters)
|
||||
- Configure firewall rules to allow only necessary ports
|
||||
- Back up `backend/.deer-flow/` directory regularly
|
||||
- Consider using a container-based sandbox (`AioSandboxProvider`) for multi-user isolation
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Full Deployment Guide](/docs/application/deployment-guide)
|
||||
- [Operations and Troubleshooting](/docs/application/operations-and-troubleshooting)
|
||||
|
||||
@@ -1,3 +1,59 @@
|
||||
import { Callout, Steps } from "nextra/components";
|
||||
|
||||
# First Conversation
|
||||
|
||||
TBD
|
||||
This tutorial walks you through your first complete agent conversation in DeerFlow — from launching the app to getting meaningful work done with the agent.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- DeerFlow app is running (see [Quick Start](/docs/application/quick-start))
|
||||
- At least one model is configured in `config.yaml`
|
||||
|
||||
## Steps
|
||||
|
||||
<Steps>
|
||||
|
||||
### Open the workspace
|
||||
|
||||
Open [http://localhost:2026](http://localhost:2026) in your browser. You will see the conversation workspace.
|
||||
|
||||
### Send your first message
|
||||
|
||||
Type a question in the input box, for example:
|
||||
|
||||
```
|
||||
Research the top 3 most popular open-source LLM frameworks in 2024 and compare their strengths and weaknesses.
|
||||
```
|
||||
|
||||
Press Enter to send.
|
||||
|
||||
### Watch the agent work
|
||||
|
||||
You will see the agent start working:
|
||||
- Expand the **thinking steps** to see which tools it is calling
|
||||
- Watch search results stream in
|
||||
- Wait for the final report to be generated
|
||||
|
||||
### Interact with the result
|
||||
|
||||
Once the report is generated, you can:
|
||||
- Ask for more detail on a specific section
|
||||
- Ask to export the report as a file (the agent will use the `present_files` tool)
|
||||
- Ask to create a chart based on the research findings
|
||||
|
||||
</Steps>
|
||||
|
||||
## What just happened
|
||||
|
||||
The agent used the DeerFlow Harness to:
|
||||
1. Receive your message and add it to the thread state
|
||||
2. Run the middleware chain (memory injection, title generation)
|
||||
3. Call the LLM, which decided to search the web
|
||||
4. Execute web search tool calls
|
||||
5. Synthesize results into a structured response
|
||||
6. Update the thread state with any artifacts produced
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Use Tools and Skills](/docs/tutorials/use-tools-and-skills)
|
||||
- [Workspace Usage](/docs/application/workspace-usage)
|
||||
|
||||
@@ -1,3 +1,59 @@
|
||||
import { Callout } from "nextra/components";
|
||||
|
||||
# Use Tools and Skills
|
||||
|
||||
TBD
|
||||
This tutorial shows you how to configure and use tools and skills in DeerFlow to give the agent access to web search, file operations, and domain-specific capabilities.
|
||||
|
||||
## Configuring tools
|
||||
|
||||
Add tools to `config.yaml`:
|
||||
|
||||
```yaml
|
||||
tools:
|
||||
# Web search
|
||||
- use: deerflow.community.ddg_search.tools:web_search_tool
|
||||
|
||||
# Web content fetching
|
||||
- use: deerflow.community.jina_ai.tools:web_fetch_tool
|
||||
|
||||
# Sandbox file operations
|
||||
- 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
|
||||
```
|
||||
|
||||
## Enabling skills
|
||||
|
||||
Enable skills through the DeerFlow app's extensions panel, or edit `extensions_config.json` directly.
|
||||
|
||||
**Via the app UI:**
|
||||
1. Open the DeerFlow app
|
||||
2. Click the Extensions/Skills icon in the sidebar
|
||||
3. Find `deep-research` and toggle it on
|
||||
|
||||
## Using a skill for research
|
||||
|
||||
With the `deep-research` skill enabled, select it in the conversation input, then send a research request:
|
||||
|
||||
```
|
||||
Do a deep research on the latest advances in quantum computing, focusing on practical applications.
|
||||
```
|
||||
|
||||
The agent will run a multi-step research workflow including web search, information synthesis, and report generation.
|
||||
|
||||
## Using the data analysis skill
|
||||
|
||||
Enable `data-analysis`, then upload a CSV or data file and ask the agent to analyze it:
|
||||
|
||||
```
|
||||
Analyze this CSV file and identify the top trends.
|
||||
```
|
||||
|
||||
The agent will use the sandbox tools to read the file, run analysis, and produce charts.
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Work with Memory](/docs/tutorials/work-with-memory)
|
||||
- [Tools Reference](/docs/harness/tools)
|
||||
- [Skills Reference](/docs/harness/skills)
|
||||
|
||||
@@ -1,3 +1,64 @@
|
||||
import { Callout } from "nextra/components";
|
||||
|
||||
# Work with Memory
|
||||
|
||||
TBD
|
||||
This tutorial shows you how to enable and use DeerFlow's memory system so the agent remembers important information about you across multiple sessions.
|
||||
|
||||
## Enable memory
|
||||
|
||||
In `config.yaml`:
|
||||
|
||||
```yaml
|
||||
memory:
|
||||
enabled: true
|
||||
injection_enabled: true
|
||||
max_injection_tokens: 2000
|
||||
debounce_seconds: 30
|
||||
```
|
||||
|
||||
## How memory works
|
||||
|
||||
Memory works automatically through `MemoryMiddleware`:
|
||||
|
||||
1. **First conversation**: tell the agent about your preferences, project, or background.
|
||||
2. **Automatic learning**: the agent extracts and saves important facts in the background.
|
||||
3. **Future conversations**: memory facts are automatically injected into the system prompt — the agent does not need you to repeat context.
|
||||
|
||||
## Example
|
||||
|
||||
**First conversation:**
|
||||
```
|
||||
I am a Python backend developer primarily using FastAPI and PostgreSQL.
|
||||
My team follows PEP 8 and prefers type annotations everywhere.
|
||||
Please remember this for future code suggestions.
|
||||
```
|
||||
|
||||
**Later conversation** (no need to repeat background):
|
||||
```
|
||||
Help me write a user authentication module
|
||||
```
|
||||
|
||||
The agent will automatically produce FastAPI-style code with type annotations.
|
||||
|
||||
## Inspect memory
|
||||
|
||||
Memory is stored in `backend/.deer-flow/memory.json`:
|
||||
|
||||
```bash
|
||||
cat backend/.deer-flow/memory.json
|
||||
```
|
||||
|
||||
## Per-agent memory
|
||||
|
||||
When a custom agent is active, it maintains its own memory file at:
|
||||
|
||||
```
|
||||
backend/.deer-flow/agents/{agent_name}/memory.json
|
||||
```
|
||||
|
||||
This keeps each agent's learned knowledge separate.
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Deploy Your Own DeerFlow](/docs/tutorials/deploy-your-own-deerflow)
|
||||
- [Memory System Reference](/docs/harness/memory)
|
||||
|
||||
Reference in New Issue
Block a user