关注公众号:闲人张,了解更多内容:
本文主要介绍在AutoGen中如何使用ReAct策略及RAG,如何更好的解决问题及使用本地知识库。
ReAct
ReAct(Reasoning and Acting) 是一种基于提示的范式,可以在使用LLM来进行一系列分析任务的自动执行。注意包含:Thought、Action、Observation、Final Answer。
关于ReAct更多的内容可以查看这篇论文:arxiv.org/abs/2210.03...
下面我们来看如何在AutoGen中使用ReAct策略:
定义ReAct策略Prompts
ini
ReAct_prompt = """尽可能回答以下问题。你可以使用提供的工具。请使用以下格式:
问题:你必须回答的输入问题
思考:你应该始终考虑该做什么
行动:要采取的行动
行动输入:对行动的输入
观察:行动的结果
...(这个过程可以多次重复)
思考:我现在知道最终答案了
最终答案:对原始输入问题的最终回答
开始!
问题:{input}
"""
定义一个方法转换ReAct策略的prompt,传入问题:
python
def react_prompt_message(sender, recipient, context):
return ReAct_prompt.format(input=context["question"])
定义一个调用工具
定义一个获取医生信息的方法,返回医生名字、价格和级别;这里使用另外一种方式来注册工具,使用function_map
来注册工具,需要定义工具的schema:
python
def get_doctor_info(subject: str) -> str:
if subject == "骨科":
return str([{"name": "李四","price": 10,"level": "专家"}, {"name": "赵六","price": 15,"level": "主任"}])
if subject == "眼科":
return str([{"name": "张三","price": 10,"level": "专家"}, {"name": "李四","price": 15,"level": "主任"}])
# 定义schema
def get_doctor_info_tool():
# Define the function schema based on the tool's args_schema
function_schema = {
"name": "get_doctor_info",
"description": "获取医生信息",
"parameters": {
"type": "object",
"properties": {
'subject': {
'type': 'string',
'description': '科室',
}
},
"required": ['query'],
},
}
return function_schema
function_schema 遵循openai规范,可参考:platform.openai.com/docs/api-re...
定义Agent并注册工具
ini
user_proxy = autogen.UserProxyAgent(
name="user_proxy",
is_termination_msg=lambda x: x.get("content", "") and x.get("content", "").rstrip().endswith("TERMINATE"),
human_input_mode="NEVER",
max_consecutive_auto_reply=10,
code_execution_config={
"use_docker": False,
},
)
user_proxy.register_function(
function_map={
"get_doctor_info": get_doctor_info
}
)
assistant = autogen.AssistantAgent(
name="Assistant",
system_message="请使用提供的工具回答问题,当任务结束时回复:TERMINATE",
llm_config={"config_list": config.config_list,
"functions": [
get_doctor_info_tool(),
]},
)
这里也同样可以使用上一篇提到的两种方式来注册工具。
执行ReAct策略
ini
user_proxy.initiate_chat(assistant,message=react_prompt_message,question="我腿部骨折需要看医生")
可以看到下面的输出,通过输出内容更易了解ReAct策略的运行过程和用处:
markdown
user_proxy (to Assistant):
尽可能回答以下问题。你可以使用提供的工具。请使用以下格式:
...
开始!
问题:我腿部骨折需要看医生
--------------------------------------------------------------------------------
Assistant (to user_proxy):
思考:需要找出处理骨折的医生,一般来说,这是骨科医生的职责。
行动:用提供的工具来找出医生信息。
行动输入:{'subject': '骨科'}
***** Suggested function call: get_doctor_info *****
Arguments:
{
"subject": "骨科"
}
****************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION get_doctor_info...
user_proxy (to Assistant):
***** Response from calling function (get_doctor_info) *****
[{'name': '李四', 'price': 10, 'level': '专家'}, {'name': '赵六', 'price': 15, 'level': '主任'}]
************************************************************
--------------------------------------------------------------------------------
Assistant (to user_proxy):
观察:找到了两位骨科医生,一个是专家级别的李四,花费是10,另一个是主任级别的赵六,花费是15。
思考:我现在知道最终答案了。
最终答案:你可以选择李四医生或赵六医生进行诊疗,李四是骨科的专家,费用为10,赵六是骨科主任,费用为15。
TERMINATE
--------------------------------------------------------------------------------
Process finished with exit code 0
另外,Teachability
使用向量库可以使Agent记住用户所给予的信息,从而可以更轻松地回答类似的问题。类似于给了Agent一个备忘录,当使用teachability.add_to_agent(agent)
时,再次提问,Agent将会直接给出答案。
RAG
RAG(Retrieval Augmented Generation),检索增强将语言模型与外部知识检索相结合,以提高生成响应的质量和相关性。在AutoGen中提供了RetrieveUserProxyAgent
和RetrieveUserProxyAgent
支持RAG。
构建embedding_function与文本拆分器
RAG数据准备大致分为四个阶段:数据提取、文本分割、向量化、数据入库
ini
openai_embedding_function = embedding_functions.OpenAIEmbeddingFunction(api_key="",api_base="",api_type="",api_version="",model_name="text-embedding-ada-002")
swift
text_splitter = RecursiveCharacterTextSplitter(separators=["\n\n", "\n", "\r", "\t"])
构建智能体
lua
assistant = RetrieveAssistantAgent(
name="assistant",
system_message="You are a helpful assistant.",
llm_config={
"timeout": 600,
"cache_seed": 42,
"config_list": config.config_list,
},
)
ragproxyagent = RetrieveUserProxyAgent(
name="ragproxyagent",
human_input_mode="NEVER",
max_consecutive_auto_reply=3,
retrieve_config={
"task": "qa",
"docs_path": [
"https://xxxx.md",
os.path.join(os.path.abspath(""), ".", "file", "info.md"),
],
"chunk_token_size": 2000,
"model": config.config_list[0]["model"],
"client": chromadb.PersistentClient(path="/tmp/chromadb"),
"embedding_model": "text-embedding-ada-002",
"must_break_at_empty_line": False,
"get_or_create": True,
"embedding_function": openai_embedding_function,
"custom_text_split_function": text_splitter.split_text,
"collection_name": "my-test"
},
code_execution_config=False,
)
retrieve_config(dict 或 None):检索代理的配置,参数介绍:
task
(可选,str) - 检索聊天的任务。可能的值有"code", "qa" 和 "default"。不同任务的系统提示将不同。默认值是default
,它支持代码和问答。client
(可选,chromadb.Client) - chromadb 客户端。如果未提供此键,将使用默认客户端chromadb.Client()
。如果您想使用其他向量数据库,请扩展此类并重写retrieve_docs
函数。docs_path
(可选,Union[str, List[str]]) - 文档目录的路径。它还可以是单个文件的路径,单个文件的网址或一系列目录、文件和网址的路径。默认为 None,仅在已创建集合的情况下有效。extra_docs
(可选,bool) - 当为 true 时,允许添加具有唯一 ID 的文档而不会覆盖现有的;当为 false 时,它使用默认 ID 替换现有文档,存在覆盖集合的风险。当设置为 true 时,它允许系统为新的文档片段分配唯一的 ID,从 "length+i" 开始,防止替换现有文档并便于向集合添加更多内容。默认情况下,"extra_docs" 设置为 false,从零开始文档 ID。collection_name
(可选,str) - 集合的名称。如果未提供此键,将使用默认名称autogen-docs
。model
(可选,str) - 用于检索聊天的模型。如果未提供此键,将使用默认模型gpt-4
。chunk_token_size
(可选,int) - 检索聊天的块令牌大小。如果未提供此键,将使用默认大小max_tokens * 0.4
。context_max_tokens
(可选,int) - 检索聊天的上下文最大令牌大小。如果未提供此键,将使用默认大小max_tokens * 0.8
。chunk_mode
(可选,str) - 检索聊天的块模式。可能的值是 "multi_lines" 和 "one_line"。如果未提供此键,将使用默认模式multi_lines
。must_break_at_empty_line
(可选,bool) - 如果为 True,则块将只在空行处分隔。 默认为 True。如果 chunk_mode 为 "one_line",此参数将被忽略。embedding_model
(可选,str) - 用于检索聊天的嵌入模型。如果未提供此键,将使用默认模型all-MiniLM-L6-v2
。推荐使用all-mpnet-base-v2
。embedding_function
(可选,Callable) - 创建向量数据库的嵌入函数。默认值为 None,将使用给定的embedding_model
的 SentenceTransformer。按照https://docs.trychroma.com/embeddings
中的示例操作。customized_prompt
(可选,str) - 检索聊天的自定义提示。默认值为 None。customized_answer_prefix
(可选,str) - 检索聊天的自定义答案前缀。默认为空字符串。如果不为空字符串并且答案中没有包含 customized_answer_prefix,将触发Update Context
。update_context
(可选,bool) - 如果为 False,将不会对互动检索应用Update Context
。默认为 True。get_or_create
(可选,bool) - 如果为 True,将为检索聊天创建/返回一个集合。这与 chromadb 中使用的相同。默认值为 False。如果集合已存在且get_or_create 为 False,则会引发 ValueError。如果 docs_path 为 None,则会设置为 True。custom_token_count_function
(可选,Callable) - 自定义函数,用于计算字符串中的令牌数量。函数应该接受 (text:str, model:str) 作为输入并返回令牌数量(int)。retrieve_config["model"] 将被传递到函数中。默认为autogen.token_count_utils.count_token 使用 tiktokencustom_text_split_function
(可选,Callable) - 自定义函数,用于将字符串分割成字符串列表。默认值为 None,将使用autogen.retrieve_utils.split_text_to_chunks
中的默认函数。custom_text_types
(可选,List[str]) - 要处理的文件类型列表。默认值为autogen.retrieve_utils.TEXT_FORMATS
。这仅适用于docs_path
下目录中的文件。明确包括的文件和网址将进行分块,无论其类型如何。recursive
(可选,bool) - 是否在 docs_path 中递归搜索文档。默认为 True。
执行问答
ini
ragproxyagent.initiate_chat(assistant, message=ragproxyagent.message_generator, problem='总结下文档信息,介绍下企业情况', search_string="code", n_results=2)
输出如下:
vbnet
Trying to create collection.
doc_ids: [['doc_1', 'doc_2']]
Adding doc_id doc_1 to context.
Adding doc_id doc_2 to context.
...
User's question is: 总结下文档信息,介绍下企业情况
...
assistant (to ragproxyagent):
这是一个由Hugging Face组织的项目,旨在开发最佳的句子嵌入模型...。文档无法提供任何关于企业的情况。
可以看到在AutoGen中RetrieveUserProxyAgent首先自动处理文档,拆分、分块并将它们存储在矢量数据库中。然后,对于给定的用户输入,它会检索相关块作为上下文并将其发送到RetrieveAssistantAgent,RetrieveAssistantAgent使用 LLM 生成代码或文本来回答问题。Agent交谈,直到他们找到满意的答案。
此外,AutoGen中也添加了QdrantRetrieveUserProxyAgent使用 qdrant 作为向量数据库; 集成了 UNSTRUCTURED 来支持许多非结构化文档。关于 RAG的内容,Autogen 仍然在快速迭代中。
解锁更多精彩关注公众号:闲人张