从零开发一个Agent

#从零开发一个Agent [TOC]

AgentRAG概述

检索向量后,判断文本块是否包含问题答案 如包含则进行回答 如不包含则重新进入向量检索,匹配+1块 最大循环次数15

核心代码

从向量数据库匹配文档,并让大模型反思 每次循环增加一个文档块,直到能回答问题 文档块数量超过15个仍无法回答问题则放弃

代码示例

首先安装相关依赖

bash 复制代码
! pip install -qU langchain-openai langchain langchain_community langchainhub
! pip install chromadb==0.5.3

导入相关包,把上次传统的RAG代码给粘贴过来。

python 复制代码
from langchain import hub as langchain_hub
from langchain.schema import StrOutputParser
from langchain_openai import ChatOpenAI
from langchain.schema.runnable import RunnablePassthrough
from langchain.text_splitter import MarkdownHeaderTextSplitter
from langchain_openai import OpenAIEmbeddings
import os
#from langchain_chroma import Chroma
from langchain_community.vectorstores.chroma import Chroma
from langchain_core.prompts import PromptTemplate
from string import Template
import uuid
python 复制代码
# 读取 ./data/data.md 文件作为运维知识库
file_path = os.path.join('data', 'data.md')
with open(file_path, 'r', encoding='utf-8') as file:
    docs_string = file.read()

# Split the document into chunks base on markdown headers.
headers_to_split_on = [
    ("#", "Header 1"),
    ("##", "Header 2"),
    ("###", "Header 3"),
]
text_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
splits = text_splitter.split_text(docs_string)
print("Length of splits: " + str(len(splits)))
print(splits)

这里输出了一下分片,接下来我们将运维知识库的每一块文本向量化(Embedding)

python 复制代码
# 保存到随机目录里
random_directory = "./" + str(uuid.uuid4())
embedding = OpenAIEmbeddings(
    model="text-embedding-3-small",
    openai_api_key="你的api key"
)
vectorstore = Chroma.from_documents(documents=splits, embedding=embedding, persist_directory=random_directory)
# vectorstore.persist()

接着我们使用代码实现了一个传统的检索增强生成(RAG)流程,其中通过向量数据库检索相关文档、使用模板生成提示、并利用 GPT-4 模型生成答案,最后输出简洁回答。

python 复制代码
# 传统 RAG 流程
retriever = vectorstore.as_retriever()
# 提示语模板
template = """使用以下上下文来回答最后的问题。
如果你不知道答案,就说不知道,不要试图编造答案。
最多使用三句话,并尽可能简洁地回答。
在答案的最后一定要说"谢谢询问!"。

{context}

Question: {question}

Helpful Answer:"""
custom_rag_prompt = PromptTemplate.from_template(template)

def format_docs(docs):
    print("匹配到的运维知识库片段:\n", "\n\n".join(doc.page_content for doc in docs))
    return "\n\n".join(doc.page_content for doc in docs)

llm = ChatOpenAI(model="gpt-4o",api_key="你的key")
rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | custom_rag_prompt
    | llm
    | StrOutputParser()
)


# 传统 RAG 无法回答的问题
res = rag_chain.invoke("谁管的系统最多?")
print("\n\nLLM 回答:", res)

接着我们实现了一个基于 Agent RAG 流程的问答系统,通过逐步增加检索的文档数量来判断是否足够回答问题,最终生成答案。如果上下文不足以回答问题,系统会增加更多文档并重新检查,直到能够回答问题为止。

python 复制代码
# Agent RAG 流程

# 文本相似性检索
def search_docs(query, k=1):
    results = vectorstore.similarity_search_with_score(
        query,
        k=k,
    )
    return "\n\n".join(doc.page_content for doc, score in results)

user_query = "谁管的系统最多?"

check_can_answer_system_prompt = """
根据上下文识别是否能够回答问题,如果不能,则返回 JSON 字符串 "{"can_answer": false}",如果可以则返回 "{"can_answer": true}"。
上下文:\n $context
问题:$question

"""
llm = ChatOpenAI(model="gpt-4o",api_key="你的API Key")
k = 1
docs = ""
while True:
    # 通过检索找到相关文档,每次循环增加一个检索文档数量,最大 15 个文档块
    print("第", k, "次检索")
    if k > 15:
        break
    docs = search_docs(user_query, k)
    print("匹配到的文档块: ", docs)
    template = Template(check_can_answer_system_prompt)
    filled_prompt = template.substitute(question=user_query, context=docs)
    # 检查上下文是否足够回答问题
    messages = [
        (
            "system",
            filled_prompt,
        ),
        ("human", "开始检查上下文是否足够回答问题。"),
    ]
    llm_message = llm.invoke(messages)
    content = llm_message.content
    print("\nLLM Res: ", content, "\n")
    if content == '{"can_answer": true}':
        break
    else:
        k += 1

print("匹配到能够回答问题的知识库,开始进行回答\n")

# 最终推理
final_system_prompt = """
您是问答任务的助手,使用检索到的上下文来回答用户提出的问题。如果你不知道答案,就说不知道。最多使用三句话并保持答案简洁。
"""

final_messages = [
    (
        "system",
        final_system_prompt,
    ),
    ("human", "上下文:\n"+ docs +"\n问题:" + user_query),
]
llm_message = llm.invoke(final_messages)
content = llm_message.content
print("\nLLM Final Res: ", content, "\n")

在经历第9次后我们发现它能够回答我们的问题了。

改进方向

判断文本块大小,并使用切片策略,避免上下文超限 改进向量搜索策略,例如通过增加offset参数过滤已验证无法回答问题的文本块 判断能否回答问题环节使用JSONMode获得更稳定的结构化输出

相关推荐
未来智慧谷8 小时前
OpenAI押注的NEO人形机器人:技术拆解与消费级人形机器人落地启示
机器人·openai·人形机器人neo
Mintopia9 小时前
🤖 通用人工智能(AGI)离 Web 应用还有多远?
前端·javascript·aigc
墨风如雪19 小时前
360 FG-CLIP2:让AI拥有“火眼金睛”,刷新全球图文理解上限
aigc
Moment1 天前
Cursor 2.0 支持模型并发,我用国产 RWKV 模型实现了一模一样的效果 🤩🤩🤩
前端·后端·openai
用户5191495848451 天前
原型污染攻击工具揭秘:Prototype Pollution Gadgets Finder
人工智能·aigc
mortimer1 天前
视频翻译中的最后一公里:口型匹配为何如此难
openai·音视频开发·视频编码
安思派Anspire1 天前
构建一个自主深度思考的RAG管道以解决复杂查询--通过网络搜索扩充知识(6)
aigc·openai·agent
ZEGO即构开发者1 天前
【ZEGO即构开发者日报】Soul AI Lab开源播客语音合成模型;腾讯混元推出国内首个交互式AI播客;ChatGPT Go向用户免费开放一年......
人工智能·aigc·语音识别·实时音视频
新智元1 天前
他发明了价值万亿的 AGI,如今穷困潦倒
人工智能·openai
Baihai_IDP1 天前
怎样为你的 RAG 应用选择合适的嵌入模型?
人工智能·llm·aigc