0


AI大模型源码解析|打造你的专属GitHub智能答疑助手!

嗨!我是小谷,大家好久不见~

前段时间网上冲浪,发现一个 大模型在垂类场景的典型应用 ,定位是 Github 智能答疑助手,功能包含优质仓库推荐、代码片段解读、提 issue 、查 issue … 对于 Ant Design 这种前端组件库,甚至可以通过一张原型图,给出界面上包含哪些 Ant Design 的原子组件!

亲自体验了一番,感觉确实很方便,发现源码也已经在 Github 上开源了,整体实现涉及 Prompt 调优、向量化知识库构建 以及 Langchain 工具链集成,每个环节都有很多学习之处,那就让我们一起通过源码看看大模型部分的实现细节吧

PeterCat 简介

在这里插入图片描述
如官网介绍,PeterCat 是专为社区维护者和开发者打造的智能答疑机器人解决方案。

支持用户在平台中通过对话模式快速搭建一个 Github 仓库的智能答疑机器人,内置 提 issue、查 issue、回 issue、Discussion 回复、PR Summary、Code Review、项目信息查询 基础能力,也可以通过自托管部署方案和一体化应用 SDK 集成至项目仓库。

在这里插入图片描述

目前在 PeterCat 平台中,已有 9 个前端方向典型应用的智能答疑机器人。

Ant Design 为例,我们不仅可以通过 Ant Design 答疑小助手来了解如何快速上手 Ant Design 组件库的使用,还能通过一张原型图快速判断出通过 Ant Design 的哪些组件可以实现,甚至连图表和文字都能准确识别,大模型对于图片中内容的解析真的有超乎预期
原型稿识别结果在这里插入图片描述在这里插入图片描述
接下来,就让我们一起来看看 PeterCat 是如何做到的吧!

源码解读

业界通用方案

所谓大模型垂类应用场景,指的是大模型在特定领域的应用,主要解决的是诸如 GPT、通义千问 等通用大模型在特定领域由于缺乏领域知识而表现欠佳的问题。这类场景通常需要喂给大模型大量的数据作为知识库进行辅助决策。

关于大模型在垂类场景的应用,常见的执行 SOP 包含:

向量化知识库构建 -> (大模型微调) -> 用户 prompt 输入 -> 向量化关键词检索 -> 查询结果精排 -> 大模型 prompt 生成 -> 大模型意图识别 -> 结果生成

在这里插入图片描述
如果是自建大模型,还可以通过大模型微调来让意图识别质量更高。

可以发现,无论在知识库构建阶段,还是关键词检索阶段,向量化 都是被反复提及的概念。

所谓向量化,其实指的是将大规模的数据或文本转化为向量的表示方式。经过向量化处理的数据,能够更好地表达数据之间的关系和相似性,提高模型的训练和预测效果

而从向量化关键词检索到大模型 prompt 生成的过程,就是我们常说的 RAG ,目的是为了最终喂给大模型的 Prompt 质量更高,也就是大家常说的如何更好的向大模型提问。

在上述的 SOP 执行基础上,借助 Langchain 将 Embedding、Prompt 生成、工具链式调用进行集成,就大致可以完成大模型在垂类领域的完整调用了。

在这里插入图片描述
如果把大模型比作是人类的大脑,那么 Langchain 可以类比为人类的四肢和躯干,大模型只用专注于模型预测的核心工作,至于工具调用、上下文记忆、多轮对话等工作交给 Langchain 进行统筹管理即可。

PeterCat 源码

有了上述一些基础知识,我们来看下 PeterCat 在大模型相关模块的实现细节:

PeterCat 大模型相关的代码主要集中在 server/agent 目录下,整体包含:

bot 构建、llm 调用、prompt 设定和 tools 工具预置四大能力,
最终以 base.py 和 qa_chat.py 文件作为 Langchain 处理用户输入以及大模型结果输出的中枢。

而向量化知识库的构建,以及 RAG 检索生成,集中在 petercat_utils 目录下实现,最终通过 server/routers/rag.py 进行调用。

Agent 工作流

按照 PeterCat 官方文档的介绍,当用户在 PeterCat 平台中输入了一个 Github 仓库地址或名称时,创建智能答疑机器人的整个 Agent 工作流为:

使用创建工具,生成该仓库答疑机器人的各项配置(Prompt,、名字、 头像、开场白、引导语、工具集……),同时触发 Issue 和 Markdown 的入库任务。

这些任务会拆分为多个子任务,将该仓库的所有已解决 issue 、高票回复以及所有 Markdown 文件内容经过 load -> split -> embed -> store 的加工过程进行知识库构建,作为机器人的回复知识依据。
在这里插入图片描述

RAG

PeterCat 服务端,采用 FastAPI 框架开发,使用了 supabase 作为数据存储方案。

为了在 RAG 检索生成时比对效率更高,机器人关联的 Github 仓库中所有文档都是通过 Embedding 处理后分类存入数据库中。
用户输入的 query 也会经过 Embedding 化后,与 supabase 中存储的知识进行匹配,再返回匹配结果。

这个过程就包含了前文说的 load -> split -> embed -> store

  1. defsupabase_embedding(documents,**kwargs: Any):from langchain_text_splitters import CharacterTextSplitter
  2. try:
  3. text_splitter = CharacterTextSplitter(
  4. chunk_size=CHUNK_SIZE, chunk_overlap=CHUNK_OVERLAP
  5. )
  6. docs = text_splitter.split_documents(documents)
  7. embeddings = OpenAIEmbeddings()
  8. vector_store = SupabaseVectorStore.from_documents(
  9. docs,
  10. embeddings,
  11. client=get_client(),
  12. table_name=TABLE_NAME,
  13. query_name=QUERY_NAME,
  14. chunk_size=CHUNK_SIZE,**kwargs,)return vector_store
  15. except Exception as e:print(e)returnNone
  1. defadd_knowledge_by_doc(config: RAGGitDocConfig):
  2. loader = init_github_file_loader(config)
  3. documents = loader.load()
  4. supabase = get_client()
  5. is_doc_added_query =(
  6. supabase.table(TABLE_NAME).select("id, repo_name, commit_id, file_path, bot_id").eq("repo_name", config.repo_name).eq("commit_id", loader.commit_id).eq("file_path", config.file_path).eq("bot_id", config.bot_id).execute())ifnot is_doc_added_query.data:
  7. is_doc_equal_query =(
  8. supabase.table(TABLE_NAME).select("*").eq("file_sha", loader.file_sha)).execute()ifnot is_doc_equal_query.data:# If there is no file with the same file_sha, perform embedding.
  9. store = supabase_embedding(
  10. documents,
  11. repo_name=config.repo_name,
  12. commit_id=loader.commit_id,
  13. file_sha=loader.file_sha,
  14. file_path=config.file_path,
  15. bot_id=config.bot_id,)return store
  16. else:
  17. new_commit_list =[{**{k: v for k, v in item.items()if k !="id"},"repo_name": config.repo_name,"commit_id": loader.commit_id,"file_path": config.file_path,"bot_id": config.bot_id,}for item in is_doc_equal_query.data
  18. ]
  19. insert_result = supabase.table(TABLE_NAME).insert(new_commit_list).execute()return insert_result
  20. else:returnTrue
  1. defsearch_knowledge(
  2. query:str,
  3. bot_id:str,
  4. meta_filter: Dict[str, Any]={},):
  5. retriever = init_retriever({"filter":{"metadata": meta_filter,"bot_id": bot_id}})
  6. docs = retriever.invoke(query)
  7. documents_as_dicts =[convert_document_to_dict(doc)for doc in docs]
  8. json_output = json.dumps(documents_as_dicts, ensure_ascii=False)return json_output
LLM 调用

PeterCat 内置了 OpenaiGemini 两大基座模型。作为智能答疑的核心,支持对模型对应回答随机性的微调。

  1. @register_llm_client("openai")classOpenAIClient(BaseLLMClient):
  2. _client: ChatOpenAI
  3. def__init__(
  4. self,
  5. temperature: Optional[int]=0.2,
  6. max_tokens: Optional[int]=1500,
  7. streaming: Optional[bool]=False,
  8. api_key: Optional[str]= OPEN_API_KEY,):
  9. self._client = ChatOpenAI(
  10. model_name="gpt-4o",
  11. temperature=temperature,
  12. streaming=streaming,
  13. max_tokens=max_tokens,
  14. openai_api_key=api_key,
  15. stream_usage=True,)defget_client(self):return self._client
  16. defget_tools(self, tools: List[Any]):return[convert_to_openai_tool(tool)for tool in tools]defparse_content(self, content: List[MessageContent]):return content
Prompt 设定

Prompt 作为影响大模型回复质量的重要依据,让人忍不住夸赞的是,PeterCat 的预置 Prompt 写的真的是非常专业!

这里放一段创建/编辑智能答疑机器人的 prompt 供大家阅读,不仅清晰的描述了向大模型提问的诉求,还向 Langchain 抛出了使用什么工具来完成工程链路的工作( create_bot tool、 edit_bot tool)。

  1. from typing import Optional
  2. CREATE_PROMPT ="""
  3. ## Role:
  4. You are a GitHub Answering Bot Creation Assistant. You specialize in creating a Q&A bot based on the information of a GitHub repository provided by the user.
  5. ## Skills:
  6. Skill 1: Retrieve GitHub Repository Name
  7. - Guide users to provide their GitHub repository name or URL.
  8. - Extract the GitHub repository name from the provided GitHub URL
  9. Skill 2: Create a Q&A Bot
  10. - Use the create_bot tool to create a bot based on the GitHub repository name provided by the user.
  11. - The uid of the current user is {user_id}
  12. Skill 3: Modify Bot Configuration
  13. - Utilize the edit_bot tool to modify the bot's configuration information based on the user's description.
  14. - Always use the created bot's ID as the id of the bot being edited and the user's ID as the uid.
  15. - If the user wishes to change the avatar, ask user to provide the URL of the new avatar.
  16. ## Limitations:
  17. - Can only create a Q&A bot or update the configuration of the bot based on the GitHub repository information provided by the user.
  18. - During the process of creating a Q&A bot, if any issues or errors are encountered, you may provide related advice or solutions, but must not directly modify the user's GitHub repository.
  19. - When modifying the bot's configuration information, you must adhere to the user's suggestions and requirements and not make changes without permission.
  20. - Whenever you encounter a 401 or Unauthorized error that seems to be an authentication failure, please inform the user in the language they are using to converse with you. For example:
  21. If user is conversing with you in Chinese:
  22. “您必须先使用 GitHub 登录 Petercat 才能使用此功能。[登录地址](https://api.petercat.ai/api/auth/login)
  23. If user is conversing with you in English:
  24. “You must log in to Petercat using GitHub before accessing this feature.” [Login URL](https://api.petercat.ai/api/auth/login)
  25. """
  26. EDIT_PROMPT ="""
  27. ## Role:
  28. You are a GitHub Answering Bot modifying assistant. You specialize in modifying the configuration of a Q&A bot based on the user's requirements.
  29. ## Skills:
  30. - Utilize the edit_bot tool to modify the bot's configuration information based on the user's description.
  31. - Always use the created bot's ID: {bot_id} as the id of the bot being edited and the uid of the current user is {user_id}.
  32. - If the user wishes to change the avatar, ask user to provide the URL of the new avatar.
  33. ## Limitations:
  34. - Can only update the configuration of the bot based on the GitHub repository information provided by the user.
  35. - During the process of a Q&A bot, if any issues or errors are encountered, you may provide related advice or solutions, but must not directly modify the user's GitHub repository.
  36. - When modifying the bot's configuration information, you must adhere to the user's suggestions and requirements and not make changes without permission.
  37. If user is conversing with you in Chinese:
  38. “您必须先使用 GitHub 登录 Petercat 才能使用此功能。[登录地址](https://api.petercat.ai/api/auth/login)
  39. If user is conversing with you in English:
  40. “You must log in to Petercat using GitHub before accessing this feature.” [Login URL](https://api.petercat.ai/api/auth/login)
  41. """defgenerate_prompt_by_user_id(user_id:str, bot_id: Optional[str]):if bot_id:return EDIT_PROMPT.format(bot_id=bot_id, user_id=user_id)else:return CREATE_PROMPT.format(user_id=user_id)
Tools 工具预置

前文说到,在 PeterCat 平台搭建的智能答疑机器人内置了 提 issue、查 issue、回 issue、Discussion 回复、PR Summary、Code Review、项目信息查询 的基础能力。

这些工作本质属于工程链路的内容,提供给 Langchain 进行工具调用。

  1. def_create_agent_with_tools(self)-> AgentExecutor:
  2. llm = self.chat_model.get_client()
  3. tools = self.init_tavily_tools()if self.enable_tavily else[]for tool in self.tools.values():
  4. tools.append(tool)if tools:
  5. parsed_tools = self.chat_model.get_tools(tools)
  6. llm = llm.bind_tools(parsed_tools)
  7. self.prompt = self.get_prompt()
  8. agent =({"input":lambda x: x["input"],"agent_scratchpad":lambda x: format_to_openai_tool_messages(
  9. x["intermediate_steps"]),"chat_history":lambda x: x["chat_history"],}| self.prompt
  10. | llm
  11. | OpenAIToolsAgentOutputParser())return AgentExecutor(
  12. agent=agent,
  13. tools=tools,
  14. verbose=True,
  15. handle_parsing_errors=True,
  16. max_iterations=5,)
bot 构建

有了上述 LLM 模型选择、Prompt 设定 和 Tools 工具的预置,我们就可以构建出一个智能答疑机器人了:

  1. defagent_stream_chat(
  2. input_data: ChatData,
  3. user_id:str,
  4. bot_id:str,)-> AsyncIterator[str]:
  5. prompt = generate_prompt_by_user_id(user_id, bot_id)
  6. agent = AgentBuilder(
  7. chat_model=OpenAIClient(),
  8. prompt=prompt, tools=TOOL_MAPPING, enable_tavily=False)return dict_to_sse(
  9. agent.run_stream_chat(input_data))
Langchain 集成

前文说到,PeterCat 提供的答疑机器人具备很多能力,什么时候该创建一个机器人、什么时候该为用户解答 Github 应用的项目数据、亦或者替用户回复一个 issue 、提取上下文… 这些其实都由 Langchain 来进行统筹决策。

Langchain 内置的 AgentExecutor 会根据用户输入决策使用什么工具执行任务,tavily_search 会在工具列表中快速检索,ChatPromptTemplate 则对对话上下文进行了格式化处理。

  1. import json
  2. import logging
  3. from typing import AsyncGenerator, AsyncIterator, Dict, Callable, Optional
  4. from langchain.agents import AgentExecutor
  5. from agent.llm import BaseLLMClient
  6. from petercat_utils.data_class import ChatData, Message
  7. from langchain.agents.format_scratchpad.openai_tools import(
  8. format_to_openai_tool_messages,)from langchain_core.messages import(
  9. AIMessage,
  10. FunctionMessage,
  11. HumanMessage,
  12. SystemMessage,)from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser
  13. from langchain.prompts import MessagesPlaceholder
  14. from langchain_core.prompts import ChatPromptTemplate
  15. from langchain_community.utilities.tavily_search import TavilySearchAPIWrapper
  16. from langchain_community.tools.tavily_search.tool import TavilySearchResults
  17. from petercat_utils import get_env_variable
  18. TAVILY_API_KEY = get_env_variable("TAVILY_API_KEY")
  19. logger = logging.getLogger()asyncdefdict_to_sse(generator: AsyncGenerator[Dict,None]):...classAgentBuilder:
  20. agent_executor: AgentExecutor
  21. def__init__(
  22. self,
  23. chat_model: BaseLLMClient,
  24. prompt:str,
  25. tools: Dict[str, Callable],
  26. enable_tavily: Optional[bool]=True,):"""
  27. @class `Builde AgentExecutor based on tools and prompt`
  28. @param prompt: str
  29. @param tools: Dict[str, Callable]
  30. @param enable_tavily: Optional[bool] If set True, enables the Tavily tool
  31. """
  32. self.prompt = prompt
  33. self.tools = tools
  34. self.enable_tavily = enable_tavily
  35. self.chat_model = chat_model
  36. self.agent_executor = self._create_agent_with_tools()definit_tavily_tools(self):# init Tavily
  37. search = TavilySearchAPIWrapper()
  38. tavily_tool = TavilySearchResults(api_wrapper=search)return[tavily_tool]def_create_agent_with_tools(self)-> AgentExecutor:...defget_prompt(self):...defchat_history_transform(self, messages:list[Message]):...asyncdefrun_stream_chat(self, input_data: ChatData)-> AsyncIterator[Dict]:...asyncdefrun_chat(self, input_data: ChatData)->str:...

总结

作为大模型在垂类场景的典型应用,PeterCat 借助 Langchain ,通过 向量化数据库构建、RAG 检索生成、Prompt 设定、Tools 工具预置 一系列操作完成了大模型在垂类场景的落地。

可以发现,即使是大模型在垂类场景的应用,我们做的工作更多也是偏向工程侧能力的升级,对于大模型的核心训练过程,其实还没有很深的涉入,这部分内容其实算做模型微调。在此基础上,多智能体的协同工作也是我们值得探索的方向之一


本文转载自: https://blog.csdn.net/double_sweet1/article/details/142844804
版权归原作者 Coding101 所有, 如有侵权,请联系我们删除。

“AI大模型源码解析|打造你的专属GitHub智能答疑助手!”的评论:

还没有评论