54 lines
2.1 KiB
Python
54 lines
2.1 KiB
Python
"""问答 agent:回答关于大屏和上传数据的问题
|
|
|
|
会话里有数据文件时挂 describe_data、query_data,先查询再回答;没有文件时不挂工具,只调用一次模型
|
|
"""
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
|
|
from langchain.agents import create_agent
|
|
from langchain.agents.middleware import ModelCallLimitMiddleware
|
|
|
|
from app.agent.data_tools import DATA_TOOLS, DataContext
|
|
from app.agent.tool_args import normalize_tool_args
|
|
from app.clients.llm import get_llm
|
|
from app.config import settings
|
|
from app.prompt.qa import QA_DATA_RULES, QA_SYSTEM_PROMPT
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class QAContext:
|
|
data: DataContext = field(default_factory=DataContext) # 本会话可用的数据表
|
|
|
|
|
|
# 是否挂数据工具 → agent
|
|
_agents: dict[bool, Any] = {}
|
|
|
|
|
|
def get_qa_agent(with_data: bool = False):
|
|
"""第一次使用时组装,之后复用;没有数据文件的请求看不到数据工具和相关提示"""
|
|
if with_data not in _agents:
|
|
_agents[with_data] = create_agent(
|
|
model=get_llm(),
|
|
tools=DATA_TOOLS if with_data else [],
|
|
system_prompt=(
|
|
f"{QA_SYSTEM_PROMPT}\n{QA_DATA_RULES}"
|
|
if with_data
|
|
else QA_SYSTEM_PROMPT
|
|
),
|
|
context_schema=QAContext,
|
|
middleware=[
|
|
# 有工具时才挂参数兼容:挂了 wrap_tool_call 中间件,没有工具也会多出一个工具节点
|
|
*([normalize_tool_args] if with_data else []),
|
|
# 超过上限时抛 ModelCallLimitExceededError,由节点按失败处理;
|
|
# 写成 end 时中间件只插入一条英文说明,节点分不清是正常结束还是用尽了次数
|
|
ModelCallLimitMiddleware(
|
|
run_limit=settings.max_qa_steps, exit_behavior="error"
|
|
),
|
|
],
|
|
# 不继承外层图的检查点:会话历史只保存回答文本,不保存查询过程
|
|
checkpointer=False,
|
|
name="qa_agent",
|
|
)
|
|
return _agents[with_data]
|