基于langchain重现agent调用llm和tools的过程
langchain封装了agent调用llm和tools过程,有效降低了agent开发复杂度。
然而对于具体应用,默认的llm和tools调用方式,可能不足以适配具体业务场景。
要完成这个任务,需要知道agent调用llm和tools的整个过程。
这里参考网络资料,梳理agent通过ollama llm分析用户问题、选择工具、执行action及结果反馈的过程。
假设ollama和langchain_ollama等工具已经安装,mac安装ollama过程可参考
在mac m1基于ollama运行deepseek r1_mac m1 ollama-CSDN博客
1 tool工具定义
如下所示,模拟公司产品数据库查询、公司介绍文档数据库查询等。
在公司介绍文档数据库中,还可以进一步调用llm整理介绍内容。
class FugeDataSource:def __init__(self, llm: BaseLLM):self.llm = llmdef find_product_description(self, product_name: str) -> str:"""模拟公司产品的数据库"""print(">>>>find_product_description")product_info = {"好快活": "好快活是一个营销人才平台,以社群+公众号+小程序结合的运营模式展开,帮助企业客户连接并匹配充满才华的营销人才。","Rimix": """Rimix通过采购流程数字化、完备的项目数据存储记录及标准的供应商管理体系,帮助企业实现采购流程, 透明合规可追溯,大幅节约采购成本。Rimix已为包括联合利华,滴滴出行等多家广告主提供服务,平均可为客户节约采购成本30%。""","Bid Agent": "Bid Agent是一款专为中国市场设计的搜索引擎优化管理工具,支持5大搜索引擎。Bid Agent平均为广告主提升18%的投放效果,同时平均提升47%的管理效率。目前已为阳狮广告、GroupM等知名4A公司提供服务与支持。",}return product_info.get(product_name, "没有找到这个产品")def find_company_info(self, query: str) -> str:"""模拟公司介绍文档数据库,让llm根据抓取信息回答问题"""print(">>>>find_company_info")context = """关于产品:"让广告技术美而温暖"是复歌的产品理念。在努力为企业客户创造价值的同时,也希望让使用复歌产品的每个人都能感受到技术的温度。我们关注用户的体验和建议,我们期待我们的产品能够给每个使用者的工作和生活带来正面的改变。我们崇尚技术,用科技的力量使工作变得简单,使生活变得更加美好而优雅,是我们的愿景。企业文化:复歌是一个非常年轻的团队,公司大部分成员是90后。工作上,专业、注重细节、拥抱创新、快速试错。协作中,开放、坦诚、包容、还有一点点举重若轻的幽默感。以上这些都是复歌团队的重要特质。在复歌,每个人可以平等地表达自己的观点和意见,每个人的想法和意愿都会被尊重。如果你有理想,并拥有被理想所驱使的自我驱动力,我们期待你的加入。"""prompt = CONTEXT_QA_PROMPT.format(query=query, context=context)return self.llm(prompt)
2 tool工具整合
为了展示agent感知tool过程,进一步对FugeDataSource定义工具添加name和description信息。
将tools送入CustomPromptTemplate进一步定义llm prompt,目的是更好地适配业务需求。
fuge_data_source = FugeDataSource(llm)tools = [Tool(name="查询产品名称",func=fuge_data_source.find_product_description,description="通过产品名称找到产品描述时用的工具,输入应该是产品名称",),Tool(name="复歌科技公司相关信息",func=fuge_data_source.find_company_info,description="当用户询问公司相关的问题,可以通过这个工具了解相关信息",),]agent_prompt = CustomPromptTemplate(template=AGENT_TMPL,tools=tools,input_variables=["input", "intermediate_steps"],)output_parser = CustomOutputParser()llm_chain = LLMChain(llm=llm, prompt=agent_prompt)tool_names = [tool.name for tool in tools]agent = LLMSingleActionAgent(llm_chain=llm_chain,output_parser=output_parser,stop=["\nObservation:"],allowed_tools=tool_names,)
3 llm prompt定制
1)prompt模版
自定义llm prompt模版是提高agent对场景应用的适配程度的最直接有效的方式。
这里通过CustomPromptTemplate实现,以下是llm prompt模版,包含tools描述、tool_names、用户问题input、以及agent_scartchpad。
AGENT_TMPL = """按照给定的格式回答以下问题。你可以使用下面这些工具:
{tools}
回答时需要遵循以下用---括起来的格式:
---
Question: 我需要回答的问题
Thought: 回答这个上述我需要做些什么
Action: ”{tool_names}“ 中的其中一个工具名
Action Input: 选择工具所需要的输入
Observation: 选择工具返回的结果
...(这个思考/行动/行动输入/观察可以重复N次)
Thought: 我现在知道最终答案
Final Answer: 原始输入问题的最终答案
---现在开始回答,记得在给出最终答案前多按照指定格式进行一步一步的推理。
Question: {input}
{agent_scratchpad}
"""
2)模版信息提取
以下是CustomPromptTemplate完善prompt模版所需信息的代码,包括从kwargs中依次提取oberservation构建agent_scratchpad、描述agent调用tool过程,以及并进一步提取tools、tool_names构建llm prompt。
class CustomPromptTemplate(StringPromptTemplate):template: str # 标准模板tools: List[Tool] # 可使用工具集合def format(self, **kwargs) -> str:"""按照定义的 template,将需要的值都填写进去。Returns:str: 填充好后的 template。"""print(f"CustomPromptTemplate-> kwargs: \n{kwargs}")intermediate_steps = kwargs.pop("intermediate_steps") # 取出中间步骤并进行执行thoughts = ""for action, observation in intermediate_steps:print(f"intermediate_steps, action: {action.log}, observation: {observation}")thoughts += action.logthoughts += f"\nObservation: {observation}\nThought: "kwargs["agent_scratchpad"] = thoughts # 记录下当前想法kwargs["tools"] = "\n".join([f"{tool.name}: {tool.description}" for tool in self.tools]) # 枚举所有可使用的工具名+工具描述kwargs["tool_names"] = ", ".join([tool.name for tool in self.tools]) # 枚举所有的工具名称print(f"CustomPromptTemplate->updated kwargs: \n{kwargs}")cur_prompt = self.template.format(**kwargs)print("*******************************")print(f"CustomPromptTemplate-> prompt:\n{cur_prompt}")print("*******************************")return cur_prompt
3)提取示例
prompt所需的action执行记录、tool信息tools和tool_names保存在kwargs,以下是一个完整的kwargs示例。借助于CustomPromptTemplate定义的format方式,可有效提取信息构建 llm prompt。
{
'input': '介绍下好快活这个产品',
'intermediate_steps': [
(
AgentAction(
tool='查询产品名称',
tool_input='好快活',
log='<think>\n好的,用户让我介绍“好快活”这个产品。首先,我需要确定“好快活”是什么产品。可能是一个品牌、软件或者硬件产品。根据提供的工具,我应该先使用“查询产品名称”工具来获取产品描述。\n\n接下来,我需要调用查询产品名称的工具,输入是“好快活”。然后观察返回的结果。假设工具返回的信息是:好快活是一款专注于提升用户工作效率的智能任务管理软件,具备自动日程安排、团队协作等功能,适合个人和企业用户。\n\n但可能还需要进一步确认是否准确,或者是否需要使用复歌科技公司的信息。不过根据问题,用户只是要求介绍该产品,所以可能不需要公司信息。但如果有需要,可能需要检查复歌科技是否与该产品相关。不过根据工具名称,复歌科技公司相关信息可能用于公司背景,而查询产品名称是直接获取产品描述。因此,可能只需要第一步的查询产品名称的结果即可。\n</think>\n\n---\nThought: 我需要先通过产品名称查询工具获取“好快活”的详细信息。\nAction: 查询产品名称\nAction Input: 好快活'
), # AgentAction
'好快活是一个营销人才平台,以社群+公众号+小程序结合的运营模式展开,帮助企业客户连接并匹配充满才华的营销人才。' # Observation
)
]
}
4 agent运行示例
agent完整代码如下所示
import re
from typing import List, Union
import textwrap
import timefrom langchain.agents import (Tool,AgentExecutor,LLMSingleActionAgent,AgentOutputParser,
)
from langchain.prompts import StringPromptTemplate
from langchain import OpenAI, LLMChain
from langchain.schema import AgentAction, AgentFinish
from langchain.prompts import PromptTemplatefrom langchain.llms.base import BaseLLMCONTEXT_QA_TMPL = """
根据以下提供的信息,回答用户的问题
信息:{context}问题:{query}
"""
CONTEXT_QA_PROMPT = PromptTemplate(input_variables=["query", "context"],template=CONTEXT_QA_TMPL,
)def output_response(response: str) -> None:print("----------------------------------------------------------------")if not response:exit(0)for line in textwrap.wrap(response, width=60):for word in line.split():for char in word:print(char, end="", flush=True)time.sleep(0.1) # Add a delay of 0.1 seconds between each characterprint(" ", end="", flush=True) # Add a space between each wordprint() # Move to the next line after each line is printedprint("----------------------------------------------------------------")class FugeDataSource:def __init__(self, llm: BaseLLM):self.llm = llmdef find_product_description(self, product_name: str) -> str:"""模拟公司产品的数据库"""print(">>>>find_product_description")product_info = {"好快活": "好快活是一个营销人才平台,以社群+公众号+小程序结合的运营模式展开,帮助企业客户连接并匹配充满才华的营销人才。","Rimix": """Rimix通过采购流程数字化、完备的项目数据存储记录及标准的供应商管理体系,帮助企业实现采购流程, 透明合规可追溯,大幅节约采购成本。Rimix已为包括联合利华,滴滴出行等多家广告主提供服务,平均可为客户节约采购成本30%。""","Bid Agent": "Bid Agent是一款专为中国市场设计的搜索引擎优化管理工具,支持5大搜索引擎。Bid Agent平均为广告主提升18%的投放效果,同时平均提升47%的管理效率。目前已为阳狮广告、GroupM等知名4A公司提供服务与支持。",}return product_info.get(product_name, "没有找到这个产品")def find_company_info(self, query: str) -> str:"""模拟公司介绍文档数据库,让llm根据抓取信息回答问题"""print(">>>>find_company_info")context = """关于产品:"让广告技术美而温暖"是复歌的产品理念。在努力为企业客户创造价值的同时,也希望让使用复歌产品的每个人都能感受到技术的温度。我们关注用户的体验和建议,我们期待我们的产品能够给每个使用者的工作和生活带来正面的改变。我们崇尚技术,用科技的力量使工作变得简单,使生活变得更加美好而优雅,是我们的愿景。企业文化:复歌是一个非常年轻的团队,公司大部分成员是90后。工作上,专业、注重细节、拥抱创新、快速试错。协作中,开放、坦诚、包容、还有一点点举重若轻的幽默感。以上这些都是复歌团队的重要特质。在复歌,每个人可以平等地表达自己的观点和意见,每个人的想法和意愿都会被尊重。如果你有理想,并拥有被理想所驱使的自我驱动力,我们期待你的加入。"""prompt = CONTEXT_QA_PROMPT.format(query=query, context=context)return self.llm(prompt)AGENT_TMPL = """按照给定的格式回答以下问题。你可以使用下面这些工具:{tools}回答时需要遵循以下用---括起来的格式:---
Question: 我需要回答的问题
Thought: 回答这个上述我需要做些什么
Action: ”{tool_names}“ 中的其中一个工具名
Action Input: 选择工具所需要的输入
Observation: 选择工具返回的结果
...(这个思考/行动/行动输入/观察可以重复N次)
Thought: 我现在知道最终答案
Final Answer: 原始输入问题的最终答案
---现在开始回答,记得在给出最终答案前多按照指定格式进行一步一步的推理。Question: {input}
{agent_scratchpad}
"""class CustomPromptTemplate(StringPromptTemplate):template: str # 标准模板tools: List[Tool] # 可使用工具集合def format(self, **kwargs) -> str:"""按照定义的 template,将需要的值都填写进去。Returns:str: 填充好后的 template。"""print(f"CustomPromptTemplate-> kwargs: \n{kwargs}")intermediate_steps = kwargs.pop("intermediate_steps") # 取出中间步骤并进行执行thoughts = ""for action, observation in intermediate_steps:print(f"intermediate_steps, action: {action.log}, observation: {observation}")thoughts += action.logthoughts += f"\nObservation: {observation}\nThought: "kwargs["agent_scratchpad"] = thoughts # 记录下当前想法kwargs["tools"] = "\n".join([f"{tool.name}: {tool.description}" for tool in self.tools]) # 枚举所有可使用的工具名+工具描述kwargs["tool_names"] = ", ".join([tool.name for tool in self.tools]) # 枚举所有的工具名称print(f"CustomPromptTemplate->updated kwargs: \n{kwargs}")cur_prompt = self.template.format(**kwargs)print("*******************************")print(f"CustomPromptTemplate-> prompt:\n{cur_prompt}")print("*******************************")return cur_promptclass CustomOutputParser(AgentOutputParser):def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:"""解析 llm 的输出,根据输出文本找到需要执行的决策。Args:llm_output (str): _description_Raises:ValueError: _description_Returns:Union[AgentAction, AgentFinish]: _description_"""print(f"CustomOutputParser-> llm_output: {llm_output}")if "Final Answer:" in llm_output: # 如果句子中包含 Final Answer 则代表已经完成return AgentFinish(return_values={"output": llm_output.split("Final Answer:")[-1].strip()},log=llm_output,)regex = r"Action\s*\d*\s*:(.*?)\nAction\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)" # 解析 action_input 和 actionmatch = re.search(regex, llm_output, re.DOTALL)if not match:raise ValueError(f"Could not parse LLM output: `{llm_output}`")action = match.group(1).strip()action_input = match.group(2)print(f"CustomOutputParser-> action: {action}, tool_input: {action_input}")return AgentAction(tool=action, tool_input=action_input.strip(" ").strip('"'), log=llm_output)from langchain_ollama import ChatOllamaif __name__ == "__main__":llm = ChatOllama(model='qwen3:4b')fuge_data_source = FugeDataSource(llm)tools = [Tool(name="查询产品名称",func=fuge_data_source.find_product_description,description="通过产品名称找到产品描述时用的工具,输入应该是产品名称",),Tool(name="复歌科技公司相关信息",func=fuge_data_source.find_company_info,description="当用户询问公司相关的问题,可以通过这个工具了解相关信息",),]agent_prompt = CustomPromptTemplate(template=AGENT_TMPL,tools=tools,input_variables=["input", "intermediate_steps"],)output_parser = CustomOutputParser()llm_chain = LLMChain(llm=llm, prompt=agent_prompt)tool_names = [tool.name for tool in tools]agent = LLMSingleActionAgent(llm_chain=llm_chain,output_parser=output_parser,stop=["\nObservation:"],allowed_tools=tool_names,)agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools, verbose=True)while True:try:user_input = input("请输入您的问题:")response = agent_executor.run(user_input)output_response(response)except KeyboardInterrupt:break
用户输入
介绍下好快活这个产品”
以下是系统输出。虽然有很多冗余,但是清晰记录了agent运行整个过程。
请输入您的问题: 介绍下好快活这个产品
> Entering new AgentExecutor chain...
CustomPromptTemplate->
kwargs: {'input': '介绍下好快活这个产品', 'intermediate_steps': []}
kwargs: {'input': '介绍下好快活这个产品', 'agent_scratchpad': '', 'tools': '查询产品名称: 通过产品名称找到产品描述时用的工具,输入应该是产品名称\n复歌科技公司相关信息: 当用户询问公司相关的问题,可以通过这个工具了解相关信息', 'tool_names': '查询产品名称, 复歌科技公司相关信息'}
*******************************
CustomPromptTemplate-> prompt:
按照给定的格式回答以下问题。你可以使用下面这些工具:查询产品名称: 通过产品名称找到产品描述时用的工具,输入应该是产品名称
复歌科技公司相关信息: 当用户询问公司相关的问题,可以通过这个工具了解相关信息回答时需要遵循以下用---括起来的格式:
---
Question: 我需要回答的问题
Thought: 回答这个上述我需要做些什么
Action: ”查询产品名称, 复歌科技公司相关信息“ 中的其中一个工具名
Action Input: 选择工具所需要的输入
Observation: 选择工具返回的结果
...(这个思考/行动/行动输入/观察可以重复N次)
Thought: 我现在知道最终答案
Final Answer: 原始输入问题的最终答案
---现在开始回答,记得在给出最终答案前多按照指定格式进行一步一步的推理。
Question: 介绍下好快活这个产品
*******************************
CustomOutputParser-> llm_output: <think>
好的,用户让我介绍“好快活”这个产品。首先,我需要确定“好快活”是什么产品。可能是一个品牌、软件或者硬件产品。根据提供的工具,我应该先使用“查询产品名称”工具来获取产品描述。接下来,我需要调用查询产品名称的工具,输入是“好快活”。然后观察返回的结果。假设工具返回的信息是:好快活是一款专注于提升用户工作效率的智能任务管理软件,具备自动日程安排、团队协作等功能,适合个人和企业用户。
但可能还需要进一步确认是否准确,或者是否需要使用复歌科技公司的信息。不过根据问题,用户只是要求介绍该产品,所以可能不需要公司信息。但如果有需要,可能需要检查复歌科技是否与该产品相关。不过根据工具名称,复歌科技公司相关信息可能用于公司背景,而查询产品名称是直接获取产品描述。因此,可能只需要第一步的查询产品名称的结果即可。
</think>---
Thought: 我需要先通过产品名称查询工具获取“好快活”的详细信息。
Action: 查询产品名称
Action Input: 好快活
CustomOutputParser-> action: 查询产品名称, tool_input: 好快活
<think>
好的,用户让我介绍“好快活”这个产品。首先,我需要确定“好快活”是什么产品。可能是一个品牌、软件或者硬件产品。根据提供的工具,我应该先使用“查询产品名称”工具来获取产品描述。接下来,我需要调用查询产品名称的工具,输入是“好快活”。然后观察返回的结果。假设工具返回的信息是:好快活是一款专注于提升用户工作效率的智能任务管理软件,具备自动日程安排、团队协作等功能,适合个人和企业用户。
但可能还需要进一步确认是否准确,或者是否需要使用复歌科技公司的信息。不过根据问题,用户只是要求介绍该产品,所以可能不需要公司信息。但如果有需要,可能需要检查复歌科技是否与该产品相关。不过根据工具名称,复歌科技公司相关信息可能用于公司背景,而查询产品名称是直接获取产品描述。因此,可能只需要第一步的查询产品名称的结果即可。
</think>---
Thought: 我需要先通过产品名称查询工具获取“好快活”的详细信息。
Action: 查询产品名称
Action Input: 好快活>>>>find_product_description
Observation:好快活是一个营销人才平台,以社群+公众号+小程序结合的运营模式展开,帮助企业客户连接并匹配充满才华的营销人才。
CustomPromptTemplate->
kwargs: {'input': '介绍下好快活这个产品', 'intermediate_steps': [(AgentAction(tool='查询产品名称', tool_input='好快活', log='<think>\n好的,用户让我介绍“好快活”这个产品。首先,我需要确定“好快活”是什么产品。可能是一个品牌、软件或者硬件产品。根据提供的工具,我应该先使用“查询产品名称”工具来获取产品描述。\n\n接下来,我需要调用查询产品名称的工具,输入是“好快活”。然后观察返回的结果。假设工具返回的信息是:好快活是一款专注于提升用户工作效率的智能任务管理软件,具备自动日程安排、团队协作等功能,适合个人和企业用户。\n\n但可能还需要进一步确认是否准确,或者是否需要使用复歌科技公司的信息。不过根据问题,用户只是要求介绍该产品,所以可能不需要公司信息。但如果有需要,可能需要检查复歌科技是否与该产品相关。不过根据工具名称,复歌科技公司相关信息可能用于公司背景,而查询产品名称是直接获取产品描述。因此,可能只需要第一步的查询产品名称的结果即可。\n</think>\n\n---\nThought: 我需要先通过产品名称查询工具获取“好快活”的详细信息。\nAction: 查询产品名称\nAction Input: 好快活'), '好快活是一个营销人才平台,以社群+公众号+小程序结合的运营模式展开,帮助企业客户连接并匹配充满才华的营销人才。')]}
intermediate_steps, action: <think>
好的,用户让我介绍“好快活”这个产品。首先,我需要确定“好快活”是什么产品。可能是一个品牌、软件或者硬件产品。根据提供的工具,我应该先使用“查询产品名称”工具来获取产品描述。接下来,我需要调用查询产品名称的工具,输入是“好快活”。然后观察返回的结果。假设工具返回的信息是:好快活是一款专注于提升用户工作效率的智能任务管理软件,具备自动日程安排、团队协作等功能,适合个人和企业用户。
但可能还需要进一步确认是否准确,或者是否需要使用复歌科技公司的信息。不过根据问题,用户只是要求介绍该产品,所以可能不需要公司信息。但如果有需要,可能需要检查复歌科技是否与该产品相关。不过根据工具名称,复歌科技公司相关信息可能用于公司背景,而查询产品名称是直接获取产品描述。因此,可能只需要第一步的查询产品名称的结果即可。
</think>---
Thought: 我需要先通过产品名称查询工具获取“好快活”的详细信息。
Action: 查询产品名称
Action Input: 好快活, observation: 好快活是一个营销人才平台,以社群+公众号+小程序结合的运营模式展开,帮助企业客户连接并匹配充满才华的营销人才。
kwargs: {'input': '介绍下好快活这个产品', 'agent_scratchpad': '<think>\n好的,用户让我介绍“好快活”这个产品。首先,我需要确定“好快活”是什么产品。可能是一个品牌、软件或者硬件产品。根据提供的工具,我应该先使用“查询产品名称”工具来获取产品描述。\n\n接下来,我需要调用查询产品名称的工具,输入是“好快活”。然后观察返回的结果。假设工具返回的信息是:好快活是一款专注于提升用户工作效率的智能任务管理软件,具备自动日程安排、团队协作等功能,适合个人和企业用户。\n\n但可能还需要进一步确认是否准确,或者是否需要使用复歌科技公司的信息。不过根据问题,用户只是要求介绍该产品,所以可能不需要公司信息。但如果有需要,可能需要检查复歌科技是否与该产品相关。不过根据工具名称,复歌科技公司相关信息可能用于公司背景,而查询产品名称是直接获取产品描述。因此,可能只需要第一步的查询产品名称的结果即可。\n</think>\n\n---\nThought: 我需要先通过产品名称查询工具获取“好快活”的详细信息。\nAction: 查询产品名称\nAction Input: 好快活\nObservation: 好快活是一个营销人才平台,以社群+公众号+小程序结合的运营模式展开,帮助企业客户连接并匹配充满才华的营销人才。\nThought: ', 'tools': '查询产品名称: 通过产品名称找到产品描述时用的工具,输入应该是产品名称\n复歌科技公司相关信息: 当用户询问公司相关的问题,可以通过这个工具了解相关信息', 'tool_names': '查询产品名称, 复歌科技公司相关信息'}
*******************************
CustomPromptTemplate-> prompt:
按照给定的格式回答以下问题。你可以使用下面这些工具:查询产品名称: 通过产品名称找到产品描述时用的工具,输入应该是产品名称
复歌科技公司相关信息: 当用户询问公司相关的问题,可以通过这个工具了解相关信息回答时需要遵循以下用---括起来的格式:
---
Question: 我需要回答的问题
Thought: 回答这个上述我需要做些什么
Action: ”查询产品名称, 复歌科技公司相关信息“ 中的其中一个工具名
Action Input: 选择工具所需要的输入
Observation: 选择工具返回的结果
...(这个思考/行动/行动输入/观察可以重复N次)
Thought: 我现在知道最终答案
Final Answer: 原始输入问题的最终答案
---现在开始回答,记得在给出最终答案前多按照指定格式进行一步一步的推理。
Question: 介绍下好快活这个产品
<think>
好的,用户让我介绍“好快活”这个产品。首先,我需要确定“好快活”是什么产品。可能是一个品牌、软件或者硬件产品。根据提供的工具,我应该先使用“查询产品名称”工具来获取产品描述。接下来,我需要调用查询产品名称的工具,输入是“好快活”。然后观察返回的结果。假设工具返回的信息是:好快活是一款专注于提升用户工作效率的智能任务管理软件,具备自动日程安排、团队协作等功能,适合个人和企业用户。
但可能还需要进一步确认是否准确,或者是否需要使用复歌科技公司的信息。不过根据问题,用户只是要求介绍该产品,所以可能不需要公司信息。但如果有需要,可能需要检查复歌科技是否与该产品相关。不过根据工具名称,复歌科技公司相关信息可能用于公司背景,而查询产品名称是直接获取产品描述。因此,可能只需要第一步的查询产品名称的结果即可。
</think>---
Thought: 我需要先通过产品名称查询工具获取“好快活”的详细信息。
Action: 查询产品名称
Action Input: 好快活
Observation: 好快活是一个营销人才平台,以社群+公众号+小程序结合的运营模式展开,帮助企业客户连接并匹配充满才华的营销人才。
Thought:*******************************
CustomOutputParser-> llm_output: <think>
好的,用户的问题是关于“好快活”这个产品的介绍。首先,我需要确认这个产品的性质和相关信息。根据提供的工具,我应该先使用“查询产品名称”来获取产品描述。输入“好快活”后,得到的结果是好快活是一个营销人才平台,结合社群、公众号和小程序的运营模式,帮助企业匹配营销人才。接下来,我需要判断是否需要进一步使用其他工具,比如复歌科技公司相关信息。但根据问题,用户只是要求介绍产品,而查询结果已经提供了足够的信息。因此,不需要额外的步骤。最终答案应基于查询结果,简洁明了地介绍该产品。
</think>Final Answer: 好快活是一个营销人才平台,通过社群+公众号+小程序的运营模式,帮助企业客户连接并匹配充满才华的营销人才。
<think>
好的,用户的问题是关于“好快活”这个产品的介绍。首先,我需要确认这个产品的性质和相关信息。根据提供的工具,我应该先使用“查询产品名称”来获取产品描述。输入“好快活”后,得到的结果是好快活是一个营销人才平台,结合社群、公众号和小程序的运营模式,帮助企业匹配营销人才。接下来,我需要判断是否需要进一步使用其他工具,比如复歌科技公司相关信息。但根据问题,用户只是要求介绍产品,而查询结果已经提供了足够的信息。因此,不需要额外的步骤。最终答案应基于查询结果,简洁明了地介绍该产品。
</think>Final Answer: 好快活是一个营销人才平台,通过社群+公众号+小程序的运营模式,帮助企业客户连接并匹配充满才华的营销人才。
> Finished chain.
----------------------------------------------------------------
好快活是一个营销人才平台,通过社群+公众号+小程序的运营模式,帮助企业客户连接并匹配充满才华的营销人才。
----------------------------------------------------------------
请输入您的问题:
5 chain相关概念理解
chain 是一步router完,tool上执行就完事了。
如果是reactagent,会根据当前的observation决策是不是还要调用其他tool来完成任务。
chain数据流转是固定的,agent数据的流转是它规划出来的,有不同的方式来规划。
reference
---
LangChain中Agent的一个实用案例
https://zhuanlan.zhihu.com/p/627948474
在mac m1基于ollama运行deepseek r1
https://blog.csdn.net/liliang199/article/details/149267372
@mcp.tool如何从函数定义映射到llm系统输入
https://blog.csdn.net/liliang199/article/details/150426177