自然语言创建 agent 就是通过一个上帝模式的 agent 通过对话帮你创建另一个某个领域的 agent。
有点像 python 中一个方法定义了另一个方法的感觉。
接下来就揭秘一下如何定义这个上帝模式的 agent
准备工作
安装以下包
%pip install llama-index-agent-openai
%pip install llama-index-embeddings-openai
%pip install llama-index-llms-openai
接下来在你的环境中设置 key
import os
os.environ["OPENAI_API_KEY"] = "sk-..."
初始化工作
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI
from llama_index.core import Settings
llm = OpenAI(model="gpt-4")
Settings.llm = llm # 配置全局使用的模型
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small") # 配置全局使用的向量模型
准备工作做完,接下来就是正式的编码了
定义子 agent 使用的工具
你希望子 agent 是某个垂直领域的问答工具,比如我想建一个食品饮料行业相关的问答工具,
那就需要为 agent 提供这方面的知识。知识可以来自 pdf,可以来自网页,可以来自你自家的数据库。这里我从网上下载了食品饮料行业的研究报告放在了 ./data 目录下。
加载 pdf
from llama_index.core import SimpleDirectoryReader
subject_docs = {}
def load_data():
for subject in subjects:
docs = SimpleDirectoryReader(
input_dir=f"./data/{subject}/", recursive=True,
file_extractor={'.pdf': PyMuPDFReader()},
).load_data() # 读取 pdf 到内存
node_parser = TokenTextSplitter(
chunk_size=512,
chunk_overlap=100,
separator="\n\n",
backup_separators=["\n", " 。", "!", "?", ";", "?", "!"],
) # 对文档内容进行切分,每块最多 512 token,前后最多可以有 100 token 重叠
nodes = node_parser.get_nodes_from_documents(docs)
subject_docs[subject] = nodes
load_data()
创建查询工具
from llama_index.core import VectorStoreIndex
from llama_index.agent.openai import OpenAIAgent
from llama_index.core.tools import QueryEngineTool, ToolMetadata
from llama_index.core import VectorStoreIndex
tool_dict = {}
def gen_tool_dict():
for subject, nodes in subject_docs.items():
vector_index = VectorStoreIndex(nodes)
vector_query_engine = vector_index.as_query_engine(llm=llm)
vector_tool = QueryEngineTool(
query_engine=vector_query_engine,
metadata=ToolMetadata(
name=subject,
description=f"Useful for questions related to {subject}".replace('_', ' ')
)
)
tool_dict[subject] = vector_tool
gen_tool_dict()
创建查询工具的检索工具
这是给最顶层的 agent 用的,他会根据你的 prompt ,创建 agent 是否需要工具,如果需要工具通过这个检索工具来检索出符合要求的工具。
有点绕,直接看代码吧
# define an "object" index and retriever over these tools
from llama_index.core import VectorStoreIndex
from llama_index.core.objects import ObjectIndex
tool_index = ObjectIndex.from_objects(
list(tool_dict.values()),
index_cls=VectorStoreIndex,
)
tool_retriever = tool_index.as_retriever(similarity_top_k=1)
Agent 元数据生成工具
所谓元数据就是我们在定义 agent 时候需要定义的 prompt,tools 等,现在这些定义的工作需要交给顶层的 agent,我们需要把这些步骤封装成工具给顶层的 agent 去调用。
from llama_index.core.llms import ChatMessage
from llama_index.core import ChatPromptTemplate
from typing import List
gen_sys_prompt_messages = [
ChatMessage(
role="system",
content="你擅长为别的机器人生成 system prompt。",
),
ChatMessage(
role="user",
content=gen_sys_prompt_str
)
]
def create_system_prompt(task):
fmt_message = gen_sys_prompt_str.format(task=task)
response = llm.chat(fmt_message)
return response.message.content
def get_tools(task):
tool_retriever = define_tool_retriever()
subset_tools = tool_retriever.retrieve(task)
return [t.metadata.name for t in subset_tools]
def create_agent(system_prompt, tool_names):
try:
print("=====================", system_prompt)
input_tools = [tool_dict[name] for name in tool_names]
tag_agent = OpenAIAgent.from_tools(
input_tools, llm=llm, verbose=True,
system_prompt=json.loads(system_prompt)["messages"]
)
agent_cache['agent'] = tag_agent
return_msg = "Agent 创建成功"
except:
return_msg = "创建失败"
return return_msg
包装成工具
from llama_index.core.tools import FunctionTool
system_prompt_tool = FunctionTool.from_defaults(fn=create_system_prompt)
get_tools_tool = FunctionTool.from_defaults(fn=get_tools)
create_agent_tool = FunctionTool.from_defaults(fn=create_agent)
最后定义上帝 agent
GPT_BUILDER_SYS_STR = """
你需要根据用户指定的任务创建一个 agent,你通常需要按照以下步骤:
1.使用 system prompt tool 为 agent 创建 system prompt
2.使用 get tools tool 获取与任务相关的工具
3.使用 create agent tool 创建 agent
"""
prefix_msgs = [ChatMessage(role='system', content=GPT_BUILDER_SYS_STR)]
builder_agent = OpenAIAgent.from_tools(
tools=[system_prompt_tool, get_tools_tool, create_agent_tool],
prefix_messages=prefix_msgs,
verbose=True
)
试一下
if __name__ == "__main__":
res = builder_agent.query("我想要一个可以回答关于食品饮料问题的机器人")
print("最终结果:", res)
if agent_cache:
agent = agent_cache['agent']
while 1:
query = input("请输入问题:")
if query == "exit":
break
res = agent.query(query)
print(res)
输出结果无法打印了,因为调试过程欠费了
下次补上吧