Prepare to merge deer-flow-2

This commit is contained in:
Willem Jiang
2026-02-14 16:28:12 +08:00
parent 06248fa6f1
commit a66d8c94fa
451 changed files with 0 additions and 142650 deletions

View File

@@ -1,53 +0,0 @@
.env
Dockerfile
.dockerignore
.git
.gitignore
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
.venv/
# Web
node_modules
npm-debug.log
.next
# IDE
.idea/
.vscode/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Project specific
conf.yaml
web/
docs/
examples/
assets/
tests/
*.log

View File

@@ -1,128 +0,0 @@
# Application Settings
# Set to True to enable debug-level logging (shows detailed LLM prompts and responses)
# Recommended for development and troubleshooting
DEBUG=True
APP_ENV=development
# Frontend API URL (used as Docker build arg for Next.js)
# This is a BUILD-TIME variable: it gets embedded into the frontend JS bundle during build.
# Default works for local development (localhost). For remote/LAN deployment, change to your host IP or domain:
# NEXT_PUBLIC_API_URL=http://192.168.1.100:8000/api
# NEXT_PUBLIC_API_URL=https://your-domain.com/api
# Note: When using docker-compose, only this root .env is used (not web/.env).
# If you change this value after building, you must rebuild: docker compose build
NEXT_PUBLIC_API_URL="http://localhost:8000/api"
AGENT_RECURSION_LIMIT=30
# CORS settings
# Comma-separated list of allowed origins for CORS requests
# Example: ALLOWED_ORIGINS=http://localhost:3000,http://example.com
ALLOWED_ORIGINS=http://localhost:3000
# Enable or disable MCP server configuration, the default is false.
# Please enable this feature before securing your front-end and back-end in a managed environment.
# Otherwise, you system could be compromised.
ENABLE_MCP_SERVER_CONFIGURATION=false
# Enable or disable PYTHON_REPL configuration, the default is false.
# Please enable this feature before securing your in a managed environment.
# Otherwise, you system could be compromised.
ENABLE_PYTHON_REPL=false
# Search Engine, Supported values: tavily, infoquest (recommended), duckduckgo, brave_search, arxiv, searx, serper
SEARCH_API=tavily
TAVILY_API_KEY=tvly-xxx
INFOQUEST_API_KEY="infoquest-xxx"
# SERPER_API_KEY=xxx # Required only if SEARCH_API is serper
# SEARX_HOST=xxx # Required only if SEARCH_API is searx.(compatible with both Searx and SearxNG)
# BRAVE_SEARCH_API_KEY=xxx # Required only if SEARCH_API is brave_search
# JINA_API_KEY=jina_xxx # Optional, default is None
# Optional, RAG provider
# RAG_PROVIDER=vikingdb_knowledge_base
# VIKINGDB_KNOWLEDGE_BASE_API_URL="api-knowledgebase.mlp.cn-beijing.volces.com"
# VIKINGDB_KNOWLEDGE_BASE_API_AK="AKxxx"
# VIKINGDB_KNOWLEDGE_BASE_API_SK=""
# VIKINGDB_KNOWLEDGE_BASE_RETRIEVAL_SIZE=15
# RAG_PROVIDER=ragflow
# RAGFLOW_API_URL="http://localhost:9388"
# RAGFLOW_API_KEY="ragflow-xxx"
# RAGFLOW_RETRIEVAL_SIZE=10
# RAGFLOW_CROSS_LANGUAGES=English,Chinese,Spanish,French,German,Japanese,Korean # Optional. To use RAGFlow's cross-language search, please separate each language with a single comma
# RAG_PROVIDER=dify
# DIFY_API_URL="https://api.dify.ai/v1"
# DIFY_API_KEY="dataset-xxx"
# MOI is a hybrid database that mainly serves enterprise users (https://www.matrixorigin.io/matrixone-intelligence)
# RAG_PROVIDER=moi
# MOI_API_URL="https://cluster.matrixonecloud.cn"
# MOI_API_KEY="xxx-xxx-xxx-xxx"
# MOI_RETRIEVAL_SIZE=10
# MOI_LIST_LIMIT=10
# RAG_PROVIDER: milvus (using free milvus instance on zilliz cloud: https://docs.zilliz.com/docs/quick-start )
# RAG_PROVIDER=milvus
# MILVUS_URI=<endpoint_of_self_hosted_milvus_or_zilliz_cloud>
# MILVUS_USER=<username_of_self_hosted_milvus_or_zilliz_cloud>
# MILVUS_PASSWORD=<password_of_self_hosted_milvus_or_zilliz_cloud>
# MILVUS_COLLECTION=documents
# MILVUS_EMBEDDING_PROVIDER=openai # support openai,dashscope
# MILVUS_EMBEDDING_BASE_URL=
# MILVUS_EMBEDDING_MODEL=
# MILVUS_EMBEDDING_API_KEY=
# MILVUS_AUTO_LOAD_EXAMPLES=true
# RAG_PROVIDER: milvus (using milvus lite on Mac or Linux)
# RAG_PROVIDER=milvus
# MILVUS_URI=./milvus_demo.db
# MILVUS_COLLECTION=documents
# MILVUS_EMBEDDING_PROVIDER=openai # support openai,dashscope
# MILVUS_EMBEDDING_BASE_URL=
# MILVUS_EMBEDDING_MODEL=
# MILVUS_EMBEDDING_API_KEY=
# MILVUS_AUTO_LOAD_EXAMPLES=true
# RAG_PROVIDER: qdrant (using qdrant cloud or self-hosted: https://qdrant.tech/documentation/quick-start/)
# RAG_PROVIDER=qdrant
# QDRANT_LOCATION=https://xyz-example.eu-central.aws.cloud.qdrant.io:6333
# QDRANT_API_KEY=<your_qdrant_api_key> # Optional, only for cloud/authenticated instances
# QDRANT_COLLECTION=documents
# QDRANT_EMBEDDING_PROVIDER=openai # support openai,dashscope
# QDRANT_EMBEDDING_BASE_URL=
# QDRANT_EMBEDDING_MODEL=text-embedding-ada-002
# QDRANT_EMBEDDING_API_KEY=
# QDRANT_AUTO_LOAD_EXAMPLES=true
# Optional, volcengine TTS for generating podcast
VOLCENGINE_TTS_APPID=xxx
VOLCENGINE_TTS_ACCESS_TOKEN=xxx
# VOLCENGINE_TTS_CLUSTER=volcano_tts # Optional, default is volcano_tts
# VOLCENGINE_TTS_VOICE_TYPE=BV700_V2_streaming # Optional, default is BV700_V2_streaming
# Optional, for langsmith tracing and monitoring
# Highly recommended for production debugging and performance monitoring
# Get your API key from https://smith.langchain.com/
# LANGSMITH_TRACING=true
# LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
# LANGSMITH_API_KEY="xxx"
# LANGSMITH_PROJECT="xxx"
# Optional, LangChain verbose logging
# Enable these to see detailed LLM interactions in console/logs
# Useful for debugging but can be very verbose
# LANGCHAIN_VERBOSE=true
# LANGCHAIN_DEBUG=true
# [!NOTE]
# For model settings and other configurations, please refer to `docs/configuration_guide.md`
# Option, for langgraph mongodb checkpointer
# Enable LangGraph checkpoint saver, supports MongoDB, Postgres
#LANGGRAPH_CHECKPOINT_SAVER=true
# Set the database URL for saving checkpoints
#LANGGRAPH_CHECKPOINT_DB_URL=mongodb://localhost:27017/
#LANGGRAPH_CHECKPOINT_DB_URL=postgresql://localhost:5432/postgres

View File

@@ -1,303 +0,0 @@
# GitHub Copilot Instructions for DeerFlow
This file provides guidance to GitHub Copilot when working with the DeerFlow repository.
## Project Overview
**DeerFlow** (Deep Exploration and Efficient Research Flow) is a community-driven Deep Research framework built on LangGraph. It orchestrates AI agents to conduct deep research, generate reports, and create content like podcasts and presentations.
### Technology Stack
- **Backend**: Python 3.12+, FastAPI, LangGraph, LangChain
- **Frontend**: Next.js (React), TypeScript, pnpm
- **Package Management**: uv (Python), pnpm (Node.js)
- **Testing**: pytest (Python), Jest (JavaScript)
- **Linting/Formatting**: Ruff (Python), ESLint/Prettier (JavaScript)
## Architecture Overview
### Core Components
1. **Multi-Agent System**: Built on LangGraph with state-based workflows
- **Coordinator**: Entry point managing workflow lifecycle
- **Planner**: Decomposes research objectives into structured plans
- **Research Team**: Specialized agents (Researcher, Coder) executing plans
- **Reporter**: Aggregates findings and generates final reports
- **Human-in-the-loop**: Interactive plan modification and approval
2. **State Management**
- Uses LangGraph StateGraph for agent communication
- MemorySaver for conversation persistence
- Checkpointing with MongoDB/PostgreSQL support
3. **External Integrations**
- Search engines: Tavily, Brave Search, DuckDuckGo
- Web crawling: Jina for content extraction
- TTS: Volcengine TTS API
- RAG: RAGFlow and VikingDB support
- MCP: Model Context Protocol integration
### Directory Structure
```
src/
├── agents/ # Agent definitions and behaviors
├── config/ # Configuration management (YAML, env vars)
├── crawler/ # Web crawling and content extraction
├── graph/ # LangGraph workflow definitions
├── llms/ # LLM provider integrations (OpenAI, DeepSeek, etc.)
├── prompts/ # Agent prompt templates
├── server/ # FastAPI web server and endpoints
├── tools/ # External tools (search, TTS, Python REPL)
└── rag/ # RAG integration for private knowledgebases
web/ # Next.js web UI (React, TypeScript)
├── src/app/ # Next.js pages and API routes
├── src/components/ # UI components and design system
└── src/core/ # Frontend utilities and state management
tests/ # Test suite
├── unit/ # Unit tests
└── integration/ # Integration tests
```
## Development Workflow
### Environment Setup
1. **Python Environment**:
```bash
# Use uv for dependency management
uv sync
# For development dependencies
uv pip install -e ".[dev]"
uv pip install -e ".[test]"
```
2. **Configuration Files**:
```bash
# Copy and configure environment files
cp .env.example .env
cp conf.yaml.example conf.yaml
```
3. **Frontend Setup**:
```bash
cd web/
pnpm install
```
### Running the Application
- **Backend Development Server**: `uv run server.py --reload`
- **Console UI**: `uv run main.py`
- **Frontend Development**: `cd web && pnpm dev`
- **Full Stack**: `./bootstrap.sh -d` (macOS/Linux) or `bootstrap.bat -d` (Windows)
- **LangGraph Studio**: `make langgraph-dev`
### Testing
- **Python Tests**: `make test` or `pytest tests/`
- **Python Coverage**: `make coverage`
- **Frontend Tests**: `cd web && pnpm test:run`
- **Frontend Lint**: `make lint-frontend`
### Code Quality
- **Python Formatting**: `make format` (uses Ruff)
- **Python Linting**: `make lint` (uses Ruff)
- **Frontend Linting**: `cd web && pnpm lint`
- **Frontend Type Check**: `cd web && pnpm typecheck`
## Coding Standards
### Python Code
1. **Style Guidelines**:
- Follow PEP 8 guidelines
- Use type hints wherever possible
- Line length: 88 characters (Ruff default)
- Python version requirement: >= 3.12
2. **Code Organization**:
- Write clear, documented code with descriptive docstrings
- Keep functions and methods focused and single-purpose
- Comment complex logic
- Use meaningful variable and function names
3. **Testing Requirements**:
- Add tests for new features in `tests/` directory
- Maintain test coverage (minimum 25%)
- Use pytest fixtures for test setup
- Test both unit and integration scenarios
4. **LangGraph Patterns**:
- Agents communicate via LangGraph state
- Each agent has specific tool permissions
- Use persistent checkpoints for conversation history
- Follow the node → edge → state pattern
### TypeScript/JavaScript Code
1. **Style Guidelines**:
- Use TypeScript for type safety
- Follow ESLint configuration
- Use Prettier for consistent formatting
- Prefer functional components with hooks
2. **Component Structure**:
- Place UI components in `web/src/components/`
- Use the established design system
- Keep components focused and reusable
- Export types alongside components
3. **API Integration**:
- API utilities in `web/src/core/api/`
- Handle errors gracefully
- Use proper TypeScript types for API responses
## Configuration Management
### Environment Variables (.env)
Key environment variables to configure:
- `TAVILY_API_KEY`: Web search integration
- `BRAVE_SEARCH_API_KEY`: Alternative search engine
- `LANGSMITH_API_KEY`: LangSmith tracing (optional)
- `LANGGRAPH_CHECKPOINT_DB_URL`: MongoDB/PostgreSQL for persistence
- `RAGFLOW_API_URL`: RAG integration
### Application Configuration (conf.yaml)
- LLM model configurations
- Provider-specific settings
- Search engine preferences
- MCP server configurations
## Common Development Tasks
### Adding New Features
1. **New Agent**:
- Add agent definition in `src/agents/`
- Update graph in `src/graph/builder.py`
- Register agent tools in prompts
2. **New Tool**:
- Implement tool in `src/tools/`
- Register in agent prompts
- Add tests for tool functionality
3. **New Workflow**:
- Create graph builder in `src/[feature]/graph/builder.py`
- Define state management
- Add nodes and edges
4. **Frontend Component**:
- Add component to `web/src/components/`
- Update API in `web/src/core/api/`
- Add corresponding types
### Debugging
- **LangGraph Studio**: `make langgraph-dev` for visual workflow debugging
- **LangSmith**: Configure `LANGSMITH_API_KEY` for tracing
- **Server Logs**: Check FastAPI server output for backend issues
- **Browser DevTools**: Use for frontend debugging
## Important Patterns
### Agent Communication
- Agents communicate through LangGraph state
- State is preserved across checkpoints
- Use proper type annotations for state
### Content Generation Pipeline
1. Planning: Planner creates research plan
2. Research: Researcher gathers information
3. Processing: Coder analyzes data/code
4. Reporting: Reporter synthesizes findings
5. Post-processing: Optional podcast/PPT generation
### Error Handling
- Use try-except blocks with specific exception types
- Log errors with appropriate context
- Provide meaningful error messages to users
- Handle API failures gracefully
### Async Operations
- Use async/await for I/O operations
- Properly handle concurrent operations
- Use appropriate timeout values
- Clean up resources in finally blocks
## Pre-commit Hooks
The repository uses pre-commit hooks for code quality:
```bash
chmod +x pre-commit
ln -s ../../pre-commit .git/hooks/pre-commit
```
## Dependencies
### Adding New Dependencies
- **Python**: Add to `pyproject.toml` dependencies, then run `uv sync`
- **JavaScript**: Use `pnpm add <package>` in the `web/` directory
### Dependency Updates
- Keep dependencies up to date
- Test thoroughly after updates
- Check compatibility with Python 3.12+ and Node.js 22+
## Documentation
### When to Update Documentation
- New features: Update relevant docs in `docs/` directory
- API changes: Update `docs/API.md`
- Configuration changes: Update `docs/configuration_guide.md`
- Breaking changes: Clearly document in README and CONTRIBUTING
### Documentation Style
- Use clear, concise language
- Include code examples where applicable
- Keep documentation in sync with code
- Use markdown formatting consistently
## Security Considerations
- Never commit API keys or secrets to the repository
- Use `.env` files for sensitive configuration
- Validate and sanitize user inputs
- Follow security best practices for web applications
- Be cautious with code execution features
## Community Guidelines
- Be respectful and inclusive
- Follow the MIT License terms
- Give constructive feedback in code reviews
- Help others learn and grow
- Stay focused on improving the project
## Getting Help
- Check existing documentation in `docs/`
- Review `Agent.md` for architecture details
- See `CONTRIBUTING` for contribution guidelines
- Check GitHub issues for known problems
- Join community discussions for support
## Additional Resources
- Main README: Comprehensive project overview
- Agent.md: Detailed architecture and agent guidance
- CONTRIBUTING: Full contribution guidelines
- docs/configuration_guide.md: Configuration details
- docs/API.md: API documentation
- docs/mcp_integrations.md: MCP integration guide

View File

@@ -1,95 +0,0 @@
name: Publish Containers
on:
push:
branches:
- main
release:
types: [published]
workflow_dispatch:
jobs:
backend-container:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 #v3.4.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 #v5.7.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
id: push
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 #v6.18.0
with:
context: .
file: Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v2
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
frontend-container:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
attestations: write
id-token: write
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}-web
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 #v3.4.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 #v5.7.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
id: push
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 #v6.18.0
with:
context: web
file: web/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v2
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true

View File

@@ -1,69 +0,0 @@
name: Lint Check
on:
push:
branches: [ 'main' ]
pull_request:
branches: [ '*' ]
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install the latest version of uv
uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 #v6.5.0
with:
version: "latest"
- name: Install dependencies
run: |
uv venv --python 3.12
uv pip install -e ".[dev]"
- name: Run linters
run: |
source .venv/bin/activate
make lint
lint-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install pnpm
run: npm install -g pnpm
- name: Install frontend dependencies
run: |
cd web
pnpm install --frozen-lockfile
- name: Run frontend linting
run: |
cd web
pnpm lint
- name: Check TypeScript types
run: |
cd web
pnpm typecheck
- name: Running the frontend tests
run: |
cd web
pnpm test:run
- name: Build frontend
run: |
cd web
pnpm build

View File

@@ -1,73 +0,0 @@
name: Test Cases Check
on:
push:
branches: [ 'main' ]
pull_request:
branches: [ '*' ]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: checkpointing_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports: ["5432:5432"]
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
mongodb:
image: mongo:6
env:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: admin
MONGO_INITDB_DATABASE: checkpointing_db
ports: ["27017:27017"]
options: >-
--health-cmd "mongosh --eval 'db.runCommand(\"ping\").ok'"
--health-interval 10s
--health-timeout 5s
--health-retries 3
steps:
- uses: actions/checkout@v3
- name: Install the latest version of uv
uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 #v6.5.0
with:
version: "latest"
- name: Install dependencies
run: |
uv venv --python 3.12
uv pip install -e ".[dev]"
uv pip install -e ".[test]"
- name: Run test cases with coverage
run: |
source .venv/bin/activate
TAVILY_API_KEY=mock-key DB_TESTS_ENABLED=true make coverage
- name: Generate HTML Coverage Report
run: |
source .venv/bin/activate
python -m coverage html -d coverage_html
- name: Upload Coverage Report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage_html/
- name: Display Coverage Summary
run: |
source .venv/bin/activate
python -m coverage report

32
.gitignore vendored
View File

@@ -1,32 +0,0 @@
# Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info
.coverage
.coverage.*
agent_history.gif
static/browser_history/*.gif
# Virtual environments
.venv
venv/
# Environment variables
.env
# user conf
conf.yaml
.idea/
.langgraph_api/
.DS_Store
# coverage report
coverage.xml
coverage/
# Temporary PPT content files
ppt_content_*.md

View File

@@ -1 +0,0 @@
3.12

121
.vscode/launch.json vendored
View File

@@ -1,121 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Tests",
"type": "debugpy",
"request": "launch",
"module": "pytest",
"args": [
"${workspaceFolder}/tests",
"-v",
"-s"
],
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}"
}
},
{
"name": "Debug Current Test File",
"type": "debugpy",
"request": "launch",
"module": "pytest",
"args": [
"${file}",
"-v",
"-s"
],
"console": "integratedTerminal",
"justMyCode": false
},
{
"name": "Python: 当前文件",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true
},
{
"name": "Python: main.py",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/main.py",
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}"
},
"args": [
"--debug", "--max_plan_iterations", "1", "--max_step_num", "1"
]
},
{
"name": "Python: llm.py",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/src/llms/llm.py",
"console": "integratedTerminal",
"justMyCode": true,
"env": {
"PYTHONPATH": "${workspaceFolder}"
}
},
{
"name": "Python: server.py",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/server.py",
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}"
}
},
{
"name": "Python: graph.py",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/src/ppt/graph/builder.py",
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}"
}
},
{
"name": "Debug: python server",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/server.py",
"console": "integratedTerminal",
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}"
},
"args": [
"--reload"
]
},
{
"name": "Debug: nodejs web",
"type": "node",
"request": "launch",
"runtimeExecutable": "pnpm",
"runtimeArgs": [
"dev"
],
"cwd": "${workspaceFolder}/web",
"console": "integratedTerminal"
},
],
"compounds": [
{
"name": "Launch Deerflow",
"configurations": ["Debug: python server", "Debug: nodejs web"]
}
]
}

View File

@@ -1,7 +0,0 @@
{
"python.testing.pytestArgs": [
"tests"
],
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}

186
Agent.md
View File

@@ -1,186 +0,0 @@
# Agent.md
This file provides guidance to AI agents when working with code in this repository.
## Architecture Overview
**DeerFlow** is a multi-agent research framework built on LangGraph that orchestrates AI agents to conduct deep research, generate reports, and create content like podcasts and presentations.
### Core Architecture
The system uses a **modular multi-agent architecture** with these key components:
- **Coordinator**: Entry point managing workflow lifecycle
- **Planner**: Decomposes research objectives into structured plans
- **Research Team**: Specialized agents (Researcher, Coder) executing plans
- **Reporter**: Aggregates findings and generates final reports
- **Human-in-the-loop**: Interactive plan modification and approval
### Graph Structure
Built on **LangGraph** with state-based workflows:
- **StateGraph** manages agent communication
- **MemorySaver** provides conversation persistence
- **Checkpointing** supports MongoDB/PostgreSQL storage
- **Nodes**: coordinator → planner → research_team → reporter
### Key Directories
```
src/
├── agents/ # Agent definitions and behaviors
├── config/ # Configuration management (YAML, env vars)
├── crawler/ # Web crawling and content extraction
├── graph/ # LangGraph workflow definitions
├── llms/ # LLM provider integrations (OpenAI, DeepSeek, etc.)
├── prompts/ # Agent prompt templates
├── server/ # FastAPI web server and endpoints
├── tools/ # External tools (search, TTS, Python REPL)
└── rag/ # RAG integration for private knowledgebases
web/ # Next.js web UI (React, TypeScript)
├── src/app/ # Next.js pages and API routes
├── src/components/ # UI components and design system
└── src/core/ # Frontend utilities and state management
```
## Development Commands
### Backend (Python)
```bash
# Install dependencies
uv sync
# Development server
uv run server.py --reload
# Console UI
uv run main.py
# Run tests
make test # Run all tests
make coverage # Run tests with coverage
pytest tests/unit/test_*.py # Run specific test file
# Code quality
make lint # Ruff linting
make format # Ruff formatting
# LangGraph Studio (debugging)
make langgraph-dev # Start LangGraph development server
```
### Frontend (Web UI)
```bash
cd web/
pnpm install # Install dependencies
pnpm dev # Development server (localhost:3000)
pnpm build # Production build
pnpm typecheck # Type checking
pnpm lint # ESLint
pnpm format:write # Prettier formatting
```
### Full Stack Development
```bash
# Run both backend and frontend
./bootstrap.sh -d # macOS/Linux
bootstrap.bat -d # Windows
```
### Docker
```bash
# Build and run
make build # Build Docker image
docker compose up # Run with Docker Compose
# Production deployment
docker build -t deer-flow-api .
docker run -p 8000:8000 deer-flow-api
```
### Fix GitHub issues
create a branch named `fix/<issue-number>` to address specific GitHub issues.
## Configuration
### Environment Setup
```bash
# Required: Copy example configs
cp .env.example .env
cp conf.yaml.example conf.yaml
# Key environment variables:
# TAVILY_API_KEY # Web search
# BRAVE_SEARCH_API_KEY # Alternative search
# LANGSMITH_API_KEY # LangSmith tracing (optional)
# LANGGRAPH_CHECKPOINT_DB_URL # MongoDB/PostgreSQL for persistence
```
### LangGraph Studio
```bash
# Local debugging with checkpointing
uvx --refresh --from "langgraph-cli[inmem]" --with-editable . --python 3.12 langgraph dev --allow-blocking
```
## Common Development Tasks
### Testing
```bash
# Unit tests
pytest tests/unit/
# Integration tests
pytest tests/integration/
# Specific component
pytest tests/unit/config/test_configuration.py
# With coverage
pytest --cov=src tests/ --cov-report=html
```
### Code Quality
```bash
# Format code
make format
# Check linting
make lint
# Type checking (frontend)
cd web && pnpm typecheck
```
### Adding New Features
1. **New Agent**: Add agent in `src/agents/` + update graph in `src/graph/builder.py`
2. **New Tool**: Add tool in `src/tools/` + register in agent prompts
3. **New Workflow**: Create graph builder in `src/[feature]/graph/builder.py`
4. **Frontend Component**: Add to `web/src/components/` + update API in `web/src/core/api/`
### Configuration Changes
- **LLM Models**: Update `conf.yaml` with new providers
- **Search Engines**: Modify `.env` SEARCH_API variable
- **RAG Integration**: Configure RAGFLOW_API_URL in `.env`
- **MCP Servers**: Add MCP settings in configuration
## Architecture Patterns
### Agent Communication
- **Message Passing**: Agents communicate via LangGraph state
- **Tool Access**: Each agent has specific tool permissions
- **State Management**: Persistent checkpoints for conversation history
### Content Generation Pipeline
1. **Planning**: Planner creates research plan
2. **Research**: Researcher gathers information
3. **Processing**: Coder analyzes data/code
4. **Reporting**: Reporter synthesizes findings
5. **Post-processing**: Optional podcast/PPT generation
### External Integrations
- **Search**: Tavily, Brave Search, DuckDuckGo
- **Crawling**: Jina for web content extraction
- **TTS**: Volcengine TTS API
- **RAG**: RAGFlow and VikingDB support
- **MCP**: Model Context Protocol integration

View File

@@ -1,144 +0,0 @@
# Contributing to DeerFlow
Thank you for your interest in contributing to DeerFlow! We welcome contributions of all kinds from the community.
## Ways to Contribute
There are many ways you can contribute to DeerFlow:
- **Code Contributions**: Add new features, fix bugs, or improve performance
- **Documentation**: Improve README, add code comments, or create examples
- **Bug Reports**: Submit detailed bug reports through issues
- **Feature Requests**: Suggest new features or improvements
- **Code Reviews**: Review pull requests from other contributors
- **Community Support**: Help others in discussions and issues
## Development Setup
1. Fork the repository
2. Clone your fork:
```bash
git clone https://github.com/bytedance/deer-flow.git
cd deer-flow
```
3. Set up your development environment:
```bash
# Install dependencies, uv will take care of the python interpreter and venv creation
uv sync
# For development, install additional dependencies
uv pip install -e ".[dev]"
uv pip install -e ".[test]"
```
4. Configure pre-commit hooks:
```bash
chmod +x pre-commit
ln -s ../../pre-commit .git/hooks/pre-commit
```
## Development Process
1. Create a new branch:
```bash
git checkout -b feature/amazing-feature
```
2. Make your changes following our coding standards:
- Write clear, documented code
- Follow PEP 8 style guidelines
- Add tests for new features
- Update documentation as needed
3. Run tests and checks:
```bash
make test # Run tests
make lint # Run linting
make format # Format code
make coverage # Check test coverage
```
4. Commit your changes:
```bash
git commit -m 'Add some amazing feature'
```
5. Push to your fork:
```bash
git push origin feature/amazing-feature
```
6. Open a Pull Request
## Pull Request Guidelines
- Fill in the pull request template completely
- Include tests for new features
- Update documentation as needed
- Ensure all tests pass and there are no linting errors
- Keep pull requests focused on a single feature or fix
- Reference any related issues
## Code Style
- Follow PEP 8 guidelines
- Use type hints where possible
- Write descriptive docstrings
- Keep functions and methods focused and single-purpose
- Comment complex logic
- Python version requirement: >= 3.12
## Testing
Run the test suite:
```bash
# Run all tests
make test
# Run specific test file
pytest tests/integration/test_workflow.py
# Run with coverage
make coverage
```
## Code Quality
```bash
# Run linting
make lint
# Format code
make format
```
## Community Guidelines
- Be respectful and inclusive
- Follow our code of conduct
- Help others learn and grow
- Give constructive feedback
- Stay focused on improving the project
## Need Help?
If you need help with anything:
- Check existing issues and discussions
- Join our community channels
- Ask questions in discussions
## License
By contributing to DeerFlow, you agree that your contributions will be licensed under the MIT License.
We appreciate your contributions to making DeerFlow better!

View File

@@ -1,32 +0,0 @@
FROM ghcr.io/astral-sh/uv:python3.12-bookworm
# Install uv.
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
# Install system dependencies including libpq
RUN apt-get update && apt-get install -y \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Pre-cache the application dependencies.
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --locked --no-install-project
# Copy the application into the container.
COPY . /app
# Install the application dependencies.
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked
EXPOSE 8000
# Run the application.
RUN useradd -m appuser
USER appuser
CMD ["uv", "run", "python", "server.py", "--host", "0.0.0.0", "--port", "8000"]

21
LICENSE
View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,2 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT

View File

@@ -1,2 +0,0 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT

View File

@@ -1,44 +0,0 @@
.PHONY: help lint format install-dev serve test coverage langgraph-dev lint-frontend add-license-all check-license-all
help: ## Show this help message
@echo "Deer Flow - Available Make Targets:"
@echo ""
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
@echo ""
@echo "Usage: make <target>"
install-dev: ## Install development dependencies which could be optional for normal usage
uv pip install -e ".[dev]" && uv pip install -e ".[test]"
format: ## Format code using ruff
uv run ruff format --config pyproject.toml .
lint: ## Lint and fix code using ruff
uv run ruff check --fix --select I --config pyproject.toml .
lint-frontend: ## Lint frontend code, run tests, and check build
cd web && pnpm install --frozen-lockfile
cd web && pnpm lint
cd web && pnpm typecheck
cd web && pnpm test:run
cd web && pnpm build
serve: ## Start development server with reload
uv run server.py --reload
test: ## Run tests with pytest, need to run after 'make install-dev' for first time
uv run pytest tests/
langgraph-dev: ## Start langgraph development server
uvx --refresh --from "langgraph-cli[inmem]" --with-editable . --python 3.12 langgraph dev --allow-blocking
coverage: ## Run tests with coverage report
uv run pytest --cov=src tests/ --cov-report=term-missing --cov-report=xml
add-license-all: ## Add license headers to all Python and TypeScript files
@echo "Adding license headers to all source files..."
@uv run python scripts/license_header.py src/ tests/ server.py main.py web/src/ web/tests/ --verbose
check-license-all: ## Check if all Python and TypeScript files have license headers
@echo "Checking license headers in all source files..."
@uv run python scripts/license_header.py src/ tests/ server.py main.py web/src/ web/tests/ --check

721
README.md
View File

@@ -1,721 +0,0 @@
# 🦌 DeerFlow
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![DeepWiki](https://img.shields.io/badge/DeepWiki-bytedance%2Fdeer--flow-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McCcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/bytedance/deer-flow)
<!-- DeepWiki badge generated by https://deepwiki.ryoppippi.com/ -->
[English](./README.md) | [简体中文](./README_zh.md) | [日本語](./README_ja.md) | [Deutsch](./README_de.md) | [Español](./README_es.md) | [Русский](./README_ru.md) | [Portuguese](./README_pt.md)
> Originated from Open Source, give back to Open Source.
> [!NOTE]
> As we're [moving to DeerFlow 2.0](https://github.com/bytedance/deer-flow/issues/824) in February, it's time to wrap up DeerFlow 1.0 on the main branch.
**DeerFlow** (**D**eep **E**xploration and **E**fficient **R**esearch **Flow**) is a community-driven Deep Research framework that builds upon the incredible work of the open source community. Our goal is to combine language models with specialized tools for tasks like web search, crawling, and Python code execution, while giving back to the community that made this possible.
Currently, DeerFlow has officially entered the [FaaS Application Center of Volcengine](https://console.volcengine.com/vefaas/region:vefaas+cn-beijing/market). Users can experience it online through the [experience link](https://console.volcengine.com/vefaas/region:vefaas+cn-beijing/market/deerflow/?channel=github&source=deerflow) to intuitively feel its powerful functions and convenient operations. At the same time, to meet the deployment needs of different users, DeerFlow supports one-click deployment based on Volcengine. Click the [deployment link](https://console.volcengine.com/vefaas/region:vefaas+cn-beijing/application/create?templateId=683adf9e372daa0008aaed5c&channel=github&source=deerflow) to quickly complete the deployment process and start an efficient research journey.
DeerFlow has newly integrated the intelligent search and crawling toolset independently developed by BytePlus--[InfoQuest (supports free online experience)](https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest)
<a href="https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest" target="_blank">
<img
src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/hubseh7bsbps/20251208-160108.png" alt="infoquest_bannar"
/>
</a>
Please visit [our official website](https://deerflow.tech/) for more details.
## Demo
### Video
<https://github.com/user-attachments/assets/f3786598-1f2a-4d07-919e-8b99dfa1de3e>
In this demo, we showcase how to use DeerFlow to:
- Seamlessly integrate with MCP services
- Conduct the Deep Research process and produce a comprehensive report with images
- Create podcast audio based on the generated report
### Replays
- [How tall is Eiffel Tower compared to the tallest building?](https://deerflow.tech/chat?replay=eiffel-tower-vs-tallest-building)
- [What are the top trending repositories on GitHub?](https://deerflow.tech/chat?replay=github-top-trending-repo)
- [Write an article about Nanjing's traditional dishes](https://deerflow.tech/chat?replay=nanjing-traditional-dishes)
- [How to decorate a rental apartment?](https://deerflow.tech/chat?replay=rental-apartment-decoration)
- [Visit our official website to explore more replays.](https://deerflow.tech/#case-studies)
---
## 📑 Table of Contents
- [🚀 Quick Start](#quick-start)
- [🌟 Features](#features)
- [🏗️ Architecture](#architecture)
- [🛠️ Development](#development)
- [🐳 Docker](#docker)
- [🗣️ Text-to-Speech Integration](#text-to-speech-integration)
- [📚 Examples](#examples)
- [❓ FAQ](#faq)
- [📜 License](#license)
- [💖 Acknowledgments](#acknowledgments)
- [⭐ Star History](#star-history)
## Quick Start
DeerFlow is developed in Python, and comes with a web UI written in Node.js. To ensure a smooth setup process, we recommend using the following tools:
### Recommended Tools
- **[`uv`](https://docs.astral.sh/uv/getting-started/installation/):**
Simplify Python environment and dependency management. `uv` automatically creates a virtual environment in the root directory and installs all required packages for you—no need to manually install Python environments.
- **[`nvm`](https://github.com/nvm-sh/nvm):**
Manage multiple versions of the Node.js runtime effortlessly.
- **[`pnpm`](https://pnpm.io/installation):**
Install and manage dependencies of Node.js project.
### Environment Requirements
Make sure your system meets the following minimum requirements:
- **[Python](https://www.python.org/downloads/):** Version `3.12+`
- **[Node.js](https://nodejs.org/en/download/):** Version `22+`
### Installation
```bash
# Clone the repository
git clone https://github.com/bytedance/deer-flow.git
cd deer-flow
# Install dependencies, uv will take care of the python interpreter and venv creation, and install the required packages
uv sync
# Configure .env with your API keys
# Tavily: https://app.tavily.com/home
# Brave_SEARCH: https://brave.com/search/api/
# volcengine TTS: Add your TTS credentials if you have them
cp .env.example .env
# See the 'Supported Search Engines' and 'Text-to-Speech Integration' sections below for all available options
# Configure conf.yaml for your LLM model and API keys
# Please refer to 'docs/configuration_guide.md' for more details
# For local development, you can use Ollama or other local models
cp conf.yaml.example conf.yaml
# Install marp for ppt generation
# https://github.com/marp-team/marp-cli?tab=readme-ov-file#use-package-manager
brew install marp-cli
```
Optionally, install web UI dependencies via [pnpm](https://pnpm.io/installation):
```bash
cd deer-flow/web
pnpm install
```
### Configurations
Please refer to the [Configuration Guide](docs/configuration_guide.md) for more details.
> [!NOTE]
> Before you start the project, read the guide carefully, and update the configurations to match your specific settings and requirements.
### Console UI
The quickest way to run the project is to use the console UI.
```bash
# Run the project in a bash-like shell
uv run main.py
```
### Web UI
This project also includes a Web UI, offering a more dynamic and engaging interactive experience.
> [!NOTE]
> You need to install the dependencies of web UI first.
```bash
# Run both the backend and frontend servers in development mode
# On macOS/Linux
./bootstrap.sh -d
# On Windows
bootstrap.bat -d
```
> [!Note]
> By default, the backend server binds to 127.0.0.1 (localhost) for security reasons. If you need to allow external connections (e.g., when deploying on Linux server), you can modify the server host to 0.0.0.0 in the bootstrap script(uv run server.py --host 0.0.0.0).
> Please ensure your environment is properly secured before exposing the service to external networks.
Open your browser and visit [`http://localhost:3000`](http://localhost:3000) to explore the web UI.
Explore more details in the [`web`](./web/) directory.
## Supported Search Engines
### Web Search
DeerFlow supports multiple search engines that can be configured in your `.env` file using the `SEARCH_API` variable:
- **Tavily** (default): A specialized search API for AI applications
- Requires `TAVILY_API_KEY` in your `.env` file
- Sign up at: https://app.tavily.com/home
- **InfoQuest** (recommended): AI-optimized intelligent search and crawling toolset independently developed by BytePlus
- Requires `INFOQUEST_API_KEY` in your `.env` file
- Support for time range filtering and site filtering
- Provides high-quality search results and content extraction
- Sign up at: https://console.byteplus.com/infoquest/infoquests
- Visit https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest to learn more
- **DuckDuckGo**: Privacy-focused search engine
- No API key required
- **Brave Search**: Privacy-focused search engine with advanced features
- Requires `BRAVE_SEARCH_API_KEY` in your `.env` file
- Sign up at: https://brave.com/search/api/
- **Arxiv**: Scientific paper search for academic research
- No API key required
- Specialized for scientific and academic papers
- **Searx/SearxNG**: Self-hosted metasearch engine
- Requires `SEARX_HOST` to be set in the `.env` file
- Supports connecting to either Searx or SearxNG
To configure your preferred search engine, set the `SEARCH_API` variable in your `.env` file:
```bash
# Choose one: tavily, infoquest, duckduckgo, brave_search, arxiv
SEARCH_API=tavily
```
### Crawling Tools
DeerFlow supports multiple crawling tools that can be configured in your `conf.yaml` file:
- **Jina** (default): Freely accessible web content crawling tool
- **InfoQuest** (recommended): AI-optimized intelligent search and crawling toolset developed by BytePlus
- Requires `INFOQUEST_API_KEY` in your `.env` file
- Provides configurable crawling parameters
- Supports custom timeout settings
- Offers more powerful content extraction capabilities
- Visit https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest to learn more
To configure your preferred crawling tool, set the following in your `conf.yaml` file:
```yaml
CRAWLER_ENGINE:
# Engine type: "jina" (default) or "infoquest"
engine: infoquest
```
### Private Knowledgebase
DeerFlow supports private knowledgebase such as RAGFlow, Qdrant, Milvus, and VikingDB, so that you can use your private documents to answer questions.
- **[RAGFlow](https://ragflow.io/docs/dev/)**: open source RAG engine
```bash
# examples in .env.example
RAG_PROVIDER=ragflow
RAGFLOW_API_URL="http://localhost:9388"
RAGFLOW_API_KEY="ragflow-xxx"
RAGFLOW_RETRIEVAL_SIZE=10
RAGFLOW_CROSS_LANGUAGES=English,Chinese,Spanish,French,German,Japanese,Korean
```
- **[Qdrant](https://qdrant.tech/)**: open source vector database
```bash
# Using Qdrant Cloud or self-hosted
RAG_PROVIDER=qdrant
QDRANT_LOCATION=https://xyz-example.eu-central.aws.cloud.qdrant.io:6333
QDRANT_API_KEY=your_qdrant_api_key
QDRANT_COLLECTION=documents
QDRANT_EMBEDDING_PROVIDER=openai
QDRANT_EMBEDDING_MODEL=text-embedding-ada-002
QDRANT_EMBEDDING_API_KEY=your_openai_api_key
QDRANT_AUTO_LOAD_EXAMPLES=true
```
## Features
### Core Capabilities
- 🤖 **LLM Integration**
- It supports the integration of most models through [litellm](https://docs.litellm.ai/docs/providers).
- Support for open source models like Qwen, you need to read the [configuration](docs/configuration_guide.md) for more details.
- OpenAI-compatible API interface
- Multi-tier LLM system for different task complexities
### Tools and MCP Integrations
- 🔍 **Search and Retrieval**
- Web search via Tavily, InfoQuest, Brave Search and more
- Crawling with Jina and InfoQuest
- Advanced content extraction
- Support for private knowledgebase
- 📃 **RAG Integration**
- Supports multiple vector databases: [Qdrant](https://qdrant.tech/), [Milvus](https://milvus.io/), [RAGFlow](https://github.com/infiniflow/ragflow), VikingDB, MOI, and Dify
- Supports mentioning files from RAG providers within the input box
- Easy switching between different vector databases through configuration
- 🔗 **MCP Seamless Integration**
- Expand capabilities for private domain access, knowledge graph, web browsing and more
- Facilitates integration of diverse research tools and methodologies
### Human Collaboration
- 💬 **Intelligent Clarification Feature**
- Multi-turn dialogue to clarify vague research topics
- Improve research precision and report quality
- Reduce ineffective searches and token usage
- Configurable switch for flexible enable/disable control
- See [Configuration Guide - Clarification](./docs/configuration_guide.md#multi-turn-clarification-feature) for details
- 🧠 **Human-in-the-loop**
- Supports interactive modification of research plans using natural language
- Supports auto-acceptance of research plans
- 📝 **Report Post-Editing**
- Supports Notion-like block editing
- Allows AI refinements, including AI-assisted polishing, sentence shortening, and expansion
- Powered by [tiptap](https://tiptap.dev/)
### Content Creation
- 🎙️ **Podcast and Presentation Generation**
- AI-powered podcast script generation and audio synthesis
- Automated creation of simple PowerPoint presentations
- Customizable templates for tailored content
## Architecture
DeerFlow implements a modular multi-agent system architecture designed for automated research and code analysis. The system is built on LangGraph, enabling a flexible state-based workflow where components communicate through a well-defined message passing system.
![Architecture Diagram](./assets/architecture.png)
> See it live at [deerflow.tech](https://deerflow.tech/#multi-agent-architecture)
The system employs a streamlined workflow with the following components:
1. **Coordinator**: The entry point that manages the workflow lifecycle
- Initiates the research process based on user input
- Delegates tasks to the planner when appropriate
- Acts as the primary interface between the user and the system
2. **Planner**: Strategic component for task decomposition and planning
- Analyzes research objectives and creates structured execution plans
- Determines if enough context is available or if more research is needed
- Manages the research flow and decides when to generate the final report
3. **Research Team**: A collection of specialized agents that execute the plan:
- **Researcher**: Conducts web searches and information gathering using tools like web search engines, crawling and even MCP services.
- **Coder**: Handles code analysis, execution, and technical tasks using Python REPL tool.
Each agent has access to specific tools optimized for their role and operates within the LangGraph framework
4. **Reporter**: Final stage processor for research outputs
- Aggregates findings from the research team
- Processes and structures the collected information
- Generates comprehensive research reports
## Text-to-Speech Integration
DeerFlow now includes a Text-to-Speech (TTS) feature that allows you to convert research reports to speech. This feature uses the volcengine TTS API to generate high-quality audio from text. Features like speed, volume, and pitch are also customizable.
### Using the TTS API
You can access the TTS functionality through the `/api/tts` endpoint:
```bash
# Example API call using curl
curl --location 'http://localhost:8000/api/tts' \
--header 'Content-Type: application/json' \
--data '{
"text": "This is a test of the text-to-speech functionality.",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
}' \
--output speech.mp3
```
## Development
### Testing
Install development dependencies:
```bash
uv pip install -e ".[test]"
```
Run the test suite:
```bash
# Run all tests
make test
# Run specific test file
pytest tests/integration/test_workflow.py
# Run with coverage
make coverage
```
### Code Quality
```bash
# Run linting
make lint
# Format code
make format
```
### Debugging with LangGraph Studio
DeerFlow uses LangGraph for its workflow architecture. You can use LangGraph Studio to debug and visualize the workflow in real-time.
#### Running LangGraph Studio Locally
DeerFlow includes a `langgraph.json` configuration file that defines the graph structure and dependencies for the LangGraph Studio. This file points to the workflow graphs defined in the project and automatically loads environment variables from the `.env` file.
##### Mac
```bash
# Install uv package manager if you don't have it
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install dependencies and start the LangGraph server
uvx --refresh --from "langgraph-cli[inmem]" --with-editable . --python 3.12 langgraph dev --allow-blocking
```
##### Windows / Linux
```bash
# Install dependencies
pip install -e .
pip install -U "langgraph-cli[inmem]"
# Start the LangGraph server
langgraph dev
```
After starting the LangGraph server, you'll see several URLs in the terminal:
- API: http://127.0.0.1:2024
- Studio UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
- API Docs: http://127.0.0.1:2024/docs
Open the Studio UI link in your browser to access the debugging interface.
#### Using LangGraph Studio
In the Studio UI, you can:
1. Visualize the workflow graph and see how components connect
2. Trace execution in real-time to see how data flows through the system
3. Inspect the state at each step of the workflow
4. Debug issues by examining inputs and outputs of each component
5. Provide feedback during the planning phase to refine research plans
When you submit a research topic in the Studio UI, you'll be able to see the entire workflow execution, including:
- The planning phase where the research plan is created
- The feedback loop where you can modify the plan
- The research and writing phases for each section
- The final report generation
### Enabling LangSmith Tracing 
DeerFlow supports LangSmith tracing to help you debug and monitor your workflows. To enable LangSmith tracing:
1. Make sure your `.env` file has the following configurations (see `.env.example`):
```bash
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY="xxx"
LANGSMITH_PROJECT="xxx"
```
2. Start tracing and visualize the graph locally with LangSmith by running:
```bash
langgraph dev
```
This will enable trace visualization in LangGraph Studio and send your traces to LangSmith for monitoring and analysis.
### Checkpointing
1. Postgres and MongoDB implementation of LangGraph checkpoint saver.
2. In-memory store is used to cache the streaming messages before persisting to database; If finish_reason is "stop" or "interrupt", it triggers persistence.
3. Supports saving and loading checkpoints for workflow execution.
4. Supports saving chat stream events for replaying conversations.
*Note: About langgraph issue #5557*
The latest langgraph-checkpoint-postgres-2.0.23 have checkpointing issue, you can check the open issue: "TypeError: Object of type HumanMessage is not JSON serializable" [https://github.com/langchain-ai/langgraph/issues/5557].
To use postgres checkpoint, you should install langgraph-checkpoint-postgres-2.0.21
*Note: About psycopg dependencies*
Please read the following document before using postgres: https://www.psycopg.org/psycopg3/docs/basic/install.html
BY default, psycopg needs libpq to be installed on your system. If you don't have libpq installed, you can install psycopg with the `binary` extra to include a statically linked version of libpq manually:
```bash
pip install psycopg[binary]
```
This will install a self-contained package with all the libraries needed, but binary not supported for all platform, you check the supported platform: https://pypi.org/project/psycopg-binary/#files
If not supported, you can select local-installation: https://www.psycopg.org/psycopg3/docs/basic/install.html#local-installation
The default database and collection will be automatically created if not exists.
Default database: checkpoing_db
Default collection: checkpoint_writes_aio (langgraph checkpoint writes)
Default collection: checkpoints_aio (langgraph checkpoints)
Default collection: chat_streams (chat stream events for replaying conversations)
You need to set the following environment variables in your `.env` file:
```bash
# Enable LangGraph checkpoint saver, supports MongoDB, Postgres
LANGGRAPH_CHECKPOINT_SAVER=true
# Set the database URL for saving checkpoints
LANGGRAPH_CHECKPOINT_DB_URL="mongodb://localhost:27017/"
#LANGGRAPH_CHECKPOINT_DB_URL=postgresql://localhost:5432/postgres
```
## Docker
You can also run this project with Docker.
First, you need to read the [configuration](docs/configuration_guide.md) below. Make sure `.env`, `.conf.yaml` files are ready.
Second, to build a Docker image of your own web server:
```bash
docker build -t deer-flow-api .
```
Finally, start up a docker container running the web server:
```bash
# Replace deer-flow-api-app with your preferred container name
# Start the server then bind to localhost:8000
docker run -d -t -p 127.0.0.1:8000:8000 --env-file .env --name deer-flow-api-app deer-flow-api
# stop the server
docker stop deer-flow-api-app
```
### Docker Compose (include both backend and frontend)
DeerFlow provides a docker-compose setup to easily run both the backend and frontend together.
#### Configuration
Before building, configure the root `.env` file (copied from `.env.example`):
```bash
cp .env.example .env
cp conf.yaml.example conf.yaml
```
> [!IMPORTANT]
> The `docker-compose.yml` only uses the **root `.env`** file (not `web/.env`). You do **not** need to create or modify `web/.env` when using Docker Compose.
If you are deploying on a **remote server** or accessing from a **LAN IP** (not `localhost`), you **must** update `NEXT_PUBLIC_API_URL` in the root `.env` to your actual host IP or domain:
```bash
# Example: accessing from LAN IP
NEXT_PUBLIC_API_URL=http://192.168.1.100:8000/api
# Example: remote deployment with domain
NEXT_PUBLIC_API_URL=https://your-domain.com/api
```
> [!NOTE]
> `NEXT_PUBLIC_API_URL` is a **build-time** variable for Next.js — it gets embedded into the frontend JavaScript bundle during `docker compose build`. If you change this value later, you must rebuild with `docker compose build` for the change to take effect.
#### Build and Run
```bash
# building docker image
docker compose build
# start the server
docker compose up
```
> [!WARNING]
> If you want to deploy the deer flow into production environments, please add authentication to the website and evaluate your security check of the MCPServer and Python Repl.
## Examples
The following examples demonstrate the capabilities of DeerFlow:
### Research Reports
1. **OpenAI Sora Report** - Analysis of OpenAI's Sora AI tool
- Discusses features, access, prompt engineering, limitations, and ethical considerations
- [View full report](examples/openai_sora_report.md)
2. **Google's Agent to Agent Protocol Report** - Overview of Google's Agent to Agent (A2A) protocol
- Discusses its role in AI agent communication and its relationship with Anthropic's Model Context Protocol (MCP)
- [View full report](examples/what_is_agent_to_agent_protocol.md)
3. **What is MCP?** - A comprehensive analysis of the term "MCP" across multiple contexts
- Explores Model Context Protocol in AI, Monocalcium Phosphate in chemistry, and Micro-channel Plate in electronics
- [View full report](examples/what_is_mcp.md)
4. **Bitcoin Price Fluctuations** - Analysis of recent Bitcoin price movements
- Examines market trends, regulatory influences, and technical indicators
- Provides recommendations based on historical data
- [View full report](examples/bitcoin_price_fluctuation.md)
5. **What is LLM?** - An in-depth exploration of Large Language Models
- Discusses architecture, training, applications, and ethical considerations
- [View full report](examples/what_is_llm.md)
6. **How to Use Claude for Deep Research?** - Best practices and workflows for using Claude in deep research
- Covers prompt engineering, data analysis, and integration with other tools
- [View full report](examples/how_to_use_claude_deep_research.md)
7. **AI Adoption in Healthcare: Influencing Factors** - Analysis of factors driving AI adoption in healthcare
- Discusses AI technologies, data quality, ethical considerations, economic evaluations, organizational readiness, and digital infrastructure
- [View full report](examples/AI_adoption_in_healthcare.md)
8. **Quantum Computing Impact on Cryptography** - Analysis of quantum computing's impact on cryptography
- Discusses vulnerabilities of classical cryptography, post-quantum cryptography, and quantum-resistant cryptographic solutions
- [View full report](examples/Quantum_Computing_Impact_on_Cryptography.md)
9. **Cristiano Ronaldo's Performance Highlights** - Analysis of Cristiano Ronaldo's performance highlights
- Discusses his career achievements, international goals, and performance in various matches
- [View full report](examples/Cristiano_Ronaldo's_Performance_Highlights.md)
To run these examples or create your own research reports, you can use the following commands:
```bash
# Run with a specific query
uv run main.py "What factors are influencing AI adoption in healthcare?"
# Run with custom planning parameters
uv run main.py --max_plan_iterations 3 "How does quantum computing impact cryptography?"
# Run in interactive mode with built-in questions
uv run main.py --interactive
# Or run with basic interactive prompt
uv run main.py
# View all available options
uv run main.py --help
```
### Interactive Mode
The application now supports an interactive mode with built-in questions in both English and Chinese:
1. Launch the interactive mode:
```bash
uv run main.py --interactive
```
2. Select your preferred language (English or 中文)
3. Choose from a list of built-in questions or select the option to ask your own question
4. The system will process your question and generate a comprehensive research report
### Human in the Loop
DeerFlow includes a human in the loop mechanism that allows you to review, edit, and approve research plans before they are executed:
1. **Plan Review**: When human in the loop is enabled, the system will present the generated research plan for your review before execution
2. **Providing Feedback**: You can:
- Accept the plan by responding with `[ACCEPTED]`
- Edit the plan by providing feedback (e.g., `[EDIT PLAN] Add more steps about technical implementation`)
- The system will incorporate your feedback and generate a revised plan
3. **Auto-acceptance**: You can enable auto-acceptance to skip the review process:
- Via API: Set `auto_accepted_plan: true` in your request
4. **API Integration**: When using the API, you can provide feedback through the `feedback` parameter:
```json
{
"messages": [{ "role": "user", "content": "What is quantum computing?" }],
"thread_id": "my_thread_id",
"auto_accepted_plan": false,
"feedback": "[EDIT PLAN] Include more about quantum algorithms"
}
```
### Command Line Arguments
The application supports several command-line arguments to customize its behavior:
- **query**: The research query to process (can be multiple words)
- **--interactive**: Run in interactive mode with built-in questions
- **--max_plan_iterations**: Maximum number of planning cycles (default: 1)
- **--max_step_num**: Maximum number of steps in a research plan (default: 3)
- **--debug**: Enable detailed debug logging
## FAQ
Please refer to the [FAQ.md](docs/FAQ.md) for more details.
## License
This project is open source and available under the [MIT License](./LICENSE).
## Acknowledgments
DeerFlow is built upon the incredible work of the open-source community. We are deeply grateful to all the projects and contributors whose efforts have made DeerFlow possible. Truly, we stand on the shoulders of giants.
We would like to extend our sincere appreciation to the following projects for their invaluable contributions:
- **[LangChain](https://github.com/langchain-ai/langchain)**: Their exceptional framework powers our LLM interactions and chains, enabling seamless integration and functionality.
- **[LangGraph](https://github.com/langchain-ai/langgraph)**: Their innovative approach to multi-agent orchestration has been instrumental in enabling DeerFlow's sophisticated workflows.
- **[Novel](https://github.com/steven-tey/novel)**: Their Notion-style WYSIWYG editor supports our report editing and AI-assisted rewriting.
- **[RAGFlow](https://github.com/infiniflow/ragflow)**: We have achieved support for research on users' private knowledge bases through integration with RAGFlow.
These projects exemplify the transformative power of open-source collaboration, and we are proud to build upon their foundations.
### Key Contributors
A heartfelt thank you goes out to the core authors of `DeerFlow`, whose vision, passion, and dedication have brought this project to life:
- **[Daniel Walnut](https://github.com/hetaoBackend/)**
- **[Henry Li](https://github.com/magiccube/)**
Your unwavering commitment and expertise have been the driving force behind DeerFlow's success. We are honored to have you at the helm of this journey.
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=bytedance/deer-flow&type=Date)](https://star-history.com/#bytedance/deer-flow&Date)

View File

@@ -1,610 +0,0 @@
# 🦌 DeerFlow
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![DeepWiki](https://img.shields.io/badge/DeepWiki-bytedance%2Fdeer--flow-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McCcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/bytedance/deer-flow)
<!-- DeepWiki badge generated by https://deepwiki.ryoppippi.com/ -->
[English](./README.md) | [简体中文](./README_zh.md) | [日本語](./README_ja.md) | [Deutsch](./README_de.md) | [Español](./README_es.md) | [Русский](./README_ru.md) | [Portuguese](./README_pt.md)
> Aus Open Source entstanden, an Open Source zurückgeben.
**DeerFlow** (**D**eep **E**xploration and **E**fficient **R**esearch **Flow**) ist ein Community-getriebenes Framework für tiefgehende Recherche, das auf der großartigen Arbeit der Open-Source-Community aufbaut. Unser Ziel ist es, Sprachmodelle mit spezialisierten Werkzeugen für Aufgaben wie Websuche, Crawling und Python-Code-Ausführung zu kombinieren und gleichzeitig der Community, die dies möglich gemacht hat, etwas zurückzugeben.
Derzeit ist DeerFlow offiziell in das [FaaS-Anwendungszentrum von Volcengine](https://console.volcengine.com/vefaas/region:vefaas+cn-beijing/market) eingezogen. Benutzer können es über den [Erfahrungslink](https://console.volcengine.com/vefaas/region:vefaas+cn-beijing/market/deerflow/?channel=github&source=deerflow) online erleben, um seine leistungsstarken Funktionen und bequemen Operationen intuitiv zu spüren. Gleichzeitig unterstützt DeerFlow zur Erfüllung der Bereitstellungsanforderungen verschiedener Benutzer die Ein-Klick-Bereitstellung basierend auf Volcengine. Klicken Sie auf den [Bereitstellungslink](https://console.volcengine.com/vefaas/region:vefaas+cn-beijing/application/create?templateId=683adf9e372daa0008aaed5c&channel=github&source=deerflow), um den Bereitstellungsprozess schnell abzuschließen und eine effiziente Forschungsreise zu beginnen.
DeerFlow hat neu die intelligente Such- und Crawling-Toolset von BytePlus integriert - [InfoQuest (unterstützt kostenlose Online-Erfahrung)](https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest)
<a href="https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest" target="_blank">
<img
src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/hubseh7bsbps/20251208-160108.png" alt="infoquest_bannar"
/>
</a>
Besuchen Sie [unsere offizielle Website](https://deerflow.tech/) für weitere Details.
## Demo
### Video
<https://github.com/user-attachments/assets/f3786598-1f2a-4d07-919e-8b99dfa1de3e>
In dieser Demo zeigen wir, wie man DeerFlow nutzt, um:
- Nahtlos mit MCP-Diensten zu integrieren
- Den Prozess der tiefgehenden Recherche durchzuführen und einen umfassenden Bericht mit Bildern zu erstellen
- Podcast-Audio basierend auf dem generierten Bericht zu erstellen
### Wiedergaben
- [Wie hoch ist der Eiffelturm im Vergleich zum höchsten Gebäude?](https://deerflow.tech/chat?replay=eiffel-tower-vs-tallest-building)
- [Was sind die angesagtesten Repositories auf GitHub?](https://deerflow.tech/chat?replay=github-top-trending-repo)
- [Einen Artikel über traditionelle Gerichte aus Nanjing schreiben](https://deerflow.tech/chat?replay=nanjing-traditional-dishes)
- [Wie dekoriert man eine Mietwohnung?](https://deerflow.tech/chat?replay=rental-apartment-decoration)
- [Besuchen Sie unsere offizielle Website, um weitere Wiedergaben zu entdecken.](https://deerflow.tech/#case-studies)
---
## 📑 Inhaltsverzeichnis
- [🚀 Schnellstart](#schnellstart)
- [🌟 Funktionen](#funktionen)
- [🏗️ Architektur](#architektur)
- [🛠️ Entwicklung](#entwicklung)
- [🐳 Docker](#docker)
- [🗣️ Text-zu-Sprache-Integration](#text-zu-sprache-integration)
- [📚 Beispiele](#beispiele)
- [❓ FAQ](#faq)
- [📜 Lizenz](#lizenz)
- [💖 Danksagungen](#danksagungen)
- [⭐ Star-Verlauf](#star-verlauf)
## Schnellstart
DeerFlow ist in Python entwickelt und kommt mit einer in Node.js geschriebenen Web-UI. Um einen reibungslosen Einrichtungsprozess zu gewährleisten, empfehlen wir die Verwendung der folgenden Tools:
### Empfohlene Tools
- **[`uv`](https://docs.astral.sh/uv/getting-started/installation/):**
Vereinfacht die Verwaltung von Python-Umgebungen und Abhängigkeiten. `uv` erstellt automatisch eine virtuelle Umgebung im Stammverzeichnis und installiert alle erforderlichen Pakete für Sie—keine manuelle Installation von Python-Umgebungen notwendig.
- **[`nvm`](https://github.com/nvm-sh/nvm):**
Verwalten Sie mühelos mehrere Versionen der Node.js-Laufzeit.
- **[`pnpm`](https://pnpm.io/installation):**
Installieren und verwalten Sie Abhängigkeiten des Node.js-Projekts.
### Umgebungsanforderungen
Stellen Sie sicher, dass Ihr System die folgenden Mindestanforderungen erfüllt:
- **[Python](https://www.python.org/downloads/):** Version `3.12+`
- **[Node.js](https://nodejs.org/en/download/):** Version `22+`
### Installation
```bash
# Repository klonen
git clone https://github.com/bytedance/deer-flow.git
cd deer-flow
# Abhängigkeiten installieren, uv kümmert sich um den Python-Interpreter und die Erstellung der venv sowie die Installation der erforderlichen Pakete
uv sync
# Konfigurieren Sie .env mit Ihren API-Schlüsseln
# Tavily: https://app.tavily.com/home
# Brave_SEARCH: https://brave.com/search/api/
# volcengine TTS: Fügen Sie Ihre TTS-Anmeldedaten hinzu, falls vorhanden
cp .env.example .env
# Siehe die Abschnitte 'Unterstützte Suchmaschinen' und 'Text-zu-Sprache-Integration' unten für alle verfügbaren Optionen
# Konfigurieren Sie conf.yaml für Ihr LLM-Modell und API-Schlüssel
# Weitere Details finden Sie unter 'docs/configuration_guide.md'
cp conf.yaml.example conf.yaml
# Installieren Sie marp für PPT-Generierung
# https://github.com/marp-team/marp-cli?tab=readme-ov-file#use-package-manager
brew install marp-cli
```
Optional können Sie Web-UI-Abhängigkeiten über [pnpm](https://pnpm.io/installation) installieren:
```bash
cd deer-flow/web
pnpm install
```
### Konfigurationen
Weitere Informationen finden Sie im [Konfigurationsleitfaden](docs/configuration_guide.md).
> [!HINWEIS]
> Lesen Sie den Leitfaden sorgfältig, bevor Sie das Projekt starten, und aktualisieren Sie die Konfigurationen entsprechend Ihren spezifischen Einstellungen und Anforderungen.
### Konsolen-UI
Der schnellste Weg, um das Projekt auszuführen, ist die Verwendung der Konsolen-UI.
```bash
# Führen Sie das Projekt in einer bash-ähnlichen Shell aus
uv run main.py
```
### Web-UI
Dieses Projekt enthält auch eine Web-UI, die ein dynamischeres und ansprechenderes interaktives Erlebnis bietet.
> [!HINWEIS]
> Sie müssen zuerst die Abhängigkeiten der Web-UI installieren.
```bash
# Führen Sie sowohl den Backend- als auch den Frontend-Server im Entwicklungsmodus aus
# Unter macOS/Linux
./bootstrap.sh -d
# Unter Windows
bootstrap.bat -d
```
> [!HINWEIS]
> Standardmäßig bindet sich der Backend-Server aus Sicherheitsgründen an 127.0.0.1 (localhost). Wenn Sie externe Verbindungen zulassen müssen (z. B. bei der Bereitstellung auf einem Linux-Server), können Sie den Server-Host im Bootstrap-Skript auf 0.0.0.0 ändern (uv run server.py --host 0.0.0.0).
> Bitte stellen Sie sicher, dass Ihre Umgebung ordnungsgemäß gesichert ist, bevor Sie den Service externen Netzwerken aussetzen.
Öffnen Sie Ihren Browser und besuchen Sie [`http://localhost:3000`](http://localhost:3000), um die Web-UI zu erkunden.
Weitere Details finden Sie im Verzeichnis [`web`](./web/).
## Unterstützte Suchmaschinen
### Websuche
DeerFlow unterstützt mehrere Suchmaschinen, die in Ihrer `.env`-Datei über die Variable `SEARCH_API` konfiguriert werden können:
- **Tavily** (Standard): Eine spezialisierte Such-API für KI-Anwendungen
- Erfordert `TAVILY_API_KEY` in Ihrer `.env`-Datei
- Registrieren Sie sich unter: https://app.tavily.com/home
- **InfoQuest** (empfohlen): Ein KI-optimiertes intelligentes Such- und Crawling-Toolset, entwickelt von BytePlus
- Erfordert `INFOQUEST_API_KEY` in Ihrer `.env`-Datei
- Unterstützung für Zeitbereichsfilterung und Seitenfilterung
- Bietet qualitativ hochwertige Suchergebnisse und Inhaltsextraktion
- Registrieren Sie sich unter: https://console.byteplus.com/infoquest/infoquests
- Besuchen Sie https://docs.byteplus.com/de/docs/InfoQuest/What_is_Info_Quest für weitere Informationen
- **DuckDuckGo**: Datenschutzorientierte Suchmaschine
- Kein API-Schlüssel erforderlich
- **Brave Search**: Datenschutzorientierte Suchmaschine mit erweiterten Funktionen
- Erfordert `BRAVE_SEARCH_API_KEY` in Ihrer `.env`-Datei
- Registrieren Sie sich unter: https://brave.com/search/api/
- **Arxiv**: Wissenschaftliche Papiersuche für akademische Forschung
- Kein API-Schlüssel erforderlich
- Spezialisiert auf wissenschaftliche und akademische Papiere
- **Searx/SearxNG**: Selbstgehostete Metasuchmaschine
- Erfordert `SEARX_HOST` in Ihrer `.env`-Datei
- Unterstützt die Anbindung an Searx oder SearxNG
Um Ihre bevorzugte Suchmaschine zu konfigurieren, setzen Sie die Variable `SEARCH_API` in Ihrer `.env`-Datei:
```bash
# Wählen Sie eine: tavily, infoquest, duckduckgo, brave_search, arxiv
SEARCH_API=tavily
```
### Crawling-Tools
- **Jina** (Standard): Kostenloses, zugängliches Webinhalts-Crawling-Tool
- Kein API-Schlüssel erforderlich für grundlegende Funktionen
- Mit API-Schlüssel erhalten Sie höhere Zugriffsraten
- Weitere Informationen unter <https://jina.ai/reader>
- **InfoQuest** (empfohlen): KI-optimiertes intelligentes Such- und Crawling-Toolset, entwickelt von BytePlus
- Erfordert `INFOQUEST_API_KEY` in Ihrer `.env`-Datei
- Bietet konfigurierbare Crawling-Parameter
- Unterstützt benutzerdefinierte Timeout-Einstellungen
- Bietet stärkere Inhaltsextraktionsfähigkeiten
- Weitere Informationen unter <https://docs.byteplus.com/de/docs/InfoQuest/What_is_Info_Quest>
Um Ihr bevorzugtes Crawling-Tool zu konfigurieren, setzen Sie Folgendes in Ihrer `conf.yaml`-Datei:
```yaml
CRAWLER_ENGINE:
# Engine-Typ: "jina" (Standard) oder "infoquest"
engine: infoquest
```
### Private Wissensbasis
DeerFlow unterstützt private Wissensbasen wie RAGFlow und VikingDB, sodass Sie Ihre privaten Dokumente zur Beantwortung von Fragen verwenden können.
- **[RAGFlow](https://ragflow.io/docs/dev/)**Open-Source-RAG-Engine
```
# Beispiele in .env.example
RAG_PROVIDER=ragflow
RAGFLOW_API_URL="http://localhost:9388"
RAGFLOW_API_KEY="ragflow-xxx"
RAGFLOW_RETRIEVAL_SIZE=10
RAGFLOW_CROSS_LANGUAGES=English,Chinese,Spanish,French,German,Japanese,Korean
```
## Funktionen
### Kernfähigkeiten
- 🤖 **LLM-Integration**
- Unterstützt die Integration der meisten Modelle über [litellm](https://docs.litellm.ai/docs/providers).
- Unterstützung für Open-Source-Modelle wie Qwen
- OpenAI-kompatible API-Schnittstelle
- Mehrstufiges LLM-System für unterschiedliche Aufgabenkomplexitäten
### Tools und MCP-Integrationen
- 🔍 **Suche und Abruf**
- Websuche über Tavily, InfoQuest, Brave Search und mehr
- Crawling mit Jina und InfoQuest
- Fortgeschrittene Inhaltsextraktion
- Unterstützung für private Wissensbasis
- 📃 **RAG-Integration**
- Unterstützt die Erwähnung von Dateien aus [RAGFlow](https://github.com/infiniflow/ragflow) innerhalb der Eingabebox. [RAGFlow-Server starten](https://ragflow.io/docs/dev/).
- 🔗 **MCP Nahtlose Integration**
- Erweiterte Fähigkeiten für privaten Domänenzugriff, Wissensgraphen, Webbrowsing und mehr
- Erleichtert die Integration verschiedener Forschungswerkzeuge und -methoden
### Menschliche Zusammenarbeit
- 🧠 **Mensch-in-der-Schleife**
- Unterstützt interaktive Modifikation von Forschungsplänen mit natürlicher Sprache
- Unterstützt automatische Akzeptanz von Forschungsplänen
- 📝 **Bericht-Nachbearbeitung**
- Unterstützt Notion-ähnliche Blockbearbeitung
- Ermöglicht KI-Verfeinerungen, einschließlich KI-unterstützter Polierung, Satzkürzung und -erweiterung
- Angetrieben von [tiptap](https://tiptap.dev/)
### Inhaltserstellung
- 🎙️ **Podcast- und Präsentationserstellung**
- KI-gestützte Podcast-Skripterstellung und Audiosynthese
- Automatisierte Erstellung einfacher PowerPoint-Präsentationen
- Anpassbare Vorlagen für maßgeschneiderte Inhalte
## Architektur
DeerFlow implementiert eine modulare Multi-Agenten-Systemarchitektur, die für automatisierte Forschung und Codeanalyse konzipiert ist. Das System basiert auf LangGraph und ermöglicht einen flexiblen zustandsbasierten Workflow, bei dem Komponenten über ein klar definiertes Nachrichtenübermittlungssystem kommunizieren.
![Architekturdiagramm](./assets/architecture.png)
> Sehen Sie es live auf [deerflow.tech](https://deerflow.tech/#multi-agent-architecture)
Das System verwendet einen optimierten Workflow mit den folgenden Komponenten:
1. **Koordinator**: Der Einstiegspunkt, der den Workflow-Lebenszyklus verwaltet
- Initiiert den Forschungsprozess basierend auf Benutzereingaben
- Delegiert Aufgaben bei Bedarf an den Planer
- Fungiert als primäre Schnittstelle zwischen dem Benutzer und dem System
2. **Planer**: Strategische Komponente für Aufgabenzerlegung und -planung
- Analysiert Forschungsziele und erstellt strukturierte Ausführungspläne
- Bestimmt, ob ausreichend Kontext verfügbar ist oder ob weitere Forschung benötigt wird
- Verwaltet den Forschungsablauf und entscheidet, wann der endgültige Bericht erstellt wird
3. **Forschungsteam**: Eine Sammlung spezialisierter Agenten, die den Plan ausführen:
- **Forscher**: Führt Websuchen und Informationssammlung mit Tools wie Websuchmaschinen, Crawling und sogar MCP-Diensten durch.
- **Codierer**: Behandelt Codeanalyse, -ausführung und technische Aufgaben mit dem Python REPL Tool.
Jeder Agent hat Zugriff auf spezifische Tools, die für seine Rolle optimiert sind, und operiert innerhalb des LangGraph-Frameworks
4. **Reporter**: Endphasenprozessor für Forschungsergebnisse
- Aggregiert Erkenntnisse vom Forschungsteam
- Verarbeitet und strukturiert die gesammelten Informationen
- Erstellt umfassende Forschungsberichte
## Text-zu-Sprache-Integration
DeerFlow enthält jetzt eine Text-zu-Sprache (TTS)-Funktion, mit der Sie Forschungsberichte in Sprache umwandeln können. Diese Funktion verwendet die volcengine TTS API, um hochwertige Audios aus Text zu generieren. Funktionen wie Geschwindigkeit, Lautstärke und Tonhöhe können ebenfalls angepasst werden.
### Verwendung der TTS API
Sie können auf die TTS-Funktionalität über den Endpunkt `/api/tts` zugreifen:
```bash
# Beispiel API-Aufruf mit curl
curl --location 'http://localhost:8000/api/tts' \
--header 'Content-Type: application/json' \
--data '{
"text": "Dies ist ein Test der Text-zu-Sprache-Funktionalität.",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
}' \
--output speech.mp3
```
## Entwicklung
### Testen
Führen Sie die Testsuite aus:
```bash
# Alle Tests ausführen
make test
# Spezifische Testdatei ausführen
pytest tests/integration/test_workflow.py
# Mit Abdeckung ausführen
make coverage
```
### Codequalität
```bash
# Lint ausführen
make lint
# Code formatieren
make format
```
### Debugging mit LangGraph Studio
DeerFlow verwendet LangGraph für seine Workflow-Architektur. Sie können LangGraph Studio verwenden, um den Workflow in Echtzeit zu debuggen und zu visualisieren.
#### LangGraph Studio lokal ausführen
DeerFlow enthält eine `langgraph.json`-Konfigurationsdatei, die die Graphstruktur und Abhängigkeiten für das LangGraph Studio definiert. Diese Datei verweist auf die im Projekt definierten Workflow-Graphen und lädt automatisch Umgebungsvariablen aus der `.env`-Datei.
##### Mac
```bash
# Installieren Sie den uv-Paketmanager, wenn Sie ihn noch nicht haben
curl -LsSf https://astral.sh/uv/install.sh | sh
# Installieren Sie Abhängigkeiten und starten Sie den LangGraph-Server
uvx --refresh --from "langgraph-cli[inmem]" --with-editable . --python 3.12 langgraph dev --allow-blocking
```
##### Windows / Linux
```bash
# Abhängigkeiten installieren
pip install -e .
pip install -U "langgraph-cli[inmem]"
# LangGraph-Server starten
langgraph dev
```
Nach dem Start des LangGraph-Servers sehen Sie mehrere URLs im Terminal:
- API: http://127.0.0.1:2024
- Studio UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
- API-Dokumentation: http://127.0.0.1:2024/docs
Öffnen Sie den Studio UI-Link in Ihrem Browser, um auf die Debugging-Schnittstelle zuzugreifen.
#### Verwendung von LangGraph Studio
In der Studio UI können Sie:
1. Den Workflow-Graphen visualisieren und sehen, wie Komponenten verbunden sind
2. Die Ausführung in Echtzeit verfolgen, um zu sehen, wie Daten durch das System fließen
3. Den Zustand in jedem Schritt des Workflows inspizieren
4. Probleme durch Untersuchung von Ein- und Ausgaben jeder Komponente debuggen
5. Feedback während der Planungsphase geben, um Forschungspläne zu verfeinern
Wenn Sie ein Forschungsthema in der Studio UI einreichen, können Sie die gesamte Workflow-Ausführung sehen, einschließlich:
- Die Planungsphase, in der der Forschungsplan erstellt wird
- Die Feedback-Schleife, in der Sie den Plan ändern können
- Die Forschungs- und Schreibphasen für jeden Abschnitt
- Die Erstellung des endgültigen Berichts
### Aktivieren von LangSmith-Tracing
DeerFlow unterstützt LangSmith-Tracing, um Ihnen beim Debuggen und Überwachen Ihrer Workflows zu helfen. Um LangSmith-Tracing zu aktivieren:
1. Stellen Sie sicher, dass Ihre `.env`-Datei die folgenden Konfigurationen enthält (siehe `.env.example`):
```bash
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY="xxx"
LANGSMITH_PROJECT="xxx"
```
2. Starten Sie das Tracing mit LangSmith lokal, indem Sie folgenden Befehl ausführen:
```bash
langgraph dev
```
Dies aktiviert die Trace-Visualisierung in LangGraph Studio und sendet Ihre Traces zur Überwachung und Analyse an LangSmith.
## Docker
Sie können dieses Projekt auch mit Docker ausführen.
Zuerst müssen Sie die [Konfiguration](docs/configuration_guide.md) unten lesen. Stellen Sie sicher, dass die Dateien `.env` und `.conf.yaml` bereit sind.
Zweitens, um ein Docker-Image Ihres eigenen Webservers zu erstellen:
```bash
docker build -t deer-flow-api .
```
Schließlich starten Sie einen Docker-Container, der den Webserver ausführt:
```bash
# Ersetzen Sie deer-flow-api-app durch Ihren bevorzugten Container-Namen
# Starten Sie den Server und binden Sie ihn an localhost:8000
docker run -d -t -p 127.0.0.1:8000:8000 --env-file .env --name deer-flow-api-app deer-flow-api
# Server stoppen
docker stop deer-flow-api-app
```
### Docker Compose (umfasst sowohl Backend als auch Frontend)
DeerFlow bietet ein docker-compose-Setup, um sowohl das Backend als auch das Frontend einfach zusammen auszuführen:
```bash
# Docker-Image erstellen
docker compose build
# Server starten
docker compose up
```
> [!WARNING]
> Wenn Sie DeerFlow in Produktionsumgebungen bereitstellen möchten, fügen Sie bitte Authentifizierung zur Website hinzu und bewerten Sie Ihre Sicherheitsüberprüfung des MCPServer und Python Repl.
## Beispiele
Die folgenden Beispiele demonstrieren die Fähigkeiten von DeerFlow:
### Forschungsberichte
1. **OpenAI Sora Bericht** - Analyse von OpenAIs Sora KI-Tool
- Diskutiert Funktionen, Zugang, Prompt-Engineering, Einschränkungen und ethische Überlegungen
- [Vollständigen Bericht ansehen](examples/openai_sora_report.md)
2. **Googles Agent-to-Agent-Protokoll Bericht** - Überblick über Googles Agent-to-Agent (A2A)-Protokoll
- Diskutiert seine Rolle in der KI-Agentenkommunikation und seine Beziehung zum Model Context Protocol (MCP) von Anthropic
- [Vollständigen Bericht ansehen](examples/what_is_agent_to_agent_protocol.md)
3. **Was ist MCP?** - Eine umfassende Analyse des Begriffs "MCP" in mehreren Kontexten
- Untersucht Model Context Protocol in KI, Monocalciumphosphat in der Chemie und Micro-channel Plate in der Elektronik
- [Vollständigen Bericht ansehen](examples/what_is_mcp.md)
4. **Bitcoin-Preisschwankungen** - Analyse der jüngsten Bitcoin-Preisbewegungen
- Untersucht Markttrends, regulatorische Einflüsse und technische Indikatoren
- Bietet Empfehlungen basierend auf historischen Daten
- [Vollständigen Bericht ansehen](examples/bitcoin_price_fluctuation.md)
5. **Was ist LLM?** - Eine eingehende Erforschung großer Sprachmodelle
- Diskutiert Architektur, Training, Anwendungen und ethische Überlegungen
- [Vollständigen Bericht ansehen](examples/what_is_llm.md)
6. **Wie nutzt man Claude für tiefgehende Recherche?** - Best Practices und Workflows für die Verwendung von Claude in der tiefgehenden Forschung
- Behandelt Prompt-Engineering, Datenanalyse und Integration mit anderen Tools
- [Vollständigen Bericht ansehen](examples/how_to_use_claude_deep_research.md)
7. **KI-Adoption im Gesundheitswesen: Einflussfaktoren** - Analyse der Faktoren, die die KI-Adoption im Gesundheitswesen vorantreiben
- Diskutiert KI-Technologien, Datenqualität, ethische Überlegungen, wirtschaftliche Bewertungen, organisatorische Bereitschaft und digitale Infrastruktur
- [Vollständigen Bericht ansehen](examples/AI_adoption_in_healthcare.md)
8. **Auswirkungen des Quantencomputing auf die Kryptographie** - Analyse der Auswirkungen des Quantencomputing auf die Kryptographie
- Diskutiert Schwachstellen der klassischen Kryptographie, Post-Quanten-Kryptographie und quantenresistente kryptographische Lösungen
- [Vollständigen Bericht ansehen](examples/Quantum_Computing_Impact_on_Cryptography.md)
9. **Cristiano Ronaldos Leistungshöhepunkte** - Analyse der Leistungshöhepunkte von Cristiano Ronaldo
- Diskutiert seine Karriereerfolge, internationalen Tore und Leistungen in verschiedenen Spielen
- [Vollständigen Bericht ansehen](examples/Cristiano_Ronaldo's_Performance_Highlights.md)
Um diese Beispiele auszuführen oder Ihre eigenen Forschungsberichte zu erstellen, können Sie die folgenden Befehle verwenden:
```bash
# Mit einer spezifischen Anfrage ausführen
uv run main.py "Welche Faktoren beeinflussen die KI-Adoption im Gesundheitswesen?"
# Mit benutzerdefinierten Planungsparametern ausführen
uv run main.py --max_plan_iterations 3 "Wie wirkt sich Quantencomputing auf die Kryptographie aus?"
# Im interaktiven Modus mit eingebauten Fragen ausführen
uv run main.py --interactive
# Oder mit grundlegendem interaktiven Prompt ausführen
uv run main.py
# Alle verfügbaren Optionen anzeigen
uv run main.py --help
```
### Interaktiver Modus
Die Anwendung unterstützt jetzt einen interaktiven Modus mit eingebauten Fragen in Englisch und Chinesisch:
1. Starten Sie den interaktiven Modus:
```bash
uv run main.py --interactive
```
2. Wählen Sie Ihre bevorzugte Sprache (English oder 中文)
3. Wählen Sie aus einer Liste von eingebauten Fragen oder wählen Sie die Option, Ihre eigene Frage zu stellen
4. Das System wird Ihre Frage verarbeiten und einen umfassenden Forschungsbericht generieren
### Mensch-in-der-Schleife
DeerFlow enthält einen Mensch-in-der-Schleife-Mechanismus, der es Ihnen ermöglicht, Forschungspläne vor ihrer Ausführung zu überprüfen, zu bearbeiten und zu genehmigen:
1. **Planüberprüfung**: Wenn Mensch-in-der-Schleife aktiviert ist, präsentiert das System den generierten Forschungsplan zur Überprüfung vor der Ausführung
2. **Feedback geben**: Sie können:
- Den Plan akzeptieren, indem Sie mit `[ACCEPTED]` antworten
- Den Plan bearbeiten, indem Sie Feedback geben (z.B., `[EDIT PLAN] Fügen Sie mehr Schritte zur technischen Implementierung hinzu`)
- Das System wird Ihr Feedback einarbeiten und einen überarbeiteten Plan generieren
3. **Automatische Akzeptanz**: Sie können die automatische Akzeptanz aktivieren, um den Überprüfungsprozess zu überspringen:
- Über API: Setzen Sie `auto_accepted_plan: true` in Ihrer Anfrage
4. **API-Integration**: Bei Verwendung der API können Sie Feedback über den Parameter `feedback` geben:
```json
{
"messages": [{"role": "user", "content": "Was ist Quantencomputing?"}],
"thread_id": "my_thread_id",
"auto_accepted_plan": false,
"feedback": "[EDIT PLAN] Mehr über Quantenalgorithmen aufnehmen"
}
```
### Kommandozeilenargumente
Die Anwendung unterstützt mehrere Kommandozeilenargumente, um ihr Verhalten anzupassen:
- **query**: Die zu verarbeitende Forschungsanfrage (kann mehrere Wörter umfassen)
- **--interactive**: Im interaktiven Modus mit eingebauten Fragen ausführen
- **--max_plan_iterations**: Maximale Anzahl von Planungszyklen (Standard: 1)
- **--max_step_num**: Maximale Anzahl von Schritten in einem Forschungsplan (Standard: 3)
- **--debug**: Detaillierte Debug-Protokollierung aktivieren
## FAQ
Weitere Informationen finden Sie in der [FAQ.md](docs/FAQ.md).
## Lizenz
Dieses Projekt ist Open Source und unter der [MIT-Lizenz](./LICENSE) verfügbar.
## Danksagungen
DeerFlow baut auf der unglaublichen Arbeit der Open-Source-Community auf. Wir sind allen Projekten und Mitwirkenden zutiefst dankbar, deren Bemühungen DeerFlow möglich gemacht haben. Wahrhaftig stehen wir auf den Schultern von Riesen.
Wir möchten unsere aufrichtige Wertschätzung den folgenden Projekten für ihre unschätzbaren Beiträge aussprechen:
- **[LangChain](https://github.com/langchain-ai/langchain)**: Ihr außergewöhnliches Framework unterstützt unsere LLM-Interaktionen und -Ketten und ermöglicht nahtlose Integration und Funktionalität.
- **[LangGraph](https://github.com/langchain-ai/langgraph)**: Ihr innovativer Ansatz zur Multi-Agenten-Orchestrierung war maßgeblich für die Ermöglichung der ausgeklügelten Workflows von DeerFlow.
- **[Novel](https://github.com/steven-tey/novel)**: Ihr Notion-artiger WYSIWYG-Editor unterstützt unsere Berichtbearbeitung und KI-unterstützte Umschreibung.
- **[RAGFlow](https://github.com/infiniflow/ragflow)**: Wir haben durch die Integration mit RAGFlow die Unterstützung für Forschung auf privaten Wissensdatenbanken der Benutzer erreicht.
Diese Projekte veranschaulichen die transformative Kraft der Open-Source-Zusammenarbeit, und wir sind stolz darauf, auf ihren Grundlagen aufzubauen.
### Hauptmitwirkende
Ein herzliches Dankeschön geht an die Hauptautoren von `DeerFlow`, deren Vision, Leidenschaft und Engagement dieses Projekt zum Leben erweckt haben:
- **[Daniel Walnut](https://github.com/hetaoBackend/)**
- **[Henry Li](https://github.com/magiccube/)**
Ihr unerschütterliches Engagement und Fachwissen waren die treibende Kraft hinter dem Erfolg von DeerFlow. Wir fühlen uns geehrt, Sie an der Spitze dieser Reise zu haben.
## Star-Verlauf
[![Star History Chart](https://api.star-history.com/svg?repos=bytedance/deer-flow&type=Date)](https://star-history.com/#bytedance/deer-flow&Date)

View File

@@ -1,607 +0,0 @@
# 🦌 DeerFlow
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![DeepWiki](https://img.shields.io/badge/DeepWiki-bytedance%2Fdeer--flow-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McCcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/bytedance/deer-flow)
<!-- DeepWiki badge generated by https://deepwiki.ryoppippi.com/ -->
[English](./README.md) | [简体中文](./README_zh.md) | [日本語](./README_ja.md) | [Deutsch](./README_de.md) | [Español](./README_es.md) | [Русский](./README_ru.md) | [Portuguese](./README_pt.md)
> Originado del código abierto, retribuido al código abierto.
**DeerFlow** (**D**eep **E**xploration and **E**fficient **R**esearch **Flow**) es un marco de Investigación Profunda impulsado por la comunidad que se basa en el increíble trabajo de la comunidad de código abierto. Nuestro objetivo es combinar modelos de lenguaje con herramientas especializadas para tareas como búsqueda web, rastreo y ejecución de código Python, mientras devolvemos a la comunidad que hizo esto posible.
Actualmente, DeerFlow ha ingresado oficialmente al Centro de Aplicaciones FaaS de Volcengine. Los usuarios pueden experimentarlo en línea a través del enlace de experiencia para sentir intuitivamente sus potentes funciones y operaciones convenientes. Al mismo tiempo, para satisfacer las necesidades de implementación de diferentes usuarios, DeerFlow admite la implementación con un clic basada en Volcengine. Haga clic en el enlace de implementación para completar rápidamente el proceso de implementación y comenzar un viaje de investigación eficiente.
DeerFlow ha integrado recientemente el conjunto de herramientas de búsqueda y rastreo inteligente desarrollado independientemente por BytePlus - [InfoQuest (admite experiencia gratuita en línea)](https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest)
<a href="https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest" target="_blank">
<img
src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/hubseh7bsbps/20251208-160108.png" alt="infoquest_bannar"
/>
</a>
Por favor, visita [nuestra página web oficial](https://deerflow.tech/) para más detalles.
## Demostración
### Video
<https://github.com/user-attachments/assets/f3786598-1f2a-4d07-919e-8b99dfa1de3e>
En esta demostración, mostramos cómo usar DeerFlow para:
- Integrar perfectamente con servicios MCP
- Realizar el proceso de Investigación Profunda y producir un informe completo con imágenes
- Crear audio de podcast basado en el informe generado
### Repeticiones
- [¿Qué altura tiene la Torre Eiffel comparada con el edificio más alto?](https://deerflow.tech/chat?replay=eiffel-tower-vs-tallest-building)
- [¿Cuáles son los repositorios más populares en GitHub?](https://deerflow.tech/chat?replay=github-top-trending-repo)
- [Escribir un artículo sobre los platos tradicionales de Nanjing](https://deerflow.tech/chat?replay=nanjing-traditional-dishes)
- [¿Cómo decorar un apartamento de alquiler?](https://deerflow.tech/chat?replay=rental-apartment-decoration)
- [Visita nuestra página web oficial para explorar más repeticiones.](https://deerflow.tech/#case-studies)
---
## 📑 Tabla de Contenidos
- [🚀 Inicio Rápido](#inicio-rápido)
- [🌟 Características](#características)
- [🏗️ Arquitectura](#arquitectura)
- [🛠️ Desarrollo](#desarrollo)
- [🐳 Docker](#docker)
- [🗣️ Integración de Texto a Voz](#integración-de-texto-a-voz)
- [📚 Ejemplos](#ejemplos)
- [❓ Preguntas Frecuentes](#preguntas-frecuentes)
- [📜 Licencia](#licencia)
- [💖 Agradecimientos](#agradecimientos)
- [⭐ Historial de Estrellas](#historial-de-estrellas)
## Inicio Rápido
DeerFlow está desarrollado en Python y viene con una interfaz web escrita en Node.js. Para garantizar un proceso de configuración sin problemas, recomendamos utilizar las siguientes herramientas:
### Herramientas Recomendadas
- **[`uv`](https://docs.astral.sh/uv/getting-started/installation/):**
Simplifica la gestión del entorno Python y las dependencias. `uv` crea automáticamente un entorno virtual en el directorio raíz e instala todos los paquetes necesarios por ti—sin necesidad de instalar entornos Python manualmente.
- **[`nvm`](https://github.com/nvm-sh/nvm):**
Gestiona múltiples versiones del entorno de ejecución Node.js sin esfuerzo.
- **[`pnpm`](https://pnpm.io/installation):**
Instala y gestiona dependencias del proyecto Node.js.
### Requisitos del Entorno
Asegúrate de que tu sistema cumple con los siguientes requisitos mínimos:
- **[Python](https://www.python.org/downloads/):** Versión `3.12+`
- **[Node.js](https://nodejs.org/en/download/):** Versión `22+`
### Instalación
```bash
# Clonar el repositorio
git clone https://github.com/bytedance/deer-flow.git
cd deer-flow
# Instalar dependencias, uv se encargará del intérprete de python, la creación del entorno virtual y la instalación de los paquetes necesarios
uv sync
# Configurar .env con tus claves API
# Tavily: https://app.tavily.com/home
# Brave_SEARCH: https://brave.com/search/api/
# volcengine TTS: Añade tus credenciales TTS si las tienes
cp .env.example .env
# Ver las secciones 'Motores de Búsqueda Compatibles' e 'Integración de Texto a Voz' a continuación para todas las opciones disponibles
# Configurar conf.yaml para tu modelo LLM y claves API
# Por favor, consulta 'docs/configuration_guide.md' para más detalles
cp conf.yaml.example conf.yaml
# Instalar marp para la generación de presentaciones
# https://github.com/marp-team/marp-cli?tab=readme-ov-file#use-package-manager
brew install marp-cli
```
Opcionalmente, instala las dependencias de la interfaz web vía [pnpm](https://pnpm.io/installation):
```bash
cd deer-flow/web
pnpm install
```
### Configuraciones
Por favor, consulta la [Guía de Configuración](docs/configuration_guide.md) para más detalles.
> [!NOTA]
> Antes de iniciar el proyecto, lee la guía cuidadosamente y actualiza las configuraciones para que coincidan con tus ajustes y requisitos específicos.
### Interfaz de Consola
La forma más rápida de ejecutar el proyecto es utilizar la interfaz de consola.
```bash
# Ejecutar el proyecto en un shell tipo bash
uv run main.py
```
### Interfaz Web
Este proyecto también incluye una Interfaz Web, que ofrece una experiencia interactiva más dinámica y atractiva.
> [!NOTA]
> Necesitas instalar primero las dependencias de la interfaz web.
```bash
# Ejecutar tanto el servidor backend como el frontend en modo desarrollo
# En macOS/Linux
./bootstrap.sh -d
# En Windows
bootstrap.bat -d
```
> [!NOTA]
> Por defecto, el servidor backend se enlaza a 127.0.0.1 (localhost) por razones de seguridad. Si necesitas permitir conexiones externas (por ejemplo, al desplegar en un servidor Linux), puedes modificar el host del servidor a 0.0.0.0 en el script de arranque (uv run server.py --host 0.0.0.0).
> Por favor, asegúrate de que tu entorno esté correctamente protegido antes de exponer el servicio a redes externas.
Abre tu navegador y visita [`http://localhost:3000`](http://localhost:3000) para explorar la interfaz web.
Explora más detalles en el directorio [`web`](./web/).
## Motores de Búsqueda Compatibles
DeerFlow soporta múltiples motores de búsqueda que pueden configurarse en tu archivo `.env` usando la variable `SEARCH_API`:
- **Tavily** (predeterminado): Una API de búsqueda especializada para aplicaciones de IA
- Requiere `TAVILY_API_KEY` en tu archivo `.env`
- Regístrate en: <https://app.tavily.com/home>
- **InfoQuest** (recomendado): Un conjunto de herramientas inteligentes de búsqueda y rastreo optimizadas para IA, desarrollado por BytePlus
- Requiere `INFOQUEST_API_KEY` en tu archivo `.env`
- Soporte para filtrado por rango de fecha y filtrado de sitios web
- Proporciona resultados de búsqueda y extracción de contenido de alta calidad
- Regístrate en: <https://console.byteplus.com/infoquest/infoquests>
- Visita https://docs.byteplus.com/es/docs/InfoQuest/What_is_Info_Quest para obtener más información
- **DuckDuckGo**: Motor de búsqueda centrado en la privacidad
- No requiere clave API
- **Brave Search**: Motor de búsqueda centrado en la privacidad con características avanzadas
- Requiere `BRAVE_SEARCH_API_KEY` en tu archivo `.env`
- Regístrate en: <https://brave.com/search/api/>
- **Arxiv**: Búsqueda de artículos científicos para investigación académica
- No requiere clave API
- Especializado en artículos científicos y académicos
- **Searx/SearxNG**: Motor de metabúsqueda autoalojado
- Requiere `SEARX_HOST` en tu archivo `.env`
- Compatible con Searx o SearxNG
Para configurar tu motor de búsqueda preferido, establece la variable `SEARCH_API` en tu archivo `.env`:
```bash
# Elige uno: tavily, infoquest, duckduckgo, brave_search, arxiv
SEARCH_API=tavily
```
### Herramientas de Rastreo
- **Jina** (predeterminado): Herramienta gratuita de rastreo de contenido web accesible
- No se requiere clave API para usar funciones básicas
- Al usar una clave API, se obtienen límites de tasa de acceso más altos
- Visite <https://jina.ai/reader> para obtener más información
- **InfoQuest** (recomendado): Conjunto de herramientas inteligentes de búsqueda y rastreo optimizadas para IA, desarrollado por BytePlus
- Requiere `INFOQUEST_API_KEY` en tu archivo `.env`
- Proporciona parámetros de rastreo configurables
- Admite configuración de tiempo de espera personalizada
- Ofrece capacidades más potentes de extracción de contenido
- Visita <https://docs.byteplus.com/es/docs/InfoQuest/What_is_Info_Quest> para obtener más información
Para configurar su herramienta de rastreo preferida, establezca lo siguiente en su archivo `conf.yaml`:
```yaml
CRAWLER_ENGINE:
# Tipo de motor: "jina" (predeterminado) o "infoquest"
engine: infoquest
```
## Características
### Capacidades Principales
- 🤖 **Integración de LLM**
- Soporta la integración de la mayoría de los modelos a través de [litellm](https://docs.litellm.ai/docs/providers).
- Soporte para modelos de código abierto como Qwen
- Interfaz API compatible con OpenAI
- Sistema LLM de múltiples niveles para diferentes complejidades de tareas
### Herramientas e Integraciones MCP
- 🔍 **Búsqueda y Recuperación**
- Búsqueda web a través de Tavily, InfoQuest, Brave Search y más
- Rastreo con Jina e InfoQuest
- Extracción avanzada de contenido
- 🔗 **Integración Perfecta con MCP**
- Amplía capacidades para acceso a dominio privado, gráfico de conocimiento, navegación web y más
- Facilita la integración de diversas herramientas y metodologías de investigación
### Colaboración Humana
- 🧠 **Humano en el Bucle**
- Soporta modificación interactiva de planes de investigación usando lenguaje natural
- Soporta aceptación automática de planes de investigación
- 📝 **Post-Edición de Informes**
- Soporta edición de bloques tipo Notion
- Permite refinamientos por IA, incluyendo pulido asistido por IA, acortamiento y expansión de oraciones
- Impulsado por [tiptap](https://tiptap.dev/)
### Creación de Contenido
- 🎙️ **Generación de Podcasts y Presentaciones**
- Generación de guiones de podcast y síntesis de audio impulsadas por IA
- Creación automatizada de presentaciones PowerPoint simples
- Plantillas personalizables para contenido a medida
## Arquitectura
DeerFlow implementa una arquitectura modular de sistema multi-agente diseñada para investigación automatizada y análisis de código. El sistema está construido sobre LangGraph, permitiendo un flujo de trabajo flexible basado en estados donde los componentes se comunican a través de un sistema de paso de mensajes bien definido.
![Diagrama de Arquitectura](./assets/architecture.png)
> Vélo en vivo en [deerflow.tech](https://deerflow.tech/#multi-agent-architecture)
El sistema emplea un flujo de trabajo racionalizado con los siguientes componentes:
1. **Coordinador**: El punto de entrada que gestiona el ciclo de vida del flujo de trabajo
- Inicia el proceso de investigación basado en la entrada del usuario
- Delega tareas al planificador cuando corresponde
- Actúa como la interfaz principal entre el usuario y el sistema
2. **Planificador**: Componente estratégico para descomposición y planificación de tareas
- Analiza objetivos de investigación y crea planes de ejecución estructurados
- Determina si hay suficiente contexto disponible o si se necesita más investigación
- Gestiona el flujo de investigación y decide cuándo generar el informe final
3. **Equipo de Investigación**: Una colección de agentes especializados que ejecutan el plan:
- **Investigador**: Realiza búsquedas web y recopilación de información utilizando herramientas como motores de búsqueda web, rastreo e incluso servicios MCP.
- **Programador**: Maneja análisis de código, ejecución y tareas técnicas utilizando la herramienta Python REPL.
Cada agente tiene acceso a herramientas específicas optimizadas para su rol y opera dentro del marco LangGraph
4. **Reportero**: Procesador de etapa final para los resultados de la investigación
- Agrega hallazgos del equipo de investigación
- Procesa y estructura la información recopilada
- Genera informes de investigación completos
## Integración de Texto a Voz
DeerFlow ahora incluye una función de Texto a Voz (TTS) que te permite convertir informes de investigación a voz. Esta función utiliza la API TTS de volcengine para generar audio de alta calidad a partir de texto. Características como velocidad, volumen y tono también son personalizables.
### Usando la API TTS
Puedes acceder a la funcionalidad TTS a través del punto final `/api/tts`:
```bash
# Ejemplo de llamada API usando curl
curl --location 'http://localhost:8000/api/tts' \
--header 'Content-Type: application/json' \
--data '{
"text": "Esto es una prueba de la funcionalidad de texto a voz.",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
}' \
--output speech.mp3
```
## Desarrollo
### Pruebas
Ejecuta el conjunto de pruebas:
```bash
# Ejecutar todas las pruebas
make test
# Ejecutar archivo de prueba específico
pytest tests/integration/test_workflow.py
# Ejecutar con cobertura
make coverage
```
### Calidad del Código
```bash
# Ejecutar linting
make lint
# Formatear código
make format
```
### Depuración con LangGraph Studio
DeerFlow utiliza LangGraph para su arquitectura de flujo de trabajo. Puedes usar LangGraph Studio para depurar y visualizar el flujo de trabajo en tiempo real.
#### Ejecutando LangGraph Studio Localmente
DeerFlow incluye un archivo de configuración `langgraph.json` que define la estructura del grafo y las dependencias para LangGraph Studio. Este archivo apunta a los grafos de flujo de trabajo definidos en el proyecto y carga automáticamente variables de entorno desde el archivo `.env`.
##### Mac
```bash
# Instala el gestor de paquetes uv si no lo tienes
curl -LsSf https://astral.sh/uv/install.sh | sh
# Instala dependencias e inicia el servidor LangGraph
uvx --refresh --from "langgraph-cli[inmem]" --with-editable . --python 3.12 langgraph dev --allow-blocking
```
##### Windows / Linux
```bash
# Instalar dependencias
pip install -e .
pip install -U "langgraph-cli[inmem]"
# Iniciar el servidor LangGraph
langgraph dev
```
Después de iniciar el servidor LangGraph, verás varias URLs en la terminal:
- API: <http://127.0.0.1:2024>
- UI de Studio: <https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024>
- Docs de API: <http://127.0.0.1:2024/docs>
Abre el enlace de UI de Studio en tu navegador para acceder a la interfaz de depuración.
#### Usando LangGraph Studio
En la UI de Studio, puedes:
1. Visualizar el grafo de flujo de trabajo y ver cómo se conectan los componentes
2. Rastrear la ejecución en tiempo real para ver cómo fluyen los datos a través del sistema
3. Inspeccionar el estado en cada paso del flujo de trabajo
4. Depurar problemas examinando entradas y salidas de cada componente
5. Proporcionar retroalimentación durante la fase de planificación para refinar planes de investigación
Cuando envías un tema de investigación en la UI de Studio, podrás ver toda la ejecución del flujo de trabajo, incluyendo:
- La fase de planificación donde se crea el plan de investigación
- El bucle de retroalimentación donde puedes modificar el plan
- Las fases de investigación y escritura para cada sección
- La generación del informe final
### Habilitando el Rastreo de LangSmith
DeerFlow soporta el rastreo de LangSmith para ayudarte a depurar y monitorear tus flujos de trabajo. Para habilitar el rastreo de LangSmith:
1. Asegúrate de que tu archivo `.env` tenga las siguientes configuraciones (ver `.env.example`):
```bash
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY="xxx"
LANGSMITH_PROJECT="xxx"
```
2. Inicia el rastreo y visualiza el grafo localmente con LangSmith ejecutando:
```bash
langgraph dev
```
Esto habilitará la visualización de rastros en LangGraph Studio y enviará tus rastros a LangSmith para monitoreo y análisis.
## Docker
También puedes ejecutar este proyecto con Docker.
Primero, necesitas leer la [configuración](docs/configuration_guide.md) a continuación. Asegúrate de que los archivos `.env` y `.conf.yaml` estén listos.
Segundo, para construir una imagen Docker de tu propio servidor web:
```bash
docker build -t deer-flow-api .
```
Finalmente, inicia un contenedor Docker que ejecute el servidor web:
```bash
# Reemplaza deer-flow-api-app con tu nombre de contenedor preferido
# Inicia el servidor y enlázalo a localhost:8000
docker run -d -t -p 127.0.0.1:8000:8000 --env-file .env --name deer-flow-api-app deer-flow-api
# detener el servidor
docker stop deer-flow-api-app
```
### Docker Compose (incluye tanto backend como frontend)
DeerFlow proporciona una configuración docker-compose para ejecutar fácilmente tanto el backend como el frontend juntos:
```bash
# construir imagen docker
docker compose build
# iniciar el servidor
docker compose up
```
> [!WARNING]
> Si desea implementar DeerFlow en entornos de producción, agregue autenticación al sitio web y evalúe su verificación de seguridad del MCPServer y Python Repl.
## Ejemplos
Los siguientes ejemplos demuestran las capacidades de DeerFlow:
### Informes de Investigación
1. **Informe sobre OpenAI Sora** - Análisis de la herramienta IA Sora de OpenAI
- Discute características, acceso, ingeniería de prompts, limitaciones y consideraciones éticas
- [Ver informe completo](examples/openai_sora_report.md)
2. **Informe sobre el Protocolo Agent to Agent de Google** - Visión general del protocolo Agent to Agent (A2A) de Google
- Discute su papel en la comunicación de agentes IA y su relación con el Model Context Protocol (MCP) de Anthropic
- [Ver informe completo](examples/what_is_agent_to_agent_protocol.md)
3. **¿Qué es MCP?** - Un análisis completo del término "MCP" en múltiples contextos
- Explora Model Context Protocol en IA, Fosfato Monocálcico en química y Placa de Microcanales en electrónica
- [Ver informe completo](examples/what_is_mcp.md)
4. **Fluctuaciones del Precio de Bitcoin** - Análisis de los movimientos recientes del precio de Bitcoin
- Examina tendencias del mercado, influencias regulatorias e indicadores técnicos
- Proporciona recomendaciones basadas en datos históricos
- [Ver informe completo](examples/bitcoin_price_fluctuation.md)
5. **¿Qué es LLM?** - Una exploración en profundidad de los Modelos de Lenguaje Grandes
- Discute arquitectura, entrenamiento, aplicaciones y consideraciones éticas
- [Ver informe completo](examples/what_is_llm.md)
6. **¿Cómo usar Claude para Investigación Profunda?** - Mejores prácticas y flujos de trabajo para usar Claude en investigación profunda
- Cubre ingeniería de prompts, análisis de datos e integración con otras herramientas
- [Ver informe completo](examples/how_to_use_claude_deep_research.md)
7. **Adopción de IA en Salud: Factores de Influencia** - Análisis de factores que impulsan la adopción de IA en salud
- Discute tecnologías IA, calidad de datos, consideraciones éticas, evaluaciones económicas, preparación organizativa e infraestructura digital
- [Ver informe completo](examples/AI_adoption_in_healthcare.md)
8. **Impacto de la Computación Cuántica en la Criptografía** - Análisis del impacto de la computación cuántica en la criptografía
- Discute vulnerabilidades de la criptografía clásica, criptografía post-cuántica y soluciones criptográficas resistentes a la cuántica
- [Ver informe completo](examples/Quantum_Computing_Impact_on_Cryptography.md)
9. **Aspectos Destacados del Rendimiento de Cristiano Ronaldo** - Análisis de los aspectos destacados del rendimiento de Cristiano Ronaldo
- Discute sus logros profesionales, goles internacionales y rendimiento en varios partidos
- [Ver informe completo](examples/Cristiano_Ronaldo's_Performance_Highlights.md)
Para ejecutar estos ejemplos o crear tus propios informes de investigación, puedes usar los siguientes comandos:
```bash
# Ejecutar con una consulta específica
uv run main.py "¿Qué factores están influyendo en la adopción de IA en salud?"
# Ejecutar con parámetros de planificación personalizados
uv run main.py --max_plan_iterations 3 "¿Cómo impacta la computación cuántica en la criptografía?"
# Ejecutar en modo interactivo con preguntas integradas
uv run main.py --interactive
# O ejecutar con prompt interactivo básico
uv run main.py
# Ver todas las opciones disponibles
uv run main.py --help
```
### Modo Interactivo
La aplicación ahora soporta un modo interactivo con preguntas integradas tanto en inglés como en chino:
1. Lanza el modo interactivo:
```bash
uv run main.py --interactive
```
2. Selecciona tu idioma preferido (English o 中文)
3. Elige de una lista de preguntas integradas o selecciona la opción para hacer tu propia pregunta
4. El sistema procesará tu pregunta y generará un informe de investigación completo
### Humano en el Bucle
DeerFlow incluye un mecanismo de humano en el bucle que te permite revisar, editar y aprobar planes de investigación antes de que sean ejecutados:
1. **Revisión del Plan**: Cuando el humano en el bucle está habilitado, el sistema presentará el plan de investigación generado para tu revisión antes de la ejecución
2. **Proporcionando Retroalimentación**: Puedes:
- Aceptar el plan respondiendo con `[ACCEPTED]`
- Editar el plan proporcionando retroalimentación (p.ej., `[EDIT PLAN] Añadir más pasos sobre implementación técnica`)
- El sistema incorporará tu retroalimentación y generará un plan revisado
3. **Auto-aceptación**: Puedes habilitar la auto-aceptación para omitir el proceso de revisión:
- Vía API: Establece `auto_accepted_plan: true` en tu solicitud
4. **Integración API**: Cuando uses la API, puedes proporcionar retroalimentación a través del parámetro `feedback`:
```json
{
"messages": [{ "role": "user", "content": "¿Qué es la computación cuántica?" }],
"thread_id": "my_thread_id",
"auto_accepted_plan": false,
"feedback": "[EDIT PLAN] Incluir más sobre algoritmos cuánticos"
}
```
### Argumentos de Línea de Comandos
La aplicación soporta varios argumentos de línea de comandos para personalizar su comportamiento:
- **query**: La consulta de investigación a procesar (puede ser múltiples palabras)
- **--interactive**: Ejecutar en modo interactivo con preguntas integradas
- **--max_plan_iterations**: Número máximo de ciclos de planificación (predeterminado: 1)
- **--max_step_num**: Número máximo de pasos en un plan de investigación (predeterminado: 3)
- **--debug**: Habilitar registro detallado de depuración
## Preguntas Frecuentes
Por favor, consulta [FAQ.md](docs/FAQ.md) para más detalles.
## Licencia
Este proyecto es de código abierto y está disponible bajo la [Licencia MIT](./LICENSE).
## Agradecimientos
DeerFlow está construido sobre el increíble trabajo de la comunidad de código abierto. Estamos profundamente agradecidos a todos los proyectos y contribuyentes cuyos esfuerzos han hecho posible DeerFlow. Verdaderamente, nos apoyamos en hombros de gigantes.
Nos gustaría extender nuestro sincero agradecimiento a los siguientes proyectos por sus invaluables contribuciones:
- **[LangChain](https://github.com/langchain-ai/langchain)**: Su excepcional marco impulsa nuestras interacciones y cadenas LLM, permitiendo integración y funcionalidad sin problemas.
- **[LangGraph](https://github.com/langchain-ai/langgraph)**: Su enfoque innovador para la orquestación multi-agente ha sido instrumental en permitir los sofisticados flujos de trabajo de DeerFlow.
Estos proyectos ejemplifican el poder transformador de la colaboración de código abierto, y estamos orgullosos de construir sobre sus cimientos.
### Contribuyentes Clave
Un sentido agradecimiento va para los autores principales de `DeerFlow`, cuya visión, pasión y dedicación han dado vida a este proyecto:
- **[Daniel Walnut](https://github.com/hetaoBackend/)**
- **[Henry Li](https://github.com/magiccube/)**
Su compromiso inquebrantable y experiencia han sido la fuerza impulsora detrás del éxito de DeerFlow. Nos sentimos honrados de tenerlos al timón de este viaje.
## Historial de Estrellas
[![Gráfico de Historial de Estrellas](https://api.star-history.com/svg?repos=bytedance/deer-flow&type=Date)](https://star-history.com/#bytedance/deer-flow&Date)

View File

@@ -1,624 +0,0 @@
# 🦌 DeerFlow
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[English](./README.md) | [简体中文](./README_zh.md) | [日本語](./README_ja.md) | [Deutsch](./README_de.md) | [Español](./README_es.md) | [Русский](./README_ru.md) | [Portuguese](./README_pt.md)
> オープンソースから生まれ、オープンソースに還元する。
**DeerFlow****D**eep **E**xploration and **E**fficient **R**esearch **Flow**は、オープンソースコミュニティの素晴らしい成果の上に構築されたコミュニティ主導の深層研究フレームワークです。私たちの目標は、言語モデルとウェブ検索、クローリング、Python コード実行などの専門ツールを組み合わせながら、これを可能にしたコミュニティに貢献することです。
現在、DeerFlow は火山引擎の FaaS アプリケーションセンターに正式に入居しています。ユーザーは体験リンクを通じてオンラインで体験し、その強力な機能と便利な操作を直感的に感じることができます。同時に、さまざまなユーザーの展開ニーズを満たすため、DeerFlow は火山引擎に基づくワンクリック展開をサポートしています。展開リンクをクリックして展開プロセスを迅速に完了し、効率的な研究の旅を始めましょう。
DeerFlow は新たにBytePlusが自主開発したインテリジェント検索・クローリングツールセットを統合しました--[InfoQuest (オンライン無料体験をサポート)](https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest)
<a href="https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest" target="_blank">
<img
src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/hubseh7bsbps/20251208-160108.png" alt="infoquest_bannar"
/>
</a>
詳細については[DeerFlow の公式ウェブサイト](https://deerflow.tech/)をご覧ください。
## デモ
### ビデオ
<https://github.com/user-attachments/assets/f3786598-1f2a-4d07-919e-8b99dfa1de3e>
このデモでは、DeerFlowの使用方法を紹介しています
- MCPサービスとのシームレスな統合
- 深層研究プロセスの実施と画像を含む包括的なレポートの作成
- 生成されたレポートに基づくポッドキャストオーディオの作成
### リプレイ例
- [エッフェル塔は世界一高いビルと比べてどれくらい高い?](https://deerflow.tech/chat?replay=eiffel-tower-vs-tallest-building)
- [GitHub で最も人気のあるリポジトリは?](https://deerflow.tech/chat?replay=github-top-trending-repo)
- [南京の伝統料理に関する記事を書く](https://deerflow.tech/chat?replay=nanjing-traditional-dishes)
- [賃貸アパートの装飾方法は?](https://deerflow.tech/chat?replay=rental-apartment-decoration)
- [公式ウェブサイトでより多くのリプレイ例をご覧ください。](https://deerflow.tech/#case-studies)
---
## 📑 目次
- [🚀 クイックスタート](#クイックスタート)
- [🌟 特徴](#特徴)
- [🏗️ アーキテクチャ](#アーキテクチャ)
- [🛠️ 開発](#開発)
- [🗣️ テキスト読み上げ統合](#テキスト読み上げ統合)
- [📚 例](#例)
- [❓ よくある質問](#よくある質問)
- [📜 ライセンス](#ライセンス)
- [💖 謝辞](#謝辞)
- [⭐ スター履歴](#スター履歴)
## クイックスタート
DeerFlow は Python で開発され、Node.js で書かれた Web UI が付属しています。スムーズなセットアッププロセスを確保するために、以下のツールの使用をお勧めします:
### 推奨ツール
- **[`uv`](https://docs.astral.sh/uv/getting-started/installation/):**
Python 環境と依存関係の管理を簡素化します。`uv`はルートディレクトリに自動的に仮想環境を作成し、必要なパッケージをすべてインストールします—Python 環境を手動でインストールする必要はありません。
- **[`nvm`](https://github.com/nvm-sh/nvm):**
複数の Node.js ランタイムバージョンを簡単に管理します。
- **[`pnpm`](https://pnpm.io/installation):**
Node.js プロジェクトの依存関係をインストールおよび管理します。
### 環境要件
システムが以下の最小要件を満たしていることを確認してください:
- **[Python](https://www.python.org/downloads/):** バージョン `3.12+`
- **[Node.js](https://nodejs.org/en/download/):** バージョン `22+`
### インストール
```bash
# リポジトリをクローン
git clone https://github.com/bytedance/deer-flow.git
cd deer-flow
# 依存関係をインストール、uvがPythonインタープリタと仮想環境の作成、必要なパッケージのインストールを担当
uv sync
# APIキーで.envを設定
# Tavily: https://app.tavily.com/home
# Brave_SEARCH: https://brave.com/search/api/
# 火山引擎TTS: TTSの資格情報がある場合は追加
cp .env.example .env
# 下記の「サポートされている検索エンジン」と「テキスト読み上げ統合」セクションですべての利用可能なオプションを確認
# LLMモデルとAPIキーのconf.yamlを設定
# 詳細は「docs/configuration_guide.md」を参照
cp conf.yaml.example conf.yaml
# PPT生成用にmarpをインストール
# https://github.com/marp-team/marp-cli?tab=readme-ov-file#use-package-manager
brew install marp-cli
```
オプションで、[pnpm](https://pnpm.io/installation)を使用して Web UI 依存関係をインストール:
```bash
cd deer-flow/web
pnpm install
```
### 設定
詳細については[設定ガイド](docs/configuration_guide.md)を参照してください。
> [!注意]
> プロジェクトを開始する前に、ガイドを注意深く読み、特定の設定と要件に合わせて構成を更新してください。
### コンソール UI
プロジェクトを実行する最も迅速な方法は、コンソール UI を使用することです。
```bash
# bashライクなシェルでプロジェクトを実行
uv run main.py
```
### Web UI
このプロジェクトには Web UI も含まれており、より動的で魅力的なインタラクティブ体験を提供します。
> [!注意]
> 先に Web UI の依存関係をインストールする必要があります。
```bash
# 開発モードでバックエンドとフロントエンドサーバーの両方を実行
# macOS/Linuxの場合
./bootstrap.sh -d
# Windowsの場合
bootstrap.bat -d
```
> [!NOTE]
> デフォルトでは、セキュリティ上の理由からバックエンドサーバーは 127.0.0.1 (localhost) にバインドされます。外部接続を許可する必要がある場合 (例: Linux サーバーにデプロイする場合) は、ブートストラップスクリプトでサーバーホストを 0.0.0.0 に変更できます (uv run server.py --host 0.0.0.0)。
> サービスを外部ネットワークに公開する前に、環境が適切に保護されていることを確認してください。
ブラウザを開き、[`http://localhost:3000`](http://localhost:3000)にアクセスして Web UI を探索してください。
[`web`](./web/)ディレクトリで詳細を確認できます。
## サポートされている検索エンジン
DeerFlow は複数の検索エンジンをサポートしており、`.env`ファイルの`SEARCH_API`変数で設定できます:
- **Tavily**デフォルトAI アプリケーション向けの専門検索 API
- `.env`ファイルに`TAVILY_API_KEY`が必要
- 登録先:<https://app.tavily.com/home>
- **InfoQuest**推奨BytePlusが開発したAI最適化のインテリジェント検索とクローリングツールセット
- `.env`ファイルに`INFOQUEST_API_KEY`が必要
- 時間範囲フィルタリングとサイトフィルタリングをサポート
- 高品質な検索結果とコンテンツ抽出を提供
- 登録先:<https://console.byteplus.com/infoquest/infoquests>
- ドキュメント:<https://docs.byteplus.com/ja/docs/InfoQuest/What_is_Info_Quest>
- **DuckDuckGo**:プライバシー重視の検索エンジン
- APIキー不要
- **Brave Search**:高度な機能を備えたプライバシー重視の検索エンジン
- `.env`ファイルに`BRAVE_SEARCH_API_KEY`が必要
- 登録先:<https://brave.com/search/api/>
- **Arxiv**:学術研究用の科学論文検索
- APIキー不要
- 科学・学術論文専用
- **Searx/SearxNG**セルフホスト型メタ検索エンジン
- `.env`ファイルに`SEARX_HOST`が必要
- Searx または SearxNG に接続可能
お好みの検索エンジンを設定するには、`.env`ファイルで`SEARCH_API`変数を設定します:
```bash
# 選択肢: tavily, infoquest, duckduckgo, brave_search, arxiv
SEARCH_API=tavily
```
### クローリングツール
- **Jina**(デフォルト):無料でアクセス可能なウェブコンテンツクローリングツール
- 基本機能を使用するにはAPIキーは不要
- APIキーを使用するとより高いアクセスレート制限が適用されます
- 詳細については <https://jina.ai/reader> を参照してください
- **InfoQuest**推奨BytePlusが開発したAI最適化のインテリジェント検索とクローリングツールセット
- `.env`ファイルに`INFOQUEST_API_KEY`が必要
- 設定可能なクローリングパラメータを提供
- カスタムタイムアウト設定をサポート
- より強力なコンテンツ抽出機能を提供
- 詳細については <https://docs.byteplus.com/ja/docs/InfoQuest/What_is_Info_Quest> を参照してください
お好みのクローリングツールを設定するには、`conf.yaml`ファイルで以下を設定します:
```yaml
CRAWLER_ENGINE:
# エンジンタイプ:"jina"(デフォルト)または "infoquest"
engine: infoquest
```
## 特徴
### コア機能
- 🤖 **LLM統合**
- [litellm](https://docs.litellm.ai/docs/providers)を通じてほとんどのモデルの統合をサポート
- Qwenなどのオープンソースモデルをサポート
- OpenAI互換のAPIインターフェース
- 異なるタスクの複雑さに対応するマルチティアLLMシステム
### ツールと MCP 統合
- 🔍 **検索と取得**
- Tavily、InfoQuest、Brave Searchなどを通じたWeb検索
- JinaとInfoQuestを使用したクローリング
- 高度なコンテンツ抽出
- 🔗 **MCPシームレス統合**
- プライベートドメインアクセス、ナレッジグラフ、Webブラウジングなどの機能を拡張
- 多様な研究ツールと方法論の統合を促進
### 人間との協力
- 🧠 **人間参加型ループ**
- 自然言語を使用した研究計画の対話的修正をサポート
- 研究計画の自動承認をサポート
- 📝 **レポート後編集**
- Notionライクなブロック編集をサポート
- AI支援による洗練、文の短縮、拡張などのAI改良を可能に
- [tiptap](https://tiptap.dev/)を活用
### コンテンツ作成
- 🎙️ **ポッドキャストとプレゼンテーション生成**
- AI駆動のポッドキャストスクリプト生成と音声合成
- シンプルなPowerPointプレゼンテーションの自動作成
- カスタマイズ可能なテンプレートで個別のコンテンツに対応
## アーキテクチャ
DeerFlow は、自動研究とコード分析のためのモジュラーなマルチエージェントシステムアーキテクチャを実装しています。システムは LangGraph 上に構築され、コンポーネントが明確に定義されたメッセージパッシングシステムを通じて通信する柔軟な状態ベースのワークフローを実現しています。
![アーキテクチャ図](./assets/architecture.png)
> [deerflow.tech](https://deerflow.tech/#multi-agent-architecture)でライブで確認できます
システムは以下のコンポーネントを含む合理化されたワークフローを採用しています:
1. **コーディネーター**:ワークフローのライフサイクルを管理するエントリーポイント
- ユーザー入力に基づいて研究プロセスを開始
- 適切なタイミングでプランナーにタスクを委託
- ユーザーとシステム間の主要なインターフェースとして機能
2. **プランナー**:タスク分解と計画のための戦略的コンポーネント
- 研究目標を分析し、構造化された実行計画を作成
- 十分なコンテキストが利用可能か、さらなる研究が必要かを判断
- 研究フローを管理し、最終レポート生成のタイミングを決定
3. **研究チーム**:計画を実行する専門エージェントの集合:
- **研究者**Web 検索エンジン、クローリング、さらには MCP サービスなどのツールを使用して Web 検索と情報収集を行う。
- **コーダー**Python REPL ツールを使用してコード分析、実行、技術的タスクを処理する。
各エージェントは自分の役割に最適化された特定のツールにアクセスでき、LangGraph フレームワーク内で動作する
4. **レポーター**:研究出力の最終段階プロセッサ
- 研究チームの調査結果を集約
- 収集した情報を処理および構造化
- 包括的な研究レポートを生成
## テキスト読み上げ統合
DeerFlowには現在、研究レポートを音声に変換できるテキスト読み上げTTS機能が含まれています。この機能は火山引擎TTS APIを使用して高品質なテキストオーディオを生成します。速度、音量、ピッチなどの特性もカスタマイズ可能です。
### TTS APIの使用
`/api/tts`エンドポイントからTTS機能にアクセスできます
```bash
# curlを使用したAPI呼び出し例
curl --location 'http://localhost:8000/api/tts' \
--header 'Content-Type: application/json' \
--data '{
"text": "これはテキスト読み上げ機能のテストです。",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
}' \
--output speech.mp3
```
## 開発
### テスト
テストスイートの実行:
```bash
# すべてのテストを実行
make test
# 特定のテストファイルを実行
pytest tests/integration/test_workflow.py
# カバレッジテストを実行
make coverage
```
### コード品質
```bash
# コードチェックを実行
make lint
# コードをフォーマット
make format
```
### LangGraph Studio によるデバッグ
DeerFlow はワークフローアーキテクチャとして LangGraph を使用しています。LangGraph Studio を使用してワークフローをリアルタイムでデバッグおよび可視化できます。
#### ローカルで LangGraph Studio を実行
DeerFlow には`langgraph.json`設定ファイルが含まれており、これが LangGraph Studio のグラフ構造と依存関係を定義しています。このファイルはプロジェクトで定義されたワークフローグラフを指し、`.env`ファイルから環境変数を自動的に読み込みます。
##### Mac
```bash
# uvパッケージマネージャがない場合はインストール
curl -LsSf https://astral.sh/uv/install.sh | sh
# 依存関係をインストールしLangGraphサーバーを開始
uvx --refresh --from "langgraph-cli[inmem]" --with-editable . --python 3.12 langgraph dev --allow-blocking
```
##### Windows / Linux
```bash
# 依存関係をインストール
pip install -e .
pip install -U "langgraph-cli[inmem]"
# LangGraphサーバーを開始
langgraph dev
```
LangGraphサーバーを開始すると、端末にいくつかのURLが表示されます
- API: <http://127.0.0.1:2024>
- Studio UI: <https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024>
- APIドキュメント: <http://127.0.0.1:2024/docs>
- API: <http://127.0.0.1:2024>
- Studio UI: <https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024>
- APIドキュメント: <http://127.0.0.1:2024/docs>
ブラウザで Studio UI リンクを開いてデバッグインターフェースにアクセスします。
#### LangGraph Studio の使用
Studio UI では、次のことができます:
1. ワークフローグラフを可視化し、コンポーネントの接続方法を確認
2. 実行をリアルタイムで追跡し、データがシステム内をどのように流れるかを理解
3. ワークフローの各ステップの状態を検査
4. 各コンポーネントの入力と出力を検査して問題をデバッグ
5. 計画段階でフィードバックを提供して研究計画を洗練
Studio UIで研究トピックを送信すると、次を含む全ワークフロー実行プロセスを見ることができます
- 研究計画を作成する計画段階
- 計画を修正できるフィードバックループ
- 各セクションの研究と執筆段階
- 最終レポート生成
### LangSmith トレースの有効化
DeerFlow は LangSmith トレース機能をサポートしており、ワークフローのデバッグとモニタリングに役立ちます。LangSmith トレースを有効にするには:
1. `.env` ファイルに次の設定があることを確認してください(`.env.example` を参照):
```bash
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY="xxx"
LANGSMITH_PROJECT="xxx"
```
2. 次のコマンドを実行して LangSmith トレースを開始します:
```bash
langgraph dev
```
これにより、LangGraph Studio でトレース可視化が有効になり、トレースがモニタリングと分析のために LangSmith に送信されます。
## Docker
このプロジェクトは Docker でも実行できます。
まず、以下の[設定](#設定)セクションを読んでください。`.env`と`.conf.yaml`ファイルが準備できていることを確認してください。
次に、独自の Web サーバーの Docker イメージをビルドします:
```bash
docker build -t deer-flow-api .
```
最後に、Web サーバーを実行する Docker コンテナを起動します:
```bash
# deer-flow-api-appを希望のコンテナ名に置き換えてください
# サーバーを起動してlocalhost:8000にバインド
docker run -d -t -p 127.0.0.1:8000:8000 --env-file .env --name deer-flow-api-app deer-flow-api
# サーバーを停止
docker stop deer-flow-api-app
```
### Docker Compose
このプロジェクトは docker compose でも設定できます:
```bash
# dockerイメージをビルド
docker compose build
# サーバーを起動
docker compose up
```
> [!WARNING]
> DeerFlow を本番環境にデプロイする場合は、ウェブサイトに認証を追加し、MCPServer と Python Repl のセキュリティチェックを評価してください。
## テキスト読み上げ統合
DeerFlow には現在、研究レポートを音声に変換できるテキスト読み上げTTS機能が含まれています。この機能は火山引擎 TTS API を使用して高品質なテキストオーディオを生成します。速度、音量、ピッチなどの特性もカスタマイズ可能です。
### TTS API の使用
`/api/tts`エンドポイントから TTS 機能にアクセスできます:
```bash
# curlを使用したAPI呼び出し例
curl --location 'http://localhost:8000/api/tts' \
--header 'Content-Type: application/json' \
--data '{
"text": "これはテキスト読み上げ機能のテストです。",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
}' \
--output speech.mp3
```
## 例
以下の例は DeerFlow の機能を示しています:
### 研究レポート
1. **OpenAI Sora レポート** - OpenAI の Sora AI ツールの分析
- 機能、アクセス方法、プロンプトエンジニアリング、制限、倫理的考慮について議論
- [完全なレポートを見る](examples/openai_sora_report.md)
2. **Google の Agent to Agent プロトコルレポート** - Google の Agent to AgentA2Aプロトコルの概要
- AI エージェント通信における役割と、Anthropic の Model Context ProtocolMCPとの関係について議論
- [完全なレポートを見る](examples/what_is_agent_to_agent_protocol.md)
3. **MCP とは何か?** - 複数のコンテキストにおける「MCP」という用語の包括的分析
- AI における Model Context Protocol、化学における Monocalcium Phosphate、電子工学における Micro-channel Plate を探る
- [完全なレポートを見る](examples/what_is_mcp.md)
4. **ビットコイン価格変動** - 最近のビットコイン価格動向の分析
- 市場動向、規制の影響、テクニカル指標の調査
- 歴史的データに基づく提言
- [完全なレポートを見る](examples/bitcoin_price_fluctuation.md)
5. **LLM とは何か?** - 大規模言語モデルの詳細な探求
- アーキテクチャ、トレーニング、応用、倫理的考慮について議論
- [完全なレポートを見る](examples/what_is_llm.md)
6. **Claude を使った深層研究の方法は?** - 深層研究での Claude の使用に関するベストプラクティスとワークフロー
- プロンプトエンジニアリング、データ分析、他のツールとの統合
- [完全なレポートを見る](examples/how_to_use_claude_deep_research.md)
7. **医療における AI 採用:影響要因** - 医療における AI 採用に影響する要因の分析
- AI テクノロジー、データ品質、倫理的考慮、経済的評価、組織の準備状況、デジタルインフラについて議論
- [完全なレポートを見る](examples/AI_adoption_in_healthcare.md)
8. **量子コンピューティングの暗号学への影響** - 量子コンピューティングの暗号学への影響の分析
- 古典的暗号の脆弱性、ポスト量子暗号学、耐量子暗号ソリューションについて議論
- [完全なレポートを見る](examples/Quantum_Computing_Impact_on_Cryptography.md)
9. **クリスティアーノ・ロナウドのパフォーマンスハイライト** - クリスティアーノ・ロナウドのパフォーマンスハイライトの分析
- 彼のキャリア達成、国際ゴール、さまざまな大会でのパフォーマンスについて議論
- [完全なレポートを見る](examples/Cristiano_Ronaldo's_Performance_Highlights.md)
これらの例を実行したり、独自の研究レポートを作成したりするには、次のコマンドを使用できます:
```bash
# 特定のクエリで実行
uv run main.py "医療におけるAI採用に影響する要因は何か"
# カスタム計画パラメータで実行
uv run main.py --max_plan_iterations 3 "量子コンピューティングは暗号学にどのように影響するか?"
# 組み込み質問を使用したインタラクティブモードで実行
uv run main.py --interactive
# または基本的なインタラクティブプロンプトで実行
uv run main.py
# 利用可能なすべてのオプションを表示
uv run main.py --help
```
### インタラクティブモード
アプリケーションは現在、英語と中国語の組み込み質問を使用したインタラクティブモードをサポートしています:
1. インタラクティブモードを開始:
```bash
uv run main.py --interactive
```
2. 好みの言語English または Chineseを選択
3. 組み込み質問リストから選択するか、独自の質問を提示するオプションを選択
4. システムが質問を処理し、包括的な研究レポートを生成
### 人間参加型ループ
DeerFlow には人間参加型ループメカニズムが含まれており、研究計画を実行する前にレビュー、編集、承認することができます:
1. **計画レビュー**:人間参加型ループが有効な場合、システムは実行前に生成された研究計画を表示
2. **フィードバック提供**:次のことができます:
- `[ACCEPTED]`と返信して計画を承認
- フィードバックを提供して計画を編集(例:`[EDIT PLAN] 技術実装に関するステップをさらに追加する`
- システムはフィードバックを統合し、修正された計画を生成
3. **自動承認**:レビュープロセスをスキップするために自動承認を有効にできます:
4. **API統合**APIを使用する場合、`feedback`パラメータでフィードバックを提供できます:
```json
{
"messages": [
{ "role": "user", "content": "量子コンピューティングとは何ですか?" }
],
"thread_id": "my_thread_id",
"auto_accepted_plan": false,
"feedback": "[EDIT PLAN] 量子アルゴリズムについてもっと含める"
}
```
### コマンドライン引数
アプリケーションは動作をカスタマイズするための複数のコマンドライン引数をサポートしています:
- **query**:処理する研究クエリ(複数の単語でも可)
- **--interactive**:組み込み質問を使用したインタラクティブモードで実行
- **--max_plan_iterations**最大計画サイクル数デフォルト1
- **--max_step_num**研究計画の最大ステップ数デフォルト3
- **--debug**:詳細なデバッグログを有効化
## よくある質問
詳細については[FAQ.md](docs/FAQ.md)を参照してください。
## ライセンス
このプロジェクトはオープンソースであり、[MIT ライセンス](./LICENSE)に従っています。
## 謝辞
DeerFlow はオープンソースコミュニティの素晴らしい成果の上に構築されています。DeerFlow を可能にしたすべてのプロジェクトと貢献者に深く感謝します。私たちは確かに巨人の肩の上に立っています。
以下のプロジェクトに心からの感謝を表します:
- **[LangChain](https://github.com/langchain-ai/langchain)**:彼らの優れたフレームワークは、シームレスな統合と機能性を実現する LLM 相互作用とチェーンに力を与えています。
- **[LangGraph](https://github.com/langchain-ai/langgraph)**マルチエージェントオーケストレーションへの革新的アプローチは、DeerFlow の複雑なワークフローの実現に不可欠でした。
これらのプロジェクトはオープンソースコラボレーションの変革力を示しており、その基盤の上に構築できることを誇りに思います。
### 主要貢献者
`DeerFlow`の主要な作者に心から感謝します。彼らのビジョン、情熱、献身がこのプロジェクトを実現しました:
- **[Daniel Walnut](https://github.com/hetaoBackend/)**
- **[Henry Li](https://github.com/magiccube/)**
あなたの揺るぎない取り組みと専門知識が DeerFlow の成功を推進しています。この旅をリードしていただき光栄です。
## スター履歴
[![Star History Chart](https://api.star-history.com/svg?repos=bytedance/deer-flow&type=Date)](https://star-history.com/#bytedance/deer-flow&Date)

View File

@@ -1,593 +0,0 @@
# 🦌 DeerFlow
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![DeepWiki](https://img.shields.io/badge/DeepWiki-bytedance%2Fdeer--flow-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McDcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/bytedance/deer-flow)
<!-- DeepWiki badge generated by https://deepwiki.ryoppippi.com/ -->
[English](./README.md) | [简体中文](./README_zh.md) | [日本語](./README_ja.md) | [Deutsch](./README_de.md) | [Español](./README_es.md) | [Русский](./README_ru.md) | [Portuguese](./README_pt.md)
> Originado do Open Source, de volta ao Open Source
**DeerFlow** (**D**eep **E**xploration and **E**fficient **R**esearch **Flow**) é um framework de Pesquisa Profunda orientado-a-comunidade que baseia-se em um íncrivel trabalho da comunidade open source. Nosso objetivo é combinar modelos de linguagem com ferramentas especializadas para tarefas como busca na web, crawling, e execução de código Python, enquanto retribui com a comunidade que o tornou possível.
Atualmente, o DeerFlow entrou oficialmente no Centro de Aplicações FaaS da Volcengine. Os usuários podem experimentá-lo online através do link de experiência para sentir intuitivamente suas funções poderosas e operações convenientes. Ao mesmo tempo, para atender às necessidades de implantação de diferentes usuários, o DeerFlow suporta implantação com um clique baseada na Volcengine. Clique no link de implantação para completar rapidamente o processo de implantação e iniciar uma jornada de pesquisa eficiente.
O DeerFlow recentemente integrou o conjunto de ferramentas de busca e rastreamento inteligente desenvolvido independentemente pela BytePlus — [InfoQuest (oferece experiência gratuita online)](https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest)
<a href="https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest" target="_blank">
<img
src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/hubseh7bsbps/20251208-160108.png" alt="infoquest_bannar"
/>
</a>
Por favor, visite [Nosso Site Oficial](https://deerflow.tech/) para maiores detalhes.
## Demo
### Video
<https://github.com/user-attachments/assets/f3786598-1f2a-4d07-919e-8b99dfa1de3e>
Nesse demo, nós demonstramos como usar o DeerFlow para:
In this demo, we showcase how to use DeerFlow to:
- Integração fácil com serviços MCP
- Conduzir o processo de Pesquisa Profunda e produzir um relatório abrangente com imagens
- Criar um áudio podcast baseado no relatório gerado
### Replays
- [Quão alta é a Torre Eiffel comparada ao prédio mais alto?](https://deerflow.tech/chat?replay=eiffel-tower-vs-tallest-building)
- [Quais são os top repositórios tendência no GitHub?](https://deerflow.tech/chat?replay=github-top-trending-repo)
- [Escreva um artigo sobre os pratos tradicionais de Nanjing's](https://deerflow.tech/chat?replay=nanjing-traditional-dishes)
- [Como decorar um apartamento alugado?](https://deerflow.tech/chat?replay=rental-apartment-decoration)
- [Visite nosso site oficial para explorar mais replays.](https://deerflow.tech/#case-studies)
---
## 📑 Tabela de Conteúdos
- [🚀 Início Rápido](#Início-Rápido)
- [🌟 Funcionalidades](#funcionalidades)
- [🏗️ Arquitetura](#arquitetura)
- [🛠️ Desenvolvimento](#desenvolvimento)
- [🐳 Docker](#docker)
- [🗣️ Texto-para-fala Integração](#texto-para-fala-integração)
- [📚 Exemplos](#exemplos)
- [❓ FAQ](#faq)
- [📜 Licença](#licença)
- [💖 Agradecimentos](#agradecimentos)
- [🏆 Contribuidores-Chave](#contribuidores-chave)
- [⭐ Histórico de Estrelas](#Histórico-Estrelas)
## Início-Rápido
DeerFlow é desenvolvido em Python, e vem com uma IU web escrita em Node.js. Para garantir um processo de configuração fácil, nós recomendamos o uso das seguintes ferramentas:
### Ferramentas Recomendadas
- **[`uv`](https://docs.astral.sh/uv/getting-started/installation/):**
Simplifica o gerenciamento de dependência de ambientes Python. `uv` automaticamente cria um ambiente virtual no diretório raiz e instala todos os pacotes necessários para não haver a necessidade de instalar ambientes Python manualmente
- **[`nvm`](https://github.com/nvm-sh/nvm):**
Gerencia múltiplas versões do ambiente de execução do Node.js sem esforço.
- **[`pnpm`](https://pnpm.io/installation):**
Instala e gerencia dependências do projeto Node.js.
### Requisitos de Ambiente
Certifique-se de que seu sistema atenda os seguintes requisitos mínimos:
- **[Python](https://www.python.org/downloads/):** Versão `3.12+`
- **[Node.js](https://nodejs.org/en/download/):** Versão `22+`
### Instalação
```bash
# Clone o repositório
git clone https://github.com/bytedance/deer-flow.git
cd deer-flow
# Instale as dependências, uv irá lidar com o interpretador do python e a criação do venv, e instalar os pacotes necessários
uv sync
# Configure .env com suas chaves de API
# Tavily: https://app.tavily.com/home
# Brave_SEARCH: https://brave.com/search/api/
# volcengine TTS: Adicione sua credencial TTS caso você a possua
cp .env.example .env
# Veja as seções abaixo 'Supported Search Engines' and 'Texto-para-Fala Integração' para todas as opções disponíveis
# Configure o conf.yaml para o seu modelo LLM e chaves API
# Por favor, consulte 'docs/configuration_guide.md' para maiores detalhes
cp conf.yaml.example conf.yaml
# Instale marp para geração de ppt
# https://github.com/marp-team/marp-cli?tab=readme-ov-file#use-package-manager
brew install marp-cli
```
Opcionalmente, instale as dependências IU web via [pnpm](https://pnpm.io/installation):
```bash
cd deer-flow/web
pnpm install
```
### Configurações
Por favor, consulte o [Guia de Configuração](docs/configuration_guide.md) para maiores detalhes.
> [!NOTA]
> Antes de iniciar o projeto, leia o guia detalhadamente, e atualize as configurações para baterem com os seus requisitos e configurações específicas.
### Console IU
A maneira mais rápida de rodar o projeto é usar o console IU.
```bash
# Execute o projeto em um shell tipo-bash
uv run main.py
```
### Web IU
Esse projeto também inclui uma IU Web, trazendo uma experiência mais interativa, dinâmica e engajadora.
> [!NOTA]
> Você precisa instalar as dependências do IU web primeiro.
```bash
# Execute ambos os servidores de backend e frontend em modo desenvolvimento
# No macOS/Linux
./bootstrap.sh -d
# No Windows
bootstrap.bat -d
```
> [!NOTA]
> Por padrão, o servidor backend se vincula a 127.0.0.1 (localhost) por motivos de segurança. Se você precisar permitir conexões externas (por exemplo, ao implantar em um servidor Linux), poderá modificar o host do servidor para 0.0.0.0 no script de inicialização (uv run server.py --host 0.0.0.0).
> Certifique-se de que seu ambiente esteja devidamente protegido antes de expor o serviço a redes externas.
Abra seu navegador e visite [`http://localhost:3000`](http://localhost:3000) para explorar a IU web.
Explore mais detalhes no diretório [`web`](./web/) .
## Mecanismos de Busca Suportados
DeerFlow suporta múltiplos mecanismos de busca que podem ser configurados no seu arquivo `.env` usando a variável `SEARCH_API`:
- **Tavily** (padrão): Uma API de busca especializada para aplicações de IA
- Requer `TAVILY_API_KEY` no seu arquivo `.env`
- Inscreva-se em: <https://app.tavily.com/home>
- **InfoQuest** (recomendado): Um conjunto de ferramentas inteligentes de busca e crawling otimizadas para IA, desenvolvido pela BytePlus
- Requer `INFOQUEST_API_KEY` no seu arquivo `.env`
- Suporte para filtragem por intervalo de tempo e filtragem de sites
- Fornece resultados de busca e extração de conteúdo de alta qualidade
- Inscreva-se em: <https://console.byteplus.com/infoquest/infoquests>
- Visite https://docs.byteplus.com/pt/docs/InfoQuest/What_is_Info_Quest para obter mais informações
- **DuckDuckGo**: Mecanismo de busca focado em privacidade
- Não requer chave API
- **Brave Search**: Mecanismo de busca focado em privacidade com funcionalidades avançadas
- Requer `BRAVE_SEARCH_API_KEY` no seu arquivo `.env`
- Inscreva-se em: <https://brave.com/search/api/>
- **Arxiv**: Busca de artigos científicos para pesquisa acadêmica
- Não requer chave API
- Especializado em artigos científicos e acadêmicos
- **Searx/SearxNG**: Mecanismo de metabusca auto-hospedado
- Requer `SEARX_HOST` no seu arquivo `.env`
- Suporta integração com Searx ou SearxNG
Para configurar o seu mecanismo preferido, defina a variável `SEARCH_API` no seu arquivo:
```bash
# Escolha uma: tavily, infoquest, duckduckgo, brave_search, arxiv
SEARCH_API=tavily
```
### Ferramentas de Crawling
- **Jina** (padrão): Ferramenta gratuita de crawling de conteúdo web acessível
- Não é necessária chave API para usar recursos básicos
- Ao usar uma chave API, você obtém limites de taxa de acesso mais altos
- Visite <https://jina.ai/reader> para obter mais informações
- **InfoQuest** (recomendado): Conjunto de ferramentas inteligentes de busca e crawling otimizadas para IA, desenvolvido pela BytePlus
- Requer `INFOQUEST_API_KEY` no seu arquivo `.env`
- Fornece parâmetros de crawling configuráveis
- Suporta configurações de timeout personalizadas
- Oferece capacidades mais poderosas de extração de conteúdo
- Visite <https://docs.byteplus.com/pt/docs/InfoQuest/What_is_Info_Quest> para obter mais informações
Para configurar sua ferramenta de crawling preferida, defina o seguinte em seu arquivo `conf.yaml`:
```yaml
CRAWLER_ENGINE:
# Tipo de mecanismo: "jina" (padrão) ou "infoquest"
engine: infoquest
```
## Funcionalidades
### Principais Funcionalidades
- 🤖 **Integração LLM**
- Suporta a integração da maioria dos modelos através de [litellm](https://docs.litellm.ai/docs/providers).
- Suporte a modelos open source como Qwen
- Interface API compatível com a OpenAI
- Sistema LLM multicamadas para diferentes complexidades de tarefa
### Ferramentas e Integrações MCP
- 🔍 **Busca e Recuperação**
- Busca web com Tavily, InfoQuest, Brave Search e mais
- Crawling com Jina e InfoQuest
- Extração de Conteúdo avançada
- 🔗 **Integração MCP perfeita**
- Expansão de capacidades de acesso para acesso a domínios privados, grafo de conhecimento, navegação web e mais
- Integração facilitdade de diversas ferramentas de pesquisa e metodologias
### Colaboração Humana
- 🧠 **Humano-no-processo**
- Suporta modificação interativa de planos de pesquisa usando linguagem natural
- Suporta auto-aceite de planos de pesquisa
- 📝 **Relatório Pós-Edição**
- Suporta edição de edição de blocos estilo Notion
- Permite refinamentos de IA, incluindo polimento de IA assistida, encurtamento de frase, e expansão
- Distribuído por [tiptap](https://tiptap.dev/)
### Criação de Conteúdo
- 🎙️ **Geração de Podcast e apresentação**
- Script de geração de podcast e síntese de áudio movido por IA
- Criação automatizada de apresentações PowerPoint simples
- Templates customizáveis para conteúdo personalizado
## Arquitetura
DeerFlow implementa uma arquitetura de sistema multi-agente modular designada para pesquisa e análise de código automatizada. O sistema é construído em LangGraph, possibilitando um fluxo de trabalho flexível baseado-em-estado onde os componentes se comunicam através de um sistema de transmissão de mensagens bem-definido.
![Diagrama de Arquitetura](./assets/architecture.png)
> Veja ao vivo em [deerflow.tech](https://deerflow.tech/#multi-agent-architecture)
O sistema emprega um fluxo de trabalho simplificado com os seguintes componentes:
1. **Coordenador**: O ponto de entrada que gerencia o ciclo de vida do fluxo de trabalho
- Inicia o processo de pesquisa baseado na entrada do usuário
- Delega tarefas so planejador quando apropriado
- Atua como a interface primária entre o usuário e o sistema
2. **Planejador**: Componente estratégico para a decomposição e planejamento
- Analisa objetivos de pesquisa e cria planos de execução estruturados
- Determina se há contexto suficiente disponível ou se mais pesquisa é necessária
- Gerencia o fluxo de pesquisa e decide quando gerar o relatório final
3. **Time de Pesquisa**: Uma coleção de agentes especializados que executam o plano:
- **Pesquisador**: Conduz buscas web e coleta informações utilizando ferramentas como mecanismos de busca web, crawling e mesmo serviços MCP.
- **Programador**: Lida com a análise de código, execução e tarefas técnicas como usar a ferramenta Python REPL.
Cada agente tem acesso à ferramentas específicas otimizadas para seu papel e opera dentro do fluxo de trabalho LangGraph.
4. **Repórter**: Estágio final do processador de estágio para saídas de pesquisa
- Resultados agregados do time de pesquisa
- Processa e estrutura as informações coletadas
- Gera relatórios abrangentes de pesquisas
## Texto-para-Fala Integração
DeerFlow agora inclui uma funcionalidade Texto-para-Fala (TTS) que permite que você converta relatórios de busca para voz. Essa funcionalidade usa o mecanismo de voz da API TTS para gerar áudio de alta qualidade a partir do texto. Funcionalidades como velocidade, volume e tom também são customizáveis.
### Usando a API TTS
Você pode acessar a funcionalidade TTS através do endpoint `/api/tts`:
```bash
# Exemplo de chamada da API usando curl
curl --location 'http://localhost:8000/api/tts' \
--header 'Content-Type: application/json' \
--data '{
"text": "This is a test of the text-to-speech functionality.",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
}' \
--output speech.mp3
```
## Desenvolvimento
### Testando
Rode o conjunto de testes:
```bash
# Roda todos os testes
make test
# Roda um arquivo de teste específico
pytest tests/integration/test_workflow.py
# Roda com coverage
make coverage
```
### Qualidade de Código
```bash
# Roda o linting
make lint
# Formata de código
make format
```
### Debugando com o LangGraph Studio
DeerFlow usa LangGraph para sua arquitetura de fluxo de trabalho. Nós podemos usar o LangGraph Studio para debugar e visualizar o fluxo de trabalho em tempo real.
#### Rodando o LangGraph Studio Localmente
DeerFlow inclui um arquivo de configuração `langgraph.json` que define a estrutura do grafo e dependências para o LangGraph Studio. Esse arquivo aponta para o grafo do fluxo de trabalho definido no projeto e automaticamente carrega as variáveis de ambiente do arquivo `.env`.
##### Mac
```bash
# Instala o gerenciador de pacote uv caso você não o possua
curl -LsSf https://astral.sh/uv/install.sh | sh
# Instala as dependências e inicia o servidor LangGraph
uvx --refresh --from "langgraph-cli[inmem]" --with-editable . --python 3.12 langgraph dev --allow-blocking
```
##### Windows / Linux
```bash
# Instala as dependências
pip install -e .
pip install -U "langgraph-cli[inmem]"
# Inicia o servidor LangGraph
langgraph dev
```
Após iniciar o servidor LangGraph, você verá diversas URLs no seu terminal:
- API: <http://127.0.0.1:2024>
- Studio UI: <https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024>
- API Docs: <http://127.0.0.1:2024/docs>
Abra o link do Studio UI no seu navegador para acessar a interface de depuração.
#### Usando o LangGraph Studio
No Studio UI, você pode:
1. Visualizar o grafo do fluxo de trabalho e como seus componentes se conectam
2. Rastrear a execução em tempo-real e ver como os dados fluem através do sistema
3. Inspecionar o estado de cada passo do fluxo de trabalho
4. Depurar problemas ao examinar entradas e saídas de cada componente
5. Coletar feedback durante a fase de planejamento para refinar os planos de pesquisa
Quando você envia um tópico de pesquisa ao Studio UI, você será capaz de ver toda a execução do fluxo de trabalho, incluindo:
- A fase de planejamento onde o plano de pesquisa foi criado
- O processo de feedback onde você pode modificar o plano
- As fases de pesquisa e escrita de cada seção
- A geração do relatório final
## Docker
Você também pode executar esse projeto via Docker.
Primeiro, voce deve ler a [configuração](#configuration) below. Make sure `.env`, `.conf.yaml` files are ready.
Segundo, para fazer o build de sua imagem docker em seu próprio servidor:
```bash
docker build -t deer-flow-api .
```
E por fim, inicie um container docker rodando o servidor web:
```bash
# substitua deer-flow-api-app com seu nome de container preferido
# Inicie o servidor e faça o bind com localhost:8000
docker run -d -t -p 127.0.0.1:8000:8000 --env-file .env --name deer-flow-api-app deer-flow-api
# pare o servidor
docker stop deer-flow-api-app
```
### Docker Compose (inclui ambos backend e frontend)
DeerFlow fornece uma estrutura docker-compose para facilmente executar ambos o backend e frontend juntos:
```bash
# building docker image
docker compose build
# start the server
docker compose up
```
> [!WARNING]
> Se você quiser implantar o DeerFlow em ambientes de produção, adicione autenticação ao site e avalie sua verificação de segurança do MCPServer e Python Repl.
## Exemplos
Os seguintes exemplos demonstram as capacidades do DeerFlow:
### Relatórios de Pesquisa
1. **Relatório OpenAI Sora** - Análise da ferramenta Sora da OpenAI
- Discute funcionalidades, acesso, engenharia de prompt, limitações e considerações éticas
- [Veja o relatório completo](examples/openai_sora_report.md)
2. **Relatório Protocolo Agent-to-Agent do Google** - Visão geral do protocolo Agent-to-Agent (A2A) do Google
- Discute o seu papel na comunicação de Agente de IA e seu relacionamento com o Protocolo de Contexto de Modelo ( MCP ) da Anthropic
- [Veja o relatório completo](examples/what_is_agent_to_agent_protocol.md)
3. **O que é MCP?** - Uma análise abrangente to termo "MCP" através de múltiplos contextos
- Explora o Protocolo de Contexto de Modelo em IA, Fosfato Monocálcio em Química, e placa de microcanal em eletrônica
- [Veja o relatório completo](examples/what_is_mcp.md)
4. **Bitcoin Price Fluctuations** - Análise das recentes movimentações de preço do Bitcoin
- Examina tendências de mercado, influências regulatórias, e indicadores técnicos
- Fornece recomendações baseadas nos dados históricos
- [Veja o relatório completo](examples/bitcoin_price_fluctuation.md)
5. **O que é LLM?** - Uma exploração em profundidade de Large Language Models
- Discute arquitetura, treinamento, aplicações, e considerações éticas
- [Veja o relatório completo](examples/what_is_llm.md)
6. **Como usar Claude para Pesquisa Aprofundada?** - Melhores práticas e fluxos de trabalho para usar Claude em pesquisa aprofundada
- Cobre engenharia de prompt, análise de dados, e integração com outras ferramentas
- [Veja o relatório completo](examples/how_to_use_claude_deep_research.md)
7. **Adoção de IA na Área da Saúde: Fatores de Influência** - Análise dos fatores que levam à adoção de IA na área da saúde
- Discute tecnologias de IA, qualidade de dados, considerações éticas, avaliações econômicas, prontidão organizacional, e infraestrutura digital
- [Veja o relatório completo](examples/AI_adoption_in_healthcare.md)
8. **Impacto da Computação Quântica em Criptografia** - Análise dos impactos da computação quântica em criptografia
- Discture vulnerabilidades da criptografia clássica, criptografia pós-quântica, e soluções criptográficas de resistência-quântica
- [Veja o relatório completo](examples/Quantum_Computing_Impact_on_Cryptography.md)
9. **Destaques da Performance do Cristiano Ronaldo** - Análise dos destaques da performance do Cristiano Ronaldo
- Discute as suas conquistas de carreira, objetivos internacionais, e performance em diversas partidas
- [Veja o relatório completo](examples/Cristiano_Ronaldo's_Performance_Highlights.md)
Para executar esses exemplos ou criar seus próprios relatórios de pesquisa, você deve utilizar os seguintes comandos:
```bash
# Executa com uma consulta específica
uv run main.py "Quais fatores estão influenciando a adoção de IA na área da saúde?"
# Executa com parâmetros de planejamento customizados
uv run main.py --max_plan_iterations 3 "Como a computação quântica impacta na criptografia?"
# Executa em modo interativo com questões embutidas
uv run main.py --interactive
# Ou executa com um prompt interativo básico
uv run main.py
# Vê todas as opções disponíveis
uv run main.py --help
```
### Modo Interativo
A aplicação agora suporta um modo interativo com questões embutidas tanto em Inglês quanto Chinês:
1. Inicie o modo interativo:
```bash
uv run main.py --interactive
```
2. Selecione sua linguagem de preferência (English or 中文)
3. Escolha uma das questões embutidas da lista ou selecione a opção para perguntar sua própria questão
4. O sistema irá processar sua questão e gerar um relatório abrangente de pesquisa
### Humano no processo
DeerFlow inclue um mecanismo de humano no processo que permite a você revisar, editar e aprovar planos de pesquisa antes que estes sejam executados:
1. **Revisão de Plano**: Quando o humano no processo está habilitado, o sistema irá apresentar o plano de pesquisa gerado para sua revisão antes da execução
2. **Fornecimento de Feedback**: Você pode:
- Aceitar o plano respondendo com `[ACCEPTED]`
- Edite o plano fornecendo feedback (e.g., `[EDIT PLAN] Adicione mais passos sobre a implementação técnica`)
- O sistema irá incorporar seu feedback e gerar um plano revisado
3. **Auto-aceite**: Você pode habilitar o auto-aceite ou pular o processo de revisão:
- Via API: Defina `auto_accepted_plan: true` na sua requisição
4. **Integração de API**: Quanto usar a API, você pode fornecer um feedback através do parâmetro `feedback`:
```json
{
"messages": [{ "role": "user", "content": "O que é computação quântica?" }],
"thread_id": "my_thread_id",
"auto_accepted_plan": false,
"feedback": "[EDIT PLAN] Inclua mais sobre algoritmos quânticos"
}
```
### Argumentos via Linha de Comando
A aplicação suporta diversos argumentos via linha de comando para customizar o seu comportamento:
- **consulta**: A consulta de pesquisa a ser processada (podem ser múltiplas palavras)
- **--interativo**: Roda no modo interativo com questões embutidas
- **--max_plan_iterations**: Número máximo de ciclos de planejamento (padrão: 1)
- **--max_step_num**: Número máximo de passos em um plano de pesquisa (padrão: 3)
- **--debug**: Habilita Enable um log de depuração detalhado
## FAQ
Por favor consulte a [FAQ.md](docs/FAQ.md) para maiores detalhes.
## Licença
Esse projeto é open source e disponível sob a [MIT License](./LICENSE).
## Agradecimentos
DeerFlow é construído através do incrível trabalho da comunidade open-source. Nós somos profundamente gratos a todos os projetos e contribuidores cujos esforços tornaram o DeerFlow possível. Realmente, nós estamos apoiados nos ombros de gigantes.
Nós gostaríamos de extender nossos sinceros agradecimentos aos seguintes projetos por suas invaloráveis contribuições:
- **[LangChain](https://github.com/langchain-ai/langchain)**: O framework excepcional deles empodera nossas interações via LLM e correntes, permitindo uma integração perfeita e funcional.
- **[LangGraph](https://github.com/langchain-ai/langgraph)**: A abordagem inovativa para orquestração multi-agente deles tem sido foi fundamental em permitir o acesso dos fluxos de trabalho sofisticados do DeerFlow.
Esses projetos exemplificam o poder transformador da colaboração open-source, e nós temos orgulho de construir baseado em suas fundações.
### Contribuidores-Chave
Um sincero muito obrigado vai para os principais autores do `DeerFlow`, cuja visão, paixão, e dedicação trouxe esse projeto à vida:
- **[Daniel Walnut](https://github.com/hetaoBackend/)**
- **[Henry Li](https://github.com/magiccube/)**
O seu compromisso inabalável e experiência tem sido a força por trás do sucesso do DeerFlow. Nós estamos honrados em tê-los no comando dessa trajetória.
## Histórico-Estrelas
[![Gráfico do Histórico de Estrelas](https://api.star-history.com/svg?repos=bytedance/deer-flow&type=Date)](https://star-history.com/#bytedance/deer-flow&Date)

View File

@@ -1,607 +0,0 @@
# 🦌 DeerFlow
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![DeepWiki](https://img.shields.io/badge/DeepWiki-bytedance%2Fdeer--flow-blue.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAAyCAYAAAAnWDnqAAAAAXNSR0IArs4c6QAAA05JREFUaEPtmUtyEzEQhtWTQyQLHNak2AB7ZnyXZMEjXMGeK/AIi+QuHrMnbChYY7MIh8g01fJoopFb0uhhEqqcbWTp06/uv1saEDv4O3n3dV60RfP947Mm9/SQc0ICFQgzfc4CYZoTPAswgSJCCUJUnAAoRHOAUOcATwbmVLWdGoH//PB8mnKqScAhsD0kYP3j/Yt5LPQe2KvcXmGvRHcDnpxfL2zOYJ1mFwrryWTz0advv1Ut4CJgf5uhDuDj5eUcAUoahrdY/56ebRWeraTjMt/00Sh3UDtjgHtQNHwcRGOC98BJEAEymycmYcWwOprTgcB6VZ5JK5TAJ+fXGLBm3FDAmn6oPPjR4rKCAoJCal2eAiQp2x0vxTPB3ALO2CRkwmDy5WohzBDwSEFKRwPbknEggCPB/imwrycgxX2NzoMCHhPkDwqYMr9tRcP5qNrMZHkVnOjRMWwLCcr8ohBVb1OMjxLwGCvjTikrsBOiA6fNyCrm8V1rP93iVPpwaE+gO0SsWmPiXB+jikdf6SizrT5qKasx5j8ABbHpFTx+vFXp9EnYQmLx02h1QTTrl6eDqxLnGjporxl3NL3agEvXdT0WmEost648sQOYAeJS9Q7bfUVoMGnjo4AZdUMQku50McCcMWcBPvr0SzbTAFDfvJqwLzgxwATnCgnp4wDl6Aa+Ax283gghmj+vj7feE2KBBRMW3FzOpLOADl0Isb5587h/U4gGvkt5v60Z1VLG8BhYjbzRwyQZemwAd6cCR5/XFWLYZRIMpX39AR0tjaGGiGzLVyhse5C9RKC6ai42ppWPKiBagOvaYk8lO7DajerabOZP46Lby5wKjw1HCRx7p9sVMOWGzb/vA1hwiWc6jm3MvQDTogQkiqIhJV0nBQBTU+3okKCFDy9WwferkHjtxib7t3xIUQtHxnIwtx4mpg26/HfwVNVDb4oI9RHmx5WGelRVlrtiw43zboCLaxv46AZeB3IlTkwouebTr1y2NjSpHz68WNFjHvupy3q8TFn3Hos2IAk4Ju5dCo8B3wP7VPr/FGaKiG+T+v+TQqIrOqMTL1VdWV1DdmcbO8KXBz6esmYWYKPwDL5b5FA1a0hwapHiom0r/cKaoqr+27/XcrS5UwSMbQAAAABJRU5ErkJggg==)](https://deepwiki.com/bytedance/deer-flow)
<!-- DeepWiki badge generated by https://deepwiki.ryoppippi.com/ -->
[English](./README.md) | [简体中文](./README_zh.md) | [日本語](./README_ja.md) | [Deutsch](./README_de.md) | [Español](./README_es.md) | [Русский](./README_ru.md) | [Portuguese](./README_pt.md)
> Создано на базе открытого кода, возвращено в открытый код.
**DeerFlow** (**D**eep **E**xploration and **E**fficient **R**esearch **Flow**) - это фреймворк для глубокого исследования, разработанный сообществом и основанный на впечатляющей работе сообщества открытого кода. Наша цель - объединить языковые модели со специализированными инструментами для таких задач, как веб-поиск, сканирование и выполнение кода Python, одновременно возвращая пользу сообществу, которое сделало это возможным.
В настоящее время DeerFlow официально вошел в Центр приложений FaaS Volcengine. Пользователи могут испытать его онлайн через ссылку для опыта, чтобы интуитивно почувствовать его мощные функции и удобные операции. В то же время, для удовлетворения потребностей развертывания различных пользователей, DeerFlow поддерживает развертывание одним кликом на основе Volcengine. Нажмите на ссылку развертывания, чтобы быстро завершить процесс развертывания и начать эффективное исследовательское путешествие.
DeerFlow недавно интегрировал интеллектуальный набор инструментов поиска и краулинга, разработанный самостоятельно компанией BytePlus — [InfoQuest (поддерживает бесплатное онлайн-опробование)](https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest)
<a href="https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest" target="_blank">
<img
src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/hubseh7bsbps/20251208-160108.png" alt="infoquest_bannar"
/>
</a>
Пожалуйста, посетите [наш официальный сайт](https://deerflow.tech/) для получения дополнительной информации.
## Демонстрация
### Видео
<https://github.com/user-attachments/assets/f3786598-1f2a-4d07-919e-8b99dfa1de3e>
В этой демонстрации мы показываем, как использовать DeerFlow для:
- Бесшовной интеграции с сервисами MCP
- Проведения процесса глубокого исследования и создания комплексного отчета с изображениями
- Создания аудио подкаста на основе сгенерированного отчета
### Повторы
- [Какова высота Эйфелевой башни по сравнению с самым высоким зданием?](https://deerflow.tech/chat?replay=eiffel-tower-vs-tallest-building)
- [Какие репозитории самые популярные на GitHub?](https://deerflow.tech/chat?replay=github-top-trending-repo)
- [Написать статью о традиционных блюдах Нанкина](https://deerflow.tech/chat?replay=nanjing-traditional-dishes)
- [Как украсить съемную квартиру?](https://deerflow.tech/chat?replay=rental-apartment-decoration)
- [Посетите наш официальный сайт, чтобы изучить больше повторов.](https://deerflow.tech/#case-studies)
---
## 📑 Оглавление
- [🚀 Быстрый старт](#быстрый-старт)
- [🌟 Особенности](#особенности)
- [🏗️ Архитектура](#архитектура)
- [🛠️ Разработка](#разработка)
- [🐳 Docker](#docker)
- [🗣️ Интеграция преобразования текста в речь](#интеграция-преобразования-текста-в-речь)
- [📚 Примеры](#примеры)
- [❓ FAQ](#faq)
- [📜 Лицензия](#лицензия)
- [💖 Благодарности](#благодарности)
- [⭐ История звезд](#история-звезд)
## Быстрый старт
DeerFlow разработан на Python и поставляется с веб-интерфейсом, написанным на Node.js. Для обеспечения плавного процесса настройки мы рекомендуем использовать следующие инструменты:
### Рекомендуемые инструменты
- **[`uv`](https://docs.astral.sh/uv/getting-started/installation/):**
Упрощает управление средой Python и зависимостями. `uv` автоматически создает виртуальную среду в корневом каталоге и устанавливает все необходимые пакеты за вас—без необходимости вручную устанавливать среды Python.
- **[`nvm`](https://github.com/nvm-sh/nvm):**
Легко управляйте несколькими версиями среды выполнения Node.js.
- **[`pnpm`](https://pnpm.io/installation):**
Установка и управление зависимостями проекта Node.js.
### Требования к среде
Убедитесь, что ваша система соответствует следующим минимальным требованиям:
- **[Python](https://www.python.org/downloads/):** Версия `3.12+`
- **[Node.js](https://nodejs.org/en/download/):** Версия `22+`
### Установка
```bash
# Клонировать репозиторий
git clone https://github.com/bytedance/deer-flow.git
cd deer-flow
# Установить зависимости, uv позаботится об интерпретаторе python и создании venv, и установит необходимые пакеты
uv sync
# Настроить .env с вашими API-ключами
# Tavily: https://app.tavily.com/home
# Brave_SEARCH: https://brave.com/search/api/
# volcengine TTS: Добавьте ваши учетные данные TTS, если они у вас есть
cp .env.example .env
# См. разделы 'Поддерживаемые поисковые системы' и 'Интеграция преобразования текста в речь' ниже для всех доступных опций
# Настроить conf.yaml для вашей модели LLM и API-ключей
# Пожалуйста, обратитесь к 'docs/configuration_guide.md' для получения дополнительной информации
cp conf.yaml.example conf.yaml
# Установить marp для генерации презентаций
# https://github.com/marp-team/marp-cli?tab=readme-ov-file#use-package-manager
brew install marp-cli
```
По желанию установите зависимости веб-интерфейса через [pnpm](https://pnpm.io/installation):
```bash
cd deer-flow/web
pnpm install
```
### Конфигурации
Пожалуйста, обратитесь к [Руководству по конфигурации](docs/configuration_guide.md) для получения дополнительной информации.
> [!ПРИМЕЧАНИЕ]
> Прежде чем запустить проект, внимательно прочитайте руководство и обновите конфигурации в соответствии с вашими конкретными настройками и требованиями.
### Консольный интерфейс
Самый быстрый способ запустить проект - использовать консольный интерфейс.
```bash
# Запустить проект в оболочке, похожей на bash
uv run main.py
```
### Веб-интерфейс
Этот проект также включает веб-интерфейс, предлагающий более динамичный и привлекательный интерактивный опыт.
> [!ПРИМЕЧАНИЕ]
> Сначала вам нужно установить зависимости веб-интерфейса.
```bash
# Запустить оба сервера, бэкенд и фронтенд, в режиме разработки
# На macOS/Linux
./bootstrap.sh -d
# На Windows
bootstrap.bat -d
```
> [!Примечание]
> По умолчанию сервер бэкенда привязывается к 127.0.0.1 (localhost) по соображениям безопасности. Если вам нужно разрешить внешние подключения (например, при развертывании на сервере Linux), вы можете изменить хост сервера на 0.0.0.0 в скрипте загрузки (uv run server.py --host 0.0.0.0).
> Пожалуйста, убедитесь, что ваша среда должным образом защищена, прежде чем подвергать сервис внешним сетям.
Откройте ваш браузер и посетите [`http://localhost:3000`](http://localhost:3000), чтобы исследовать веб-интерфейс.
Исследуйте больше деталей в каталоге [`web`](./web/).
## Поддерживаемые поисковые системы
DeerFlow поддерживает несколько поисковых систем, которые можно настроить в файле `.env` с помощью переменной `SEARCH_API`:
- **Tavily** (по умолчанию): Специализированный поисковый API для приложений ИИ
- Требуется `TAVILY_API_KEY` в вашем файле `.env`
- Зарегистрируйтесь на: <https://app.tavily.com/home>
- **InfoQuest** (рекомендуется): Набор интеллектуальных инструментов для поиска и сканирования, оптимизированных для ИИ, разработанный компанией BytePlus
- Требуется `INFOQUEST_API_KEY` в вашем файле `.env`
- Поддержка фильтрации по диапазону времени и фильтрации сайтов
- Предоставляет высококачественные результаты поиска и извлечение контента
- Зарегистрируйтесь на: <https://console.byteplus.com/infoquest/infoquests>
- Посетите https://docs.byteplus.com/ru/docs/InfoQuest/What_is_Info_Quest для получения дополнительной информации
- **DuckDuckGo**: Поисковая система, ориентированная на конфиденциальность
- Не требуется API-ключ
- **Brave Search**: Поисковая система, ориентированная на конфиденциальность, с расширенными функциями
- Требуется `BRAVE_SEARCH_API_KEY` в вашем файле `.env`
- Зарегистрируйтесь на: <https://brave.com/search/api/>
- **Arxiv**: Поиск научных статей для академических исследований
- Не требуется API-ключ
- Специализируется на научных и академических статьях
- **Searx/SearxNG**: Самостоятельно размещённая метапоисковая система
- Требуется `SEARX_HOST` в вашем файле `.env`
- Поддерживает подключение к Searx или SearxNG
Чтобы настроить предпочитаемую поисковую систему, установите переменную `SEARCH_API` в вашем файле `.env`:
```bash
# Выберите одно: tavily, infoquest, duckduckgo, brave_search, arxiv
SEARCH_API=tavily
```
### Инструменты сканирования
- **Jina** (по умолчанию): Бесплатный доступный инструмент для сканирования веб-контента
- API-ключ не требуется для использования базовых функций
- При использовании API-ключа вы получаете более высокие лимиты скорости доступа
- Посетите <https://jina.ai/reader> для получения дополнительной информации
- **InfoQuest** (рекомендуется): Набор интеллектуальных инструментов для поиска и сканирования, оптимизированных для ИИ, разработанный компанией BytePlus
- Требуется `INFOQUEST_API_KEY` в вашем файле `.env`
- Предоставляет настраиваемые параметры сканирования
- Поддерживает настройки пользовательских тайм-аутов
- Предоставляет более мощные возможности извлечения контента
- Посетите <https://docs.byteplus.com/ru/docs/InfoQuest/What_is_Info_Quest> для получения дополнительной информации
Чтобы настроить предпочитаемый инструмент сканирования, установите следующее в вашем файле `conf.yaml`:
```yaml
CRAWLER_ENGINE:
# Тип движка: "jina" (по умолчанию) или "infoquest"
engine: infoquest
```
## Особенности
### Ключевые возможности
- 🤖 **Интеграция LLM**
- Поддерживает интеграцию большинства моделей через [litellm](https://docs.litellm.ai/docs/providers).
- Поддержка моделей с открытым исходным кодом, таких как Qwen
- API-интерфейс, совместимый с OpenAI
- Многоуровневая система LLM для задач различной сложности
### Инструменты и интеграции MCP
- 🔍 **Поиск и извлечение**
- Веб-поиск через Tavily, InfoQuest, Brave Search и другие
- Сканирование с Jina и InfoQuest
- Расширенное извлечение контента
- 🔗 **Бесшовная интеграция MCP**
- Расширение возможностей для доступа к частным доменам, графам знаний, веб-браузингу и многому другому
- Облегчает интеграцию различных исследовательских инструментов и методологий
### Человеческое взаимодействие
- 🧠 **Человек в контуре**
- Поддерживает интерактивное изменение планов исследования с использованием естественного языка
- Поддерживает автоматическое принятие планов исследования
- 📝 **Пост-редактирование отчетов**
- Поддерживает блочное редактирование в стиле Notion
- Позволяет совершенствовать с помощью ИИ, включая полировку, сокращение и расширение предложений
- Работает на [tiptap](https://tiptap.dev/)
### Создание контента
- 🎙️ **Генерация подкастов и презентаций**
- Генерация сценариев подкастов и синтез аудио с помощью ИИ
- Автоматическое создание простых презентаций PowerPoint
- Настраиваемые шаблоны для индивидуального контента
## Архитектура
DeerFlow реализует модульную архитектуру системы с несколькими агентами, предназначенную для автоматизированных исследований и анализа кода. Система построена на LangGraph, обеспечивающей гибкий рабочий процесс на основе состояний, где компоненты взаимодействуют через четко определенную систему передачи сообщений.
![Диаграмма архитектуры](./assets/architecture.png)
> Посмотрите вживую на [deerflow.tech](https://deerflow.tech/#multi-agent-architecture)
В системе используется оптимизированный рабочий процесс со следующими компонентами:
1. **Координатор**: Точка входа, управляющая жизненным циклом рабочего процесса
- Инициирует процесс исследования на основе пользовательского ввода
- Делегирует задачи планировщику, когда это необходимо
- Выступает в качестве основного интерфейса между пользователем и системой
2. **Планировщик**: Стратегический компонент для декомпозиции и планирования задач
- Анализирует цели исследования и создает структурированные планы выполнения
- Определяет, достаточно ли доступного контекста или требуется дополнительное исследование
- Управляет потоком исследования и решает, когда генерировать итоговый отчет
3. **Исследовательская команда**: Набор специализированных агентов, которые выполняют план:
- **Исследователь**: Проводит веб-поиск и сбор информации с использованием таких инструментов, как поисковые системы, сканирование и даже сервисы MCP.
- **Программист**: Обрабатывает анализ кода, выполнение и технические задачи с помощью инструмента Python REPL.
Каждый агент имеет доступ к определенным инструментам, оптимизированным для его роли, и работает в рамках фреймворка LangGraph
4. **Репортер**: Процессор финальной стадии для результатов исследования
- Агрегирует находки исследовательской команды
- Обрабатывает и структурирует собранную информацию
- Генерирует комплексные исследовательские отчеты
## Интеграция преобразования текста в речь
DeerFlow теперь включает функцию преобразования текста в речь (TTS), которая позволяет конвертировать исследовательские отчеты в речь. Эта функция использует API TTS volcengine для генерации высококачественного аудио из текста. Также можно настраивать такие параметры, как скорость, громкость и тон.
### Использование API TTS
Вы можете получить доступ к функциональности TTS через конечную точку `/api/tts`:
```bash
# Пример вызова API с использованием curl
curl --location 'http://localhost:8000/api/tts' \
--header 'Content-Type: application/json' \
--data '{
"text": "Это тест функциональности преобразования текста в речь.",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
}' \
--output speech.mp3
```
## Разработка
### Тестирование
Запустите набор тестов:
```bash
# Запустить все тесты
make test
# Запустить определенный тестовый файл
pytest tests/integration/test_workflow.py
# Запустить с покрытием
make coverage
```
### Качество кода
```bash
# Запустить линтинг
make lint
# Форматировать код
make format
```
### Отладка с LangGraph Studio
DeerFlow использует LangGraph для своей архитектуры рабочего процесса. Вы можете использовать LangGraph Studio для отладки и визуализации рабочего процесса в реальном времени.
#### Запуск LangGraph Studio локально
DeerFlow включает конфигурационный файл `langgraph.json`, который определяет структуру графа и зависимости для LangGraph Studio. Этот файл указывает на графы рабочего процесса, определенные в проекте, и автоматически загружает переменные окружения из файла `.env`.
##### Mac
```bash
# Установите менеджер пакетов uv, если у вас его нет
curl -LsSf https://astral.sh/uv/install.sh | sh
# Установите зависимости и запустите сервер LangGraph
uvx --refresh --from "langgraph-cli[inmem]" --with-editable . --python 3.12 langgraph dev --allow-blocking
```
##### Windows / Linux
```bash
# Установить зависимости
pip install -e .
pip install -U "langgraph-cli[inmem]"
# Запустить сервер LangGraph
langgraph dev
```
После запуска сервера LangGraph вы увидите несколько URL в терминале:
- API: <http://127.0.0.1:2024>
- Studio UI: <https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024>
- API Docs: <http://127.0.0.1:2024/docs>
Откройте ссылку Studio UI в вашем браузере для доступа к интерфейсу отладки.
#### Использование LangGraph Studio
В интерфейсе Studio вы можете:
1. Визуализировать граф рабочего процесса и видеть, как соединяются компоненты
2. Отслеживать выполнение в реальном времени, чтобы видеть, как данные проходят через систему
3. Исследовать состояние на каждом шаге рабочего процесса
4. Отлаживать проблемы путем изучения входов и выходов каждого компонента
5. Предоставлять обратную связь во время фазы планирования для уточнения планов исследования
Когда вы отправляете тему исследования в интерфейсе Studio, вы сможете увидеть весь процесс выполнения рабочего процесса, включая:
- Фазу планирования, где создается план исследования
- Цикл обратной связи, где вы можете модифицировать план
- Фазы исследования и написания для каждого раздела
- Генерацию итогового отчета
### Включение трассировки LangSmith
DeerFlow поддерживает трассировку LangSmith, чтобы помочь вам отладить и контролировать ваши рабочие процессы. Чтобы включить трассировку LangSmith:
1. Убедитесь, что в вашем файле `.env` есть следующие конфигурации (см. `.env.example`):
```bash
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY="xxx"
LANGSMITH_PROJECT="xxx"
```
2. Запустите трассировку и визуализируйте граф локально с LangSmith, выполнив:
```bash
langgraph dev
```
Это включит визуализацию трассировки в LangGraph Studio и отправит ваши трассировки в LangSmith для мониторинга и анализа.
## Docker
Вы также можете запустить этот проект с Docker.
Во-первых, вам нужно прочитать [конфигурацию](docs/configuration_guide.md) ниже. Убедитесь, что файлы `.env`, `.conf.yaml` готовы.
Во-вторых, чтобы построить Docker-образ вашего собственного веб-сервера:
```bash
docker build -t deer-flow-api .
```
Наконец, запустите Docker-контейнер с веб-сервером:
```bash
# Замените deer-flow-api-app на предпочитаемое вами имя контейнера
# Запустите сервер и привяжите к localhost:8000
docker run -d -t -p 127.0.0.1:8000:8000 --env-file .env --name deer-flow-api-app deer-flow-api
# остановить сервер
docker stop deer-flow-api-app
```
### Docker Compose (включает как бэкенд, так и фронтенд)
DeerFlow предоставляет настройку docker-compose для легкого запуска бэкенда и фронтенда вместе:
```bash
# сборка docker-образа
docker compose build
# запуск сервера
docker compose up
```
> [!WARNING]
> Если вы хотите развернуть DeerFlow в производственных средах, пожалуйста, добавьте аутентификацию к веб-сайту и оцените свою проверку безопасности MCPServer и Python Repl.
## Примеры
Следующие примеры демонстрируют возможности DeerFlow:
### Исследовательские отчеты
1. **Отчет о OpenAI Sora** - Анализ инструмента ИИ Sora от OpenAI
- Обсуждаются функции, доступ, инженерия промптов, ограничения и этические соображения
- [Просмотреть полный отчет](examples/openai_sora_report.md)
2. **Отчет о протоколе Agent to Agent от Google** - Обзор протокола Agent to Agent (A2A) от Google
- Обсуждается его роль в коммуникации агентов ИИ и его отношение к протоколу Model Context Protocol (MCP) от Anthropic
- [Просмотреть полный отчет](examples/what_is_agent_to_agent_protocol.md)
3. **Что такое MCP?** - Комплексный анализ термина "MCP" в различных контекстах
- Исследует Model Context Protocol в ИИ, Монокальцийфосфат в химии и Микроканальные пластины в электронике
- [Просмотреть полный отчет](examples/what_is_mcp.md)
4. **Колебания цены Биткоина** - Анализ недавних движений цены Биткоина
- Исследует рыночные тренды, регуляторные влияния и технические индикаторы
- Предоставляет рекомендации на основе исторических данных
- [Просмотреть полный отчет](examples/bitcoin_price_fluctuation.md)
5. **Что такое LLM?** - Углубленное исследование больших языковых моделей
- Обсуждаются архитектура, обучение, приложения и этические соображения
- [Просмотреть полный отчет](examples/what_is_llm.md)
6. **Как использовать Claude для глубокого исследования?** - Лучшие практики и рабочие процессы для использования Claude в глубоком исследовании
- Охватывает инженерию промптов, анализ данных и интеграцию с другими инструментами
- [Просмотреть полный отчет](examples/how_to_use_claude_deep_research.md)
7. **Внедрение ИИ в здравоохранении: Влияющие факторы** - Анализ факторов, движущих внедрением ИИ в здравоохранении
- Обсуждаются технологии ИИ, качество данных, этические соображения, экономические оценки, организационная готовность и цифровая инфраструктура
- [Просмотреть полный отчет](examples/AI_adoption_in_healthcare.md)
8. **Влияние квантовых вычислений на криптографию** - Анализ влияния квантовых вычислений на криптографию
- Обсуждаются уязвимости классической криптографии, пост-квантовая криптография и криптографические решения, устойчивые к квантовым вычислениям
- [Просмотреть полный отчет](examples/Quantum_Computing_Impact_on_Cryptography.md)
9. **Ключевые моменты выступлений Криштиану Роналду** - Анализ выдающихся выступлений Криштиану Роналду
- Обсуждаются его карьерные достижения, международные голы и выступления в различных матчах
- [Просмотреть полный отчет](examples/Cristiano_Ronaldo's_Performance_Highlights.md)
Чтобы запустить эти примеры или создать собственные исследовательские отчеты, вы можете использовать следующие команды:
```bash
# Запустить с определенным запросом
uv run main.py "Какие факторы влияют на внедрение ИИ в здравоохранении?"
# Запустить с пользовательскими параметрами планирования
uv run main.py --max_plan_iterations 3 "Как квантовые вычисления влияют на криптографию?"
# Запустить в интерактивном режиме с встроенными вопросами
uv run main.py --interactive
# Или запустить с базовым интерактивным приглашением
uv run main.py
# Посмотреть все доступные опции
uv run main.py --help
```
### Интерактивный режим
Приложение теперь поддерживает интерактивный режим с встроенными вопросами как на английском, так и на китайском языках:
1. Запустите интерактивный режим:
```bash
uv run main.py --interactive
```
2. Выберите предпочитаемый язык (English или 中文)
3. Выберите из списка встроенных вопросов или выберите опцию задать собственный вопрос
4. Система обработает ваш вопрос и сгенерирует комплексный исследовательский отчет
### Человек в контуре
DeerFlow включает механизм "человек в контуре", который позволяет вам просматривать, редактировать и утверждать планы исследования перед их выполнением:
1. **Просмотр плана**: Когда активирован режим "человек в контуре", система представит сгенерированный план исследования для вашего просмотра перед выполнением
2. **Предоставление обратной связи**: Вы можете:
- Принять план, ответив `[ACCEPTED]`
- Отредактировать план, предоставив обратную связь (например, `[EDIT PLAN] Добавить больше шагов о технической реализации`)
- Система включит вашу обратную связь и сгенерирует пересмотренный план
3. **Автоматическое принятие**: Вы можете включить автоматическое принятие, чтобы пропустить процесс просмотра:
- Через API: Установите `auto_accepted_plan: true` в вашем запросе
4. **Интеграция API**: При использовании API вы можете предоставить обратную связь через параметр `feedback`:
```json
{
"messages": [{ "role": "user", "content": "Что такое квантовые вычисления?" }],
"thread_id": "my_thread_id",
"auto_accepted_plan": false,
"feedback": "[EDIT PLAN] Включить больше о квантовых алгоритмах"
}
```
### Аргументы командной строки
Приложение поддерживает несколько аргументов командной строки для настройки его поведения:
- **query**: Запрос исследования для обработки (может состоять из нескольких слов)
- **--interactive**: Запустить в интерактивном режиме с встроенными вопросами
- **--max_plan_iterations**: Максимальное количество циклов планирования (по умолчанию: 1)
- **--max_step_num**: Максимальное количество шагов в плане исследования (по умолчанию: 3)
- **--debug**: Включить подробное логирование отладки
## FAQ
Пожалуйста, обратитесь к [FAQ.md](docs/FAQ.md) для получения дополнительной информации.
## Лицензия
Этот проект имеет открытый исходный код и доступен под [Лицензией MIT](./LICENSE).
## Благодарности
DeerFlow создан на основе невероятной работы сообщества открытого кода. Мы глубоко благодарны всем проектам и контрибьюторам, чьи усилия сделали DeerFlow возможным. Поистине, мы стоим на плечах гигантов.
Мы хотели бы выразить искреннюю признательность следующим проектам за их неоценимый вклад:
- **[LangChain](https://github.com/langchain-ai/langchain)**: Их исключительный фреймворк обеспечивает наши взаимодействия и цепочки LLM, позволяя бесшовную интеграцию и функциональность.
- **[LangGraph](https://github.com/langchain-ai/langgraph)**: Их инновационный подход к оркестровке многоагентных систем сыграл решающую роль в обеспечении сложных рабочих процессов DeerFlow.
Эти проекты являются примером преобразующей силы сотрудничества в области открытого кода, и мы гордимся тем, что строим на их основе.
### Ключевые контрибьюторы
Сердечная благодарность основным авторам `DeerFlow`, чье видение, страсть и преданность делу вдохнули жизнь в этот проект:
- **[Daniel Walnut](https://github.com/hetaoBackend/)**
- **[Henry Li](https://github.com/magiccube/)**
Ваша непоколебимая приверженность и опыт стали движущей силой успеха DeerFlow. Мы считаем за честь иметь вас во главе этого путешествия.
## История звезд
[![Star History Chart](https://api.star-history.com/svg?repos=bytedance/deer-flow&type=Date)](https://star-history.com/#bytedance/deer-flow&Date)

View File

@@ -1,686 +0,0 @@
# 🦌 DeerFlow
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[English](./README.md) | [简体中文](./README_zh.md) | [日本語](./README_ja.md) | [Deutsch](./README_de.md) | [Español](./README_es.md) | [Русский](./README_ru.md) |[Portuguese](./README_pt.md)
> 源于开源,回馈开源。
**DeerFlow****D**eep **E**xploration and **E**fficient **R**esearch **Flow**)是一个社区驱动的深度研究框架,它建立在开源社区的杰出工作基础之上。我们的目标是将语言模型与专业工具(如网络搜索、爬虫和 Python 代码执行)相结合,同时回馈使这一切成为可能的社区。
目前DeerFlow 已正式入驻[火山引擎的 FaaS 应用中心](https://console.volcengine.com/vefaas/region:vefaas+cn-beijing/market),用户可通过[体验链接](https://console.volcengine.com/vefaas/region:vefaas+cn-beijing/market/deerflow/?channel=github&source=deerflow)进行在线体验直观感受其强大功能与便捷操作同时为满足不同用户的部署需求DeerFlow 支持基于火山引擎一键部署,点击[部署链接](https://console.volcengine.com/vefaas/region:vefaas+cn-beijing/application/create?templateId=683adf9e372daa0008aaed5c&channel=github&source=deerflow)即可快速完成部署流程,开启高效研究之旅。
DeerFlow 新接入BytePlus自主推出的智能搜索与爬取工具集--[InfoQuest支持在线免费体验](https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest)
<a href="https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest" target="_blank">
<img
src="https://sf16-sg.tiktokcdn.com/obj/eden-sg/hubseh7bsbps/20251208-141052.png" alt="infoquest_bannar"
/>
</a>
请访问[DeerFlow 的官方网站](https://deerflow.tech/)了解更多详情。
## 演示
### 视频
<https://github.com/user-attachments/assets/f3786598-1f2a-4d07-919e-8b99dfa1de3e>
在此演示中,我们展示了如何使用 DeerFlow
- 无缝集成 MCP 服务
- 进行深度研究过程并生成包含图像的综合报告
- 基于生成的报告创建播客音频
### 回放示例
- [埃菲尔铁塔与最高建筑相比有多高?](https://deerflow.tech/chat?replay=eiffel-tower-vs-tallest-building)
- [GitHub 上最热门的仓库有哪些?](https://deerflow.tech/chat?replay=github-top-trending-repo)
- [撰写关于南京传统美食的文章](https://deerflow.tech/chat?replay=nanjing-traditional-dishes)
- [如何装饰租赁公寓?](https://deerflow.tech/chat?replay=rental-apartment-decoration)
- [访问我们的官方网站探索更多回放示例。](https://deerflow.tech/#case-studies)
---
## 📑 目录
- [🚀 快速开始](#快速开始)
- [🌟 特性](#特性)
- [🏗️ 架构](#架构)
- [🛠️ 开发](#开发)
- [🗣️ 文本转语音集成](#文本转语音集成)
- [📚 示例](#示例)
- [❓ 常见问题](#常见问题)
- [📜 许可证](#许可证)
- [💖 致谢](#致谢)
- [⭐ Star History](#star-history)
## 快速开始
DeerFlow 使用 Python 开发,并配有用 Node.js 编写的 Web UI。为确保顺利的设置过程我们推荐使用以下工具
### 推荐工具
- **[`uv`](https://docs.astral.sh/uv/getting-started/installation/):**
简化 Python 环境和依赖管理。`uv`会自动在根目录创建虚拟环境并为您安装所有必需的包—无需手动安装 Python 环境。
- **[`nvm`](https://github.com/nvm-sh/nvm):**
轻松管理多个 Node.js 运行时版本。
- **[`pnpm`](https://pnpm.io/installation):**
安装和管理 Node.js 项目的依赖。
### 环境要求
确保您的系统满足以下最低要求:
- **[Python](https://www.python.org/downloads/):** 版本 `3.12+`
- **[Node.js](https://nodejs.org/en/download/):** 版本 `22+`
### 安装
```bash
# 克隆仓库
git clone https://github.com/bytedance/deer-flow.git
cd deer-flow
# 安装依赖uv将负责Python解释器和虚拟环境的创建并安装所需的包
uv sync
# 使用您的API密钥配置.env
# Tavily: https://app.tavily.com/home
# Brave_SEARCH: https://brave.com/search/api/
# 火山引擎TTS: 如果您有TTS凭证请添加
cp .env.example .env
# 查看下方的"支持的搜索引擎"和"文本转语音集成"部分了解所有可用选项
# 为您的LLM模型和API密钥配置conf.yaml
# 请参阅'docs/configuration_guide.md'获取更多详情
cp conf.yaml.example conf.yaml
# 安装marp用于PPT生成
# https://github.com/marp-team/marp-cli?tab=readme-ov-file#use-package-manager
brew install marp-cli
```
可选,通过[pnpm](https://pnpm.io/installation)安装 Web UI 依赖:
```bash
cd deer-flow/web
pnpm install
```
### 配置
请参阅[配置指南](docs/configuration_guide.md)获取更多详情。
> [! 注意]
> 在启动项目之前,请仔细阅读指南,并更新配置以匹配您的特定设置和要求。
### 控制台 UI
运行项目的最快方法是使用控制台 UI。
```bash
# 在类bash的shell中运行项目
uv run main.py
```
### Web UI
本项目还包括一个 Web UI提供更加动态和引人入胜的交互体验。
> [! 注意]
> 您需要先安装 Web UI 的依赖。
```bash
# 在开发模式下同时运行后端和前端服务器
# 在macOS/Linux上
./bootstrap.sh -d
# 在Windows上
bootstrap.bat -d
```
> [! 注意]
> 出于安全考虑,后端服务器默认绑定到 127.0.0.1 (localhost)。如果您需要允许外部连接例如在Linux服务器上部署时您可以修改启动脚本中的主机地址为 0.0.0.0。uv run server.py --host 0.0.0.0
> 请注意,在将服务暴露给外部网络之前,请务必确保您的环境已经过适当的安全加固。
打开浏览器并访问[`http://localhost:3000`](http://localhost:3000)探索 Web UI。
在[`web`](./web/)目录中探索更多详情。
## 支持的搜索引擎
### 公域搜索引擎
DeerFlow 支持多种搜索引擎,可以在`.env`文件中通过`SEARCH_API`变量进行配置:
- **Tavily**(默认):专为 AI 应用设计的专业搜索 API
- 需要在`.env`文件中设置`TAVILY_API_KEY`
- 注册地址:<https://app.tavily.com/home>
- **InfoQuest**推荐BytePlus自主研发的专为AI应用优化的智能搜索与爬取工具集
- 需要在`.env`文件中设置`INFOQUEST_API_KEY`
- 支持时间范围过滤和站点过滤
- 提供高质量的搜索结果和内容提取
- 注册地址:<https://console.byteplus.com/infoquest/infoquests>
- 访问 <https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest> 了解更多信息
- **DuckDuckGo**:注重隐私的搜索引擎
- 无需 API 密钥
- **Brave Search**:具有高级功能的注重隐私的搜索引擎
- 需要在`.env`文件中设置`BRAVE_SEARCH_API_KEY`
- 注册地址:<https://brave.com/search/api/>
- **Arxiv**:用于学术研究的科学论文搜索
- 无需 API 密钥
- 专为科学和学术论文设计
- **Searx/SearxNG**:自托管的元搜索引擎
- 需要在`.env`文件中设置`SEARX_HOST`
- 支持对接Searx或SearxNG
要配置您首选的搜索引擎,请在`.env`文件中设置`SEARCH_API`变量:
```bash
# 选择一个tavily, infoquest, duckduckgo, brave_search, arxiv
SEARCH_API=tavily
```
### 爬取工具
- **Jina**(默认):免费可访问的网页内容爬取工具
- 无需 API 密钥即可使用基础功能
- 使用 API 密钥可获得更高的访问速率限制
- 访问 <https://jina.ai/reader> 了解更多信息
- **InfoQuest**推荐BytePlus自主研发的专为AI应用优化的智能搜索与爬取工具集
- 需要在`.env`文件中设置`INFOQUEST_API_KEY`
- 提供可配置的爬取参数
- 支持自定义超时设置
- 提供更强大的内容提取能力
- 访问 <https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest> 了解更多信息
要配置您首选的爬取工具,请在`conf.yaml`文件中设置:
```yaml
CRAWLER_ENGINE:
# 引擎类型:"jina"(默认)或 "infoquest"
engine: infoquest
```
### 私域知识库引擎
DeerFlow 支持基于私有域知识的检索,您可以将文档上传到多种私有知识库中,以便在研究过程中使用,当前支持的私域知识库有:
- **[RAGFlow](https://ragflow.io/docs/dev/)**:开源的基于检索增强生成的知识库引擎
```
# 参照示例进行配置 .env.example
RAG_PROVIDER=ragflow
RAGFLOW_API_URL="http://localhost:9388"
RAGFLOW_API_KEY="ragflow-xxx"
RAGFLOW_RETRIEVAL_SIZE=10
```
- **[MOI]**AI 原生多模态数据智能平台
```
# 参照示例进行配置 .env.example
RAG_PROVIDER=moi
MOI_API_URL="https://freetier-01.cn-hangzhou.cluster.matrixonecloud.cn"
MOI_API_KEY="xxx-xxx-xxx-xxx"
MOI_RETRIEVAL_SIZE=10
MOI_LIST_LIMIT=10
```
- **[VikingDB 知识库](https://www.volcengine.com/docs/84313/1254457)**:火山引擎提供的公有云知识库引擎
> 注意先从 [火山引擎](https://www.volcengine.com/docs/84313/1254485) 获取账号 AK/SK
```
# 参照示例进行配置 .env.example
RAG_PROVIDER=vikingdb_knowledge_base
VIKINGDB_KNOWLEDGE_BASE_API_URL="api-knowledgebase.mlp.cn-beijing.volces.com"
VIKINGDB_KNOWLEDGE_BASE_API_AK="volcengine-ak-xxx"
VIKINGDB_KNOWLEDGE_BASE_API_SK="volcengine-sk-xxx"
VIKINGDB_KNOWLEDGE_BASE_RETRIEVAL_SIZE=15
```
## 特性
### 核心能力
- 🤖 **LLM 集成**
- 通过[litellm](https://docs.litellm.ai/docs/providers)支持集成大多数模型
- 支持开源模型如 Qwen
- 兼容 OpenAI 的 API 接口
- 多层 LLM 系统适用于不同复杂度的任务
### 工具和 MCP 集成
- 🔍 **搜索和检索**
- 通过 Tavily、InfoQuest、Brave Search 等进行网络搜索
- 使用 Jina、InfoQuest 进行爬取
- 高级内容提取
- 支持检索指定私有知识库
- 📃 **RAG 集成**
- 支持 [RAGFlow](https://github.com/infiniflow/ragflow) 知识库
- 支持 [VikingDB](https://www.volcengine.com/docs/84313/1254457) 火山知识库
- 🔗 **MCP 无缝集成**
- 扩展私有域访问、知识图谱、网页浏览等能力
- 促进多样化研究工具和方法的集成
### 人机协作
- 💬 **智能澄清功能**
- 多轮对话澄清模糊的研究主题
- 提高研究精准度和报告质量
- 减少无效搜索和 token 使用
- 可配置开关,灵活控制启用/禁用
- 详见 [配置指南 - 澄清功能](./docs/configuration_guide.md#multi-turn-clarification-feature)
- 🧠 **人在环中**
- 支持使用自然语言交互式修改研究计划
- 支持自动接受研究计划
- 📝 **报告后期编辑**
- 支持类 Notion 的块编辑
- 允许 AI 优化,包括 AI 辅助润色、句子缩短和扩展
- 由[tiptap](https://tiptap.dev/)提供支持
### 内容创作
- 🎙️ **播客和演示文稿生成**
- AI 驱动的播客脚本生成和音频合成
- 自动创建简单的 PowerPoint 演示文稿
- 可定制模板以满足个性化内容需求
## 架构
DeerFlow 实现了一个模块化的多智能体系统架构,专为自动化研究和代码分析而设计。该系统基于 LangGraph 构建,实现了灵活的基于状态的工作流,其中组件通过定义良好的消息传递系统进行通信。
![架构图](./assets/architecture.png)
> 在[deerflow.tech](https://deerflow.tech/#multi-agent-architecture)上查看实时演示
系统采用了精简的工作流程,包含以下组件:
1. **协调器**:管理工作流生命周期的入口点
- 根据用户输入启动研究过程
- 在适当时候将任务委派给规划器
- 作为用户和系统之间的主要接口
2. **规划器**:负责任务分解和规划的战略组件
- 分析研究目标并创建结构化执行计划
- 确定是否有足够的上下文或是否需要更多研究
- 管理研究流程并决定何时生成最终报告
3. **研究团队**:执行计划的专业智能体集合:
- **研究员**:使用网络搜索引擎、爬虫甚至 MCP 服务等工具进行网络搜索和信息收集。
- **编码员**:使用 Python REPL 工具处理代码分析、执行和技术任务。
每个智能体都可以访问针对其角色优化的特定工具,并在 LangGraph 框架内运行
4. **报告员**:研究输出的最终阶段处理器
- 汇总研究团队的发现
- 处理和组织收集的信息
- 生成全面的研究报告
## 文本转语音集成
DeerFlow 现在包含一个文本转语音 (TTS) 功能,允许您将研究报告转换为语音。此功能使用火山引擎 TTS API 生成高质量的文本音频。速度、音量和音调等特性也可以自定义。
### 使用 TTS API
您可以通过`/api/tts`端点访问 TTS 功能:
```bash
# 使用curl的API调用示例
curl --location 'http://localhost:8000/api/tts' \
--header 'Content-Type: application/json' \
--data '{
"text": "这是文本转语音功能的测试。",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
}' \
--output speech.mp3
```
## 开发
### 测试
运行测试套件:
```bash
# 运行所有测试
make test
# 运行特定测试文件
pytest tests/integration/test_workflow.py
# 运行覆盖率测试
make coverage
```
### 代码质量
```bash
# 运行代码检查
make lint
# 格式化代码
make format
```
### 使用 LangGraph Studio 进行调试
DeerFlow 使用 LangGraph 作为其工作流架构。您可以使用 LangGraph Studio 实时调试和可视化工作流。
#### 本地运行 LangGraph Studio
DeerFlow 包含一个`langgraph.json`配置文件,该文件定义了 LangGraph Studio 的图结构和依赖关系。该文件指向项目中定义的工作流图,并自动从`.env`文件加载环境变量。
##### Mac
```bash
# 如果您没有uv包管理器请安装它
curl -LsSf https://astral.sh/uv/install.sh | sh
# 安装依赖并启动LangGraph服务器
uvx --refresh --from "langgraph-cli[inmem]" --with-editable . --python 3.12 langgraph dev --allow-blocking
```
##### Windows / Linux
```bash
# 安装依赖
pip install -e .
pip install -U "langgraph-cli[inmem]"
# 启动LangGraph服务器
langgraph dev
```
启动 LangGraph 服务器后,您将在终端中看到几个 URL
- API: <http://127.0.0.1:2024>
- Studio UI: <https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024>
- API 文档:<http://127.0.0.1:2024/docs>
在浏览器中打开 Studio UI 链接以访问调试界面。
#### 使用 LangGraph Studio
在 Studio UI 中,您可以:
1. 可视化工作流图并查看组件如何连接
2. 实时跟踪执行情况,了解数据如何在系统中流动
3. 检查工作流每个步骤的状态
4. 通过检查每个组件的输入和输出来调试问题
5. 在规划阶段提供反馈以完善研究计划
当您在 Studio UI 中提交研究主题时,您将能够看到整个工作流执行过程,包括:
- 创建研究计划的规划阶段
- 可以修改计划的反馈循环
- 每个部分的研究和写作阶段
- 最终报告生成
### 启用 LangSmith 追踪
DeerFlow 支持 LangSmith 追踪功能,帮助您调试和监控工作流。要启用 LangSmith 追踪:
1. 确保您的 `.env` 文件中有以下配置(参见 `.env.example`
```bash
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY="xxx"
LANGSMITH_PROJECT="xxx"
```
2. 通过运行以下命令本地启动 LangSmith 追踪:
```bash
langgraph dev
```
这将在 LangGraph Studio 中启用追踪可视化,并将您的追踪发送到 LangSmith 进行监控和分析。
## Docker
您也可以使用 Docker 运行此项目。
首先,您需要阅读下面的[配置](#配置)部分。确保`.env`和`.conf.yaml`文件已准备就绪。
其次,构建您自己的 Web 服务器 Docker 镜像:
```bash
docker build -t deer-flow-api .
```
最后,启动运行 Web 服务器的 Docker 容器:
```bash
# 将deer-flow-api-app替换为您首选的容器名称
# 启动服务器并绑定到localhost:8000
docker run -d -t -p 127.0.0.1:8000:8000 --env-file .env --name deer-flow-api-app deer-flow-api
# 停止服务器
docker stop deer-flow-api-app
```
### Docker Compose
您也可以使用 docker compose 同时运行后端和前端。
#### 配置
构建前,先配置根目录的 `.env` 文件(从 `.env.example` 复制):
```bash
cp .env.example .env
cp conf.yaml.example conf.yaml
```
> [!IMPORTANT]
> `docker-compose.yml` 只使用**根目录的 `.env`** 文件(不使用 `web/.env`)。使用 Docker Compose 时,您**不需要**创建或修改 `web/.env`。
如果您在**远程服务器**上部署或通过**局域网 IP**(非 `localhost`)访问,**必须**将根目录 `.env` 中的 `NEXT_PUBLIC_API_URL` 修改为实际的主机 IP 或域名:
```bash
# 示例:通过局域网 IP 访问
NEXT_PUBLIC_API_URL=http://192.168.1.100:8000/api
# 示例:使用域名的远程部署
NEXT_PUBLIC_API_URL=https://your-domain.com/api
```
> [!NOTE]
> `NEXT_PUBLIC_API_URL` 是 Next.js 的**构建时**变量——它会在 `docker compose build` 时被嵌入到前端 JavaScript 包中。如果之后修改了此值,必须重新执行 `docker compose build` 才能生效。
#### 构建和运行
```bash
# 构建docker镜像
docker compose build
# 启动服务器
docker compose up
```
> [!WARNING]
> 如果您想将 DeerFlow 部署到生产环境中,请为网站添加身份验证,并评估 MCPServer 和 Python Repl 的安全检查。
## 文本转语音集成
DeerFlow 现在包含一个文本转语音 (TTS) 功能,允许您将研究报告转换为语音。此功能使用火山引擎 TTS API 生成高质量的文本音频。速度、音量和音调等特性也可以自定义。
### 使用 TTS API
您可以通过`/api/tts`端点访问 TTS 功能:
```bash
# 使用curl的API调用示例
curl --location 'http://localhost:8000/api/tts' \
--header 'Content-Type: application/json' \
--data '{
"text": "这是文本转语音功能的测试。",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0
}' \
--output speech.mp3
```
## 示例
以下示例展示了 DeerFlow 的功能:
### 研究报告
1. **OpenAI Sora 报告** - OpenAI 的 Sora AI 工具分析
- 讨论功能、访问方式、提示工程、限制和伦理考虑
- [查看完整报告](examples/openai_sora_report.md)
2. **Google 的 Agent to Agent 协议报告** - Google 的 Agent to Agent (A2A) 协议概述
- 讨论其在 AI 智能体通信中的作用及其与 Anthropic 的 Model Context Protocol (MCP) 的关系
- [查看完整报告](examples/what_is_agent_to_agent_protocol.md)
3. **什么是 MCP** - 对"MCP"一词在多个上下文中的全面分析
- 探讨 AI 中的 Model Context Protocol、化学中的 Monocalcium Phosphate 和电子学中的 Micro-channel Plate
- [查看完整报告](examples/what_is_mcp.md)
4. **比特币价格波动** - 最近比特币价格走势分析
- 研究市场趋势、监管影响和技术指标
- 基于历史数据提供建议
- [查看完整报告](examples/bitcoin_price_fluctuation.md)
5. **什么是 LLM** - 对大型语言模型的深入探索
- 讨论架构、训练、应用和伦理考虑
- [查看完整报告](examples/what_is_llm.md)
6. **如何使用 Claude 进行深度研究?** - 在深度研究中使用 Claude 的最佳实践和工作流程
- 涵盖提示工程、数据分析和与其他工具的集成
- [查看完整报告](examples/how_to_use_claude_deep_research.md)
7. **医疗保健中的 AI 采用:影响因素** - 影响医疗保健中 AI 采用的因素分析
- 讨论 AI 技术、数据质量、伦理考虑、经济评估、组织准备度和数字基础设施
- [查看完整报告](examples/AI_adoption_in_healthcare.md)
8. **量子计算对密码学的影响** - 量子计算对密码学影响的分析
- 讨论经典密码学的漏洞、后量子密码学和抗量子密码解决方案
- [查看完整报告](examples/Quantum_Computing_Impact_on_Cryptography.md)
9. **克里斯蒂亚诺·罗纳尔多的表现亮点** - 克里斯蒂亚诺·罗纳尔多表现亮点的分析
- 讨论他的职业成就、国际进球和在各种比赛中的表现
- [查看完整报告](examples/Cristiano_Ronaldo's_Performance_Highlights.md)
要运行这些示例或创建您自己的研究报告,您可以使用以下命令:
```bash
# 使用特定查询运行
uv run main.py "哪些因素正在影响医疗保健中的AI采用"
# 使用自定义规划参数运行
uv run main.py --max_plan_iterations 3 "量子计算如何影响密码学?"
# 在交互模式下运行,带有内置问题
uv run main.py --interactive
# 或者使用基本交互提示运行
uv run main.py
# 查看所有可用选项
uv run main.py --help
```
### 交互模式
应用程序现在支持带有英文和中文内置问题的交互模式:
1. 启动交互模式:
```bash
uv run main.py --interactive
```
2. 选择您偏好的语言English 或中文)
3. 从内置问题列表中选择或选择提出您自己问题的选项
4. 系统将处理您的问题并生成全面的研究报告
### 人在环中
DeerFlow 包含一个人在环中机制,允许您在执行研究计划前审查、编辑和批准:
1. **计划审查**:启用人在环中时,系统将在执行前向您展示生成的研究计划
2. **提供反馈**:您可以:
- 通过回复`[ACCEPTED]`接受计划
- 通过提供反馈编辑计划(例如,`[EDIT PLAN] 添加更多关于技术实现的步骤`
- 系统将整合您的反馈并生成修订后的计划
3. **自动接受**:您可以启用自动接受以跳过审查过程:
- 通过 API在请求中设置`auto_accepted_plan: true`
4. **API 集成**:使用 API 时,您可以通过`feedback`参数提供反馈:
```json
{
"messages": [{ "role": "user", "content": "什么是量子计算?" }],
"thread_id": "my_thread_id",
"auto_accepted_plan": false,
"feedback": "[EDIT PLAN] 包含更多关于量子算法的内容"
}
```
### 命令行参数
应用程序支持多个命令行参数来自定义其行为:
- **query**:要处理的研究查询(可以是多个词)
- **--interactive**:以交互模式运行,带有内置问题
- **--max_plan_iterations**最大规划周期数默认1
- **--max_step_num**研究计划中的最大步骤数默认3
- **--debug**:启用详细调试日志
## 常见问题
请参阅[FAQ.md](docs/FAQ.md)获取更多详情。
## 许可证
本项目是开源的,遵循[MIT 许可证](./LICENSE)。
## 致谢
DeerFlow 建立在开源社区的杰出工作基础之上。我们深深感谢所有使 DeerFlow 成为可能的项目和贡献者。诚然,我们站在巨人的肩膀上。
我们要向以下项目表达诚挚的感谢,感谢他们的宝贵贡献:
- **[LangChain](https://github.com/langchain-ai/langchain)**:他们卓越的框架为我们的 LLM 交互和链提供动力,实现了无缝集成和功能。
- **[LangGraph](https://github.com/langchain-ai/langgraph)**:他们在多智能体编排方面的创新方法对于实现 DeerFlow 复杂工作流至关重要。
这些项目展示了开源协作的变革力量,我们很自豪能够在他们的基础上构建。
### 核心贡献者
衷心感谢`DeerFlow`的核心作者,他们的愿景、热情和奉献使这个项目得以实现:
- **[Daniel Walnut](https://github.com/hetaoBackend/)**
- **[Henry Li](https://github.com/magiccube/)**
您坚定不移的承诺和专业知识是 DeerFlow 成功的驱动力。我们很荣幸有您引领这一旅程。
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=bytedance/deer-flow&type=Date)](https://star-history.com/#bytedance/deer-flow&Date)

View File

@@ -1,9 +0,0 @@
# Security Policy
## Supported Versions
As deer-flow doesn't provide an offical release yet, please use the latest version for the security updates.
## Reporting a Vulnerability
Please go to https://github.com/bytedance/deer-flow/security to report the vulnerability you find.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

View File

@@ -1,28 +0,0 @@
@echo off
SETLOCAL ENABLEEXTENSIONS
REM Check if argument is dev mode
SET MODE=%1
IF "%MODE%"=="--dev" GOTO DEV
IF "%MODE%"=="-d" GOTO DEV
IF "%MODE%"=="dev" GOTO DEV
IF "%MODE%"=="development" GOTO DEV
:PROD
echo Starting DeerFlow in [PRODUCTION] mode...
start uv run server.py
cd web
start pnpm start
REM Wait for user to close
GOTO END
:DEV
echo Starting DeerFlow in [DEVELOPMENT] mode...
start uv run server.py --reload
cd web
start pnpm dev
REM Wait for user to close
pause
:END
ENDLOCAL

View File

@@ -1,18 +0,0 @@
#!/bin/bash
# Start both of DeerFlow's backend and web UI server.
# If the user presses Ctrl+C, kill them both.
if [ "$1" = "--dev" -o "$1" = "-d" -o "$1" = "dev" -o "$1" = "development" ]; then
echo -e "Starting DeerFlow in [DEVELOPMENT] mode...\n"
uv run server.py --reload & SERVER_PID=$$!
cd web && pnpm dev & WEB_PID=$$!
trap "kill $$SERVER_PID $$WEB_PID" SIGINT SIGTERM
wait
else
echo -e "Starting DeerFlow in [PRODUCTION] mode...\n"
uv run server.py & SERVER_PID=$$!
cd web && pnpm start & WEB_PID=$$!
trap "kill $$SERVER_PID $$WEB_PID" SIGINT SIGTERM
wait
fi

View File

@@ -1,127 +0,0 @@
# [!NOTE]
# Read the `docs/configuration_guide.md` carefully, and update the
# configurations to match your specific settings and requirements.
# - Replace `api_key` with your own credentials.
# - Replace `base_url` and `model` name if you want to use a custom model.
# - Set `verify_ssl` to `false` if your LLM server uses self-signed certificates
# - A restart is required every time you change the `conf.yaml` file.
BASIC_MODEL:
base_url: https://ark.cn-beijing.volces.com/api/v3
model: "doubao-1-5-pro-32k-250115"
api_key: xxxx
# max_retries: 3 # Maximum number of retries for LLM calls
# verify_ssl: false # Uncomment this line to disable SSL certificate verification for self-signed certificates
# token_limit: 200000 # Maximum input tokens for context compression (prevents token overflow errors)
# Local model configuration example:
# Ollama (Tested and supported for local development)
# BASIC_MODEL:
# base_url: "http://localhost:11434/v1" # Ollama OpenAI compatible endpoint
# model: "qwen3:14b" # or "llama3.2", etc.
# api_key: "ollama" # Ollama doesn't need real API key
# max_retries: 3
# verify_ssl: false # Local deployment usually doesn't need SSL verification
# To use Google Ai Studio as your basic platform:
# BASIC_MODEL:
# platform: "google_aistudio"
# model: "gemini-2.5-flash" # or "gemini-1.5-pro", "gemini-2.5-flash-exp", etc.
# api_key: your_gemini_api_key # Get from https://aistudio.google.com/app/apikey
# max_retries: 3
# Reasoning model is optional.
# Uncomment the following settings if you want to use reasoning model
# for planning.
# REASONING_MODEL:
# base_url: https://ark.cn-beijing.volces.com/api/v3
# model: "doubao-1-5-thinking-pro-m-250428"
# api_key: xxxx
# max_retries: 3 # Maximum number of retries for LLM calls
# token_limit: 150000 # Maximum input tokens for context compression
# OTHER SETTINGS:
# Tool-specific interrupts configuration (Issue #572)
# Allows interrupting execution before specific tools are called.
# Useful for reviewing sensitive operations like database queries or API calls.
# Note: This can be overridden per-request via the API.
# TOOL_INTERRUPTS:
# # List of tool names to interrupt before execution
# # Example: interrupt before database tools or sensitive API calls
# interrupt_before:
# - "db_tool" # Database operations
# - "db_read_tool" # Database reads
# - "db_write_tool" # Database writes
# - "payment_api" # Payment-related API calls
# - "admin_api" # Administrative API calls
# # When interrupt is triggered, user will be prompted to approve/reject
# # Approved keywords: "approved", "approve", "yes", "proceed", "continue", "ok", "okay", "accepted", "accept"
# Web search toggle (Issue #681)
# Set to false to disable web search and use only local RAG knowledge base.
# This is useful for environments without internet access.
# WARNING: If you disable web search, make sure to configure local RAG resources;
# otherwise, the researcher will operate in pure LLM reasoning mode without external data.
# Note: This can be overridden per-request via the API parameter `enable_web_search`.
# ENABLE_WEB_SEARCH: true
# Search engine configuration
# Supported engines: tavily, infoquest
# SEARCH_ENGINE:
# # Engine type to use: "tavily" or "infoquest"
# engine: tavily or infoquest
#
# # The following parameters are specific to Tavily
# # Only include results from these domains
# include_domains:
# - example.com
# - trusted-news.com
# - reliable-source.org
# - gov.cn
# - edu.cn
# # Exclude results from these domains
# exclude_domains:
# - example.com
# # Include an answer in the search results
# include_answer: false
# # Search depth: "basic" or "advanced"
# search_depth: "advanced"
# # Include raw content from pages
# include_raw_content: true
# # Include images in search results
# include_images: true
# # Include descriptions for images
# include_image_descriptions: true
# # Minimum score threshold for results (0-1)
# min_score_threshold: 0.0
# # Maximum content length per page
# max_content_length_per_page: 4000
#
# # The following parameters are specific to InfoQuest
# # Used to limit the scope of search results, only returns content within the specified time range. Set to -1 to disable time filtering
# time_range: 30
# # Used to limit the scope of search results, only returns content from specified whitelisted domains. Set to empty string to disable site filtering
# site: "example.com"
# Crawler engine configuration
# Supported engines: jina (default), infoquest
# Uncomment the following section to configure crawler engine
# CRAWLER_ENGINE:
# # Engine type to use: "jina" (default) or "infoquest"
# engine: infoquest
#
# # The following timeout parameters are only effective when engine is set to "infoquest"
# # Waiting time after page loading (in seconds)
# # Set to positive value to enable, -1 to disable
# fetch_time: 10
# # Overall timeout for the entire crawling process (in seconds)
# # Set to positive value to enable, -1 to disable
# timeout: 30
# # Timeout for navigating to the page (in seconds)
# # Set to positive value to enable, -1 to disable
# navi_timeout: 15

View File

@@ -1,35 +0,0 @@
services:
backend:
build:
context: .
dockerfile: Dockerfile
container_name: deer-flow-backend
# Remove the ports section to not expose to host
env_file:
- .env
volumes:
- ./conf.yaml:/app/conf.yaml:ro
restart: unless-stopped
networks:
- deer-flow-network
frontend:
build:
context: ./web
dockerfile: Dockerfile
args:
- NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
container_name: deer-flow-frontend
ports:
- "3000:3000"
env_file:
- .env
depends_on:
- backend
restart: unless-stopped
networks:
- deer-flow-network
networks:
deer-flow-network:
driver: bridge

View File

@@ -1,552 +0,0 @@
# DeerFlow API Documentation
## Overview
DeerFlow API is a comprehensive backend service for advanced research and content generation. It provides endpoints for chat-based research, text-to-speech conversion, content generation (podcasts, presentations, prose), prompt enhancement, and RAG (Retrieval-Augmented Generation) functionality.
**API Version:** 0.1.0
**Base URL:** `http://localhost:8000`
---
## Authentication
Currently, the API does not require authentication. CORS is configured with origins defined by the `ALLOWED_ORIGINS` environment variable (default: `http://localhost:3000`).
---
## API Endpoints
### Chat & Research
#### `POST /api/chat/stream`
Initiates a streaming chat session with the research agent. Returns Server-Sent Events (SSE) with message chunks, tool calls, and intermediate results.
**Request Body:**
```json
{
"messages": [
{
"role": "user",
"content": "What is quantum computing?"
}
],
"thread_id": "__default__",
"max_plan_iterations": 1,
"max_step_num": 3,
"max_search_results": 3,
"auto_accepted_plan": false,
"report_style": "ACADEMIC",
"enable_background_investigation": true,
"enable_deep_thinking": false,
"enable_clarification": false
}
```
**Query Parameters:**
- `messages` (required, array[ChatMessage]): History of messages between user and assistant
- `resources` (optional, array[Resource]): Resources for the research
- `thread_id` (optional, string, default: `"__default__"`): Conversation identifier
- `max_plan_iterations` (optional, integer, default: 1): Maximum number of plan iterations
- `max_step_num` (optional, integer, default: 3): Maximum number of steps in a plan
- `max_search_results` (optional, integer, default: 3): Maximum number of search results
- `auto_accepted_plan` (optional, boolean, default: false): Automatically accept the plan
- `interrupt_feedback` (optional, string): User feedback on the plan
- `mcp_settings` (optional, object): MCP settings (requires `ENABLE_MCP_SERVER_CONFIGURATION=true`)
- `enable_background_investigation` (optional, boolean, default: true): Get background investigation before plan
- `report_style` (optional, enum): Style of the report - `ACADEMIC`, `POPULAR_SCIENCE`, `NEWS`, `SOCIAL_MEDIA`, `STRATEGIC_INVESTMENT`
- `enable_deep_thinking` (optional, boolean, default: false): Enable deep thinking
- `enable_clarification` (optional, boolean): Enable multi-turn clarification
- `max_clarification_rounds` (optional, integer): Maximum clarification rounds
**Response:**
- Content-Type: `text/event-stream`
- Server-sent events with various message types:
- `message_chunk`: Raw message tokens
- `tool_calls`: Tool invocations
- `tool_call_chunks`: Partial tool call data
- `tool_call_result`: Result of a tool call
- `interrupt`: Plan interruption for user feedback
- `error`: Error messages
**Example Response (Server-Sent Events):**
```
event: message_chunk
data: {"thread_id":"abc123","agent":"researcher","role":"assistant","content":"I'll search for information about quantum computing..."}
event: tool_calls
data: {"thread_id":"abc123","agent":"researcher","tool_calls":[{"name":"web_search","args":"{\"query\":\"quantum computing\"}"}]}
event: tool_call_result
data: {"thread_id":"abc123","agent":"researcher","content":"Found 10 results about quantum computing"}
```
**Error Responses:**
- `403`: MCP server configuration is disabled
- `500`: Internal server error during graph execution
---
### Text-to-Speech
#### `POST /api/tts`
Converts text to speech using Volcengine TTS API.
**Requirements:**
- Environment variables must be set:
- `VOLCENGINE_TTS_APPID`
- `VOLCENGINE_TTS_ACCESS_TOKEN`
**Request Body:**
```json
{
"text": "Hello, this is a test",
"encoding": "mp3",
"voice_type": "BV700_V2_streaming",
"speed_ratio": 1.0,
"volume_ratio": 1.0,
"pitch_ratio": 1.0,
"text_type": "plain",
"with_frontend": 1,
"frontend_type": "unitTson"
}
```
**Parameters:**
- `text` (required, string, max 1024 chars): Text to convert to speech
- `encoding` (optional, string, default: `"mp3"`): Audio format - `mp3`, `wav`
- `voice_type` (optional, string, default: `"BV700_V2_streaming"`): Voice type
- `speed_ratio` (optional, float, default: 1.0): Speech speed ratio
- `volume_ratio` (optional, float, default: 1.0): Speech volume ratio
- `pitch_ratio` (optional, float, default: 1.0): Speech pitch ratio
- `text_type` (optional, string, default: `"plain"`): `plain` or `ssml`
- `with_frontend` (optional, integer, default: 1): Enable frontend processing
- `frontend_type` (optional, string, default: `"unitTson"`): Frontend type
**Response:**
- Content-Type: `audio/mp3` or `audio/wav` (depends on encoding)
- Binary audio data
- Header: `Content-Disposition: attachment; filename=tts_output.{encoding}`
**Error Responses:**
- `400`: Missing required environment variables
- `500`: Internal server error during TTS processing
---
### Content Generation
#### `POST /api/podcast/generate`
Generates an audio podcast from provided text content.
**Request Body:**
```json
{
"content": "# Podcast Content\nThis is the content of the podcast..."
}
```
**Parameters:**
- `content` (required, string): Podcast content in text format
**Response:**
- Content-Type: `audio/mp3`
- Binary audio data
**Error Responses:**
- `500`: Error during podcast generation
---
#### `POST /api/ppt/generate`
Generates a PowerPoint presentation from provided content.
**Request Body:**
```json
{
"content": "# Presentation Title\n## Slide 1\nContent here..."
}
```
**Parameters:**
- `content` (required, string): Content for the presentation
**Response:**
- Content-Type: `application/vnd.openxmlformats-officedocument.presentationml.presentation`
- Binary PowerPoint file (.pptx)
- Header: `Content-Disposition: attachment; filename=output.pptx`
**Error Responses:**
- `500`: Error during PPT generation
---
#### `POST /api/prose/generate`
Generates prose content with streaming output based on prompt and option.
**Request Body:**
```json
{
"prompt": "Write a creative story about",
"option": "story",
"command": "make it exciting"
}
```
**Parameters:**
- `prompt` (required, string): Content/prompt for prose generation
- `option` (required, string): Prose writing option
- `command` (optional, string, default: `""`): User custom command
**Response:**
- Content-Type: `text/event-stream`
- Server-sent events with prose content chunks
**Example Response:**
```
data: "Once upon a time, there was..."
data: " a mysterious kingdom..."
```
**Error Responses:**
- `500`: Error during prose generation
---
### Prompt Enhancement
#### `POST /api/prompt/enhance`
Enhances and refines user prompts with specified report style and context.
**Request Body:**
```json
{
"prompt": "Tell me about climate change",
"context": "For a scientific audience",
"report_style": "ACADEMIC"
}
```
**Parameters:**
- `prompt` (required, string): Original prompt to enhance
- `context` (optional, string, default: `""`): Additional context about intended use
- `report_style` (optional, string, default: `"academic"`): Style - `academic`, `popular_science`, `news`, `social_media`, `strategic_investment`
**Response:**
```json
{
"result": "Enhanced and refined prompt here..."
}
```
**Error Responses:**
- `500`: Error during prompt enhancement
---
### MCP Integration
#### `POST /api/mcp/server/metadata`
Retrieves metadata and available tools from a Model Context Protocol (MCP) server.
**Requirements:**
- Environment variable: `ENABLE_MCP_SERVER_CONFIGURATION=true`
**Request Body - For stdio transport:**
```json
{
"transport": "stdio",
"command": "python",
"args": ["-m", "mcp_server"],
"env": {
"VAR_NAME": "value"
},
"timeout_seconds": 300
}
```
**Request Body - For SSE transport:**
```json
{
"transport": "sse",
"url": "https://mcp-server.example.com",
"headers": {
"Authorization": "Bearer token"
}
}
```
**Parameters:**
- `transport` (required, string): `stdio`, `sse`, or `streamable_http`
- `command` (optional, string): Command to execute (stdio type)
- `args` (optional, array[string]): Command arguments (stdio type)
- `url` (optional, string): Server URL (sse/streamable_http type)
- `env` (optional, object): Environment variables (stdio type)
- `headers` (optional, object): HTTP headers (sse/streamable_http type)
- `timeout_seconds` (optional, integer): Custom timeout in seconds (default: 300)
**Response:**
```json
{
"transport": "stdio",
"command": "python",
"args": ["-m", "mcp_server"],
"tools": [
{
"name": "tool_1",
"description": "Description of tool",
"parameters": {}
}
]
}
```
**Error Responses:**
- `403`: MCP server configuration is disabled
- `500`: Error retrieving MCP server metadata
---
### RAG Configuration
#### `GET /api/rag/config`
Returns the current RAG (Retrieval-Augmented Generation) provider configuration.
**Response:**
```json
{
"provider": "ragflow"
}
```
**Error Responses:**
- None (always returns 200)
---
#### `GET /api/rag/resources`
Retrieves available resources from the RAG system based on optional query.
**Query Parameters:**
- `query` (optional, string): Search query for resources
**Response:**
```json
{
"resources": [
{
"id": "resource_1",
"name": "Document",
"type": "pdf"
}
]
}
```
**Error Responses:**
- None (returns empty resources array if retriever not configured)
---
### Server Configuration
#### `GET /api/config`
Returns the complete server configuration including RAG settings and available models.
**Response:**
```json
{
"rag": {
"provider": "ragflow"
},
"models": {
"llm": ["gpt-4", "gpt-3.5-turbo"],
"embedding": ["openai-embedding"]
}
}
```
**Error Responses:**
- None (always returns 200)
---
## Data Structures
### ChatMessage
```json
{
"role": "user or assistant",
"content": "string or array of ContentItem"
}
```
### ContentItem
```json
{
"type": "text or image",
"text": "string (for text type)",
"image_url": "string (for image type)"
}
```
### ReportStyle Enum
- `ACADEMIC`
- `POPULAR_SCIENCE`
- `NEWS`
- `SOCIAL_MEDIA`
- `STRATEGIC_INVESTMENT`
---
## Error Handling
All endpoints follow standard HTTP status codes:
| Status | Meaning |
|--------|---------|
| 200 | Success |
| 400 | Bad Request - Invalid parameters |
| 403 | Forbidden - Feature disabled or unauthorized |
| 500 | Internal Server Error |
Error response format:
```json
{
"detail": "Error message describing what went wrong"
}
```
---
## Streaming Responses
Several endpoints return streaming responses using Server-Sent Events (SSE):
- `/api/chat/stream` - Chat streaming
- `/api/prose/generate` - Prose generation streaming
To consume SSE in your client:
```javascript
const eventSource = new EventSource('/api/chat/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({...})
});
eventSource.addEventListener('message_chunk', (event) => {
console.log(event.data);
});
```
---
## Rate Limiting & Quotas
Currently no rate limiting is implemented. The system respects the following limits:
- TTS text input: max 1024 characters
- Search results: configurable via `max_search_results`
- Plan iterations: configurable via `max_plan_iterations`
---
## Environment Variables
Key environment variables for API configuration:
```bash
# CORS
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
# TTS
VOLCENGINE_TTS_APPID=your_app_id
VOLCENGINE_TTS_ACCESS_TOKEN=your_access_token
VOLCENGINE_TTS_CLUSTER=volcano_tts
VOLCENGINE_TTS_VOICE_TYPE=BV700_V2_streaming
# MCP
ENABLE_MCP_SERVER_CONFIGURATION=false
# Checkpointing
LANGGRAPH_CHECKPOINT_SAVER=false
LANGGRAPH_CHECKPOINT_DB_URL=postgresql://user:pass@localhost/db
# RAG
RAG_PROVIDER=ragflow
```
---
## Examples
### Example 1: Chat with Research
```bash
curl -X POST http://localhost:8000/api/chat/stream \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "user", "content": "What are the latest AI trends?"}],
"thread_id": "conversation_1",
"max_search_results": 5,
"report_style": "POPULAR_SCIENCE"
}'
```
### Example 2: Text-to-Speech
```bash
curl -X POST http://localhost:8000/api/tts \
-H "Content-Type: application/json" \
-d '{
"text": "Hello world",
"encoding": "mp3",
"speed_ratio": 1.2
}' \
--output audio.mp3
```
### Example 3: Enhance Prompt
```bash
curl -X POST http://localhost:8000/api/prompt/enhance \
-H "Content-Type: application/json" \
-d '{
"prompt": "Tell me about space",
"context": "For kids aged 8-10",
"report_style": "POPULAR_SCIENCE"
}'
```
### Example 4: Get Server Configuration
```bash
curl -X GET http://localhost:8000/api/config
```
---
## Changelog
### Version 0.1.0
- Initial API release
- Chat streaming with research capabilities
- Text-to-speech conversion
- Content generation (podcasts, presentations, prose)
- Prompt enhancement
- MCP server integration
- RAG configuration and resources
---
## Support
For issues or questions about the API, please refer to the project documentation or file an issue in the repository.

View File

@@ -1,317 +0,0 @@
# Debugging Guide
This guide helps you debug DeerFlow workflows, view model outputs, and troubleshoot common issues.
## Table of Contents
- [Viewing Model Output](#viewing-model-output)
- [Debug Logging Configuration](#debug-logging-configuration)
- [LangChain Verbose Logging](#langchain-verbose-logging)
- [LangSmith Tracing](#langsmith-tracing)
- [Docker Compose Debugging](#docker-compose-debugging)
- [Common Issues](#common-issues)
## Viewing Model Output
When you need to see the complete model output, including tool calls and internal reasoning, you have several options:
### 1. Enable Debug Logging
Set `DEBUG=True` in your `.env` file or configuration:
```bash
DEBUG=True
```
This enables debug-level logging throughout the application, showing detailed information about:
- System prompts sent to LLMs
- Model responses
- Tool calls and results
- Workflow state transitions
### 2. Enable LangChain Verbose Logging
Add these environment variables to your `.env` file for detailed LangChain output:
```bash
# Enable verbose logging for LangChain
LANGCHAIN_VERBOSE=true
LANGCHAIN_DEBUG=true
```
This will show:
- Chain execution steps
- LLM input/output for each call
- Tool invocations
- Intermediate results
### 3. Enable LangSmith Tracing (Recommended for Production)
For advanced debugging and visualization, configure LangSmith integration:
```bash
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY="your-api-key"
LANGSMITH_PROJECT="your-project-name"
```
LangSmith provides:
- Visual trace of workflow execution
- Performance metrics
- Token usage statistics
- Error tracking
- Comparison between runs
To get started with LangSmith:
1. Sign up at [LangSmith](https://smith.langchain.com/)
2. Create a project
3. Copy your API key
4. Add the configuration to your `.env` file
## Debug Logging Configuration
### Log Levels
DeerFlow uses Python's standard logging levels:
- **DEBUG**: Detailed diagnostic information
- **INFO**: General informational messages
- **WARNING**: Warning messages
- **ERROR**: Error messages
- **CRITICAL**: Critical errors
### Viewing Logs
**Development mode (console):**
```bash
uv run main.py
```
Logs will be printed to the console.
**Docker Compose:**
```bash
# View logs from all services
docker compose logs -f
# View logs from backend only
docker compose logs -f backend
# View logs with timestamps
docker compose logs -f --timestamps
```
## LangChain Verbose Logging
### What It Shows
When `LANGCHAIN_VERBOSE=true` is enabled, you'll see output like:
```
> Entering new AgentExecutor chain...
Thought: I need to search for information about quantum computing
Action: web_search
Action Input: "quantum computing basics 2024"
Observation: [Search results...]
Thought: I now have enough information to answer
Final Answer: ...
```
### Configuration Options
```bash
# Basic verbose mode
LANGCHAIN_VERBOSE=true
# Full debug mode with internal details
LANGCHAIN_DEBUG=true
# Both (recommended for debugging)
LANGCHAIN_VERBOSE=true
LANGCHAIN_DEBUG=true
```
## LangSmith Tracing
### Setup
1. **Create a LangSmith account**: Visit [smith.langchain.com](https://smith.langchain.com)
2. **Get your API key**: Navigate to Settings → API Keys
3. **Configure environment variables**:
```bash
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY="lsv2_pt_..."
LANGSMITH_PROJECT="deerflow-debug"
```
4. **Restart your application**
### Features
- **Visual traces**: See the entire workflow execution as a graph
- **Performance metrics**: Identify slow operations
- **Token tracking**: Monitor LLM token usage
- **Error analysis**: Quickly identify failures
- **Comparison**: Compare different runs side-by-side
### Viewing Traces
1. Run your workflow as normal
2. Visit [smith.langchain.com](https://smith.langchain.com)
3. Select your project
4. View traces in the "Traces" tab
## Docker Compose Debugging
### Update docker-compose.yml
Add debug environment variables to your `docker-compose.yml`:
```yaml
services:
backend:
build:
context: .
dockerfile: Dockerfile
environment:
# Debug settings
- DEBUG=True
- LANGCHAIN_VERBOSE=true
- LANGCHAIN_DEBUG=true
# LangSmith (optional)
- LANGSMITH_TRACING=true
- LANGSMITH_ENDPOINT=https://api.smith.langchain.com
- LANGSMITH_API_KEY=${LANGSMITH_API_KEY}
- LANGSMITH_PROJECT=${LANGSMITH_PROJECT}
```
### View Detailed Logs
```bash
# Start with verbose output
docker compose up
# Or in detached mode and follow logs
docker compose up -d
docker compose logs -f backend
```
### Common Docker Commands
```bash
# View logs from last 100 lines
docker compose logs --tail=100 backend
# View logs with timestamps
docker compose logs -f --timestamps
# Check container status
docker compose ps
# Restart services
docker compose restart backend
```
## Common Issues
### Issue: "Log information doesn't show complete content"
**Solution**: Enable debug logging as described above:
```bash
DEBUG=True
LANGCHAIN_VERBOSE=true
LANGCHAIN_DEBUG=true
```
### Issue: "Can't see system prompts"
**Solution**: Debug logging will show system prompts. Look for log entries like:
```
[INFO] System Prompt:
You are DeerFlow, a friendly AI assistant...
```
### Issue: "Want to see token usage"
**Solution**: Enable LangSmith tracing or check model responses in verbose mode:
```bash
LANGCHAIN_VERBOSE=true
```
### Issue: "Need to debug specific nodes"
**Solution**: Add custom logging in specific nodes. For example, in `src/graph/nodes.py`:
```python
import logging
logger = logging.getLogger(__name__)
def my_node(state, config):
logger.debug(f"Node input: {state}")
# ... your code ...
logger.debug(f"Node output: {result}")
return result
```
### Issue: "Logs are too verbose"
**Solution**: Adjust log level for specific modules:
```python
# In your code
logging.getLogger('langchain').setLevel(logging.WARNING)
logging.getLogger('openai').setLevel(logging.WARNING)
```
## Performance Debugging
### Measure Execution Time
Enable LangSmith or add timing logs:
```python
import time
start = time.time()
result = some_function()
logger.info(f"Execution time: {time.time() - start:.2f}s")
```
### Monitor Token Usage
With LangSmith enabled, token usage is automatically tracked. Alternatively, check model responses:
```bash
LANGCHAIN_VERBOSE=true
```
Look for output like:
```
Tokens Used: 150
Prompt Tokens: 100
Completion Tokens: 50
```
## Additional Resources
- [LangSmith Documentation](https://docs.smith.langchain.com/)
- [LangGraph Debugging](https://langchain-ai.github.io/langgraph/how-tos/debugging/)
- [Configuration Guide](./configuration_guide.md)
- [API Documentation](./API.md)
## Getting Help
If you're still experiencing issues:
1. Check existing [GitHub Issues](https://github.com/bytedance/deer-flow/issues)
2. Enable debug logging and LangSmith tracing
3. Collect relevant log output
4. Create a new issue with:
- Description of the problem
- Steps to reproduce
- Log output
- Configuration (without sensitive data)

View File

@@ -1,94 +0,0 @@
# FAQ
## Table of Contents
- [Where's the name DeerFlow come from?](#wheres-the-name-deerflow-come-from)
- [Which models does DeerFlow support?](#which-models-does-deerflow-support)
- [How do I view complete model output?](#how-do-i-view-complete-model-output)
- [How do I enable debug logging?](#how-do-i-enable-debug-logging)
- [How do I troubleshoot issues?](#how-do-i-troubleshoot-issues)
## Where's the name DeerFlow come from?
DeerFlow is short for **D**eep **E**xploration and **E**fficient **R**esearch **Flow**. It is named after the deer, which is a symbol of gentleness and elegance. We hope DeerFlow can bring a gentle and elegant deep research experience to you.
## Which models does DeerFlow support?
Please refer to the [Configuration Guide](configuration_guide.md) for more details.
## How do I view complete model output?
If you want to see the complete model output, including system prompts, tool calls, and LLM responses:
1. **Enable debug logging** by setting `DEBUG=True` in your `.env` file
2. **Enable LangChain verbose logging** by adding these to your `.env`:
```bash
LANGCHAIN_VERBOSE=true
LANGCHAIN_DEBUG=true
```
3. **Use LangSmith tracing** for visual debugging (recommended for production):
```bash
LANGSMITH_TRACING=true
LANGSMITH_API_KEY="your-api-key"
LANGSMITH_PROJECT="your-project-name"
```
For detailed instructions, see the [Debugging Guide](DEBUGGING.md).
## How do I enable debug logging?
To enable debug logging:
1. Open your `.env` file
2. Set `DEBUG=True`
3. Restart your application
For Docker Compose:
```bash
docker compose restart
```
For development:
```bash
uv run main.py
```
You'll now see detailed logs including:
- System prompts sent to LLMs
- Model responses
- Tool execution details
- Workflow state transitions
See the [Debugging Guide](DEBUGGING.md) for more options.
## How do I troubleshoot issues?
When encountering issues:
1. **Check the logs**: Enable debug logging as described above
2. **Review configuration**: Ensure your `.env` and `conf.yaml` are correct
3. **Check existing issues**: Search [GitHub Issues](https://github.com/bytedance/deer-flow/issues) for similar problems
4. **Enable verbose logging**: Use `LANGCHAIN_VERBOSE=true` for detailed output
5. **Use LangSmith**: For visual debugging, enable LangSmith tracing
For Docker-specific issues:
```bash
# View logs
docker compose logs -f
# Check container status
docker compose ps
# Restart services
docker compose restart
```
For more detailed troubleshooting steps, see the [Debugging Guide](DEBUGGING.md).

View File

@@ -1,223 +0,0 @@
# License Header Management
This document explains how to manage license headers in the DeerFlow project.
## License Header Format
All source files in this project should include license headers.
### Python Files
```python
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
```
For files with a shebang (`#!/usr/bin/env python3`), the header is placed after the shebang:
```python
#!/usr/bin/env python3
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import something
```
### TypeScript Files
```typescript
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
import { something } from "somewhere";
```
## Makefile Targets
### Check License Headers
Check if all Python and TypeScript files have the required license header:
```bash
# Check all files (Python and TypeScript)
make check-license-all
# Check only Python files
make check-license
# Check only TypeScript files
make check-license-ts
```
These commands:
- Scan all source files in `src/`, `tests/`, `web/src/`, `web/tests/`, and root-level files
- Report files missing the license header
- Return exit code 1 if any files are missing headers (useful for CI/CD)
- Return exit code 0 if all files have headers
### Add License Headers
Automatically add license headers to files that don't have them:
```bash
# Add to all files (Python and TypeScript)
make add-license-all
# Add only to Python files
make add-license
# Add only to TypeScript files
make add-license-ts
```
These commands:
- Add the appropriate license header to files that don't have it
- Preserve shebangs at the top of Python files
- Add appropriate spacing after headers
- Show vTypeScript files
uv run python scripts/license_header.py web/src/components/ --check
# Check a single file (works for both .py and .ts/.tsx)
uv run python scripts/license_header.py src/workflow.py --check
uv run python scripts/license_header.py web/src/core/api/chat.ts --check
```
### Script Options
- `--check`: Check mode - verify headers without modifying files
- `--verbose` / `-v`: Show detailed output for each file processed
- `paths`: One or more paths (files or directories) to process
### Supported File Types
The script automatically detects and processes:
- Python files (`.py`)
- TypeScript files (`.ts`)
- TypeScript React files (`.tsx`)
## Pre-commit Hook
The license header check is integrated into the pre-commit hook. Before allowing a commit, it will:
1. Run linting (`make lint`)
2. Run formatting (`make format`)
This ensures all merged code has proper license headers for both Python and TypeScript fileill be blocked. Run `make add-license-all` to fix.
## CI/CD Integration
For continuous integration, add the license check to your workflow:
```bash
# In your CI script or GitHub Actions
- make check-license `.next` (Next.js build directory)
```
This ensures all merged code has proper license headers.
## Files Excluded
The license header tool automatically skips:
- `__pycache__` directories
- `.pytest_cache`, `.ruff_cache`, `.mypy_cache`
- `node_modules`
- Virtual environment directories (`.venv`, `venv`, `.tox`)
- Build artifacts (`build`, `dist`)
- `.git` directory
## Customization
### Changing the License Header
S` dictionary in `scripts/license_header.py`:
```python
LICENSE_HEADERS: Dict[str, str] = {
"python": """# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
""",
"typescript": """// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
""",
}
```
### Adding Licenserce header to all files:
@uv run python scripts/license_header.py src/ tests/ scripts/ web/src/ web/test
1. Add the extension to `FILE_TYPE_MAP` in `scripts/license_header.py`
2. Add the corresponding header format to `LICENSE_HEADERS`
```python
FILE_TYPE_MAP = {
".py": "python",
".ts": "typescript",
".tsx": "typescript",
".js": "javascript", # Example: adding JavaScript support
}
LICENSE_HEADERS = {
# ... existing headers ...
"javascript": """// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
""",
}PDX-License-Identifier: MIT
"""
```
-all
Checking license headers in all source files...
✅ All 289 source file(s) have license headers.
```
### Example 2: Check Only Python and TypeScript Files
```bash
$ make check-license-all
Checking license headers in Python and TypeScript files...
❌ 3 file(s) missing license header:
- web/src/components/new-component.tsx
- web/src/core/api/new-api.ts
- web/tests/new-test.test.ts
Run 'make add-license-all' to add headers.
```
### Example 3: Add Headers to New Module
```bash
$ make add-license-all
Adding license headers to all source files...
✅ Added license header to 11 file(s).
```
### Example 4: Check Specific Directory
```bash
$ uv run python scripts/license_header.py web/src/components/ --check --verbose
Header already present: web/src/components/deer-flow/logo.tsx
Header already present: web/src/components/deer-flow/markdown.tsx
Header already present: web/src/components/editor/index.tsx
✅ All 24 sourceooks for exact matches (ignoring leading/trailing whitespace)
### "Pre-commit hook blocks my commit"
- Run `make add-license-all` to add headers to all files
- Or disable the check temporarily by editing the `pre-commit` file
## Examples
### Example 1: Check All Files
```bash
$ make check-license-all
Checking license headers in Python files...
✅ All 156 Python file(s) have license headers.
```
### Example 2: Add Headers to New Module
```bash
$ make add-license-all
Adding license headers to Python files...
✅ Added license header to 11 file(s).
```
### Example 3: Check Specific Directory
```bash
$ uv run python scripts/license_header.py src/agents/ --check --verbose
Header already present: src/agents/base.py
Header already present: src/agents/coordinator.py
✅ All 8 Python file(s) have license headers.
```

View File

@@ -1,430 +0,0 @@
# Configuration Guide
## Quick Settings
Copy the `conf.yaml.example` file to `conf.yaml` and modify the configurations to match your specific settings and requirements.
```bash
cd deer-flow
cp conf.yaml.example conf.yaml
```
## Which models does DeerFlow support?
In DeerFlow, we currently only support non-reasoning models. This means models like OpenAI's o1/o3 or DeepSeek's R1 are not supported yet, but we plan to add support for them in the future. Additionally, all Gemma-3 models are currently unsupported due to the lack of tool usage capabilities.
### Supported Models
`doubao-1.5-pro-32k-250115`, `gpt-4o`, `qwen-max-latest`,`qwen3-235b-a22b`,`qwen3-coder`, `gemini-2.0-flash`, `deepseek-v3`, and theoretically any other non-reasoning chat models that implement the OpenAI API specification.
### Local Model Support
DeerFlow supports local models through OpenAI-compatible APIs:
- **Ollama**: `http://localhost:11434/v1` (tested and supported for local development)
See the `conf.yaml.example` file for detailed configuration examples.
> [!NOTE]
> The Deep Research process requires the model to have a **longer context window**, which is not supported by all models.
> A work-around is to set the `Max steps of a research plan` to `2` in the settings dialog located on the top right corner of the web page,
> or set `max_step_num` to `2` when invoking the API.
### How to switch models?
You can switch the model in use by modifying the `conf.yaml` file in the root directory of the project, using the configuration in the [litellm format](https://docs.litellm.ai/docs/providers/openai_compatible).
---
### How to use OpenAI-Compatible models?
DeerFlow supports integration with OpenAI-Compatible models, which are models that implement the OpenAI API specification. This includes various open-source and commercial models that provide API endpoints compatible with the OpenAI format. You can refer to [litellm OpenAI-Compatible](https://docs.litellm.ai/docs/providers/openai_compatible) for detailed documentation.
The following is a configuration example of `conf.yaml` for using OpenAI-Compatible models:
```yaml
# An example of Doubao models served by VolcEngine
BASIC_MODEL:
base_url: "https://ark.cn-beijing.volces.com/api/v3"
model: "doubao-1.5-pro-32k-250115"
api_key: YOUR_API_KEY
# An example of Aliyun models
BASIC_MODEL:
base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
model: "qwen-max-latest"
api_key: YOUR_API_KEY
# An example of deepseek official models
BASIC_MODEL:
base_url: "https://api.deepseek.com"
model: "deepseek-chat"
api_key: YOUR_API_KEY
# An example of Google Gemini models using OpenAI-Compatible interface
BASIC_MODEL:
base_url: "https://generativelanguage.googleapis.com/v1beta/openai/"
model: "gemini-2.0-flash"
api_key: YOUR_API_KEY
```
The following is a configuration example of `conf.yaml` for using best opensource OpenAI-Compatible models:
```yaml
# Use latest deepseek-v3 to handle basic tasks, the open source SOTA model for basic tasks
BASIC_MODEL:
base_url: https://api.deepseek.com
model: "deepseek-v3"
api_key: YOUR_API_KEY
temperature: 0.6
top_p: 0.90
# Use qwen3-235b-a22b to handle reasoning tasks, the open source SOTA model for reasoning
REASONING_MODEL:
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
model: "qwen3-235b-a22b-thinking-2507"
api_key: YOUR_API_KEY
temperature: 0.6
top_p: 0.90
# Use qwen3-coder-480b-a35b-instruct to handle coding tasks, the open source SOTA model for coding
CODE_MODEL:
base_url: https://dashscope.aliyuncs.com/compatible-mode/v1
model: "qwen3-coder-480b-a35b-instruct"
api_key: YOUR_API_KEY
temperature: 0.6
top_p: 0.90
```
In addition, you need to set the `AGENT_LLM_MAP` in `src/config/agents.py` to use the correct model for each agent. For example:
```python
# Define agent-LLM mapping
AGENT_LLM_MAP: dict[str, LLMType] = {
"coordinator": "reasoning",
"planner": "reasoning",
"researcher": "reasoning",
"coder": "basic",
"reporter": "basic",
"podcast_script_writer": "basic",
"ppt_composer": "basic",
"prose_writer": "basic",
"prompt_enhancer": "basic",
}
### How to use Google AI Studio models?
DeerFlow supports native integration with Google AI Studio (formerly Google Generative AI) API. This provides direct access to Google's Gemini models with their full feature set and optimized performance.
To use Google AI Studio models, you need to:
1. Get your API key from [Google AI Studio](https://aistudio.google.com/app/apikey)
2. Set the `platform` field to `"google_aistudio"` in your configuration
3. Configure your model and API key
The following is a configuration example for using Google AI Studio models:
```yaml
# Google AI Studio native API (recommended for Google models)
BASIC_MODEL:
platform: "google_aistudio"
model: "gemini-2.5-flash" # or "gemini-1.5-pro" ,...
api_key: YOUR_GOOGLE_API_KEY # Get from https://aistudio.google.com/app/apikey
```
**Note:** The `platform: "google_aistudio"` field is required to distinguish from other providers that may offer Gemini models through OpenAI-compatible APIs.
```
### How to use models with self-signed SSL certificates?
If your LLM server uses self-signed SSL certificates, you can disable SSL certificate verification by adding the `verify_ssl: false` parameter to your model configuration:
```yaml
BASIC_MODEL:
base_url: "https://your-llm-server.com/api/v1"
model: "your-model-name"
api_key: YOUR_API_KEY
verify_ssl: false # Disable SSL certificate verification for self-signed certificates
```
> [!WARNING]
> Disabling SSL certificate verification reduces security and should only be used in development environments or when you trust the LLM server. In production environments, it's recommended to use properly signed SSL certificates.
### How to use Ollama models?
DeerFlow supports the integration of Ollama models. You can refer to [litellm Ollama](https://docs.litellm.ai/docs/providers/ollama). <br>
The following is a configuration example of `conf.yaml` for using Ollama models(you might need to run the 'ollama serve' first):
```yaml
BASIC_MODEL:
model: "model-name" # Model name, which supports the completions API(important), such as: qwen3:8b, mistral-small3.1:24b, qwen2.5:3b
base_url: "http://localhost:11434/v1" # Local service address of Ollama, which can be started/viewed via ollama serve
api_key: "whatever" # Mandatory, fake api_key with a random string you like :-)
```
### How to use OpenRouter models?
DeerFlow supports the integration of OpenRouter models. You can refer to [litellm OpenRouter](https://docs.litellm.ai/docs/providers/openrouter). To use OpenRouter models, you need to:
1. Obtain the OPENROUTER_API_KEY from OpenRouter (https://openrouter.ai/) and set it in the environment variable.
2. Add the `openrouter/` prefix before the model name.
3. Configure the correct OpenRouter base URL.
The following is a configuration example for using OpenRouter models:
1. Configure OPENROUTER_API_KEY in the environment variable (such as the `.env` file)
```ini
OPENROUTER_API_KEY=""
```
2. Set the model name in `conf.yaml`
```yaml
BASIC_MODEL:
model: "openrouter/google/palm-2-chat-bison"
```
Note: The available models and their exact names may change over time. Please verify the currently available models and their correct identifiers in [OpenRouter's official documentation](https://openrouter.ai/docs).
### How to use Azure OpenAI chat models?
DeerFlow supports the integration of Azure OpenAI chat models. You can refer to [AzureChatOpenAI](https://python.langchain.com/api_reference/openai/chat_models/langchain_openai.chat_models.azure.AzureChatOpenAI.html). Configuration example of `conf.yaml`:
```yaml
BASIC_MODEL:
model: "azure/gpt-4o-2024-08-06"
azure_endpoint: $AZURE_OPENAI_ENDPOINT
api_version: $OPENAI_API_VERSION
api_key: $AZURE_OPENAI_API_KEY
```
### How to configure context length for different models
Different models have different context length limitations. DeerFlow provides a method to control the context length between different models. You can configure the context length between different models in the `conf.yaml` file. For example:
```yaml
BASIC_MODEL:
base_url: https://ark.cn-beijing.volces.com/api/v3
model: "doubao-1-5-pro-32k-250115"
api_key: ""
token_limit: 128000
```
This means that the context length limit using this model is 128k.
The context management doesn't work if the token_limit is not set.
## About Search Engine
### Supported Search Engines
DeerFlow supports the following search engines:
- Tavily
- InfoQuest
- DuckDuckGo
- Brave Search
- Arxiv
- Searx
- Serper
- Wikipedia
### How to use Serper Search?
To use Serper as your search engine, you need to:
1. Get your API key from [Serper](https://serper.dev/)
2. Set `SEARCH_API=serper` in your `.env` file
3. Set `SERPER_API_KEY=your_api_key` in your `.env` file
### How to control search domains for Tavily?
DeerFlow allows you to control which domains are included or excluded in Tavily search results through the configuration file. This helps improve search result quality and reduce hallucinations by focusing on trusted sources.
`Tips`: it only supports Tavily currently.
You can configure domain filtering and search results in your `conf.yaml` file as follows:
```yaml
SEARCH_ENGINE:
engine: tavily
# Only include results from these domains (whitelist)
include_domains:
- trusted-news.com
- gov.org
- reliable-source.edu
# Exclude results from these domains (blacklist)
exclude_domains:
- unreliable-site.com
- spam-domain.net
# Include images in search results, default: true
include_images: false
# Include image descriptions in search results, default: true
include_image_descriptions: false
# Include raw content in search results, default: true
include_raw_content: false
```
### How to post-process Tavily search results
DeerFlow can post-process Tavily search results:
* Remove duplicate content
* Filter low-quality content: Filter out results with low relevance scores
* Clear base64 encoded images
* Length truncation: Truncate each search result according to the user-configured length
The filtering of low-quality content and length truncation depend on user configuration, providing two configurable parameters:
* min_score_threshold: Minimum relevance score threshold, search results below this threshold will be filtered. If not set, no filtering will be performed;
* max_content_length_per_page: Maximum length limit for each search result content, parts exceeding this length will be truncated. If not set, no truncation will be performed;
These two parameters can be configured in `conf.yaml` as shown below:
```yaml
SEARCH_ENGINE:
engine: tavily
include_images: true
min_score_threshold: 0.4
max_content_length_per_page: 5000
```
That's meaning that the search results will be filtered based on the minimum relevance score threshold and truncated to the maximum length limit for each search result content.
## Web Search Toggle
DeerFlow allows you to disable web search functionality, which is useful for environments without internet access or when you want to use only local RAG knowledge bases.
### Configuration
You can disable web search in your `conf.yaml` file:
```yaml
# Disable web search (use only local RAG)
ENABLE_WEB_SEARCH: false
```
Or via API request parameter:
```json
{
"messages": [{"role": "user", "content": "Research topic"}],
"enable_web_search": false
}
```
> [!WARNING]
> If you disable web search, make sure to configure local RAG resources; otherwise, the researcher will operate in pure LLM reasoning mode without external data sources.
### Behavior When Web Search is Disabled
- **Background investigation**: Skipped entirely (relies on web search)
- **Researcher node**: Will use only RAG retriever tools if configured
- **Pure reasoning mode**: If no RAG resources are available, the researcher will rely solely on LLM reasoning
---
## Recursion Fallback Configuration
When agents hit the recursion limit, DeerFlow can gracefully generate a summary of accumulated findings instead of failing (enabled by default).
### Configuration
In `conf.yaml`:
```yaml
ENABLE_RECURSION_FALLBACK: true
```
### Recursion Limit
Set the maximum recursion limit via environment variable:
```bash
export AGENT_RECURSION_LIMIT=50 # default: 25
```
Or in `.env`:
```ini
AGENT_RECURSION_LIMIT=50
```
---
## RAG (Retrieval-Augmented Generation) Configuration
DeerFlow supports multiple RAG providers for document retrieval. Configure the RAG provider by setting environment variables.
### Supported RAG Providers
- **RAGFlow**: Document retrieval using RAGFlow API
- **VikingDB Knowledge Base**: ByteDance's VikingDB knowledge base service
- **Milvus**: Open-source vector database for similarity search
- **Qdrant**: Open-source vector search engine with cloud and self-hosted options
- **MOI**: Hybrid database for enterprise users
- **Dify**: AI application platform with RAG capabilities
### Qdrant Configuration
To use Qdrant as your RAG provider, set the following environment variables:
```bash
# RAG_PROVIDER: qdrant (using Qdrant Cloud or self-hosted)
RAG_PROVIDER=qdrant
QDRANT_LOCATION=https://xyz-example.eu-central.aws.cloud.qdrant.io:6333
QDRANT_API_KEY=<your_qdrant_api_key>
QDRANT_COLLECTION=documents
QDRANT_EMBEDDING_PROVIDER=openai # support openai, dashscope
QDRANT_EMBEDDING_BASE_URL=
QDRANT_EMBEDDING_MODEL=text-embedding-ada-002
QDRANT_EMBEDDING_API_KEY=<your_embedding_api_key>
QDRANT_AUTO_LOAD_EXAMPLES=true # automatically load example markdown files
```
### Milvus Configuration
To use Milvus as your RAG provider, set the following environment variables:
```bash
# RAG_PROVIDER: milvus (using free milvus instance on zilliz cloud: https://docs.zilliz.com/docs/quick-start )
RAG_PROVIDER=milvus
MILVUS_URI=<endpoint_of_self_hosted_milvus_or_zilliz_cloud>
MILVUS_USER=<username_of_self_hosted_milvus_or_zilliz_cloud>
MILVUS_PASSWORD=<password_of_self_hosted_milvus_or_zilliz_cloud>
MILVUS_COLLECTION=documents
MILVUS_EMBEDDING_PROVIDER=openai
MILVUS_EMBEDDING_BASE_URL=
MILVUS_EMBEDDING_MODEL=
MILVUS_EMBEDDING_API_KEY=
# RAG_PROVIDER: milvus (using milvus lite on Mac or Linux)
RAG_PROVIDER=milvus
MILVUS_URI=./milvus_demo.db
MILVUS_COLLECTION=documents
MILVUS_EMBEDDING_PROVIDER=openai
MILVUS_EMBEDDING_BASE_URL=
MILVUS_EMBEDDING_MODEL=
MILVUS_EMBEDDING_API_KEY=
```
---
## Multi-Turn Clarification (Optional)
An optional feature that helps clarify vague research questions through conversation. **Disabled by default.**
### Enable via Command Line
```bash
# Enable clarification for vague questions
uv run main.py "Research AI" --enable-clarification
# Set custom maximum clarification rounds
uv run main.py "Research AI" --enable-clarification --max-clarification-rounds 3
# Interactive mode with clarification
uv run main.py --interactive --enable-clarification --max-clarification-rounds 3
```
### Enable via API
```json
{
"messages": [{"role": "user", "content": "Research AI"}],
"enable_clarification": true,
"max_clarification_rounds": 3
}
```
### Enable via UI Settings
1. Open DeerFlow web interface
2. Navigate to **Settings****General** tab
3. Find **"Enable Clarification"** toggle
4. Turn it **ON** to enable multi-turn clarification. Clarification is **disabled** by default. You need to manually enable it through any of the above methods. When clarification is enabled, you'll see **"Max Clarification Rounds"** field appear below the toggle
6. Set the maximum number of clarification rounds (default: 3, minimum: 1)
7. Click **Save** to apply changes
**When enabled**, the Coordinator will ask up to the specified number of clarifying questions for vague topics before starting research, improving report relevance and depth. The `max_clarification_rounds` parameter controls how many rounds of clarification are allowed.
**Note**: The `max_clarification_rounds` parameter only takes effect when `enable_clarification` is set to `true`. If clarification is disabled, this parameter is ignored.

View File

@@ -1,298 +0,0 @@
# MCP Integrations (Beta)
This feature is disabled by default. You can enable it by setting the environment variable `ENABLE_MCP_SERVER_CONFIGURATION=true`.
> [!WARNING]
> Please enable this feature only after securing your front-end and back-end in a managed environment.
> Otherwise, your system could be compromised.
## Enabling MCP
Set the following environment variable in your `.env` file:
```bash
ENABLE_MCP_SERVER_CONFIGURATION=true
```
Then restart the DeerFlow server.
---
## MCP Server Examples
### 1. GitHub Trending
Fetches trending repositories from GitHub.
```json
{
"mcpServers": {
"mcp-github-trending": {
"transport": "stdio",
"command": "uvx",
"args": ["mcp-github-trending"]
}
}
}
```
**Available Tools:**
- `get_github_trending_repositories` - Get trending repositories by language and time range
---
### 2. Filesystem Access
Provides secure file system access with configurable allowed directories.
```json
{
"mcpServers": {
"filesystem": {
"transport": "stdio",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/path/to/allowed/directory"
]
}
}
}
```
**Available Tools:**
- `read_text_file` - Read contents of a text file
- `read_multiple_files` - Read multiple files at once
- `write_file` - Write content to a file
- `edit_file` - Edit a file with line-based replacements
- `create_directory` - Create a new directory
- `list_directory` - List files and directories
- `directory_tree` - Get a recursive tree view
- `move_file` - Move or rename files
- `search_files` - Search for files by pattern
- `get_file_info` - Get file metadata
---
### 3. Brave Search
Web search using Brave Search API.
**Prerequisites:** Get API key from [Brave Search API](https://brave.com/search/api/)
```json
{
"mcpServers": {
"brave-search": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"BRAVE_API_KEY": "your-brave-api-key"
}
}
}
}
```
**Available Tools:**
- `brave_web_search` - Perform web searches
- `brave_local_search` - Search for local businesses and places
---
### 4. Tavily Search
AI-optimized search engine for research tasks.
**Prerequisites:** Get API key from [Tavily](https://tavily.com/)
```json
{
"mcpServers": {
"tavily": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "tavily-mcp"],
"env": {
"TAVILY_API_KEY": "tvly-your-api-key"
}
}
}
}
```
**Available Tools:**
- `tavily-search` - Perform AI-optimized web search
- `tavily-extract` - Extract content from web pages
---
## Adding MCP Tools to Agents
When using MCP tools in DeerFlow, you need to specify:
1. **`enabled_tools`** - Which tools from the MCP server to enable
2. **`add_to_agents`** - Which DeerFlow agents can use these tools (`researcher`, `coder`, or both)
### Example: Full Configuration for Chat API
```json
{
"messages": [{"role": "user", "content": "Research the top GitHub trends"}],
"mcp_settings": {
"servers": {
"github-trending": {
"transport": "stdio",
"command": "uvx",
"args": ["mcp-github-trending"],
"enabled_tools": ["get_github_trending_repositories"],
"add_to_agents": ["researcher"]
}
}
}
}
```
---
## APIs
### Get MCP Server Metadata
**POST /api/mcp/server/metadata**
Use this endpoint to discover available tools from an MCP server.
For `stdio` type:
```json
{
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
}
```
For `sse` type:
```json
{
"transport": "sse",
"url": "http://localhost:3000/sse",
"headers": {
"Authorization": "Bearer your-token"
}
}
```
For `streamable_http` type:
```json
{
"transport": "streamable_http",
"url": "http://localhost:3000/mcp",
"headers": {
"API_KEY": "your-api-key"
}
}
```
### Chat Stream with MCP
**POST /api/chat/stream**
```json
{
"messages": [{"role": "user", "content": "Your research query"}],
"thread_id": "unique-thread-id",
"mcp_settings": {
"servers": {
"your-mcp-server": {
"transport": "stdio",
"command": "uvx",
"args": ["your-mcp-package"],
"env": {
"API_KEY": "your-api-key"
},
"enabled_tools": ["tool1", "tool2"],
"add_to_agents": ["researcher"]
}
}
}
}
```
---
## Timeout Configuration
DeerFlow provides configurable timeout settings for MCP server connections to handle various network conditions and server responsiveness scenarios.
### Global Default Timeout
Set the default timeout for all MCP server connections via environment variable:
```bash
# .env file
MCP_DEFAULT_TIMEOUT_SECONDS=60
```
**Default value:** 60 seconds
### Per-Request Timeout Override
When querying the MCP server metadata API, you can override the default timeout for a specific request:
**Example: Get MCP Server Metadata with Custom Timeout**
```json
{
"transport": "sse",
"url": "http://localhost:3000/sse",
"headers": {
"Authorization": "Bearer your-token"
},
"timeout_seconds": 45,
"sse_read_timeout": 20
}
```
**Parameters:**
- `timeout_seconds` (optional, integer): Overall timeout in seconds for the MCP server connection. Overrides `MCP_DEFAULT_TIMEOUT_SECONDS` environment variable.
- `sse_read_timeout` (optional, integer): Timeout in seconds for SSE (Server-Sent Events) streaming read operations. Only applicable for `sse` transport type. When provided, allows fine-grained control over streaming timeouts.
### Timeout Recommendations
- **Fast, Local MCP Servers**: 10-15 seconds
- **Standard Production Servers**: 30-60 seconds
- **Slow or High-Latency Servers**: 60+ seconds (use with caution)
> [!NOTE]
> The `timeout_seconds` parameter is recommended for most use cases. The `sse_read_timeout` parameter should only be used when you need separate control over SSE streaming read operations.
### Example: Chat API with Custom Timeouts
```json
{
"messages": [{"role": "user", "content": "Research query"}],
"mcp_settings": {
"servers": {
"my-mcp-server": {
"transport": "sse",
"url": "http://localhost:3000/sse",
"timeout_seconds": 45,
"sse_read_timeout": 20,
"enabled_tools": ["tool1", "tool2"],
"add_to_agents": ["researcher"]
}
}
}
}
```
---
## Additional Resources
- [MCP Official Documentation](https://modelcontextprotocol.io/)
- [MCP Server Registry](https://github.com/modelcontextprotocol/servers)

View File

@@ -1,740 +0,0 @@
{
"openapi": "3.0.0",
"info": {
"title": "DeerFlow API",
"description": "API for Deer - Advanced research and content generation system",
"version": "0.1.0"
},
"servers": [
{
"url": "http://localhost:8000",
"description": "Local development server"
}
],
"paths": {
"/api/chat/stream": {
"post": {
"summary": "Stream chat responses",
"description": "Initiates a streaming chat session with the research agent. Returns server-sent events with message chunks, tool calls, and intermediate results.",
"tags": ["Chat"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ChatRequest"
}
}
}
},
"responses": {
"200": {
"description": "Successful streaming response",
"content": {
"text/event-stream": {
"schema": {
"type": "object",
"description": "Server-sent events with various message types"
}
}
}
},
"403": {
"description": "MCP server configuration is disabled"
},
"500": {
"description": "Internal server error during graph execution"
}
}
}
},
"/api/tts": {
"post": {
"summary": "Convert text to speech",
"description": "Converts text to speech using Volcengine TTS API. Requires VOLCENGINE_TTS_APPID and VOLCENGINE_TTS_ACCESS_TOKEN environment variables.",
"tags": ["Text-to-Speech"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TTSRequest"
}
}
}
},
"responses": {
"200": {
"description": "Audio file in requested format",
"content": {
"audio/mp3": {
"schema": {
"type": "string",
"format": "binary"
}
},
"audio/wav": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"400": {
"description": "Missing required environment variables"
},
"500": {
"description": "Internal server error during TTS processing"
}
}
}
},
"/api/podcast/generate": {
"post": {
"summary": "Generate podcast from content",
"description": "Generates an audio podcast from the provided text content",
"tags": ["Content Generation"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GeneratePodcastRequest"
}
}
}
},
"responses": {
"200": {
"description": "Generated podcast audio file",
"content": {
"audio/mp3": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"500": {
"description": "Error during podcast generation"
}
}
}
},
"/api/ppt/generate": {
"post": {
"summary": "Generate PowerPoint presentation",
"description": "Generates a PowerPoint presentation from the provided content",
"tags": ["Content Generation"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GeneratePPTRequest"
}
}
}
},
"responses": {
"200": {
"description": "Generated PowerPoint file",
"content": {
"application/vnd.openxmlformats-officedocument.presentationml.presentation": {
"schema": {
"type": "string",
"format": "binary"
}
}
}
},
"500": {
"description": "Error during PPT generation"
}
}
}
},
"/api/prose/generate": {
"post": {
"summary": "Generate prose content",
"description": "Generates prose content with streaming output based on the provided prompt and option",
"tags": ["Content Generation"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenerateProseRequest"
}
}
}
},
"responses": {
"200": {
"description": "Streaming prose content",
"content": {
"text/event-stream": {
"schema": {
"type": "string",
"description": "Server-sent events with prose content chunks"
}
}
}
},
"500": {
"description": "Error during prose generation"
}
}
}
},
"/api/prompt/enhance": {
"post": {
"summary": "Enhance user prompts",
"description": "Enhances and refines user prompts with specified report style and context",
"tags": ["Prompt"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/EnhancePromptRequest"
}
}
}
},
"responses": {
"200": {
"description": "Enhanced prompt result",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"result": {
"type": "string",
"description": "The enhanced prompt"
}
}
}
}
}
},
"500": {
"description": "Error during prompt enhancement"
}
}
}
},
"/api/mcp/server/metadata": {
"post": {
"summary": "Get MCP server metadata",
"description": "Retrieves metadata and available tools from a Model Context Protocol (MCP) server. Requires ENABLE_MCP_SERVER_CONFIGURATION=true.",
"tags": ["MCP"],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MCPServerMetadataRequest"
}
}
}
},
"responses": {
"200": {
"description": "MCP server metadata and available tools",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MCPServerMetadataResponse"
}
}
}
},
"403": {
"description": "MCP server configuration is disabled"
},
"500": {
"description": "Error retrieving MCP server metadata"
}
}
}
},
"/api/rag/config": {
"get": {
"summary": "Get RAG configuration",
"description": "Returns the current RAG (Retrieval-Augmented Generation) provider configuration",
"tags": ["RAG"],
"responses": {
"200": {
"description": "RAG configuration",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RAGConfigResponse"
}
}
}
}
}
}
},
"/api/rag/resources": {
"get": {
"summary": "Get RAG resources",
"description": "Retrieves available resources from the RAG system based on optional query parameter",
"tags": ["RAG"],
"parameters": [
{
"name": "query",
"in": "query",
"description": "Search query for resources",
"required": false,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "List of RAG resources",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RAGResourcesResponse"
}
}
}
}
}
}
},
"/api/config": {
"get": {
"summary": "Get server configuration",
"description": "Returns the complete server configuration including RAG settings and available models",
"tags": ["Configuration"],
"responses": {
"200": {
"description": "Server configuration",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ConfigResponse"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"ChatRequest": {
"type": "object",
"description": "Request for chat streaming endpoint",
"properties": {
"messages": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ChatMessage"
},
"description": "History of messages between the user and assistant"
},
"resources": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Resource"
},
"description": "Resources to be used for the research"
},
"debug": {
"type": "boolean",
"default": false,
"description": "Whether to enable debug logging"
},
"thread_id": {
"type": "string",
"default": "__default__",
"description": "A specific conversation identifier"
},
"max_plan_iterations": {
"type": "integer",
"default": 1,
"description": "The maximum number of plan iterations"
},
"max_step_num": {
"type": "integer",
"default": 3,
"description": "The maximum number of steps in a plan"
},
"max_search_results": {
"type": "integer",
"default": 3,
"description": "The maximum number of search results"
},
"auto_accepted_plan": {
"type": "boolean",
"default": false,
"description": "Whether to automatically accept the plan"
},
"interrupt_feedback": {
"type": "string",
"nullable": true,
"description": "Interrupt feedback from the user on the plan"
},
"mcp_settings": {
"type": "object",
"nullable": true,
"description": "MCP settings for the chat request"
},
"enable_background_investigation": {
"type": "boolean",
"default": true,
"description": "Whether to get background investigation before plan"
},
"report_style": {
"type": "string",
"enum": ["ACADEMIC", "POPULAR_SCIENCE", "NEWS", "SOCIAL_MEDIA", "STRATEGIC_INVESTMENT"],
"default": "ACADEMIC",
"description": "The style of the report"
},
"enable_deep_thinking": {
"type": "boolean",
"default": false,
"description": "Whether to enable deep thinking"
},
"enable_clarification": {
"type": "boolean",
"nullable": true,
"description": "Whether to enable multi-turn clarification"
},
"max_clarification_rounds": {
"type": "integer",
"nullable": true,
"description": "Maximum number of clarification rounds"
}
}
},
"ChatMessage": {
"type": "object",
"required": ["role", "content"],
"properties": {
"role": {
"type": "string",
"enum": ["user", "assistant"],
"description": "The role of the message sender"
},
"content": {
"oneOf": [
{
"type": "string",
"description": "Text content"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/ContentItem"
},
"description": "Multiple content items"
}
]
}
}
},
"ContentItem": {
"type": "object",
"required": ["type"],
"properties": {
"type": {
"type": "string",
"description": "The type of content (text, image, etc.)"
},
"text": {
"type": "string",
"nullable": true,
"description": "The text content if type is 'text'"
},
"image_url": {
"type": "string",
"nullable": true,
"description": "The image URL if type is 'image'"
}
}
},
"Resource": {
"type": "object",
"description": "A resource for RAG queries"
},
"TTSRequest": {
"type": "object",
"required": ["text"],
"properties": {
"text": {
"type": "string",
"description": "The text to convert to speech (max 1024 characters)"
},
"voice_type": {
"type": "string",
"default": "BV700_V2_streaming",
"description": "The voice type to use"
},
"encoding": {
"type": "string",
"default": "mp3",
"enum": ["mp3", "wav"],
"description": "The audio encoding format"
},
"speed_ratio": {
"type": "number",
"format": "float",
"default": 1.0,
"description": "Speech speed ratio"
},
"volume_ratio": {
"type": "number",
"format": "float",
"default": 1.0,
"description": "Speech volume ratio"
},
"pitch_ratio": {
"type": "number",
"format": "float",
"default": 1.0,
"description": "Speech pitch ratio"
},
"text_type": {
"type": "string",
"default": "plain",
"enum": ["plain", "ssml"],
"description": "Text type"
},
"with_frontend": {
"type": "integer",
"default": 1,
"description": "Whether to use frontend processing"
},
"frontend_type": {
"type": "string",
"default": "unitTson",
"description": "Frontend type"
}
}
},
"GeneratePodcastRequest": {
"type": "object",
"required": ["content"],
"properties": {
"content": {
"type": "string",
"description": "The content of the podcast"
}
}
},
"GeneratePPTRequest": {
"type": "object",
"required": ["content"],
"properties": {
"content": {
"type": "string",
"description": "The content of the PowerPoint presentation"
}
}
},
"GenerateProseRequest": {
"type": "object",
"required": ["prompt", "option"],
"properties": {
"prompt": {
"type": "string",
"description": "The content/prompt of the prose"
},
"option": {
"type": "string",
"description": "The option of the prose writer"
},
"command": {
"type": "string",
"default": "",
"description": "The user custom command of the prose writer"
}
}
},
"EnhancePromptRequest": {
"type": "object",
"required": ["prompt"],
"properties": {
"prompt": {
"type": "string",
"description": "The original prompt to enhance"
},
"context": {
"type": "string",
"default": "",
"description": "Additional context about the intended use"
},
"report_style": {
"type": "string",
"default": "academic",
"enum": ["academic", "ACADEMIC", "popular_science", "POPULAR_SCIENCE", "news", "NEWS", "social_media", "SOCIAL_MEDIA", "strategic_investment", "STRATEGIC_INVESTMENT"],
"description": "The style of the report"
}
}
},
"MCPServerMetadataRequest": {
"type": "object",
"required": ["transport"],
"properties": {
"transport": {
"type": "string",
"enum": ["stdio", "sse", "streamable_http"],
"description": "The type of MCP server connection"
},
"command": {
"type": "string",
"nullable": true,
"description": "The command to execute (for stdio type)"
},
"args": {
"type": "array",
"items": {
"type": "string"
},
"nullable": true,
"description": "Command arguments (for stdio type)"
},
"url": {
"type": "string",
"nullable": true,
"description": "The URL of the SSE server (for sse type)"
},
"env": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"nullable": true,
"description": "Environment variables (for stdio type)"
},
"headers": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"nullable": true,
"description": "HTTP headers (for sse/streamable_http type)"
},
"timeout_seconds": {
"type": "integer",
"nullable": true,
"description": "Optional custom timeout in seconds"
}
}
},
"MCPServerMetadataResponse": {
"type": "object",
"required": ["transport"],
"properties": {
"transport": {
"type": "string",
"description": "The type of MCP server connection"
},
"command": {
"type": "string",
"nullable": true,
"description": "The command to execute (for stdio type)"
},
"args": {
"type": "array",
"items": {
"type": "string"
},
"nullable": true,
"description": "Command arguments (for stdio type)"
},
"url": {
"type": "string",
"nullable": true,
"description": "The URL of the SSE server (for sse type)"
},
"env": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"nullable": true,
"description": "Environment variables (for stdio type)"
},
"headers": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"nullable": true,
"description": "HTTP headers (for sse/streamable_http type)"
},
"tools": {
"type": "array",
"description": "Available tools from the MCP server"
}
}
},
"RAGConfigResponse": {
"type": "object",
"properties": {
"provider": {
"type": "string",
"nullable": true,
"description": "The provider of the RAG (default: ragflow)"
}
}
},
"RAGResourceRequest": {
"type": "object",
"properties": {
"query": {
"type": "string",
"nullable": true,
"description": "The query of the resource to be searched"
}
}
},
"RAGResourcesResponse": {
"type": "object",
"required": ["resources"],
"properties": {
"resources": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Resource"
},
"description": "The resources of the RAG"
}
}
},
"ConfigResponse": {
"type": "object",
"required": ["rag", "models"],
"properties": {
"rag": {
"$ref": "#/components/schemas/RAGConfigResponse",
"description": "The config of the RAG"
},
"models": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
},
"description": "The configured models"
}
}
}
}
}
}

View File

@@ -1,110 +0,0 @@
# AI Adoption in Healthcare: Influencing Factors
## Key Points
- AI technologies like machine learning, deep learning, and NLP are rapidly changing healthcare, offering enhanced accuracy and efficiency.
- Data quality, including volume, type, bias, security, and privacy, significantly impacts the reliability and ethical implications of AI applications in healthcare.
- Ethical considerations, such as data privacy, algorithmic bias, and transparency, are critical for ensuring fair and equitable AI outcomes in healthcare.
- Economic evaluations of AI in healthcare need to be comprehensive, considering initial investments, running costs, and comparisons with traditional methods.
- Organizational readiness, including digital skills, structural adaptations, and addressing ethical concerns, is essential for successful AI integration in healthcare.
- Healthcare lags behind other industries in AI adoption, necessitating enhanced digital infrastructure and a shift in how healthcare is delivered and accessed.
---
## Overview
Artificial Intelligence (AI) is poised to revolutionize healthcare through machine learning, deep learning, and natural language processing. The successful integration of AI in healthcare depends on several factors, including technological maturity, data quality, ethical considerations, economic feasibility, organizational readiness, and digital infrastructure. Addressing these elements is essential for creating trustworthy and effective AI solutions that improve patient outcomes and optimize healthcare delivery.
---
## Detailed Analysis
### Technical Maturity and Validation
AI technologies, particularly machine learning (ML), deep learning (DL), and natural language processing (NLP), are increasingly prevalent in healthcare. Large Language Models (LLMs) leverage deep learning and large datasets to process text-based content. However, the accuracy, reliability, and performance of AI algorithms must be comprehensively tested using diverse datasets to avoid overfitting and ensure proper validation [https://pmc.ncbi.nlm.nih.gov/articles/PMC11047988/].
### Data Availability and Quality
Data quality is crucial for the trustworthiness of AI in healthcare [https://www.nature.com/articles/s41746-024-01196-4]. Key considerations include:
* **Data Volume:** AI applications require large datasets to train effectively.
* **Data Type:** AI must handle both structured and unstructured data, including text, images, and sensor readings.
* **Data Bias:** Biases in training data can lead to unfair or inaccurate outcomes, raising ethical concerns [https://pmc.ncbi.nlm.nih.gov/articles/PMC10718098/].
* **Data Security and Privacy:** Protecting patient data is paramount, especially with increased data volumes. De-identification may not completely eliminate the risk of data linkage [https://pmc.ncbi.nlm.nih.gov/articles/PMC10718098/].
Sharing inclusive AI algorithms and retraining existing algorithms with local data can address the lack of diversity in openly shared datasets, while preserving patient privacy [https://pmc.ncbi.nlm.nih.gov/articles/PMC8515002/].
### Ethical Considerations
Ethical considerations are paramount in the use of AI in healthcare [https://pmc.ncbi.nlm.nih.gov/articles/PMC11249277/]. Key issues include:
* **Privacy and Data Security:** Ensuring the confidentiality and security of patient data.
* **Algorithmic Bias:** Mitigating biases in algorithms to ensure equitable outcomes.
* **Transparency:** Making AI decision-making processes understandable.
* **Clinical Validation:** Ensuring AI tools are rigorously tested and validated for clinical use.
* **Professional Responsibility:** Defining the roles and responsibilities of healthcare professionals when using AI.
### Economic Costs and Benefits
Comprehensive cost-benefit analyses of AI in healthcare are needed [https://www.jmir.org/2020/2/e16866/]. These analyses should include:
* **Initial Investment:** Costs associated with AI technology, infrastructure and software.
* **Running Costs:** Ongoing expenses for maintenance, updates, and training.
* **Comparison with Alternatives:** Evaluating AI against traditional methods to determine cost-effectiveness [https://pmc.ncbi.nlm.nih.gov/articles/PMC9777836/].
* **Potential Savings:** AI can automate administrative tasks and improve diagnostic accuracy, leading to potential cost savings [https://itrexgroup.com/blog/assessing-the-costs-of-implementing-ai-in-healthcare/].
### Organizational Impact
AI integration impacts healthcare organizations by:
* **Assisting Physicians:** AI supports diagnosis and treatment planning [https://pmc.ncbi.nlm.nih.gov/articles/PMC10804900/].
* **Improving Efficiency:** AI can expedite patient waiting times and reduce paperwork [https://pmc.ncbi.nlm.nih.gov/articles/PMC10804900/].
* **Requiring New Skills:** Organizations need to embed digital and AI skills within their workforce [https://www.mckinsey.com/industries/healthcare/our-insights/transforming-healthcare-with-ai].
* **Demanding Cultural Change:** A shift towards innovation, continuous learning, and multidisciplinary working is necessary [https://www.mckinsey.com/industries/healthcare/our-insights/transforming-healthcare-with-ai].
The AI application management model (AIAMA) can help manage AI implementation from an organizational perspective [https://www.sciencedirect.com/science/article/pii/S0268401223001093].
### Digital Readiness
Healthcare's digital transformation through AI depends on:
* **Data Infrastructure:** Ability to manage and analyze large volumes of patient data [https://www.sciencedirect.com/science/article/abs/pii/B9780443215988000142].
* **Technology Adoption:** Addressing challenges through efficiency, accuracy, and patient-centric services [https://optasy.com/blog/revolutionizing-patient-care-rise-ai-and-digital-healthcare].
* **Industry Lag:** Healthcare is "below average" in AI adoption compared to other sectors [https://www.weforum.org/stories/2025/03/ai-transforming-global-health/].
* **Rethinking Healthcare Delivery:** AI transformation requires rethinking how healthcare is delivered and accessed [https://www.weforum.org/stories/2025/03/ai-transforming-global-health/].
---
## Key Citations
- [AI Technologies in Healthcare](https://bmcmededuc.biomedcentral.com/articles/10.1186/s12909-023-04698-z)
- [NLP in Healthcare](https://pmc.ncbi.nlm.nih.gov/articles/PMC6616181/)
- [AI Algorithm Validation](https://pmc.ncbi.nlm.nih.gov/articles/PMC11047988/)
- [Data Quality for Trustworthy AI](https://www.nature.com/articles/s41746-024-01196-4)
- [Data Privacy in the Era of AI](https://pmc.ncbi.nlm.nih.gov/articles/PMC10718098/)
- [Addressing Bias in Big Data and AI](https://pmc.ncbi.nlm.nih.gov/articles/PMC8515002/)
- [Ethical Considerations in the Use of Artificial Intelligence and ...](https://pmc.ncbi.nlm.nih.gov/articles/PMC11249277/)
- [The Economic Impact of Artificial Intelligence in Health Care](https://www.jmir.org/2020/2/e16866/)
- [Economics of Artificial Intelligence in Healthcare: Diagnosis vs ...](https://pmc.ncbi.nlm.nih.gov/articles/PMC9777836/)
- [Assessing the Cost of Implementing AI in Healthcare - ITRex Group](https://itrexgroup.com/blog/assessing-the-costs-of-implementing-ai-in-healthcare/)
- [Impact of Artificial Intelligence (AI) Technology in Healthcare Sector](https://pmc.ncbi.nlm.nih.gov/articles/PMC10804900/)
- [Transforming healthcare with AI: The impact on the workforce and ...](https://www.mckinsey.com/industries/healthcare/our-insights/transforming-healthcare-with-ai)
- [Managing artificial intelligence applications in healthcare: Promoting ...](https://www.sciencedirect.com/science/article/pii/S0268401223001093)
- [Healthcare digital transformation through the adoption of artificial ...](https://www.sciencedirect.com/science/article/abs/pii/B9780443215988000142)
- [Revolutionize Patient Care: The Rise of AI and Digital Healthcare](https://optasy.com/blog/revolutionizing-patient-care-rise-ai-and-digital-healthcare)
- [6 ways AI is transforming healthcare - The World Economic Forum](https://www.weforum.org/stories/2025/03/ai-transforming-global-health/)

View File

@@ -1,146 +0,0 @@
# Cristiano Ronaldo's Performance Highlights
## Key Points
- Cristiano Ronaldo is Portugal's all-time top scorer with **136 goals** and record appearance maker with **219 caps** as of March 23, 2025.
- He holds the record for most goals in the UEFA Champions League (140), most international goals (136), and most appearances for a national team (219).
- Ronaldo has won the UEFA European Championship (2016) and the UEFA Nations League (2019) with Portugal.
- He has scored a record 924 senior career goals for club and country and has made over 1,250 professional career appearances.
- Ronaldo has won 5 Ballon d'Or awards, the most for a European player.
- He is the current captain of Portugal and has the most caps as captain for the team.
---
## Overview
Cristiano Ronaldo dos Santos Aveiro is widely regarded as one of the greatest football players of all time. Throughout his illustrious career, he has achieved remarkable success at both the club and international levels. This report highlights Ronaldo's performance milestones, records, and achievements, showcasing his impact on the sport.
---
## Detailed Analysis
### Sporting CP
Ronaldo began his professional career at Sporting CP, where he quickly gained attention for his skill and potential.
| Achievement | Description |
| ---------------- | ------------------------------------------------------------------------------------------ |
| Debut | Made his debut for Sporting CP's first team. |
| Manchester United Friendly | Played in a friendly match against Manchester United in 2003, impressing the English side. |
| Goals | Scored 5 goals for the club. |
### Manchester United
Ronaldo's move to Manchester United marked the beginning of his international stardom.
| Achievement | Description |
| --------------------- | --------------------------------------------------------------------------------------------- |
| Debut | Made his debut for Manchester United. |
| First Goal | Scored his first goal for the club. |
| Best Moments | Showcased exceptional performances and won multiple titles. |
### Real Madrid
At Real Madrid, Ronaldo reached new heights, becoming the club's all-time leading goalscorer.
| Achievement | Description |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| Goals Scored | Scored 451 goals in 438 appearances. |
| Trophies Won | Won four Champions League titles, three Club World Cups, and two LaLiga titles. |
| All-Time Leading Goalscorer | Became the club's all-time leading goalscorer. |
### Juventus
Ronaldo continued his success at Juventus, winning Serie A titles and scoring consistently.
| Achievement | Description |
| --------------------- | ------------------------------------------------------------------------------------------------ |
| Goals Scored | Scored 101 goals in 134 appearances. |
| Key Performances | Notable performances include a double against Parma and a hat-trick against Atletico Madrid. |
### Al Nassr
Currently playing for Al Nassr, Ronaldo continues to add to his legacy.
| Achievement | Description |
| ---------------- | --------------------------------------------------------------------------- |
| AFC Champions League | Featured in matches in the AFC Champions League Elite. |
| Other Games | Played in various other games, contributing to the team's performance. |
### Portugal National Team
Ronaldo's international career is filled with records and achievements.
| Achievement | Description |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| Total Goals and Appearances | Portugal's record appearance maker with 219 caps and all-time top scorer with 136 goals as of March 23, 2025. |
| Goals in Competitive Matches | Scored 114 goals in competitive matches. |
| Trophies Won | Won the UEFA European Championship (2016) and the UEFA Nations League (2019). |
| Individual Awards | Named the Best Portuguese Player of All Time in 2015. |
| Major Tournament Statistics | Most games in the European Championship (30) and all-time leading scorer (14 goals). The only player to score at five different Euros. |
| Significant Match Performances | Scored twice against the Republic of Ireland on September 1, 2021, surpassing Ali Daei's record. |
| Records Broken | Holds the record for most goals scored in the history of international football, with 136 goals. |
| Captaincy and Leadership | Current captain of Portugal with the most caps as captain. |
| Other Records and Achievements | Won 5 Ballon d'Or awards, 3 UEFA Men's Player of the Year Awards, and 4 European Golden Shoes; Has won 33 trophies, including 7 league titles and 5 UEFA Champions Leagues |
---
## Key Citations
- [Cristiano Ronaldo Sporting CP Highlights | TikTok](https://www.tiktok.com/@sporting_cp/video/7339169970695228705?lang=en)
- [Cristiano Ronaldo Sporting Lisbon friendly highlights](https://www.manutd.com/en/videos/detail/cristiano-ronaldo-sporting-lisbon-friendly-highlights)
- [All 5 Goals For Sporting Lisbon - Cristiano Ronaldo - YouTube](https://www.youtube.com/watch?v=OBV57bqFvrw)
- [The Best of CR7 at Manchester United: 45 Minutes of Pure Magic ...](https://www.youtube.com/watch?v=Q9_NhdNLyBQ)
- [Cristiano Ronaldo's performance at Manchester United: 5 best moments at ...](https://www.elfutbolero.us/premier-league/cristiano-ronaldos-performance-at-manchester-united-5-best-moments-at-the-club-20241230-47146.html)
- [Manchester United Guide: Ronaldo's Career Highlights](https://unitedingratitude.aon.com/manchester-united-guide-ronaldos-career-highlights)
- [Cristiano Ronaldo's Real Madrid Highlights Gallery - Getty Images](https://www.gettyimages.com/sets/Un9jMk8A2kyZVnrlal2KXg/cristiano-ronaldo's-real-madrid-highlights)
- [Cristiano Ronaldo | Official Website | Real Madrid C.F.](https://www.realmadrid.com/en-US/the-club/history/football-legends/cristiano-ronaldo-dos-santos-aveiro)
- [Real Madrid 6 x 0 Espanyol (C. Ronaldo Hat-Trick) La Liga 15/16 ...](https://www.youtube.com/watch?v=RunxuA6wtHk&vl=en)
- [HIGHLIGHTS: Juventus vs Parma - 2-1 - Cristiano Ronaldo at the double ...](https://www.juventus.com/en/video/highlights-juventus-vs-parma-2-1-cristiano-ronaldo-at-the-double)
- [HIGHLIGHTS | Juventus 3-0 Atletico Madrid | Ronaldo greatest ... - YouTube](https://www.youtube.com/watch?v=cLfSpFg6Pxg)
- [REWIND | Cristiano Ronaldo's First for Juve - Juventus.com](https://www.juventus.com/en/news/articles/rewind-cristiano-ronaldo-s-first-for-juve)
- [Al Nassr (KSA) - Esteghlal FC (IRN) | Highlights ACL Elite™ - YouTube](https://www.youtube.com/watch?v=CUbYX4s-n8A)
- [Cristiano Ronaldo FINISHED? Al Orobah 2-1 Al Nassr HIGHLIGHTS](https://www.youtube.com/watch?v=FRhpTh0Eauk)
- [Ronaldo Brace! | Al Nassr (KSA) - Al Wasl FC (UAE) | Highlights](https://www.youtube.com/watch?v=Lyss81RSvBg)
- [Portugal national football team records and statistics - Wikipedia](https://en.wikipedia.org/wiki/Portugal_national_football_team_records_and_statistics)
- [The Records Cristiano Ronaldo Holds in Portugal National Team](https://setantasports.com/uncategorized/the-records-cristiano-ronaldo-holds-in-portugal-national-team/)
- [Cristiano Ronaldo - National team - Transfermarkt](https://www.transfermarkt.us/cristiano-ronaldo/nationalmannschaft/spieler/8198)
- [Cristiano Ronaldo's 136 international goals: Opposition, when they ...](https://www.uefa.com/uefanationsleague/news/0257-0e001aafb4e9-7c6ad3889ce0-7c6ad3889ce0)
- [Cristiano Ronaldo: All-time leading scorer in men's international ...](https://www.uefa.com/uefanationsleague/news/026a-1297500e1b34-a17bbbcad258-1000--cristiano-ronaldo-all-time-leading-scorer-in-men-s-interna/)
- [International Goals and Stats - Messi vs Ronaldo All Time ...](https://www.messivsronaldo.app/international-stats/)
- [List of career achievements by Cristiano Ronaldo - Wikipedia](https://en.wikipedia.org/wiki/List_of_career_achievements_by_Cristiano_Ronaldo)
- [Cristiano Ronaldo - Wikipedia](https://en.wikipedia.org/wiki/Cristiano_Ronaldo)
- [Trophies won by Cristiano Ronaldo 2024 - Statista](https://www.statista.com/statistics/1008294/cristiano-ronaldo-trophy-titles/)
- [[Statmuse] Cristiano Ronaldo major tournament career: 21 knockout ...](https://www.reddit.com/r/soccer/comments/1dw9r96/statmuse_cristiano_ronaldo_major_tournament/)
- [Cristiano Ronaldo | Stats | Portugal | UEFA EURO 2024](https://www.uefa.com/euro2024/teams/players/63706--cristiano-ronaldo/statistics/)
- [List of Portugal national football team captains - Wikipedia](https://en.wikipedia.org/wiki/List_of_Portugal_national_football_team_captains)
- [Ronaldo retains Portugal captaincy after Euro 2024](https://punchng.com/ronaldo-retains-portugal-captaincy-after-euro-2024/)
- [Euro 2024: Cristiano Ronaldo captains Portugal to become the first ...](https://www.marca.com/en/football/uefa-euro/2024/06/18/6671f709e2704ee6288b45b4.html)

View File

@@ -1,177 +0,0 @@
## Quantum Computing Impact on Cryptography
### Key Points
- Quantum computers threaten classical cryptographic algorithms like RSA and ECC due to Shor's algorithm.
- AES is vulnerable to Grover's algorithm, albeit to a lesser extent than RSA and ECC. AES-256 is more resistant than AES-128.
- Post-quantum cryptography (PQC) aims to develop algorithms resistant to quantum computer attacks.
- Quantum Key Distribution (QKD) offers secure key exchange based on quantum mechanics, but faces practical challenges.
- NIST is standardizing PQC algorithms, and organizations are exploring hybrid QKD/PQC solutions.
- The timeline for significant quantum attacks is uncertain, but proactive measures are necessary.
---
### Overview
Quantum computing poses a significant threat to modern cryptography. Quantum algorithms like Shor's and Grover's can break or weaken widely used encryption methods. This necessitates the development and adoption of quantum-resistant cryptographic solutions. This report provides an overview of the impact of quantum computing on existing cryptographic algorithms and explores potential solutions like post-quantum cryptography (PQC) and Quantum Key Distribution (QKD).
---
### Detailed Analysis
#### Vulnerabilities of Classical Cryptography
Classical cryptographic algorithms rely on mathematical problems that are difficult for classical computers to solve but are vulnerable to quantum algorithms.
| Algorithm | Vulnerability | Quantum Algorithm | Impact |
| :-------- | :------------ | :---------------- | :------------------------------------------------------------------ |
| RSA | Factoring | Shor's Algorithm | Efficient factorization of large numbers, breaking RSA encryption |
| ECC | Discrete Log | Shor's Algorithm | Efficiently solves discrete logarithm problems, breaking ECC encryption |
| AES | Brute Force | Grover's Algorithm| Reduces the search space, weakening AES security; AES-256 is stronger |
Shor's algorithm can efficiently factor large numbers, rendering RSA and ECC useless if a sufficiently powerful quantum computer is developed [http://greekcrisis.net/shors-algorithm-quantum-computers/]. Breaking RSA-2048 requires approximately 4000 qubits, and ECC-256 requires about 2500 qubits [https://ej-compute.org/index.php/compute/article/view/146].
Grover's algorithm reduces the brute-force search space for AES, weakening its security [https://ej-compute.org/index.php/compute/article/view/146]. AES-256 is more secure against quantum attacks than AES-128 or AES-192 [https://crypto.stackexchange.com/questions/6712/is-aes-256-a-post-quantum-secure-cipher-or-not].
#### Quantum Computational Resources
Breaking RSA-2048 requires around 4000 qubits and millions of gate operations, potentially achievable within the next decade [https://ej-compute.org/index.php/compute/article/view/146]. A quantum computer breaking RSA-2048 in hours could be built by 2030 for around a billion dollars [https://crypto.stackexchange.com/questions/102671/is-aes-128-quantum-safe]. IBM has a 1121-qubit 'Condor' processor, with leading platforms aiming for two-qubit gate fidelity in the range of 99.9% to 99.99% [https://methodologists.net/Exploring-the-Transformative-Advancements-in-Quantum-Computing-and-Their-Global-Impact-in-2024].
#### Post-Quantum Cryptography (PQC)
Post-quantum cryptography (PQC) involves developing cryptographic algorithms that are secure against attacks by both classical and quantum computers [https://en.wikipedia.org/wiki/Post-quantum_cryptography].
**PQC Algorithm Types**
| Algorithm Type | Examples | Characteristics |
| :------------------- | :---------------------------------------- | :--------------------------------------------------------------------------- |
| Lattice-based | CRYSTALS-Kyber, CRYSTALS-Dilithium, NTRU | Based on the hardness of lattice problems |
| Multivariate | Rainbow | Based on the difficulty of solving systems of multivariate polynomial equations |
| Hash-based | SPHINCS+ | Based on the security of cryptographic hash functions |
| Code-based | Classic McEliece | Based on the difficulty of decoding general linear codes |
| Isogeny-based | CSIDH | Based on isogenies between supersingular elliptic curves |
| Symmetric Key Quantum Resistance | AES and SNOW 3G | Post quantum resistance to known Symmetric Key Quantum resistance attacks |
PQC algorithms often require larger key sizes compared to pre-quantum algorithms [https://en.wikipedia.org/wiki/Post-quantum_cryptography].
**NIST Standardization**
NIST is conducting a Post-Quantum Cryptography Standardization Process to select PQC algorithms [https://en.wikipedia.org/wiki/Post-quantum_cryptography]. NIST has released the first three finalized post-quantum encryption standards: CRYSTALS-Kyber (ML-KEM), CRYSTALS-Dilithium (ML-DSA), and SPHINCS+ [https://www.nist.gov/news-events/news/2024/08/nist-releases-first-3-finalized-post-quantum-encryption-standards].
#### Quantum Key Distribution (QKD)
QKD offers a method for secure key exchange leveraging the principles of quantum mechanics [https://www.iosrjournals.org/iosr-jce/papers/Vol16-issue2/Version-11/A0162110109.pdf]. Eavesdropping introduces detectable anomalies due to the disturbance of the quantum system [https://en.wikipedia.org/wiki/Quantum_key_distribution].
**QKD Protocols**
| Protocol | Description |
| :------- | :---------- |
| BB84 | First QKD protocol |
| E91 | Uses entangled photons |
| COW | Coherent One Way |
Practical challenges include secret key rate, distance, size, cost, and practical security [https://arxiv.org/abs/1606.05853]. The NSA views quantum-resistant cryptography (PQC) as a more cost-effective and easily maintained solution than QKD for securing data in National Security Systems [https://www.nsa.gov/Cybersecurity/Quantum-Key-Distribution-QKD-and-Quantum-Cryptography-QC/].
#### Hybrid Approaches
Hybrid security systems integrating PQC and QKD are being explored [https://www.gsma.com/newsroom/wp-content/uploads//IG.18-Hybrid-QKD-and-PQC-security-scenarios-and-use-cases-Whitepaper-v1.0-002.pdf]. Network operators are expected to spend over $6 billion on QKD development and implementation between 2025 and 2030 [https://smartinfrastructuremagazine.com/news/quantum-key-distribution-network-operators-to-spend-6-3-billion-over-next-six-years].
#### Risk Assessment and Timelines
Quantum computing advancements are progressing, creating an urgent need to transition to quantum-safe alternatives [https://ej-compute.org/index.php/compute/article/view/146]. Cryptographic vulnerabilities may emerge within the next 510 years [https://ej-compute.org/index.php/compute/article/view/146].
---
### Key Citations
- [Implementation of Shor's Algorithm and Its Demonstrated Quantum ... - JSR](https://www.jsr.org/hs/index.php/path/article/view/6348)
- [Implementation and Analysis of Shor's Algorithm to Break RSA ...](https://www.researchgate.net/publication/377245624_Implementation_and_Analysis_of_Shor's_Algorithm_to_Break_RSA_Cryptosystem_Security)
- [Quantum AI: Shor's Algorithm - How Quantum Computers Break Cryptography ...](http://greekcrisis.net/shors-algorithm-quantum-computers/)
- [vulnerability of RSA/ECC to QC : r/cryptography - Reddit](https://www.reddit.com/r/cryptography/comments/1ajubq8/vulnerability_of_rsaecc_to_qc/)
- [Cyber Security Implications of Quantum Computing: Shor's ...](https://www.academia.edu/127333737/Cyber_Security_Implications_of_Quantum_Computing_Shors_Algorithm_and_Beyond)
- [The Impact of Quantum Computing on Cryptographic Systems: Urgency of ...](https://ej-compute.org/index.php/compute/article/view/146)
- [Exploring AES Encryption Implementation Through Quantum Computing ...](https://sciencepublishinggroup.com/article/10.11648/j.ajcst.20240704.12)
- [CSRC Presentations | CSRC - NIST Computer Security Resource Center](https://csrc.nist.gov/Presentations/2024/practical-cost-of-grover-for-aes-key-recovery)
- [Is AES-256 a post-quantum secure cipher or not?](https://crypto.stackexchange.com/questions/6712/is-aes-256-a-post-quantum-secure-cipher-or-not)
- [RSA's demise from quantum attacks is very much ... - Ars Technica](https://arstechnica.com/information-technology/2023/01/fear-not-rsa-encryption-wont-fall-to-quantum-computing-anytime-soon/)
- [Chinese researchers break RSA encryption with a quantum computer](https://www.csoonline.com/article/3562701/chinese-researchers-break-rsa-encryption-with-a-quantum-computer.html)
- [Quantum Computing and the Risks to the RSA Algorithm](https://robharrisoneu.substack.com/p/quantum-computing-and-the-risks-to)
- [Quantum Computing Breakthrough Could Crack ECC Cryptography ...](https://quantumzeitgeist.com/quantum-computing-breakthrough-could-crack-ecc-cryptography-exposing-internet-secrets-claims-psiquantum-researcher/)
- [Quantum vs. regular computing time to break ECC?](https://crypto.stackexchange.com/questions/35384/quantum-vs-regular-computing-time-to-break-ecc)
- [Is AES-128 quantum safe? - Cryptography Stack Exchange](https://crypto.stackexchange.com/questions/102671/is-aes-128-quantum-safe)
- [How many decades AES-128 will last? : r/cryptography - Reddit](https://www.reddit.com/r/cryptography/13lp9nf/how_many_decades_aes128_will_last/)
- [AES-256 joins the quantum resistance - Fierce Electronics](https://www.fierceelectronics.com/electronics/aes-256-joins-quantum-resistance)
- [The State of Quantum Computing in 2024: Innovations, Challenges, and ...](https://methodologists.net/Exploring-the-Transformative-Advancements-in-Quantum-Computing-and-Their-Global-Impact-in-2024)
- [The Current State of Quantum Computing - IEEE Computer Society](https://www.computer.org/publications/tech-news/research/current-state-of-quantum-computing)
- [The Quantum Hardware Landscape: Competing Architectures](https://quantumzeitgeist.com/quantum-hardware/)
- [Practical Impacts of Quantum Computing - National Institute of ...](https://www.nist.gov/document/post-quantum-cryptography-and-cybersecurity)
- [Quantum Threat Timeline Report 2024 - Global Risk Institute](https://globalriskinstitute.org/publication/2024-quantum-threat-timeline-report/)
- [The quantum threat to blockchain: summary and timeline analysis](https://link.springer.com/article/10.1007/s42484-023-00105-4)
- [Post-quantum cryptography - Wikipedia](https://en.wikipedia.org/wiki/Post-quantum_cryptography)
- [First Four Quantum-Resistant Cryptographic Algorithms - Embedded](https://www.embedded.com/first-four-quantum-resistant-cryptographic-algorithms/)
- [Microsoft's quantum-resistant cryptography is here](https://techcommunity.microsoft.com/blog/microsoft-security-blog/microsofts-quantum-resistant-cryptography-is-here/4238780)
- [Exploring Elliptic Curve vs. Lattice-Based Cryptography for Future ...](https://medium.com/@RocketMeUpCybersecurity/exploring-elliptic-curve-vs-lattice-based-cryptography-for-future-security-0c8426c97deb)
- [[PDF] Performance Comparisons and Migration Analyses of Lattice-based ...](https://eprint.iacr.org/2020/990.pdf)
- [[PDF] A Survey on Code-based Cryptography - arXiv](https://arxiv.org/pdf/2201.07119)
- [Understanding Lattice-Based Cryptography - Blue Goat Cyber](https://bluegoatcyber.com/blog/understanding-lattice-based-cryptography/)
- [A Survey of Code-Based Cryptography - Clemson University](https://open.clemson.edu/cgi/viewcontent.cgi?article=5227&context=all_theses)
- [NIST Releases First 3 Finalized Post-Quantum Encryption Standards](https://www.nist.gov/news-events/news/2024/08/nist-releases-first-3-finalized-post-quantum-encryption-standards)
- [Post-Quantum Cryptography Is a Must to Protect Your Systems | Gartner](https://www.gartner.com/en/articles/post-quantum-cryptography)
- [Secure Data Infrastructure in a Post-Quantum Cryptographic World](https://futurumgroup.com/research-reports/secure-data-infrastructure-in-a-post-quantum-cryptographic-world/)
- [NCSC Sets 2035 Deadline for Post-Quantum Cryptography Migration](https://www.infosecurity-magazine.com/news/ncsc-post-quantum-cryptography/)
- [PQC (Post-Quantum Cryptography): The New Network Security Threat](https://hackhunting.com/2025/01/11/post-quantum-cryptography-the-new-network-security-threat/)
- [Exploring Post-Quantum Cryptography: Review and Directions for the ...](https://www.mdpi.com/2227-7080/12/12/241)
- [[PDF] a performance comparison of some hash functions in hash-based ...](https://jomardpublishing.com/UploadFiles/Files/journals/JTME/V5N3/KaratayM_et_al.pdf)
- [[PDF] Comparative Analysis of Different Cryptographic Hash Functions](http://www.diva-portal.org/smash/get/diva2:1885074/FULLTEXT01.pdf)
- [Multivariate Cryptography - SpringerLink](https://link.springer.com/referenceworkentry/10.1007/978-3-642-27739-9_421-2)
- [Quantum Key Distribution Protocols: A Review](https://www.iosrjournals.org/iosr-jce/papers/Vol16-issue2/Version-11/A0162110109.pdf)
- [Quantum key distribution - Wikipedia](https://en.wikipedia.org/wiki/Quantum_key_distribution)
- [Practical challenges in quantum key distribution - arXiv.org](https://arxiv.org/abs/1606.05853)
- [Quantum Key Distribution (QKD) and Quantum Cryptography QC](https://www.nsa.gov/Cybersecurity/Quantum-Key-Distribution-QKD-and-Quantum-Cryptography-QC/)
- [Hybrid QKD and PQC security scenarios and use cases Whitepaper](https://www.gsma.com/newsroom/wp-content/uploads//IG.18-Hybrid-QKD-and-PQC-security-scenarios-and-use-cases-Whitepaper-v1.0-002.pdf)
- [Quantum key distribution: Network… | Smart Infrastructure Magazine](https://smartinfrastructuremagazine.com/news/quantum-key-distribution-network-operators-to-spend-6-3-billion-over-next-six-years)

View File

@@ -1,45 +0,0 @@
## Bitcoin Price Fluctuations in the Recent 3 Months
### Executive Summary
This report analyzes Bitcoin price fluctuations over the past three months, based on available search results. The analysis considers market sentiment, regulatory influences, economic factors, and technical analysis indicators. Due to limitations in accessing and processing raw data, the report relies on summarized findings from various sources.
### Key Findings
* **Trump Administration Policies:** Tariffs imposed in April 2025 impacted Bitcoin, causing it to fall from $109K to $84K.
* **Economic Uncertainty:** General economic uncertainty contributed to Bitcoin falling below $90,000.
* **Market Sentiment:** The Crypto Fear and Greed Index reflects the overall market sentiment, which fluctuates based on news and events.
* **Technical Analysis:** Key support levels around $80,400 and $74,000, with resistance levels near $98,500 and $106,000.
### Detailed Analysis
**Influencing Factors:**
* **Regulatory Environment:** The Trump administration's approach to crypto regulation and SEC actions appear to have influenced Bitcoin's price.
* **Market Sentiment:** The Crypto Fear and Greed Index is a key indicator of market sentiment.
* **Trading Volume:** Historical data from Yahoo Finance and Investing.com shows Bitcoin trading volume over the past 3 months.
* **Social Media Sentiment:** Sentiment analysis from platforms like the r/cryptocurrency subreddit and Twitter (X) can provide insights into market perceptions.
* **GBTC Holdings:** Grayscale Bitcoin Trust (GBTC) historical prices and data reflect its holdings.
* **Bitcoin Futures:** Historical data for Bitcoin Futures (BTC=F) is available on Yahoo Finance.
* **Google Trends:** Google Trends data indicates the search popularity of "bitcoin" over time. Recent articles suggest a decline in interest in "bitcoin" and "bitcoin price" searches.
**Price Movements:**
* Bitcoin experienced a drop from $109K to $84K following Trump's tariffs on April 2, 2025.
* Bitcoin fell below $90,000 due to economic uncertainty.
* Key support levels to watch are around $80,400 and $74,000, with resistance levels near $98,500 and $106,000.
### Conclusions and Recommendations
Based on the available information, Bitcoin's price fluctuations in the last three months have been influenced by a combination of regulatory actions, economic conditions, and market sentiment.
**Recommendations:**
* Monitor regulatory developments and their potential impact on the cryptocurrency market.
* Track economic indicators and assess their influence on investor behavior.
* Analyze market sentiment using tools like the Crypto Fear and Greed Index and social media analysis.
* Consider technical analysis indicators to identify potential support and resistance levels.
**Limitations:**
This report is based on summarized search results and lacks access to raw data for comprehensive analysis. Further investigation with detailed data analysis is recommended for more accurate conclusions.

View File

@@ -1,77 +0,0 @@
# Deep Research with Claude: Workflows and Best Practices
## Executive Summary
This report outlines optimal workflows and best practices for integrating Claude into deep research processes, covering data collection, preprocessing, analysis, and synthesis. It also addresses integration with other tools, validation methods, cost management, collaboration strategies, documentation practices, and relevant case studies. Claude can assist in academic writing and research and should be used to support, not replace, original thought.
## Key Findings
* Claude can assist in academic writing and research, but should be used to support, not replace, original thought.
* Claude's Project feature allows uploading relevant documents to reduce repetitive context-setting.
* The AI has a data analysis tool that can write and run JavaScript code to process data and offer insights.
* Claude offers citation tools for verifying sources and ensuring proper formatting.
* Haiku is the fastest and most cost-effective model in its intelligence category.
* Claude can serve as a virtual teammate to advance work.
* Sharing work products created with Claude can improve innovation in product development and research.
* Claude can create technical documentation faster while maintaining consistency.
* Claude integrates with note-taking, writing, and reference management tools.
## Detailed Analysis
### Workflows and Best Practices
* **Define Research Questions:** Clearly define research questions and areas of focus in initial prompts.
* **Structured Data:** Provide relevant data in a structured message.
* **Project Feature:** Use Claude's Project feature to upload relevant documents, reducing the need for repetitive context-setting.
* [Source: [https://support.anthropic.com/en/articles/9797557-usage-limit-best-practices](https://support.anthropic.com/en/articles/9797557-usage-limit-best-practices)]
* **Prompt Engineering:** Employ prompt engineering techniques, such as including "Think step by step," to improve performance.
* [Source: [https://aws.amazon.com/blogs/machine-learning/prompt-engineering-techniques-and-best-practices-learn-by-doing-with-anthropics-claude-3-on-amazon-bedrock/](https://aws.amazon.com/blogs/machine-learning/prompt-engineering-techniques-and-best-practices-learn-by-doing-with-anthropics-claude-3-on-amazon-bedrock/)]
### Data Analysis
* **Data Analysis Tool:** Utilize Claudes built-in data analysis tool, which writes and runs JavaScript code to process data and provide insights.
* [Source: [https://www.anthropic.com/news/analysis-tool](https://www.anthropic.com/news/analysis-tool), [https://support.anthropic.com/en/articles/10008684-enabling-and-using-the-analysis-tool](https://support.anthropic.com/en/articles/10008684-enabling-and-using-the-analysis-tool)]
* **CSV Analysis:** Use the data analysis tool to analyze and visualize data from uploaded CSV files.
* [Source: [https://support.anthropic.com/en/articles/10008684-enabling-and-using-the-analysis-tool](https://support.anthropic.com/en/articles/10008684-enabling-and-using-the-analysis-tool)]
### Validation
* **Citation Tools:** Utilize Claude's citation tools to verify sources and ensure correct formatting for academic rigor.
* [Source: [https://www.yomu.ai/blog/claude-ai-in-academic-writing-and-research-essential-tips-for-optimal-results](https://www.yomu.ai/blog/claude-ai-in-academic-writing-and-research-essential-tips-for-optimal-results)]
* **Prompt Sanitization:** Note that the Anthropic API performs basic prompt sanitization and validation.
* [Source: [https://docs.anthropic.com/en/api/prompt-validation](https://docs.anthropic.com/en/api/prompt-validation)]
### Cost Management
* **Model Selection:** Consider using the Haiku model for cost-effective performance in its intelligence category.
* [Source: [https://www.anthropic.com/news/claude-3-family](https://www.anthropic.com/news/claude-3-family)]
### Collaboration
* **Virtual Teammate:** Leverage Claude as a virtual teammate to move work forward.
* [Source: [https://www.anthropic.com/team](https://www.anthropic.com/team)]
* **Shared Work Products:** Share work products co-created with Claude to foster innovation, particularly in product development and research.
* [Source: [https://www.anthropic.com/news/projects](https://www.anthropic.com/news/projects)]
### Documentation
* **Technical Documentation:** Use Claude to create technical documentation more efficiently and maintain consistency.
* [Source: [https://beginswithai.com/how-to-use-claude-ai-to-create-technical-documentation/](https://beginswithai.com/how-to-use-claude-ai-to-create-technical-documentation/)]
### Integration with Other Tools
* **Note-Taking and Writing Tools:** Integrate Claude with note-taking and writing tools such as Evernote, OneNote, or Google Docs.
* [Source: [https://beginswithai.com/using-claude-for-research/](https://beginswithai.com/using-claude-for-research/)]
* **Reference Management Tools:** Work with reference management tools like Zotero, Mendeley, and EndNote.
* [Source: [https://beginswithai.com/using-claude-for-research/](https://beginswithai.com/using-claude-for-research/)]
* **Platform Integration:** Ensure smooth integration with platforms like Anthropic API and Google Cloud's Vertex AI.
* [Source: [https://www.yomu.ai/blog/claude-ai-in-academic-writing-and-research-essential-tips-for-optimal-results](https://www.yomu.ai/blog/claude-ai-in-academic-writing-and-research-essential-tips-for-optimal-results)]
### Case Studies
* **Diverse Applications:** Explore case studies that demonstrate the successful use of Claude in various domains, including whale conservation, brand management, cybersecurity, hiring, insurance, code review, customer service, and sales.
* [Source: [https://www.anthropic.com/customers](https://www.anthropic.com/customers)]
## Conclusions and Recommendations
Claude is a valuable tool for deep research if used strategically. By defining clear research questions, providing structured data, and utilizing Claude's project features, researchers can maximize its potential. The AI's data analysis capabilities, especially with CSV files, offer real-time insights. Validating Claude's outputs through citation tools and careful prompt engineering is essential for accuracy. Collaboration features enhance teamwork, and integrations with other research tools streamline workflows. The case studies show the broad applicability of Claude across different fields, highlighting its versatility and potential impact.

View File

@@ -1,72 +0,0 @@
# Nanjing Tangbao: A Culinary Specialty
## Key Points
- Nanjing Tangbao are soup-filled dumplings with a rich history and cultural significance in Nanjing, dating back to the Ming and Qing Dynasties.
- Key characteristics include a thin, almost translucent skin, a generous amount of rich broth, and a savory filling, often featuring minced pork and flavorful seasonings.
- Modern adaptations of Tangbao include variations in size, skin thickness, and filling, with some preferring the Nanjing style over the Shanghai Xiaolongbao.
- Numerous restaurants and street food stalls specialize in Tangbao, with Yinshi Jishi Tangbao and Fuzimiao being frequently recommended establishments.
- Tourism in Nanjing significantly impacts the popularity and availability of Nanjing Tangbao, contributing to the protection of cultural heritage and the growth of related industries.
- Preparation involves making a gelatinous pork stock (aspic) that melts into soup when steamed, and high-quality pork is crucial for authentic taste and texture.
## Overview
Nanjing Tangbao, also known as soup dumplings, are a traditional delicacy in Nanjing. They have a long history and are culturally significant to the region. These soup-filled buns are known for their flavorful broth and savory filling encased in a delicate wrapper. The meticulous preparation and unique characteristics contribute to their cultural significance in Nanjing.
## Detailed Analysis
### Historical and Cultural Significance
Nanjing Tangbao has a high reputation dating back to the Ming and Qing Dynasties. Nanjing, as a city with a rich history, features Tangbao as one of its culinary specialties. The rise of tourism in Nanjing promotes the protection of tangible and intangible cultural heritage.
### Characteristics and Ingredients
Nanjing Tangbao are characterized by a thin skin and lots of soup. The Nanjing style Tangbao is smaller, with an almost translucent skin and less meat, which has become a preferred style. Key ingredients include minced pork, soy sauce, ginger, garlic, sesame oil, Shaoxing wine, and a gelatinous pork stock (aspic) that creates the soup.
### Preparation
The preparation of Nanjing Tangbao involves several key steps: marinating the pork, making the aspic, preparing the dough for the wrappers, filling the dumplings, and steaming them. The sourcing of high-quality pork and the careful preparation of the aspic are crucial for achieving the authentic taste and texture.
### Modern Adaptations and Variations
Modern adaptations of Xiao Long Bao are considered by some to be Nanjing Tangbao. Nanjing's Tangbao is slightly different from Shanghais Xiaolongbao, being larger with a generous amount of rich broth inside, often served with a straw.
### Notable Establishments
Several establishments in Nanjing are renowned for their Tangbao offerings. Yinshi Jishi Tangbao at No. 398 Mochou Road is a recommended place to try Tangbao. Fuzimiao (Confucius Temple) and Hunan Road are also known for their Tangbao. Other famous restaurants include Zhiwei Guan and Zhu Yansheng Tang Bao. Liu Changxing restaurant is recommended for those who prefer more savory dumplings.
### Impact of Tourism
The development of Nanjing tourism directly promotes the growth of local transportation, hotels, and retail stores. Tourism significantly impacts the popularity and availability of Nanjing Tangbao, contributing to the protection of cultural heritage and the growth of related industries.
### Images of Nanjing Tangbao
![Nanjing Tangbao](https://cdn.tasteatlas.com/Images/Dishes/126cfc45688546f19620ac483dfaecb7.jpg)
![Tangbao Dumpling](https://livingnomads.com/wp-content/uploads/2023/10/04/Nanjing-China-Food_Tangbao3.jpg)
## Key Citations
- [What to eat in Nanjing? — 11+ best Nanjing street food & Nanjing famous ...](https://livingnomads.com/2023/10/nanjing-street-food/)
- [Tang Bao 汤包 - Chinese Food | Study in China](https://www.istudy-china.com/tang-bao-%E6%B1%A4%E5%8C%85-chinese-food/)
- [Jia Jia Tang Bao, Shanghai - Best xiao long bao in Shanghai? - Foodnut.com](https://www.foodnut.com/590/jia-jia-tang-bao-restaurant-review-shanghai/)
- [Jia Jia Tang Bao : Shanghai | Xtreme Foodies](https://www.xtremefoodies.com/food-category/Steamed/review/Jia-Jia-Tang-Bao/Xiaolongbao/7186_4288)
- [Culinary Delights of the South Capital: Top 10 Foods to Eat in Nanjing](https://chinatraveltales.com/article/culinary-delights-of-the-south-capital-top-10-foods-to-eat-in-nanjing)
- [Top 10 Nanjing Food You Must Try - Trip.com](https://www.trip.com/guide/food/nanjing-food.html)
- [8 Must-Eats In Nanjing - hiredchina.com](https://www.hiredchina.com/articles/8-must-eats-in-nanjing/)
- [PDF] On Study of “Macro-tourism” Industry Theory](https://ccsenet.org/journal/index.php/ijbm/article/download/3779/3389)
- [Easy Tangbao Recipe for Juicy Soup Dumplings - altadiscus.com](https://altadiscus.com/tangbao-recipe/)
- [Tangbao Authentic Recipe - TasteAtlas](https://www.tasteatlas.com/tangbao/recipe)
- [Tangbao - Wikipedia](https://en.wikipedia.org/wiki/Tangbao)
- [Xiaolongbao - ArcGIS StoryMaps](https://storymaps.arcgis.com/stories/088f5531b41547b7b2e022142ad74953)

View File

@@ -1,128 +0,0 @@
# OpenAI Sora Usage Report
## Key Points
* Sora is OpenAI's text-to-video model that generates videos from text prompts and can extend existing short videos. It was released publicly for ChatGPT Plus and ChatGPT Pro users in December 2024.
* Currently, access to Sora is limited, primarily granted to selected developers, visual artists, designers, and filmmakers for testing and feedback purposes. The API is not yet publicly available.
* Sora allows users to generate videos with customizable resolutions up to 1080p and lengths up to 20 seconds, supporting various aspect ratios and the incorporation of user-provided assets.
* Sora is capable of generating videos in diverse styles, applying camera angles, motion, and lighting effects, and mimicking realistic or imaginative scenarios based on text prompts.
* Limitations include potential inaccuracies in simulating physics, biases, and ethical concerns related to deepfakes and misinformation, which OpenAI is addressing with content moderation and community-driven guidelines.
* Geographically, Sora is available in over 150 countries but remains inaccessible in the European Union and the UK due to regulatory challenges and a prioritized rollout to US users.
---
## Overview
OpenAI's Sora is a text-to-video model designed to generate short video clips based on user-provided text prompts. Launched in December 2024, Sora represents a significant advancement in AI-driven content creation, allowing users to bring imaginative scenarios to life through video. However, its release is accompanied by both excitement and concerns regarding its capabilities, limitations, and ethical implications.
---
## Detailed Analysis
### Functionalities and Capabilities
Sora offers a range of functionalities, including:
* **Text-to-Video Generation**: Creating realistic and imaginative videos from text prompts.
* **Video Editing**: Options for remixing, re-cutting, looping, blending, and storyboarding video content.
* **Prompt Interpretation**: Generating videos that mimic real-world scenes or bring to life imaginative scenarios.
* **Video Styles and Content**: Generating videos in various styles, from realistic to artistic.
Sora is capable of applying various camera angles, motion, and lighting effects to the generated videos. Specific camera movements like pan, tilt, dolly, zoom, and more can be directed using detailed prompts.
### Access and Availability
Currently, access to Sora is limited. It is primarily available to selected developers, visual artists, designers, and filmmakers for the purpose of testing, gathering feedback, and assessing potential weaknesses and risks. The API is not yet publicly available, and OpenAI has not specified a concrete timeline for broader access. It was released publicly for ChatGPT Plus and ChatGPT Pro users in December 2024.
Geographical availability is also restricted. While Sora is available in more than 150 countries, it is currently inaccessible in the European Union and the UK due to specific EU regulations regarding AI use and an initial focus on US users.
### Content Limitations and Restrictions
Sora has several limitations and restrictions:
* **Resolution and Length**: Videos can be generated up to 1080p resolution, with lengths up to 20 seconds for ChatGPT Pro users and 10 seconds for ChatGPT Plus users. Lower resolutions, such as 480p, are also available.
* **Complexity**: The model sometimes struggles with realistic physics and complex actions over long durations.
* **Content Restrictions**: There are age restrictions, allowing only adults (above 18 years) to use the tool, and visual content depicting minors is prohibited. There are limitations in depicting humans; for now, only a small group of selected testers can create human-like videos.
* **Biases and Inaccuracies**: Sora may not always understand the entire context of a prompt, leading to inaccurate or irrelevant outputs and potential biases perpetuating stereotypes.
### Ethical Considerations and Policies
Sora raises ethical concerns related to the creation of deepfakes and the potential spread of misinformation. OpenAI is aware of these concerns and is implementing policies and safeguards to address them:
* **Content Moderation**: Features to promote responsible use and prohibit harmful content.
* **Community Guidelines**: Community-driven guidelines to ensure Sora responds to cultural diversity.
* **Limited Initial Access**: Limiting initial access to a carefully chosen group to understand and address concerns before wider release.
### Potential Applications and Impact
Sora has potential applications in filmmaking, advertising, education, and gaming. It can revolutionize content creation by enabling the creation of realistic and personalized video content and transform educational materials and marketing campaigns.
However, Sora also has the potential to cause job displacement across various industries, raising concerns about fair compensation for intellectual property rights holders and artists.
---
## Key Citations
- [OpenAI Sora: Text to Video generation - ElevenLabs](https://elevenlabs.io/blog/openai-sora)
- [Sora (text-to-video model) - Wikipedia](https://en.wikipedia.org/wiki/Sora_(text-to-video_model))
- [Introducing OpenAI's Sora: Revolutionizing Text-to-Video Conversion](https://pcsocial.medium.com/introducing-openais-sora-revolutionizing-text-to-video-conversion-b99b37a71e55)
- [OpenAI Sora Is Here! How to Access It and Feature Overview](https://blog.vive.com/us/openai-sora-is-here-how-to-access-it-and-feature-overview/)
- [What Is OpenAI's Sora? How It Works, Examples, Features](https://www.datacamp.com/blog/openai-announces-sora-text-to-video-generative-ai-is-about-to-go-mainstream)
- [Six Top Features of Sora, OpenAI's New AI Video Creation Platform](https://www.maginative.com/article/six-top-features-of-sora-openais-new-ai-video-creation-platform/)
- [The Ultimate Guide to Sora AI + Prompts and Examples - SaaS Genius](https://www.saasgenius.com/blog-business/the-ultimate-guide-to-sora/)
- [17 Best OpenAI Sora AI Video Examples (2025) - SEO.AI](https://seo.ai/blog/openai-sora-examples)
- [OpenAI's Sora Video Generator Is Now Available...But Not to All](https://tech.co/news/openai-sora-video-generator-launch)
- [Generating videos on Sora | OpenAI Help Center](https://help.openai.com/en/articles/9957612-generating-videos-on-sora)
- [OpenAI Limits Sora Access After Higher-Than-Expected Demand](https://www.pcmag.com/news/openai-releases-sora-video-generator-will-it-simplify-or-destroy-filmmaking)
- [My OpenAI's Sora video generator review: Is it worth the hype?](https://techpoint.africa/guide/openai-sora-video-generator-review/)
- [OpenAI disables video gen for certain Sora users as capacity ...](https://techcrunch.com/2025/03/31/openai-disables-video-gen-for-certain-sora-users-as-capacity-challenges-continue/)
- [Feedback on Sora Text-to-Video Generator. Disappointed - ChatGPT](https://community.openai.com/t/feedback-on-sora-text-to-video-generator-disappointed/1079553)
- [10 Best Sora AI Prompts For Viral Videos - AI Tools](https://www.godofprompt.ai/blog/10-best-sora-ai-prompts-for-viral-videos?srsltid=AfmBOopcJdIgojxyXbT5TbGxgnr5ijJJAn0dp3wn8net2BmqUzKzCSzS)
- [Crafting Cinematic Sora Video Prompts: A complete guide · GitHub](https://gist.github.com/ruvnet/e20537eb50866b2d837d4d13b066bd88)
- [How to Use OpenAI Sora: A Step-by-Step Guide - Alicia Lyttle](https://alicialyttle.com/how-to-use-openai-sora-ai-video-generator/)
- [Sora: Creating video from text - OpenAI](https://openai.com/index/sora/)
- [Is OpenAI Sora API Available? And How to Use it? - Apidog](https://apidog.com/blog/openai-sora-api/)
- [Sora is here - OpenAI](https://openai.com/index/sora-is-here/)
- [Understanding OpenAI Sora: Features, Uses, and Limitations](https://digitalguider.com/blog/openai-sora/)
- [Sora's Limitations, Hidden Features and Capabilities (2025)](https://618media.com/en/blog/soras-limitations-and-its-capabilities/)
- [OpenAI Unveils AI Video Generator Sora, But Limits Human Depictions](https://vocal.media/futurism/open-ai-unveils-ai-video-generator-sora-but-limits-human-depictions)
- [How to Access Sora in Europe? - Swiftask](https://www.swiftask.ai/blog/comment-acceder-a-sora-en-europe)
- [How to access Sora AI in UK and EU 2025 - VPNpro](https://vpnpro.com/guides-and-tutorials/how-to-access-sora/)
- [The Rise of Sora: OpenAI's Frontier in Generative Video Innovation](https://www.launchconsulting.com/posts/the-rise-of-sora-openais-frontier-in-generative-video-innovation)
- [Meet Sora— OpenAI's Latest Innovation to Bridge the Gap Between Text and Visuals](https://www.practicallogix.com/meet-sora-openais-latest-innovation-to-bridge-the-gap-between-text-and-visuals/)
- [Do you think the potential use of OpenAI's Sora for creating AI ...](https://www.quora.com/Do-you-think-the-potential-use-of-OpenAIs-Sora-for-creating-AI-deepfakes-are-outweighed-by-the-risks)
- [What We Know About OpenAI's Sora So Far](https://www.unite.ai/what-we-know-about-openais-sora-so-far/)
- [What is OpenAI's Sora? and How to Use it? - Great Learning](https://www.mygreatlearning.com/blog/what-is-sora-and-how-to-use-it/)
- [SORA By Open AI To Kill Off Jobs: Bane or Boon? - Be10X](https://be10x.in/blog/sora-by-open-ai-to-kill-off-jobs-bane-or-boon/)
- [OpenAI Is Ready for Hollywood to Accept Its Vision](https://www.hollywoodreporter.com/business/business-news/openai-hollywood-sora-1236170402/)

View File

@@ -1,54 +0,0 @@
# Google's Agent to Agent Protocol Report
## Key Points
- Google's Agent2Agent (A2A) protocol standardizes communication between AI agents, promoting collaboration across diverse systems.
- A2A facilitates message exchange for sharing context, instructions, and artifacts between agents.
- The protocol complements Anthropic's Model Context Protocol (MCP) by providing a networking layer for agents.
- A2A allows agents to negotiate content formats, supporting diverse media types such as iframes and video.
- Google intends A2A to be an open, community-driven project to foster innovation and adoption.
- Industry experts anticipate A2A will accelerate AI adoption by simplifying integrations and data exchange.
---
## Overview
Google's Agent2Agent (A2A) protocol is designed to establish a standardized method for AI agents to communicate, irrespective of their origin, framework, or location. This initiative seeks to foster seamless collaboration and collective intelligence among AI agents, thereby enhancing the effectiveness of agentic solutions. A2A operates as a networking layer that complements other protocols such as Anthropic's Model Context Protocol (MCP), contributing to a more unified AI agent ecosystem.
---
## Detailed Analysis
### Purpose and Design
A2A addresses the challenge of integrating disparate AI systems by providing a common language for AI agents. It enables these agents to share context, replies, artifacts, and user instructions, facilitating collaborative problem-solving. The design of A2A supports flexible user experiences by allowing agents to negotiate content formats like iframes, videos, and web forms.
### Technical Aspects
The protocol utilizes "parts" within messages, which are fully formed pieces of content with specified content types, enabling negotiation of the correct format needed between agents. A2A builds upon existing standards including HTTP, SSE, and JSON-RPC.
### Community and Industry Impact
Google's vision for A2A is to create an open, community-driven project that encourages contributions and updates from the open-source community. Industry experts from companies like Deloitte, Accenture, EPAM, and New Relic believe A2A will accelerate AI adoption by simplifying integrations, facilitating data exchange, and fostering a more unified AI agent ecosystem. LangChain has also expressed interest in collaborating with Google Cloud on this shared protocol.
### Relationship with MCP
A2A complements Anthropic's Model Context Protocol (MCP). While A2A provides a networking layer for agents to communicate, MCP functions as a plugin system, granting agents access to tools, context, and data.
---
## Key Citations
- [Announcing the Agent2Agent Protocol (A2A)](https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/)
- [Build and manage multi-system agents with Vertex AI - Google Cloud](https://cloud.google.com/blog/products/ai-machine-learning/build-and-manage-multi-system-agents-with-vertex-ai)
- [Google just Launched Agent2Agent, an Open Protocol for AI agents ...](https://www.maginative.com/article/google-just-launched-agent2agent-an-open-protocol-for-ai-agents-to-work-directly-with-each-other/)
- [Protocols for Agentic AI: Google's New A2A Joins Viral MCP](https://virtualizationreview.com/articles/2025/04/09/protocols-for-agentic-ai-googles-new-a2a-joins-viral-mcp.aspx)
- [Google's Agent2Agent interoperability protocol aims to standardize ...](https://venturebeat.com/ai/googles-agent2agent-interoperability-protocol-aims-to-standardize-agentic-communication/)
- [Meet Google A2A: The Protocol That will Revolutionize Multi-Agent ...](https://medium.com/@the_manoj_desai/meet-google-a2a-the-protocol-that-will-revolutionize-multi-agent-ai-systems-80d55a4583ed)
- [Google's Agent2Agent Protocol Helps AI Agents Talk to Each Other](https://thenewstack.io/googles-agent2agent-protocol-helps-ai-agents-talk-to-each-other/)

View File

@@ -1,106 +0,0 @@
## Report on Large Language Models (LLMs)
This report provides a comprehensive overview of Large Language Models (LLMs), covering their definition, architecture, training, applications, limitations, biases, ethical considerations, and mitigation strategies, based on the provided search results.
### Executive Summary
LLMs are deep learning models that use transformer architecture and are trained on massive datasets. They excel at various Natural Language Processing (NLP) tasks, including text generation, translation, and question answering. However, they also present limitations, biases, and ethical challenges that need to be addressed for responsible development and deployment.
### Key Findings
* **Definition and Architecture**: LLMs are deep learning algorithms that perform NLP tasks using transformer models and are trained on massive datasets. They consist of encoders, decoders, and attention mechanisms, with key components like embedding layers and attention mechanisms.
* **Training Data and Methodologies**: LLMs are trained on datasets like Common Crawl (5.4 trillion tokens) and The Pile (800 GB). Training methodologies include unsupervised pre-training, supervised fine-tuning, and transfer learning.
* **Applications**: LLMs are used in text generation, machine translation, question answering, code generation, text summarization, and sentiment analysis.
* **Performance Benchmarks**: LLM performance is evaluated using metrics like accuracy, precision, recall, F1 score, BLEU, ROUGE, perplexity, and HumanEval (pass@k).
* **Limitations**: LLMs have computational constraints, struggle with complex linguistic elements, lack long-term memory, and can perpetuate biases.
* **Biases**: LLMs exhibit gender, racial, cultural, and socio-economic stereotypes due to biases in their training data.
* **Ethical Considerations**: LLMs raise ethical concerns about misuse, privacy, and accountability.
* **Mitigation Strategies**: Mitigation strategies include data curation, model adjustments, and post-processing techniques.
### Detailed Analysis
#### Definition and Architecture
LLMs are a specific type of generative AI designed for text-based content generation. They leverage deep learning algorithms and transformer models to perform various NLP tasks. A typical LLM architecture includes:
* **Embedding Layer**: Converts input text into numerical embeddings, capturing semantic and syntactic meaning.
* **Attention Mechanism**: Allows the model to focus on relevant parts of the input text.
* **Transformer Models**: A tokenizer converts text into numerical values (tokens), and encoders create meaningful embeddings.
LLMs typically have at least one billion or more parameters.
#### Training Data and Methodologies
LLMs require vast amounts of data for effective training. Some key datasets include:
* **Common Crawl**: 5.4 trillion tokens
* **Cosmopedia**: 25 billion tokens
* **The Pile**: 800 GB
Training methodologies include:
* **Unsupervised Pre-training**: Learning general language representations.
* **Supervised Fine-tuning**: Adapting models to specific tasks.
* **Transfer Learning**: Leveraging knowledge gained from one task to improve performance on another.
#### Applications
LLMs have a wide array of applications across various domains:
* **Text Generation**: Creating coherent and contextually relevant text.
* **Machine Translation**: Converting text from one language to another.
* **Question Answering**: Providing answers to questions posed in natural language.
* **Code Generation**: Generating code snippets or complete programs.
* **Text Summarization**: Condensing large amounts of text into shorter summaries.
* **Sentiment Analysis**: Determining the emotional tone or attitude expressed in text.
#### Performance Benchmarks and Evaluation Metrics
Evaluating LLM performance involves using standardized benchmarks and metrics. Key metrics include:
* **Accuracy**: Measures the correctness of the model's outputs.
* **Precision and Recall**: Assess the relevance and completeness of the results.
* **F1 Score**: Provides a balanced measure of precision and recall.
* **BLEU and ROUGE**: Evaluate the quality of machine-translated or summarized text.
* **Perplexity**: Measures the uncertainty of the model in predicting the next word in a sequence.
* **HumanEval (pass@k)**: Assesses code generation performance.
#### Limitations, Biases, and Ethical Considerations
LLMs face several limitations:
* **Computational Constraints**: Limited by fixed token limits.
* **Complex Linguistic Elements**: Struggle with nuanced language.
* **Lack of Long-Term Memory**: Difficulty retaining information over extended contexts.
* **Perpetuation of Biases**: Reinforce stereotypes from training data.
Biases in LLMs can manifest as:
* **Gender Stereotypes**: Skewed outputs based on gender.
* **Racial Stereotypes**: Unfair representations of different racial groups.
* **Cultural Stereotypes**: Biased outputs related to specific cultures.
Ethical considerations include:
* **Potential Misuse**: Disinformation and manipulation.
* **Privacy Issues**: Data usage and potential exposure of personal information.
* **Accountability Challenges**: Difficulty in tracing the reasoning processes of LLMs.
#### Mitigation Strategies
Various strategies can be employed to mitigate limitations and biases:
* **Data Curation**: Refining training data to reduce biases.
* **Model Adjustments**: Implementing fairness constraints during training.
* **Post-processing Corrections**: Fine-tuning outputs to reduce biases.
* **Resampling and Augmentation**: Balancing and expanding the training dataset.
### Conclusions and Recommendations
LLMs are powerful tools with a wide range of applications, but they are not without limitations and risks. Addressing these challenges requires:
* **Ongoing Research**: Continued investigation into biases, limitations, and mitigation strategies.
* **Ethical Frameworks**: Development of updated ethical guidelines for responsible development and deployment.
* **Collaboration**: Interdisciplinary efforts involving researchers, developers, and policymakers.
* **Data Transparency**: Increased transparency about training data and model development processes.
* **Careful Implementation**: Strategic application of mitigation techniques to avoid unintended performance trade-offs.

View File

@@ -1,51 +0,0 @@
# Anthropic Model Context Protocol (MCP) Report
## Key Points
* Anthropic's Model Context Protocol (MCP) is an open standard introduced in late November 2024, designed to standardize how AI models interact with external data and tools.
* MCP acts as a universal interface, similar to a "USB port," facilitating easier integration of AI models with various data sources and services without custom integrations.
* Anthropic focuses on developer experience with MCP, aiming to simplify integration and enhance the utility of AI models in real-world scenarios.
* MCP faces scalability challenges, particularly in distributed cloud environments, which Anthropic addresses through remote server support with robust security measures.
* User testimonials and case studies from Anthropic highlight improvements in talent acquisition, knowledge worker productivity, developer productivity, search, productivity, and investment analysis.
---
## Overview
Anthropic's Model Context Protocol (MCP) is an open standard introduced in late November 2024, designed to standardize how AI models, especially Large Language Models (LLMs), interact with external data sources and tools. It addresses the challenge of integrating AI systems by providing a universal interface that allows models to access relevant context and perform actions on other systems. The protocol aims to break AI systems out of isolation by making them easily integrable with various data sources and services, promoting a more scalable and efficient approach to AI application development.
---
## Detailed Analysis
### Definition and Purpose
Anthropic's Model Context Protocol (MCP) functions as a universal interface, akin to a "USB port," enabling AI models to interact seamlessly with external data sources and tools. This standardization simplifies integration processes and enables AI systems to access relevant context and execute actions on other systems more efficiently. The protocol facilitates two-way communication, empowering models to fetch data and trigger actions via standardized messages.
### Performance
Anthropic's strategic focus with MCP centers on enhancing the developer experience rather than solely optimizing raw model performance. This approach differentiates them from companies prioritizing larger, more powerful models. MCP is geared towards streamlining the integration and utility of existing models within practical, real-world workflows. Key quantitative metrics for evaluating LLM performance include F1 score, BLEU score, perplexity, accuracy, precision, and recall.
### Scalability
MCP encounters scalability challenges, particularly within distributed cloud environments. Anthropic is actively addressing these issues by developing remote server support, which includes robust authentication, encryption, and potentially brokered connections to accommodate enterprise-scale deployments. MCP offers a more scalable methodology for managing context and instructions for intricate AI applications by delivering specific "policy" context precisely when required.
### User Testimonials and Case Studies
Anthropic provides case studies demonstrating how customers utilize Claude, showcasing improvements in talent acquisition, knowledge worker productivity, developer productivity, search and productivity, and investment analysis. These examples illustrate the practical benefits and versatility of Anthropic's AI solutions.
---
## Key Citations
- [Create strong empirical evaluations - Anthropic API](https://docs.anthropic.com/en/docs/build-with-claude/develop-tests)
- [Define your success criteria - Anthropic API](https://docs.anthropic.com/en/docs/build-with-claude/define-success)
- [The Model Context Protocol (MCP) by Anthropic: Origins ... - Wandb](https://wandb.ai/onlineinference/mcp/reports/The-Model-Context-Protocol-MCP-by-Anthropic-Origins-functionality-and-impact--VmlldzoxMTY5NDI4MQ)
- [Anthropic introduces open source Model Context Protocol to boost ...](https://www.techmonitor.ai/digital-economy/ai-and-automation/anthropic-introduces-open-source-mcp-to-simplify-ai-system-integrations)
- [Anthropic's Model Context Protocol: Building an 'ODBC for AI' in an ...](https://salesforcedevops.net/index.php/2024/11/29/anthropics-model-context-protocol/)
- [Customers - Anthropic](https://www.anthropic.com/customers)

View File

@@ -1,11 +0,0 @@
{
"dockerfile_lines": [],
"graphs": {
"deep_research": "./src/workflow.py:graph",
"podcast_generation": "./src/podcast/graph/builder.py:workflow",
"ppt_generation": "./src/ppt/graph/builder.py:workflow"
},
"python_version": "3.12",
"env": "./.env",
"dependencies": ["."]
}

191
main.py
View File

@@ -1,191 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Entry point script for the DeerFlow project.
"""
import argparse
import asyncio
from InquirerPy import inquirer
from src.config.questions import BUILT_IN_QUESTIONS, BUILT_IN_QUESTIONS_ZH_CN
from src.workflow import run_agent_workflow_async
def ask(
question,
debug=False,
max_plan_iterations=1,
max_step_num=3,
enable_background_investigation=True,
enable_clarification=False,
max_clarification_rounds=None,
locale=None,
):
"""Run the agent workflow with the given question.
Args:
question: The user's query or request
debug: If True, enables debug level logging
max_plan_iterations: Maximum number of plan iterations
max_step_num: Maximum number of steps in a plan
enable_background_investigation: If True, performs web search before planning to enhance context
enable_clarification: If False (default), skip clarification; if True, enable multi-turn clarification
max_clarification_rounds: Maximum number of clarification rounds (default: None, uses State default=3)
locale: The locale setting (e.g., 'en-US', 'zh-CN')
"""
asyncio.run(
run_agent_workflow_async(
user_input=question,
debug=debug,
max_plan_iterations=max_plan_iterations,
max_step_num=max_step_num,
enable_background_investigation=enable_background_investigation,
enable_clarification=enable_clarification,
max_clarification_rounds=max_clarification_rounds,
locale=locale,
)
)
def main(
debug=False,
max_plan_iterations=1,
max_step_num=3,
enable_background_investigation=True,
enable_clarification=False,
max_clarification_rounds=None,
):
"""Interactive mode with built-in questions.
Args:
enable_background_investigation: If True, performs web search before planning to enhance context
debug: If True, enables debug level logging
max_plan_iterations: Maximum number of plan iterations
max_step_num: Maximum number of steps in a plan
enable_clarification: If False (default), skip clarification; if True, enable multi-turn clarification
max_clarification_rounds: Maximum number of clarification rounds (default: None, uses State default=3)
"""
# First select language
language = inquirer.select(
message="Select language / 选择语言:",
choices=["English", "中文"],
).execute()
# Set locale based on language
locale = "en-US" if language == "English" else "zh-CN"
# Choose questions based on language
questions = (
BUILT_IN_QUESTIONS if language == "English" else BUILT_IN_QUESTIONS_ZH_CN
)
ask_own_option = (
"[Ask my own question]" if language == "English" else "[自定义问题]"
)
# Select a question
initial_question = inquirer.select(
message=(
"What do you want to know?" if language == "English" else "您想了解什么?"
),
choices=[ask_own_option] + questions,
).execute()
if initial_question == ask_own_option:
initial_question = inquirer.text(
message=(
"What do you want to know?"
if language == "English"
else "您想了解什么?"
),
).execute()
# Pass all parameters to ask function
ask(
question=initial_question,
debug=debug,
max_plan_iterations=max_plan_iterations,
max_step_num=max_step_num,
enable_background_investigation=enable_background_investigation,
enable_clarification=enable_clarification,
max_clarification_rounds=max_clarification_rounds,
locale=locale,
)
if __name__ == "__main__":
# Set up argument parser
parser = argparse.ArgumentParser(description="Run the Deer")
parser.add_argument("query", nargs="*", help="The query to process")
parser.add_argument(
"--interactive",
action="store_true",
help="Run in interactive mode with built-in questions",
)
parser.add_argument(
"--max_plan_iterations",
type=int,
default=1,
help="Maximum number of plan iterations (default: 1)",
)
parser.add_argument(
"--max_step_num",
type=int,
default=3,
help="Maximum number of steps in a plan (default: 3)",
)
parser.add_argument("--debug", action="store_true", help="Enable debug logging")
parser.add_argument(
"--no-background-investigation",
action="store_false",
dest="enable_background_investigation",
help="Disable background investigation before planning",
)
parser.add_argument(
"--enable-clarification",
action="store_true",
dest="enable_clarification",
help="Enable multi-turn clarification for vague questions (default: disabled)",
)
parser.add_argument(
"--max-clarification-rounds",
type=int,
dest="max_clarification_rounds",
help="Maximum number of clarification rounds (default: 3)",
)
args = parser.parse_args()
if args.interactive:
# Pass command line arguments to main function
main(
debug=args.debug,
max_plan_iterations=args.max_plan_iterations,
max_step_num=args.max_step_num,
enable_background_investigation=args.enable_background_investigation,
enable_clarification=args.enable_clarification,
max_clarification_rounds=args.max_clarification_rounds,
)
else:
# Parse user input from command line arguments or user input
if args.query:
user_query = " ".join(args.query)
else:
# Loop until user provides non-empty input
while True:
user_query = input("Enter your query: ")
if user_query is not None and user_query != "":
break
# Run the agent workflow with the provided parameters
ask(
question=user_query,
debug=args.debug,
max_plan_iterations=args.max_plan_iterations,
max_step_num=args.max_step_num,
enable_background_investigation=args.enable_background_investigation,
enable_clarification=args.enable_clarification,
max_clarification_rounds=args.max_clarification_rounds,
)

View File

@@ -1,38 +0,0 @@
#!/bin/sh
# Run make lint
echo "Running linting..."
make lint
LINT_RESULT=$?
if [ $LINT_RESULT -ne 0 ]; then
echo "❌ Linting failed. Please fix the issues and try committing again."
exit 1
fi
# Run make format
echo "Running formatting..."
make format
FORMAT_RESULT=$?
if [ $FORMAT_RESULT -ne 0 ]; then
echo "❌ Formatting failed. Please fix the issues and try committing again."
exit 1
fi
# Check license headers
echo "Checking license headers..."
make check-license-all
LICENSE_RESULT=$?
if [ $LICENSE_RESULT -ne 0 ]; then
echo "❌ Some files are missing license headers."
echo "Run 'make add-license-all' to add them automatically."
exit 1
fi
# If any files were reformatted, add them back to staging
git diff --name-only | xargs -I {} git add "{}"
echo "✅ Pre-commit checks passed!"
exit 0

View File

@@ -1,99 +0,0 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "deer-flow"
version = "0.1.0"
description = "DeerFlow project"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"httpx>=0.28.1",
# LangChain 1.x core packages
"langchain>=1.0.0",
"langchain-core>=1.2.5",
"langchain-community>=0.3.19",
"langchain-experimental>=0.3.4",
"langchain-openai>=0.3.8",
"langchain-text-splitters>=0.3.6",
# LangGraph
"langgraph>=0.3.5",
# Other dependencies
"readabilipy>=0.3.0",
"python-dotenv>=1.0.1",
"socksio>=1.0.0",
"markdownify>=1.1.0",
"fastapi>=0.110.0",
"uvicorn>=0.27.1",
"sse-starlette>=1.6.5",
"pandas>=2.2.3",
"numpy>=2.2.3",
"yfinance>=0.2.54",
"litellm>=1.63.11",
"json-repair>=0.7.0",
"jinja2>=3.1.3",
"duckduckgo-search>=8.0.0",
"ddgs>=9.0.0",
"inquirerpy>=0.3.4",
"arxiv>=2.2.0",
"mcp>=1.11.0",
"langchain-mcp-adapters>=0.0.9",
"langchain-deepseek>=0.1.3",
"langchain-google-genai>=2.0.6",
"wikipedia>=1.4.0",
"langchain-tavily>=0.2.0",
"langgraph-checkpoint-mongodb>=0.1.4",
"langgraph-checkpoint-postgres==2.0.21",
"pymilvus>=2.3.0",
"langchain-milvus>=0.2.1",
"psycopg[binary]>=3.2.9",
"qdrant-client>=1.15.1",
"langchain-qdrant>=0.2.0",
"orjson>=3.11.5",
]
[project.optional-dependencies]
dev = [
"ruff",
"langgraph-cli[inmem]>=0.2.10",
]
test = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"pytest-asyncio>=1.0.0",
"pytest-cov>=6.0.0",
"asyncpg-stubs>=0.30.2",
"mongomock>=4.3.0",
"pytest-postgresql>=7.0.2",
]
[tool.uv]
required-version = ">=0.6.15"
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
addopts = "-v --cov=src --cov-report=term-missing"
filterwarnings = [
"ignore::DeprecationWarning",
"ignore::UserWarning",
]
[tool.coverage.report]
fail_under = 25
[tool.hatch.build.targets.wheel]
packages = ["src"]
[tool.ruff]
line-length = 88
indent-width = 4
target-version = "py312"
extend-include = ["*.pyi"]
[tool.ruff.format]
indent-style = "space"
line-ending = "auto"
exclude = ['^/build/']

View File

@@ -1,227 +0,0 @@
#!/usr/bin/env python3
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""Script to add or check license headers in Python and TypeScript files."""
import argparse
import sys
from pathlib import Path
from typing import Dict, List
# License headers for different file types
LICENSE_HEADERS: Dict[str, str] = {
"python": """# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
""",
"typescript": """// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
""",
}
# File extensions mapping
FILE_TYPE_MAP = {
".py": "python",
".ts": "typescript",
".tsx": "typescript",
}
# Patterns to skip
SKIP_PATTERNS = [
"__pycache__",
".pytest_cache",
".ruff_cache",
"node_modules",
".next",
".venv",
"venv",
".tox",
"build",
"dist",
".git",
".mypy_cache",
]
def should_skip(path: Path) -> bool:
"""Check if a path should be skipped."""
return any(pattern in str(path) for pattern in SKIP_PATTERNS)
def get_file_type(file_path: Path) -> str | None:
"""Get the file type based on extension."""
return FILE_TYPE_MAP.get(file_path.suffix)
def has_license_header(content: str, file_type: str) -> bool:
"""Check if content already has the license header."""
lines = content.split("\n")
license_header = LICENSE_HEADERS[file_type]
# Skip shebang if present (Python files)
start_idx = 0
if lines and lines[0].startswith("#!"):
start_idx = 1
# Skip empty lines after shebang
while start_idx < len(lines) and not lines[start_idx].strip():
start_idx += 1
# Check if license header is present
header_lines = license_header.strip().split("\n")
if len(lines) < start_idx + len(header_lines):
return False
for i, header_line in enumerate(header_lines):
if lines[start_idx + i].strip() != header_line.strip():
return False
return True
def add_license_header(file_path: Path, dry_run: bool = False) -> bool:
"""Add license header to a file if not present.
Args:
file_path: Path to the file
dry_run: If True, only check without modifying
Returns:
True if header was added (or would be added in dry-run), False if already present
"""
file_type = get_file_type(file_path)
if not file_type:
return False
try:
content = file_path.read_text(encoding="utf-8")
except Exception as e:
print(f"Error reading {file_path}: {e}", file=sys.stderr)
return False
if has_license_header(content, file_type):
return False
if dry_run:
return True
# Prepare new content with license header
license_header = LICENSE_HEADERS[file_type]
lines = content.split("\n")
new_lines = []
# Preserve shebang at the top if present (Python files)
start_idx = 0
if lines and lines[0].startswith("#!"):
new_lines.append(lines[0])
start_idx = 1
# Skip empty lines after shebang
while start_idx < len(lines) and not lines[start_idx].strip():
start_idx += 1
new_lines.append("") # Empty line after shebang
# Add license header
new_lines.extend(license_header.strip().split("\n"))
new_lines.append("") # Empty line after header
# Add the rest of the file
new_lines.extend(lines[start_idx:])
# Write back to file
try:
file_path.write_text("\n".join(new_lines), encoding="utf-8")
return True
except Exception as e:
print(f"Error writing {file_path}: {e}", file=sys.stderr)
return False
def find_source_files(root: Path) -> List[Path]:
"""Find all Python and TypeScript files in the given directory tree."""
source_files = []
for extension in FILE_TYPE_MAP.keys():
for path in root.rglob(f"*{extension}"):
if should_skip(path):
continue
source_files.append(path)
return sorted(source_files)
def main():
parser = argparse.ArgumentParser(
description="Add or check license headers in Python and TypeScript files"
)
parser.add_argument(
"paths",
nargs="*",
default=["."],
help="Paths to check (files or directories)",
)
parser.add_argument(
"--check",
action="store_true",
help="Check if headers are present without modifying files",
)
parser.add_argument(
"--verbose",
"-v",
action="store_true",
help="Verbose output",
)
args = parser.parse_args()
# Collect all source files
all_files = []
for path_str in args.paths:
path = Path(path_str)
if not path.exists():
print(f"Error: Path does not exist: {path}", file=sys.stderr)
sys.exit(1)
if path.is_file():
if path.suffix in FILE_TYPE_MAP and not should_skip(path):
all_files.append(path)
else:
all_files.extend(find_source_files(path))
if not all_files:
print("No source files found.")
return 0
# Process files
missing_header = []
modified = []
for file_path in all_files:
if add_license_header(file_path, dry_run=args.check):
missing_header.append(file_path)
if not args.check:
modified.append(file_path)
if args.verbose:
print(f"Added header to: {file_path}")
elif args.verbose:
print(f"Header already present: {file_path}")
# Report results
if args.check:
if missing_header:
print(f"\n{len(missing_header)} file(s) missing license header:")
for path in missing_header:
print(f" - {path}")
print("\nRun 'make add-license-all' to add headers.")
return 1
else:
print(f"✅ All {len(all_files)} source file(s) have license headers.")
return 0
else:
if modified:
print(f"✅ Added license header to {len(modified)} file(s).")
else:
print(f"✅ All {len(all_files)} source file(s) already have license headers.")
return 0
if __name__ == "__main__":
sys.exit(main())

108
server.py
View File

@@ -1,108 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Server script for running the DeerFlow API.
"""
import argparse
import asyncio
import logging
import os
import signal
import sys
import uvicorn
# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)
# To ensure compatibility with Windows event loop issues when using Uvicorn and Asyncio Checkpointer,
# This is necessary because some libraries expect a selector-based event loop.
# This is a workaround for issues with Uvicorn and Watchdog on Windows.
# See:
# Since Python 3.8 the default on Windows is the Proactor event loop,
# which lacks add_reader/add_writer and can break libraries that expect selector-based I/O (e.g., some Uvicorn/Watchdog/stdio integrations).
# For compatibility, this forces the selector loop.
if os.name == "nt":
logger.info("Setting Windows event loop policy for asyncio")
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
def handle_shutdown(signum, frame):
"""Handle graceful shutdown on SIGTERM/SIGINT"""
logger.info("Received shutdown signal. Starting graceful shutdown...")
sys.exit(0)
# Register signal handlers
signal.signal(signal.SIGTERM, handle_shutdown)
signal.signal(signal.SIGINT, handle_shutdown)
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser(description="Run the DeerFlow API server")
parser.add_argument(
"--reload",
action="store_true",
help="Enable auto-reload (default: True except on Windows)",
)
parser.add_argument(
"--host",
type=str,
default="localhost",
help="Host to bind the server to (default: localhost)",
)
parser.add_argument(
"--port",
type=int,
default=8000,
help="Port to bind the server to (default: 8000)",
)
parser.add_argument(
"--log-level",
type=str,
default="info",
choices=["debug", "info", "warning", "error", "critical"],
help="Log level (default: info)",
)
args = parser.parse_args()
# Determine reload setting
reload = False
if args.reload:
reload = True
# Check for DEBUG environment variable to override log level
if os.getenv("DEBUG", "").lower() in ("true", "1", "yes"):
log_level = "debug"
else:
log_level = args.log_level
try:
logger.info(f"Starting DeerFlow API server on {args.host}:{args.port}")
logger.info(f"Log level: {log_level.upper()}")
# Set the appropriate logging level for the src package if debug is enabled
if log_level.lower() == "debug":
logging.getLogger("src").setLevel(logging.DEBUG)
logging.getLogger("langchain").setLevel(logging.DEBUG)
logging.getLogger("langgraph").setLevel(logging.DEBUG)
logger.info("DEBUG logging enabled for src, langchain, and langgraph packages - detailed diagnostic information will be logged")
uvicorn.run(
"src.server:app",
host=args.host,
port=args.port,
reload=reload,
log_level=log_level,
)
except Exception as e:
logger.error(f"Failed to start server: {str(e)}")
sys.exit(1)

View File

@@ -1,11 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import asyncio
import os
# Configure Windows event loop policy for PostgreSQL compatibility
# On Windows, psycopg requires a selector-based event loop, not the default ProactorEventLoop
# This must be set at the earliest possible point before any event loop is created
if os.name == "nt":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

View File

@@ -1,6 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from .agents import create_agent
__all__ = ["create_agent"]

View File

@@ -1,173 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import asyncio
import inspect
import logging
from typing import Any, Callable, List, Optional
from langchain.agents import create_agent as langchain_create_agent
from langchain.agents.middleware import AgentMiddleware
from langgraph.runtime import Runtime
from src.agents.tool_interceptor import wrap_tools_with_interceptor
from src.config.agents import AGENT_LLM_MAP
from src.llms.llm import get_llm_by_type
from src.prompts import apply_prompt_template
logger = logging.getLogger(__name__)
class DynamicPromptMiddleware(AgentMiddleware):
"""Middleware to apply dynamic prompt template before model invocation.
This middleware prepends a system message with the rendered prompt template
to the messages list before the model is called.
"""
def __init__(self, prompt_template: str, locale: str = "en-US"):
self.prompt_template = prompt_template
self.locale = locale
def before_model(self, state: Any, runtime: Runtime) -> dict[str, Any] | None:
"""Apply prompt template and prepend system message to messages."""
try:
# Get the rendered messages including system prompt from template
rendered_messages = apply_prompt_template(
self.prompt_template, state, locale=self.locale
)
# The first message is the system prompt, extract it
if rendered_messages and len(rendered_messages) > 0:
system_message = rendered_messages[0]
# Prepend system message to existing messages
return {"messages": [system_message]}
return None
except Exception as e:
logger.error(
f"Failed to apply prompt template in before_model: {e}",
exc_info=True
)
return None
async def abefore_model(self, state: Any, runtime: Runtime) -> dict[str, Any] | None:
"""Async version of before_model."""
return self.before_model(state, runtime)
class PreModelHookMiddleware(AgentMiddleware):
"""Middleware to execute a pre-model hook before model invocation.
This middleware wraps the legacy pre_model_hook callable and executes it
as part of the middleware chain.
"""
def __init__(self, pre_model_hook: Callable):
self._pre_model_hook = pre_model_hook
def before_model(self, state: Any, runtime: Runtime) -> dict[str, Any] | None:
"""Execute the pre-model hook."""
if not self._pre_model_hook:
return None
try:
result = self._pre_model_hook(state, runtime)
return result
except Exception as e:
logger.error(
f"Pre-model hook execution failed in before_model: {e}",
exc_info=True
)
return None
async def abefore_model(self, state: Any, runtime: Runtime) -> dict[str, Any] | None:
"""Async version of before_model."""
if not self._pre_model_hook:
return None
try:
# Check if the hook is async
if inspect.iscoroutinefunction(self._pre_model_hook):
result = await self._pre_model_hook(state, runtime)
else:
# Run synchronous hook in thread pool to avoid blocking event loop
result = await asyncio.to_thread(self._pre_model_hook, state, runtime)
return result
except Exception as e:
logger.error(
f"Pre-model hook execution failed in abefore_model: {e}",
exc_info=True
)
return None
# Create agents using configured LLM types
def create_agent(
agent_name: str,
agent_type: str,
tools: list,
prompt_template: str,
pre_model_hook: callable = None,
interrupt_before_tools: Optional[List[str]] = None,
locale: str = "en-US",
):
"""Factory function to create agents with consistent configuration.
Args:
agent_name: Name of the agent
agent_type: Type of agent (researcher, coder, etc.)
tools: List of tools available to the agent
prompt_template: Name of the prompt template to use
pre_model_hook: Optional hook to preprocess state before model invocation
interrupt_before_tools: Optional list of tool names to interrupt before execution
locale: Language locale for prompt template selection (e.g., en-US, zh-CN)
Returns:
A configured agent graph
"""
logger.debug(
f"Creating agent '{agent_name}' of type '{agent_type}' "
f"with {len(tools)} tools and template '{prompt_template}'"
)
# Wrap tools with interrupt logic if specified
processed_tools = tools
if interrupt_before_tools:
logger.info(
f"Creating agent '{agent_name}' with tool-specific interrupts: {interrupt_before_tools}"
)
logger.debug(f"Wrapping {len(tools)} tools for agent '{agent_name}'")
processed_tools = wrap_tools_with_interceptor(tools, interrupt_before_tools)
logger.debug(f"Agent '{agent_name}' tool wrapping completed")
else:
logger.debug(f"Agent '{agent_name}' has no interrupt-before-tools configured")
if agent_type not in AGENT_LLM_MAP:
logger.warning(
f"Agent type '{agent_type}' not found in AGENT_LLM_MAP. "
f"Falling back to default LLM type 'basic' for agent '{agent_name}'. "
"This may indicate a configuration issue."
)
llm_type = AGENT_LLM_MAP.get(agent_type, "basic")
logger.debug(f"Agent '{agent_name}' using LLM type: {llm_type}")
logger.debug(f"Creating agent '{agent_name}' with locale: {locale}")
# Build middleware list
# Use closure to capture locale from the workflow state instead of relying on
# agent state.get("locale"), which doesn't have the locale field
# See: https://github.com/bytedance/deer-flow/issues/743
middleware = [DynamicPromptMiddleware(prompt_template, locale)]
# Add pre-model hook middleware if provided
if pre_model_hook:
middleware.append(PreModelHookMiddleware(pre_model_hook))
agent = langchain_create_agent(
name=agent_name,
model=get_llm_by_type(llm_type),
tools=processed_tools,
middleware=middleware,
)
logger.info(f"Agent '{agent_name}' created successfully")
return agent

View File

@@ -1,245 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import json
import logging
from typing import Any, Callable, List, Optional
from langchain_core.tools import BaseTool
from langgraph.types import interrupt
from src.utils.log_sanitizer import (
sanitize_feedback,
sanitize_log_input,
sanitize_tool_name,
)
logger = logging.getLogger(__name__)
class ToolInterceptor:
"""Intercepts tool calls and triggers interrupts for specified tools."""
def __init__(self, interrupt_before_tools: Optional[List[str]] = None):
"""Initialize the interceptor with list of tools to interrupt before.
Args:
interrupt_before_tools: List of tool names to interrupt before execution.
If None or empty, no interrupts are triggered.
"""
self.interrupt_before_tools = interrupt_before_tools or []
logger.info(
f"ToolInterceptor initialized with interrupt_before_tools: {self.interrupt_before_tools}"
)
def should_interrupt(self, tool_name: str) -> bool:
"""Check if execution should be interrupted before this tool.
Args:
tool_name: Name of the tool being called
Returns:
bool: True if tool should trigger an interrupt, False otherwise
"""
should_interrupt = tool_name in self.interrupt_before_tools
if should_interrupt:
logger.info(f"Tool '{tool_name}' marked for interrupt")
return should_interrupt
@staticmethod
def _format_tool_input(tool_input: Any) -> str:
"""Format tool input for display in interrupt messages.
Attempts to format as JSON for better readability, with fallback to string representation.
Args:
tool_input: The tool input to format
Returns:
str: Formatted representation of the tool input
"""
if tool_input is None:
return "No input"
# Try to serialize as JSON first for better readability
try:
# Handle dictionaries and other JSON-serializable objects
if isinstance(tool_input, (dict, list, tuple)):
return json.dumps(tool_input, indent=2, default=str)
elif isinstance(tool_input, str):
return tool_input
else:
# For other types, try to convert to dict if it has __dict__
# Otherwise fall back to string representation
return str(tool_input)
except (TypeError, ValueError):
# JSON serialization failed, use string representation
return str(tool_input)
@staticmethod
def wrap_tool(
tool: BaseTool, interceptor: "ToolInterceptor"
) -> BaseTool:
"""Wrap a tool to add interrupt logic by creating a wrapper.
Args:
tool: The tool to wrap
interceptor: The ToolInterceptor instance
Returns:
BaseTool: The wrapped tool with interrupt capability
"""
original_func = tool.func
safe_tool_name = sanitize_tool_name(tool.name)
logger.debug(f"Wrapping tool '{safe_tool_name}' with interrupt capability")
def intercepted_func(*args: Any, **kwargs: Any) -> Any:
"""Execute the tool with interrupt check."""
tool_name = tool.name
safe_tool_name_local = sanitize_tool_name(tool_name)
logger.debug(f"[ToolInterceptor] Executing tool: {safe_tool_name_local}")
# Format tool input for display
tool_input = args[0] if args else kwargs
tool_input_repr = ToolInterceptor._format_tool_input(tool_input)
safe_tool_input = sanitize_log_input(tool_input_repr, max_length=100)
logger.debug(f"[ToolInterceptor] Tool input: {safe_tool_input}")
should_interrupt = interceptor.should_interrupt(tool_name)
logger.debug(f"[ToolInterceptor] should_interrupt={should_interrupt} for tool '{safe_tool_name_local}'")
if should_interrupt:
logger.info(
f"[ToolInterceptor] Interrupting before tool '{safe_tool_name_local}'"
)
logger.debug(
f"[ToolInterceptor] Interrupt message: About to execute tool '{safe_tool_name_local}' with input: {safe_tool_input}..."
)
# Trigger interrupt and wait for user feedback
try:
feedback = interrupt(
f"About to execute tool: '{tool_name}'\n\nInput:\n{tool_input_repr}\n\nApprove execution?"
)
safe_feedback = sanitize_feedback(feedback)
logger.debug(f"[ToolInterceptor] Interrupt returned with feedback: {f'{safe_feedback[:100]}...' if safe_feedback and len(safe_feedback) > 100 else safe_feedback if safe_feedback else 'None'}")
except Exception as e:
logger.error(f"[ToolInterceptor] Error during interrupt: {str(e)}")
raise
logger.debug(f"[ToolInterceptor] Processing feedback approval for '{safe_tool_name_local}'")
# Check if user approved
is_approved = ToolInterceptor._parse_approval(feedback)
logger.info(f"[ToolInterceptor] Tool '{safe_tool_name_local}' approval decision: {is_approved}")
if not is_approved:
logger.warning(f"[ToolInterceptor] User rejected execution of tool '{safe_tool_name_local}'")
return {
"error": f"Tool execution rejected by user",
"tool": tool_name,
"status": "rejected",
}
logger.info(f"[ToolInterceptor] User approved execution of tool '{safe_tool_name_local}', proceeding")
# Execute the original tool
try:
logger.debug(f"[ToolInterceptor] Calling original function for tool '{safe_tool_name_local}'")
result = original_func(*args, **kwargs)
logger.info(f"[ToolInterceptor] Tool '{safe_tool_name_local}' execution completed successfully")
result_len = len(str(result))
logger.debug(f"[ToolInterceptor] Tool result length: {result_len}")
return result
except Exception as e:
logger.error(f"[ToolInterceptor] Error executing tool '{safe_tool_name_local}': {str(e)}")
raise
# Replace the function and update the tool
# Use object.__setattr__ to bypass Pydantic validation
logger.debug(f"Attaching intercepted function to tool '{safe_tool_name}'")
object.__setattr__(tool, "func", intercepted_func)
# Also ensure the tool's _run method is updated if it exists
if hasattr(tool, '_run'):
logger.debug(f"Also wrapping _run method for tool '{safe_tool_name}'")
# Wrap _run to ensure interception is applied regardless of invocation method
object.__setattr__(tool, "_run", intercepted_func)
return tool
@staticmethod
def _parse_approval(feedback: str) -> bool:
"""Parse user feedback to determine if tool execution was approved.
Args:
feedback: The feedback string from the user
Returns:
bool: True if feedback indicates approval, False otherwise
"""
if not feedback:
logger.warning("Empty feedback received, treating as rejection")
return False
feedback_lower = feedback.lower().strip()
# Check for approval keywords
approval_keywords = [
"approved",
"approve",
"yes",
"proceed",
"continue",
"ok",
"okay",
"accepted",
"accept",
"[approved]",
]
for keyword in approval_keywords:
if keyword in feedback_lower:
return True
# Default to rejection if no approval keywords found
logger.warning(
f"No approval keywords found in feedback: {feedback}. Treating as rejection."
)
return False
def wrap_tools_with_interceptor(
tools: List[BaseTool], interrupt_before_tools: Optional[List[str]] = None
) -> List[BaseTool]:
"""Wrap multiple tools with interrupt logic.
Args:
tools: List of tools to wrap
interrupt_before_tools: List of tool names to interrupt before
Returns:
List[BaseTool]: List of wrapped tools
"""
if not interrupt_before_tools:
logger.debug("No tool interrupts configured, returning tools as-is")
return tools
logger.info(
f"Wrapping {len(tools)} tools with interrupt logic for: {interrupt_before_tools}"
)
interceptor = ToolInterceptor(interrupt_before_tools)
wrapped_tools = []
for tool in tools:
try:
wrapped_tool = ToolInterceptor.wrap_tool(tool, interceptor)
wrapped_tools.append(wrapped_tool)
logger.debug(f"Wrapped tool: {tool.name}")
except Exception as e:
logger.error(f"Failed to wrap tool {tool.name}: {str(e)}")
# Add original tool if wrapping fails
wrapped_tools.append(tool)
logger.info(f"Successfully wrapped {len(wrapped_tools)} tools")
return wrapped_tools

View File

@@ -1,28 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Citation management module for DeerFlow.
This module provides structured citation/source metadata handling
for research reports, enabling proper attribution and inline citations.
"""
from .collector import CitationCollector
from .extractor import (
citations_to_markdown_references,
extract_citations_from_messages,
merge_citations,
)
from .formatter import CitationFormatter
from .models import Citation, CitationMetadata
__all__ = [
"Citation",
"CitationMetadata",
"CitationCollector",
"CitationFormatter",
"extract_citations_from_messages",
"merge_citations",
"citations_to_markdown_references",
]

View File

@@ -1,285 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Citation collector for gathering and managing citations during research.
"""
import logging
from typing import Any, Dict, List, Optional
from .models import Citation, CitationMetadata
logger = logging.getLogger(__name__)
class CitationCollector:
"""
Collects and manages citations during the research process.
This class handles:
- Collecting citations from search results and crawled pages
- Deduplicating citations by URL
- Assigning citation numbers
- Tracking which citations are actually used in the report
"""
def __init__(self):
self._citations: Dict[str, CitationMetadata] = {} # url -> metadata
self._citation_order: List[str] = [] # ordered list of URLs
self._used_citations: set[str] = set() # URLs that are actually cited
self._url_to_index: Dict[str, int] = {} # url -> index of _citation_order (O(1) lookup)
def add_from_search_results(
self, results: List[Dict[str, Any]], query: str = ""
) -> List[CitationMetadata]:
"""
Add citations from search results.
Args:
results: List of search result dictionaries
query: The search query that produced these results
Returns:
List of CitationMetadata objects that were added
"""
added = []
for result in results:
# Skip image results
if result.get("type") == "image_url":
continue
url = result.get("url")
if not url:
continue
# Create or update citation metadata
metadata = CitationMetadata.from_search_result(result, query)
if url not in self._citations:
self._citations[url] = metadata
self._citation_order.append(url)
self._url_to_index[url] = len(self._citation_order) - 1
added.append(metadata)
logger.debug(f"Added citation: {metadata.title} ({url})")
else:
# Update with potentially better metadata
existing = self._citations[url]
if metadata.relevance_score > existing.relevance_score:
self._citations[url] = metadata
logger.debug(f"Updated citation: {metadata.title} ({url})")
return added
def add_from_crawl_result(
self, url: str, title: str, content: Optional[str] = None, **extra_metadata
) -> CitationMetadata:
"""
Add or update a citation from a crawled page.
Args:
url: The URL of the crawled page
title: The page title
content: The page content
**extra_metadata: Additional metadata fields
Returns:
The CitationMetadata object
"""
if url in self._citations:
# Update existing citation with crawled content
metadata = self._citations[url]
if title and title != "Untitled":
metadata.title = title
if content:
metadata.raw_content = content
if not metadata.content_snippet:
metadata.content_snippet = content[:500]
else:
# Create new citation
metadata = CitationMetadata(
url=url,
title=title or "Untitled",
content_snippet=content[:500] if content else None,
raw_content=content,
**extra_metadata,
)
self._citations[url] = metadata
self._citation_order.append(url)
self._url_to_index[url] = len(self._citation_order) - 1
return metadata
def mark_used(self, url: str) -> Optional[int]:
"""
Mark a citation as used and return its number.
Args:
url: The URL of the citation
Returns:
The citation number (1-indexed) or None if not found
"""
if url in self._citations:
self._used_citations.add(url)
return self.get_number(url)
return None
def get_number(self, url: str) -> Optional[int]:
"""
Get the citation number for a URL (O(1) time complexity).
Args:
url: The URL to look up
Returns:
The citation number (1-indexed) or None if not found
"""
index = self._url_to_index.get(url)
return index + 1 if index is not None else None
def get_metadata(self, url: str) -> Optional[CitationMetadata]:
"""
Get the metadata for a URL.
Args:
url: The URL to look up
Returns:
The CitationMetadata or None if not found
"""
return self._citations.get(url)
def get_all_citations(self) -> List[Citation]:
"""
Get all collected citations in order.
Returns:
List of Citation objects
"""
citations = []
for i, url in enumerate(self._citation_order):
metadata = self._citations[url]
citations.append(
Citation(
number=i + 1,
metadata=metadata,
)
)
return citations
def get_used_citations(self) -> List[Citation]:
"""
Get only the citations that have been marked as used.
Returns:
List of Citation objects that are actually used
"""
citations = []
number = 1
for url in self._citation_order:
if url in self._used_citations:
metadata = self._citations[url]
citations.append(
Citation(
number=number,
metadata=metadata,
)
)
number += 1
return citations
def to_dict(self) -> Dict[str, Any]:
"""
Serialize the collector state to a dictionary.
Returns:
Dictionary representation of the collector
"""
return {
"citations": [c.to_dict() for c in self.get_all_citations()],
"used_urls": list(self._used_citations),
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "CitationCollector":
"""
Deserialize a collector from a dictionary.
Args:
data: Dictionary representation
Returns:
CitationCollector instance
"""
collector = cls()
for citation_data in data.get("citations", []):
citation = Citation.from_dict(citation_data)
collector._citations[citation.url] = citation.metadata
index = len(collector._citation_order)
collector._citation_order.append(citation.url)
collector._url_to_index[citation.url] = index
collector._used_citations = set(data.get("used_urls", []))
return collector
def merge_with(self, other: "CitationCollector") -> None:
"""
Merge another collector's citations into this one.
Args:
other: Another CitationCollector to merge
"""
for url in other._citation_order:
if url not in self._citations:
self._citations[url] = other._citations[url]
self._citation_order.append(url)
self._url_to_index[url] = len(self._citation_order) - 1
self._used_citations.update(other._used_citations)
@property
def count(self) -> int:
"""Return the total number of citations."""
return len(self._citations)
@property
def used_count(self) -> int:
"""Return the number of used citations."""
return len(self._used_citations)
def clear(self) -> None:
"""Clear all citations."""
self._citations.clear()
self._citation_order.clear()
self._used_citations.clear()
self._url_to_index.clear()
def extract_urls_from_text(text: str) -> List[str]:
"""
Extract URLs from markdown text.
Args:
text: Markdown text that may contain URLs
Returns:
List of URLs found in the text
"""
import re
urls = []
# Match markdown links: [text](url)
markdown_pattern = r"\[([^\]]+)\]\(([^)]+)\)"
for match in re.finditer(markdown_pattern, text):
url = match.group(2)
if url.startswith(("http://", "https://")):
urls.append(url)
# Match bare URLs
bare_url_pattern = r"(?<![\(\[])(https?://[^\s\)>\]]+)"
for match in re.finditer(bare_url_pattern, text):
url = match.group(1)
if url not in urls:
urls.append(url)
return urls

View File

@@ -1,445 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Citation extraction utilities for extracting citations from tool results.
"""
import json
import logging
import re
from typing import Any, Dict, List, Optional
from langchain_core.messages import AIMessage, ToolMessage
from .models import CitationMetadata
logger = logging.getLogger(__name__)
def extract_citations_from_messages(messages: List[Any]) -> List[Dict[str, Any]]:
"""
Extract citation metadata from agent messages (tool calls/results).
Args:
messages: List of messages from agent execution
Returns:
List of citation dictionaries
"""
citations = []
seen_urls = set()
logger.info(f"[Citations] Starting extraction from {len(messages)} messages")
for message in messages:
# Extract from ToolMessage results (web_search, crawl)
if isinstance(message, ToolMessage):
logger.info(
f"[Citations] Found ToolMessage: name={getattr(message, 'name', 'unknown')}"
)
tool_citations = _extract_from_tool_message(message)
for citation in tool_citations:
url = citation.get("url", "")
if url and url not in seen_urls:
seen_urls.add(url)
citations.append(citation)
# Also check AIMessage tool_calls for any embedded results
if isinstance(message, AIMessage) and hasattr(message, "tool_calls"):
for tool_call in message.tool_calls or []:
if tool_call.get("name") == "web_search":
# The query is in the args
query = tool_call.get("args", {}).get("query", "")
logger.info(
"[Citations] Found web_search tool call with query=%r", query
)
# Note: results come in subsequent ToolMessage
logger.info(
f"[Citations] Extracted {len(citations)} unique citations from {len(messages)} messages"
)
return citations
def _extract_from_tool_message(message: ToolMessage) -> List[Dict[str, Any]]:
"""
Extract citations from a tool message result.
Args:
message: ToolMessage with tool execution result
Returns:
List of citation dictionaries
"""
citations = []
tool_name = getattr(message, "name", "") or ""
content = getattr(message, "content", "")
logger.info(
f"Processing tool message: tool_name='{tool_name}', content_len={len(str(content)) if content else 0}"
)
if not content:
return citations
# Parse JSON content
try:
if isinstance(content, str):
data = json.loads(content)
else:
data = content
except (json.JSONDecodeError, TypeError):
logger.debug(
f"Could not parse tool message content as JSON: {str(content)[:100]}..."
)
return citations
logger.debug(f"Parsed tool message data type: {type(data).__name__}")
# Try to detect content type by structure rather than just tool name
tool_name_lower = tool_name.lower() if tool_name else ""
# Handle web_search results (by name or by structure)
if tool_name_lower in (
"web_search",
"tavily_search",
"duckduckgo_search",
"brave_search",
"searx_search",
):
citations.extend(_extract_from_search_results(data))
logger.debug(
f"Extracted {len(citations)} citations from search tool '{tool_name}'"
)
# Handle crawl results (by name or by structure)
elif tool_name_lower in ("crawl_tool", "crawl", "jina_crawl"):
citation = _extract_from_crawl_result(data)
if citation:
citations.append(citation)
logger.debug(f"Extracted 1 citation from crawl tool '{tool_name}'")
# Fallback: Try to detect by data structure
else:
# Check if it looks like search results (list of items with url)
if isinstance(data, list) and len(data) > 0:
first_item = data[0]
if isinstance(first_item, dict) and "url" in first_item:
logger.debug(
f"Auto-detected search results format for tool '{tool_name}'"
)
citations.extend(_extract_from_search_results(data))
# Check if it looks like crawl result (dict with url and crawled_content)
elif (
isinstance(data, dict)
and "url" in data
and ("crawled_content" in data or "content" in data)
):
logger.debug(f"Auto-detected crawl result format for tool '{tool_name}'")
citation = _extract_from_crawl_result(data)
if citation:
citations.append(citation)
return citations
def _extract_from_search_results(data: Any) -> List[Dict[str, Any]]:
"""
Extract citations from web search results.
Args:
data: Parsed JSON data from search tool
Returns:
List of citation dictionaries
"""
citations = []
# Handle list of results
if isinstance(data, list):
for result in data:
if isinstance(result, dict) and result.get("type") != "image_url":
citation = _result_to_citation(result)
if citation:
citations.append(citation)
# Handle dict with results key
elif isinstance(data, dict):
if "error" in data:
logger.warning(f"Search error: {data.get('error')}")
return citations
results = data.get("results", [])
for result in results:
if isinstance(result, dict) and result.get("type") != "image_url":
citation = _result_to_citation(result)
if citation:
citations.append(citation)
return citations
def _result_to_citation(result: Dict[str, Any]) -> Optional[Dict[str, Any]]:
"""
Convert a search result to a citation dictionary.
Args:
result: Search result dictionary
Returns:
Citation dictionary or None
"""
url = result.get("url", "")
if not url:
return None
return {
"url": url,
"title": result.get("title", "Untitled"),
"description": result.get("content", ""),
"content_snippet": (result.get("content", "") or "")[:500],
"relevance_score": result.get("score", 0.0),
"domain": _extract_domain(url),
"accessed_at": None, # Will be filled by CitationMetadata
"source_type": "web_search",
}
def extract_title_from_content(content: Optional[str], max_length: int = 200) -> str:
"""
Intelligent title extraction supporting multiple formats.
Priority:
1. HTML <title> tag
2. Markdown h1 (# Title)
3. Markdown h2-h6 (## Title, etc.)
4. JSON/YAML title field
5. First substantial non-empty line
6. "Untitled" as fallback
Args:
content: The content to extract title from (can be None)
max_length: Maximum title length (default: 200)
Returns:
Extracted title or "Untitled"
"""
if not content:
return "Untitled"
# 1. Try HTML title tag
html_title_match = re.search(
r'<title[^>]*>([^<]+)</title>',
content,
re.IGNORECASE | re.DOTALL
)
if html_title_match:
title = html_title_match.group(1).strip()
if title:
return title[:max_length]
# 2. Try Markdown h1 (exact match of only one #)
md_h1_match = re.search(
r'^#{1}\s+(.+?)$',
content,
re.MULTILINE
)
if md_h1_match:
title = md_h1_match.group(1).strip()
if title:
return title[:max_length]
# 3. Try any Markdown heading (h2-h6)
md_heading_match = re.search(
r'^#{2,6}\s+(.+?)$',
content,
re.MULTILINE
)
if md_heading_match:
title = md_heading_match.group(1).strip()
if title:
return title[:max_length]
# 4. Try JSON/YAML title field
json_title_match = re.search(
r'"?title"?\s*:\s*["\']?([^"\'\n]+)["\']?',
content,
re.IGNORECASE
)
if json_title_match:
title = json_title_match.group(1).strip()
if title and len(title) > 3:
return title[:max_length]
# 5. First substantial non-empty line
for line in content.split('\n'):
line = line.strip()
# Skip short lines, code blocks, list items, and separators
if (line and
len(line) > 10 and
not line.startswith(('```', '---', '***', '- ', '* ', '+ ', '#'))):
return line[:max_length]
return "Untitled"
def _extract_from_crawl_result(data: Any) -> Optional[Dict[str, Any]]:
"""
Extract citation from crawl tool result.
Args:
data: Parsed JSON data from crawl tool
Returns:
Citation dictionary or None
"""
if not isinstance(data, dict):
return None
url = data.get("url", "")
if not url:
return None
content = data.get("crawled_content", "")
# Extract title using intelligent extraction function
title = extract_title_from_content(content)
return {
"url": url,
"title": title,
"description": content[:300] if content else "",
"content_snippet": content[:500] if content else "",
"raw_content": content,
"domain": _extract_domain(url),
"source_type": "crawl",
}
def _extract_domain(url: Optional[str]) -> str:
"""
Extract domain from URL using urllib with regex fallback.
Handles:
- Standard URLs: https://www.example.com/path
- Short URLs: example.com
- Invalid URLs: graceful fallback
Args:
url: The URL string to extract domain from (can be None)
Returns:
The domain netloc (including port if present), or empty string if extraction fails
"""
if not url:
return ""
# Approach 1: Try urllib first (fast path for standard URLs)
try:
from urllib.parse import urlparse
parsed = urlparse(url)
if parsed.netloc:
return parsed.netloc
except Exception as e:
logger.debug(f"URL parsing failed for {url}: {e}")
# Approach 2: Regex fallback (for non-standard or bare URLs without scheme)
# Matches: domain[:port] where domain is a valid hostname
# Pattern breakdown:
# ([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)
# - domain labels separated by dots, each 1-63 chars, starting/ending with alphanumeric
# (?::\d+)? - optional port
pattern = r'^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*(?::\d+)?)(?:[/?#]|$)'
match = re.match(pattern, url)
if match:
return match.group(1)
logger.warning(f"Could not extract domain from URL: {url}")
return ""
def merge_citations(
existing: List[Dict[str, Any]], new: List[Dict[str, Any]]
) -> List[Dict[str, Any]]:
"""
Merge new citations into existing list, avoiding duplicates.
Args:
existing: Existing citations list
new: New citations to add
Returns:
Merged list of citations
"""
seen_urls = {c.get("url") for c in existing if c.get("url")}
result = list(existing)
for citation in new:
url = citation.get("url", "")
if url and url not in seen_urls:
seen_urls.add(url)
result.append(citation)
elif url in seen_urls:
# Update existing citation with potentially better data
for i, existing_citation in enumerate(result):
if existing_citation.get("url") == url:
# Prefer higher relevance score
if citation.get("relevance_score", 0) > existing_citation.get(
"relevance_score", 0
):
# Update selectively instead of blindly merging all fields.
updated = existing_citation.copy()
# Always update relevance_score
if "relevance_score" in citation:
updated["relevance_score"] = citation["relevance_score"]
# Merge other metadata only if improved (here assuming non-empty is 'better')
for key in ("title", "description", "snippet"):
new_value = citation.get(key)
if new_value:
updated[key] = new_value
result[i] = updated
break
break
return result
def citations_to_markdown_references(citations: List[Dict[str, Any]]) -> str:
"""
Convert citations list to markdown references section.
Args:
citations: List of citation dictionaries
Returns:
Markdown formatted references section
"""
if not citations:
return ""
lines = ["## Key Citations", ""]
for i, citation in enumerate(citations, 1):
title = citation.get("title", "Untitled")
url = citation.get("url", "")
domain = citation.get("domain", "")
# Main reference link
lines.append(f"- [{title}]({url})")
# Add metadata as comment for parsing
metadata_parts = []
if domain:
metadata_parts.append(f"domain: {domain}")
if citation.get("relevance_score"):
metadata_parts.append(f"score: {citation['relevance_score']:.2f}")
if metadata_parts:
lines.append(f" <!-- {', '.join(metadata_parts)} -->")
lines.append("") # Empty line between citations
return "\n".join(lines)

View File

@@ -1,397 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Citation formatter for generating citation sections and inline references.
"""
import re
from typing import Any, Dict, List
from .models import Citation
class CitationFormatter:
"""
Formats citations for display in reports.
Supports multiple citation styles:
- numbered: [1], [2], etc.
- superscript: ¹, ², etc.
- footnote: [^1], [^2], etc.
- inline: (Author, Year) or (Source)
"""
SUPERSCRIPT_MAP = {
"0": "",
"1": "¹",
"2": "²",
"3": "³",
"4": "",
"5": "",
"6": "",
"7": "",
"8": "",
"9": "",
}
def __init__(self, style: str = "numbered"):
"""
Initialize the formatter.
Args:
style: Citation style ('numbered', 'superscript', 'footnote', 'inline')
"""
self.style = style
def format_inline_marker(self, number: int) -> str:
"""
Format an inline citation marker.
Args:
number: The citation number
Returns:
Formatted marker string
"""
if self.style == "superscript":
return "".join(self.SUPERSCRIPT_MAP.get(c, c) for c in str(number))
elif self.style == "footnote":
return f"[^{number}]"
else: # numbered
return f"[{number}]"
def format_reference(self, citation: Citation) -> str:
"""
Format a single reference for the citations section.
Args:
citation: The citation to format
Returns:
Formatted reference string
"""
metadata = citation.metadata
# Build reference with available metadata
parts = []
# Number and title
parts.append(f"[{citation.number}] **{metadata.title}**")
# Author if available
if metadata.author:
parts.append(f" *{metadata.author}*")
# Domain/source
if metadata.domain:
parts.append(f" Source: {metadata.domain}")
# Published date if available
if metadata.published_date:
parts.append(f" Published: {metadata.published_date}")
# URL
parts.append(f" URL: {metadata.url}")
# Description/snippet
if metadata.description:
snippet = metadata.description[:200]
if len(metadata.description) > 200:
snippet += "..."
parts.append(f" > {snippet}")
return "\n".join(parts)
def format_simple_reference(self, citation: Citation) -> str:
"""
Format a simple reference (title + URL).
Args:
citation: The citation to format
Returns:
Simple reference string
"""
return f"- [{citation.metadata.title}]({citation.metadata.url})"
def format_rich_reference(self, citation: Citation) -> str:
"""
Format a rich reference with metadata as JSON-like annotation.
Args:
citation: The citation to format
Returns:
Rich reference string with metadata
"""
metadata = citation.metadata
parts = [f"- [{metadata.title}]({metadata.url})"]
annotations = []
if metadata.domain:
annotations.append(f"domain: {metadata.domain}")
if metadata.relevance_score > 0:
annotations.append(f"relevance: {metadata.relevance_score:.2f}")
if metadata.accessed_at:
annotations.append(f"accessed: {metadata.accessed_at[:10]}")
if annotations:
parts.append(f" <!-- {', '.join(annotations)} -->")
return "\n".join(parts)
def format_citations_section(
self, citations: List[Citation], include_metadata: bool = True
) -> str:
"""
Format the full citations section for a report.
Args:
citations: List of citations to include
include_metadata: Whether to include rich metadata
Returns:
Formatted citations section markdown
"""
if not citations:
return ""
lines = ["## Key Citations", ""]
for citation in citations:
if include_metadata:
lines.append(self.format_rich_reference(citation))
else:
lines.append(self.format_simple_reference(citation))
lines.append("") # Empty line between citations
return "\n".join(lines)
def format_footnotes_section(self, citations: List[Citation]) -> str:
"""
Format citations as footnotes (for footnote style).
Args:
citations: List of citations
Returns:
Footnotes section markdown
"""
if not citations:
return ""
lines = ["", "---", ""]
for citation in citations:
lines.append(
f"[^{citation.number}]: {citation.metadata.title} - {citation.metadata.url}"
)
return "\n".join(lines)
def add_citation_markers_to_text(
self, text: str, citations: List[Citation], url_to_number: Dict[str, int]
) -> str:
"""
Add citation markers to text where URLs are referenced.
Args:
text: The text to process
citations: Available citations
url_to_number: Mapping from URL to citation number
Returns:
Text with citation markers added
"""
# Find all markdown links and add citation numbers
def replace_link(match):
full_match = match.group(0)
url = match.group(2)
if url in url_to_number:
number = url_to_number[url]
marker = self.format_inline_marker(number)
return f"{full_match}{marker}"
return full_match
pattern = r"\[([^\]]+)\]\(([^)]+)\)"
return re.sub(pattern, replace_link, text)
@staticmethod
def build_citation_data_json(citations: List[Citation]) -> str:
"""
Build a JSON block containing citation data for frontend use.
Args:
citations: List of citations
Returns:
JSON string with citation data
"""
import json
data = {
"citations": [c.to_dict() for c in citations],
"count": len(citations),
}
return json.dumps(data, ensure_ascii=False)
def parse_citations_from_report(
report: str, section_patterns: List[str] = None
) -> Dict[str, Any]:
"""
Extract citation information from report, supporting multiple formats.
Supports various citation formats:
- Markdown: [Title](URL)
- Numbered: [1] Title - URL
- Footnote: [^1]: Title - URL
- HTML: <a href="URL">Title</a>
Args:
report: The report markdown text
section_patterns: Custom section header patterns (optional)
Returns:
Dictionary with 'citations' list and 'count' of unique citations
"""
if section_patterns is None:
section_patterns = [
r"(?:##\s*Key Citations|##\s*References|##\s*Sources|##\s*Bibliography)",
]
citations = []
# 1. Find citation section and extract citations
for pattern in section_patterns:
# Use a more efficient pattern that matches line-by-line content
# instead of relying on dotall with greedy matching for large reports
section_matches = re.finditer(
pattern + r"\s*\n((?:(?!\n##).*\n?)*)",
report,
re.IGNORECASE | re.MULTILINE,
)
for section_match in section_matches:
section = section_match.group(1)
# 2. Extract citations in various formats
citations.extend(_extract_markdown_links(section))
citations.extend(_extract_numbered_citations(section))
citations.extend(_extract_footnote_citations(section))
citations.extend(_extract_html_links(section))
# 3. Deduplicate by URL
unique_citations = {}
for citation in citations:
url = citation.get("url", "")
if url and url not in unique_citations:
unique_citations[url] = citation
return {
"citations": list(unique_citations.values()),
"count": len(unique_citations),
}
def _extract_markdown_links(text: str) -> List[Dict[str, str]]:
"""
Extract Markdown links [title](url).
Args:
text: Text to extract from
Returns:
List of citation dictionaries with title, url, and format
"""
citations = []
pattern = r"\[([^\]]+)\]\(([^)]+)\)"
for match in re.finditer(pattern, text):
title, url = match.groups()
if url.startswith(("http://", "https://")):
citations.append({
"title": title.strip(),
"url": url.strip(),
"format": "markdown",
})
return citations
def _extract_numbered_citations(text: str) -> List[Dict[str, str]]:
"""
Extract numbered citations [1] Title - URL.
Args:
text: Text to extract from
Returns:
List of citation dictionaries
"""
citations = []
# Match: [number] title - URL
pattern = r"\[\d+\]\s+([^-\n]+?)\s*-\s*(https?://[^\s\n]+)"
for match in re.finditer(pattern, text):
title, url = match.groups()
citations.append({
"title": title.strip(),
"url": url.strip(),
"format": "numbered",
})
return citations
def _extract_footnote_citations(text: str) -> List[Dict[str, str]]:
"""
Extract footnote citations [^1]: Title - URL.
Args:
text: Text to extract from
Returns:
List of citation dictionaries
"""
citations = []
# Match: [^number]: title - URL
pattern = r"\[\^(\d+)\]:\s+([^-\n]+?)\s*-\s*(https?://[^\s\n]+)"
for match in re.finditer(pattern, text):
_, title, url = match.groups()
citations.append({
"title": title.strip(),
"url": url.strip(),
"format": "footnote",
})
return citations
def _extract_html_links(text: str) -> List[Dict[str, str]]:
"""
Extract HTML links <a href="url">title</a>.
Args:
text: Text to extract from
Returns:
List of citation dictionaries
"""
citations = []
pattern = r'<a\s+(?:[^>]*?\s)?href=(["\'])([^"\']+)\1[^>]*>([^<]+)</a>'
for match in re.finditer(pattern, text, re.IGNORECASE):
_, url, title = match.groups()
if url.startswith(("http://", "https://")):
citations.append({
"title": title.strip(),
"url": url.strip(),
"format": "html",
})
return citations

View File

@@ -1,185 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Citation data models for structured source metadata.
"""
import hashlib
from datetime import datetime
from typing import Any, Dict, List, Optional
from urllib.parse import urlparse
from pydantic import BaseModel, ConfigDict, Field
class CitationMetadata(BaseModel):
"""Metadata extracted from a source."""
# Core identifiers
url: str
title: str
# Content information
description: Optional[str] = None
content_snippet: Optional[str] = None
raw_content: Optional[str] = None
# Source metadata
domain: Optional[str] = None
author: Optional[str] = None
published_date: Optional[str] = None
language: Optional[str] = None
# Media
images: List[str] = Field(default_factory=list)
favicon: Optional[str] = None
# Quality indicators
relevance_score: float = 0.0
credibility_score: float = 0.0
# Timestamps
accessed_at: str = Field(default_factory=lambda: datetime.now().isoformat())
# Additional metadata
extra: Dict[str, Any] = Field(default_factory=dict)
model_config = ConfigDict(arbitrary_types_allowed=True)
def __init__(self, **data):
"""Initialize and extract domain from URL if not provided."""
super().__init__(**data)
if not self.domain and self.url:
try:
parsed = urlparse(self.url)
self.domain = parsed.netloc
except Exception:
# If URL parsing fails for any reason, leave `domain` as None.
# This is a non-critical convenience field and failures here
# should not prevent citation metadata creation.
pass
@property
def id(self) -> str:
"""Generate a unique ID for this citation based on URL."""
return hashlib.sha256(self.url.encode("utf-8")).hexdigest()[:12]
def to_dict(self) -> Dict[str, Any]:
"""Convert to dictionary for JSON serialization."""
return {
"id": self.id,
"url": self.url,
"title": self.title,
"description": self.description,
"content_snippet": self.content_snippet,
"domain": self.domain,
"author": self.author,
"published_date": self.published_date,
"language": self.language,
"images": self.images,
"favicon": self.favicon,
"relevance_score": self.relevance_score,
"credibility_score": self.credibility_score,
"accessed_at": self.accessed_at,
"extra": self.extra,
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "CitationMetadata":
"""Create from dictionary."""
# Remove 'id' as it's computed from url
data = {k: v for k, v in data.items() if k != "id"}
return cls.model_validate(data)
@classmethod
def from_search_result(
cls, result: Dict[str, Any], query: str = ""
) -> "CitationMetadata":
"""Create citation metadata from a search result."""
return cls(
url=result.get("url", ""),
title=result.get("title", "Untitled"),
description=result.get("content", result.get("description", "")),
content_snippet=result.get("content", "")[:500]
if result.get("content")
else None,
raw_content=result.get("raw_content"),
relevance_score=result.get("score", 0.0),
extra={"query": query, "result_type": result.get("type", "page")},
)
class Citation(BaseModel):
"""
A citation reference that can be used in reports.
This represents a numbered citation that links to source metadata.
"""
# Citation number (1-indexed for display)
number: int
# Reference to the source metadata
metadata: CitationMetadata
# Context where this citation is used
context: Optional[str] = None
# Specific quote or fact being cited
cited_text: Optional[str] = None
model_config = ConfigDict(arbitrary_types_allowed=True)
@property
def id(self) -> str:
"""Get the citation ID from metadata."""
return self.metadata.id
@property
def url(self) -> str:
"""Get the URL from metadata."""
return self.metadata.url
@property
def title(self) -> str:
"""Get the title from metadata."""
return self.metadata.title
def to_dict(self) -> Dict[str, Any]:
"""Convert to dictionary for JSON serialization."""
return {
"number": self.number,
"metadata": self.metadata.to_dict(),
"context": self.context,
"cited_text": self.cited_text,
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Citation":
"""Create from dictionary."""
return cls.model_validate({
"number": data["number"],
"metadata": CitationMetadata.from_dict(data["metadata"])
if isinstance(data.get("metadata"), dict)
else data["metadata"],
"context": data.get("context"),
"cited_text": data.get("cited_text"),
})
def to_markdown_reference(self) -> str:
"""Generate markdown reference format: [Title](URL)"""
return f"[{self.title}]({self.url})"
def to_numbered_reference(self) -> str:
"""Generate numbered reference format: [1] Title - URL"""
return f"[{self.number}] {self.title} - {self.url}"
def to_inline_marker(self) -> str:
"""Generate inline citation marker: [^1]"""
return f"[^{self.number}]"
def to_footnote(self) -> str:
"""Generate footnote definition: [^1]: Title - URL"""
return f"[^{self.number}]: {self.title} - {self.url}"

View File

@@ -1,50 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from dotenv import load_dotenv
from .loader import load_yaml_config
from .questions import BUILT_IN_QUESTIONS, BUILT_IN_QUESTIONS_ZH_CN
from .tools import SELECTED_SEARCH_ENGINE, SearchEngine
# Load environment variables
load_dotenv()
# Team configuration
TEAM_MEMBER_CONFIGURATIONS = {
"researcher": {
"name": "researcher",
"desc": (
"Responsible for searching and collecting relevant information, understanding user needs and conducting research analysis"
),
"desc_for_llm": (
"Uses search engines and web crawlers to gather information from the internet. "
"Outputs a Markdown report summarizing findings. Researcher can not do math or programming."
),
"is_optional": False,
},
"coder": {
"name": "coder",
"desc": (
"Responsible for code implementation, debugging and optimization, handling technical programming tasks"
),
"desc_for_llm": (
"Executes Python or Bash commands, performs mathematical calculations, and outputs a Markdown report. "
"Must be used for all mathematical computations."
),
"is_optional": True,
},
}
TEAM_MEMBERS = list(TEAM_MEMBER_CONFIGURATIONS.keys())
__all__ = [
# Other configurations
"TEAM_MEMBERS",
"TEAM_MEMBER_CONFIGURATIONS",
"SELECTED_SEARCH_ENGINE",
"SearchEngine",
"BUILT_IN_QUESTIONS",
"BUILT_IN_QUESTIONS_ZH_CN",
load_yaml_config,
]

View File

@@ -1,21 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from typing import Literal
# Define available LLM types
LLMType = Literal["basic", "reasoning", "vision", "code"]
# Define agent-LLM mapping
AGENT_LLM_MAP: dict[str, LLMType] = {
"coordinator": "basic",
"planner": "basic",
"researcher": "basic",
"analyst": "basic",
"coder": "basic",
"reporter": "basic",
"podcast_script_writer": "basic",
"ppt_composer": "basic",
"prose_writer": "basic",
"prompt_enhancer": "basic",
}

View File

@@ -1,83 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import logging
import os
from dataclasses import dataclass, field, fields
from typing import Any, Optional
from langchain_core.runnables import RunnableConfig
from src.config.loader import get_bool_env, get_int_env, get_str_env
from src.config.report_style import ReportStyle
from src.rag.retriever import Resource
logger = logging.getLogger(__name__)
def get_recursion_limit(default: int = 25) -> int:
"""Get the recursion limit from environment variable or use default.
Args:
default: Default recursion limit if environment variable is not set or invalid
Returns:
int: The recursion limit to use
"""
env_value_str = get_str_env("AGENT_RECURSION_LIMIT", str(default))
parsed_limit = get_int_env("AGENT_RECURSION_LIMIT", default)
if parsed_limit > 0:
logger.info(f"Recursion limit set to: {parsed_limit}")
return parsed_limit
else:
logger.warning(
f"AGENT_RECURSION_LIMIT value '{env_value_str}' (parsed as {parsed_limit}) is not positive. "
f"Using default value {default}."
)
return default
@dataclass(kw_only=True)
class Configuration:
"""The configurable fields."""
resources: list[Resource] = field(
default_factory=list
) # Resources to be used for the research
max_plan_iterations: int = 1 # Maximum number of plan iterations
max_step_num: int = 3 # Maximum number of steps in a plan
max_search_results: int = 3 # Maximum number of search results
mcp_settings: dict = None # MCP settings, including dynamic loaded tools
report_style: str = ReportStyle.ACADEMIC.value # Report style
enable_deep_thinking: bool = False # Whether to enable deep thinking
enforce_web_search: bool = (
False # Enforce at least one web search step in every plan
)
enforce_researcher_search: bool = (
True # Enforce that researcher must use web search tool at least once
)
enable_web_search: bool = (
True # Whether to enable web search, set to False to use only local RAG
)
interrupt_before_tools: list[str] = field(
default_factory=list
) # List of tool names to interrupt before execution
enable_recursion_fallback: bool = (
True # Enable graceful fallback when recursion limit is reached
)
@classmethod
def from_runnable_config(
cls, config: Optional[RunnableConfig] = None
) -> "Configuration":
"""Create a Configuration instance from a RunnableConfig."""
configurable = (
config["configurable"] if config and "configurable" in config else {}
)
values: dict[str, Any] = {
f.name: os.environ.get(f.name.upper(), configurable.get(f.name))
for f in fields(cls)
if f.init
}
return cls(**{k: v for k, v in values.items() if v is not None})

View File

@@ -1,78 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import os
from typing import Any, Dict
import yaml
def get_bool_env(name: str, default: bool = False) -> bool:
val = os.getenv(name)
if val is None:
return default
return str(val).strip().lower() in {"1", "true", "yes", "y", "on"}
def get_str_env(name: str, default: str = "") -> str:
val = os.getenv(name)
return default if val is None else str(val).strip()
def get_int_env(name: str, default: int = 0) -> int:
val = os.getenv(name)
if val is None:
return default
try:
return int(val.strip())
except ValueError:
print(f"Invalid integer value for {name}: {val}. Using default {default}.")
return default
def replace_env_vars(value: str) -> str:
"""Replace environment variables in string values."""
if not isinstance(value, str):
return value
if value.startswith("$"):
env_var = value[1:]
return os.getenv(env_var, env_var)
return value
def process_dict(config: Dict[str, Any]) -> Dict[str, Any]:
"""Recursively process dictionary to replace environment variables."""
if not config:
return {}
result = {}
for key, value in config.items():
if isinstance(value, dict):
result[key] = process_dict(value)
elif isinstance(value, str):
result[key] = replace_env_vars(value)
else:
result[key] = value
return result
_config_cache: Dict[str, Dict[str, Any]] = {}
def load_yaml_config(file_path: str) -> Dict[str, Any]:
"""Load and process YAML configuration file."""
# 如果文件不存在,返回{}
if not os.path.exists(file_path):
return {}
# 检查缓存中是否已存在配置
if file_path in _config_cache:
return _config_cache[file_path]
# 如果缓存中不存在,则加载并处理配置
with open(file_path, "r") as f:
config = yaml.safe_load(f)
processed_config = process_dict(config)
# 将处理后的配置存入缓存
_config_cache[file_path] = processed_config
return processed_config

View File

@@ -1,34 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Built-in questions for Deer.
"""
# English built-in questions
BUILT_IN_QUESTIONS = [
"What factors are influencing AI adoption in healthcare?",
"How does quantum computing impact cryptography?",
"What are the latest developments in renewable energy technology?",
"How is climate change affecting global agriculture?",
"What are the ethical implications of artificial intelligence?",
"What are the current trends in cybersecurity?",
"How is blockchain technology being used outside of cryptocurrency?",
"What advances have been made in natural language processing?",
"How is machine learning transforming the financial industry?",
"What are the environmental impacts of electric vehicles?",
]
# Chinese built-in questions
BUILT_IN_QUESTIONS_ZH_CN = [
"人工智能在医疗保健领域的应用有哪些因素影响?",
"量子计算如何影响密码学?",
"可再生能源技术的最新发展是什么?",
"气候变化如何影响全球农业?",
"人工智能的伦理影响是什么?",
"网络安全的当前趋势是什么?",
"区块链技术在加密货币之外如何应用?",
"自然语言处理领域有哪些进展?",
"机器学习如何改变金融行业?",
"电动汽车对环境有什么影响?",
]

View File

@@ -1,9 +0,0 @@
import enum
class ReportStyle(enum.Enum):
ACADEMIC = "academic"
POPULAR_SCIENCE = "popular_science"
NEWS = "news"
SOCIAL_MEDIA = "social_media"
STRATEGIC_INVESTMENT = "strategic_investment"

View File

@@ -1,40 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import enum
import os
from dotenv import load_dotenv
load_dotenv()
class SearchEngine(enum.Enum):
TAVILY = "tavily"
INFOQUEST = "infoquest"
DUCKDUCKGO = "duckduckgo"
BRAVE_SEARCH = "brave_search"
ARXIV = "arxiv"
SEARX = "searx"
WIKIPEDIA = "wikipedia"
SERPER = "serper"
class CrawlerEngine(enum.Enum):
JINA = "jina"
INFOQUEST = "infoquest"
# Tool configuration
SELECTED_SEARCH_ENGINE = os.getenv("SEARCH_API", SearchEngine.TAVILY.value)
class RAGProvider(enum.Enum):
DIFY = "dify"
RAGFLOW = "ragflow"
VIKINGDB_KNOWLEDGE_BASE = "vikingdb_knowledge_base"
MOI = "moi"
MILVUS = "milvus"
QDRANT = "qdrant"
SELECTED_RAG_PROVIDER = os.getenv("RAG_PROVIDER")

View File

@@ -1,9 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from .article import Article
from .crawler import Crawler
from .jina_client import JinaClient
from .readability_extractor import ReadabilityExtractor
__all__ = ["Article", "Crawler", "JinaClient", "ReadabilityExtractor"]

View File

@@ -1,53 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import re
from urllib.parse import urljoin
from markdownify import markdownify as md
class Article:
url: str
def __init__(self, title: str, html_content: str):
self.title = title
self.html_content = html_content
def to_markdown(self, including_title: bool = True) -> str:
markdown = ""
if including_title:
markdown += f"# {self.title}\n\n"
if self.html_content is None or not str(self.html_content).strip():
markdown += "*No content available*\n"
else:
markdown += md(self.html_content)
return markdown
def to_message(self) -> list[dict]:
image_pattern = r"!\[.*?\]\((.*?)\)"
content: list[dict[str, str]] = []
markdown = self.to_markdown()
if not markdown or not markdown.strip():
return [{"type": "text", "text": "No content available"}]
parts = re.split(image_pattern, markdown)
for i, part in enumerate(parts):
if i % 2 == 1:
image_url = urljoin(self.url, part.strip())
content.append({"type": "image_url", "image_url": {"url": image_url}})
else:
text_part = part.strip()
if text_part:
content.append({"type": "text", "text": text_part})
# If after processing all parts, content is still empty, provide a fallback message.
if not content:
content = [{"type": "text", "text": "No content available"}]
return content

View File

@@ -1,236 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import re
import logging
from src.config.tools import CrawlerEngine
from src.config import load_yaml_config
from src.crawler.article import Article
from src.crawler.infoquest_client import InfoQuestClient
from src.crawler.jina_client import JinaClient
from src.crawler.readability_extractor import ReadabilityExtractor
logger = logging.getLogger(__name__)
def safe_truncate(text: str, max_length: int = 500) -> str:
"""
Safely truncate text to a maximum length without breaking multi-byte characters.
Args:
text: The text to truncate
max_length: Maximum number of characters to keep
Returns:
Truncated text that is safe to use without encoding issues
"""
if text is None:
return None
if len(text) <= max_length:
return text
# Ensure max_length is at least 3 to accommodate the placeholder
if max_length < 3:
return "..."[:max_length]
# Use Python's built-in textwrap.shorten which handles unicode safely
try:
import textwrap
return textwrap.shorten(text, width=max_length, placeholder="...")
except (ImportError, TypeError):
# Fallback for older Python versions or if textwrap.shorten has issues
# Truncate to max_length - 3 to make room for "..."
truncated = text[:max_length - 3]
# Remove any incomplete Unicode surrogate pair
while truncated and ord(truncated[-1]) >= 0xD800 and ord(truncated[-1]) <= 0xDFFF:
truncated = truncated[:-1]
return truncated + "..."
def is_html_content(content: str) -> bool:
"""
Check if the provided content is HTML.
Uses a more robust detection method that checks for common HTML patterns
including DOCTYPE declarations, HTML tags, and other HTML markers.
"""
if not content or not content.strip():
return False
content = content.strip()
# Check for HTML comments
if content.startswith('<!--') and '-->' in content:
return True
# Check for DOCTYPE declarations (case insensitive)
if re.match(r'^<!DOCTYPE\s+html', content, re.IGNORECASE):
return True
# Check for XML declarations followed by HTML
if content.startswith('<?xml') and '<html' in content:
return True
# Check for common HTML tags at the beginning
html_start_patterns = [
r'^<html',
r'^<head',
r'^<body',
r'^<title',
r'^<meta',
r'^<link',
r'^<script',
r'^<style',
r'^<div',
r'^<p>',
r'^<p\s',
r'^<span',
r'^<h[1-6]',
r'^<!DOCTYPE',
r'^<\!DOCTYPE', # Some variations
]
for pattern in html_start_patterns:
if re.match(pattern, content, re.IGNORECASE):
return True
# Check for any HTML-like tags in the content (more permissive)
if re.search(r'<[^>]+>', content):
# Additional check: ensure it's not just XML or other markup
# Look for common HTML attributes or elements
html_indicators = [
r'href\s*=',
r'src\s*=',
r'class\s*=',
r'id\s*=',
r'<img\s',
r'<a\s',
r'<div',
r'<p>',
r'<p\s',
r'<!DOCTYPE',
]
for indicator in html_indicators:
if re.search(indicator, content, re.IGNORECASE):
return True
# Also check for self-closing HTML tags
self_closing_tags = [
r'<img\s+[^>]*?/>',
r'<br\s*/?>',
r'<hr\s*/?>',
r'<input\s+[^>]*?/>',
r'<meta\s+[^>]*?/>',
r'<link\s+[^>]*?/>',
]
for tag in self_closing_tags:
if re.search(tag, content, re.IGNORECASE):
return True
return False
class Crawler:
def crawl(self, url: str) -> Article:
# To help LLMs better understand content, we extract clean
# articles from HTML, convert them to markdown, and split
# them into text and image blocks for one single and unified
# LLM message.
#
# The system supports multiple crawler engines:
# - Jina: An accessible solution, though with some limitations in readability extraction
# - InfoQuest: A BytePlus product offering advanced capabilities with configurable parameters
# like fetch_time, timeout, and navi_timeout.
#
# Instead of using Jina's own markdown converter, we'll use
# our own solution to get better readability results.
# Get crawler configuration
config = load_yaml_config("conf.yaml")
crawler_config = config.get("CRAWLER_ENGINE", {})
# Get the selected crawler tool based on configuration
crawler_client = self._select_crawler_tool(crawler_config)
html = self._crawl_with_tool(crawler_client, url)
# Check if we got valid HTML content
if not html or not html.strip():
logger.warning(f"Empty content received from URL {url}")
article = Article(
title="Empty Content",
html_content="<p>No content could be extracted from this page</p>"
)
article.url = url
return article
# Check if content is actually HTML using more robust detection
if not is_html_content(html):
logger.warning(f"Non-HTML content received from URL {url}, creating fallback article")
# Return a simple article with the raw content (safely truncated)
article = Article(
title="Non-HTML Content",
html_content=f"<p>This URL returned content that cannot be parsed as HTML. Raw content: {safe_truncate(html, 500)}</p>"
)
article.url = url
return article
try:
extractor = ReadabilityExtractor()
article = extractor.extract_article(html)
except Exception as e:
logger.error(f"Failed to extract article from {url}: {repr(e)}")
# Fall back to a simple article with the raw HTML (safely truncated)
article = Article(
title="Content Extraction Failed",
html_content=f"<p>Content extraction failed. Raw content: {safe_truncate(html, 500)}</p>"
)
article.url = url
return article
article.url = url
return article
def _select_crawler_tool(self, crawler_config: dict):
# Only check engine from configuration file
engine = crawler_config.get("engine", CrawlerEngine.JINA.value)
if engine == CrawlerEngine.JINA.value:
logger.info(f"Selecting Jina crawler engine")
return JinaClient()
elif engine == CrawlerEngine.INFOQUEST.value:
logger.info(f"Selecting InfoQuest crawler engine")
# Read timeout parameters directly from crawler_config root level
# These parameters are only effective when engine is set to "infoquest"
fetch_time = crawler_config.get("fetch_time", -1)
timeout = crawler_config.get("timeout", -1)
navi_timeout = crawler_config.get("navi_timeout", -1)
# Log the configuration being used
if fetch_time > 0 or timeout > 0 or navi_timeout > 0:
logger.debug(
f"Initializing InfoQuestCrawler with parameters: "
f"fetch_time={fetch_time}, "
f"timeout={timeout}, "
f"navi_timeout={navi_timeout}"
)
# Initialize InfoQuestClient with the parameters from configuration
return InfoQuestClient(
fetch_time=fetch_time,
timeout=timeout,
navi_timeout=navi_timeout
)
else:
raise ValueError(f"Unsupported crawler engine: {engine}")
def _crawl_with_tool(self, crawler_client, url: str) -> str:
logger.info(f"Crawling URL: {url} using {crawler_client.__class__.__name__}")
try:
return crawler_client.crawl(url, return_format="html")
except Exception as e:
logger.error(f"Failed to fetch URL {url} using {crawler_client.__class__.__name__}: {repr(e)}")
raise

View File

@@ -1,153 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""Util that calls InfoQuest Crawler API.
In order to set this up, follow instructions at:
https://docs.byteplus.com/en/docs/InfoQuest/What_is_Info_Quest
"""
import json
import logging
import os
from typing import Dict, Any
import requests
logger = logging.getLogger(__name__)
class InfoQuestClient:
"""Client for interacting with the InfoQuest web crawling API."""
def __init__(self, fetch_time: int = -1, timeout: int = -1, navi_timeout: int = -1):
logger.info(
"\n============================================\n"
"🚀 BytePlus InfoQuest Crawler Initialization 🚀\n"
"============================================"
)
self.fetch_time = fetch_time
self.timeout = timeout
self.navi_timeout = navi_timeout
self.api_key_set = bool(os.getenv("INFOQUEST_API_KEY"))
config_details = (
f"\n📋 Configuration Details:\n"
f"├── Fetch Timeout: {fetch_time} {'(Default: No timeout)' if fetch_time == -1 else '(Custom)'}\n"
f"├── Timeout: {timeout} {'(Default: No timeout)' if timeout == -1 else '(Custom)'}\n"
f"├── Navigation Timeout: {navi_timeout} {'(Default: No timeout)' if navi_timeout == -1 else '(Custom)'}\n"
f"└── API Key: {'✅ Configured' if self.api_key_set else '❌ Not set'}"
)
logger.info(config_details)
logger.info("\n" + "*" * 70 + "\n")
def crawl(self, url: str, return_format: str = "html") -> str:
logger.debug("Preparing request for URL: %s", url)
# Prepare headers
headers = self._prepare_headers()
# Prepare request data
data = self._prepare_request_data(url, return_format)
# Log request details
logger.debug(
"InfoQuest Crawler request prepared: endpoint=https://reader.infoquest.bytepluses.com, "
"format=%s",
data.get("format")
)
logger.debug("Sending crawl request to InfoQuest API")
try:
response = requests.post(
"https://reader.infoquest.bytepluses.com",
headers=headers,
json=data
)
# Check if status code is not 200
if response.status_code != 200:
error_message = f"InfoQuest API returned status {response.status_code}: {response.text}"
logger.error(error_message)
return f"Error: {error_message}"
# Check for empty response
if not response.text or not response.text.strip():
error_message = "InfoQuest Crawler API returned empty response"
logger.error("BytePlus InfoQuest Crawler returned empty response for URL: %s", url)
return f"Error: {error_message}"
# Try to parse response as JSON and extract reader_result
try:
response_data = json.loads(response.text)
# Extract reader_result if it exists
if "reader_result" in response_data:
logger.debug("Successfully extracted reader_result from JSON response")
return response_data["reader_result"]
elif "content" in response_data:
# Fallback to content field if reader_result is not available
logger.debug("Using content field as fallback")
return response_data["content"]
else:
# If neither field exists, return the original response
logger.warning("Neither reader_result nor content field found in JSON response")
except json.JSONDecodeError:
# If response is not JSON, return the original text
logger.debug("Response is not in JSON format, returning as-is")
# Print partial response for debugging
if logger.isEnabledFor(logging.DEBUG):
response_sample = response.text[:200] + ("..." if len(response.text) > 200 else "")
logger.debug(
"Successfully received response, content length: %d bytes, first 200 chars: %s",
len(response.text), response_sample
)
return response.text
except Exception as e:
error_message = f"Request to InfoQuest API failed: {str(e)}"
logger.error(error_message)
return f"Error: {error_message}"
def _prepare_headers(self) -> Dict[str, str]:
"""Prepare request headers."""
headers = {
"Content-Type": "application/json",
}
# Add API key if available
if os.getenv("INFOQUEST_API_KEY"):
headers["Authorization"] = f"Bearer {os.getenv('INFOQUEST_API_KEY')}"
logger.debug("API key added to request headers")
else:
logger.warning(
"InfoQuest API key is not set. Provide your own key for authentication."
)
return headers
def _prepare_request_data(self, url: str, return_format: str) -> Dict[str, Any]:
"""Prepare request data with formatted parameters."""
# Normalize return_format
if return_format and return_format.lower() == "html":
normalized_format = "HTML"
else:
normalized_format = return_format
data = {"url": url, "format": normalized_format}
# Add timeout parameters if set to positive values
timeout_params = {}
if self.fetch_time > 0:
timeout_params["fetch_time"] = self.fetch_time
if self.timeout > 0:
timeout_params["timeout"] = self.timeout
if self.navi_timeout > 0:
timeout_params["navi_timeout"] = self.navi_timeout
# Log applied timeout parameters
if timeout_params:
logger.debug("Applying timeout parameters: %s", timeout_params)
data.update(timeout_params)
return data

View File

@@ -1,42 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import logging
import os
import requests
logger = logging.getLogger(__name__)
class JinaClient:
def crawl(self, url: str, return_format: str = "html") -> str:
headers = {
"Content-Type": "application/json",
"X-Return-Format": return_format,
}
if os.getenv("JINA_API_KEY"):
headers["Authorization"] = f"Bearer {os.getenv('JINA_API_KEY')}"
else:
logger.warning(
"Jina API key is not set. Provide your own key to access a higher rate limit. See https://jina.ai/reader for more information."
)
data = {"url": url}
try:
response = requests.post("https://r.jina.ai/", headers=headers, json=data)
if response.status_code != 200:
error_message = f"Jina API returned status {response.status_code}: {response.text}"
logger.error(error_message)
return f"Error: {error_message}"
if not response.text or not response.text.strip():
error_message = "Jina API returned empty response"
logger.error(error_message)
return f"Error: {error_message}"
return response.text
except Exception as e:
error_message = f"Request to Jina API failed: {str(e)}"
logger.error(error_message)
return f"Error: {error_message}"

View File

@@ -1,29 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import logging
from readabilipy import simple_json_from_html_string
from .article import Article
logger = logging.getLogger(__name__)
class ReadabilityExtractor:
def extract_article(self, html: str) -> Article:
article = simple_json_from_html_string(html, use_readability=True)
content = article.get("content")
if not content or not str(content).strip():
logger.warning("Readability extraction returned empty content")
content = "<p>No content could be extracted from this page</p>"
title = article.get("title")
if not title or not str(title).strip():
title = "Untitled"
return Article(
title=title,
html_content=content,
)

View File

@@ -1,21 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Report Quality Evaluation Module for DeerFlow.
This module provides objective methods to evaluate generated report quality,
including automated metrics and LLM-based evaluation.
"""
from .evaluator import ReportEvaluator
from .metrics import ReportMetrics, compute_metrics
from .llm_judge import LLMJudge, evaluate_with_llm
__all__ = [
"ReportEvaluator",
"ReportMetrics",
"compute_metrics",
"LLMJudge",
"evaluate_with_llm",
]

View File

@@ -1,249 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Combined report evaluator orchestrating both automated metrics and LLM evaluation.
"""
import logging
from dataclasses import dataclass
from typing import Any, Dict, Optional
from .llm_judge import EvaluationResult, LLMJudge
from .metrics import ReportMetrics, compute_metrics, get_word_count_target
logger = logging.getLogger(__name__)
@dataclass
class CombinedEvaluation:
"""Combined evaluation results from metrics and LLM judge."""
metrics: ReportMetrics
llm_evaluation: Optional[EvaluationResult]
final_score: float
grade: str
summary: str
def to_dict(self) -> Dict[str, Any]:
"""Convert to dictionary format."""
return {
"metrics": self.metrics.to_dict(),
"llm_evaluation": (
self.llm_evaluation.to_dict() if self.llm_evaluation else None
),
"final_score": self.final_score,
"grade": self.grade,
"summary": self.summary,
}
def score_to_grade(score: float) -> str:
"""Convert numeric score to letter grade."""
if score >= 9.0:
return "A+"
elif score >= 8.5:
return "A"
elif score >= 8.0:
return "A-"
elif score >= 7.5:
return "B+"
elif score >= 7.0:
return "B"
elif score >= 6.5:
return "B-"
elif score >= 6.0:
return "C+"
elif score >= 5.5:
return "C"
elif score >= 5.0:
return "C-"
elif score >= 4.0:
return "D"
else:
return "F"
class ReportEvaluator:
"""
Combined report evaluator using both automated metrics and LLM-as-Judge.
This evaluator provides comprehensive report quality assessment by:
1. Computing automated metrics (fast, deterministic)
2. Running LLM-based evaluation (nuanced, contextual)
3. Combining both for a final score and grade
"""
def __init__(self, llm: Any = None, use_llm: bool = True):
"""
Initialize the evaluator.
Args:
llm: Optional LLM instance for LLM-as-Judge evaluation
use_llm: Whether to use LLM evaluation (can be disabled for speed)
"""
self.use_llm = use_llm
self.llm_judge = LLMJudge(llm=llm) if use_llm else None
def _compute_metrics_score(
self, metrics: ReportMetrics, report_style: str
) -> float:
"""
Convert automated metrics to a 0-10 score.
Scoring breakdown:
- Section coverage: 30%
- Citation quality: 25%
- Word count compliance: 20%
- Source diversity: 15%
- Image inclusion: 10%
"""
score = 0.0
section_score = metrics.section_coverage_score * 10
score += section_score * 0.30
citation_score = min(metrics.citation_count / 10, 1.0) * 10
score += citation_score * 0.25
target = get_word_count_target(report_style)
if target:
if target["min"] <= metrics.word_count <= target["max"]:
word_score = 10.0
elif metrics.word_count < target["min"]:
word_score = (metrics.word_count / target["min"]) * 8
else:
excess_ratio = metrics.word_count / target["max"]
word_score = max(10 - (excess_ratio - 1) * 5, 5)
score += word_score * 0.20
diversity_score = min(metrics.unique_sources / 5, 1.0) * 10
score += diversity_score * 0.15
image_score = min(metrics.image_count / 3, 1.0) * 10
score += image_score * 0.10
return round(score, 2)
def _generate_summary(
self,
metrics: ReportMetrics,
llm_eval: Optional[EvaluationResult],
final_score: float,
grade: str,
) -> str:
"""Generate a human-readable evaluation summary."""
lines = [f"Report Grade: {grade} ({final_score}/10)", ""]
lines.append("**Automated Metrics:**")
lines.append(f"- Word Count: {metrics.word_count}")
lines.append(f"- Citations: {metrics.citation_count}")
lines.append(f"- Unique Sources: {metrics.unique_sources}")
lines.append(f"- Images: {metrics.image_count}")
lines.append(
f"- Section Coverage: {metrics.section_coverage_score * 100:.0f}%"
)
if metrics.sections_missing:
lines.append(f"- Missing Sections: {', '.join(metrics.sections_missing)}")
if llm_eval:
lines.append("")
lines.append("**LLM Evaluation:**")
for criterion, score in llm_eval.scores.items():
lines.append(f"- {criterion.replace('_', ' ').title()}: {score}/10")
if llm_eval.strengths:
lines.append("")
lines.append("**Strengths:**")
for strength in llm_eval.strengths[:3]:
lines.append(f"- {strength}")
if llm_eval.weaknesses:
lines.append("")
lines.append("**Areas for Improvement:**")
for weakness in llm_eval.weaknesses[:3]:
lines.append(f"- {weakness}")
return "\n".join(lines)
async def evaluate(
self,
report: str,
query: str,
report_style: str = "default",
) -> CombinedEvaluation:
"""
Evaluate a report using both metrics and LLM.
Args:
report: The report text to evaluate
query: The original research query
report_style: The style of report
Returns:
CombinedEvaluation with full results
"""
metrics = compute_metrics(report, report_style)
metrics_score = self._compute_metrics_score(metrics, report_style)
llm_eval = None
if self.use_llm and self.llm_judge:
try:
llm_eval = await self.llm_judge.evaluate(report, query, report_style)
except Exception as e:
logger.warning(f"LLM evaluation failed, using metrics only: {e}")
if llm_eval and llm_eval.overall_score > 0:
final_score = (metrics_score * 0.4) + (llm_eval.weighted_score * 0.6)
else:
final_score = metrics_score
final_score = round(final_score, 2)
grade = score_to_grade(final_score)
summary = self._generate_summary(metrics, llm_eval, final_score, grade)
return CombinedEvaluation(
metrics=metrics,
llm_evaluation=llm_eval,
final_score=final_score,
grade=grade,
summary=summary,
)
def evaluate_sync(
self,
report: str,
query: str,
report_style: str = "default",
) -> CombinedEvaluation:
"""Synchronous version of evaluate."""
import asyncio
return asyncio.run(self.evaluate(report, query, report_style))
def evaluate_metrics_only(
self,
report: str,
report_style: str = "default",
) -> Dict[str, Any]:
"""
Quick evaluation using only automated metrics (no LLM).
Args:
report: The report text to evaluate
report_style: The style of report
Returns:
Dictionary with metrics and score
"""
metrics = compute_metrics(report, report_style)
metrics_score = self._compute_metrics_score(metrics, report_style)
grade = score_to_grade(metrics_score)
return {
"metrics": metrics.to_dict(),
"score": metrics_score,
"grade": grade,
}

View File

@@ -1,282 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
LLM-as-Judge evaluation for report quality.
Uses an LLM to evaluate reports on multiple quality dimensions,
providing more nuanced assessment than automated metrics alone.
"""
import json
import logging
from dataclasses import dataclass
from typing import Any, Dict, List, Optional
from langchain_core.messages import HumanMessage, SystemMessage
logger = logging.getLogger(__name__)
# Maximum characters of report content to send to the LLM for evaluation.
# This limit prevents exceeding LLM context windows and controls token usage.
MAX_REPORT_LENGTH = 15000
EVALUATION_CRITERIA = {
"factual_accuracy": {
"description": "Are claims supported by cited sources? Is information accurate and verifiable?",
"weight": 0.25,
},
"completeness": {
"description": "Does the report comprehensively cover all aspects of the topic?",
"weight": 0.20,
},
"coherence": {
"description": "Is the report logically structured, well-organized, and easy to follow?",
"weight": 0.20,
},
"relevance": {
"description": "Does the content directly address the research question without unnecessary tangents?",
"weight": 0.15,
},
"citation_quality": {
"description": "Are sources credible, diverse, and properly cited?",
"weight": 0.10,
},
"writing_quality": {
"description": "Is the writing clear, professional, and appropriate for the target audience?",
"weight": 0.10,
},
}
JUDGE_SYSTEM_PROMPT = """You are an expert report quality evaluator. Your task is to objectively assess the quality of research reports.
Evaluate the report on the following criteria, scoring each from 1-10:
1. **Factual Accuracy** (1-10): Are claims supported by cited sources? Is information accurate?
2. **Completeness** (1-10): Does the report cover all aspects of the topic comprehensively?
3. **Coherence** (1-10): Is the report logically structured and easy to follow?
4. **Relevance** (1-10): Does content directly address the research question?
5. **Citation Quality** (1-10): Are sources credible, diverse, and properly cited?
6. **Writing Quality** (1-10): Is the writing clear and appropriate for the audience?
Respond ONLY with a valid JSON object in this exact format:
{
"scores": {
"factual_accuracy": <1-10>,
"completeness": <1-10>,
"coherence": <1-10>,
"relevance": <1-10>,
"citation_quality": <1-10>,
"writing_quality": <1-10>
},
"overall_score": <1-10>,
"strengths": ["strength1", "strength2"],
"weaknesses": ["weakness1", "weakness2"],
"suggestions": ["suggestion1", "suggestion2"]
}
Be objective and thorough in your evaluation."""
@dataclass
class EvaluationResult:
"""Container for LLM evaluation results."""
scores: Dict[str, int]
overall_score: float
weighted_score: float
strengths: List[str]
weaknesses: List[str]
suggestions: List[str]
raw_response: Optional[str] = None
def to_dict(self) -> Dict[str, Any]:
"""Convert evaluation result to dictionary."""
return {
"scores": self.scores,
"overall_score": self.overall_score,
"weighted_score": self.weighted_score,
"strengths": self.strengths,
"weaknesses": self.weaknesses,
"suggestions": self.suggestions,
}
class LLMJudge:
"""LLM-based report quality evaluator."""
def __init__(self, llm: Any = None):
"""
Initialize the LLM Judge.
Args:
llm: LangChain-compatible LLM instance. If None, will be created on demand.
"""
self._llm = llm
def _get_llm(self):
"""Get or create the LLM instance."""
if self._llm is None:
from src.llms.llm import get_llm_by_type
self._llm = get_llm_by_type("basic")
return self._llm
def _calculate_weighted_score(self, scores: Dict[str, int]) -> float:
"""Calculate weighted average score based on criteria weights."""
total_weight = 0
weighted_sum = 0
for criterion, score in scores.items():
if criterion in EVALUATION_CRITERIA:
weight = EVALUATION_CRITERIA[criterion]["weight"]
weighted_sum += score * weight
total_weight += weight
if total_weight > 0:
return round(weighted_sum / total_weight, 2)
return 0.0
def _parse_response(self, response: str) -> Dict[str, Any]:
"""Parse LLM response into structured format."""
try:
json_match = response
if "```json" in response:
json_match = response.split("```json")[1].split("```")[0]
elif "```" in response:
json_match = response.split("```")[1].split("```")[0]
return json.loads(json_match.strip())
except (json.JSONDecodeError, IndexError) as e:
logger.warning(f"Failed to parse LLM response: {e}")
return {
"scores": {
"factual_accuracy": 5,
"completeness": 5,
"coherence": 5,
"relevance": 5,
"citation_quality": 5,
"writing_quality": 5,
},
"overall_score": 5,
"strengths": ["Unable to parse evaluation"],
"weaknesses": ["Evaluation parsing failed"],
"suggestions": ["Please re-run evaluation"],
}
async def evaluate(
self,
report: str,
query: str,
report_style: str = "default",
) -> EvaluationResult:
"""
Evaluate a report using LLM-as-Judge.
Args:
report: The report text to evaluate
query: The original research query
report_style: The style of report for context
Returns:
EvaluationResult with scores and feedback
"""
llm = self._get_llm()
user_prompt = f"""Please evaluate the following research report.
**Original Research Query:** {query}
**Report Style:** {report_style}
**Report to Evaluate:**
{report[:MAX_REPORT_LENGTH]}
Provide your evaluation in the specified JSON format."""
messages = [
SystemMessage(content=JUDGE_SYSTEM_PROMPT),
HumanMessage(content=user_prompt),
]
try:
response = await llm.ainvoke(messages)
response_text = (
response.content if hasattr(response, "content") else str(response)
)
parsed = self._parse_response(response_text)
scores = parsed.get("scores", {})
weighted_score = self._calculate_weighted_score(scores)
return EvaluationResult(
scores=scores,
overall_score=parsed.get("overall_score", 5),
weighted_score=weighted_score,
strengths=parsed.get("strengths", []),
weaknesses=parsed.get("weaknesses", []),
suggestions=parsed.get("suggestions", []),
raw_response=response_text,
)
except Exception as e:
logger.error(f"LLM evaluation failed: {e}")
return EvaluationResult(
scores={
"factual_accuracy": 0,
"completeness": 0,
"coherence": 0,
"relevance": 0,
"citation_quality": 0,
"writing_quality": 0,
},
overall_score=0,
weighted_score=0,
strengths=[],
weaknesses=[f"Evaluation failed: {str(e)}"],
suggestions=["Please retry evaluation"],
)
def evaluate_sync(
self,
report: str,
query: str,
report_style: str = "default",
) -> EvaluationResult:
"""
Synchronous version of evaluate.
Args:
report: The report text to evaluate
query: The original research query
report_style: The style of report for context
Returns:
EvaluationResult with scores and feedback
"""
import asyncio
return asyncio.run(self.evaluate(report, query, report_style))
async def evaluate_with_llm(
report: str,
query: str,
report_style: str = "default",
llm: Any = None,
) -> EvaluationResult:
"""
Convenience function to evaluate a report with LLM.
Args:
report: The report text to evaluate
query: The original research query
report_style: The style of report for context
llm: Optional LLM instance to use
Returns:
EvaluationResult with scores and feedback
"""
judge = LLMJudge(llm=llm)
return await judge.evaluate(report, query, report_style)

View File

@@ -1,229 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""
Automated metrics for report quality evaluation.
These metrics can be computed without LLM calls, providing fast and
deterministic quality assessment.
"""
import re
from dataclasses import dataclass, field
from typing import Dict, List, Optional
from urllib.parse import urlparse
@dataclass
class ReportMetrics:
"""Container for computed report metrics."""
word_count: int = 0
citation_count: int = 0
unique_sources: int = 0
image_count: int = 0
section_count: int = 0
sections_found: List[str] = field(default_factory=list)
sections_missing: List[str] = field(default_factory=list)
section_coverage_score: float = 0.0
has_title: bool = False
has_key_points: bool = False
has_overview: bool = False
has_citations_section: bool = False
def to_dict(self) -> Dict:
"""Convert metrics to dictionary."""
return {
"word_count": self.word_count,
"citation_count": self.citation_count,
"unique_sources": self.unique_sources,
"image_count": self.image_count,
"section_count": self.section_count,
"sections_found": self.sections_found,
"sections_missing": self.sections_missing,
"section_coverage_score": self.section_coverage_score,
"has_title": self.has_title,
"has_key_points": self.has_key_points,
"has_overview": self.has_overview,
"has_citations_section": self.has_citations_section,
}
# Required sections for different report styles
REPORT_STYLE_SECTIONS = {
"default": [
"title",
"key_points",
"overview",
"detailed_analysis",
"key_citations",
],
"academic": [
"title",
"key_points",
"overview",
"detailed_analysis",
"literature_review",
"methodology",
"key_citations",
],
"news": [
"title",
"key_points",
"overview",
"detailed_analysis",
"key_citations",
],
"popular_science": [
"title",
"key_points",
"overview",
"detailed_analysis",
"key_citations",
],
"social_media": [
"title",
"key_points",
"overview",
"key_citations",
],
"strategic_investment": [
"title",
"key_points",
"overview",
"detailed_analysis",
"executive_summary",
"market_analysis",
"technology_analysis",
"investment_recommendations",
"key_citations",
],
}
# Section name patterns for detection (supports both English and Chinese)
SECTION_PATTERNS = {
"title": r"^#\s+.+",
"key_points": r"(?:key\s*points|要点|关键发现|核心观点)",
"overview": r"(?:overview|概述|简介|背景)",
"detailed_analysis": r"(?:detailed\s*analysis|详细分析|深度分析|分析)",
"key_citations": r"(?:key\s*citations|references|参考文献|引用|来源)",
"literature_review": r"(?:literature\s*review|文献综述|研究回顾)",
"methodology": r"(?:methodology|方法论|研究方法)",
"executive_summary": r"(?:executive\s*summary|执行摘要|投资建议)",
"market_analysis": r"(?:market\s*analysis|市场分析|产业分析)",
"technology_analysis": r"(?:technology|技术.*(?:分析|解析|深度))",
"investment_recommendations": r"(?:investment.*recommend|投资建议|投资评级)",
}
def count_words(text: str) -> int:
"""Count words in text, handling both English and Chinese."""
english_words = len(re.findall(r"\b[a-zA-Z]+\b", text))
chinese_chars = len(re.findall(r"[\u4e00-\u9fff]", text))
return english_words + chinese_chars
def count_citations(text: str) -> int:
"""Count markdown-style citations [text](url)."""
pattern = r"\[[^\]]*\]\(https?://[^\s\)]+\)"
return len(re.findall(pattern, text))
def extract_domains(text: str) -> List[str]:
"""Extract unique domains from URLs in the text."""
url_pattern = r"https?://([^\s\)\]]+)"
urls = re.findall(url_pattern, text)
domains = set()
for url in urls:
try:
parsed = urlparse(f"http://{url}")
domain = parsed.netloc or url.split("/")[0]
domain = domain.lower().replace("www.", "")
if domain:
domains.add(domain)
except Exception:
continue
return list(domains)
def count_images(text: str) -> int:
"""Count markdown images ![alt](url)."""
pattern = r"!\[[^\]]*\]\([^)]+\)"
return len(re.findall(pattern, text))
def detect_sections(text: str, report_style: str = "default") -> Dict[str, bool]:
"""Detect which sections are present in the report."""
required_sections = REPORT_STYLE_SECTIONS.get(
report_style, REPORT_STYLE_SECTIONS["default"]
)
detected = {}
text_lower = text.lower()
for section in required_sections:
pattern = SECTION_PATTERNS.get(section, section.replace("_", r"\s*"))
if section == "title":
detected[section] = bool(re.search(pattern, text, re.MULTILINE))
else:
detected[section] = bool(
re.search(pattern, text_lower, re.IGNORECASE | re.MULTILINE)
)
return detected
def compute_metrics(
report: str, report_style: str = "default", target_word_count: Optional[int] = None
) -> ReportMetrics:
"""
Compute automated metrics for a report.
Args:
report: The report text in markdown format
report_style: The style of report (academic, news, etc.)
target_word_count: Optional target word count for compliance check
Returns:
ReportMetrics object with computed values
"""
metrics = ReportMetrics()
metrics.word_count = count_words(report)
metrics.citation_count = count_citations(report)
domains = extract_domains(report)
metrics.unique_sources = len(domains)
metrics.image_count = count_images(report)
sections_detected = detect_sections(report, report_style)
metrics.sections_found = [s for s, found in sections_detected.items() if found]
metrics.sections_missing = [
s for s, found in sections_detected.items() if not found
]
metrics.section_count = len(metrics.sections_found)
total_sections = len(sections_detected)
if total_sections > 0:
metrics.section_coverage_score = len(metrics.sections_found) / total_sections
metrics.has_title = sections_detected.get("title", False)
metrics.has_key_points = sections_detected.get("key_points", False)
metrics.has_overview = sections_detected.get("overview", False)
metrics.has_citations_section = sections_detected.get("key_citations", False)
return metrics
def get_word_count_target(report_style: str) -> Dict[str, int]:
"""Get target word count range for a report style."""
targets = {
"strategic_investment": {"min": 10000, "max": 15000},
"academic": {"min": 3000, "max": 8000},
"news": {"min": 800, "max": 2000},
"popular_science": {"min": 1500, "max": 4000},
"social_media": {"min": 500, "max": 1500},
"default": {"min": 1000, "max": 5000},
}
return targets.get(report_style, targets["default"])

View File

@@ -1,9 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from .builder import build_graph, build_graph_with_memory
__all__ = [
"build_graph_with_memory",
"build_graph",
]

View File

@@ -1,91 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import END, START, StateGraph
from src.prompts.planner_model import StepType
from .nodes import (
analyst_node,
background_investigation_node,
coder_node,
coordinator_node,
human_feedback_node,
planner_node,
reporter_node,
research_team_node,
researcher_node,
)
from .types import State
def continue_to_running_research_team(state: State):
current_plan = state.get("current_plan")
if not current_plan or not current_plan.steps:
return "planner"
if all(step.execution_res for step in current_plan.steps):
return "planner"
# Find first incomplete step
incomplete_step = None
for step in current_plan.steps:
if not step.execution_res:
incomplete_step = step
break
if not incomplete_step:
return "planner"
if incomplete_step.step_type == StepType.RESEARCH:
return "researcher"
if incomplete_step.step_type == StepType.ANALYSIS:
return "analyst"
if incomplete_step.step_type == StepType.PROCESSING:
return "coder"
return "planner"
def _build_base_graph():
"""Build and return the base state graph with all nodes and edges."""
builder = StateGraph(State)
builder.add_edge(START, "coordinator")
builder.add_node("coordinator", coordinator_node)
builder.add_node("background_investigator", background_investigation_node)
builder.add_node("planner", planner_node)
builder.add_node("reporter", reporter_node)
builder.add_node("research_team", research_team_node)
builder.add_node("researcher", researcher_node)
builder.add_node("analyst", analyst_node)
builder.add_node("coder", coder_node)
builder.add_node("human_feedback", human_feedback_node)
builder.add_edge("background_investigator", "planner")
builder.add_conditional_edges(
"research_team",
continue_to_running_research_team,
["planner", "researcher", "analyst", "coder"],
)
builder.add_edge("reporter", END)
return builder
def build_graph_with_memory():
"""Build and return the agent workflow graph with memory."""
# use persistent memory to save conversation history
# TODO: be compatible with SQLite / PostgreSQL
memory = MemorySaver()
# build state graph
builder = _build_base_graph()
return builder.compile(checkpointer=memory)
def build_graph():
"""Build and return the agent workflow graph without memory."""
# build state graph
builder = _build_base_graph()
return builder.compile()
graph = build_graph()

View File

@@ -1,393 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import json
import logging
import uuid
from datetime import datetime
from typing import List, Optional, Tuple
import psycopg
from langgraph.store.memory import InMemoryStore
from psycopg.rows import dict_row
from pymongo import MongoClient
from src.config.loader import get_bool_env, get_str_env
class ChatStreamManager:
"""
Manages chat stream messages with persistent storage and in-memory caching.
This class handles the storage and retrieval of chat messages using both
an in-memory store for temporary data and MongoDB or PostgreSQL for persistent storage.
It tracks message chunks and consolidates them when a conversation finishes.
Attributes:
store (InMemoryStore): In-memory storage for temporary message chunks
mongo_client (MongoClient): MongoDB client connection
mongo_db (Database): MongoDB database instance
postgres_conn (psycopg.Connection): PostgreSQL connection
logger (logging.Logger): Logger instance for this class
"""
def __init__(
self, checkpoint_saver: bool = False, db_uri: Optional[str] = None
) -> None:
"""
Initialize the ChatStreamManager with database connections.
Args:
db_uri: Database connection URI. Supports MongoDB (mongodb://) and PostgreSQL (postgresql://)
If None, uses LANGGRAPH_CHECKPOINT_DB_URL env var or defaults to localhost
"""
self.logger = logging.getLogger(__name__)
self.store = InMemoryStore()
self.checkpoint_saver = checkpoint_saver
# Use provided URI or fall back to environment variable or default
self.db_uri = db_uri
# Initialize database connections
self.mongo_client = None
self.mongo_db = None
self.postgres_conn = None
if self.checkpoint_saver:
if self.db_uri is None:
self.logger.warning(
"Checkpoint saver is enabled but db_uri is None. "
"Please provide a valid database URI or disable checkpoint saver."
)
elif self.db_uri.startswith("mongodb://"):
self._init_mongodb()
elif self.db_uri.startswith("postgresql://") or self.db_uri.startswith(
"postgres://"
):
self._init_postgresql()
else:
self.logger.warning(
f"Unsupported database URI scheme: {self.db_uri}. "
"Supported schemes: mongodb://, postgresql://, postgres://"
)
else:
self.logger.warning("Checkpoint saver is disabled")
def _init_mongodb(self) -> None:
"""Initialize MongoDB connection."""
try:
self.mongo_client = MongoClient(self.db_uri)
self.mongo_db = self.mongo_client.checkpointing_db
# Test connection
self.mongo_client.admin.command("ping")
self.logger.info("Successfully connected to MongoDB")
except Exception as e:
self.logger.error(f"Failed to connect to MongoDB: {e}")
def _init_postgresql(self) -> None:
"""Initialize PostgreSQL connection and create table if needed."""
try:
self.postgres_conn = psycopg.connect(self.db_uri, row_factory=dict_row)
self.logger.info("Successfully connected to PostgreSQL")
self._create_chat_streams_table()
except Exception as e:
self.logger.error(f"Failed to connect to PostgreSQL: {e}")
def _create_chat_streams_table(self) -> None:
"""Create the chat_streams table if it doesn't exist."""
try:
with self.postgres_conn.cursor() as cursor:
create_table_sql = """
CREATE TABLE IF NOT EXISTS chat_streams (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
thread_id VARCHAR(255) NOT NULL UNIQUE,
messages JSONB NOT NULL,
ts TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_chat_streams_thread_id ON chat_streams(thread_id);
CREATE INDEX IF NOT EXISTS idx_chat_streams_ts ON chat_streams(ts);
"""
cursor.execute(create_table_sql)
self.postgres_conn.commit()
self.logger.info("Chat streams table created/verified successfully")
except Exception as e:
self.logger.error(f"Failed to create chat_streams table: {e}")
if self.postgres_conn:
self.postgres_conn.rollback()
def process_stream_message(
self, thread_id: str, message: str, finish_reason: str
) -> bool:
"""
Process and store a chat stream message chunk.
This method handles individual message chunks during streaming and consolidates
them into a complete message when the stream finishes. Messages are stored
temporarily in memory and permanently in MongoDB when complete.
Args:
thread_id: Unique identifier for the conversation thread
message: The message content or chunk to store
finish_reason: Reason for message completion ("stop", "interrupt", or partial)
Returns:
bool: True if message was processed successfully, False otherwise
"""
if not thread_id or not isinstance(thread_id, str):
self.logger.warning("Invalid thread_id provided")
return False
if not message:
self.logger.warning("Empty message provided")
return False
try:
# Create namespace for this thread's messages
store_namespace: Tuple[str, str] = ("messages", thread_id)
# Get or initialize message cursor for tracking chunks
cursor = self.store.get(store_namespace, "cursor")
current_index = 0
if cursor is None:
# Initialize cursor for new conversation
self.store.put(store_namespace, "cursor", {"index": 0})
else:
# Increment index for next chunk
current_index = int(cursor.value.get("index", 0)) + 1
self.store.put(store_namespace, "cursor", {"index": current_index})
# Store the current message chunk
self.store.put(store_namespace, f"chunk_{current_index}", message)
# Check if conversation is complete and should be persisted
if finish_reason in ("stop", "interrupt"):
return self._persist_complete_conversation(
thread_id, store_namespace, current_index
)
return True
except Exception as e:
self.logger.error(
f"Error processing stream message for thread {thread_id}: {e}"
)
return False
def _persist_complete_conversation(
self, thread_id: str, store_namespace: Tuple[str, str], final_index: int
) -> bool:
"""
Persist completed conversation to database (MongoDB or PostgreSQL).
Retrieves all message chunks from memory store and saves the complete
conversation to the configured database for permanent storage.
Args:
thread_id: Unique identifier for the conversation thread
store_namespace: Namespace tuple for accessing stored messages
final_index: The final chunk index for this conversation
Returns:
bool: True if persistence was successful, False otherwise
"""
try:
# Retrieve all message chunks from memory store
# Get all messages up to the final index including cursor metadata
memories = self.store.search(store_namespace, limit=final_index + 2)
# Extract message content, filtering out cursor metadata
messages: List[str] = []
for item in memories:
value = item.dict().get("value", "")
# Skip cursor metadata, only include actual message chunks
if value and not isinstance(value, dict):
messages.append(str(value))
if not messages:
self.logger.warning(f"No messages found for thread {thread_id}")
return False
if not self.checkpoint_saver:
self.logger.warning("Checkpoint saver is disabled")
return False
# Choose persistence method based on available connection
success = False
if self.mongo_db is not None:
success = self._persist_to_mongodb(thread_id, messages)
elif self.postgres_conn is not None:
success = self._persist_to_postgresql(thread_id, messages)
else:
self.logger.warning("No database connection available")
return False
if success:
try:
for item in memories:
self.store.delete(store_namespace, item.key)
except Exception as e:
self.logger.error(
f"Error cleaning up memory store for thread {thread_id}: {e}"
)
return success
except Exception as e:
self.logger.error(
f"Error persisting conversation for thread {thread_id}: {e}"
)
return False
def _persist_to_mongodb(self, thread_id: str, messages: List[str]) -> bool:
"""Persist conversation to MongoDB."""
try:
# Get MongoDB collection for chat streams
collection = self.mongo_db.chat_streams
# Check if conversation already exists in database
existing_document = collection.find_one({"thread_id": thread_id})
current_timestamp = datetime.now()
if existing_document:
# Append new messages to existing conversation
update_result = collection.update_one(
{"thread_id": thread_id},
{
"$push": {"messages": {"$each": messages}},
"$set": {"ts": current_timestamp}
},
)
self.logger.info(
f"Updated conversation for thread {thread_id}: "
f"{update_result.modified_count} documents modified"
)
return update_result.modified_count > 0
else:
# Create new conversation document
new_document = {
"thread_id": thread_id,
"messages": messages,
"ts": current_timestamp,
"id": uuid.uuid4().hex,
}
insert_result = collection.insert_one(new_document)
self.logger.info(
f"Created new conversation: {insert_result.inserted_id}"
)
return insert_result.inserted_id is not None
except Exception as e:
self.logger.error(f"Error persisting to MongoDB: {e}")
return False
def _persist_to_postgresql(self, thread_id: str, messages: List[str]) -> bool:
"""Persist conversation to PostgreSQL."""
try:
with self.postgres_conn.cursor() as cursor:
# Check if conversation already exists
cursor.execute(
"SELECT id FROM chat_streams WHERE thread_id = %s", (thread_id,)
)
existing_record = cursor.fetchone()
current_timestamp = datetime.now()
messages_json = json.dumps(messages)
if existing_record:
# Append new messages to existing conversation
cursor.execute(
"""
UPDATE chat_streams
SET messages = messages || %s::jsonb, ts = %s
WHERE thread_id = %s
""",
(messages_json, current_timestamp, thread_id),
)
affected_rows = cursor.rowcount
self.postgres_conn.commit()
self.logger.info(
f"Updated conversation for thread {thread_id}: "
f"{affected_rows} rows modified"
)
return affected_rows > 0
else:
# Create new conversation record
conversation_id = uuid.uuid4()
cursor.execute(
"""
INSERT INTO chat_streams (id, thread_id, messages, ts)
VALUES (%s, %s, %s, %s)
""",
(conversation_id, thread_id, messages_json, current_timestamp),
)
affected_rows = cursor.rowcount
self.postgres_conn.commit()
self.logger.info(
f"Created new conversation with ID: {conversation_id}"
)
return affected_rows > 0
except Exception as e:
self.logger.error(f"Error persisting to PostgreSQL: {e}")
if self.postgres_conn:
self.postgres_conn.rollback()
return False
def close(self) -> None:
"""Close database connections."""
try:
if self.mongo_client is not None:
self.mongo_client.close()
self.logger.info("MongoDB connection closed")
except Exception as e:
self.logger.error(f"Error closing MongoDB connection: {e}")
try:
if self.postgres_conn is not None:
self.postgres_conn.close()
self.logger.info("PostgreSQL connection closed")
except Exception as e:
self.logger.error(f"Error closing PostgreSQL connection: {e}")
def __enter__(self):
"""Context manager entry."""
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""Context manager exit - close connections."""
self.close()
# Global instance for backward compatibility
# TODO: Consider using dependency injection instead of global instance
_default_manager = ChatStreamManager(
checkpoint_saver=get_bool_env("LANGGRAPH_CHECKPOINT_SAVER", False),
db_uri=get_str_env("LANGGRAPH_CHECKPOINT_DB_URL", "mongodb://localhost:27017"),
)
def chat_stream_message(thread_id: str, message: str, finish_reason: str) -> bool:
"""
Legacy function wrapper for backward compatibility.
Args:
thread_id: Unique identifier for the conversation thread
message: The message content to store
finish_reason: Reason for message completion
Returns:
bool: True if message was processed successfully
"""
checkpoint_saver = get_bool_env("LANGGRAPH_CHECKPOINT_SAVER", False)
if checkpoint_saver:
return _default_manager.process_stream_message(
thread_id, message, finish_reason
)
else:
return False

File diff suppressed because it is too large Load Diff

View File

@@ -1,48 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from dataclasses import field
from typing import Any
from langgraph.graph import MessagesState
from src.prompts.planner_model import Plan
from src.rag import Resource
class State(MessagesState):
"""State for the agent system, extends MessagesState with next field."""
# Runtime Variables
locale: str = "en-US"
research_topic: str = ""
clarified_research_topic: str = (
"" # Complete/final clarified topic with all clarification rounds
)
observations: list[str] = []
resources: list[Resource] = []
plan_iterations: int = 0
current_plan: Plan | str = None
final_report: str = ""
auto_accepted_plan: bool = False
enable_background_investigation: bool = True
background_investigation_results: str = None
# Citation metadata collected during research
# Format: List of citation dictionaries with url, title, description, etc.
citations: list[dict[str, Any]] = field(default_factory=list)
# Clarification state tracking (disabled by default)
enable_clarification: bool = (
False # Enable/disable clarification feature (default: False)
)
clarification_rounds: int = 0
clarification_history: list[str] = field(default_factory=list)
is_clarification_complete: bool = False
max_clarification_rounds: int = (
3 # Default: 3 rounds (only used when enable_clarification=True)
)
# Workflow control
goto: str = "planner" # Default next node

View File

@@ -1,113 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from typing import Any
ASSISTANT_SPEAKER_NAMES = {
"coordinator",
"planner",
"researcher",
"coder",
"reporter",
"background_investigator",
}
def get_message_content(message: Any) -> str:
"""Extract message content from dict or LangChain message."""
if isinstance(message, dict):
return message.get("content", "")
return getattr(message, "content", "")
def is_user_message(message: Any) -> bool:
"""Return True if the message originated from the end user."""
if isinstance(message, dict):
role = (message.get("role") or "").lower()
if role in {"user", "human"}:
return True
if role in {"assistant", "system"}:
return False
name = (message.get("name") or "").lower()
if name and name in ASSISTANT_SPEAKER_NAMES:
return False
return role == "" and name not in ASSISTANT_SPEAKER_NAMES
message_type = (getattr(message, "type", "") or "").lower()
name = (getattr(message, "name", "") or "").lower()
if message_type == "human":
return not (name and name in ASSISTANT_SPEAKER_NAMES)
role_attr = getattr(message, "role", None)
if isinstance(role_attr, str) and role_attr.lower() in {"user", "human"}:
return True
additional_role = getattr(message, "additional_kwargs", {}).get("role")
if isinstance(additional_role, str) and additional_role.lower() in {
"user",
"human",
}:
return True
return False
def get_latest_user_message(messages: list[Any]) -> tuple[Any, str]:
"""Return the latest user-authored message and its content."""
for message in reversed(messages or []):
if is_user_message(message):
content = get_message_content(message)
if content:
return message, content
return None, ""
def build_clarified_topic_from_history(
clarification_history: list[str],
) -> tuple[str, list[str]]:
"""Construct clarified topic string from an ordered clarification history."""
sequence = [item for item in clarification_history if item]
if not sequence:
return "", []
if len(sequence) == 1:
return sequence[0], sequence
head, *tail = sequence
clarified_string = f"{head} - {', '.join(tail)}"
return clarified_string, sequence
def reconstruct_clarification_history(
messages: list[Any],
fallback_history: list[str] | None = None,
base_topic: str = "",
) -> list[str]:
"""Rebuild clarification history from user-authored messages, with fallback.
Args:
messages: Conversation messages in chronological order.
fallback_history: Optional existing history to use if no user messages found.
base_topic: Optional topic to use when no user messages are available.
Returns:
A cleaned clarification history containing unique consecutive user contents.
"""
sequence: list[str] = []
for message in messages or []:
if not is_user_message(message):
continue
content = get_message_content(message)
if not content:
continue
if sequence and sequence[-1] == content:
continue
sequence.append(content)
if sequence:
return sequence
fallback = [item for item in (fallback_history or []) if item]
if fallback:
return fallback
base_topic = (base_topic or "").strip()
return [base_topic] if base_topic else []

View File

@@ -1,2 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT

View File

@@ -1,341 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import logging
import os
from pathlib import Path
from typing import Any, Dict, get_args
import httpx
from langchain_core.language_models import BaseChatModel
from langchain_deepseek import ChatDeepSeek
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_openai import AzureChatOpenAI, ChatOpenAI
from src.config import load_yaml_config
from src.config.agents import LLMType
from src.llms.providers.dashscope import ChatDashscope
logger = logging.getLogger(__name__)
# Cache for LLM instances
_llm_cache: dict[LLMType, BaseChatModel] = {}
# Allowed LLM configuration keys to prevent unexpected parameters from being passed
# to LLM constructors (Issue #411 - SEARCH_ENGINE warning fix)
ALLOWED_LLM_CONFIG_KEYS = {
# Common LLM configuration keys
"model",
"api_key",
"base_url",
"api_base",
"max_retries",
"timeout",
"max_tokens",
"temperature",
"top_p",
"frequency_penalty",
"presence_penalty",
"stop",
"n",
"stream",
"logprobs",
"echo",
"best_of",
"logit_bias",
"user",
"seed",
# SSL and HTTP client settings
"verify_ssl",
"http_client",
"http_async_client",
# Platform-specific keys
"platform",
"google_api_key",
# Azure-specific keys
"azure_endpoint",
"azure_deployment",
"api_version",
"azure_ad_token",
"azure_ad_token_provider",
# Dashscope/Doubao specific keys
"extra_body",
# Token limit for context compression (removed before passing to LLM)
"token_limit",
# Default headers
"default_headers",
"default_query",
}
def _get_config_file_path() -> str:
"""Get the path to the configuration file."""
return str((Path(__file__).parent.parent.parent / "conf.yaml").resolve())
def _get_llm_type_config_keys() -> dict[str, str]:
"""Get mapping of LLM types to their configuration keys."""
return {
"reasoning": "REASONING_MODEL",
"basic": "BASIC_MODEL",
"vision": "VISION_MODEL",
"code": "CODE_MODEL",
}
def _get_env_llm_conf(llm_type: str) -> Dict[str, Any]:
"""
Get LLM configuration from environment variables.
Environment variables should follow the format: {LLM_TYPE}__{KEY}
e.g., BASIC_MODEL__api_key, BASIC_MODEL__base_url
"""
prefix = f"{llm_type.upper()}_MODEL__"
conf = {}
for key, value in os.environ.items():
if key.startswith(prefix):
conf_key = key[len(prefix) :].lower()
conf[conf_key] = value
return conf
def _create_llm_use_conf(llm_type: LLMType, conf: Dict[str, Any]) -> BaseChatModel:
"""Create LLM instance using configuration."""
llm_type_config_keys = _get_llm_type_config_keys()
config_key = llm_type_config_keys.get(llm_type)
if not config_key:
raise ValueError(f"Unknown LLM type: {llm_type}")
llm_conf = conf.get(config_key, {})
if not isinstance(llm_conf, dict):
raise ValueError(f"Invalid LLM configuration for {llm_type}: {llm_conf}")
# Get configuration from environment variables
env_conf = _get_env_llm_conf(llm_type)
# Merge configurations, with environment variables taking precedence
merged_conf = {**llm_conf, **env_conf}
# Filter out unexpected parameters to prevent LangChain warnings (Issue #411)
# This prevents configuration keys like SEARCH_ENGINE from being passed to LLM constructors
allowed_keys_lower = {k.lower() for k in ALLOWED_LLM_CONFIG_KEYS}
unexpected_keys = [key for key in merged_conf.keys() if key.lower() not in allowed_keys_lower]
for key in unexpected_keys:
removed_value = merged_conf.pop(key)
logger.warning(
f"Removed unexpected LLM configuration key '{key}'. "
f"This key is not a valid LLM parameter and may have been placed in the wrong section of conf.yaml. "
f"Valid LLM config keys include: model, api_key, base_url, max_retries, temperature, etc."
)
# Remove unnecessary parameters when initializing the client
if "token_limit" in merged_conf:
merged_conf.pop("token_limit")
if not merged_conf:
raise ValueError(f"No configuration found for LLM type: {llm_type}")
# Add max_retries to handle rate limit errors
if "max_retries" not in merged_conf:
merged_conf["max_retries"] = 3
# Handle SSL verification settings
verify_ssl = merged_conf.pop("verify_ssl", True)
# Create custom HTTP client if SSL verification is disabled
if not verify_ssl:
http_client = httpx.Client(verify=False)
http_async_client = httpx.AsyncClient(verify=False)
merged_conf["http_client"] = http_client
merged_conf["http_async_client"] = http_async_client
# Check if it's Google AI Studio platform based on configuration
platform = merged_conf.get("platform", "").lower()
is_google_aistudio = platform == "google_aistudio" or platform == "google-aistudio"
if is_google_aistudio:
# Handle Google AI Studio specific configuration
gemini_conf = merged_conf.copy()
# Map common keys to Google AI Studio specific keys
if "api_key" in gemini_conf:
gemini_conf["google_api_key"] = gemini_conf.pop("api_key")
# Remove base_url and platform since Google AI Studio doesn't use them
gemini_conf.pop("base_url", None)
gemini_conf.pop("platform", None)
# Remove unsupported parameters for Google AI Studio
gemini_conf.pop("http_client", None)
gemini_conf.pop("http_async_client", None)
return ChatGoogleGenerativeAI(**gemini_conf)
if "azure_endpoint" in merged_conf or os.getenv("AZURE_OPENAI_ENDPOINT"):
return AzureChatOpenAI(**merged_conf)
# Check if base_url is dashscope endpoint
if "base_url" in merged_conf and "dashscope." in merged_conf["base_url"]:
if llm_type == "reasoning":
merged_conf["extra_body"] = {"enable_thinking": True}
else:
merged_conf["extra_body"] = {"enable_thinking": False}
return ChatDashscope(**merged_conf)
if llm_type == "reasoning":
merged_conf["api_base"] = merged_conf.pop("base_url", None)
return ChatDeepSeek(**merged_conf)
else:
return ChatOpenAI(**merged_conf)
def get_llm_by_type(llm_type: LLMType) -> BaseChatModel:
"""
Get LLM instance by type. Returns cached instance if available.
"""
if llm_type in _llm_cache:
return _llm_cache[llm_type]
conf = load_yaml_config(_get_config_file_path())
llm = _create_llm_use_conf(llm_type, conf)
_llm_cache[llm_type] = llm
return llm
def get_configured_llm_models() -> dict[str, list[str]]:
"""
Get all configured LLM models grouped by type.
Returns:
Dictionary mapping LLM type to list of configured model names.
"""
try:
conf = load_yaml_config(_get_config_file_path())
llm_type_config_keys = _get_llm_type_config_keys()
configured_models: dict[str, list[str]] = {}
for llm_type in get_args(LLMType):
# Get configuration from YAML file
config_key = llm_type_config_keys.get(llm_type, "")
yaml_conf = conf.get(config_key, {}) if config_key else {}
# Get configuration from environment variables
env_conf = _get_env_llm_conf(llm_type)
# Merge configurations, with environment variables taking precedence
merged_conf = {**yaml_conf, **env_conf}
# Check if model is configured
model_name = merged_conf.get("model")
if model_name:
configured_models.setdefault(llm_type, []).append(model_name)
return configured_models
except Exception as e:
# Log error and return empty dict to avoid breaking the application
print(f"Warning: Failed to load LLM configuration: {e}")
return {}
def _get_model_token_limit_defaults() -> dict[str, int]:
"""
Get default token limits for common LLM models.
These are conservative limits to prevent token overflow errors (Issue #721).
Users can override by setting token_limit in their config.
"""
return {
# OpenAI models
"gpt-4o": 120000,
"gpt-4-turbo": 120000,
"gpt-4": 8000,
"gpt-3.5-turbo": 4000,
# Anthropic Claude
"claude-3": 180000,
"claude-2": 100000,
# Google Gemini
"gemini-2": 180000,
"gemini-1.5-pro": 180000,
"gemini-1.5-flash": 180000,
"gemini-pro": 30000,
# Bytedance Doubao
"doubao": 200000,
# DeepSeek
"deepseek": 100000,
# Ollama/local
"qwen": 30000,
"llama": 4000,
# Default fallback for unknown models
"default": 100000,
}
def _infer_token_limit_from_model(model_name: str) -> int:
"""
Infer a reasonable token limit from the model name.
This helps protect against token overflow errors when token_limit is not explicitly configured.
Args:
model_name: The model name from configuration
Returns:
A conservative token limit based on known model capabilities
"""
if not model_name:
return 100000 # Safe default
model_name_lower = model_name.lower()
defaults = _get_model_token_limit_defaults()
# Try exact or prefix matches
for key, limit in defaults.items():
if key in model_name_lower:
return limit
# Return safe default if no match found
return defaults["default"]
def get_llm_token_limit_by_type(llm_type: str) -> int:
"""
Get the maximum token limit for a given LLM type.
Priority order:
1. Explicitly configured token_limit in conf.yaml
2. Inferred from model name based on known model capabilities
3. Safe default (100,000 tokens)
This helps prevent token overflow errors (Issue #721) even when token_limit is not configured.
Args:
llm_type (str): The type of LLM (e.g., 'basic', 'reasoning', 'vision', 'code').
Returns:
int: The maximum token limit for the specified LLM type (conservative estimate).
"""
llm_type_config_keys = _get_llm_type_config_keys()
config_key = llm_type_config_keys.get(llm_type)
conf = load_yaml_config(_get_config_file_path())
model_config = conf.get(config_key, {})
# First priority: explicitly configured token_limit
if "token_limit" in model_config:
configured_limit = model_config["token_limit"]
if configured_limit is not None:
return configured_limit
# Second priority: infer from model name
model_name = model_config.get("model")
if model_name:
inferred_limit = _infer_token_limit_from_model(model_name)
return inferred_limit
# Fallback: safe default
return _get_model_token_limit_defaults()["default"]
# In the future, we will use reasoning_llm and vl_llm for different purposes
# reasoning_llm = get_llm_by_type("reasoning")
# vl_llm = get_llm_by_type("vision")

View File

@@ -1,320 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
# Standard library imports
from typing import Any, Dict, Iterator, List, Mapping, Optional, Type, Union, cast
# Third-party imports
import openai
from langchain_core.callbacks import CallbackManagerForLLMRun
from langchain_core.messages import (
AIMessageChunk,
BaseMessage,
BaseMessageChunk,
ChatMessageChunk,
FunctionMessageChunk,
HumanMessageChunk,
SystemMessageChunk,
ToolMessageChunk,
)
from langchain_core.messages.ai import UsageMetadata
from langchain_core.messages.tool import tool_call_chunk
from langchain_core.outputs import ChatGenerationChunk, ChatResult
from langchain_openai import ChatOpenAI
from langchain_openai.chat_models.base import (
_create_usage_metadata,
_handle_openai_bad_request,
warnings,
)
def _convert_delta_to_message_chunk(
delta_dict: Mapping[str, Any], default_class: Type[BaseMessageChunk]
) -> BaseMessageChunk:
"""Convert a delta dictionary to a message chunk.
Args:
delta_dict: Dictionary containing delta information from OpenAI response
default_class: Default message chunk class to use if role is not specified
Returns:
BaseMessageChunk: Appropriate message chunk based on role and content
Raises:
KeyError: If required keys are missing from the delta dictionary
"""
message_id = delta_dict.get("id")
role = cast(str, delta_dict.get("role", ""))
content = cast(str, delta_dict.get("content") or "")
additional_kwargs: Dict[str, Any] = {}
# Handle function calls
if function_call_data := delta_dict.get("function_call"):
function_call = dict(function_call_data)
if "name" in function_call and function_call["name"] is None:
function_call["name"] = ""
additional_kwargs["function_call"] = function_call
# Handle tool calls
tool_call_chunks = []
if raw_tool_calls := delta_dict.get("tool_calls"):
additional_kwargs["tool_calls"] = raw_tool_calls
try:
tool_call_chunks = [
tool_call_chunk(
name=rtc.get("function", {}).get("name"),
args=rtc.get("function", {}).get("arguments"),
id=rtc.get("id"),
index=rtc.get("index", 0),
)
for rtc in raw_tool_calls
if rtc.get("function") # Ensure function key exists
]
except (KeyError, TypeError):
# Log the error but continue processing
pass
# Return appropriate message chunk based on role
if role == "user" or default_class == HumanMessageChunk:
return HumanMessageChunk(content=content, id=message_id)
elif role == "assistant" or default_class == AIMessageChunk:
# Handle reasoning content for OpenAI reasoning models
if reasoning_content := delta_dict.get("reasoning_content"):
additional_kwargs["reasoning_content"] = reasoning_content
return AIMessageChunk(
content=content,
additional_kwargs=additional_kwargs,
id=message_id,
tool_call_chunks=tool_call_chunks, # type: ignore[arg-type]
)
elif role in ("system", "developer") or default_class == SystemMessageChunk:
if role == "developer":
additional_kwargs = {"__openai_role__": "developer"}
return SystemMessageChunk(
content=content, id=message_id, additional_kwargs=additional_kwargs
)
elif role == "function" or default_class == FunctionMessageChunk:
function_name = delta_dict.get("name", "")
return FunctionMessageChunk(content=content, name=function_name, id=message_id)
elif role == "tool" or default_class == ToolMessageChunk:
tool_call_id = delta_dict.get("tool_call_id", "")
return ToolMessageChunk(
content=content, tool_call_id=tool_call_id, id=message_id
)
elif role or default_class == ChatMessageChunk:
return ChatMessageChunk(content=content, role=role, id=message_id)
else:
return default_class(content=content, id=message_id) # type: ignore
def _convert_chunk_to_generation_chunk(
chunk: Dict[str, Any],
default_chunk_class: Type[BaseMessageChunk],
base_generation_info: Optional[Dict[str, Any]],
) -> Optional[ChatGenerationChunk]:
"""Convert a streaming chunk to a generation chunk.
Args:
chunk: Raw chunk data from OpenAI streaming response
default_chunk_class: Default message chunk class to use
base_generation_info: Base generation information to include
Returns:
Optional[ChatGenerationChunk]: Generated chunk or None if chunk should be skipped
"""
# Skip content.delta type chunks from beta.chat.completions.stream
if chunk.get("type") == "content.delta":
return None
token_usage = chunk.get("usage")
choices = (
chunk.get("choices", [])
# Handle chunks from beta.chat.completions.stream format
or chunk.get("chunk", {}).get("choices", [])
)
usage_metadata: Optional[UsageMetadata] = (
_create_usage_metadata(token_usage) if token_usage else None
)
# Handle empty choices
if not choices:
generation_chunk = ChatGenerationChunk(
message=default_chunk_class(content="", usage_metadata=usage_metadata)
)
return generation_chunk
choice = choices[0]
if choice.get("delta") is None:
return None
message_chunk = _convert_delta_to_message_chunk(
choice["delta"], default_chunk_class
)
generation_info = dict(base_generation_info) if base_generation_info else {}
# Add finish reason and model info if available
if finish_reason := choice.get("finish_reason"):
generation_info["finish_reason"] = finish_reason
if model_name := chunk.get("model"):
generation_info["model_name"] = model_name
if system_fingerprint := chunk.get("system_fingerprint"):
generation_info["system_fingerprint"] = system_fingerprint
# Add log probabilities if available
if logprobs := choice.get("logprobs"):
generation_info["logprobs"] = logprobs
# Attach usage metadata to AI message chunks
if usage_metadata and isinstance(message_chunk, AIMessageChunk):
message_chunk.usage_metadata = usage_metadata
generation_chunk = ChatGenerationChunk(
message=message_chunk, generation_info=generation_info or None
)
return generation_chunk
class ChatDashscope(ChatOpenAI):
"""Extended ChatOpenAI model with reasoning capabilities.
This class extends the base ChatOpenAI model to support OpenAI's reasoning models
that include reasoning_content in their responses. It handles the extraction and
preservation of reasoning content during both streaming and non-streaming operations.
"""
def _create_chat_result(
self,
response: Union[Dict[str, Any], openai.BaseModel],
generation_info: Optional[Dict[str, Any]] = None,
) -> ChatResult:
"""Create a chat result from the OpenAI response.
Args:
response: The response from OpenAI API
generation_info: Additional generation information
Returns:
ChatResult: The formatted chat result with reasoning content if available
"""
chat_result = super()._create_chat_result(response, generation_info)
# Only process BaseModel responses (not raw dict responses)
if not isinstance(response, openai.BaseModel):
return chat_result
# Extract reasoning content if available
try:
if (
hasattr(response, "choices")
and response.choices
and hasattr(response.choices[0], "message")
and hasattr(response.choices[0].message, "reasoning_content")
):
reasoning_content = response.choices[0].message.reasoning_content
if reasoning_content and chat_result.generations:
chat_result.generations[0].message.additional_kwargs[
"reasoning_content"
] = reasoning_content
except (IndexError, AttributeError):
# If reasoning content extraction fails, continue without it
pass
return chat_result
def _stream(
self,
messages: List[BaseMessage],
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> Iterator[ChatGenerationChunk]:
"""Create a streaming generator for chat completions.
Args:
messages: List of messages to send to the model
stop: Optional list of stop sequences
run_manager: Optional callback manager for LLM runs
**kwargs: Additional keyword arguments for the API call
Yields:
ChatGenerationChunk: Individual chunks from the streaming response
Raises:
openai.BadRequestError: If the API request is invalid
"""
kwargs["stream"] = True
payload = self._get_request_payload(messages, stop=stop, **kwargs)
default_chunk_class: Type[BaseMessageChunk] = AIMessageChunk
base_generation_info: Dict[str, Any] = {}
# Handle response format for beta completions
if "response_format" in payload:
if self.include_response_headers:
warnings.warn(
"Cannot currently include response headers when response_format is "
"specified."
)
payload.pop("stream")
response_stream = self.root_client.beta.chat.completions.stream(**payload)
context_manager = response_stream
else:
# Handle regular streaming with optional response headers
if self.include_response_headers:
raw_response = self.client.with_raw_response.create(**payload)
response = raw_response.parse()
base_generation_info = {"headers": dict(raw_response.headers)}
else:
response = self.client.create(**payload)
context_manager = response
try:
with context_manager as response:
is_first_chunk = True
for chunk in response:
# Convert chunk to dict if it's a model object
if not isinstance(chunk, dict):
chunk = chunk.model_dump()
generation_chunk = _convert_chunk_to_generation_chunk(
chunk,
default_chunk_class,
base_generation_info if is_first_chunk else {},
)
if generation_chunk is None:
continue
# Update default chunk class for subsequent chunks
default_chunk_class = generation_chunk.message.__class__
# Handle log probabilities for callback
logprobs = (generation_chunk.generation_info or {}).get("logprobs")
if run_manager:
run_manager.on_llm_new_token(
generation_chunk.text,
chunk=generation_chunk,
logprobs=logprobs,
)
is_first_chunk = False
yield generation_chunk
except openai.BadRequestError as e:
_handle_openai_bad_request(e)
# Handle final completion for response_format requests
if hasattr(response, "get_final_completion") and "response_format" in payload:
try:
final_completion = response.get_final_completion()
generation_chunk = self._get_generation_chunk_from_completion(
final_completion
)
if run_manager:
run_manager.on_llm_new_token(
generation_chunk.text, chunk=generation_chunk
)
yield generation_chunk
except AttributeError:
# If get_final_completion method doesn't exist, continue without it
pass

View File

@@ -1,16 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import logging
from src.podcast.graph.state import PodcastState
logger = logging.getLogger(__name__)
def audio_mixer_node(state: PodcastState):
logger.info("Mixing audio chunks for podcast...")
audio_chunks = state["audio_chunks"]
combined_audio = b"".join(audio_chunks)
logger.info("The podcast audio is now ready.")
return {"output": combined_audio}

View File

@@ -1,39 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from langgraph.graph import END, START, StateGraph
from src.podcast.graph.audio_mixer_node import audio_mixer_node
from src.podcast.graph.script_writer_node import script_writer_node
from src.podcast.graph.state import PodcastState
from src.podcast.graph.tts_node import tts_node
def build_graph():
"""Build and return the podcast workflow graph."""
# build state graph
builder = StateGraph(PodcastState)
builder.add_node("script_writer", script_writer_node)
builder.add_node("tts", tts_node)
builder.add_node("audio_mixer", audio_mixer_node)
builder.add_edge(START, "script_writer")
builder.add_edge("script_writer", "tts")
builder.add_edge("tts", "audio_mixer")
builder.add_edge("audio_mixer", END)
return builder.compile()
workflow = build_graph()
if __name__ == "__main__":
from dotenv import load_dotenv
load_dotenv()
report_content = open("examples/nanjing_tangbao.md").read()
final_state = workflow.invoke({"input": report_content})
for line in final_state["script"].lines:
print("<M>" if line.speaker == "male" else "<F>", line.text)
with open("final.mp3", "wb") as f:
f.write(final_state["output"])

View File

@@ -1,58 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import json
import logging
import openai
from langchain_core.messages import HumanMessage, SystemMessage
from src.config.agents import AGENT_LLM_MAP
from src.llms.llm import get_llm_by_type
from src.prompts.template import get_prompt_template
from src.utils.json_utils import repair_json_output
from ..types import Script
from .state import PodcastState
logger = logging.getLogger(__name__)
def script_writer_node(state: PodcastState):
logger.info("Generating script for podcast...")
base_model = get_llm_by_type(AGENT_LLM_MAP["podcast_script_writer"])
messages = [
SystemMessage(content=get_prompt_template("podcast/podcast_script_writer")),
HumanMessage(content=state["input"]),
]
try:
# Try structured output with json_mode first
model = base_model.with_structured_output(Script, method="json_mode")
script = model.invoke(messages)
except openai.BadRequestError as e:
# Fall back for models that don't support json_object (e.g., Kimi K2)
if "json_object" in str(e).lower():
logger.warning(
f"Model doesn't support json_mode, falling back to prompting: {e}"
)
response = base_model.invoke(messages)
content = response.content if hasattr(response, "content") else str(response)
try:
repaired = repair_json_output(content)
script_dict = json.loads(repaired)
except json.JSONDecodeError as json_err:
logger.error(
"Failed to parse JSON from podcast script writer fallback "
"response: %s; content: %r",
json_err,
content,
)
raise
script = Script.model_validate(script_dict)
else:
raise
logger.debug("Generated podcast script: %s", script)
return {"script": script, "audio_chunks": []}

View File

@@ -1,22 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from typing import Optional
from langgraph.graph import MessagesState
from ..types import Script
class PodcastState(MessagesState):
"""State for the podcast generation."""
# Input
input: str = ""
# Output
output: Optional[bytes] = None
# Assets
script: Optional[Script] = None
audio_chunks: list[bytes] = []

View File

@@ -1,47 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import base64
import logging
import os
from src.podcast.graph.state import PodcastState
from src.tools.tts import VolcengineTTS
logger = logging.getLogger(__name__)
def tts_node(state: PodcastState):
logger.info("Generating audio chunks for podcast...")
tts_client = _create_tts_client()
for line in state["script"].lines:
tts_client.voice_type = (
"BV002_streaming" if line.speaker == "male" else "BV001_streaming"
)
result = tts_client.text_to_speech(line.paragraph, speed_ratio=1.05)
if result["success"]:
audio_data = result["audio_data"]
audio_chunk = base64.b64decode(audio_data)
state["audio_chunks"].append(audio_chunk)
else:
logger.error(result["error"])
return {
"audio_chunks": state["audio_chunks"],
}
def _create_tts_client():
app_id = os.getenv("VOLCENGINE_TTS_APPID", "")
if not app_id:
raise Exception("VOLCENGINE_TTS_APPID is not set")
access_token = os.getenv("VOLCENGINE_TTS_ACCESS_TOKEN", "")
if not access_token:
raise Exception("VOLCENGINE_TTS_ACCESS_TOKEN is not set")
cluster = os.getenv("VOLCENGINE_TTS_CLUSTER", "volcano_tts")
voice_type = "BV001_streaming"
return VolcengineTTS(
appid=app_id,
access_token=access_token,
cluster=cluster,
voice_type=voice_type,
)

View File

@@ -1,16 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from typing import Literal
from pydantic import BaseModel, Field
class ScriptLine(BaseModel):
speaker: Literal["male", "female"] = Field(default="male")
paragraph: str = Field(default="")
class Script(BaseModel):
locale: Literal["en", "zh"] = Field(default="en")
lines: list[ScriptLine] = Field(default=[])

View File

@@ -1,31 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from langgraph.graph import END, START, StateGraph
from src.ppt.graph.ppt_composer_node import ppt_composer_node
from src.ppt.graph.ppt_generator_node import ppt_generator_node
from src.ppt.graph.state import PPTState
def build_graph():
"""Build and return the ppt workflow graph."""
# build state graph
builder = StateGraph(PPTState)
builder.add_node("ppt_composer", ppt_composer_node)
builder.add_node("ppt_generator", ppt_generator_node)
builder.add_edge(START, "ppt_composer")
builder.add_edge("ppt_composer", "ppt_generator")
builder.add_edge("ppt_generator", END)
return builder.compile()
workflow = build_graph()
if __name__ == "__main__":
from dotenv import load_dotenv
load_dotenv()
report_content = open("examples/nanjing_tangbao.md").read()
final_state = workflow.invoke({"input": report_content})

View File

@@ -1,33 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import logging
import os
import uuid
from langchain_core.messages import HumanMessage, SystemMessage
from src.config.agents import AGENT_LLM_MAP
from src.llms.llm import get_llm_by_type
from src.prompts.template import get_prompt_template
from .state import PPTState
logger = logging.getLogger(__name__)
def ppt_composer_node(state: PPTState):
logger.info("Generating ppt content...")
model = get_llm_by_type(AGENT_LLM_MAP["ppt_composer"])
ppt_content = model.invoke(
[
SystemMessage(content=get_prompt_template("ppt/ppt_composer", locale=state.get("locale", "en-US"))),
HumanMessage(content=state["input"]),
],
)
logger.info(f"ppt_content: {ppt_content}")
# save the ppt content in a temp file
temp_ppt_file_path = os.path.join(os.getcwd(), f"ppt_content_{uuid.uuid4()}.md")
with open(temp_ppt_file_path, "w") as f:
f.write(ppt_content.content)
return {"ppt_content": ppt_content, "ppt_file_path": temp_ppt_file_path}

View File

@@ -1,25 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
import logging
import os
import subprocess
import uuid
from src.ppt.graph.state import PPTState
logger = logging.getLogger(__name__)
def ppt_generator_node(state: PPTState):
logger.info("Generating ppt file...")
# use marp cli to generate ppt file
# https://github.com/marp-team/marp-cli?tab=readme-ov-file
generated_file_path = os.path.join(
os.getcwd(), f"generated_ppt_{uuid.uuid4()}.pptx"
)
subprocess.run(["marp", state["ppt_file_path"], "-o", generated_file_path])
# remove the temp file
os.remove(state["ppt_file_path"])
logger.info(f"generated_file_path: {generated_file_path}")
return {"generated_file_path": generated_file_path}

View File

@@ -1,19 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from langgraph.graph import MessagesState
class PPTState(MessagesState):
"""State for the ppt generation."""
# Input
input: str = ""
locale: str = ""
# Output
generated_file_path: str = ""
# Assets
ppt_content: str = ""
ppt_file_path: str = ""

View File

@@ -1,4 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
"""Prompt enhancer module for improving user prompts."""

View File

@@ -1,25 +0,0 @@
# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
# SPDX-License-Identifier: MIT
from langgraph.graph import StateGraph
from src.prompt_enhancer.graph.enhancer_node import prompt_enhancer_node
from src.prompt_enhancer.graph.state import PromptEnhancerState
def build_graph():
"""Build and return the prompt enhancer workflow graph."""
# Build state graph
builder = StateGraph(PromptEnhancerState)
# Add the enhancer node
builder.add_node("enhancer", prompt_enhancer_node)
# Set entry point
builder.set_entry_point("enhancer")
# Set finish point
builder.set_finish_point("enhancer")
# Compile and return the graph
return builder.compile()

Some files were not shown because too many files have changed in this diff Show More