十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Deep Search:用 ADK 构建带引用的迭代式深度研究多智能体(全栈实战解析)

Deep Search:用 ADK 构建带引用的迭代式深度研究多智能体(全栈实战解析) Deep Search用 ADK 构建带引用的迭代式深度研究多智能体全栈实战解析【免费下载链接】adk-samplesA collection of sample agents built with Agent Development Kit (ADK)项目地址: https://gitcode.com/GitHub_Trending/ad/adk-samples导读Deep Search是 adk-samples 仓库core/python/deep-search中一个可直接 clone 学习、具备生产级形态的全栈研究型 Agent。与仓库中常见的 RAG 类示例不同它的核心价值不在数据管道而在于app/agent.py中构建的多智能体图先由根 Agent 与用户人机协作制定研究计划Human-in-the-LoopHITL获批后再进入搜索 → 批评 → 精炼的迭代循环直至达到质量线后合成一份带行内引用的研究报告并配套 React 前端与 ADK 驱动的 FastAPI 后端。读完本文你将掌握如何用LlmAgent、SequentialAgent、LoopAgent与自定义BaseAgent编排多智能体工作流如何用EscalationChecker实现基于数据的循环终止以及如何把 Gemini 的 grounding 元数据加工成可点击的 Markdown 行内引用。何时选择这个配方根据 AGENTS.md 的定位当出现以下需求时应优先参考本配方用户期望一个深度研究Agent先规划、再搜索、自我批评、迭代精炼而不是一次问答就结束需要在自主执行前引入人机协作的计划审批环节要求行内来源引用让每一条结论都能回链到具体网页 URL需要一个React FastAPI 全栈示例含自定义研究时间线 UI或一份可复制的无头headless多智能体 ADK 编排骨架。它刻意保持极简的基础设施没有数据存储、没有摄取管道、没有 Terraform——所有数据都在运行时来自 ADK 内置的google_search工具这与仓库中依赖语料库的 RAG 配方形成鲜明对比。架构总览两阶段工作流app/agent.py中的整体流程可以概括为先规划、后执行的两个阶段端到端数据流如下来自 AGENTS.mduser topic - interactive_planner_agent (root LlmAgent) # Phase 1: Plan Refine (HITL) calls plan_generator (AgentTool) to draft a plan refines with user; waits for EXPLICIT approval | (approved) v research_pipeline (SequentialAgent) # Phase 2: Autonomous research 1. section_planner - markdown outline (state: report_sections) 2. section_researcher - first-pass web research (state: section_research_findings) 3. iterative_refinement_loop (LoopAgent, max max_search_iterations) research_evaluator - grade pass/fail follow_up_queries (state: research_evaluation) escalation_checker - stop loop when grade pass enhanced_search_executor - run follow-ups, merge findings 4. report_composer_with_citations - report with cite sourcesrc-N/ tags citation_replacement_callback rewrites tags - Markdown links (state: final_report_with_citations)循环要么在research_evaluator打出pass时提前终止由自定义的EscalationChecker触发 escalate要么在跑满max_search_iterations次后停止——以先到者为准。整个图的组装见 app/agent.pyresearch_pipeline是SequentialAgent其中嵌入了名为iterative_refinement_loop的LoopAgent根 Agent 是interactive_planner_agent最后通过App(root_agentroot_agent, nameapp)暴露给运行时。Phase 1计划与精炼Human-in-the-Loop根 Agentinteractive_planner_agent根 Agent 是LlmAgent职责被严格限定在 agent.py 的指令中永远不直接回答问题。无论用户输入什么它都只能走三步Plan调用plan_generator工具起草研究计划并呈现给用户Refine吸收用户反馈反复精炼直到用户满意Execute仅在用户显式批准如looks good, run it后才把任务委托给research_pipeline。它的output_key是research_plan后续所有阶段都从 state 中读取这个键。注意它只通过tools[AgentTool(plan_generator)]暴露计划生成工具研究本身由sub_agents[research_pipeline]承接。plan_generator5 目标 标签化计划plan_generator是一个带有完整策略指令的LlmAgentagent.py它的核心规则包括初始输出必须是 5 条以动词开头的行动导向研究目标如 Analyze…、Identify…、Investigate…而不是事实陈述每条都要带任务类型前缀工具使用被严格限制只有主题含糊或时效性敏感、不查关键信息就无法规划时才允许调用google_search明确禁止研究主题的内容——那是下游研究员的活精炼时通过标签标记变更方便下游理解计划的演化历史。计划中使用的标签体系详见 README.md类别标签含义研究计划标签[RESEARCH]信息收集、调查、分析类目标需要研究员使用搜索工具研究计划标签[DELIVERABLE]综合信息、产出结构化结果表格、图表、摘要、报告在研究之后执行精炼标签[MODIFIED]已有目标被更新精炼标签[NEW]按用户反馈新增的目标精炼标签[IMPLIED]Agent 主动推断出的隐含交付物如比较分析隐含对比表格初始 5 个目标全部归类为[RESEARCH]如果这些目标天然隐含标准产出物例如综合评审隐含总结文档Agent 必须主动追加[DELIVERABLE][IMPLIED]目标精炼后计划不再受 5 条上限约束[NEW]/[IMPLIED]目标一般追加在列表末尾以保持原有顺序。Phase 2自主研究流水线计划获批后research_pipelineSequentialAgent按顺序执行四个子阶段。section_planner把计划变成报告大纲section_planneragent.py是报告架构师读取research_plan产出一个含4~6 个互不重叠章节的 Markdown 大纲output_keyreport_sections。它的指令明确要求忽略计划中的各类标签[MODIFIED]/[NEW]/[RESEARCH]/[DELIVERABLE]并且不写 References/Sources 章节——引用必须在正文行内完成。section_researcher第一轮网络研究section_researcheragent.py是整个研究的第一遍执行者配了BuiltInPlanner(thinking_configgenai_types.ThinkingConfig(include_thoughtsTrue))以启用思考能力。其指令把执行严格切分为两个顺序阶段Phase 1[RESEARCH]任务对每个研究目标设计4~5 个多角度搜索查询全部用google_search执行汇总成详细摘要并内部保存绝不允许丢失Phase 2[DELIVERABLE]任务必须等所有研究目标完成后才启动对每个交付目标产出指定产物如必须是规范 Markdown 表格只允许使用 Phase 1 的摘要、禁止发起新搜索。它的output_keysection_research_findings并挂载了after_agent_callbackcollect_research_sources_callback用于把这次搜索的 grounding 元数据收进 state见下文引用机制。iterative_refinement_loop搜索 → 批评 → 精炼这是全图最精彩的部分——一个LoopAgentagent.pymax_iterationsconfig.max_search_iterations内部串行三个子 Agentresearch_evaluatoragent.py质量保证分析师使用critic_model。通过output_schemaFeedback强制输出结构化 JSON只评估给定主题下研究的质量、深度与完整性不质疑主题前提本身。打分规则很明确若覆盖有明显缺口给fail、写详细评论并生成5~7 条针对性 follow-up 查询若研究充分则给pass。它还设置了disallow_transfer_to_parentTrue与disallow_transfer_to_peersTrue防止把控制权转走。Feedback的 Pydantic 定义agent.py如下class Feedback(BaseModel): grade: Literal[pass, fail] Field( descriptionEvaluation result. pass if the research is sufficient, fail if it needs revision. ) comment: str Field(descriptionDetailed explanation of the evaluation...) follow_up_queries: list[SearchQuery] | None Field( defaultNone, descriptionA list of specific, targeted follow-up search queries needed to fix research gaps..., )escalation_checker自定义BaseAgent见下节enhanced_search_executoragent.py精炼执行者同样带BuiltInPlanner。它读取research_evaluation中的反馈用google_search逐条执行follow_up_queries把新发现与既有section_research_findings合并输出新的、完整的、改进后的研究结果覆盖同一个output_keysection_research_findings并同样挂载collect_research_sources_callback收集新来源。EscalationChecker数据驱动的循环终止技巧EscalationCheckeragent.py是理解整个配方循环控制的关键也是 AGENTS.md 特别点名的模式一个唯一职责是循环控制的自定义BaseAgent。它的_run_async_impl读ctx.session.state[research_evaluation]当grade pass时 yield 一个携带EventActions(escalateTrue)的事件来终止LoopAgent否则 yield 一个无操作事件让流程继续。核心实现如下async def _run_async_impl(self, ctx: InvocationContext) - AsyncGenerator[Event, None]: evaluation_result ctx.session.state.get(research_evaluation) if evaluation_result and evaluation_result.get(grade) pass: yield Event(authorself.name, actionsEventActions(escalateTrue)) else: yield Event(authorself.name)这种把状态读出来、按数据决定是否 escalate的做法正是让LoopAgent在数据驱动条件下提前退出的通用范式——可以平移到任何需要质量达标即停的循环场景。report_composer_with_citations带行内引用的报告合成report_composeragent.py使用critic_modelinclude_contentsnone以节省上下文。它同时读取research_plan、section_research_findings、sources、report_sections四个 state 键产出final_cited_report。引用规则是硬约束唯一合法格式是cite sourcesrc-N /紧跟在所支持论断之后并且报告不设 References 章节。after_agent_callbackcitation_replacement_callback负责把标签最终替换为 Markdown 链接。引用机制从 grounding 元数据到 Markdown 链接引用链路由两个回调构成全部实现在 agent.pycollect_research_sources_callbackafter_agent_callback挂在两个研究员 Agent 上遍历session.events从grounding_metadata.grounding_chunks提取 URL、标题、域名标题与域名相同时用域名兜底为每个新 URL 分配自增短 IDsrc-N并写入state[url_to_short_id]同时从grounding_supports提取每个来源支撑的文本片段与置信度分数缺省 0.5累积到state[sources][short_id][supported_claims]。citation_replacement_callbackafter_agent_callback挂在合成 Agent 上读取final_cited_report与sources用正则rcite\ssource\s*\s*[\]?\s*(src-\d)\s*[\]?\s*/把合法标签替换为标题形式的 Markdown 链接无效标签找不到对应来源记录 warning 后直接移除最后还会修复标点前的多余空格re.sub(r\s([.,;:]), r\1, ...)并把结果写入state[final_report_with_citations]作为回调返回值。这套机制意味着最终报告没有独立的参考文献区每条论断后紧跟来源链接来源标题即链接文本——这正是行内引用inline citations的落地形态。状态即数据总线跟踪键的流转本配方没有数据库会话状态session state就是数据总线。Agent 之间不通过返回值而通过 state 键通信AGENTS.md 给出了完整的键流转链research_plan → report_sections → section_research_findings → research_evaluation → sources / url_to_short_id → final_cited_report → final_report_with_citations阅读 agent.py 时顺着每个 Agent 的output_key与指令中的{state}模板引用如{research_plan?}、{sources}就能完整还原数据流这也解释了为什么无存储设计下信息仍能跨 Agent 无缝接力。配置与认证引导app/config.pyResearchConfiguration是一个 dataclassconfig.py只有三个字段worker_model工作模型规划、研究、精炼、搜索查询生成等读取环境变量MODEL_NAMEcritic_model批评/合成模型评估、最终报告同样读取MODEL_NAMEmax_search_iterations精炼循环上限默认5。两个模型共用同一个环境变量意味着当前配方对 worker 与 critic 不做模型区分。认证引导写在模块顶层config.py若设置了GOOGLE_API_KEY走AI Studio模式并显式把GOOGLE_GENAI_USE_VERTEXAI置为False防止陈旧的 env 值悄悄改变认证模式否则调用google.auth.default()解析项目 ID设置GOOGLE_CLOUD_PROJECT/GOOGLE_CLOUD_LOCATION默认global并把GOOGLE_GENAI_USE_VERTEXAI置为True走Vertex AI。因此 AI Studio 是默认路径没有凭证时以 Vertex 模式导入会直接失败。此外 app/init.py 中还有一层 env bootstrap加载.env、解析 GCP 项目、设置 Vertex 默认值然后才 importroot_agent——这个顺序是刻意的因为 agent 在 import 时就会读取环境变量bootstrap 必须先行from app.agent import root_agent # noqa: E402。前端与后端按 Agent 名耦合前端是独立的 React Vite 应用frontend/src消费 ADK 的/api/run_sse流并按Agent 名路由事件frontend/src/App.tsx定义后端↔UI 契约getEventTitle()把每个 Agent 映射为时间线标签网站计数来自section_researcher/enhanced_search_executor最终报告从report_composer_with_citations捕获frontend/src/components/ActivityTimeline.tsx渲染实时研究时间线frontend/src/components/ChatMessagesView.tsx渲染聊天与最终带引用的报告frontend/src/components/WelcomeScreen.tsx 与 frontend/src/components/InputForm.tsx负责输入区components/ui/是 Shadcn 组件。这也带来一个强约束Agent 名是前后端的公共 API。改名前必须同步更新前端否则时间线与报告展示都会失效详见下文 Gotchas。运行方式Makefile 目标与命令本配方在 Makefile 中暴露了完整的目标集AGENTS.mdMakefile 目标实际命令说明make installuv sync npm --prefix frontend install安装 Python 与前端依赖make dev后台同时启动 dev-backend dev-frontend一键起双服务make dev-backenduv run adk api_server app --allow_origins*ADK API 服务监听:8000make dev-frontendnpm --prefix frontend run devVite 开发服务器监听:5173将/api/*代理到http://127.0.0.1:8000base path/app/make playgrounduv run adk web --port 8501ADK 内置 Web UIStreamlit 风格无需 Reactmake lintuv sync --dev --extra lint后依次跑 codespell、ruff check、ruff format --check、mypy代码质量检查注意没有make test唯一的冒烟测试需要手动运行uv run pytest tests/test_runnability.py。该测试tests/test_runnability.py在patch(google.auth.default, ...)的情况下导入app.agent断言root_agent与app均已定义它内部用setdefault预置了GOOGLE_CLOUD_PROJECTtest-project与MODEL_NAMEgemini-3.5-flash从而在无 ADC 凭证时也能通过导入。依赖方面pyproject.toml 声明google-adk1.8.0与python-dotenv1.0.0Python 版本要求3.11,3.13dev 组包含 pytest、pytest-asyncio、nest-asyncio、agent-starter-pack 与 jupyterlint 可选依赖包含 ruff、mypy、codespell 等。配方本身被[tool.agent-starter-pack]标记为deployment_targets [agent_engine, cloud_run]说明可部署到 Agent Runtime 或 Cloud Run。关于 Eval 的事实边界按 AGENTS.md 的明确说明本配方没有内置评测没有tests/eval/目录、没有eval_config.yaml、没有 LLM-judge 打分唯一的测试是tests/test_runnability.py冒烟测试且未接入make test若要补充评测需要自建tests/eval/datasets/与eval_config.yaml可参考仓库内 RAG 类配方的 agents-cli eval 格式再用 agents CLI 运行。不要在本文基础上假设存在任何现成 eval 路径。Gotchas使用前必读的六个坑AGENTS.md 总结了实践中最容易踩的坑Agent 名是公共 API前端按精确名称匹配plan_generator、section_planner、section_researcher、enhanced_search_executor、report_composer_with_citations、interactive_planner_agent。在 app/agent.py 中改名必须同步 frontend/src/App.tsx 与 frontend/src/components/ChatMessagesView.tsx。模型来自MODEL_NAME而非硬编码worker_model与critic_model读同一个变量未设置时config.py返回None——务必设置冒烟测试默认gemini-3.5-flash不要使用已废弃的gemini-2.0-flash/gemini-2.5-flash。AI Studio 默认、Vertex 可选有GOOGLE_API_KEY走 AI Studio否则回退google.auth.default() Vertex无凭证时 Vertex 模式导入会失败。精炼循环有界pass即停经EscalationChecker或max_search_iterations默认 5到顶先到为准调高上限会线性增加延迟与成本。无make test与无 evalmake lint跑 codespell ruff mypy冒烟测试需手动uv run pytest tests/test_runnability.py。make dev跑两个服务后台同时启动dev-backendADKapi_server:8000与dev-frontendVite:5173Vite 把/api/*代理到http://127.0.0.1:8000base path 为/app/。复用指南如何搬走这套配方本配方的复用性设计得非常干净AGENTS.mdapp/是自包含的 ADK Agent整体拷贝目录多智能体图、配置与引用回调会一起迁移。它唯一的运行时输入是环境变量MODEL_NAME以及GOOGLE_API_KEY或 Vertex 凭证二者其一没有需要搭建的数据存储、摄取管道或 Terraformfrontend/是独立的 React Vite 应用自带package.json可以整体拷贝但它通过Agent 名与 ADK SSE 契约/api/run_sse、/api/apps/app/...耦合后端——务必与app/agent.py保持名称同步Agent 也可以无头运行把任意 ADK 运行时指向app.agent:root_agent即可make playground通过adk web就是这么做的完全不需要 React。从实践角度看这份配方最大的学习价值在于三件事用LoopAgent 自定义EscalationChecker实现质量达标即停的迭代控制、用output_key/{state}模板让多智能体通过会话状态解耦通信、以及把 Gemini grounding 元数据改造成可点击的行内引用——这三个模式都可以直接平移到你自己的 ADK 项目中。【免费下载链接】adk-samplesA collection of sample agents built with Agent Development Kit (ADK)项目地址: https://gitcode.com/GitHub_Trending/ad/adk-samples创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表