ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Datawhale 的基本信息

Datawhale 的基本信息 Datawhale 的基本信息【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/GitHub_Trending/he/hello-agentsDatawhale 是一个专注于数据科学与 AI 的开源组织成立于 2018 年[1]...核心定位开源教育平台提供高质量的 AI 与数据科学学习资源[1]学习者社区聚集数万名 AI 学习者和从业者[3]知识共享倡导开源精神内容完全免费开放[2]Sources[1] https://github.com/datawhalechina [2] https://datawhale.club/about [3] https://www.zhihu.com/org/datawhale执行过程中系统会实时向前端推送进度信息 json { type: status, message: 正在搜索: Datawhale 的基本信息 }{ type: status, message: 正在总结搜索结果... }{ type: task, task: { id: 1, title: Datawhale 的基本信息, status: completed } }阶段三报告Reporting报告阶段的目标是整合所有子任务的总结生成最终报告。系统接收所有子任务的总结 研究主题作为输入输出Markdown 格式的最终报告。报告包含五个部分标题、概述、各子任务详细分析、总结、参考文献。报告生成 Agent 会按子任务的逻辑顺序组织内容、开头添加简要概述、合并重复信息、统一 Markdown 格式并把所有来源引用整理进参考文献区。四、Agent 系统设计4.1 三个 Agent 的职责划分第七章中我们学会了用SimpleAgent构建 Agent它的设计哲学简单直接每次调用run()方法Agent 分析用户问题、决定是否调用工具、返回结果。这对简单任务很有效但面对深度研究这样的复杂任务需要采用多 Agent 协作的方式。本项目设计了三个专职 AgentAgent职责设计哲学研究规划专家TODO Planner把研究主题分解为 35 个子任务类似人类研究者研究前的头脑风暴任务总结专家Task Summarizer总结搜索结果、提取关键信息类似人类研究者读完文献后的笔记报告撰写专家Report Writer整合所有子任务总结生成最终报告类似人类研究者完成全部调研后撰写报告Agent 1研究规划专家TODO Planner其提示词见 backend/src/prompts.py要求 Agent结合研究主题梳理35 个最关键的调研任务每个任务要有明确意图与可执行的检索方向任务之间应互补、避免重复必须调用note工具同步任务信息这是唯一写入笔记的途径严格以 JSON 格式回复{tasks: [...]}。关键设计点包括提示词注入当前日期以获取最新信息明确要求JSON 格式输出便于解析通过示例帮助 Agent 理解预期输出强调子任务数量与逻辑关系等约束。Agent 2任务总结专家Task Summarizer其提示词见 backend/src/prompts.py要求 Agent 基于给定上下文为特定任务生成要点总结对内容进行详尽且细致的总结并尽可能多维度原理、应用、优缺点、工程实践、对比、历史演变等拓展梳理35 条关键发现每条发现需说明含义与价值、可引用事实数据。关键设计点提示词包含任务标题、意图、查询等上下文明确要求输出包含核心观点、关键数据、来源引用强调每个观点都要加来源引用通过示例帮助 Agent 理解输出格式。Agent 3报告撰写专家Report Writer其提示词见 backend/src/prompts.py采用REPORT_TEMPLATE模板要求报告包含五大部分背景概览简述研究主题的重要性与上下文核心洞见提炼 35 条最重要的结论标注文献/任务编号证据与数据罗列支持性的事实或指标风险与挑战分析潜在的问题、限制或待验证的假设参考来源按任务列出关键来源条目标题 链接。同时要求报告使用 Markdown、各部分明确分节、禁止添加额外的封面或结语、若某部分信息缺失需说明暂无相关信息、输出内容中禁止残留[TOOL_CALL:...]指令。4.2 ToolAwareSimpleAgent 设计在深度研究助手中我们需要记录每个 Agent 的工具调用用途包括调试查看 Agent 调用了哪些工具、传入了什么参数日志记录研究过程的全部操作分析分析 Agent 的行为模式进度展示实时展示 Agent 正在做什么。SimpleAgent本身不支持工具调用监听因此需要扩展它。ToolAwareSimpleAgent在SimpleAgent之上增加了tool_call_listener参数——这是一个回调函数每次调用工具时都会被触发from hello_agents import ToolAwareSimpleAgent def tool_listener(call_info): print(fAgent: {call_info[agent_name]}) print(fTool: {call_info[tool_name]}) print(fParameters: {call_info[parsed_parameters]}) print(fResult: {call_info[result]}) agent ToolAwareSimpleAgent( nameResearch Assistant, system_promptYou are a research assistant, llmllm, tool_call_listenertool_listener )ToolAwareSimpleAgent继承自SimpleAgent并重写_execute_tool_call方法先解析参数、调用父类执行工具然后通知监听器agent 名称、工具名、解析后的参数、执行结果。在仓库真实实现中工具调用事件由 backend/src/services/tool_events.py 的ToolCallTracker统一收集它能从工具参数中推断 task_id优先取task_id字段其次从tags中的task_\d或标题中的任务 N匹配并从note工具结果文本中提取note_id最终把事件转换为 SSE 负载type: tool_call、agent、tool、parameters、result、task_id、note_id、note_path。4.3 三个 Agent 的协作模式三个 Agent 是顺序协作关系多任务执行时也可并行见下线性流程Agent 按固定顺序执行输入输出清晰每个 Agent 的输入来自上一个 Agent 的输出任务间可并行仓库的流式实现backend/src/agent.py中每个子任务由独立线程Thread执行多个子任务的搜索与总结可以并发进行事件通过Queue汇聚后按序 yield。图 14-6 Agent 协作过程DeepResearchAgent是整个系统的核心协调器backend/src/agent.py它调度三个服务完成完整流程def run(self, topic: str) - SummaryStateOutput: state SummaryState(research_topictopic) state.todo_items self.planner.plan_todo_list(state) # 1. 规划 if not state.todo_items: # 规划失败时的兜底 state.todo_items [self.planner.create_fallback_task(state)] for task in state.todo_items: self._execute_task(state, task, emit_streamFalse) # 2. 执行 report self.reporting.generate_report(state) # 3. 报告 state.structured_report report self._persist_final_report(state, report) # 4. 持久化 return SummaryStateOutput(running_summaryreport, ...)注意源码中的兜底机制当规划 Agent 无法生成任务返回空列表时PlanningService.create_fallback_task会创建一个基础背景梳理任务保证研究流程不会中断backend/src/services/planner.py。五、工具系统集成5.1 SearchTool 多搜索引擎扩展第七章中实现的基础版SearchTool集成了 Tavily 与 SerpApi。本章进一步扩展新增 DuckDuckGo、Perplexity、SearXNG 等搜索引擎并实现 Advanced 模式多引擎组合搜索。SearchTool 提供统一的搜索接口无论使用哪个引擎调用方式都相同。引擎选择通过配置文件完成backend/src/config.pyclass SearchAPI(str, Enum): TAVILY tavily DUCKDUCKGO duckduckgo PERPLEXITY perplexity SEARXNG searxng ADVANCED advanced class Configuration(BaseModel): search_api: SearchAPI SearchAPI.DUCKDUCKGO # ...# .env SEARCH_APItavily这样用户只需修改.env文件即可切换搜索引擎无需改动代码。仓库中的搜索调度实现在 backend/src/services/search.py它调用全局共享的SearchTool(backendhybrid)传入modestructured、fetch_full_page、max_results5、max_tokens_per_source2000、loop_count等参数。SearchTool返回的字典包含results搜索结果列表每条含 title、URL、snippetbackend实际使用的搜索引擎answerAI 生成的答案仅 Perplexity 返回notices通知信息如 API 限额、错误等。去重处理搜索结果可能包含重复 URL需要去重真实实现见 backend/src/utils.py 的deduplicate_and_format_sources以 URL 为键保留首个来源def deduplicate_sources(sources: List[dict]) - List[dict]: Remove duplicate URLs seen_urls set() unique_sources [] for source in sources: if source[url] not in seen_urls: seen_urls.add(source[url]) unique_sources.append(source) return unique_sourcesToken 限制搜索结果可能包含大量文本需要限制每个来源的 token 数。简单估算规则是 1 token ≈ 4 字符def limit_source_tokens(source: dict, max_tokens: int 2000) - dict: Limit the number of tokens for a source snippet source[snippet] max_chars max_tokens * 4 if len(snippet) max_chars: snippet snippet[:max_chars] ... return {**source, snippet: snippet}5.2 NoteTool 研究进度持久化深度研究助手使用NoteTool第九章集成的内置工具持久化研究进度支持创建、读取、更新、删除笔记。研究过程中需要记录每个子任务的搜索结果、总结与最终报告这些信息持久化到磁盘后可支持中断后从上次进度继续研究、查看研究全过程操作、分析研究质量与效率。NoteTool把笔记存储在指定 workspace 目录中每条笔记是一个 Markdown 文件文件名即任务 ID内容包含任务标题、任务意图、搜索查询、搜索结果与总结。生成的文件树workspace/ ├── notes/ │ ├── 1.md # 任务 1 的笔记 │ ├── 2.md # 任务 2 的笔记 │ ├── 3.md # 任务 3 的笔记 │ └── ... └── reports/ └── final_report.md # 最终报告在深度研究助手中用NotesService记录每个子任务的研究进度仓库真实实现把该逻辑内联进DeepResearchAgent见 backend/src/agent.py 的_persist_final_report它会在更新失败时回退为创建class NotesService: def __init__(self, workspace: str): self.note_tool NoteTool(workspaceworkspace) def save_task_summary(self, task: TodoItem, search_results: List[dict], summary: str): content self._format_note_content(task, search_results, summary) self.note_tool.run({ action: create, title: fTask {task.id}: {task.title}, content: content, tags: [research, summary] }) def _format_note_content(self, task, search_results, summary) - str: content f# Task {task.id}: {task.title}\n\n content f## Task Information\n\n- **Intent**: {task.intent}\n- **Query**: {task.query}\n\n content f## Search Results\n\n for idx, result in enumerate(search_results, start1): content f[{idx}] {result[title]}\nURL: {result[url]}\nSnippet: {result[snippet]}\n\n content f## Summary\n\n{summary}\n return content值得注意的是仓库中的 Agent 会主动通过[TOOL_CALL:note:{...}]指令调用 note 工具见 backend/src/services/notes.py 的build_note_guidance总结 Agent 在书写总结前先read最新笔记、完成后update增量信息规划 Agent 创建任务时同步创建笔记报告 Agent 生成报告前逐个read任务笔记、结束后创建conclusion类型笔记沉淀报告要点。这种笔记即协作介质的设计让三个 Agent 可以通过持久化笔记共享上下文也天然支持断点续研。5.3 ToolRegistry 工具管理ToolRegistry是 HelloAgents 框架的工具注册表用于管理所有工具的注册与调用。在深度研究助手中用它管理SearchTool与NoteToolfrom hello_agents import ToolAwareSimpleAgent from hello_agents.tools import ToolRegistry, SearchTool, NoteTool # 创建工具 search_tool SearchTool(backendhybrid) note_tool NoteTool(workspace./workspace/notes) # 创建注册表并注册 registry ToolRegistry() registry.register_tool(search_tool) registry.register_tool(note_tool) # 创建 Agent agent ToolAwareSimpleAgent( nameResearch Assistant, system_promptYou are a research assistant, llmllm, tool_registryregistry )仓库中 backend/src/agent.py 在enable_notes开启时才注册 NoteTool 并传入tool_registry否则 Agent 不启用工具调用enable_tool_callingFalse体现配置驱动的灵活性。工具调用流程Agent 生成指令如[TOOL_CALL:search_tool:{input: Datawhale 组织, backend: tavily}]解析指令ToolRegistry解析指令提取工具名与参数查找工具根据工具名找到对应工具调用工具调用工具的run方法并传入参数返回结果工具返回执行结果格式化结果把结果格式化为字符串返回给 Agent。图 14-7 工具调用过程六、服务层实现服务层是连接 Agent 与工具的桥梁负责具体业务逻辑。四个核心服务分别是PlanningService、SummarizationService、ReportingService、SearchService。6.1 规划服务PlanningServicePlanningService负责调用研究规划 Agent 分解主题这是整个研究流程的第一步也是最关键的一步backend/src/services/planner.py。核心职责构建规划 Prompt基于研究主题和当前日期构建调用规划 Agent生成子任务列表解析 JSON 响应从 Agent 回复中提取 JSON 格式的子任务列表校验子任务格式确保每个子任务包含 title、intent、query 字段。JSON 解析与校验是工程重点。Agent 返回的 JSON 可能包含额外文本或格式错误常见问题与解决方案常见问题解决方案包含额外文本JSON 前后有解释性文字用正则/边界字符提取 JSON 部分格式错误缺引号、缺逗号多策略解析先提取 JSON 数组/对象再尝试整体解析缺少必填字段逐条校验 title/intent/query缺失则抛出异常或回退默认值仓库中的_extract_json_payload采用找{...}或[...]边界的策略解析_extract_tasks还支持从[TOOL_CALL:...]指令中提取任务负载并支持strip_thinking_tokens预处理移除think推理段见 backend/src/utils.py。字段缺失时不会直接失败而是回退到默认值title→ 任务N、intent→ 聚焦主题的关键问题、query→ 研究主题保证健壮性。规划质量评估可以增加评估方法def evaluate_plan(self, todo_items: List[TodoItem]) - dict: score 100 suggestions [] if len(todo_items) 3: score - 20 suggestions.append(子任务过少可能遗漏重要信息) elif len(todo_items) 5: score - 10 suggestions.append(子任务过多可能存在冗余) for task in todo_items: if len(task.query.split()) 2: score - 10 suggestions.append(f任务 {task.title} 的查询过于简单) return {score: score, suggestions: suggestions}好的规划标准覆盖全面、逻辑清晰、查询精准、数量适中35 个。6.2 总结服务SummarizationServiceSummarizationService负责调用任务总结 Agent是研究流程的核心环节直接决定研究质量backend/src/services/summarizer.py。职责格式化搜索结果把搜索结果整理为可读文本编号 标题 URL 摘要构建总结 Prompt基于任务信息与搜索结果构建调用总结 Agent生成总结提取来源引用从总结中提取来源引用。class SummarizationService: def __init__(self, llm: HelloAgentsLLM, tool_call_listenerNone): self._agent ToolAwareSimpleAgent( nameTask Summarizer, system_promptYou are a task summarization expert, llmllm, tool_call_listenertool_call_listener ) def summarize_task(self, task: TodoItem, search_results: List[dict]) - str: formatted_sources self._format_sources(search_results) prompt task_summarizer_instructions.format( task_titletask.title, task_intenttask.intent, task_querytask.query, search_resultsformatted_sources, ) summary self._agent.run(prompt) return summary仓库中SummarizationService还提供流式总结stream_task_summary逐 chunk 读取agent.stream_run(prompt)的输出实时过滤think推理段、移除[TOOL_CALL:...]指令后把可见文本逐步 yield 给前端同时通过闭包get_summary()收集完整总结兼顾实时展示与最终落盘。6.3 报告生成服务ReportingServiceReportingService负责调用报告生成 Agent 整合所有子任务总结是研究流程的最后一步backend/src/services/reporter.py。职责格式化子任务总结把所有子任务总结统一格式任务编号、标题、意图、总结、来源 URL构建报告 Prompt基于研究主题与子任务总结构建调用报告 Agent生成最终报告整理引用把全部来源引用整理进参考文献区。class ReportingService: def generate_report(self, research_topic: str, task_summaries) - str: formatted_summaries self._format_summaries(task_summaries) prompt report_writer_instructions.format( research_topicresearch_topic, task_summariesformatted_summaries, ) report self._agent.run(prompt) return report仓库实现中报告 Agent 的 Prompt 会注入每个任务的目标、检索查询、执行状态、任务总结、来源概览以及可用任务笔记清单note_id并要求先逐个read任务笔记再整合信息必要时创建conclusion笔记沉淀报告要点。6.4 搜索调度服务SearchServiceSearchService负责调度搜索引擎、执行搜索并返回结果是连接 Agent 与 SearchTool 的桥梁backend/src/services/search.py。注意这里没有采用 SimpleAgent 直接调用工具的常见形式而是通过中间层把 SearchTool 的执行结果返回给 Agent让 Agent 更专注于处理获取到的信息。职责调度搜索引擎根据配置选择引擎执行搜索调用 SearchTool处理结果去重、限制 token、格式化错误处理处理搜索失败场景异常时记录日志并返回空列表。class SearchService: def __init__(self, config: Configuration): self.config config self.search_tool SearchTool(backendhybrid) def search(self, query: str, max_results: int 5) - List[dict]: try: raw_response self.search_tool.run({ input: query, backend: self.config.search_api.value, mode: structured, max_results: max_results }) results raw_response.get(results, []) results self._deduplicate_sources(results) results self._limit_source_tokens(results) return results except Exception as e: logger.error(fSearch failed: {query}, error: {e}) return []调度逻辑读取SEARCH_API配置 → 选择引擎 → 执行搜索 → 去重/限 token/格式化 → 返回结果。为提升效率、降低成本还可以为搜索结果增加缓存MD5 生成缓存键命中直接返回import hashlib, json from pathlib import Path class SearchService: def __init__(self, config): self.config config self.search_tool SearchTool(backendhybrid) self.cache_dir Path(./cache/search) self.cache_dir.mkdir(parentsTrue, exist_okTrue) def search(self, query, max_results5, use_cacheTrue): cache_key self._generate_cache_key(query, max_results) cache_file self.cache_dir / f{cache_key}.json if use_cache and cache_file.exists(): return json.load(open(cache_file, r, encodingutf-8)) results self._execute_search(query, max_results) if use_cache and results: json.dump(results, open(cache_file, w, encodingutf-8), ensure_asciiFalse, indent2) return results def _generate_cache_key(self, query, max_results) - str: content f{query}_{max_results}_{self.config.search_api.value} return hashlib.md5(content.encode()).hexdigest()通过四个核心服务我们构建了完整的研究流程。各服务各司其职、通过清晰的接口协作实现了从研究主题到最终报告的自动化。七、前端交互设计7.1 全屏模态对话框 UI深度研究助手采用全屏模态对话框 UI优点沉浸式体验全屏展示避免干扰聚焦研究层次清晰主页与研究页分离层级分明易于关闭点击关闭按钮或按 ESC 键返回主页响应式设计适配不同屏幕尺寸。全屏模态对话框包含四部分顶部栏研究主题 关闭按钮进度区当前研究进度规划、执行、报告内容区研究结果Markdown 格式底部栏状态信息如研究中…、已完成。图 14-9 全屏模态对话框 UI对应的 Vue 实现ResearchModal.vue核心逻辑template div v-ifisOpen classmodal-overlay click.selfclose div classmodal-container !-- 顶部栏 -- div classmodal-header h2{{ researchTopic }}/h2 button clickclose classclose-button×/button /div !-- 进度区 -- div classprogress-section div classprogress-bar div classprogress-fill :style{ width: progressPercentage % }/div /div div classprogress-text{{ progressText }}/div /div !-- 内容区 -- div classcontent-section div v-ifisLoading classloading-spinner div classspinner/div p研究中请稍候.../p /div div v-else classmarkdown-content v-htmlrenderedMarkdown/div /div !-- 底部栏 -- div classmodal-footer span classstatus-text{{ statusText }}/span /div /div /div /template script setup langts import { ref, computed, watch } from vue import { marked } from marked const props defineProps{ isOpen: boolean; researchTopic: string }() const emit defineEmits{ close: [] }() const isLoading ref(true) const progressPercentage ref(0) const progressText ref(Preparing...) const statusText ref(Researching...) const markdownContent ref() const renderedMarkdown computed(() marked(markdownContent.value)) const close () emit(close) const handleKeydown (e: KeyboardEvent) { if (e.key Escape) close() } watch(() props.isOpen, (isOpen) { isOpen ? document.addEventListener(keydown, handleKeydown) : document.removeEventListener(keydown, handleKeydown) }) /script为适配不同屏幕尺寸添加媒体查询/* 平板设备 */ media (max-width: 768px) { .modal-container { width: 95vw; height: 95vh; } } /* 手机设备 */ media (max-width: 480px) { .modal-container { width: 100vw; height: 100vh; border-radius: 0; } .modal-header h2 { font-size: 18px; } }7.2 SSE 实时进度展示深度研究助手使用SSEServer-Sent Events实现实时进度展示。SSE 是服务端推送技术允许服务器主动向客户端发送数据。图 14-10 SSE 过程流程说明客户端发起请求向/research/stream发送请求携带研究主题服务端建立 SSE 连接返回text/event-stream响应服务端推送进度分阶段推送研究进度规划 10%、执行 10%80%、报告 80%100%客户端接收进度监听 SSE 事件、更新 UI研究完成服务端推送最终报告并关闭连接。后端 FastAPI SSE 端点真实实现见 backend/src/main.py事件数据通过agent.run_stream()生成from fastapi import FastAPI from fastapi.responses import StreamingResponse app.post(/research/stream) def stream_research(payload: ResearchRequest) - StreamingResponse: agent DeepResearchAgent(config_build_config(payload)) def event_iterator(): for event in agent.run_stream(payload.topic): yield fdata: {json.dumps(event, ensure_asciiFalse)}\n\n return StreamingResponse( event_iterator(), media_typetext/event-stream, headers{Cache-Control: no-cache, Connection: keep-alive}, )前端使用 fetch 流式读取 SSE真实实现见 frontend/src/services/api.ts它用fetchReadableStreamTextDecoder逐段解析data:事件比EventSource更灵活——可以携带 POST body 并支持 AbortSignal 取消// composables/useResearch.ts import { ref } from vue export function useResearch() { const isLoading ref(false) const progressPercentage ref(0) const progressText ref() const markdownContent ref() const error refstring | null(null) const startResearch (topic: string) { isLoading.value true error.value null const eventSource new EventSource(/api/research?topic${encodeURIComponent(topic)}) eventSource.onmessage (event) { const data JSON.parse(event.data) switch (data.type) { case progress: progressPercentage.value data.percentage progressText.value data.text break case plan: console.log(规划结果:, data.data) break case task_summary: markdownContent.value \n\n## Task ${data.task_id}\n\n${data.summary} break case report: markdownContent.value data.data break case error: error.value data.message eventSource.close() isLoading.value false break case completed: eventSource.close() isLoading.value false break } } eventSource.onerror (err) { console.error(SSE error:, err) error.value 连接失败请重试 eventSource.close() isLoading.value false } } return { isLoading, progressPercentage, progressText, markdownContent, error, startResearch } }在组件中使用script setup langts import { useResearch } from /composables/useResearch const { isLoading, progressPercentage, progressText, markdownContent, error, startResearch } useResearch() const handleStartResearch (topic: string) startResearch(topic) /script7.3 研究结果可视化研究结果以 Markdown 格式展示包括标题、段落、列表、引用等元素。使用marked库将 Markdown 转为 HTML 并添加自定义样式import { marked } from marked marked.setOptions({ breaks: true, // 支持换行 gfm: true, // 支持 GitHub 风格 Markdown }) const renderedHtml marked(markdownContent.value)研究报告中包含大量来源引用需要特殊处理## References ### Task 1: Datawhale 的基本信息 - [Datawhale GitHub](https://github.com/datawhalechina) - [Datawhale 官方网站](https://datawhale.club) ### Task 2: Datawhale 的主要项目 - [Hello-Agents 教程](https://github.com/datawhalechina/Hello-Agents)【免费下载链接】hello-agents 《从零开始构建智能体》——从零开始的智能体原理与实践教程项目地址: https://gitcode.com/GitHub_Trending/he/hello-agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表