-
+
diff --git a/gui/templates/setting.html b/gui/templates/setting.html
index e8c2caf..515efef 100644
--- a/gui/templates/setting.html
+++ b/gui/templates/setting.html
@@ -14,7 +14,7 @@
-
+
diff --git a/llm/agent/agent_service.py b/llm/agent/agent_service.py
new file mode 100644
index 0000000..ec8eeee
--- /dev/null
+++ b/llm/agent/agent_service.py
@@ -0,0 +1,133 @@
+import sqlite3
+import threading
+import datetime
+import time
+import os
+from scheduler.thread_manager import MyThread
+from core import member_db
+from core.interact import Interact
+from utils import util
+import fay_booter
+
+scheduled_tasks = {}
+agent_running = False
+
+
+# 数据库初始化
+def init_db():
+ conn = sqlite3.connect('timer.db')
+ cursor = conn.cursor()
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS timer (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ time TEXT NOT NULL,
+ repeat_rule TEXT NOT NULL,
+ content TEXT NOT NULL,
+ uid INTEGER
+ )
+ ''')
+ conn.commit()
+ conn.close()
+
+
+
+# 插入测试数据
+def insert_test_data():
+ conn = sqlite3.connect('timer.db')
+ cursor = conn.cursor()
+ cursor.execute("INSERT INTO timer (time, repeat_rule, content) VALUES (?, ?, ?)", ('16:20', '1010001', 'Meeting Reminder'))
+ conn.commit()
+ conn.close()
+
+# 解析重复规则返回待执行时间,None代表不在今天的待执行计划
+def parse_repeat_rule(rule, task_time):
+ today = datetime.datetime.now()
+ if rule == '0000000': # 不重复
+ task_datetime = datetime.datetime.combine(today.date(), task_time)
+ if task_datetime > today:
+ return task_datetime
+ else:
+ return None
+ for i, day in enumerate(rule):
+ if day == '1' and today.weekday() == i:
+ task_datetime = datetime.datetime.combine(today.date(), task_time)
+ if task_datetime > today:
+ return task_datetime
+ return None
+
+# 执行任务
+def execute_task(task_time, id, content, uid):
+ username = member_db.new_instance().find_username_by_uid(uid=uid)
+ if not username:
+ username = "User"
+ interact = Interact("text", 1, {'user': username, 'msg': "执行任务->\n" + content, 'observation': ""})
+ util.printInfo(3, "系统", '执行任务:{}'.format(interact.data["msg"]), time.time())
+ text = fay_booter.feiFei.on_interact(interact)
+ if text is not None and id in scheduled_tasks:
+ del scheduled_tasks[id]
+ # 如果不重复,执行后删除记录
+ conn = sqlite3.connect('timer.db')
+ cursor = conn.cursor()
+ cursor.execute("DELETE FROM timer WHERE repeat_rule = '0000000' AND id = ?", (id,))
+ conn.commit()
+ conn.close()
+
+
+# 30秒扫描一次数据库,当扫描到今天的不存在于定时任务列表的记录,则添加到定时任务列表。执行完的记录从定时任务列表中清除。
+def check_and_execute():
+ while agent_running:
+ conn = sqlite3.connect('timer.db')
+ cursor = conn.cursor()
+ cursor.execute("SELECT * FROM timer")
+ rows = cursor.fetchall()
+ for row in rows:
+ id, task_time_str, repeat_rule, content, uid = row
+ task_time = datetime.datetime.strptime(task_time_str, '%H:%M').time()
+ next_execution = parse_repeat_rule(repeat_rule, task_time)
+
+ if next_execution and id not in scheduled_tasks:
+ timer_thread = threading.Timer((next_execution - datetime.datetime.now()).total_seconds(), execute_task, [next_execution, id, content, uid])
+ timer_thread.start()
+ scheduled_tasks[id] = timer_thread
+
+ conn.close()
+ time.sleep(30) # 30秒扫描一次
+
+# agent启动
+def agent_start():
+ global agent_running
+
+ agent_running = True
+ #初始计划
+ if not os.path.exists("./timer.db"):
+ init_db()
+ content ="""执行任务->
+ 你是一个数字人,你的责任是陪伴主人生活、工作:
+ 1、在每天早上8点提醒主人起床;
+ 2、每天12:00及18:30提醒主人吃饭;
+ 3、每天21:00陪主人聊聊天;
+ 4、每天23:00提醒主人睡觉。
+ """
+ interact = Interact("text", 1, {'user': 'User', 'msg': content, 'observation': ""})
+ util.printInfo(3, "系统", '执行任务:{}'.format(interact.data["msg"]), time.time())
+ text = fay_booter.feiFei.on_interact(interact)
+ if text is None:
+ util.printInfo(3, "系统", '任务执行失败', time.time())
+
+ check_and_execute_thread = MyThread(target=check_and_execute)
+ check_and_execute_thread.start()
+
+
+
+def agent_stop():
+ global agent_running
+ global scheduled_tasks
+ # 取消所有定时任务
+ for task in scheduled_tasks.values():
+ task.cancel()
+ agent_running = False
+ scheduled_tasks = {}
+
+
+if __name__ == "__main__":
+ agent_start()
diff --git a/llm/agent/fay_agent.py b/llm/agent/fay_agent.py
new file mode 100644
index 0000000..c06992a
--- /dev/null
+++ b/llm/agent/fay_agent.py
@@ -0,0 +1,99 @@
+import os
+import time
+from llm.agent.tools.MyTimer import MyTimer
+from llm.agent.tools.Weather import Weather
+from llm.agent.tools.QueryTimerDB import QueryTimerDB
+from llm.agent.tools.DeleteTimer import DeleteTimer
+from llm.agent.tools.QueryTime import QueryTime
+from llm.agent.tools.PythonExecutor import PythonExecutor
+from llm.agent.tools.WebPageRetriever import WebPageRetriever
+from llm.agent.tools.WebPageScraper import WebPageScraper
+from llm.agent.tools.ToRemind import ToRemind
+from langgraph.prebuilt import create_react_agent
+from langchain_openai import ChatOpenAI
+from langgraph.checkpoint.memory import MemorySaver
+import utils.config_util as cfg
+from utils import util
+from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
+from core import content_db
+from core import member_db
+
+class FayAgentCore():
+ def __init__(self, uid=0, observation=""):
+ self.observation=observation
+ cfg.load_config()
+ os.environ["OPENAI_API_KEY"] = cfg.key_gpt_api_key
+ os.environ["OPENAI_API_BASE"] = cfg.gpt_base_url
+ os.environ["LANGCHAIN_TRACING_V2"] = "true"
+ os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
+ os.environ["LANGCHAIN_API_KEY"] = "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"
+ os.environ["LANGCHAIN_PROJECT"] = "pr-best-artist-21"
+
+ #创建llm
+ self.llm = ChatOpenAI(model=cfg.gpt_model_engine)
+
+ #创建agent graph
+ my_timer = MyTimer(uid=uid)#传入uid
+ weather_tool = Weather()
+ query_timer_db_tool = QueryTimerDB()
+ delete_timer_tool = DeleteTimer()
+ python_executor = PythonExecutor()
+ web_page_retriever = WebPageRetriever()
+ web_page_scraper = WebPageScraper()
+ to_remind = ToRemind()
+ self.tools = [my_timer, weather_tool, query_timer_db_tool, delete_timer_tool, python_executor, web_page_retriever, web_page_scraper, to_remind]
+ self.attr_info = ", ".join(f"{key}: {value}" for key, value in cfg.config["attribute"].items())
+ self.prompt_template = """
+ 现在时间是:{now_time}。你是一个数字人,负责协助主人处理问题和陪伴主人生活、工作。你的个人资料是:{attr_info}。通过外部设备观测到:{observation}。\n请依据以信息为主人服务。
+ """.format(now_time=QueryTime().run(""), attr_info=self.attr_info, observation=self.observation)
+ self.memory = MemorySaver()
+ self.agent = create_react_agent(self.llm, self.tools, checkpointer=self.memory)
+
+ self.total_tokens = 0
+ self.total_cost = 0
+
+ #载入记忆
+ def get_history_messages(self, uid):
+ chat_history = []
+ history = content_db.new_instance().get_list('all','desc', 100, uid)
+ if history and len(history) > 0:
+ i = 0
+ while i < len(history):
+ if history[i][0] == "member":
+ chat_history.append(HumanMessage(content=history[i][2], user=member_db.new_instance().find_username_by_uid(uid=uid)))
+ else:
+ chat_history.append(AIMessage(content=history[i][2]))
+ i += 1
+ return chat_history
+
+
+ def run(self, input_text, uid=0):
+ result = ""
+ messages = self.get_history_messages(uid)
+ messages.insert(0, SystemMessage(self.prompt_template))
+ messages.append(HumanMessage(content=input_text))
+
+ try:
+ for chunk in self.agent.stream(
+ {"messages": messages}, {"configurable": {"thread_id": "tid{}".format(uid)}}
+ ):
+ if chunk.get("agent"):
+ if chunk['agent']['messages'][0].content:
+ result = chunk['agent']['messages'][0].content
+ cb = chunk['agent']['messages'][0].response_metadata['token_usage']['total_tokens']
+ self.total_tokens = self.total_tokens + cb
+
+ util.log(1, "本次消耗token:{},共消耗token:{}".format(cb, self.total_tokens))
+ except Exception as e:
+ print(e)
+ return result
+
+def question(cont, uid=0, observation=""):
+ starttime = time.time()
+ agent = FayAgentCore(uid=uid, observation=observation)
+ response_text = agent.run(cont, uid)
+ util.log(1, "接口调用耗时 :" + str(time.time() - starttime))
+ return response_text
+if __name__ == "__main__":
+ agent = FayAgentCore()
+ print(agent.run("你好"))
diff --git a/llm/agent/tools/DeleteTimer.py b/llm/agent/tools/DeleteTimer.py
new file mode 100644
index 0000000..d92c01c
--- /dev/null
+++ b/llm/agent/tools/DeleteTimer.py
@@ -0,0 +1,41 @@
+import sqlite3
+from typing import Any
+
+from langchain.tools import BaseTool
+
+from llm.agent import agent_service
+
+
+class DeleteTimer(BaseTool):
+ name: str = "DeleteTimer"
+ description: str = "用于删除某一个日程,接受任务id作为参数,如:2"
+
+ def __init__(self):
+ super().__init__()
+
+ def _run(self, para) -> str:
+ try:
+ id = int(para)
+ except ValueError:
+ return "输入的 ID 无效,必须是数字。"
+
+ try:
+ with sqlite3.connect('timer.db') as conn:
+ cursor = conn.cursor()
+ cursor.execute("DELETE FROM timer WHERE id = ?", (id,))
+ conn.commit()
+ except sqlite3.Error as e:
+ return f"数据库错误: {e}"
+
+ if id in agent_service.scheduled_tasks:
+ agent_service.scheduled_tasks[id].cancel()
+ del agent_service.scheduled_tasks[id]
+
+ return f"任务 {id} 取消成功。"
+
+
+
+if __name__ == "__main__":
+ tool = DeleteTimer()
+ result = tool.run("1")
+ print(result)
diff --git a/llm/agent/tools/KnowledgeBaseResponder.py b/llm/agent/tools/KnowledgeBaseResponder.py
new file mode 100644
index 0000000..15e5e2e
--- /dev/null
+++ b/llm/agent/tools/KnowledgeBaseResponder.py
@@ -0,0 +1,100 @@
+import os
+from typing import Any
+
+from langchain.tools import BaseTool
+from langchain_community.document_loaders import PyPDFLoader
+from langchain_community.embeddings.openai import OpenAIEmbeddings
+from langchain.indexes.vectorstore import VectorstoreIndexCreator, VectorStoreIndexWrapper
+from langchain_community.vectorstores.chroma import Chroma
+from langchain_openai import ChatOpenAI
+import hashlib
+#若要使用请自行配置
+os.environ["OPENAI_API_KEY"] = ""
+os.environ["OPENAI_API_BASE"] = "https://api.openai.com/v1"
+index_name = "knowledge_data"
+folder_path = "agent/tools/KnowledgeBaseResponder/knowledge_base"
+local_persist_path = "agent/tools/KnowledgeBaseResponder"
+md5_file_path = os.path.join(local_persist_path, "pdf_md5.txt")
+#
+class KnowledgeBaseResponder(BaseTool):
+ name = "KnowledgeBaseResponder"
+ description = """此工具用于连接本地知识库获取问题答案,使用时请传入相关问题作为参数,例如:“草梅最适合的生长温度”"""
+
+ def __init__(self):
+ super().__init__()
+
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
+ # 用例中没有用到 arun 不予具体实现
+ pass
+
+
+ def _run(self, para: str) -> str:
+ self.save_all()
+ result = self.question(para)
+ return result
+
+ def generate_file_md5(self, file_path):
+ hasher = hashlib.md5()
+ with open(file_path, 'rb') as afile:
+ buf = afile.read()
+ hasher.update(buf)
+ return hasher.hexdigest()
+
+ def load_md5_list(self):
+ if os.path.exists(md5_file_path):
+ with open(md5_file_path, 'r') as file:
+ return {line.split(",")[0]: line.split(",")[1].strip() for line in file}
+ return {}
+
+ def update_md5_list(self, file_name, md5_value):
+ md5_list = self.load_md5_list()
+ md5_list[file_name] = md5_value
+ with open(md5_file_path, 'w') as file:
+ for name, md5 in md5_list.items():
+ file.write(f"{name},{md5}\n")
+
+ def load_all_pdfs(self, folder_path):
+ md5_list = self.load_md5_list()
+ for file_name in os.listdir(folder_path):
+ if file_name.endswith(".pdf"):
+ file_path = os.path.join(folder_path, file_name)
+ file_md5 = self.generate_file_md5(file_path)
+ if file_name not in md5_list or md5_list[file_name] != file_md5:
+ print(f"正在加载 {file_name} 到索引...")
+ self.load_pdf_and_save_to_index(file_path, index_name)
+ self.update_md5_list(file_name, file_md5)
+
+ def get_index_path(self, index_name):
+ return os.path.join(local_persist_path, index_name)
+
+ def load_pdf_and_save_to_index(self, file_path, index_name):
+ loader = PyPDFLoader(file_path)
+ embedding = OpenAIEmbeddings(model="text-embedding-ada-002")
+ index = VectorstoreIndexCreator(embedding=embedding, vectorstore_kwargs={"persist_directory": self.get_index_path(index_name)}).from_loaders([loader])
+ index.vectorstore.persist()
+
+ def load_index(self, index_name):
+ index_path = self.get_index_path(index_name)
+ embedding = OpenAIEmbeddings(model="text-embedding-ada-002")
+ vectordb = Chroma(persist_directory=index_path, embedding_function=embedding)
+ return VectorStoreIndexWrapper(vectorstore=vectordb)
+
+ def save_all(self):
+ self.load_all_pdfs(folder_path)
+
+ def question(self, cont):
+ try:
+ info = cont
+ index = self.load_index(index_name)
+ llm = ChatOpenAI(model="gpt-4-0125-preview")
+ ans = index.query(info, llm, chain_type="map_reduce")
+ return ans
+ except Exception as e:
+ print(f"请求失败: {e}")
+ return "抱歉,我现在太忙了,休息一会,请稍后再试。"
+
+
+if __name__ == "__main__":
+ tool = KnowledgeBaseResponder()
+ info = tool.run("草莓最适合的生长温度")
+ print(info)
diff --git a/llm/agent/tools/KnowledgeBaseResponder/knowledge_base/1.pdf b/llm/agent/tools/KnowledgeBaseResponder/knowledge_base/1.pdf
new file mode 100644
index 0000000..e8f8eb9
--- /dev/null
+++ b/llm/agent/tools/KnowledgeBaseResponder/knowledge_base/1.pdf
@@ -0,0 +1 @@
+
diff --git a/llm/agent/tools/MyTimer.py b/llm/agent/tools/MyTimer.py
new file mode 100644
index 0000000..64bdd7b
--- /dev/null
+++ b/llm/agent/tools/MyTimer.py
@@ -0,0 +1,56 @@
+import abc
+import sqlite3
+import re
+from typing import Any
+from langchain.tools import BaseTool
+
+class MyTimer(BaseTool, abc.ABC):
+ name: str = "MyTimer"
+ description: str = ("用于设置日程。接受3个参数,格式为: HH:MM|YYYYYYY|事项内容,所用标点符号必须为标准的英文字符。"
+ "其中,'HH:MM' 表示时间(24小时制),'YYYYYYY' 表示循环规则(每位代表一天,从星期一至星期日,1为循环,0为不循环,"
+ "如'1000100'代表每周一和周五循环),'事项内容' 是提醒的具体内容。返回例子:15:15|0000000|提醒主人叫咖啡")
+ uid: int = 0
+
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
+ # 用例中没有用到 arun 不予具体实现
+ pass
+
+ def _run(self, para: str) -> str:
+ # 拆分输入字符串
+ parts = para.split("|")
+ if len(parts) != 3:
+ return f"输入格式错误,当前字符串{para} len:{len(parts)}。请按照 HH:MM|YYYYYYY|事项内容 格式提供参数,如:15:15|0000001|提醒主人叫咖啡。"
+
+ time = parts[0].strip("'")
+ repeat_rule = parts[1].strip("'")
+ content = parts[2].strip("'")
+
+ # 验证时间格式
+ if not re.match(r'^[0-2][0-9]:[0-5][0-9]$', time):
+ return "时间格式错误。请按照'HH:MM'格式提供时间。"
+
+ # 验证循环规则格式
+ if not re.match(r'^[01]{7}$', repeat_rule):
+ return "循环规则格式错误。请提供长度为7的0和1组成的字符串。"
+
+ # 验证事项内容
+ if not isinstance(content, str) or not content:
+ return "事项内容必须为非空字符串。"
+
+ # 数据库操作
+ conn = sqlite3.connect('timer.db')
+ cursor = conn.cursor()
+ try:
+ cursor.execute("INSERT INTO timer (time, repeat_rule, content, uid) VALUES (?, ?, ?, ?)", (time, repeat_rule, content, self.uid))
+ conn.commit()
+ except sqlite3.Error as e:
+ return f"数据库错误: {e}"
+ finally:
+ conn.close()
+
+ return "日程设置成功"
+
+if __name__ == "__main__":
+ my_timer = MyTimer()
+ result = my_timer._run("15:15|0000001|提醒主人叫咖啡")
+ print(result)
diff --git a/llm/agent/tools/PythonExecutor.py b/llm/agent/tools/PythonExecutor.py
new file mode 100644
index 0000000..9e7a34e
--- /dev/null
+++ b/llm/agent/tools/PythonExecutor.py
@@ -0,0 +1,42 @@
+import os
+from typing import Any, Dict
+import subprocess
+import tempfile
+from langchain.tools import BaseTool
+
+class PythonExecutor(BaseTool):
+ name: str = "python_executor"
+ description: str = "此工具用于执行传入的 Python 代码片段,并返回执行结果"
+
+ def __init__(self):
+ super().__init__()
+
+ def _run(self, code: str) -> str:
+ if not code:
+ return "代码不能为空"
+
+ try:
+ # 创建临时文件以写入代码
+ with tempfile.NamedTemporaryFile(suffix=".py", delete=False) as tmpfile:
+ tmpfile_path = tmpfile.name
+ tmpfile.write(code.encode())
+
+ # 使用 subprocess 执行 Python 代码文件
+ result = subprocess.run(['python', tmpfile_path], capture_output=True, text=True)
+ os.remove(tmpfile_path) # 删除临时文件
+
+ if result.returncode == 0:
+ return f"执行成功:\n{result.stdout}"
+ else:
+ return f"执行失败,错误信息:\n{result.stderr}"
+
+ except Exception as e:
+ return f"执行代码时发生错误:{str(e)}"
+
+if __name__ == "__main__":
+ python_executor = PythonExecutor()
+ code_snippet = """
+print("Hello, world!")
+"""
+ execution_result = python_executor.run(code_snippet)
+ print(execution_result)
diff --git a/llm/agent/tools/QueryTime.py b/llm/agent/tools/QueryTime.py
new file mode 100644
index 0000000..194e506
--- /dev/null
+++ b/llm/agent/tools/QueryTime.py
@@ -0,0 +1,46 @@
+import abc
+import math
+from typing import Any
+from datetime import datetime
+from langchain.tools import BaseTool
+
+class QueryTime(BaseTool, abc.ABC):
+ name: str = "QueryTime"
+ description: str = "用于查询当前日期、星期几及时间"
+
+ def __init__(self):
+ super().__init__()
+
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
+ # 用例中没有用到 arun 不予具体实现
+ pass
+
+ def _run(self, para) -> str:
+ # 获取当前时间
+ now = datetime.now()
+ # 获取当前日期
+ today = now.date()
+ # 获取星期几的信息
+ week_day = today.strftime("%A")
+ # 将星期几的英文名称转换为中文
+ week_day_zh = {
+ "Monday": "星期一",
+ "Tuesday": "星期二",
+ "Wednesday": "星期三",
+ "Thursday": "星期四",
+ "Friday": "星期五",
+ "Saturday": "星期六",
+ "Sunday": "星期日",
+ }.get(week_day, "未知")
+ # 将日期格式化为字符串
+ date_str = today.strftime("%Y年%m月%d日")
+
+ # 将时间格式化为字符串
+ time_str = now.strftime("%H:%M")
+
+ return "现在时间是:{0} {1} {2}".format(time_str, week_day_zh, date_str)
+
+if __name__ == "__main__":
+ tool = QueryTime()
+ result = tool.run("")
+ print(result)
diff --git a/llm/agent/tools/QueryTimerDB.py b/llm/agent/tools/QueryTimerDB.py
new file mode 100644
index 0000000..3018488
--- /dev/null
+++ b/llm/agent/tools/QueryTimerDB.py
@@ -0,0 +1,41 @@
+import abc
+import sqlite3
+from typing import Any
+import ast
+
+
+from langchain.tools import BaseTool
+
+
+class QueryTimerDB(BaseTool, abc.ABC):
+ name: str = "QueryTimerDB"
+ description: str = "用于查询所有日程,返回的数据里包含3个参数:时间、循环规则(如:'1000100'代表星期一和星期五循环,'0000000'代表不循环)、执行的事项"
+
+ def __init__(self):
+ super().__init__()
+
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
+ # 用例中没有用到 arun 不予具体实现
+ pass
+
+
+ def _run(self, para) -> str:
+ conn = sqlite3.connect('timer.db')
+ cursor = conn.cursor()
+ # 执行查询
+ cursor.execute("SELECT * FROM timer")
+ # 获取所有记录
+ rows = cursor.fetchall()
+ # 拼接结果
+ result = ""
+ for row in rows:
+ result = result + str(row) + "\n"
+ conn.commit()
+ conn.close()
+ return result
+
+
+if __name__ == "__main__":
+ tool = QueryTimerDB()
+ result = tool.run("")
+ print(result)
diff --git a/llm/agent/tools/SendToPanel.py b/llm/agent/tools/SendToPanel.py
new file mode 100644
index 0000000..fb3fdc1
--- /dev/null
+++ b/llm/agent/tools/SendToPanel.py
@@ -0,0 +1,26 @@
+import abc
+from typing import Any
+from langchain.tools import BaseTool
+import fay_booter
+
+class SendToPanel(BaseTool, abc.ABC):
+ name = "SendToPanel"
+ description = "用于给主人面板发送消息,使用时请传入消息内容作为参数。"
+
+ def __init__(self):
+ super().__init__()
+
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
+ # 用例中没有用到 arun 不予具体实现
+ pass
+
+ def _run(self, para) -> str:
+ fay_booter.feiFei.send_to_panel(para)
+ return "成功给主人,发送消息:{}".format(para)
+
+
+
+if __name__ == "__main__":
+ tool = SendToPanel()
+ result = tool.run("归纳一下近年关于“经济发展”的论文的特点和重点")
+ print(result)
diff --git a/llm/agent/tools/SendWX.py b/llm/agent/tools/SendWX.py
new file mode 100644
index 0000000..ccf9c5d
--- /dev/null
+++ b/llm/agent/tools/SendWX.py
@@ -0,0 +1,31 @@
+import abc
+from typing import Any
+from langchain.tools import BaseTool
+import requests
+import json
+
+url = "http://127.0.0.1:4008/send"
+headers = {'Content-Type': 'application/json'}
+data = {
+ "message": "你好",
+ "receiver": "@2efc4e10cf2eafd0b0125930e4b96ed0cebffa75b2fd272590e38763225a282b"
+}
+
+
+class SendWX(BaseTool, abc.ABC):
+ name = "SendWX"
+ description = "给主人微信发送消息,传入参数是:('消息内容')"
+
+ def __init__(self):
+ super().__init__()
+
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
+ # 用例中没有用到 arun 不予具体实现
+ pass
+
+ def _run(self, para) -> str:
+ global data
+ data['message'] = para
+ response = requests.post(url, headers=headers, data=json.dumps(data))
+ return "成功给主人,发送微信消息:{}".format(para)
+
diff --git a/llm/agent/tools/ToRemind.py b/llm/agent/tools/ToRemind.py
new file mode 100644
index 0000000..43e4d1b
--- /dev/null
+++ b/llm/agent/tools/ToRemind.py
@@ -0,0 +1,33 @@
+import abc
+from typing import Any
+from langchain.tools import BaseTool
+import re
+import random
+class ToRemind(BaseTool, abc.ABC):
+ name: str = "ToRemind"
+ description: str = ("用于实时发送信息提醒主人做某事项(不能带时间),传入事项内容作为参数。")
+
+ def __init__(self):
+ super().__init__()
+
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
+ # 用例中没有用到 arun 不予具体实现
+ pass
+
+ def _run(self, para: str) -> str:
+
+ para = para.replace("提醒", "回复")
+ demo = [
+ "主人!是时候(事项内容)了喔~",
+ "亲爱的主人,现在是(事项内容)的时候啦!",
+ "嘿,主人,该(事项内容)了哦~",
+ "温馨提醒:(事项内容)的时间到啦,主人!",
+ "小提醒:主人,现在可以(事项内容)了~"
+ ]
+
+ return f"直接以中文友善{para},如"+ random.choice(demo)
+
+if __name__ == "__main__":
+ my_timer = ToRemind()
+ result = my_timer._run("提醒主人叫咖啡")
+ print(result)
diff --git a/llm/agent/tools/Weather.py b/llm/agent/tools/Weather.py
new file mode 100644
index 0000000..f94c723
--- /dev/null
+++ b/llm/agent/tools/Weather.py
@@ -0,0 +1,53 @@
+import os
+from typing import Any
+
+import requests
+from langchain.tools import BaseTool
+from urllib.parse import quote
+
+class Weather(BaseTool):
+ name: str = "weather"
+ description: str = "此工具用于获取天气预报信息,需传入英文的城市名,参数格式:Guangzhou"
+
+ def __init__(self):
+ super().__init__()
+
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
+ # 用例中没有用到 arun 不予具体实现
+ pass
+
+
+ def _run(self, para: str) -> str:
+ try:
+ if not para:
+ return "参数不能为空"
+ encoded_city = quote(para)
+
+ api_url = f"http://api.openweathermap.org/data/2.5/weather?q={encoded_city}&appid=272fcb70d2c4e6f5134c2dce7d091df6"
+ response = requests.get(api_url)
+ if response.status_code == 200:
+ weather_data = response.json()
+ # 提取天气信息
+ temperature_kelvin = weather_data['main']['temp']
+ temperature_celsius = temperature_kelvin - 273.15
+ min_temperature_kelvin = weather_data['main']['temp_min']
+ max_temperature_kelvin = weather_data['main']['temp_max']
+ min_temperature_celsius = min_temperature_kelvin - 273.15
+ max_temperature_celsius = max_temperature_kelvin - 273.15
+ description = weather_data['weather'][0]['description']
+ wind_speed = weather_data['wind']['speed']
+
+ # 构建天气描述
+ weather_description = f"今天天气:{description},气温:{temperature_celsius:.2f}摄氏度,风速:{wind_speed} m/s。"
+
+ return f"天气预报信息:{weather_description}"
+ else:
+ return f"无法获取天气预报信息,状态码:{response.status_code}"
+ except Exception as e:
+ return f"发生错误:{str(e)}"
+
+
+if __name__ == "__main__":
+ weather_tool = Weather()
+ weather_info = weather_tool.run("Guangzhou")
+ print(weather_info)
diff --git a/llm/agent/tools/WebPageRetriever.py b/llm/agent/tools/WebPageRetriever.py
new file mode 100644
index 0000000..29f135d
--- /dev/null
+++ b/llm/agent/tools/WebPageRetriever.py
@@ -0,0 +1,42 @@
+import abc
+from typing import Any
+from langchain.tools import BaseTool
+import requests
+
+class WebPageRetriever(BaseTool, abc.ABC):
+ name: str = "WebPageRetriever"
+ description: str = "专门用于通过Bing搜索API快速检索和获取与特定查询词条相关的网页信息。使用时请传入需要查询的关键词作为参数。"
+
+ def __init__(self):
+ super().__init__()
+
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
+ # 用例中没有用到 arun 不予具体实现
+ pass
+
+ def _run(self, para) -> str:
+ query = para
+ subscription_key = ""#请自行进行补充
+ if not subscription_key:
+ print("请填写bing v7的subscription_key")
+ return '请填写bing v7的subscription_key'
+
+ url = "https://api.bing.microsoft.com/v7.0/search"
+ headers = {'Ocp-Apim-Subscription-Key': subscription_key}
+ params = {'q': query, 'mkt': 'en-US'}
+
+ try:
+ response = requests.get(url, headers=headers, params=params)
+ response.raise_for_status()
+ data = response.json()
+ web_pages = data.get('webPages', {})
+ return web_pages
+ except Exception as e:
+ print("Http Error:", e)
+ return 'bing v7查询有误'
+
+
+if __name__ == "__main__":
+ tool = WebPageRetriever()
+ result = tool.run("归纳一下近年关于“经济发展”的论文的特点和重点")
+ print(result)
diff --git a/llm/agent/tools/WebPageScraper.py b/llm/agent/tools/WebPageScraper.py
new file mode 100644
index 0000000..105c6a3
--- /dev/null
+++ b/llm/agent/tools/WebPageScraper.py
@@ -0,0 +1,35 @@
+from bs4 import BeautifulSoup
+import abc
+from typing import Any
+from langchain.tools import BaseTool
+import requests
+
+class WebPageScraper(BaseTool, abc.ABC):
+ name: str = "WebPageScraper"
+ description: str = "此工具用于获取网页内容,使用时请传入需要查询的网页地址作为参数,如:https://www.baidu.com/。"
+
+ def __init__(self):
+ super().__init__()
+
+ async def _arun(self, *args: Any, **kwargs: Any) -> Any:
+ # 用例中没有用到 arun 不予具体实现
+ pass
+
+ def _run(self, para) -> str:
+ headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}
+ try:
+ response = requests.get(para, headers=headers, timeout=10, verify=True)
+ soup = BeautifulSoup(response.text, 'html.parser')
+ return soup
+ except requests.exceptions.SSLCertVerificationError:
+ return 'SSL证书验证失败'
+ except requests.exceptions.Timeout:
+ return '请求超时'
+ except Exception as e:
+ print("Http Error:", e)
+ return '无法获取该网页内容'
+
+if __name__ == "__main__":
+ tool = WebPageScraper()
+ result = tool.run("https://book.douban.com/review/14636204")
+ print(result)
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 7b3707f..42dbfca 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -17,11 +17,14 @@ pytz
gevent~=22.10.1
edge_tts
pydub
-langchain==0.0.336
chromadb
tenacity==8.2.3
pygame
scipy
flask-httpauth
opencv-python
-psutil
\ No newline at end of file
+psutil
+langchain
+langchain_openai
+langgraph
+langchain-community
\ No newline at end of file
diff --git a/system.conf b/system.conf
index 8068cba..c1fbc84 100644
--- a/system.conf
+++ b/system.conf
@@ -43,7 +43,7 @@ baidu_emotion_secret_key=
-#NLP多选一:lingju、gpt、rasa、VisualGLM、rwkv、xingchen、langchain 、ollama_api、privategpt、coze
+#NLP多选一:agent、lingju、gpt、rasa、VisualGLM、rwkv、xingchen、langchain 、ollama_api、privategpt、coze
chat_module= gpt
#灵聚 服务密钥(NLP多选1) https://open.lingju.ai
diff --git a/test/test_langchain.ipynb b/test/test_langchain.ipynb
new file mode 100644
index 0000000..7217c00
--- /dev/null
+++ b/test/test_langchain.ipynb
@@ -0,0 +1,715 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "1、安装依赖。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Requirement already satisfied: langchain in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (0.3.7)\n",
+ "Requirement already satisfied: langchain-openai in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (0.2.6)\n",
+ "Collecting langchain-openai\n",
+ " Downloading langchain_openai-0.2.8-py3-none-any.whl.metadata (2.6 kB)\n",
+ "Requirement already satisfied: langgraph in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (0.2.45)\n",
+ "Collecting langgraph\n",
+ " Downloading langgraph-0.2.50-py3-none-any.whl.metadata (15 kB)\n",
+ "Requirement already satisfied: langsmith in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (0.1.142)\n",
+ "Collecting langsmith\n",
+ " Downloading langsmith-0.1.143-py3-none-any.whl.metadata (13 kB)\n",
+ "Requirement already satisfied: PyYAML>=5.3 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain) (6.0.2)\n",
+ "Requirement already satisfied: SQLAlchemy<3,>=1.4 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain) (2.0.35)\n",
+ "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain) (3.10.10)\n",
+ "Requirement already satisfied: langchain-core<0.4.0,>=0.3.15 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain) (0.3.15)\n",
+ "Requirement already satisfied: langchain-text-splitters<0.4.0,>=0.3.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain) (0.3.2)\n",
+ "Requirement already satisfied: numpy<2.0.0,>=1.26.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain) (1.26.4)\n",
+ "Requirement already satisfied: pydantic<3.0.0,>=2.7.4 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain) (2.9.2)\n",
+ "Requirement already satisfied: requests<3,>=2 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain) (2.32.3)\n",
+ "Requirement already satisfied: tenacity!=8.4.0,<10,>=8.1.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain) (8.2.3)\n",
+ "Collecting langchain-core<0.4.0,>=0.3.15 (from langchain)\n",
+ " Downloading langchain_core-0.3.19-py3-none-any.whl.metadata (6.3 kB)\n",
+ "Requirement already satisfied: openai<2.0.0,>=1.54.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain-openai) (1.54.3)\n",
+ "Requirement already satisfied: tiktoken<1,>=0.7 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain-openai) (0.8.0)\n",
+ "Collecting langgraph-checkpoint<3.0.0,>=2.0.4 (from langgraph)\n",
+ " Downloading langgraph_checkpoint-2.0.4-py3-none-any.whl.metadata (4.6 kB)\n",
+ "Requirement already satisfied: langgraph-sdk<0.2.0,>=0.1.32 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langgraph) (0.1.35)\n",
+ "Requirement already satisfied: httpx<1,>=0.23.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langsmith) (0.27.2)\n",
+ "Requirement already satisfied: orjson<4.0.0,>=3.9.14 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langsmith) (3.10.11)\n",
+ "Requirement already satisfied: requests-toolbelt<2.0.0,>=1.0.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langsmith) (1.0.0)\n",
+ "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (2.4.3)\n",
+ "Requirement already satisfied: aiosignal>=1.1.2 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.3.1)\n",
+ "Requirement already satisfied: attrs>=17.3.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (24.2.0)\n",
+ "Requirement already satisfied: frozenlist>=1.1.1 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.5.0)\n",
+ "Requirement already satisfied: multidict<7.0,>=4.5 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (6.1.0)\n",
+ "Requirement already satisfied: yarl<2.0,>=1.12.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.17.1)\n",
+ "Requirement already satisfied: anyio in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith) (4.6.2.post1)\n",
+ "Requirement already satisfied: certifi in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith) (2024.8.30)\n",
+ "Requirement already satisfied: httpcore==1.* in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith) (1.0.6)\n",
+ "Requirement already satisfied: idna in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith) (3.10)\n",
+ "Requirement already satisfied: sniffio in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from httpx<1,>=0.23.0->langsmith) (1.3.1)\n",
+ "Requirement already satisfied: h11<0.15,>=0.13 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from httpcore==1.*->httpx<1,>=0.23.0->langsmith) (0.14.0)\n",
+ "Requirement already satisfied: jsonpatch<2.0,>=1.33 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.15->langchain) (1.33)\n",
+ "Requirement already satisfied: packaging<25,>=23.2 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.15->langchain) (24.1)\n",
+ "Requirement already satisfied: typing-extensions>=4.7 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langchain-core<0.4.0,>=0.3.15->langchain) (4.12.2)\n",
+ "Requirement already satisfied: msgpack<2.0.0,>=1.1.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langgraph-checkpoint<3.0.0,>=2.0.4->langgraph) (1.1.0)\n",
+ "Requirement already satisfied: httpx-sse>=0.4.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from langgraph-sdk<0.2.0,>=0.1.32->langgraph) (0.4.0)\n",
+ "Requirement already satisfied: distro<2,>=1.7.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from openai<2.0.0,>=1.54.0->langchain-openai) (1.9.0)\n",
+ "Requirement already satisfied: jiter<1,>=0.4.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from openai<2.0.0,>=1.54.0->langchain-openai) (0.7.0)\n",
+ "Requirement already satisfied: tqdm>4 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from openai<2.0.0,>=1.54.0->langchain-openai) (4.67.0)\n",
+ "Requirement already satisfied: annotated-types>=0.6.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from pydantic<3.0.0,>=2.7.4->langchain) (0.7.0)\n",
+ "Requirement already satisfied: pydantic-core==2.23.4 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from pydantic<3.0.0,>=2.7.4->langchain) (2.23.4)\n",
+ "Requirement already satisfied: charset-normalizer<4,>=2 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from requests<3,>=2->langchain) (3.4.0)\n",
+ "Requirement already satisfied: urllib3<3,>=1.21.1 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from requests<3,>=2->langchain) (2.2.3)\n",
+ "Requirement already satisfied: greenlet!=0.4.17 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from SQLAlchemy<3,>=1.4->langchain) (3.1.1)\n",
+ "Requirement already satisfied: regex>=2022.1.18 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from tiktoken<1,>=0.7->langchain-openai) (2024.11.6)\n",
+ "Requirement already satisfied: jsonpointer>=1.9 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from jsonpatch<2.0,>=1.33->langchain-core<0.4.0,>=0.3.15->langchain) (3.0.0)\n",
+ "Requirement already satisfied: colorama in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from tqdm>4->openai<2.0.0,>=1.54.0->langchain-openai) (0.4.6)\n",
+ "Requirement already satisfied: propcache>=0.2.0 in d:\\anaconda3\\envs\\fay312-2\\lib\\site-packages (from yarl<2.0,>=1.12.0->aiohttp<4.0.0,>=3.8.3->langchain) (0.2.0)\n",
+ "Downloading langchain_openai-0.2.8-py3-none-any.whl (50 kB)\n",
+ "Downloading langgraph-0.2.50-py3-none-any.whl (124 kB)\n",
+ "Downloading langsmith-0.1.143-py3-none-any.whl (306 kB)\n",
+ "Downloading langchain_core-0.3.19-py3-none-any.whl (409 kB)\n",
+ "Downloading langgraph_checkpoint-2.0.4-py3-none-any.whl (23 kB)\n",
+ "Installing collected packages: langsmith, langchain-core, langgraph-checkpoint, langchain-openai, langgraph\n",
+ " Attempting uninstall: langsmith\n",
+ " Found existing installation: langsmith 0.1.142\n",
+ " Uninstalling langsmith-0.1.142:\n",
+ " Successfully uninstalled langsmith-0.1.142\n",
+ " Attempting uninstall: langchain-core\n",
+ " Found existing installation: langchain-core 0.3.15\n",
+ " Uninstalling langchain-core-0.3.15:\n",
+ " Successfully uninstalled langchain-core-0.3.15\n",
+ " Attempting uninstall: langgraph-checkpoint\n",
+ " Found existing installation: langgraph-checkpoint 2.0.2\n",
+ " Uninstalling langgraph-checkpoint-2.0.2:\n",
+ " Successfully uninstalled langgraph-checkpoint-2.0.2\n",
+ " Attempting uninstall: langchain-openai\n",
+ " Found existing installation: langchain-openai 0.2.6\n",
+ " Uninstalling langchain-openai-0.2.6:\n",
+ " Successfully uninstalled langchain-openai-0.2.6\n",
+ " Attempting uninstall: langgraph\n",
+ " Found existing installation: langgraph 0.2.45\n",
+ " Uninstalling langgraph-0.2.45:\n",
+ " Successfully uninstalled langgraph-0.2.45\n",
+ "Successfully installed langchain-core-0.3.19 langchain-openai-0.2.8 langgraph-0.2.50 langgraph-checkpoint-2.0.4 langsmith-0.1.143\n"
+ ]
+ }
+ ],
+ "source": [
+ "!pip install -U langchain langchain-openai langgraph langsmith"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "2、配置环境变量。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "\n",
+ "os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
+ "os.environ[\"LANGCHAIN_ENDPOINT\"] = \"https://api.smith.langchain.com\"\n",
+ "os.environ[\"LANGCHAIN_API_KEY\"] = \"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\"\n",
+ "os.environ[\"LANGCHAIN_PROJECT\"] = \"pr-best-artist-21\"\n",
+ "\n",
+ "os.environ[\"OPENAI_API_KEY\"] = \"sk-\"\n",
+ "os.environ[\"OPENAI_API_BASE\"] = \"\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "3、定义llm model。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Hello! How can I assist you today?'"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from langchain_openai import ChatOpenAI\n",
+ "llm = ChatOpenAI()\n",
+ "llm.invoke(\"Hello, world!\").content#test"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "4、定义工具。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "现在时间是:16:12 星期日 2024年11月17日\n"
+ ]
+ }
+ ],
+ "source": [
+ "import abc\n",
+ "from typing import Any\n",
+ "from datetime import datetime\n",
+ "from langchain.tools import BaseTool\n",
+ "\n",
+ "class QueryTime(BaseTool, abc.ABC):\n",
+ " name: str = \"QueryTime\"\n",
+ " description: str = \"用于查询当前日期、星期几及时间\" \n",
+ "\n",
+ " def __init__(self):\n",
+ " super().__init__()\n",
+ "\n",
+ " async def _arun(self, *args: Any, **kwargs: Any) -> Any:\n",
+ " # 用例中没有用到 arun,不予具体实现\n",
+ " pass\n",
+ "\n",
+ " def _run(self, para) -> str:\n",
+ " # 获取当前时间\n",
+ " now = datetime.now()\n",
+ " # 获取当前日期\n",
+ " today = now.date()\n",
+ " # 获取星期几的信息\n",
+ " week_day = today.strftime(\"%A\")\n",
+ " # 将星期几的英文名称转换为中文\n",
+ " week_day_zh = {\n",
+ " \"Monday\": \"星期一\",\n",
+ " \"Tuesday\": \"星期二\",\n",
+ " \"Wednesday\": \"星期三\",\n",
+ " \"Thursday\": \"星期四\",\n",
+ " \"Friday\": \"星期五\",\n",
+ " \"Saturday\": \"星期六\",\n",
+ " \"Sunday\": \"星期日\",\n",
+ " }.get(week_day, \"未知\")\n",
+ " # 将日期格式化为字符串\n",
+ " date_str = today.strftime(\"%Y年%m月%d日\")\n",
+ " # 将时间格式化为字符串\n",
+ " time_str = now.strftime(\"%H:%M\")\n",
+ "\n",
+ " return f\"现在时间是:{time_str} {week_day_zh} {date_str}\"\n",
+ "\n",
+ "if __name__ == \"__main__\":\n",
+ " tool = QueryTime()\n",
+ " result = tool.run(\"\")\n",
+ " print(result)\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "天气预报信息:今天天气:broken clouds,气温:29.97摄氏度,风速:4.4 m/s。\n"
+ ]
+ }
+ ],
+ "source": [
+ "from typing import Any\n",
+ "\n",
+ "import requests\n",
+ "from langchain.tools import BaseTool\n",
+ "from urllib.parse import quote\n",
+ "\n",
+ "class Weather(BaseTool):\n",
+ " name: str = \"weather\"\n",
+ " description: str = \"此工具用于获取天气预报信息,需传入英文的城市名,参数格式:Guangzhou\"\n",
+ "\n",
+ " def __init__(self):\n",
+ " super().__init__()\n",
+ "\n",
+ " async def _arun(self, *args: Any, **kwargs: Any) -> Any:\n",
+ " # 用例中没有用到 arun 不予具体实现\n",
+ " pass\n",
+ "\n",
+ "\n",
+ " def _run(self, para: str) -> str:\n",
+ " try:\n",
+ " if not para:\n",
+ " return \"参数不能为空\"\n",
+ " encoded_city = quote(para)\n",
+ "\n",
+ " api_url = f\"http://api.openweathermap.org/data/2.5/weather?q={encoded_city}&appid=272fcb70d2c4e6f5134c2dce7d091df6\"\n",
+ " response = requests.get(api_url)\n",
+ " if response.status_code == 200:\n",
+ " weather_data = response.json()\n",
+ " # 提取天气信息\n",
+ " temperature_kelvin = weather_data['main']['temp']\n",
+ " temperature_celsius = temperature_kelvin - 273.15\n",
+ " min_temperature_kelvin = weather_data['main']['temp_min']\n",
+ " max_temperature_kelvin = weather_data['main']['temp_max']\n",
+ " min_temperature_celsius = min_temperature_kelvin - 273.15\n",
+ " max_temperature_celsius = max_temperature_kelvin - 273.15\n",
+ " description = weather_data['weather'][0]['description']\n",
+ " wind_speed = weather_data['wind']['speed']\n",
+ "\n",
+ " # 构建天气描述\n",
+ " weather_description = f\"今天天气:{description},气温:{temperature_celsius:.2f}摄氏度,风速:{wind_speed} m/s。\"\n",
+ "\n",
+ " return f\"天气预报信息:{weather_description}\"\n",
+ " else:\n",
+ " return f\"无法获取天气预报信息,状态码:{response.status_code}\"\n",
+ " except Exception as e:\n",
+ " return f\"发生错误:{str(e)}\"\n",
+ "\n",
+ "\n",
+ "if __name__ == \"__main__\":\n",
+ " weather_tool = Weather()\n",
+ " weather_info = weather_tool.run(\"Guangzhou\")\n",
+ " print(weather_info)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "5、创建agent graph。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from langgraph.checkpoint.memory import MemorySaver\n",
+ "from langgraph.prebuilt import create_react_agent\n",
+ "\n",
+ "memory = MemorySaver()\n",
+ "tools = [QueryTime(), Weather()]\n",
+ "agent_graph = create_react_agent(llm, tools, checkpointer=memory)\n",
+ "\n",
+ "#memeory上用于分块\n",
+ "config = {\"configurable\": {\"thread_id\": \"abc123\"}}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "6、查看agent graph。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from IPython.display import Image, display\n",
+ "\n",
+ "try:\n",
+ " display(Image(agent_graph.get_graph().draw_mermaid_png()))\n",
+ "except Exception:\n",
+ " # This requires some extra dependencies and is optional\n",
+ " pass"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "7、执行。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 31,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "你好\n",
+ "你好,张三!有什么我可以帮助你的吗?如果你有任何问题或者想聊天,随时告诉我!\n"
+ ]
+ }
+ ],
+ "source": [
+ "from langchain_core.messages import HumanMessage, SystemMessage\n",
+ "events = agent_graph.stream(\n",
+ " {\"messages\": [SystemMessage(\"你的名字叫张三,18岁。\"), HumanMessage(content=\"你好\", name=\"User\")]}, config, stream_mode=\"values\"\n",
+ ")\n",
+ "for event in events:\n",
+ " if \"messages\" in event:\n",
+ " print(event[\"messages\"][-1].content)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'agent': {'messages': [AIMessage(content='请问您具体想了解什么呢?我可以提供天气预报、时间日期等信息。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 89, 'total_tokens': 111, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-4ddeb38a-9300-440d-8138-c279fa2c5097-0', usage_metadata={'input_tokens': 89, 'output_tokens': 22, 'total_tokens': 111, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}}\n",
+ "请问您具体想了解什么呢?我可以提供天气预报、时间日期等信息。\n",
+ "token使用:111\n",
+ "----\n"
+ ]
+ }
+ ],
+ "source": [
+ "\n",
+ "for chunk in agent_executor.stream(\n",
+ " {\"messages\": [HumanMessage(content=\"还有吗\", name=\"User\")]}, {\"configurable\": {\"thread_id\": \"abc123\"}}\n",
+ "):\n",
+ " print(chunk)\n",
+ " if chunk.get(\"agent\"):\n",
+ " if chunk['agent']['messages'][0].content:\n",
+ " print(chunk['agent']['messages'][0].content)\n",
+ " else:\n",
+ " print(\"现在调用{}工具\".format(chunk['agent']['messages'][0].additional_kwargs['tool_calls'][0]['function']['name']))\n",
+ " print(\"token使用:{}\".format(chunk['agent']['messages'][0].response_metadata['token_usage']['total_tokens']))\n",
+ "\n",
+ " print(\"----\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "8、测试记忆机制。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[HumanMessage(content='还有吗', additional_kwargs={}, response_metadata={}, name='User', id='f466081a-e840-42f7-ac2c-c9465dfe658d'),\n",
+ " AIMessage(content='请问您具体想了解什么呢?我可以提供天气预报、时间日期等信息。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 89, 'total_tokens': 111, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-4ddeb38a-9300-440d-8138-c279fa2c5097-0', usage_metadata={'input_tokens': 89, 'output_tokens': 22, 'total_tokens': 111, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='你好吗', additional_kwargs={}, response_metadata={}, name='User'),\n",
+ " AIMessage(content='你好吗', additional_kwargs={}, response_metadata={})]"
+ ]
+ },
+ "execution_count": 16,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from langchain_core.messages import HumanMessage, AIMessage\n",
+ "snapshot = agent_executor.get_state(config)\n",
+ "existing_messages = snapshot.values[\"messages\"]\n",
+ "existing_messages.append(HumanMessage(content=\"你叫什么名字?\", name=\"User\"))\n",
+ "existing_messages.append(AIMessage(\"我叫fay\"))\n",
+ "existing_messages#.pretty_print()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'configurable': {'thread_id': 'abc123',\n",
+ " 'checkpoint_ns': '',\n",
+ " 'checkpoint_id': '1efa4b9f-bff1-6823-8002-f65425e81a5d'}}"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "agent_executor.update_state(config, {\"messages\": existing_messages})"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[HumanMessage(content='还有吗', additional_kwargs={}, response_metadata={}, name='User', id='f466081a-e840-42f7-ac2c-c9465dfe658d'),\n",
+ " AIMessage(content='请问您具体想了解什么呢?我可以提供天气预报、时间日期等信息。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 89, 'total_tokens': 111, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-4ddeb38a-9300-440d-8138-c279fa2c5097-0', usage_metadata={'input_tokens': 89, 'output_tokens': 22, 'total_tokens': 111, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='你好吗', additional_kwargs={}, response_metadata={}, name='User', id='e509be56-3442-4648-ad9a-cee13bca82f0'),\n",
+ " AIMessage(content='你好吗', additional_kwargs={}, response_metadata={}, id='575b7cbd-bd07-4e88-aed2-d29d7602b6e4')]"
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "snapshot = agent_executor.get_state(config)\n",
+ "existing_messages = snapshot.values[\"messages\"]\n",
+ "existing_messages"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "StateSnapshot(values={'messages': [HumanMessage(content='还有吗', additional_kwargs={}, response_metadata={}, name='User', id='f466081a-e840-42f7-ac2c-c9465dfe658d'), AIMessage(content='请问您具体想了解什么呢?我可以提供天气预报、时间日期等信息。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 89, 'total_tokens': 111, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-4ddeb38a-9300-440d-8138-c279fa2c5097-0', usage_metadata={'input_tokens': 89, 'output_tokens': 22, 'total_tokens': 111, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}, next=(), config={'configurable': {'thread_id': 'abc123', 'checkpoint_ns': '', 'checkpoint_id': '1efa3c92-a44b-6f14-8001-e40ae3f48e95'}}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='请问您具体想了解什么呢?我可以提供天气预报、时间日期等信息。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 89, 'total_tokens': 111, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-4ddeb38a-9300-440d-8138-c279fa2c5097-0', usage_metadata={'input_tokens': 89, 'output_tokens': 22, 'total_tokens': 111, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]}}, 'thread_id': 'abc123', 'step': 1, 'parents': {}}, created_at='2024-11-16T03:16:26.467714+00:00', parent_config={'configurable': {'thread_id': 'abc123', 'checkpoint_ns': '', 'checkpoint_id': '1efa3c92-921f-6959-8000-39ede570ea4c'}}, tasks=())"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "snapshot"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "dict"
+ ]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "type(memory.get_tuple(config).checkpoint)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 50,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'v': 1,\n",
+ " 'ts': '2024-11-15T08:21:08.671329+00:00',\n",
+ " 'id': '1efa32a9-0e5e-61cf-801f-fee8f6f6d005',\n",
+ " 'channel_values': {'messages': [HumanMessage(content='现在什么时间,广州天气怎么样', additional_kwargs={}, response_metadata={}, name='User', id='e26e51c3-2a22-4997-b8c4-c8354192aeea'),\n",
+ " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Sga9wIgaKZ8ZtZRzHvlIdbz1', 'function': {'arguments': '{\"para\": {}}', 'name': 'QueryTime'}, 'type': 'function'}, {'id': 'call_YyxTGWDjmKnRMLICROzdqBfe', 'function': {'arguments': '{\"para\": \"Guangzhou\"}', 'name': 'weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 45, 'prompt_tokens': 94, 'total_tokens': 139, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-366f5601-27ef-4238-8928-e7a74218a560-0', tool_calls=[{'name': 'QueryTime', 'args': {'para': {}}, 'id': 'call_Sga9wIgaKZ8ZtZRzHvlIdbz1', 'type': 'tool_call'}, {'name': 'weather', 'args': {'para': 'Guangzhou'}, 'id': 'call_YyxTGWDjmKnRMLICROzdqBfe', 'type': 'tool_call'}], usage_metadata={'input_tokens': 94, 'output_tokens': 45, 'total_tokens': 139, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " ToolMessage(content='现在时间是:15:35 星期五 2024年11月15日', name='QueryTime', id='18e008ef-b0a6-4dcc-9ade-20f88a349a07', tool_call_id='call_Sga9wIgaKZ8ZtZRzHvlIdbz1'),\n",
+ " ToolMessage(content='天气预报信息:今天天气:overcast clouds,气温:24.97摄氏度,风速:1.64 m/s。', name='weather', id='5e0da87a-8f24-4652-9c4b-fde489ec3812', tool_call_id='call_YyxTGWDjmKnRMLICROzdqBfe'),\n",
+ " AIMessage(content='现在时间是:15:35,星期五,2024年11月15日。\\n\\n广州的天气预报信息:今天天气为阴云,气温为24.97摄氏度,风速为1.64米/秒。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 53, 'prompt_tokens': 296, 'total_tokens': 349, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-d5eaf7a8-ad14-4e2e-b31d-caa45a58901c-0', usage_metadata={'input_tokens': 296, 'output_tokens': 53, 'total_tokens': 349, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='你好', additional_kwargs={}, response_metadata={}, name='User', id='8fc0dbed-ab1a-4e5d-b7fe-d4d5784ac463'),\n",
+ " AIMessage(content='你好!有什么我可以帮助你的吗?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 360, 'total_tokens': 370, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-ce3076b5-a8cc-4653-aa31-2d895339ba67-0', usage_metadata={'input_tokens': 360, 'output_tokens': 10, 'total_tokens': 370, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='你知道我在那里吗', additional_kwargs={}, response_metadata={}, name='User', id='cf569e60-e19b-4ded-8247-33a080071353'),\n",
+ " AIMessage(content='我无法直接知道你的位置,但可以根据你提供的信息来帮助你。如果你告诉我你所在的城市或地区,我可以为你提供相关的天气、新闻或其他信息。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 40, 'prompt_tokens': 384, 'total_tokens': 424, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-c4be7ab9-8ac5-44be-b2ef-a510173e9213-0', usage_metadata={'input_tokens': 384, 'output_tokens': 40, 'total_tokens': 424, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='我在广州啊,你记住了', additional_kwargs={}, response_metadata={}, name='User', id='177253af-5f01-4b90-b0de-7d2f6b353972'),\n",
+ " AIMessage(content='好的,我记住了你在广州。如果你需要关于广州的任何信息,随时告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 23, 'prompt_tokens': 441, 'total_tokens': 464, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-6a3af2ce-42c9-4ff5-bd0e-ac111f05ff3d-0', usage_metadata={'input_tokens': 441, 'output_tokens': 23, 'total_tokens': 464, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='那你帮我查一下天气', additional_kwargs={}, response_metadata={}, name='User', id='ecf1bbe7-1281-42ef-8c38-b31905b77e41'),\n",
+ " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_uxQylEdyIjo7mbwhXgN6aWlM', 'function': {'arguments': '{\"para\":\"Guangzhou\"}', 'name': 'weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 480, 'total_tokens': 495, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-5fef1bc4-389c-4378-b33f-fc1711665a31-0', tool_calls=[{'name': 'weather', 'args': {'para': 'Guangzhou'}, 'id': 'call_uxQylEdyIjo7mbwhXgN6aWlM', 'type': 'tool_call'}], usage_metadata={'input_tokens': 480, 'output_tokens': 15, 'total_tokens': 495, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " ToolMessage(content='天气预报信息:今天天气:broken clouds,气温:24.97摄氏度,风速:1.54 m/s。', name='weather', id='83324068-99a3-4cc4-9344-602137b4ff0f', tool_call_id='call_uxQylEdyIjo7mbwhXgN6aWlM'),\n",
+ " AIMessage(content='广州的天气预报信息:今天天气为多云,气温为24.97摄氏度,风速为1.54米/秒。有什么其他需要了解的吗?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 41, 'prompt_tokens': 533, 'total_tokens': 574, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-6a9b5728-48d1-4e9a-9aee-c0aec6fea0a6-0', usage_metadata={'input_tokens': 533, 'output_tokens': 41, 'total_tokens': 574, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='深圳呢', additional_kwargs={}, response_metadata={}, name='User', id='514a6dcf-404c-4529-bf27-e34e8a669be9'),\n",
+ " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_TJNJH6UBaF8x7gTuZd8X7JAd', 'function': {'arguments': '{\"para\":\"Shenzhen\"}', 'name': 'weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 585, 'total_tokens': 599, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-f5a9852a-e502-4944-9f82-6b58cbd66a6f-0', tool_calls=[{'name': 'weather', 'args': {'para': 'Shenzhen'}, 'id': 'call_TJNJH6UBaF8x7gTuZd8X7JAd', 'type': 'tool_call'}], usage_metadata={'input_tokens': 585, 'output_tokens': 14, 'total_tokens': 599, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " ToolMessage(content='天气预报信息:今天天气:light rain,气温:24.73摄氏度,风速:1.46 m/s。', name='weather', id='6f99f5c2-e61e-4c09-8a88-858711a628ac', tool_call_id='call_TJNJH6UBaF8x7gTuZd8X7JAd'),\n",
+ " AIMessage(content='深圳的天气预报信息:今天天气为小雨,气温为24.73摄氏度,风速为1.46米/秒。如果你还有其他问题,随时告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 45, 'prompt_tokens': 637, 'total_tokens': 682, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-5ad2461a-11ff-40cc-8ad2-2413b75ef8a3-0', usage_metadata={'input_tokens': 637, 'output_tokens': 45, 'total_tokens': 682, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='有什么玩', additional_kwargs={}, response_metadata={}, name='User', id='9fc4b0b2-24d6-444a-923d-b3c6e63809cc'),\n",
+ " AIMessage(content='在广州和深圳,你可以尝试以下一些活动和景点:\\n\\n### 广州\\n1. **广州塔(小蛮腰)**:可以登塔俯瞰城市全景。\\n2. **珠江夜游**:欣赏珠江两岸的美丽夜景。\\n3. **白云山**:适合徒步和观赏自然风光。\\n4. **上下九步行街**:体验广州的美食和购物。\\n5. **陈家祠**:了解岭南文化和传统建筑。\\n\\n### 深圳\\n1. **深圳湾公园**:适合散步和骑行,享受海风。\\n2. **大梅沙海滨公园**:可以游泳和沙滩活动。\\n3. **欢乐谷**:一个大型的主题公园,适合家庭游玩。\\n4. **东部华侨城**:有自然景观和文化体验的综合旅游区。\\n5. **深圳博物馆**:了解深圳的发展历史和文化。\\n\\n你对哪个活动感兴趣呢?或者想了解更多信息?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 238, 'prompt_tokens': 693, 'total_tokens': 931, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-987a1730-2229-47d3-a215-0e1cac207f00-0', usage_metadata={'input_tokens': 693, 'output_tokens': 238, 'total_tokens': 931, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='北京呢', additional_kwargs={}, response_metadata={}, name='User', id='3df98b9a-22e2-42da-9f31-916b055079e4'),\n",
+ " AIMessage(content='在北京,你可以尝试以下一些活动和景点:\\n\\n### 北京\\n1. **故宫博物院**:探索中国古代皇宫的历史和文化。\\n2. **长城**:游览八达岭或慕田峪段,体验这一历史奇迹。\\n3. **天安门广场**:参观广场及其周围的历史建筑,包括人民大会堂和毛主席纪念堂。\\n4. **颐和园**:欣赏美丽的皇家园林和昆明湖的风景。\\n5. **798艺术区**:探索现代艺术和文化的创意产业园区。\\n6. **胡同游**:体验北京的传统胡同文化,可以选择骑自行车游览。\\n7. **北京烤鸭**:在著名的餐馆品尝正宗的北京烤鸭。\\n\\n如果你对某个特定的景点或活动感兴趣,或者需要更多的信息,请告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 212, 'prompt_tokens': 942, 'total_tokens': 1154, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-c0d85ea4-6e2d-4434-8773-a3dc9e170fbd-0', usage_metadata={'input_tokens': 942, 'output_tokens': 212, 'total_tokens': 1154, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='还有吗', additional_kwargs={}, response_metadata={}, name='User', id='a8698fad-e437-4f69-91bf-04a87f58d4e7'),\n",
+ " AIMessage(content='当然可以!以下是一些更多在北京可以做的事情和景点:\\n\\n### 更多北京活动和景点\\n8. **圆明园**:游览这座历史悠久的皇家园林,了解其辉煌与毁灭的历史。\\n9. **南锣鼓巷**:体验传统与现代结合的文化,享受美食和购物。\\n10. **北京植物园**:欣赏各种植物和花卉,适合家庭和自然爱好者。\\n11. **首都博物馆**:了解北京的历史和文化,有丰富的展览。\\n12. **鸟巢和水立方**:参观2008年奥运会的标志性建筑,外观非常壮观。\\n13. **王府井步行街**:购物和美食的天堂,尝试各种地道小吃。\\n14. **北京剧院**:观看京剧或其他表演,体验中国传统艺术。\\n15. **长安街**:沿着长安街散步,欣赏沿途的现代建筑与历史景点。\\n\\n如果你还有其他问题或需要更具体的信息,比如餐馆推荐或交通方式,随时告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 259, 'prompt_tokens': 1165, 'total_tokens': 1424, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-491a2935-7dbb-44c7-86c8-afa5e121fbd0-0', usage_metadata={'input_tokens': 1165, 'output_tokens': 259, 'total_tokens': 1424, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})],\n",
+ " 'agent': 'agent'},\n",
+ " 'channel_versions': {'__start__': '00000000000000000000000000000032.0.15693994337439554',\n",
+ " 'messages': '00000000000000000000000000000033.0.7077459190085686',\n",
+ " 'start:agent': '00000000000000000000000000000033.0.9607591474652312',\n",
+ " 'agent': '00000000000000000000000000000033.0.8028913424477877',\n",
+ " 'branch:agent:should_continue:tools': '00000000000000000000000000000023.0.7713433790844227',\n",
+ " 'tools': '00000000000000000000000000000024.0.695707121431364'},\n",
+ " 'versions_seen': {'__input__': {},\n",
+ " '__start__': {'__start__': '00000000000000000000000000000031.0.9988558075001674'},\n",
+ " 'agent': {'start:agent': '00000000000000000000000000000032.0.7643999578358889',\n",
+ " 'tools': '00000000000000000000000000000023.0.7854437453842145'},\n",
+ " 'tools': {'branch:agent:should_continue:tools': '00000000000000000000000000000022.0.0983258158769671'}},\n",
+ " 'pending_sends': []}"
+ ]
+ },
+ "execution_count": 50,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "memory.get_tuple(config).checkpoint"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[HumanMessage(content='现在什么时间,广州天气怎么样', additional_kwargs={}, response_metadata={}, name='User', id='e26e51c3-2a22-4997-b8c4-c8354192aeea'),\n",
+ " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Sga9wIgaKZ8ZtZRzHvlIdbz1', 'function': {'arguments': '{\"para\": {}}', 'name': 'QueryTime'}, 'type': 'function'}, {'id': 'call_YyxTGWDjmKnRMLICROzdqBfe', 'function': {'arguments': '{\"para\": \"Guangzhou\"}', 'name': 'weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 45, 'prompt_tokens': 94, 'total_tokens': 139, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-366f5601-27ef-4238-8928-e7a74218a560-0', tool_calls=[{'name': 'QueryTime', 'args': {'para': {}}, 'id': 'call_Sga9wIgaKZ8ZtZRzHvlIdbz1', 'type': 'tool_call'}, {'name': 'weather', 'args': {'para': 'Guangzhou'}, 'id': 'call_YyxTGWDjmKnRMLICROzdqBfe', 'type': 'tool_call'}], usage_metadata={'input_tokens': 94, 'output_tokens': 45, 'total_tokens': 139, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " ToolMessage(content='现在时间是:15:35 星期五 2024年11月15日', name='QueryTime', id='18e008ef-b0a6-4dcc-9ade-20f88a349a07', tool_call_id='call_Sga9wIgaKZ8ZtZRzHvlIdbz1'),\n",
+ " ToolMessage(content='天气预报信息:今天天气:overcast clouds,气温:24.97摄氏度,风速:1.64 m/s。', name='weather', id='5e0da87a-8f24-4652-9c4b-fde489ec3812', tool_call_id='call_YyxTGWDjmKnRMLICROzdqBfe'),\n",
+ " AIMessage(content='现在时间是:15:35,星期五,2024年11月15日。\\n\\n广州的天气预报信息:今天天气为阴云,气温为24.97摄氏度,风速为1.64米/秒。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 53, 'prompt_tokens': 296, 'total_tokens': 349, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-d5eaf7a8-ad14-4e2e-b31d-caa45a58901c-0', usage_metadata={'input_tokens': 296, 'output_tokens': 53, 'total_tokens': 349, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='你好', additional_kwargs={}, response_metadata={}, name='User', id='8fc0dbed-ab1a-4e5d-b7fe-d4d5784ac463'),\n",
+ " AIMessage(content='你好!有什么我可以帮助你的吗?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 360, 'total_tokens': 370, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-ce3076b5-a8cc-4653-aa31-2d895339ba67-0', usage_metadata={'input_tokens': 360, 'output_tokens': 10, 'total_tokens': 370, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='你知道我在那里吗', additional_kwargs={}, response_metadata={}, name='User', id='cf569e60-e19b-4ded-8247-33a080071353'),\n",
+ " AIMessage(content='我无法直接知道你的位置,但可以根据你提供的信息来帮助你。如果你告诉我你所在的城市或地区,我可以为你提供相关的天气、新闻或其他信息。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 40, 'prompt_tokens': 384, 'total_tokens': 424, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-c4be7ab9-8ac5-44be-b2ef-a510173e9213-0', usage_metadata={'input_tokens': 384, 'output_tokens': 40, 'total_tokens': 424, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='我在广州啊,你记住了', additional_kwargs={}, response_metadata={}, name='User', id='177253af-5f01-4b90-b0de-7d2f6b353972'),\n",
+ " AIMessage(content='好的,我记住了你在广州。如果你需要关于广州的任何信息,随时告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 23, 'prompt_tokens': 441, 'total_tokens': 464, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-6a3af2ce-42c9-4ff5-bd0e-ac111f05ff3d-0', usage_metadata={'input_tokens': 441, 'output_tokens': 23, 'total_tokens': 464, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='那你帮我查一下天气', additional_kwargs={}, response_metadata={}, name='User', id='ecf1bbe7-1281-42ef-8c38-b31905b77e41'),\n",
+ " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_uxQylEdyIjo7mbwhXgN6aWlM', 'function': {'arguments': '{\"para\":\"Guangzhou\"}', 'name': 'weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 480, 'total_tokens': 495, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-5fef1bc4-389c-4378-b33f-fc1711665a31-0', tool_calls=[{'name': 'weather', 'args': {'para': 'Guangzhou'}, 'id': 'call_uxQylEdyIjo7mbwhXgN6aWlM', 'type': 'tool_call'}], usage_metadata={'input_tokens': 480, 'output_tokens': 15, 'total_tokens': 495, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " ToolMessage(content='天气预报信息:今天天气:broken clouds,气温:24.97摄氏度,风速:1.54 m/s。', name='weather', id='83324068-99a3-4cc4-9344-602137b4ff0f', tool_call_id='call_uxQylEdyIjo7mbwhXgN6aWlM'),\n",
+ " AIMessage(content='广州的天气预报信息:今天天气为多云,气温为24.97摄氏度,风速为1.54米/秒。有什么其他需要了解的吗?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 41, 'prompt_tokens': 533, 'total_tokens': 574, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-6a9b5728-48d1-4e9a-9aee-c0aec6fea0a6-0', usage_metadata={'input_tokens': 533, 'output_tokens': 41, 'total_tokens': 574, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='深圳呢', additional_kwargs={}, response_metadata={}, name='User', id='514a6dcf-404c-4529-bf27-e34e8a669be9'),\n",
+ " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_TJNJH6UBaF8x7gTuZd8X7JAd', 'function': {'arguments': '{\"para\":\"Shenzhen\"}', 'name': 'weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 585, 'total_tokens': 599, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-f5a9852a-e502-4944-9f82-6b58cbd66a6f-0', tool_calls=[{'name': 'weather', 'args': {'para': 'Shenzhen'}, 'id': 'call_TJNJH6UBaF8x7gTuZd8X7JAd', 'type': 'tool_call'}], usage_metadata={'input_tokens': 585, 'output_tokens': 14, 'total_tokens': 599, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " ToolMessage(content='天气预报信息:今天天气:light rain,气温:24.73摄氏度,风速:1.46 m/s。', name='weather', id='6f99f5c2-e61e-4c09-8a88-858711a628ac', tool_call_id='call_TJNJH6UBaF8x7gTuZd8X7JAd'),\n",
+ " AIMessage(content='深圳的天气预报信息:今天天气为小雨,气温为24.73摄氏度,风速为1.46米/秒。如果你还有其他问题,随时告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 45, 'prompt_tokens': 637, 'total_tokens': 682, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-5ad2461a-11ff-40cc-8ad2-2413b75ef8a3-0', usage_metadata={'input_tokens': 637, 'output_tokens': 45, 'total_tokens': 682, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='有什么玩', additional_kwargs={}, response_metadata={}, name='User', id='9fc4b0b2-24d6-444a-923d-b3c6e63809cc'),\n",
+ " AIMessage(content='在广州和深圳,你可以尝试以下一些活动和景点:\\n\\n### 广州\\n1. **广州塔(小蛮腰)**:可以登塔俯瞰城市全景。\\n2. **珠江夜游**:欣赏珠江两岸的美丽夜景。\\n3. **白云山**:适合徒步和观赏自然风光。\\n4. **上下九步行街**:体验广州的美食和购物。\\n5. **陈家祠**:了解岭南文化和传统建筑。\\n\\n### 深圳\\n1. **深圳湾公园**:适合散步和骑行,享受海风。\\n2. **大梅沙海滨公园**:可以游泳和沙滩活动。\\n3. **欢乐谷**:一个大型的主题公园,适合家庭游玩。\\n4. **东部华侨城**:有自然景观和文化体验的综合旅游区。\\n5. **深圳博物馆**:了解深圳的发展历史和文化。\\n\\n你对哪个活动感兴趣呢?或者想了解更多信息?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 238, 'prompt_tokens': 693, 'total_tokens': 931, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-987a1730-2229-47d3-a215-0e1cac207f00-0', usage_metadata={'input_tokens': 693, 'output_tokens': 238, 'total_tokens': 931, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='北京呢', additional_kwargs={}, response_metadata={}, name='User', id='3df98b9a-22e2-42da-9f31-916b055079e4'),\n",
+ " AIMessage(content='在北京,你可以尝试以下一些活动和景点:\\n\\n### 北京\\n1. **故宫博物院**:探索中国古代皇宫的历史和文化。\\n2. **长城**:游览八达岭或慕田峪段,体验这一历史奇迹。\\n3. **天安门广场**:参观广场及其周围的历史建筑,包括人民大会堂和毛主席纪念堂。\\n4. **颐和园**:欣赏美丽的皇家园林和昆明湖的风景。\\n5. **798艺术区**:探索现代艺术和文化的创意产业园区。\\n6. **胡同游**:体验北京的传统胡同文化,可以选择骑自行车游览。\\n7. **北京烤鸭**:在著名的餐馆品尝正宗的北京烤鸭。\\n\\n如果你对某个特定的景点或活动感兴趣,或者需要更多的信息,请告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 212, 'prompt_tokens': 942, 'total_tokens': 1154, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-c0d85ea4-6e2d-4434-8773-a3dc9e170fbd-0', usage_metadata={'input_tokens': 942, 'output_tokens': 212, 'total_tokens': 1154, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})]"
+ ]
+ },
+ "execution_count": 44,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "memory.get_tuple(config).checkpoint['channel_values']['messages']"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'messages': [HumanMessage(content='现在什么时间,广州天气怎么样', additional_kwargs={}, response_metadata={}, name='User', id='e26e51c3-2a22-4997-b8c4-c8354192aeea'),\n",
+ " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Sga9wIgaKZ8ZtZRzHvlIdbz1', 'function': {'arguments': '{\"para\": {}}', 'name': 'QueryTime'}, 'type': 'function'}, {'id': 'call_YyxTGWDjmKnRMLICROzdqBfe', 'function': {'arguments': '{\"para\": \"Guangzhou\"}', 'name': 'weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 45, 'prompt_tokens': 94, 'total_tokens': 139, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-366f5601-27ef-4238-8928-e7a74218a560-0', tool_calls=[{'name': 'QueryTime', 'args': {'para': {}}, 'id': 'call_Sga9wIgaKZ8ZtZRzHvlIdbz1', 'type': 'tool_call'}, {'name': 'weather', 'args': {'para': 'Guangzhou'}, 'id': 'call_YyxTGWDjmKnRMLICROzdqBfe', 'type': 'tool_call'}], usage_metadata={'input_tokens': 94, 'output_tokens': 45, 'total_tokens': 139, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " ToolMessage(content='现在时间是:15:35 星期五 2024年11月15日', name='QueryTime', id='18e008ef-b0a6-4dcc-9ade-20f88a349a07', tool_call_id='call_Sga9wIgaKZ8ZtZRzHvlIdbz1'),\n",
+ " ToolMessage(content='天气预报信息:今天天气:overcast clouds,气温:24.97摄氏度,风速:1.64 m/s。', name='weather', id='5e0da87a-8f24-4652-9c4b-fde489ec3812', tool_call_id='call_YyxTGWDjmKnRMLICROzdqBfe'),\n",
+ " AIMessage(content='现在时间是:15:35,星期五,2024年11月15日。\\n\\n广州的天气预报信息:今天天气为阴云,气温为24.97摄氏度,风速为1.64米/秒。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 53, 'prompt_tokens': 296, 'total_tokens': 349, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-d5eaf7a8-ad14-4e2e-b31d-caa45a58901c-0', usage_metadata={'input_tokens': 296, 'output_tokens': 53, 'total_tokens': 349, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='你好', additional_kwargs={}, response_metadata={}, name='User', id='8fc0dbed-ab1a-4e5d-b7fe-d4d5784ac463'),\n",
+ " AIMessage(content='你好!有什么我可以帮助你的吗?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 360, 'total_tokens': 370, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-ce3076b5-a8cc-4653-aa31-2d895339ba67-0', usage_metadata={'input_tokens': 360, 'output_tokens': 10, 'total_tokens': 370, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='你知道我在那里吗', additional_kwargs={}, response_metadata={}, name='User', id='cf569e60-e19b-4ded-8247-33a080071353'),\n",
+ " AIMessage(content='我无法直接知道你的位置,但可以根据你提供的信息来帮助你。如果你告诉我你所在的城市或地区,我可以为你提供相关的天气、新闻或其他信息。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 40, 'prompt_tokens': 384, 'total_tokens': 424, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-c4be7ab9-8ac5-44be-b2ef-a510173e9213-0', usage_metadata={'input_tokens': 384, 'output_tokens': 40, 'total_tokens': 424, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='我在广州啊,你记住了', additional_kwargs={}, response_metadata={}, name='User', id='177253af-5f01-4b90-b0de-7d2f6b353972'),\n",
+ " AIMessage(content='好的,我记住了你在广州。如果你需要关于广州的任何信息,随时告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 23, 'prompt_tokens': 441, 'total_tokens': 464, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-6a3af2ce-42c9-4ff5-bd0e-ac111f05ff3d-0', usage_metadata={'input_tokens': 441, 'output_tokens': 23, 'total_tokens': 464, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='那你帮我查一下天气', additional_kwargs={}, response_metadata={}, name='User', id='ecf1bbe7-1281-42ef-8c38-b31905b77e41'),\n",
+ " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_uxQylEdyIjo7mbwhXgN6aWlM', 'function': {'arguments': '{\"para\":\"Guangzhou\"}', 'name': 'weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 480, 'total_tokens': 495, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-5fef1bc4-389c-4378-b33f-fc1711665a31-0', tool_calls=[{'name': 'weather', 'args': {'para': 'Guangzhou'}, 'id': 'call_uxQylEdyIjo7mbwhXgN6aWlM', 'type': 'tool_call'}], usage_metadata={'input_tokens': 480, 'output_tokens': 15, 'total_tokens': 495, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " ToolMessage(content='天气预报信息:今天天气:broken clouds,气温:24.97摄氏度,风速:1.54 m/s。', name='weather', id='83324068-99a3-4cc4-9344-602137b4ff0f', tool_call_id='call_uxQylEdyIjo7mbwhXgN6aWlM'),\n",
+ " AIMessage(content='广州的天气预报信息:今天天气为多云,气温为24.97摄氏度,风速为1.54米/秒。有什么其他需要了解的吗?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 41, 'prompt_tokens': 533, 'total_tokens': 574, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-6a9b5728-48d1-4e9a-9aee-c0aec6fea0a6-0', usage_metadata={'input_tokens': 533, 'output_tokens': 41, 'total_tokens': 574, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='深圳呢', additional_kwargs={}, response_metadata={}, name='User', id='514a6dcf-404c-4529-bf27-e34e8a669be9'),\n",
+ " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_TJNJH6UBaF8x7gTuZd8X7JAd', 'function': {'arguments': '{\"para\":\"Shenzhen\"}', 'name': 'weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 585, 'total_tokens': 599, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-f5a9852a-e502-4944-9f82-6b58cbd66a6f-0', tool_calls=[{'name': 'weather', 'args': {'para': 'Shenzhen'}, 'id': 'call_TJNJH6UBaF8x7gTuZd8X7JAd', 'type': 'tool_call'}], usage_metadata={'input_tokens': 585, 'output_tokens': 14, 'total_tokens': 599, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " ToolMessage(content='天气预报信息:今天天气:light rain,气温:24.73摄氏度,风速:1.46 m/s。', name='weather', id='6f99f5c2-e61e-4c09-8a88-858711a628ac', tool_call_id='call_TJNJH6UBaF8x7gTuZd8X7JAd'),\n",
+ " AIMessage(content='深圳的天气预报信息:今天天气为小雨,气温为24.73摄氏度,风速为1.46米/秒。如果你还有其他问题,随时告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 45, 'prompt_tokens': 637, 'total_tokens': 682, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-5ad2461a-11ff-40cc-8ad2-2413b75ef8a3-0', usage_metadata={'input_tokens': 637, 'output_tokens': 45, 'total_tokens': 682, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='有什么玩', additional_kwargs={}, response_metadata={}, name='User', id='9fc4b0b2-24d6-444a-923d-b3c6e63809cc'),\n",
+ " AIMessage(content='在广州和深圳,你可以尝试以下一些活动和景点:\\n\\n### 广州\\n1. **广州塔(小蛮腰)**:可以登塔俯瞰城市全景。\\n2. **珠江夜游**:欣赏珠江两岸的美丽夜景。\\n3. **白云山**:适合徒步和观赏自然风光。\\n4. **上下九步行街**:体验广州的美食和购物。\\n5. **陈家祠**:了解岭南文化和传统建筑。\\n\\n### 深圳\\n1. **深圳湾公园**:适合散步和骑行,享受海风。\\n2. **大梅沙海滨公园**:可以游泳和沙滩活动。\\n3. **欢乐谷**:一个大型的主题公园,适合家庭游玩。\\n4. **东部华侨城**:有自然景观和文化体验的综合旅游区。\\n5. **深圳博物馆**:了解深圳的发展历史和文化。\\n\\n你对哪个活动感兴趣呢?或者想了解更多信息?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 238, 'prompt_tokens': 693, 'total_tokens': 931, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_04751d0b65', 'finish_reason': 'stop', 'logprobs': None}, id='run-987a1730-2229-47d3-a215-0e1cac207f00-0', usage_metadata={'input_tokens': 693, 'output_tokens': 238, 'total_tokens': 931, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}}),\n",
+ " HumanMessage(content='北京呢', additional_kwargs={}, response_metadata={}, name='User', id='3df98b9a-22e2-42da-9f31-916b055079e4'),\n",
+ " AIMessage(content='在北京,你可以尝试以下一些活动和景点:\\n\\n### 北京\\n1. **故宫博物院**:探索中国古代皇宫的历史和文化。\\n2. **长城**:游览八达岭或慕田峪段,体验这一历史奇迹。\\n3. **天安门广场**:参观广场及其周围的历史建筑,包括人民大会堂和毛主席纪念堂。\\n4. **颐和园**:欣赏美丽的皇家园林和昆明湖的风景。\\n5. **798艺术区**:探索现代艺术和文化的创意产业园区。\\n6. **胡同游**:体验北京的传统胡同文化,可以选择骑自行车游览。\\n7. **北京烤鸭**:在著名的餐馆品尝正宗的北京烤鸭。\\n\\n如果你对某个特定的景点或活动感兴趣,或者需要更多的信息,请告诉我!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 212, 'prompt_tokens': 942, 'total_tokens': 1154, 'completion_tokens_details': {'accepted_prediction_tokens': None, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': None}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_d54531d9eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-c0d85ea4-6e2d-4434-8773-a3dc9e170fbd-0', usage_metadata={'input_tokens': 942, 'output_tokens': 212, 'total_tokens': 1154, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 0}})],\n",
+ " 'agent': 'agent'}"
+ ]
+ },
+ "execution_count": 43,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "memory.get_tuple(config).checkpoint['channel_values']"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "fay312-2",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/test/test_langserve.py b/test/test_langserve.py
new file mode 100644
index 0000000..80df13c
--- /dev/null
+++ b/test/test_langserve.py
@@ -0,0 +1,44 @@
+from fastapi import FastAPI
+from langchain_core.prompts import ChatPromptTemplate
+from langchain_core.output_parsers import StrOutputParser
+from langchain_openai import ChatOpenAI
+from langserve import add_routes
+import os
+os.environ["OPENAI_API_KEY"] = "sk-"
+os.environ["OPENAI_API_BASE"] = "https://cn.api.zyai.online/v1"
+
+# 1. Create prompt template
+system_template = "Translate the following into {language}:"
+prompt_template = ChatPromptTemplate.from_messages([
+ ('system', system_template),
+ ('user', '{text}')
+])
+
+# 2. Create model
+model = ChatOpenAI()
+
+# 3. Create parser
+parser = StrOutputParser()
+
+# 4. Create chain
+chain = prompt_template | model | parser
+
+
+# 4. App definition
+app = FastAPI(
+ title="LangChain Server",
+ version="1.0",
+ description="A simple API server using LangChain's Runnable interfaces",
+)
+
+# 5. Adding chain route
+add_routes(
+ app,
+ chain,
+ path="/chain",
+)
+
+if __name__ == "__main__":
+ import uvicorn
+
+ uvicorn.run(app, host="localhost", port=8000)
\ No newline at end of file
diff --git a/test/test_nlp.py b/test/test_nlp.py
index fd76bec..e5bbd06 100644
--- a/test/test_nlp.py
+++ b/test/test_nlp.py
@@ -2,7 +2,7 @@ import requests
import json
def test_gpt(prompt):
- url = 'http://faycontroller.yaheen.com:5000/v1/chat/completions' # 替换为您的接口地址
+ url = 'http://127.0.0.1:5000/v1/chat/completions' # 替换为您的接口地址
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer YOUR_API_KEY', # 如果您的接口需要身份验证
diff --git a/utils/config_util.py b/utils/config_util.py
index 1bb34b3..331af04 100644
--- a/utils/config_util.py
+++ b/utils/config_util.py
@@ -2,6 +2,16 @@ import os
import json
import codecs
from configparser import ConfigParser
+import functools
+from threading import Lock
+
+lock = Lock()
+def synchronized(func):
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ with lock:
+ return func(*args, **kwargs)
+ return wrapper
config: json = None
system_config: ConfigParser = None
@@ -40,6 +50,7 @@ coze_api_key = None
start_mode = None
fay_url = None
+@synchronized
def load_config():
global config
global system_config
@@ -116,8 +127,11 @@ def load_config():
coze_api_key = system_config.get('key', 'coze_api_key')
start_mode = system_config.get('key', 'start_mode')
fay_url = system_config.get('key', 'fay_url')
+
+ #读取用户配置
config = json.load(codecs.open('config.json', encoding='utf-8'))
+@synchronized
def save_config(config_data):
global config
config = config_data