• 01. 预构建的 ReACT 智能体

    在 LangGraph 中除了能使用基础组件(节点、边、数据状态)来构建 Agent 智能体,这也是 LangGraph 自由性高的一个优点,我们还可以使用 LangGraph 预构建的代理来快速创建智能体,例如:ReACT智能体 亦或者 工具调用智能体。

    使用技巧也非常简单,导入对应的 预构建函数 然后调用函数即可,例如

    from langgraph.prebuilt.chat_agent_executor import create_react_agent, create_tool_calling_executor

    不过在 LangGraph 底层,目前预构建的 ReACT 智能体目前也是基于 函数调用 的,并且在 0.3.0 版本被剔除,但是其封装思路仍然非常值得借鉴。

    完整实例如下

    import dotenv

    from langchain_community.tools import GoogleSerperRun

    from langchain_community.tools.openai_dalle_image_generation import OpenAIDALLEImageGenerationTool

    from langchain_community.utilities import GoogleSerperAPIWrapper

    from langchain_community.utilities.dalle_image_generator import DallEAPIWrapper

    from langchain_core.pydantic_v1 import BaseModel, Field

    from langchain_openai import ChatOpenAI

    from langgraph.prebuilt.chat_agent_executor import create_react_agent

    dotenv.load_dotenv()

    class GoogleSerperArgsSchema(BaseModel):

        query: str = Field(description="执行谷歌搜索的查询语句")

    class DallEArgsSchema(BaseModel):

        query: str = Field(description="输入应该是生成图像的文本提示(prompt)")

    # 1.定义工具与工具列表

    google_serper = GoogleSerperRun(

        name="google_serper",

        description=(

            "一个低成本的谷歌搜索API。"

            "当你需要回答有关时事的问题时,可以调用该工具。"

            "该工具的输入是搜索查询语句。"

        ),

        args_schema=GoogleSerperArgsSchema,

        api_wrapper=GoogleSerperAPIWrapper(),

    )

    dalle = OpenAIDALLEImageGenerationTool(

        name="openai_dalle",

        api_wrapper=DallEAPIWrapper(model="dall-e-3"),

        args_schema=DallEArgsSchema,

    )

    tools = [google_serper, dalle]

    # 2.创建大语言模型

    model = ChatOpenAI(model="gpt-4o-mini", temperature=0)

    # 3.使用预构建的函数创建ReACT智能体

    agent = create_react_agent(

        model=model,

        tools=tools

    )

    # 4.调用智能体并输出内容

    print(agent.invoke({"messages": [("human", "帮我绘制一幅鲨鱼在天上飞的图片")]}))

    输出内容:

    {'messages': [HumanMessage(content='帮我绘制一幅鲨鱼在天上飞的图片', id='1e1a56dc-2e17-47e9-ab45-1d6154079cde'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_RSRd2xhwjY6SOmiQv4LkCulc', 'function': {'arguments': '{"query":"A surreal scene of a shark flying in the sky, surrounded by fluffy clouds and a bright blue sky. The shark appears to be gliding smoothly, with sunlight reflecting off its scales, creating a whimsical and dreamlike atmosphere."}', 'name': 'openai_dalle'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 60, 'prompt_tokens': 168, 'total_tokens': 228}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_80a1bad4c7', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-2e105a61-6cef-4716-8b0a-df9629289a95-0', tool_calls=[{'name': 'openai_dalle', 'args': {'query': 'A surreal scene of a shark flying in the sky, surrounded by fluffy clouds and a bright blue sky. The shark appears to be gliding smoothly, with sunlight reflecting off its scales, creating a whimsical and dreamlike atmosphere.'}, 'id': 'call_RSRd2xhwjY6SOmiQv4LkCulc', 'type': 'tool_call'}], usage_metadata={'input_tokens': 168, 'output_tokens': 60, 'total_tokens': 228}), ToolMessage(content='https://dalleproduse.blob.core.windows.net/private/images/a1793f8c-a319-4b41-9c17-0530bdd7b996/generated_00.png?se=2024-08-23T06%3A39%3A10Z&sig=HoH1JnIJHtnxOHQqS2wAHHH%2FduLzQvh0nCN0FJBy7M8%3D&ske=2024-08-29T03%3A57%3A46Z&skoid=09ba021e-c417-441c-b203-c81e5dcd7b7f&sks=b&skt=2024-08-22T03%3A57%3A46Z&sktid=33e01921-4d64-4f8c-a055-5bdaffd5e33d&skv=2020-10-02&sp=r&spr=https&sr=b&sv=2020-10-02', name='openai_dalle', id='eabd6566-1494-4190-b25d-7d52f9a67600', tool_call_id='call_RSRd2xhwjY6SOmiQv4LkCulc'), AIMessage(content='这是您请求的画面:一只鲨鱼在天上飞翔的图片。您可以点击下面的链接查看这幅图。\n\n![鲨鱼在天上飞](https://dalleproduse.blob.core.windows.net/private/images/a1793f8c-a319-4b41-9c17-0530bdd7b996/generated_00.png?se=2024-08-23T06%3A39%3A10Z&sig=HoH1JnIJHtnxOHQqS2wAHHH%2FduLzQvh0nCN0FJBy7M8%3D&ske=2024-08-29T03%3A57%3A46Z&skoid=09ba021e-c417-441c-b203-c81e5dcd7b7f&sks=b&skt=2024-08-22T03%3A57%3A46Z&sktid=33e01921-4d64-4f8c-a055-5bdaffd5e33d&skv=2020-10-02&sp=r&spr=https&sr=b&sv=2020-10-02)', response_metadata={'token_usage': {'completion_tokens': 266, 'prompt_tokens': 462, 'total_tokens': 728}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_80a1bad4c7', 'finish_reason': 'stop', 'logprobs': None}, id='run-728b9bab-383f-4437-9238-6077b185a495-0', usage_metadata={'input_tokens': 462, 'output_tokens': 266, 'total_tokens': 728})]}

    02. LangGraph 其他预构建组件

    除了 create_react_agent() 预构建组件,在 LangGraph 中其实还内置了一些高频使用的 预构建组件,涵盖了 MessagesState、ToolNode、ValidationNode 和 injectedState 等。

    其中 MessagesState 就是我们一直在定义的自定义状态,在 LangGraph 内部已经帮我们封装好了,导入后可以直接使用,如果需要除了消息外的其他信息,可以继承该类进行重写

    # langgrap/graph/message.py -> MessagesState  

    class MessagesState(TypedDict):  

    messages: Annotated[list[AnyMessage], add_messages]  

    ​  

    # 导入示例  

    from langgraph.graph import MessagesState

    而 ToolNode 节点其实就是工具执行节点,该节点会自动执行 数据状态 中最后一条消息中的工具调用信息,其实就是我们上节课所使用的 tool_executor() 函数,输出是一个 ToolMessages 列表,使用技巧也非常简单,实例化该类并传递工具列表即可。

    该类等价于以下函数

    tools_by_name = {tool.name: tool for tool in tools}

    def tool_node(state: dict):

        result = []

        for tool_call in state["messages"][-1].tool_calls:

            tool = tools_by_name[tool_call["name"]]

            observation = tool.invoke(tool_call["args"])

            result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))

    return {"messages": result}

    ValidationNode 这个类用来校验最后一个 AIMessage 中所有工具请求是否正确,通常用于校验 LLM 的结构化输出是否正确,该类在实例化的时候,需要传递 Pydantic模型 作为需要校验的类,使用示例如下

    class SelectNumber(BaseModel):

        a: int

        @validator("a")

        def a_must_be_meaningful(cls, v):

            if v != 37:

                raise ValueError("Only 37 is allowed")

            return v

    builder = MessageGraph()

    llm = ChatAnthropic(model="claude-3-haiku-20240307").bind_tools([SelectNumber])

    builder.add_node("model", llm)

    builder.add_node("validation", ValidationNode([SelectNumber]))

    builder.add_edge(START, "model")

    def should_validate(state: list) -> Literal["validation", "__end__"]:

        if state[-1].tool_calls:

            return "validation"

        return END

    builder.add_conditional_edges("model", should_validate)

    而 InjectedState 其实和我们在 LLMOps 项目中使用的 injector 依赖注入包非常接近,主要用于在 工具 上注入 数据状态,这样在工具中也可以实际获取到 图架构应用 的 数据状态,并且使用 Annotated 装饰的参数不会被视为是工具的参数,LLM 在执行函数调用的过程中,不会生成该参数,使用示例如下

    from typing_extensions import Annotated, TypedDict

    class AgentState(TypedDict):

        messages: List[BaseMessage]

        foo: str

    @tool

    def state_tool(x: int, state: Annotated[dict, InjectedState]) -> str:

        '''Do something with state.'''

        if len(state["messages"]) > 2:

            return state["foo"] + str(x)

        else:

            return "not enough messages"

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐