react_agent/ agent_tools/middleware
This commit is contained in:
parent
56b276eb3f
commit
187b8c8756
|
|
@ -0,0 +1,2 @@
|
|||
.git
|
||||
.idea
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="RAG" jdkType="Python SDK" />
|
||||
<orderEntry type="jdk" jdkName="edu" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -3,5 +3,5 @@
|
|||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.12 (Eula)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="RAG" project-jdk-type="Python SDK" />
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="edu" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
Binary file not shown.
|
|
@ -0,0 +1,39 @@
|
|||
from langchain.agents import create_agent
|
||||
from model.factory import chat_model
|
||||
from utils.prompt_loader import load_system_prompts
|
||||
from agent.tools.agent_tools import (rag_summarize, get_weather, get_user_id,
|
||||
get_user_location, get_current_month,
|
||||
fill_context_for_report, fetch_external_data)
|
||||
from agent.tools.middleware import monitor_tool, log_before_model, repoet_prompt_switch
|
||||
|
||||
|
||||
class ReactAgent:
|
||||
def __init__(self):
|
||||
self.agent = create_agent(
|
||||
model=chat_model,
|
||||
system_prompt=load_system_prompts(),
|
||||
tools=[rag_summarize, get_weather, get_user_location, get_user_id,
|
||||
get_current_month, fetch_external_data, fill_context_for_report],
|
||||
middleware=[monitor_tool, log_before_model, repoet_prompt_switch],
|
||||
)
|
||||
|
||||
def excute_stream(self, query: str):
|
||||
input_dict = {
|
||||
"messages": [
|
||||
{"role": "user", "content": query}
|
||||
]
|
||||
}
|
||||
|
||||
# 上下文runtime信息,做提示词切换标记
|
||||
response = self.agent.stream(input_dict, stream_mode="values", context={"report": False})
|
||||
for chunk in response:
|
||||
latest_message = chunk["messages"][-1]
|
||||
if latest_message.content:
|
||||
yield latest_message.content.strip() + "\n"
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
agent = ReactAgent();
|
||||
stream = agent.excute_stream("扫地机器人在我所在地的气温下如何保养")
|
||||
for chunk in stream:
|
||||
print(chunk, end="", flush=True)
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,99 @@
|
|||
import pandas
|
||||
from langchain_core.tools import tool
|
||||
from rag.rag_service import RagSummarizeService
|
||||
import random
|
||||
from utils.config_handler import agent_conf
|
||||
from utils.path_tool import get_abs_path
|
||||
from utils.logger_handler import logger
|
||||
import os
|
||||
|
||||
rag = RagSummarizeService()
|
||||
|
||||
user_ids = [str(i) for i in range(1001, 1011, 1)]
|
||||
month_arr = [f"2025-{str(i).zfill(2)}" for i in range(1, 13, 1)]
|
||||
external_data = {}
|
||||
|
||||
|
||||
@tool(description="向量存储中检索参考资料")
|
||||
def rag_summarize(query: str) -> str:
|
||||
return rag.rag_summarize(query)
|
||||
|
||||
|
||||
@tool(description="获取指定城市天气,消息以字符串方式返回")
|
||||
def get_weather(city: str) -> str:
|
||||
return f"城市{city}天气为晴天,温度为26摄氏度,湿度50%,南风1级,AQI21,最近6小时降雨概率极低"
|
||||
|
||||
|
||||
@tool(description="获取用户所在城市名称,以纯字符串形式返回")
|
||||
def get_user_location() -> str:
|
||||
return random.choice(["深圳", "合肥", "杭州"])
|
||||
|
||||
|
||||
@tool(description="获取用户ID,以纯字符串形式返回")
|
||||
def get_user_id() -> str:
|
||||
return random.choice(user_ids)
|
||||
|
||||
|
||||
@tool(description="获取当前月份,以纯字符串形式返回")
|
||||
def get_current_month() -> str:
|
||||
return random.choice(month_arr)
|
||||
|
||||
|
||||
def generate_external_data():
|
||||
"""得到用户字典,
|
||||
{
|
||||
"user_id": {
|
||||
"month": {"特征: ..., "效率:}
|
||||
}
|
||||
}"""
|
||||
|
||||
if not external_data:
|
||||
external_data_path = agent_conf['external_data_path']
|
||||
external_data_path = get_abs_path(external_data_path)
|
||||
|
||||
if not os.path.exists(external_data_path):
|
||||
raise FileExistsError(f"外部文件{external_data_path}不存在")
|
||||
|
||||
with open(external_data_path, 'r', encoding='utf-8') as f:
|
||||
for line in f.readlines():
|
||||
arr = line.strip().split(',')
|
||||
user_id = arr[0].replace('"', "")
|
||||
feature = arr[1].replace('"', "")
|
||||
efficiency = arr[2].replace('"', "")
|
||||
consumables = arr[3].replace('"', "")
|
||||
comparison = arr[4].replace('"', "")
|
||||
time = arr[5].replace('"', "")
|
||||
|
||||
if user_id not in external_data:
|
||||
external_data[user_id] = {}
|
||||
|
||||
external_data[user_id][time] = {
|
||||
"特征": feature,
|
||||
"效率": efficiency,
|
||||
"耗材": consumables,
|
||||
"对比": comparison,
|
||||
}
|
||||
return external_data
|
||||
|
||||
|
||||
@tool(description="从外部系统获取用户使用记录,以春字符串形式返回,如果未检索到,返回空字符串")
|
||||
def fetch_external_data(user_id: str, month: str) -> str:
|
||||
generate_external_data()
|
||||
|
||||
try:
|
||||
return external_data[user_id][month]
|
||||
except KeyError:
|
||||
logger.warning(f"[fetch_external_data]未检索到用户:{user_id}在{month}的使用数据")
|
||||
return ""
|
||||
|
||||
|
||||
@tool(description="无入参,无返回值,调用后自动触发中间件,自动为报告生成动态场景上下文"
|
||||
"+")
|
||||
def fill_context_for_report():
|
||||
return "fill_context_for_report已调用"
|
||||
|
||||
# if __name__ == '__main__':
|
||||
# user_id = "1005"
|
||||
# month = "2025-06"
|
||||
# res = fetch_external_data(user_id, month)
|
||||
# print(res)
|
||||
Binary file not shown.
|
|
@ -0,0 +1,51 @@
|
|||
from langchain.agents.middleware import wrap_tool_call, before_model, dynamic_prompt, ModelRequest
|
||||
from langchain.tools.tool_node import ToolCallRequest
|
||||
from typing import Callable
|
||||
from langchain_core.messages import ToolMessage
|
||||
from langgraph.types import Command
|
||||
from utils.logger_handler import logger
|
||||
from langchain.agents import AgentState
|
||||
from langgraph.runtime import Runtime
|
||||
from utils.prompt_loader import load_system_prompts, load_report_prompts
|
||||
|
||||
@wrap_tool_call
|
||||
def monitor_tool(
|
||||
# 函数
|
||||
request: ToolCallRequest,
|
||||
# 入参
|
||||
handler: Callable[[ToolCallRequest], ToolMessage | Command],
|
||||
) -> ToolMessage | Command:
|
||||
logger.info(f"[tool monitor]执行工具:{request.tool_call['name']}")
|
||||
logger.info(f"[tool monitor]传入参数:{request.tool_call['args']}")
|
||||
|
||||
try:
|
||||
result = handler(request)
|
||||
logger.info(f"[tool minitor]工具{request.tool_call['name']}调用成功")
|
||||
|
||||
if request.tool_call['name'] == 'fill_context_for_report':
|
||||
request.runtime.context["report"] = True
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(f"工具{request.tool_call['name']}调用失败,原因: {str(e)}")
|
||||
raise e
|
||||
|
||||
|
||||
@before_model
|
||||
def log_before_model(
|
||||
state: AgentState, # 状态记录
|
||||
runtine: Runtime, # 执行过程 上下文信息
|
||||
):
|
||||
logger.info(f"[log_before_model]即将调用模型,带有{len(state["messages"])}条消息")
|
||||
logger.debug(f"[log_before_model]{type(state["messages"][-1]).__name__} | "
|
||||
f"消息内容:{state["messages"][-1].content.strip()}")
|
||||
return None
|
||||
|
||||
|
||||
@dynamic_prompt # 每一次提示词生成前,调用
|
||||
def repoet_prompt_switch(request: ModelRequest):
|
||||
is_report = request.runtime.context.get("report", False)
|
||||
if is_report:
|
||||
return load_report_prompts()
|
||||
|
||||
return load_system_prompts()
|
||||
|
|
@ -0,0 +1 @@
|
|||
external_data_path: data/external/records.csv
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
2026-03-01 00:10:11,186 - Agent - WARNING - agent_tools.py:86 - [fetch_external_data]未检索到用户:1004在2月的使用数据
|
||||
2026-03-01 00:10:15,880 - Agent - WARNING - agent_tools.py:86 - [fetch_external_data]未检索到用户:1008在8月的使用数据
|
||||
2026-03-01 11:06:16,324 - Agent - INFO - middleware.py:39 - [log_before_model]即将调用模型,带有1条消息
|
||||
2026-03-01 11:06:16,324 - Agent - DEBUG - middleware.py:40 - [log_before_model]HumanMessage | 消息内容:扫地机器人在我所在地的气温下如何保养
|
||||
2026-03-01 11:06:50,251 - Agent - INFO - middleware.py:39 - [log_before_model]即将调用模型,带有1条消息
|
||||
2026-03-01 11:06:50,251 - Agent - DEBUG - middleware.py:40 - [log_before_model]HumanMessage | 消息内容:扫地机器人在我所在地的气温下如何保养
|
||||
2026-03-01 11:08:04,788 - Agent - INFO - middleware.py:39 - [log_before_model]即将调用模型,带有1条消息
|
||||
2026-03-01 11:08:04,789 - Agent - DEBUG - middleware.py:40 - [log_before_model]HumanMessage | 消息内容:扫地机器人在我所在地的气温下如何保养
|
||||
2026-03-01 11:08:09,924 - Agent - INFO - middleware.py:18 - [tool monitor]执行工具:get_user_location
|
||||
2026-03-01 11:08:09,925 - Agent - INFO - middleware.py:19 - [tool monitor]传入参数:{}
|
||||
2026-03-01 11:08:09,926 - Agent - INFO - middleware.py:23 - [tool minitor]工具get_user_location调用成功
|
||||
2026-03-01 11:08:09,927 - Agent - INFO - middleware.py:39 - [log_before_model]即将调用模型,带有3条消息
|
||||
2026-03-01 11:08:09,927 - Agent - DEBUG - middleware.py:40 - [log_before_model]ToolMessage | 消息内容:杭州
|
||||
2026-03-01 11:08:13,076 - Agent - INFO - middleware.py:18 - [tool monitor]执行工具:get_weather
|
||||
2026-03-01 11:08:13,076 - Agent - INFO - middleware.py:19 - [tool monitor]传入参数:{'city': '杭州'}
|
||||
2026-03-01 11:08:13,078 - Agent - INFO - middleware.py:23 - [tool minitor]工具get_weather调用成功
|
||||
2026-03-01 11:08:13,079 - Agent - INFO - middleware.py:39 - [log_before_model]即将调用模型,带有5条消息
|
||||
2026-03-01 11:08:13,079 - Agent - DEBUG - middleware.py:40 - [log_before_model]ToolMessage | 消息内容:城市杭州天气为晴天,温度为26摄氏度,湿度50%,南风1级,AQI21,最近6小时降雨概率极低
|
||||
2026-03-01 11:08:16,346 - Agent - INFO - middleware.py:18 - [tool monitor]执行工具:rag_summarize
|
||||
2026-03-01 11:08:16,346 - Agent - INFO - middleware.py:19 - [tool monitor]传入参数:{'query': '扫地机器人在26摄氏度温度和50%湿度环境下的保养方法'}
|
||||
2026-03-01 11:08:19,183 - Agent - INFO - middleware.py:23 - [tool minitor]工具rag_summarize调用成功
|
||||
2026-03-01 11:08:19,185 - Agent - INFO - middleware.py:39 - [log_before_model]即将调用模型,带有7条消息
|
||||
2026-03-01 11:08:19,185 - Agent - DEBUG - middleware.py:40 - [log_before_model]ToolMessage | 消息内容:参考资料中未提及扫地机器人在26摄氏度温度和50%湿度环境下的具体保养方法。
|
||||
2026-03-01 11:08:21,538 - Agent - INFO - middleware.py:18 - [tool monitor]执行工具:rag_summarize
|
||||
2026-03-01 11:08:21,539 - Agent - INFO - middleware.py:19 - [tool monitor]传入参数:{'query': '扫地机器人日常保养方法'}
|
||||
2026-03-01 11:08:25,493 - Agent - INFO - middleware.py:23 - [tool minitor]工具rag_summarize调用成功
|
||||
2026-03-01 11:08:25,494 - Agent - INFO - middleware.py:39 - [log_before_model]即将调用模型,带有9条消息
|
||||
2026-03-01 11:08:25,494 - Agent - DEBUG - middleware.py:40 - [log_before_model]ToolMessage | 消息内容:定期清理滚刷和边刷上的缠绕物,清空尘盒,擦拭传感器和充电触点,检查并清理滤网,避免在潮湿或有水区域使用,及时更换磨损配件。
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue