liutao 2 месяцев назад
Родитель
Сommit
55d95fe1b4

+ 9 - 4
aiAgent_gd/qwen_agent/memory/data/plans/plan_examples_智能选址.jsonl

@@ -1,12 +1,17 @@
 [
   {
     "query_type": "land_site_selection",
-    "query": "帮我在萧山区推荐几块50亩左右的工业用地",
-    "plan": "Question: 帮我在萧山区推荐几块50亩左右的工业用地 \nThought: 用户问题中想查询城市为‘萧山区’,面积为‘50’亩左右,用地性质‘工业’的地块,数量未限制,所以需要通过[LandSiteSelectionSqlAgent]查询图层信息,最后使用summary的Action来总结并输出。Plan: ```json\n    [{\"action_name\": \"LandSiteSelectionSqlAgent\", \"instruction\": \"你需要调用 [LandSiteSelectionSqlAgent],来查询城市为‘萧山区’,面积为‘50’亩左右,用地性质‘工业’的地块\"},\n    {\"action_name\": \"summary\", \"instruction\": \"你需要根据用户的Question和查询的结果,回答用户问题。\"}]"
+    "query": "帮我在萧山区推荐几块50亩左右的工业用地,数据表是控制性详细规划",
+    "plan": "Question: 帮我在萧山区推荐几块50亩左右的工业用地 \nThought: 用户问题中想查询城市为‘萧山区’,面积为‘50’亩左右,用地性质‘工业’的地块,数量未限制,数据表是控制性详细规划表,所以需要通过[LandSiteSelectionSqlAgent]查询图层信息,最后使用summary的Action来总结并输出。Plan: ```json\n    [{\"action_name\": \"LandSiteSelectionSqlAgent\", \"instruction\": \"你需要调用 [LandSiteSelectionSqlAgent],来查询城市为‘萧山区’,面积为‘50’亩左右,数据表是‘控制性详细规划’表,用地性质‘工业’的地块\"},\n    {\"action_name\": \"summary\", \"instruction\": \"你需要根据用户的Question和查询的结果,回答用户问题。\"}]"
   },
   {
     "query_type": "land_site_selection",
-    "query": "帮我在萧山区推荐一宗1公顷左右的学校用地",
-    "plan": "Question: 帮我在萧山区推荐一宗1公顷左右的学校用地\nThought: 用户问题中想查询城市为‘萧山区’,数量为‘1’宗,面积为‘1公顷’左右,用地性质‘学校’的地块,所以需要通过[LandSiteSelectionSqlAgent]查询图层信息,最后使用summary的Action来总结并输出。Plan: ```json\n    [{\"action_name\": \"LandSiteSelectionSqlAgent\", \"instruction\": \"你需要调用 [LandSiteSelectionSqlAgent],来查询城市为‘萧山区’,数量为‘1’宗,面积为‘1公顷’左右,用地性质'学校'的地块\"},\n    {\"action_name\": \"summary\", \"instruction\": \"你需要根据用户的Question和查询的结果,回答用户问题。\"}]"
+    "query": "帮我在萧山区推荐一宗1公顷左右的学校用地,数据表是控制性详细规划\"",
+    "plan": "Question: 帮我在萧山区推荐一宗1公顷左右的学校用地\nThought: 用户问题中想查询城市为‘萧山区’,数量为‘1’宗,面积为‘1公顷’左右,用地性质‘学校’的地块,所以需要通过[LandSiteSelectionSqlAgent]查询图层信息,最后使用summary的Action来总结并输出。Plan: ```json\n    [{\"action_name\": \"LandSiteSelectionSqlAgent\", \"instruction\": \"你需要调用 [LandSiteSelectionSqlAgent],来查询城市为‘萧山区’,数量为‘1’宗,面积为‘1公顷’左右,数据表是‘控制性详细规划’表,用地性质'学校'的地块\"},\n    {\"action_name\": \"summary\", \"instruction\": \"你需要根据用户的Question和查询的结果,回答用户问题。\"}]"
+  },
+  {
+    "query_type": "land_site_selection",
+    "query": "帮我在萧山区推荐几块50亩左右的工业用地,数据表是公告地块",
+    "plan": "Question: 帮我在萧山区推荐几块50亩左右的工业用地 \nThought: 用户问题中想查询城市为‘萧山区’,面积为‘50’亩左右,用地性质‘工业’的地块,数量未限制,数据表是公告地块表,所以需要通过[LandSiteSelectionSqlAgent]查询图层信息,最后使用summary的Action来总结并输出。Plan: ```json\n    [{\"action_name\": \"LandSiteSelectionSqlAgent\", \"instruction\": \"你需要调用 [LandSiteSelectionSqlAgent],来查询城市为‘萧山区’,面积为‘50’亩左右,数据表是‘公告地块’表,用地性质‘工业’的地块\"},\n    {\"action_name\": \"summary\", \"instruction\": \"你需要根据用户的Question和查询的结果,回答用户问题。\"}]"
   }
 ]

+ 9 - 4
aiAgent_gd/qwen_agent/memory/data/sqls/sql_examples_智能选址.jsonl

@@ -1,12 +1,17 @@
 [
   {
     "query_type": "land_site_selection",
-    "query": "帮我在萧山区推荐几块50亩左右的工业用地",
-    "sql_code": "select objectid, dymc, xzqmc, ydxz, st_area(shape::geography) as pfmarea, st_astext(st_centroid(shape)) as center_wkt from dlgis.gcs330000g2007_kzxxxgh_kgdk_kgy_dsgj as a where xzqmc = '萧山区' and ydxz like '%工业%' and abs(ydmj - 50*0.0667) <= 1 and NOT EXISTS (select 1 from dlgis.gcs330000k3003_zdzy_gd as b where st_intersects(a.shape, b.shape)) order by ydmj nulls last limit 10"
+    "query": "帮我在萧山区推荐几块50亩左右的工业用地,数据表是控制性详细规划",
+    "sql_code": "select objectid from sde.kzxxxgh where xzqmc = '萧山区' and ydxz like '%工业%' and abs(ydmj - 50*0.0667) <= 1  order by ydmj nulls last limit 10"
   },
   {
     "query_type": "land_site_selection",
-    "query": "帮我在萧山区推荐一宗1公顷左右的学校用地",
-    "sql_code": "select objectid,dymc, xzqmc, ydxz, st_area(shape::geography) as pfmarea, st_astext(st_centroid(shape)) as center_wkt from dlgis.gcs330000g2007_kzxxxgh_kgdk_kgy_dsgj as a where xzqmc = '萧山区' and ydxz like '%学校%' and abs(ydmj - 1) <= 1 and NOT EXISTS (select 1 from dlgis.gcs330000k3003_zdzy_gd as b where st_intersects(a.shape, b.shape)) order by ydmj nulls last limit 10"
+    "query": "帮我在萧山区推荐一宗1公顷左右的学校用地,数据表是控制性详细规划",
+    "sql_code": "select objectid from sde.kzxxxgh where xzqmc = '萧山区' and ydxz like '%学校%' and abs(ydmj - 1) <= 1 order by ydmj nulls last limit 10"
+  },
+  {
+    "query_type": "land_site_selection",
+    "query": "帮我在萧山区推荐几块50亩左右的工业用地,数据表是公告地块",
+    "sql_code": "select id from sde.ecgap_klyzy where xzqmc = '萧山区' and tdyt like '%工业%' and abs(dkmj-5) <= 1  order by dkmj nulls last limit 10"
   }
 ]

+ 29 - 18
aiAgent_gd/qwen_agent/sub_agent/sql/land_site_selection_sql_agent.py

@@ -32,11 +32,12 @@ class LandSiteSelectionSqlAgent(BaseSubAgent):
         self.SubAgent_Summary_Prompt = "通过查询数据库,检索数据库得到的信息为:\n{obs}\n"
         self.SubAgent_PROMPT = """你是一个PostgreSQL专家,当前需要根据用户问题和上下文,生成语法正确的PostgreSQL查询语句。'
          #数据库表的表名和表结构如下:
-        `dlgis.gcs330000g2007_kzxxxgh_kgdk_kgy_dsgj`(
+         以下是控制性详细规划表
+        `sde.kzxxxgh`(
             `objectid` COMMENTS '主键ID',
             `xzqmc` COMMENTS '所属区县(行政区代码) 用来指定‘区’或者‘县’',
             `xzqdm` COMMENTS '行政区代码 6位,前2位代表省,前4位代表市,前6位代表区县',
-            `dymc` COMMENTS '地块名称',
+            `dymc` COMMENTS '单元名称',
             `yddm` COMMENTS '用地代码',
             `ydxz` COMMENTS '用地性质',
             `ydmj` COMMENTS '用地面积 单位:公顷',
@@ -52,23 +53,33 @@ class LandSiteSelectionSqlAgent(BaseSubAgent):
             `ldlxx` COMMENTS '绿地率下限',
             `shape` COMMENTS '地块图形wkt',
         )'
-
+        
+        以下是公告地块表
+         `sde.ecgap_klyzy`(
+            `id` COMMENTS '主键ID',
+            `xzqmc` COMMENTS '所属区县(行政区代码) 用来指定区 或者 县',
+            `xzqdm` COMMENTS '行政区代码 6位,前2位代表省,前4位代表市,前6位代表区县',
+            `dkmc` COMMENTS '地块名称',
+            `dkid` COMMENTS '地块id',
+            `address` COMMENTS '土地坐落',
+            `dkmj` COMMENTS '土地面积,单位亩',
+            `tdyt` COMMENTS '土地规划用途',
+            `shape` COMMENTS '地块图形wkt',
+            `sfsj` COMMENTS '是否上架 1表示已上架,0表示未上架'
+        )
         有几个注意事项:
-        注意1: 查询地区条件时,区县为**时请使用 xzqmc 字段。省为**时请先将行政区名称转换为行政区代码,使用xzqdm字段的前2位进行模糊查询,市为**时请先将行政区名称转换为行政区代码,使用xzqdm字段的前4位进行模糊查询
-        注意2: 使用 order by 进行排序时。必须使用 nulls last 确保 null值不会对排序产生影响,使用方法如下: order by xxxx desc nulls last 或者 order by xxxx nulls last
-        注意3: 当用户问题中的面积等于不是一个确定值的时候,如‘面积为xx亩左右’或‘面积为xx平方米左右’或‘面积为xx公顷左右’, 需要条件中添加 abs(ydmj - xx) <= 1, 将面积差控制在1公顷之内。使用 ‘order by abs(ydmj - xx)  nulls last’ 来进行排序
-        注意4: 当用户问题中的面积是一个确定值的时候,如‘面积为xx亩’或‘面积为xx平方米’或‘面积为xx公顷左右’, 需要条件中添加 abs(ydmj - xx) <= 1, 将面积差控制在1公顷之内。使用 ‘order by abs(ydmj - xx)  nulls last’ 来进行排序
-        注意5: 查询出地块。必须要对ydmj进行desc排序。查询地块有数量限制时,比如'1宗','一宗','1块',使用limit 1语句;未限定时,只查询10宗,使用limit 10语句
-        注意6: 问题中设计具体的地点时,需要使用round(st_distance(st_geometryfromtext('具体地点的wkt', 4490)::geography,shape::geography)::numeric,0)获取其distance, 如果问题未指定范围则使用 distance <= 5000 来限制在地点5公里内,并对其排序
-        注意7: 生成sql时,只对涉及表结构中的字段进行条件设置,不可生成不在表字段列表中的查询条件,不可生成任何不在表字段中的条件,比如周边5公里有什么设施
-        注意8: 生成sql时,必须使用 st_astext(st_centroid(shape)) as center_wkt 
-        注意9: 查询语句必须包含 objectid, dymc, xzqmc, ydxz, st_area(shape::geography) as pfmarea, st_astext(st_centroid(shape)) as center_wkt 这几个字段
-        注意10: 只准生成查询 的sql 语句,不可生成任何 修改数据的语句, 比如:update, delete, insert, truncate 等
-        注意11:当用户问题中的用地性质是"工业用地"时,去掉"用地",使用ydxz进行模糊查询,比如ydxz like '%工业%',工业用地没有二级分类
-        注意12:where语句中必须包含NOT EXISTS (select 1 from dlgis.gcs330000k3003_zdzy_gd as b where st_intersects(a.shape, b.shape)
-        注意13:数据表的schema是dlgis
-        注意14:from语句中给dlgis.gcs330000g2007_kzxxxgh_kgdk_kgy_dsgj设置别名a
-        注意15:select语句中使用st_area(shape::geography) as pfmarea字段来计算面积,单位是平方米,不要做任何的单位换算
+        
+        注意1:查询的数据表有两张,分别是控制性详细规划表(sde.kzxxxgh)和公告地块表(sde.ecgap_klyzy)
+        注意2: 查询地区条件时,区县为**时请使用 xzqmc 字段。省为**时请先将行政区名称转换为行政区代码,使用xzqdm字段的前2位进行模糊查询,市为**时请先将行政区名称转换为行政区代码,使用xzqdm字段的前4位进行模糊查询
+        注意3: 使用 order by 进行排序时。必须使用 nulls last 确保 null值不会对排序产生影响,使用方法如下: order by xxxx desc nulls last 或者 order by xxxx nulls last
+        注意4: 当用户问题中的面积等于不是一个确定值的时候,如‘面积为xx亩左右’或‘面积为xx平方米左右’或‘面积为xx公顷左右’, 需要条件中添加 abs(ydmj - xx) <= 1, 将面积差控制在1公顷之内。使用 ‘order by abs(ydmj - xx)  nulls last’ 来进行排序
+        注意5: 当用户问题中的面积是一个确定值的时候,如‘面积为xx亩’或‘面积为xx平方米’或‘面积为xx公顷左右’, 需要条件中添加 abs(ydmj - xx) <= 1, 将面积差控制在1公顷之内。使用 ‘order by abs(ydmj - xx)  nulls last’ 来进行排序
+        注意6: 查询出地块。必须要对ydmj进行desc排序。查询地块有数量限制时,比如'1宗','一宗','1块',使用limit 1语句;未限定时,只查询10宗,使用limit 10语句
+        注意7: 问题中设计具体的地点时,需要使用round(st_distance(st_geometryfromtext('具体地点的wkt', 4490)::geography,shape::geography)::numeric,0)获取其distance, 如果问题未指定范围则使用 distance <= 5000 来限制在地点5公里内,并对其排序
+        注意8: 控制性详细规划表查询语句select种只包含objectid字段,公告地块表查询语句select种只包含id字段
+        注意9: 只准生成查询 的sql 语句,不可生成任何 修改数据的语句, 比如:update, delete, insert, truncate 等
+        注意10:当用户问题中的数据源是‘控制性详细规划表’,用地性质是"工业用地"时,去掉"用地",使用ydxz进行模糊查询,比如ydxz like '%工业%',工业用地没有二级分类
+        注意11:数据表的schema是sde
         """
         self.retriever = SqlRetriever(query_type='land_site_selection')
 

+ 24 - 9
aiAgent_gd/run_server_async.py

@@ -6,6 +6,7 @@ from typing import List
 from zipfile import ZipFile
 import json
 import fiona
+from pydantic import BaseModel
 from shapely.geometry import shape
 from sse_starlette.sse import EventSourceResponse
 from fastapi import FastAPI, UploadFile, File, Form
@@ -26,7 +27,8 @@ from qwen_agent.llm.llm_client import LLMClient, LLMAsyncClient
 from agent_config import LLMDict_Qwen_72B_1211, LLMDict_GPT4_TURBO
 from agent_messages import BaseRequest
 from qwen_agent.tools.tools import async_xzdb
-from qwen_agent.tools.gis.spatial_analysis.geo_analysis import  intersect_kfq,intersect_gyyd
+from qwen_agent.tools.gis.spatial_analysis.geo_analysis import intersect_kfq, intersect_gyyd
+
 prompt_lan = "CN"
 llm_name = "qwen-plus"
 llm_turbo_name = "gpt-4-turbo"
@@ -174,9 +176,18 @@ async def clarificationByTurbo(request: BaseRequest):
     )
 
 
-@app.get("/queryGeometry")
-async def queryGeometry(id: int):
-    sql = f'select objectid, xzqmc, xzqdm, dymc, yddm, ydxz, ydmj, rjlsx, rjlxx, jzmdsx, jzmdxx, jzgdsx, jzgdxx, ldlsx, ldlxx, pfwh, pfsj, shape, st_area(shape::geography) as pfmarea,st_astext(shape) as geom, st_astext(st_centroid(shape)) as center_wkt from dlgis.gcs330000g2007_kzxxxgh_kgdk_kgy_dsgj where objectid = {id}'
+@app.get("/kgQuery")
+async def kgQuery(id: str):
+    sql = f'select objectid, xzqmc, xzqdm, dymc, yddm, ydxz, ydmj, rjlsx, rjlxx, jzmdsx, jzmdxx, jzgdsx, jzgdxx, ldlsx, ldlxx, pfwh, pfsj, st_area(shape::geography) as pfmarea,st_astext(shape) as geom, st_astext(st_centroid(shape)) as center_wkt from sde.kzxxxgh where objectid in ({id})'
+    res_tuples = await async_xzdb.run(sql)
+    result, success = res_tuples
+    print(success, result)
+    return json.loads(result)
+
+
+@app.get("/klyzyQuery")
+async def klyzyQuery(id: str):
+    sql = f'select *, st_astext(shape) as geom, st_astext(st_centroid(shape)) as center_wkt from sde.ecgap_klyzy where id in ({id})'
     res_tuples = await async_xzdb.run(sql)
     result, success = res_tuples
     print(success, result)
@@ -191,6 +202,7 @@ async def queryGeometryList(items):
     print(success, result)
     return json.loads(result)
 
+
 @app.get("/queryYjjbntGeometry")
 async def queryYjjbntGeometry(id: int):
     sql = f'select *,st_astext(shape) as geom from dlgis.gcs330000g2001_yjjbnt_gx_xsb where objectid = {id}'
@@ -199,17 +211,20 @@ async def queryYjjbntGeometry(id: int):
     print(success, result)
     return json.loads(result)
 
+
 @app.get("/kfqintersect")
-async def kfqintersect(wkt:str):
-    result= await intersect_kfq(
+async def kfqintersect(wkt: str):
+    result = await intersect_kfq(
         wkt)
     return result
 
-@app.get("/intersect_gyyd")
-async def gyydintersect(wkt:str):
-    result= await intersect_gyyd(wkt)
+
+@app.get("/gyydintersect")
+async def gyydintersect(wkt: str):
+    result = await intersect_gyyd(wkt)
     return result
 
+
 llm_client = LLMClient(model=llm_name, model_server=model_server)
 llm_client_async = LLMAsyncClient(model=llm_name, model_server=model_server)