老顾深度解析【字节跳动的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的开源项目的介绍,这里就全部介绍完了。希望可以帮助小伙伴们学习,谢谢大家!!!

相关推荐
夫子3965 小时前
【深度干货】Transformer推理优化完全指南:模型压缩、推理加速与硬件调优
人工智能·llm
智泊AI7 小时前
终于有人把AI大模型训练过程讲明白了!!!
llm
大模型真好玩8 小时前
大模型Agent开发框架哪家强?12项Agent开发框架入门与选型
人工智能·agent·mcp
数据智能老司机11 小时前
建构 AI Agent 应用——Agentic 系统的学习机制
架构·llm·agent
数据智能老司机13 小时前
建构 AI Agent 应用——编排
架构·llm·agent
董厂长1 天前
SubAgent的“指令漂移 (Instruction Drift)“困境
人工智能·agent·mcp·subagent
镰刀韭菜1 天前
【AI4S】大语言模型与化学的未来,以及整合外部工具和聊天机器人的潜力
llm·transformer·大语言模型·药物设计·分子发现·chemchat·smiles
数据智能老司机2 天前
建构 AI Agent 应用——工具调用
架构·llm·agent
aopstudio2 天前
llms.txt:为大模型打造的“网站说明书”
人工智能·python·llm·开发者工具
大模型真好玩2 天前
深入浅出LangGraph AI Agent智能体开发教程(九)—LangGraph长短期记忆管理
人工智能·python·agent