【LLM-agent】(task2)用llama-index搭建AI Agent

note

  • LlamaIndex 实现 Agent 需要导入 ReActAgentFunction Tool,循环执行:推理、行动、观察、优化推理、重复进行。可以在 arize_phoenix 中看到 agent 的具体提示词,工具被装换成了提示词
  • ReActAgent 使得业务自动向代码转换成为可能,只要有 API 模型就可以调用,很多业务场景都适用,LlamaIndex 提供了一些开源的工具实现,可以到官网查看。
  • 虽然 Agent 可以实现业务功能, 但是一个 Agent 不能完成所有的功能,这也符合软件解耦的设计原则,不同的 Agent 可以完成不同的任务,各司其职,Agent 之间可以进行交互、通信,类似于微服务。

文章目录

一、LlamaIndex中agent的构建

步骤:

  • 定义工具函数(大模型会根据函数的注释来判断使用哪个函数来完成任务)
  • 把工具函数放入FunctionTool对象中,供Agent能够使用
  • LlamaIndex 实现 Agent 需要导入 ReActAgent 和 Function Tool
    • ReActAgent 通过结合推理(Reasoning)和行动(Acting)来创建动态的 LLM Agent 的框架。该方法允许 LLM 模型通过在复杂环境中交替进行推理步骤和行动步骤来更有效地执行任务。ReActAgent 将推理和动作形成了闭环,Agent 可以自己完成给定的任务。

一个典型的 ReActAgent 遵循以下循环:

  • 初始推理:代理首先进行推理步骤,以理解任务、收集相关信息并决定下一步行为。
  • 行动:代理基于其推理采取行动------例如查询API、检索数据或执行命令。
  • 观察:代理观察行动的结果并收集任何新的信息。
  • 优化推理:利用新信息,代理再次进行推理,更新其理解、计划或假设。
  • 重复:代理重复该循环,在推理和行动之间交替,直到达到满意的结论或完成任务。

二、代码实践

python 复制代码
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()
# 初始化变量
base_url = None
chat_model = None
api_key = None

# 使用with语句打开文件,确保文件使用完毕后自动关闭
env_path = "/Users/guomiansheng/Desktop/LLM/llm_app/wow-agent/.env.txt"
with open(env_path, 'r') as file:
    # 逐行读取文件
    for line in file:
        # 移除字符串头尾的空白字符(包括'\n')
        line = line.strip()
        # 检查并解析变量
        if "base_url" in line:
            base_url = line.split('=', 1)[1].strip().strip('"')
        elif "chat_model" in line:
            chat_model = line.split('=', 1)[1].strip().strip('"')
        elif "ZHIPU_API_KEY" in line:
            api_key = line.split('=', 1)[1].strip().strip('"')

# 打印变量以验证
print(f"base_url: {base_url}")
print(f"chat_model: {chat_model}")
print(f"ZHIPU_API_KEY: {api_key}")


from openai import OpenAI
client = OpenAI(
    api_key = api_key,
    base_url = base_url
)
print(client)

def get_completion(prompt):
    response = client.chat.completions.create(
        model="glm-4-flash",  # 填写需要调用的模型名称
        messages=[
            {"role": "user", "content": prompt},
        ],
    )
    return response.choices[0].message.content


# 用llama-index
from openai import OpenAI
from pydantic import Field  # 导入Field,用于Pydantic模型中定义字段的元数据
from llama_index.core.llms import (
    CustomLLM,
    CompletionResponse,
    LLMMetadata,
)
from llama_index.core.embeddings import BaseEmbedding
from llama_index.core.llms.callbacks import llm_completion_callback
from typing import List, Any, Generator


# 定义OurLLM类,继承自CustomLLM基类
class OurLLM(CustomLLM):
    api_key: str = Field(default=api_key)
    base_url: str = Field(default=base_url)
    model_name: str = Field(default=chat_model)
    client: OpenAI = Field(default=None, exclude=True)  # 显式声明 client 字段

    def __init__(self, api_key: str, base_url: str, model_name: str = chat_model, **data: Any):
        super().__init__(**data)
        self.api_key = api_key
        self.base_url = base_url
        self.model_name = model_name
        self.client = OpenAI(api_key=self.api_key, base_url=self.base_url)  # 使用传入的api_key和base_url初始化 client 实例

    @property
    def metadata(self) -> LLMMetadata:
        """Get LLM metadata."""
        return LLMMetadata(
            model_name=self.model_name,
        )

    @llm_completion_callback()
    def complete(self, prompt: str, **kwargs: Any) -> CompletionResponse:
        response = self.client.chat.completions.create(model=self.model_name, messages=[{"role": "user", "content": prompt}])
        if hasattr(response, 'choices') and len(response.choices) > 0:
            response_text = response.choices[0].message.content
            return CompletionResponse(text=response_text)
        else:
            raise Exception(f"Unexpected response format: {response}")

    @llm_completion_callback()
    def stream_complete(
        self, prompt: str, **kwargs: Any
    ) -> Generator[CompletionResponse, None, None]:
        response = self.client.chat.completions.create(
            model=self.model_name,
            messages=[{"role": "user", "content": prompt}],
            stream=True
        )

        try:
            for chunk in response:
                chunk_message = chunk.choices[0].delta
                if not chunk_message.content:
                    continue
                content = chunk_message.content
                yield CompletionResponse(text=content, delta=content)

        except Exception as e:
            raise Exception(f"Unexpected response format: {e}")


llm = OurLLM(api_key=api_key, base_url=base_url, model_name=chat_model)
# print(llm)
# 测试模型是否能正常回答
response = llm.stream_complete("你是谁?")
for chunk in response:
    print(chunk, end="", flush=True)


import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool


def multiply(a: float, b: float) -> float:
    """Multiply two numbers and returns the product"""
    return a * b


def add(a: float, b: float) -> float:
    """Add two numbers and returns the sum"""
    return a + b


# 定义个类似天气预报的function
def get_weather(city: str) -> int:
    """
    Gets the weather temperature of a specified city.

    Args:
    city (str): The name or abbreviation of the city.

    Returns:
    int: The temperature of the city. Returns 20 for 'NY' (New York),
         30 for 'BJ' (Beijing), and -1 for unknown cities.
    """

    # Convert the input city to uppercase to handle case-insensitive comparisons
    city = city.upper()

    # Check if the city is New York ('NY')
    if city == "NY":
        return 20  # Return 20°C for New York

    # Check if the city is Beijing ('BJ')
    elif city == "BJ":
        return 30  # Return 30°C for Beijing

    # If the city is neither 'NY' nor 'BJ', return -1 to indicate unknown city
    else:
        return -1



def main():

    multiply_tool = FunctionTool.from_defaults(fn=multiply)
    add_tool = FunctionTool.from_defaults(fn=add)

    # 创建ReActAgent实例
    agent = ReActAgent.from_tools([multiply_tool, add_tool], llm=llm, verbose=True)
    response = agent.chat("20+(2*4)等于多少?使用工具计算每一步")
    print(f"第一个agent的结果: ", response, "\n")

    weather_tool = FunctionTool.from_defaults(fn=get_weather)
    agent = ReActAgent.from_tools([multiply_tool, add_tool, weather_tool], llm=llm, verbose=True)
    response = agent.chat("纽约天气怎么样?")
    print(f"第二个agent的结果: ", response)


if __name__ == "__main__":
    main()

输出的结果:

(1)计算的例子:

  • 将提问中的计算步骤分别利用了我们自定义的函数 add 和 multiply,比task1只能控制prompt情况更加自由了

(2)天气预报的例子

  • 可以在 arize_phoenix 中看到 agent 的具体提示词,工具被装换成了提示词
  • ReActAgent 使得业务自动向代码转换成为可能,只要有 API 模型就可以调用,很多业务场景都适用,LlamaIndex 提供了一些开源的工具实现,可以到官网查看。
  • 虽然 Agent 可以实现业务功能, 但是一个 Agent 不能完成所有的功能,这也符合软件解耦的设计原则,不同的 Agent 可以完成不同的任务,各司其职,Agent 之间可以进行交互、通信,类似于微服务。

Reference

[1] 官方文档:https://docs.cloud.llamaindex.ai/

[2] https://github.com/datawhalechina/wow-agent

[3] https://www.datawhale.cn/learn/summary/86

相关推荐
程序猿000001号4 小时前
DeepSeek本地部署详细指南
大模型·本地部署·deepseek
大模型之路11 小时前
DeepSeek Janus-Pro:多模态AI模型的突破与创新
llm·强化学习·deepseek·deepseekr1
产品媛Gloria Deng12 小时前
分享| RL-GPT 框架通过慢agent和快agent结合提高AI解决复杂任务的能力-Arxiv
人工智能·gpt·ai·agent·ai智能体
songqq271 天前
【快速上手】阿里云百炼大模型
阿里云·大模型
两棵雪松2 天前
对比使用DeepSeek与文新一言,了解DeepSeek的关键技术论文
大模型
x-cmd2 天前
[250125] DeepSeek 发布开源大模型 R1,性能比肩 OpenAI o1 | 希捷推出高达 36TB 的硬盘
ai·开源·llm·openai·存储·硬件·deepseek
大模型之路2 天前
深度解析 DeepSeek R1:强化学习与知识蒸馏的协同力量
人工智能·llm·deepseek·deepseek-v3·deepseek-r1
程序设计实验室3 天前
开发者新选择:用DeepSeek实现Cursor级智能编程的免费方案
llm