基于OpenAI+Langchain+Tavily的聊天机器人数据源溯源实现方案
聊天机器人数据源溯源需求与代码说明
项目背景与现状
正在开发一款基于OpenAI模型、Langchain框架,并集成Tavily Search的聊天机器人。该机器人采用主OpenAI聊天模型Agent架构,可调用自定义API,每个API本质是具备工具调用能力的Langchain Agent(如对接Tavily的网页搜索API)。
目前已完成核心逻辑开发,包括OpenAI、Langchain及Tavily Search功能集成,实现了工具初始化、Prompt编写、Agent执行生成对话回复等流程,但尚未建立稳定的数据源捕获与日志系统,无法追踪机器人生成回复时所使用的数据来源(如URL、文本片段、元数据等)。
核心需求
- 修改搜索工具与执行逻辑,实现类似浏览器历史记录的数据源溯源功能,让机器人能够记录并展示每一条回复所依赖的Tavily搜索结果来源信息。
- 了解是否有开发者在Langchain+OpenAI架构中实现过此类溯源功能,或有相关文档参考。
代码结构与片段
createNewCompletion(服务类核心方法)
负责初始化工具、聊天模型、解析历史对话,调用Agent生成回复
async createNewCompletion( userId: number, chatId: number, dto: CreateNewCompletionDto, ) { //.... const parameters = await this.getChatModelParameters(userId, chatId); const tools = this.initializeTools(userId, parameters.toolsList); delete parameters.toolsList; const chatModel = await this.initializeChatModel(userId, parameters); const messages = await this.chatHistoryParser(userId, chatId); const completion = await this.openAiToolsAgentExecutor( chatModel, tools, messages, dto, userId, chatId, ); return { message: 'Completion created successfully', data: completion, }; //.... }
openAiToolsAgentExecutor(OpenAI工具Agent执行器)
执行OpenAI工具Agent,创建Prompt与Agent实例,调用Executor生成回复
private async openAiToolsAgentExecutor( llm, tools, messages, dto, userId, chatId, ) { //... const prompt = ChatPromptTemplate.fromMessages([ [ 'system', 'You are a helpful assistant. Answer all questions to the best of your ability. Use the suite of tools provided if needed. You may not need to use tools for every query - the user may just want to chat!', ], new MessagesPlaceholder('messages'), new MessagesPlaceholder('agent_scratchpad'), ]); const agent = await createOpenAIToolsAgent({ llm, tools, prompt, }); const executor = new AgentExecutor({ agent, tools, }); const completion = await executor.invoke({ messages: [...messages, new HumanMessage(dto.prompt)], }); //.... return completion ; //... }
initializeTools(工具初始化方法)
初始化WEB_SEARCH_API等工具,其中网页搜索工具通过调用tavilySearch方法实现
private initializeTools(userId: number, toolsList: string[]) { const tools = [ //.... new DynamicStructuredTool({ name: 'WEB_SEARCH_API', description: 'Call this to search the web', schema: z.object({ query: z.string().describe('Query to search the web'), }), func: async ({ query }) => { try { const { data } = await this.toolServices.tavilySearch(userId, { query: `We need to search the web for the following query: ${query}`, }); return data.output; } catch (error) { throw new Error('Error searching the web'); } }, }), //.... ]; // Filter the allTools array to only include tools whose name is in the toolsList array const selectedTools = toolsList.length > 0 ? tools.filter((tool) => toolsList.includes(tool.name)) : tools; return selectedTools; }
tavilySearch(Tavily搜索API方法)
调用Tavily工具执行搜索,返回结果
async tavilySearch(userId: number, dto: TavilySearchDto) { //.... const TOOL_KEY = 'TAVILY_SEARCH'; const chatModel = await this.initializeChatModel(userId); const tools = this.searchWithTavilyTools(TOOL_KEY); const executor = this.tavilyAgentExecutor(chatModel, tools); const completion = await executor.invoke({ input: dto.query, }); return { message: 'Tavily search completed successfully.', data: completion, }; //.... }
searchWithTavilyTools(Tavily搜索工具初始化方法)
初始化Tavily搜索工具,封装Tavily调用逻辑
private searchWithTavilyTools(toolName: string) { //... const tavily = this.initializeTavilySearchTool(); const tavilySearchTool = new DynamicStructuredTool({ name: toolName, description: 'Call this to search on the web and get the most relevant information based on the query.', schema: z.object({ query: z.string().describe('The query to search on the web.'), }), func: async ({ query }) => { try { const result = await tavily.invoke(query); return result; } catch (error) { throw new Error('Error while searching the web with Tavily.'); } }, }); const tools = [tavilySearchTool]; return tools; //.... }
tavilyAgentExecutor(Tavily搜索专用Agent执行器)
创建Tavily搜索专用Agent Executor,配置Prompt与模型函数绑定
private tavilyAgentExecutor( chatModel: ChatOpenAI<ChatOpenAICallOptions>, tools: DynamicStructuredTool< z.ZodObject< { query: z.ZodString; }, 'strip', z.ZodTypeAny, { query?: string; }, { query?: string; } > >[], ) { //..... const prompt = ChatPromptTemplate.fromMessages([ [ 'system', 'You are an exceptionally adept assistant with advanced capabilities in web search. Your task is to meticulously search the web for the most relevant information based on the user query. Utilize the comprehensive suite of tools at your disposal to expertly retrieve the required information, ensuring accuracy and relevance in every aspect of your search.', ], ['human', '{input}'], new MessagesPlaceholder('agent_scratchpad'), ]); const modelWithFunctions = chatModel.bind({ functions: tools.map((tool) => convertToOpenAIFunction(tool)), }); const runnableAgent = RunnableSequence.from([ { input: (i: { input: string; steps: AgentStep[] }) => i.input, agent_scratchpad: (i: { input: string; steps: AgentStep[] }) => formatToOpenAIFunctionMessages(i.steps), }, prompt, modelWithFunctions, new OpenAIFunctionsAgentOutputParser(), ]); const executor = AgentExecutor.fromAgentAndTools({ agent: runnableAgent, tools, }); return executor; //.... }
内容的提问来源于stack exchange,提问作者MrN3O
相关产品推荐
相关产品推荐

