feat:完成数据文件上传解析及测试
This commit is contained in:
+21
-9
@@ -1,5 +1,7 @@
|
||||
"""数据文件的本地工具:describe_data 查看列概况,query_data 执行只读 SQL;问答和 screen agent 共用
|
||||
|
||||
apply_actions 里的 $query 也通过 DataContext.query 执行,见 tools.py
|
||||
|
||||
工具只能看到 DataContext 里的表,也就是当前用户在本会话里未过期的文件,查询引擎也只为这些表建视图
|
||||
工具通过 runtime.context.data 读取 DataContext,用到它们的 agent 上下文都要有 data 字段;
|
||||
上下文类型因 agent 而异,所以写 ToolRuntime[Any](不写类型参数时按 None 处理,序列化会告警)
|
||||
@@ -14,7 +16,7 @@ from langchain_core.messages import ToolMessage
|
||||
from pydantic import Field
|
||||
|
||||
from app.config import settings
|
||||
from app.datafiles.query import QueryError, run_query
|
||||
from app.datafiles.query import MAX_ROWS, QueryError, QueryResult, run_query
|
||||
from app.schemas.data_file import RequestDataFile, RequestDataTable
|
||||
|
||||
# 列超过这么多时,不指定 columns 只返回列名和类型,避免一次塞进太多概况
|
||||
@@ -39,6 +41,22 @@ class DataContext:
|
||||
for table in file.tables
|
||||
}
|
||||
|
||||
def query(self, sql: str, *, max_rows: int = MAX_ROWS) -> QueryResult:
|
||||
"""执行一条只读 SQL;失败时抛 QueryError,原因可以直接返回给模型修正"""
|
||||
paths = self.paths()
|
||||
# 任务执行期间被删除或清理的文件跳过,不影响查询其他表
|
||||
existing = {name: path for name, path in paths.items() if path.exists()}
|
||||
try:
|
||||
return run_query(
|
||||
sql, existing, timeout=settings.data_query_timeout, max_rows=max_rows
|
||||
)
|
||||
except QueryError as error:
|
||||
if gone := [name for name in paths if name not in existing]:
|
||||
raise QueryError(
|
||||
f"{error};{'、'.join(gone)} 的文件已删除或过期,不能再查询"
|
||||
) from None
|
||||
raise
|
||||
|
||||
|
||||
def _error(runtime: ToolRuntime, message: str) -> ToolMessage:
|
||||
# 返回给模型修正,不中断 agent
|
||||
@@ -111,16 +129,10 @@ def query_data(sql: str, runtime: ToolRuntime[Any]) -> dict[str, Any] | ToolMess
|
||||
回答和图表里的数字以查询结果为准,不要自己心算
|
||||
"""
|
||||
data: DataContext = runtime.context.data
|
||||
paths = data.paths()
|
||||
# 任务执行期间被删除或清理的文件跳过,不影响查询其他表
|
||||
existing = {name: path for name, path in paths.items() if path.exists()}
|
||||
try:
|
||||
return run_query(sql, existing, timeout=settings.data_query_timeout).to_dict()
|
||||
return data.query(sql).to_dict()
|
||||
except QueryError as error:
|
||||
message = str(error)
|
||||
if gone := [name for name in paths if name not in existing]:
|
||||
message += f";{'、'.join(gone)} 的文件已删除或过期,不能再查询"
|
||||
return _error(runtime, message)
|
||||
return _error(runtime, str(error))
|
||||
|
||||
|
||||
DATA_TOOLS = [describe_data, query_data]
|
||||
|
||||
Reference in New Issue
Block a user