老顾深度解析【字节跳动的AI项目DeerFlow】源码之工程结构(六)

前言

老顾花了很多的篇幅已经介绍了关于DeerFlow项目中的AI Agent多智能体相关的源码。需要了解的人可以看前面的文章。

这篇文章老顾给大家介绍一下DeerFlow工程方面的技术点,也是值得我们学习的地方。

工程结构

diff 复制代码
-DEER-FLOW
--docs
----xx.md
--examples
----yy.md
--src
--tests
--web
--.env
--.python-version
--bootstrap.bat
--bootstrap.sh
--conf.yaml
--docker-compose.yml
--Dockerfile
--main.py
--Makefile
--pyproject.toml
--server.py
--uv.lock

上面是deerflow的工程目录结构,我们来看一下各自的作用

**docs:**存放着相关核心介绍,如怎么使用配置

**examples:**md格式的文档,一些案例的报告

**src:**项目的Python的源代码就在此目录下

**tests:**单元测试

**web:**前端页面代码

**.env:**项目的全局的环境变量都在此处

**.python-version:**uv虚拟环境配置的python版本

**bootstrap.bat:**windows版本的执行脚本,启动后端和前端

**bootstrap.sh:**linux版本的执行脚本,启动后端和前端

**conf.yaml:**大模型相关的配置

**docker-compose.yml:**容器的编排文件

**Dockerfile:**容器的镜像文件配置

**main.py:**支持用户通过命令行或交互式界面提问

**Makefile:**提供一组用于开发、测试、格式化和运行项目的命令

**pyproject.toml:**里面包含了依赖的包,打包方式等

**server.py:**项目后端的启动入口

**uv.lock:**uv虚拟环境的系统文件

我们来重点看一下**pyproject.toml文件,**里面的信息是比较重要的

pyproject.toml

1. 构建系统配置

ini 复制代码
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
  • 作用:定义项目使用的构建工具。
  • 说明
  • requires:指定构建项目所需的依赖项,这里使用了 hatchling。
  • build-backend:指定构建后端使用的模块,这里是 hatchling.build。

2. 项目基本信息

ini 复制代码
[project]
name = "deer-flow"
version = "0.1.0"
description = "DeerFlow project"
readme = "README.md"
requires-python = ">=3.12"
  • 作用:定义项目的基本信息。
  • 说明
  • name:项目的名称,这里是 deer-flow。
  • version:项目的当前版本号,这里是 0.1.0。
  • description:项目的简短描述,这里是 DeerFlow project。
  • readme:项目的 README 文件路径,这里是 README.md
  • requires-python:项目所需的 Python 版本,这里是 >=3.12。

3. 项目依赖

ini 复制代码
dependencies = [
    "httpx>=0.28.1",
    "langchain-community>=0.3.19",
    "langchain-experimental>=0.3.4",
    ...
]
  • 作用:定义项目运行所需的依赖项。
  • 说明
  • 列出了所有必需的 Python 包及其版本要求,例如:
  • httpx>=0.28.1:要求 httpx 的版本至少为 0.28.1。
  • langchain-community>=0.3.19:要求 langchain-community 的版本至少为 0.3.19。

4. 可选依赖

ini 复制代码
[project.optional-dependencies]
dev = [
    "black>=24.2.0",
    "langgraph-cli[inmem]>=0.2.10",
]
test = [
    "pytest>=7.4.0",
    "pytest-cov>=4.1.0",
    "pytest-asyncio>=1.0.0",
]
  • 作用:定义可选的依赖组,用户可以根据需要安装。
  • 说明
  • dev:开发环境所需的依赖,例如代码格式化工具 black。
  • test:测试环境所需的依赖,例如测试框架 pytest。

5. 测试配置

ini 复制代码
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
addopts = "-v --cov=src --cov-report=term-missing"
filterwarnings = [
    "ignore::DeprecationWarning",
    "ignore::UserWarning",
]
  • 作用:定义 pytest 测试框架的配置选项。
  • 说明
  • testpaths:指定测试文件所在的目录,这里是 tests。
  • python_files:指定测试文件的命名模式,这里是 test_*.py。
  • addopts:指定测试时的附加选项:
  • -v:详细输出。
  • --cov=src:计算 src 目录的代码覆盖率。
  • --cov-report=term-missing:在终端显示未覆盖的代码行。
  • filterwarnings:忽略特定的警告信息,例如 DeprecationWarning 和 UserWarning。

6. 覆盖率报告配置

ini 复制代码
[tool.coverage.report]
fail_under = 25
  • 作用:定义代码覆盖率的报告配置。
  • 说明
  • fail_under:如果代码覆盖率低于 25%,则测试失败。

7. 构建目标配置

ini 复制代码
[tool.hatch.build.targets.wheel]
packages = ["src"]
  • 作用:定义构建 wheel 包时包含的代码包。
  • 说明
  • packages:指定构建时包含的目录,这里是 src。

8. 代码格式化工具配置

ini 复制代码
[tool.black]
line-length = 88
target-version = ["py312"]
include = '.pyi?$'
extend-exclude = '''
^/build/
'''
  • 作用:定义代码格式化工具 black 的配置。
  • 说明
  • line-length:指定每行代码的最大长度为 88。
  • target-version:指定目标 Python 版本为 3.12。
  • include:指定需要格式化的文件类型,这里是 .py 和 .pyi。
  • extend-exclude:指定不需要格式化的目录,这里是 build。

该 pyproject.toml 文件定义了项目的构建工具、基本信息、依赖项、可选依赖、测试配置、代码覆盖率、构建目标以及代码格式化规则。它是现代 Python 项目的标准配置文件,能够帮助开发者快速配置和管理项目。

下面我们来看看src目录下面有哪些点,可以值得学习的

src源码

一、config

里面存放了项目的配置信息,其中里面有个configuration.py文件,

此文件 configuration.py 用于定义程序的配置类 Configuration ,它提供了一种结构化的方式来管理应用程序的可配置参数。这些参数可以来源于环境变量或 RunnableConfig 对象

以下是对代码的详细解释:

  1. 配置管理:通过 dataclass 定义了程序运行所需的配置项,如资源列表、最大迭代次数、报告风格等。
  2. 灵活的配置来源:支持从环境变量或传入的 RunnableConfig 中读取配置值,提供了灵活性。
  3. 默认值管理:为每个配置项提供了默认值或默认工厂函数,确保即使没有显式提供配置,程序也能正常运行。

二、prompts

此目录下面存放了智能体中所需要的提示词文件,里面template.py文件定义了获取提示词模板的方法。

三、server

此目录中app.py是与前端交互的请求入口地址,里面采用了fastapi框架;里面有个比较重要的Stream流失输出的技术点 ,StreamingResponse中media_type="text/event-stream" ,

media_type="text/event-stream" 的作用是设置 HTTP 响应的内容类型为 Server-Sent Events (SSE) 流。SSE 是一种允许服务器向客户端(通常是浏览器)持续推送数据的技术。

1、作用:

  • 实时数据推送:服务器可以持续不断地向客户端发送数据,而不需要客户端反复发起请求。
  • 单向通信:数据从服务器推送到客户端,适用于服务器主动更新客户端的场景。
  • **轻量级协议:**相比 WebSocket,SSE 更简单,适合不需要双向通信的场景。

2、一般应用场景:

  1. 实时日志更新:如监控系统、任务执行日志的实时展示。
  2. 实时通知:用户消息提醒、系统告警。
  3. 流式数据传输:AI 生成文本的逐步返回(如 ChatGPT 类型的流式回复)。
  4. 股票价格、天气更新等:需要服务器持续推送数据更新的场景。

3、前端如何接收:

前端使用 EventSource 对象来接收 text/event-stream 数据。

4、示例代码:

ini 复制代码
const eventSource = new EventSource('/api/chat/stream');


eventSource.onmessage = function(event) {
    console.log('Received data:', event.data);
    // 处理服务器发送的数据
    const data = JSON.parse(event.data);
    
    if (data.event === "stream_end") {
        console.log("Stream has ended");
        eventSource.close();  // 主动关闭连接
        return;
    }
};


eventSource.onerror = function(err) {
    console.error('EventSource failed:', err);
};

5、消息格式说明

服务器发送的数据需要遵循 SSE 协议格式,例如:

css 复制代码
event: message
data: {"content": "Hello", "role": "assistant"}

里面的其他目录,都是以不同的Agent作为文件夹归类的,如:rag、ppt、podcast等Agent

四、日志装饰

我们来看一下src/tools/decorators.py这个文件,里面就是对logger日志做一些增强。

1. 函数装饰器 log_io

python 复制代码
def log_io(func: Callable) -> Callable:
  • 这是一个装饰器函数,用于记录被装饰函数的输入参数和返回值
  • 使用 @functools.wraps(func) 保持原函数的元信息
  • 在函数调用前后分别记录参数和返回值到日志中

2. 混入类 LoggedToolMixin

kotlin 复制代码
class LoggedToolMixin:

这是一个混入类,为工具类提供日志记录功能:

  • _log_operation 方法:记录类方法调用的参数信息
  • _run 方法:重写基类的 _run 方法,添加输入输出日志记录
  • 通过 super()._run(*args, **kwargs) 调用原始方法实现

3. 工厂函数 create_logged_tool

python 复制代码
def create_logged_tool(base_tool_class: Type[T]) -> Type[T]:
  • 这是一个工厂函数,用于动态创建带日志功能的工具类
  • 创建的新类同时继承 LoggedToolMixin 和原始工具类
  • 自动为新类生成更具描述性的名称(添加"Logged"前缀)

这套系统允许开发者通过简单的装饰器或类工厂方式,为现有的工具函数和类添加自动化的输入输出日志记录功能,便于调试和监控工具的执行情况。

server.py

这段代码是一个用于运行 DeerFlow API 服务的服务器脚本,主要功能是启动一个基于 uvicornASGI 服务器。下面是代码的详细解释:

主要功能

  • 启动 API 服务:使用 uvicorn 启动一个 ASGI 服务器来运行 src.server:app 应用。
  • 命令行参数解析:支持通过命令行参数配置服务器的 host、port、日志级别和自动重载功能。
  • 日志配置:设置日志记录格式和级别。
  • 优雅关闭:注册信号处理器以实现服务器的优雅关闭。
scss 复制代码
signal.signal(signal.SIGTERM, handle_shutdown)
signal.signal(signal.SIGINT, handle_shutdown)
  • 注册信号处理器,分别处理终止信号(SIGTERM)和中断信号(SIGINT)。
  • 使用 argparse 模块定义和解析命令行参数:
  • **--reload:**启用自动重载功能(默认为 False)。
  • **--host:**指定服务器绑定的主机地址(默认为 localhost)。
  • **--port:**指定服务器绑定的端口号(默认为 8000)。
  • **--log-level:**指定日志级别(默认为 info)。

服务器启动

ini 复制代码
uvicorn.run(
    "src.server:app",
    host=args.host,
    port=args.port,
    reload=reload,
    log_level=args.log_level,
)
  • 使用 uvicorn.run 启动服务器:
  • 加载 src.server:app 模块中的 app 应用。
  • 根据命令行参数配置主机地址、端口、重载选项和日志级别。

总结

到此DeerFlow老顾介绍了工程方面的一些技术点,一些信息是值得我们学习的,尤其我们对Python工程化不是太熟悉的小伙伴。

整个DeerFlow的开源项目的介绍,这里就全部介绍完了。希望可以帮助小伙伴们学习,谢谢大家!!!

相关推荐
302AI2 分钟前
编程能力超越 Claude Opus 4?DeepSeek V3.1最新版本实测
llm·ai编程·deepseek
许泽宇的技术分享1 小时前
ReAct Agent:让AI像人类一样思考与行动的革命性框架
人工智能·agent·react
亚马逊云开发者3 小时前
在 Amazon Bedrock 中结合 RAG 与 MCP 高效缓解提示词膨胀问题
llm
数据智能老司机4 小时前
MCP 实战——MCP 服务器的身份验证与部署
llm·agent·mcp
数据智能老司机4 小时前
MCP 实战——高级服务器架构
llm·agent·mcp
DevYK15 小时前
企业级 Agent 开发实战(一) LangGraph 快速入门
后端·llm·agent
Ethan.Yuan16 小时前
【深度长文】Anthropic发布Prompt Engineering全新指南
大模型·llm·prompt·提示工程
zhayujie18 小时前
RAG优化实战 - LinkAI智能体平台的知识库升级之路
ai·大模型·agent·知识库·rag
AI大模型20 小时前
基于 Docker 的 LLaMA-Factory 全流程部署指南
docker·llm·llama