
hello-agents 内置 Deep Research 搜索调研智能体架构、工作流与平台集成实践【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/datawhalechina/hello-agents本文以 Hello-Agents 开源仓库第 16 章毕业项目AgentPlatformBase中内置的deep_research搜索调研智能体为核心系统讲解其基于 TODO 列表的深度研究工作流、配置体系、多后端搜索分发、NoteTool 笔记协作机制以及 HTTP 服务与平台适配器集成方式。读完本文读者能够完整理解该搜索员的内部实现原理掌握独立运行、配置调优和二次接入平台的方法。一、定位chapter16 平台内置的搜索调研智能体deep_research是 chapter16 平台内置的搜索调研智能体即平台文档中常说的搜索员负责把用户提交的研究主题转化为一份结构化的 Markdown 研究报告。它的定位说明记录在 agents/deep_research/README.md源码位于agents/deep_research/src/该目录在仓库中的完整相对路径为 Co-creation-projects/huailishang-AgentPlatformBase/agents/deep_research/。1.1 与 chapter14 的关系这份源码来自 chapter14 的 DeepResearchAgent对应章节文档见 docs/chapter14/Chapter14-Automated-Deep-Research-Agent.md参考实现见 code/chapter14/helloagents-deepresearch/并已内置到 chapter16 项目中。README 明确说明默认运行不再依赖code/chapter14即使只保留平台本体也可以直接运行搜索员——这是它与章节示例代码解耦的关键设计让毕业项目可以独立提交和运行。1.2 运行数据目录运行数据写入两个固定目录平台级完整路径为 Co-creation-projects/huailishang-AgentPlatformBase/data/deep_research/data/deep_research/runs/ data/deep_research/notes/两者的生命周期策略截然不同runs/单次运行过程产物任务文件、中间数据等可按保留期清理。平台在 backend/maintenance.py 中通过RESEARCH_RUN_RETENTION_DAYS7默认 7 天惰性清理超过保留期的产物详见平台 README.md 的清理策略一节。notes/研究笔记和索引默认长期保留平台不会自动删除该目录。这些笔记由 NoteTool 持久化是跨任务复用的长期知识资产详见第六节。二、源码结构总览deep_research的源码组织清晰采用编排器 领域服务 提示词的分层结构Co-creation-projects/huailishang-AgentPlatformBase/agents/deep_research/src/ ├── agent.py # 编排器协调整个研究流程DeepResearchAgent ├── config.py # 配置模型Configuration SearchAPI 枚举 ├── main.py # FastAPI HTTP 入口/research、/research/stream ├── models.py # 状态模型TodoItem / SummaryState / 输入输出 ├── prompts.py # 三套提示词规划、任务总结、报告撰写 ├── utils.py # 工具函数去重格式化、strip think 等 └── services/ ├── planner.py # 规划服务主题 → TODO 任务列表 ├── search.py # 搜索服务多后端分发与上下文构造 ├── summarizer.py # 总结服务同步/流式任务总结 ├── reporter.py # 报告服务任务结果 → 最终报告 ├── notes.py # 笔记协作指引构造 ├── text_processing.py # 文本后处理strip_tool_calls 等 └── tool_events.py # 工具调用事件跟踪器ToolCallTracker各模块职责对应关系如下表文件核心类/函数职责agent.pyDeepResearchAgent编排规划 → 执行 → 汇总 → 报告全流程提供run与run_streamconfig.pyConfiguration、SearchAPI配置加载环境变量 覆盖项与搜索后端枚举main.pycreate_appFastAPI 服务暴露同步与 SSE 流式研究接口models.pyTodoItem、SummaryState等数据类状态模型贯穿整个流程prompts.py三套 prompt 常量研究规划专家、任务总结专家、报告撰写专家的系统提示词planner.pyPlanningService把主题拆解为 3~5 个互补的检索任务含 JSON 解析与回退任务search.pydispatch_search等调用 SearchTool 分发到指定后端构造去重后的研究上下文summarizer.pySummarizationService基于检索上下文生成任务要点总结支持流式输出reporter.pyReportingService汇总所有任务总结与来源生成结构化研究报告三、核心工作流基于 TODO 的深度研究流程DeepResearchAgent的核心工作流定义在 agent.py 的run()方法中整体分为四个阶段研究主题 topic │ ▼ ① 规划PlanningService.plan_todo_list() │ LLM 输出 {tasks: [...]} JSON解析为 TodoItem 列表 │ ▼ ② 执行遍历每个 TodoItem │ ├─ dispatch_search() → 多后端搜索得到 sources context │ ├─ SummarizationService → 基于 context 生成任务总结 │ └─ 状态推进pending → in_progress → completed / skipped │ ▼ ③ 汇总ReportingService.generate_report() │ 读取任务笔记整合任务总结与来源生成报告 │ ▼ ④ 持久化_persist_final_report() │ NoteTool 以 conclusion 类型笔记保存研究报告 │ ▼ SummaryStateOutputrunning_summary report_markdown todo_items3.1 阶段一研究规划Planner规划由PlanningService完成services/planner.py其 prompt 由todo_planner_instructions格式化生成要求 LLM 严格以如下 JSON 回复{ tasks: [ { title: 任务名称10字内突出重点, intent: 任务要解决的核心问题用1-2句描述, query: 建议使用的检索关键词 } ] }解析过程做了多层容错_extract_tasks先按strip_thinking_tokens配置剥离think推理段尝试从响应中定位{...}或[...]提取 JSON_extract_json_payload若 JSON 解析失败再尝试从[TOOL_CALL:...]指令中提取任务负载_extract_tool_payload。plan_todo_list还会清理规划 Agent 的历史记录self._agent.clear_history()保证每个主题的规划相互独立。若规划失败返回空列表agent.run会调用create_fallback_task生成一个兜底任务基础背景梳理query为主题 最新进展避免流程中断见 agent.py。3.2 阶段二任务执行搜索 总结对每个 TodoItem_execute_task依次执行agent.py搜索dispatch_search(task.query, config, state.research_loop_count)返回(search_result, notices, answer_text, backend)无结果处理若search_result为空或results为空任务状态置为skipped并跳过总结上下文构造prepare_research_context将搜索结果格式化为去重后的上下文任务总结SummarizationService基于任务主题 任务名称 任务目标 检索查询 任务上下文生成要点总结状态推进为completed。state.research_loop_count会随每个成功任务递增并作为loop_count传入搜索后端用于控制研究深度。3.3 阶段三报告撰写ReporterReportingService.generate_reportservices/reporter.py把每个任务的目标 / 查询 / 状态 / 总结 / 来源概览拼装成任务块并附带可用的任务笔记 ID 列表交由报告撰写专家按report_writer_instructions生成最终报告。报告模板固定为五个分节背景概览简述研究主题的重要性与上下文核心洞见提炼 3-5 条最重要的结论标注文献/任务编号证据与数据罗列支持性的事实或指标风险与挑战分析潜在的问题、限制或待验证的假设参考来源按任务列出关键来源条目标题 链接。3.4 流式执行与并发除同步的run()外DeepResearchAgent还提供run_stream()agent.py它以生成器逐条产出进度事件主要事件类型包括事件类型含义status流程状态提示如初始化研究流程、搜索通知todo_list规划完成后的任务列表task_status单个任务状态in_progress/skipped/completed/failedsources任务检索到的来源概览与原始上下文task_summary_chunk任务总结的流式文本块report_note研究报告笔记持久化结果含 note_id / note_pathfinal_report最终完整报告done流程结束值得注意的并发设计run_stream为每个任务启动一个守护线程执行搜索与总结agent.py通过线程安全的事件队列Queue汇聚事件主循环按__task_done__计数判断全部任务完成共享状态写入通过self._state_lock加锁保护。同时_set_tool_event_sink可以启用即时工具事件回调把 NoteTool 调用事件实时汇入流中。四、配置详解从环境变量到运行时覆盖Configuration是 Pydantic 模型config.py全字段如下字段类型默认值说明max_web_research_loopsint3研究深度即研究迭代轮数local_llmstrllama3.2本地模型名Ollama / LMStudiollm_providerstrollamaLLM 提供方ollama/lmstudio/ 自定义 OpenAI 兼容服务search_apiSearchAPISearchAPI.DUCKDUCKGO搜索后端详见第五节enable_notesboolTrue是否用 NoteTool 存储任务进度notes_workspacestr./notesNoteTool 持久化任务笔记的目录fetch_full_pageboolTrue是否在搜索结果中包含完整页面内容ollama_base_urlstrhttp://localhost:11434Ollama API 地址不含/v1后缀lmstudio_base_urlstrhttp://localhost:1234/v1LMStudio 的 OpenAI 兼容地址strip_thinking_tokensboolTrue是否剥离模型响应中的think段use_tool_callingboolFalse是否用工具调用替代 JSON 模式做结构化输出llm_api_keyOptional[str]None自定义服务时的 API Keyllm_base_urlOptional[str]None自定义服务的 Base URLllm_model_idOptional[str]None自定义服务的模型标识4.1 环境变量加载Configuration.from_env()config.py按字段名大写自动读取环境变量如MAX_WEB_RESEARCH_LOOPS、SEARCH_API同时支持一组显式别名LOCAL_LLM、LLM_PROVIDER、LLM_API_KEY、LLM_MODEL_ID、LLM_BASE_URL、LMSTUDIO_BASE_URL、OLLAMA_BASE_URL、MAX_WEB_RESEARCH_LOOPS、FETCH_FULL_PAGE、STRIP_THINKING_TOKENS、USE_TOOL_CALLING、SEARCH_API、ENABLE_NOTES、NOTES_WORKSPACE。加载优先级为环境变量 → 显式别名 → 调用方传入的overrides字典后者优先级最高。4.2 LLM 初始化逻辑_init_llmagent.py统一通过HelloAgentsLLM构造模型固定temperature0.0保证研究输出的确定性并按 provider 分派ollamabase_url使用sanitized_ollama_url()即把http://localhost:11434自动补全为http://localhost:11434/v1OpenAI 客户端要求/v1后缀无 API Key 时默认填入ollamalmstudio使用lmstudio_base_url默认已含/v1其他自定义使用llm_base_url与llm_api_key。resolved_model()的模型解析顺序为llm_model_id优先其次local_llm。启动时main.py的 startup 钩子会把上述配置API Key 经_mask_secret脱敏打印到日志便于排障。五、多后端搜索分发机制搜索后端通过SearchAPI枚举约束config.pyclass SearchAPI(Enum): PERPLEXITY perplexity TAVILY tavily DUCKDUCKGO duckduckgo SEARXNG searxng ADVANCED advanceddispatch_searchservices/search.py复用hello_agents的SearchTool单例缓存避免重复初始化并以结构化模式调用_get_search_tool().run({ input: query, backend: search_api, # 由配置或请求覆盖 mode: structured, fetch_full_page: config.fetch_full_page, max_results: 5, # 固定单次最多 5 条结果 max_tokens_per_source: 2000, # 单来源内容 token 上限模块常量 loop_count: loop_count, # 当前研究轮数 })返回结构统一为{results, backend, answer, notices}若后端返回纯文本通知如无结果提示会被包装为notices而非直接失败。上下文构造方面prepare_research_contextservices/search.py调用utils.py中的两个关键函数deduplicate_and_format_sources以 URL 为主键对来源去重拼接信息来源 / URL / 信息内容并在fetch_full_pageTrue时附加raw_content——按max_tokens_per_source * CHARS_PER_TOKENCHARS_PER_TOKEN 4字符/token截断并标注[truncated]format_sources生成* 标题 : URL形式的来源概览列表供报告参考来源分节引用。若后端返回answerAI 直接答案会被拼接到上下文最前面作为AI直接答案...帮助总结专家快速把握核心结论。六、笔记协作机制NoteTool 与多智能体协作这是该搜索员最具特色的设计三个 LLM 角色规划专家、总结专家、报告撰写专家通过统一的note工具共享研究中间状态形成结构化笔记协作链路。note工具由hello_agents.tools.builtin.note_tool.NoteTool提供agent.py仅在enable_notesTrue时注册到共享的ToolRegistry。6.1 统一的工具调用协议各 Agent 通过文本指令[TOOL_CALL:note:{JSON}]调用笔记工具常见动作# 创建任务笔记 [TOOL_CALL:note:{action:create,task_id:1,title:任务 1: 背景梳理,note_type:task_state,tags:[deep_research,task_1],content:请记录任务概览、系统提示、来源概览、任务总结}] # 读取任务笔记 [TOOL_CALL:note:{action:read,note_id:note_id}] # 更新任务笔记 [TOOL_CALL:note:{action:update,note_id:note_id,task_id:1,title:任务 1: 背景梳理,note_type:task_state,tags:[deep_research,task_1],content:...新增内容...}]6.2 笔记约定与协作规则类型区分任务进度使用note_typetask_state最终报告使用note_typeconclusion标签规范tags必须包含deep_research与task_{task_id}方便其他 Agent 快速定位见 prompts.py先读后写总结专家和报告撰写专家在生成输出前必须read对应笔记获取最新状态完成后用update增量追加且同步笔记成功后再输出面向用户的总结由build_note_guidance注入见 services/notes.py输出清洗最终呈现给用户的总结与报告中禁止残留[TOOL_CALL:...]指令由strip_tool_callsservices/text_processing.py统一清除。6.3 最终报告持久化run()结束后_persist_final_reportagent.py会把报告写入conclusion类型笔记优先查找已有研究报告笔记做update否则create并通过正则ID:\s*(.)解析返回的 note_id。笔记落在notes_workspace目录下平台集成时解析为data/deep_research/notes/文件名形如{note_id}.md。这就是 README 所述notes/研究笔记和索引默认长期保留的由来。七、两种运行方式7.1 编程方式类 API在 main.py 的 FastAPI 服务之外可以直接以 Python 方式调用from agent import DeepResearchAgent from config import Configuration config Configuration.from_env() # 或传入 overrides agent DeepResearchAgent(configconfig) result agent.run(AI Agent 平台架构) # 同步执行 print(result.report_markdown) # 流式执行 for event in agent.run_stream(AI Agent 平台架构): print(event[type], event)run返回SummaryStateOutputmodels.py包含running_summary、report_markdown和todo_items三个字段模块底部还提供便捷函数run_deep_research(topic, configNone)镜像类 API。7.2 HTTP 服务方式FastAPI SSEmain.py以create_app()构建 FastAPI 应用暴露三个端点端点方法说明/healthzGET健康检查返回{status: ok}/researchPOST同步研究请求体{topic: ..., search_api: 可选覆盖后端}返回report_markdown与结构化todo_items/research/streamPOSTSSE 流式研究逐事件输出data: {json}\n\n媒体类型text/event-stream关闭Cache-Control缓存请求体由ResearchRequest约束topic为必填search_api字段可覆盖环境变量配置的搜索后端_build_config将其作为 overrides 传入Configuration.from_env。本地启动方式python main.py # uvicorn 监听 0.0.0.0:8000reloadTrue流式响应中包含第六节所述的全部事件类型前端可通过type字段增量渲染任务列表、来源与总结。八、平台集成DeepResearchAdapter在 chapter16 平台中搜索员通过适配器模式接入统一后端backend/agents/adapters/deep_research.py。DeepResearchAdapter(BaseAgent)的关键逻辑动态加载_load_deep_research_types把settings.chapter14_backend_path指向的智能体源码目录插入sys.path动态importlib.import_module(agent / config)并加载.env配置——这意味着平台运行时不关心搜索员源码的物理位置只要路径存在即可配置注入_deep_research_overrides把平台级配置llm_provider、llm_model_id、llm_api_key、llm_base_url、search_api、max_web_research_loops、fetch_full_page、enable_notes等映射为 overrides并解析notes_workspace/run_workspace到平台数据目录自动mkdir防护策略group_chat批量对话直接返回提示请单独使用 deep_research 提交明确研究主题dry_run模式只做就绪检查不真实执行运行与产出agent.run(request.input)后序列化todo_items汇总completed/skipped/failed计数把报告、任务、耗时timings写入artifacts平台联动通过event_logger上报agent_started/agent_completed事件用memory_store记录输入输出执行前调用cleanup_deep_research_artifacts()惰性清理过期运行产物。用户在平台前端只需用指定智能体即可发起调研deep_research 调研 AI Agent 平台架构平台整体采用前端输入deep_research→POST /tasks→ 后台运行 → 前端轮询任务状态 → 返回报告的任务机制详见 Co-creation-projects/huailishang-AgentPlatformBase/README.md。平台自带冒烟测试 smoke_test.py覆盖健康检查、智能体列表、dry run、批量保护与任务执行链路通过时输出chapter16 platform smoke test passed。九、源码级细节与注意事项9.1 思考段与工具指令的清洗模型尤其是本地模型可能在输出中附带think.../think推理段。utils.strip_thinking_tokensutils.py用循环切除所有完整think对流式总结场景下summarizer.py还会在增量缓冲中实时剔除未闭合的think保证前端看到的文本不闪烁见 services/summarizer.py。两个开关均受strip_thinking_tokens配置控制。9.2 线程安全与事件跟踪ToolCallTrackerservices/tool_events.py作为共享工具调用监听器tool_call_listenerself._tool_tracker.record注入所有 Agent_drain_tool_events在流程关键节点统一排空事件run_stream的多线程并发写入由_state_lock保护确保web_research_results、sources_gathered、research_loop_count等共享状态不出现竞态。9.3 无结果与失败兜底规划阶段失败 →create_fallback_task兜底任务搜索无结果 → 状态置为skipped不生成总结平台适配器检测到有任务但无 completed 且无报告时会返回明确提示并引导查看data/deep_research/runs下的task_*文件deep_research.py而非静默失败。9.4 目录与清理边界再次强调 README 中的目录约定这也是运维的核心依据data/deep_research/runs/存放单次运行过程产物平台默认按RESEARCH_RUN_RETENTION_DAYS7自动清理data/deep_research/notes/存放研究笔记与索引含最终报告默认长期保留、不自动删除。十、小结deep_research是 chapter16 平台中技术闭环最完整的智能体之一它用研究规划专家 → 任务总结专家 → 报告撰写专家三个 LLM 角色叠加 TODO 状态机实现主题拆解、多后端检索、增量总结与结构化报告生成通过 NoteTool 的[TOOL_CALL:note:{...}]协议沉淀可长期复用的研究笔记通过Configuration环境变量体系做到 Ollama / LMStudio / 自定义 OpenAI 兼容服务的无缝切换最终经DeepResearchAdapter接入平台统一任务机制并对运行产物与长期笔记实施差异化的生命周期管理。无论是学习多智能体协作、Todo-based 工作流编排还是构建可落地的自动化调研服务这份内置实现都是贴近实战的参考范本。【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/datawhalechina/hello-agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考