LangGraph+BrightData+PaperSearch的研究助理

LangGraph+BrightData+PaperSearch的研究助理

摘要:使用LangGraph的ReAct-Agent范式集成了BrightData和PaperSearch的MCP工具,通过搜索和爬取领英和学术网站,实现论文搜索和读取,学者信息提取,邮箱查找等功能。

链接:github.com/16Miku/Agen...

🚀 前言:我的 AI 助理"精神分裂"了

大家好,我是你们的技术博主。最近在开发 AI Agent 的时候,我遇到了一个很头疼的问题:如何让一个 Agent 既能做"正经事",又能"好好聊天"?

  • 当我让它分析论文时,我希望它给我一个结构清晰、字段分明的 JSON 报告。
  • 当我让它抓取个人主页时,我也希望得到一份规整的结构化数据。
  • 但当我只是想跟它说句"干得不错"时,我希望它能像个正常"人"一样回复我,而不是冷冰冰地甩给我一个空的 JSON 对象。

传统的 Agent 开发模式,比如用 response_format 强行规定输出格式,虽然能解决前两个问题,但却让 Agent 丧失了灵活性,变成了一个只会"填表"的机器人。这显然不是我们想要的"智能助理"。

经过一番探索,我找到了一种极其优雅的解决方案:把结构化输出本身,也变成一种"工具"! 让 Agent 自己来决定什么时候该"填表",什么时候该"聊天"。

今天,我就将手把手带大家,使用 LangGraph 和 Google 最新的 gemini-2.5-flash 模型,构建一个能够无缝切换学术研究信息抓取日常对话三种模式的"全能AI研究助理"。


🔥 核心思路:让"格式"成为一种可选工具

我们这次优化的核心思想,简单来说就是:不强迫,只引导

我们不再粗暴地告诉 LLM:"你必须用这个格式回复我!" 而是换一种更聪明的方式:

  1. 我们定义好想要的报告格式,比如 PaperAnalysis(论文分析报告)和 LinkedinProfile(领英主页报告)。
  2. 但我们不把它们作为强制的 response_format,而是把它们伪装成两个特殊的"工具"交给 Agent。
  3. 我们在 System Prompt 中明确告诉 Agent:"你的工具箱里有搜索、抓取等普通工具,还有两个特殊的'报告生成'工具。当你需要产出正式报告时,请在收集完所有信息后,调用这两个工具来格式化你的最终答案。"

这样做的好处是显而易见的:

  • 高度灵活:Agent 掌握了主动权,可以根据对话上下文自主判断是否需要结构化输出。
  • 任务解耦:将"信息收集"和"格式化输出"两个步骤分开,Agent 的思考过程(Chain of Thought)更加清晰,有助于完成复杂任务。
  • 自然交互:对于普通聊天,Agent 可以直接回复,交互体验大大提升。

理论说完了,让我们 show the code!


🛠️ 实战演练:三步构建全能助理

步骤 1: 环境准备与依赖安装

首先,我们需要在 Colab 环境中安装所有必需的库。这里我们用到了 langgraph 核心框架,langchain-google-genai 用于驱动 Gemini 模型,以及 beautifulsoup4 等辅助库。

⚠️ 注意: 每次安装或升级库之后,为了让新版本生效,请务必在 Colab 菜单栏点击 "代码执行程序" -> "重启会话"。

python 复制代码
# --- 步骤 1: 安装与重启 ---
!pip install --upgrade --quiet langchain langchain-core langchain-mcp-adapters langchain-google-genai langgraph beautifulsoup4
print("✅ 库已升级。请务必从菜单栏点击 '代码执行程序' -> '重启会话',然后再继续运行下面的代码!")

步骤 2: 编写"灵魂"代码

这是我们整个项目的核心代码。我会逐一拆解,让你看懂每一部分的功能。

2.1 导入与密钥配置

常规操作,导入所有需要的模块,并从 Colab 的 userdata 中加载我们的 API 密钥。这种方式比直接把密钥写在代码里更安全。

python 复制代码
# 2.1: 导入
import asyncio
import os
from typing import List, Union
from dataclasses import dataclass
import nest_asyncio
nest_asyncio.apply() # 允许在Jupyter/Colab环境中嵌套运行asyncio事件循环

from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
from pydantic import BaseModel, Field # 导入 Pydantic 用于定义我们的"伪工具"

# 2.2: 加载密钥
from google.colab import userdata
os.environ["GEMINI_API_KEY"] = userdata.get('GEMINI_API_KEY')
BrightData_API_KEY = userdata.get('BrightData_API_KEY')
Paper_Search_API_KEY = userdata.get('Paper_Search_API_KEY')
2.2 🔥 核心优化点:创建"伪工具"🔥

这里就是我们整个方案的"魔法"所在!我们使用 Pydantic 的 BaseModel 来定义两个类:PaperAnalysisLinkedinProfile

  • BaseModel: Pydantic 的基础类,能让我们像定义一个普通的 Python 类一样来定义数据结构。
  • Field : 用于为类的属性添加额外的描述信息。这一点至关重要 ,因为 LLM 正是通过读取这些 description 来理解每个字段的含义以及整个"工具"的作用。
  • 类的文档字符串 (docstring) : 比如 """当用户要求...调用此工具来格式化最终报告。""",这是对整个工具最直接的描述,Agent 会优先读取它来判断工具的用途。
python 复制代码
# ================================================================= #
#  🔥🔥🔥 核心优化点 1: 创建专门用于结构化输出的"伪工具" 🔥🔥🔥
# ================================================================= #
# 我们不再将 dataclass 作为 response_format,而是将它们包装成 Pydantic 模型,
# 并作为"工具"提供给 Agent。这让 Agent 可以自己决定何时调用它们。

class PaperAnalysis(BaseModel):
    """当用户要求对一篇学术论文进行详细分析时,调用此工具来格式化最终报告。"""
    title: str = Field(description="论文的完整标题")
    authors: List[str] = Field(description="论文的核心作者列表")
    research_field: str = Field(description="根据内容总结出的研究方向")
    summary: str = Field(description="对论文核心贡献的详细总结")
    author_contact: str = Field(description="从抓取内容中找到的作者邮箱或个人主页,如果找不到则为 '联系方式未找到'")

class LinkedinProfile(BaseModel):
    """当用户要求提取领英个人主页信息时,调用此工具来格式化最终报告。"""
    full_name: str = Field(description="用户的全名")
    headline: str = Field(description="用户的头衔或当前职位")
    location: str = Field(description="用户所在的地理位置")
    summary: str = Field(description="个人简介部分的总结")
    experience: List[str] = Field(description="一个包含所有工作经历的列表")
    contact: str = Field(description="从抓取内容中找到的邮箱或个人主页,如果找不到则为 '联系方式未找到'")
2.3 设计"行动指南":System Prompt

一个好的 System Prompt 是 Agent 的"灵魂"。在这里,我们明确地为 Agent 设定了角色、能力,以及最重要的------行动指南(ReAct 思考模式)。

请注意,我们特地强调了 PaperAnalysisLinkedinProfile特殊的"报告生成"工具 ,并指导 Agent 在收集完信息后必须调用它们来生成报告。这种明确的指令对于引导 Agent 行为至关重要。

python 复制代码
# --- 步骤 2.3: 设计一个更通用的 System Prompt ---
SYSTEM_PROMPT = """
你是一个全能的AI研究助理。你可以处理多种任务,包括分析学术论文和查询个人资料。

**你的能力 (工具箱):**
*   你拥有学术搜索、通用网页搜索和网页抓取等一系列工具。
*   **特别注意:** 你还拥有两个特殊的"报告生成"工具:`PaperAnalysis` 和 `LinkedinProfile`。

**你的行动指南 (ReAct 思考模式):**
1.  **分析与规划:** 理解用户的请求。如果用户的最终目的是生成一份结构化的报告(比如论文分析或个人资料总结),你的最终行动**必须**是调用 `PaperAnalysis` 或 `LinkedinProfile` 工具。
2.  **信息收集:** 使用你的其他工具(如 `search_arxiv`, `scrape_as_markdown`)来收集填充报告所需的所有信息。
3.  **生成报告:** 当你收集到足够的信息后,调用相应的报告生成工具 (`PaperAnalysis` 或 `LinkedinProfile`),将收集到的信息作为参数传入。
4.  **普通对话:** 如果用户只是进行普通聊天或提出简单问题,直接用自然语言回答即可,无需调用报告工具。
"""
2.4 Agent 的组装与测试

现在,万事俱备,我们来组装 Agent。

  1. 初始化工具集 :我们通过 MultiServerMCPClient 加载了来自 BrightData 和 Paper Search 的真实工具集。
  2. 注入"伪工具" :我们将刚才定义的 PaperAnalysisLinkedinProfile 类,像普通工具一样,追加到 all_tools 列表中。
  3. 创建 Agent :调用 create_agent 函数。请注意,我们没有传递 response_format 参数!这就是我们赋予 Agent 自由的关键。
  4. 多任务测试:我们设计了三个连续的测试用例,覆盖了论文分析、个人资料查询和普通聊天这三种场景。
python 复制代码
# --- 步骤 2.4: 定义主异步函数 ---
async def main():
    print("🚀 开始配置通用 AI Agent...")

    # --- 初始化工具集 ---
    # MultiServerMCPClient 用于连接和管理多个外部工具服务
    mcp_client = MultiServerMCPClient({
        "bright_data": {
            "url": f"https://mcp.brightdata.com/mcp?token={BrightData_API_KEY}&pro=1",
            "transport": "streamable_http",
        },
        "Paper_Search": {
            "url": f"https://server.smithery.ai/@adamamer20/paper-search-mcp-openai/mcp?api_key={Paper_Search_API_KEY}",
            "transport": "streamable_http",
        }
    })

    # 异步获取所有可用的真实工具
    real_tools = await mcp_client.get_tools()

    # 将我们的"伪工具"(Pydantic模型)加入到工具列表中
    all_tools = real_tools + [PaperAnalysis, LinkedinProfile]
    print(f"✅ 成功加载 {len(all_tools)} 个工具。")

    # --- 配置 LLM ---
    # 使用 Google 的 gemini-2.5-flash 模型,性价比很高
    llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", google_api_key=os.environ["GEMINI_API_KEY"])
    print("✅ LLM 配置完成: gemini-2.5-flash")

    # --- 配置内存 ---
    # 使用内存存储会话历史,方便进行多轮对话
    checkpointer = InMemorySaver()
    print("💾 内存已配置: InMemorySaver")

    # --- 步骤 2.5: 创建 Agent,注意这次不指定 response_format ---
    print("🤖 正在创建通用 Agent...")
    agent_executor = create_agent(
        model=llm,
        tools=all_tools, # 传入包含真实工具和"伪工具"的完整列表
        system_prompt=SYSTEM_PROMPT,
        checkpointer=checkpointer
        # 我们移除了 response_format,给予 Agent 更大的自由度
    )
    print("✅ Agent 创建成功!")

    # --- 步骤 2.6: 进行多任务测试 ---
    print("\n" + "="*50)
    print("🚀 开始多任务对话测试!")
    print("="*50)

    # 为本次对话创建一个唯一的线程ID,以保持上下文
    conversation_config = {"configurable": {"thread_id": "multi-task-thread-1"}}

    # --- 任务1: 论文分析 ---
    user_input_1 = "请使用 'search_arxiv' 工具搜索 'https://arxiv.org/abs/2409.09046'里的这篇论文,并用 'read_arxiv_paper' 工具读取论文内容。帮我提取论文主要内容和提取作者信息,尤其是作者们的邮箱。"
    print(f"👤 用户 (任务1): {user_input_1}\n")
    response_1 = await agent_executor.ainvoke({"messages": [("user", user_input_1)]}, config=conversation_config)
    final_answer_1 = response_1['messages'][-1].content
    # ... (打印部分省略) ...

    # --- 任务2: 个人资料查询 ---
    user_input_2 = "干得好!现在,请帮我查找吴恩达的领英主页信息,并以结构化形式返回。"
    print(f"👤 用户 (任务2): {user_input_2}\n")
    response_2 = await agent_executor.ainvoke({"messages": [("user", user_input_2)]}, config=conversation_config)
    final_answer_2 = response_2['messages'][-1].content
    # ... (打印部分省略) ...

    # --- 任务3: 普通聊天 ---
    user_input_3 = "谢谢你,你真是个好帮手。"
    print(f"👤 用户 (任务3): {user_input_3}\n")
    response_3 = await agent_executor.ainvoke({"messages": [("user", user_input_3)]}, config=conversation_config)
    final_answer_3 = response_3['messages'][-1].content
    # ... (打印部分省略) ...

    # --- 统一输出最终结果 ---
    print("\n" + "---" * 20)
    print("最终成果展示:")
    print("---" * 20)
    print("\n[任务一:论文分析结果]\n")
    print(final_answer_1)
    print("\n[任务二:个人资料查询结果]\n")
    print(final_answer_2)
    print("\n[任务三:普通聊天结果]\n")
    print(final_answer_3)


# --- 步骤 2.7: 运行主函数 ---
if __name__ == "__main__":
    asyncio.run(main())

步骤 3: 见证奇迹!分析运行结果

让我们看看这个聪明的 Agent 是如何处理我们抛给它的三个不同任务的。

任务 1: 论文分析 📖

用户输入 : 请使用 'search_arxiv' 工具搜索 'https://arxiv.org/abs/2409.09046'里的这篇论文...帮我提取论文主要内容和提取作者信息...

Agent 回答:

text 复制代码
好的,我已经读取了这篇论文。

**论文主要内容摘要:**

大型语言模型(LLMs)在人工智能法律和政策应用中面临知识过时、幻觉和复杂语境中推理能力差的局限性。检索增强生成(RAG)系统通过整合外部知识来解决这些问题...为高风险法律和政策应用提供了一个强大且适应性强的解决方案。

**作者信息:**

*   **作者:** Rishi Kalra, Zekun Wu, Ayesha Gulley, Airlie Hilliard, Xin Guan, Adriano Koshiyama, Philip Treleaven
*   **所属机构:** Holistic AI 和 University College London

论文中并未直接提供作者的邮箱地址...为了获取作者的邮箱,我需要进行一次网页搜索。请问您是否希望我尝试搜索作者的邮箱?

结果分析 : Agent 准确地执行了 search_arxivread_arxiv_paper 工具,并用 Markdown 格式清晰地总结了论文内容和作者信息。有趣的是,它没有 调用我们预设的 PaperAnalysis 工具。这恰恰证明了它的智能和灵活性!它判断当前场景下,一个格式化的文本回复已经足够清晰,并且在发现信息不完整(找不到邮箱)时,它没有强行填表,而是主动与用户沟通,请求下一步指令。非常棒!

任务 2: 个人资料查询 🧑‍💼

用户输入 : 干得好!现在,请帮我查找吴恩达的领英主页信息,并以结构化形式返回。

Agent 回答:

text 复制代码
好的,这是吴恩达(Andrew Ng)的领英主页信息:

**全名:** Andrew Ng
**头衔:** DeepLearning.AI 创始人;AI Fund 管理合伙人;LandingAI 执行主席
**地点:** 美国加利福尼亚州帕洛阿尔托
**个人简介:** Andrew Ng 是人工智能领域的杰出人物...他的个人主页是 http://andrewng.org。
**经历:**
*   DeepLearning.AI 创始人 (2017 年 6 月 - 至今)
*   AI Fund 管理合伙人 (2018 年 1 月 - 至今)
*   ...
**联系方式:** https://www.linkedin.com/in/andrewyng

结果分析 : 完美! 这次 Agent 的表现堪称典范。

  1. 它理解了"吴恩达"和"领英主页"。
  2. 调用 search_engine 工具找到了正确的 URL。
  3. 调用 web_data_linkedin_person_profile 工具抓取了页面信息。
  4. 最关键的一步 :它调用了我们定义的 LinkedinProfile 这个"伪工具",将抓取到的非结构化信息,自动填充到了我们预设的字段中。
  5. 最后,它将这个结构化的结果以用户友好的格式呈现出来。

这完美地展示了我们的核心策略是多么成功!

任务 3: 普通聊天 😊

用户输入 : 谢谢你,你真是个好帮手。

Agent 回答:

text 复制代码
不客气!很高兴能帮到您。如果您还有其他问题或需要进一步的帮助,请随时告诉我。

结果分析 : 正如我们所期望的,Agent 在面对简单的感谢时,给出了一个自然、礼貌的回复。它没有调用任何工具,更没有去尝试匹配 PaperAnalysisLinkedinProfile,因为它清楚地知道,这只是一个简单的对话。这证明了我们的 Agent 真正实现了"能屈能伸",在不同场景下游刃有余。


总结与展望

通过这次实践,我们成功使用LangGraph的ReAct-Agent范式集成了BrightData和PaperSearch的MCP工具,通过搜索和爬取领英和学术网站,实现了具备论文搜索和读取,学者信息提取,邮箱查找等功能的 AI 助理。其成功的关键,就在于我们转变了思路:

将"强制的输出格式"转变为"可选的格式化工具",把最终决策权交还给 Agent。

这种基于 Pydantic 模型和 ReAct 模式的"伪工具"方法,不仅让我们的 Agent 更加智能和灵活,也为我们未来构建更复杂的、多功能的 Agent 系统提供了一个极具价值的设计范式。

希望今天的分享能对你有所启发。如果你对这个项目有任何疑问或者更好的想法,欢迎在评论区留言讨论!


附:完整项目源码

(为了方便大家复制代码,这里再次贴出完整的、可直接运行的代码)

python 复制代码
# --- 步骤 1: 安装与重启 (同前) ---
!pip install --upgrade --quiet langchain langchain-core langchain-mcp-adapters langchain-google-genai langgraph beautifulsoup4
print("✅ 库已升级。请务必从菜单栏点击 '代码执行程序' -> '重启会话',然后再继续运行下面的代码!")



# --- 步骤 2: 完整代码 ---

# 2.1: 导入
import asyncio
import os
from typing import List, Union
from dataclasses import dataclass
import nest_asyncio
nest_asyncio.apply()

from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
# from langchain_core.pydantic_v1 import BaseModel, Field # 导入 Pydantic 用于动态工具
from pydantic import BaseModel, Field


# 2.2: 加载密钥
from google.colab import userdata
os.environ["GEMINI_API_KEY"] = userdata.get('GEMINI_API_KEY')
BrightData_API_KEY = userdata.get('BrightData_API_KEY')
Paper_Search_API_KEY = userdata.get('Paper_Search_API_KEY')

# ================================================================= #
#  🔥🔥🔥 核心优化点 1: 创建专门用于结构化输出的"伪工具" 🔥🔥🔥
# ================================================================= #
# 我们不再将 dataclass 作为 response_format,而是将它们包装成 Pydantic 模型,
# 并作为"工具"提供给 Agent。这让 Agent 可以自己决定何时调用它们。

class PaperAnalysis(BaseModel):
    """当用户要求对一篇学术论文进行详细分析时,调用此工具来格式化最终报告。"""
    title: str = Field(description="论文的完整标题")
    authors: List[str] = Field(description="论文的核心作者列表")
    research_field: str = Field(description="根据内容总结出的研究方向")
    summary: str = Field(description="对论文核心贡献的详细总结")
    author_contact: str = Field(description="从抓取内容中找到的作者邮箱或个人主页,如果找不到则为 '联系方式未找到'")

class LinkedinProfile(BaseModel):
    """当用户要求提取领英个人主页信息时,调用此工具来格式化最终报告。"""
    full_name: str = Field(description="用户的全名")
    headline: str = Field(description="用户的头衔或当前职位")
    location: str = Field(description="用户所在的地理位置")
    summary: str = Field(description="个人简介部分的总结")
    experience: List[str] = Field(description="一个包含所有工作经历的列表")
    contact: str = Field(description="从抓取内容中找到的邮箱或个人主页,如果找不到则为 '联系方式未找到'")

# --- 步骤 2.3: 设计一个更通用的 System Prompt ---
SYSTEM_PROMPT = """
你是一个全能的AI研究助理。你可以处理多种任务,包括分析学术论文和查询个人资料。

**你的能力 (工具箱):**
*   你拥有学术搜索、通用网页搜索和网页抓取等一系列工具。
*   **特别注意:** 你还拥有两个特殊的"报告生成"工具:`PaperAnalysis` 和 `LinkedinProfile`。

**你的行动指南 (ReAct 思考模式):**
1.  **分析与规划:** 理解用户的请求。如果用户的最终目的是生成一份结构化的报告(比如论文分析或个人资料总结),你的最终行动**必须**是调用 `PaperAnalysis` 或 `LinkedinProfile` 工具。
2.  **信息收集:** 使用你的其他工具(如 `search_arxiv`, `scrape_as_markdown`)来收集填充报告所需的所有信息。
3.  **生成报告:** 当你收集到足够的信息后,调用相应的报告生成工具 (`PaperAnalysis` 或 `LinkedinProfile`),将收集到的信息作为参数传入。
4.  **普通对话:** 如果用户只是进行普通聊天或提出简单问题,直接用自然语言回答即可,无需调用报告工具。
"""

# --- 步骤 2.4: 定义主异步函数 ---
async def main():
    print("🚀 开始配置通用 AI Agent...")

    # --- 初始化工具集 ---
    mcp_client = MultiServerMCPClient({
    "bright_data": {
        "url": f"https://mcp.brightdata.com/mcp?token={BrightData_API_KEY}&pro=1",
        "transport": "streamable_http",
    },
    "Paper_Search": {
        "url": f"https://server.smithery.ai/@adamamer20/paper-search-mcp-openai/mcp?api_key={Paper_Search_API_KEY}",
        "transport": "streamable_http",
    }
    })


    real_tools = await mcp_client.get_tools()

    # 将我们的"伪工具"加入工具列表
    all_tools = real_tools + [PaperAnalysis, LinkedinProfile]
    print(f"✅ 成功加载 {len(all_tools)} 个工具。")

    # --- 配置 LLM ---
    llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash", google_api_key=os.environ["GEMINI_API_KEY"])
    print("✅ LLM 配置完成: gemini-2.5-flash")

    # --- 配置内存 ---
    checkpointer = InMemorySaver()
    print("💾 内存已配置: InMemorySaver")

    # --- 步骤 2.5: 创建 Agent,注意这次不指定 response_format ---
    print("🤖 正在创建通用 Agent...")
    agent_executor = create_agent(
        model=llm,
        tools=all_tools,
        system_prompt=SYSTEM_PROMPT,
        checkpointer=checkpointer
        # 我们移除了 response_format,给予 Agent 更大的自由度
    )
    print("✅ Agent 创建成功!")

    # --- 步骤 2.6: 进行多任务测试 ---
    print("\n" + "="*50)
    print("🚀 开始多任务对话测试!")
    print("="*50)

    conversation_config = {"configurable": {"thread_id": "multi-task-thread-1"}}

    # --- 任务1: 论文分析 ---
    user_input_1 = "请使用 'search_arxiv' 工具搜索 'https://arxiv.org/abs/2409.09046'里的这篇论文,并用 'read_arxiv_paper' 工具读取论文内容。帮我提取论文主要内容和提取作者信息,尤其是作者们的邮箱。"
    print(f"👤 用户 (任务1): {user_input_1}\n")
    response_1 = await agent_executor.ainvoke({"messages": [("user", user_input_1)]}, config=conversation_config)
    final_answer_1 = response_1['messages'][-1].content
    print("\n" + "🤖" * 25)
    print("🤖 Agent 的回答 (任务1):")
    print(final_answer_1)
    print("🤖" * 25 + "\n")

    # --- 任务2: 个人资料查询 ---
    user_input_2 = "干得好!现在,请帮我查找吴恩达的领英主页信息,并以结构化形式返回。"
    print(f"👤 用户 (任务2): {user_input_2}\n")
    response_2 = await agent_executor.ainvoke({"messages": [("user", user_input_2)]}, config=conversation_config)
    final_answer_2 = response_2['messages'][-1].content
    print("\n" + "🤖" * 25)
    print("🤖 Agent 的回答 (任务2):")
    print(final_answer_2)
    print("🤖" * 25 + "\n")

    # --- 任务3: 普通聊天 ---
    user_input_3 = "谢谢你,你真是个好帮手。"
    print(f"👤 用户 (任务3): {user_input_3}\n")
    response_3 = await agent_executor.ainvoke({"messages": [("user", user_input_3)]}, config=conversation_config)
    final_answer_3 = response_3['messages'][-1].content
    print("\n" + "🤖" * 25)
    print("🤖 Agent 的回答 (任务3):")
    print(final_answer_3)
    print("🤖" * 25)

# --- 步骤 2.7: 运行主函数 ---
if __name__ == "__main__":
    asyncio.run(main())
相关推荐
自学互联网2 小时前
python爬虫入门案例day05:Pexels
开发语言·爬虫·python
star_start_sky10 小时前
住宅代理网络:我最近用来数据采集和自动化的小工具
网络·爬虫·自动化
汗流浃背了吧,老弟!13 小时前
基于 LangChain 和 Hugging Face 的 RAG 问答系统实现
langchain
wshzd13 小时前
LLM之Agent(二十九)|LangChain 1.0核心组件介绍
前端·javascript·langchain
zhangbaolin15 小时前
深度智能体-人机回环
langchain·大模型·人机交互·深度智能体
g32308631 天前
langchain langGraph 中streaming 流式输出 stream_mode
langchain·langgraph
zhangbaolin1 天前
深度智能体的中间件
中间件·langchain·大模型·深度智能体
小程故事多_801 天前
LangGraph系列:多智能体终极方案,ReAct+MCP工业级供应链系统
人工智能·react.js·langchain
世界那么哒哒1 天前
LangChain v1.0+ 如何构建自定义中间件来拦截和控制 Agent 执行过程
langchain·agent