Files
my-v0-server/app/agent/qa_agent.py
T

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]