tool_examples.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. """
  2. Tool Examples - 工具装饰器使用样例
  3. 本文件展示 @tool 装饰器的各种用法,参考 Resonote 项目的实际工具实现。
  4. 样例包括:
  5. 1. 基础工具(最简形式)
  6. 2. 带 i18n 展示信息的工具
  7. 3. 带可编辑参数的工具
  8. 4. 需要用户确认的危险操作
  9. 5. 带 context 参数的工具
  10. 6. 同步工具
  11. 注意:
  12. - uid 参数会由框架自动注入,不需要用户传递
  13. - context 参数用于传递额外上下文(如当前阅读位置等)
  14. - 返回值会自动序列化为 JSON 字符串
  15. """
  16. from typing import List, Dict, Any, Optional
  17. from reson_agent import tool
  18. # ============================================================
  19. # 1. 基础工具(最简形式)
  20. # ============================================================
  21. @tool()
  22. async def hello_world(name: str, uid: str = "") -> Dict[str, str]:
  23. """
  24. 最简单的工具示例
  25. Args:
  26. name: 要问候的名字
  27. uid: 用户ID(自动注入)
  28. Returns:
  29. 包含问候语的字典
  30. """
  31. return {"greeting": f"Hello, {name}!"}
  32. # ============================================================
  33. # 2. 带 i18n 展示信息的工具
  34. # ============================================================
  35. @tool(
  36. display={
  37. "zh": {
  38. "name": "搜索内容",
  39. "params": {
  40. "query": "搜索关键词",
  41. "limit": "返回数量"
  42. }
  43. },
  44. "en": {
  45. "name": "Search Content",
  46. "params": {
  47. "query": "Search query",
  48. "limit": "Number of results"
  49. }
  50. }
  51. }
  52. )
  53. async def search_content(
  54. query: str,
  55. limit: int = 10,
  56. uid: str = ""
  57. ) -> List[Dict[str, Any]]:
  58. """
  59. 搜索用户的内容
  60. 使用语义搜索查找相关内容。display 参数用于前端展示:
  61. - 工具名称会根据用户语言显示为"搜索内容"或"Search Content"
  62. - 参数名称也会相应翻译
  63. Args:
  64. query: 搜索查询文本
  65. limit: 返回结果数量(默认10)
  66. uid: 用户ID(自动注入)
  67. Returns:
  68. 搜索结果列表,每个包含 id, title, content, score
  69. """
  70. # 实际实现中会调用向量搜索
  71. # 这里只是示例
  72. return [
  73. {
  74. "id": "doc_001",
  75. "title": f"关于 {query} 的文档",
  76. "content": f"这是与 {query} 相关的内容...",
  77. "score": 0.95
  78. }
  79. ]
  80. # ============================================================
  81. # 3. 带可编辑参数的工具
  82. # ============================================================
  83. @tool(
  84. editable_params=["query", "filters"],
  85. display={
  86. "zh": {
  87. "name": "高级搜索",
  88. "params": {
  89. "query": "搜索关键词",
  90. "filters": "过滤条件",
  91. "sort_by": "排序方式"
  92. }
  93. },
  94. "en": {
  95. "name": "Advanced Search",
  96. "params": {
  97. "query": "Search query",
  98. "filters": "Filters",
  99. "sort_by": "Sort by"
  100. }
  101. }
  102. }
  103. )
  104. async def advanced_search(
  105. query: str,
  106. filters: Optional[Dict[str, Any]] = None,
  107. sort_by: str = "relevance",
  108. limit: int = 20,
  109. uid: str = ""
  110. ) -> Dict[str, Any]:
  111. """
  112. 高级搜索工具(允许用户编辑参数)
  113. editable_params 指定哪些参数允许用户在 LLM 生成后编辑:
  114. - LLM 会先生成 query 和 filters
  115. - 用户可以在确认前修改这些参数
  116. - 适用于搜索、创建等需要用户微调的场景
  117. Args:
  118. query: 搜索查询
  119. filters: 过滤条件(如 {"type": "note", "date_range": "7d"})
  120. sort_by: 排序方式(relevance/date/title)
  121. limit: 返回数量
  122. uid: 用户ID(自动注入)
  123. Returns:
  124. 搜索结果和元数据
  125. """
  126. return {
  127. "results": [
  128. {"id": "1", "title": "Result 1", "score": 0.9},
  129. {"id": "2", "title": "Result 2", "score": 0.8},
  130. ],
  131. "total": 42,
  132. "query": query,
  133. "filters_applied": filters or {},
  134. "sort_by": sort_by
  135. }
  136. # ============================================================
  137. # 4. 需要用户确认的危险操作
  138. # ============================================================
  139. @tool(
  140. requires_confirmation=True,
  141. display={
  142. "zh": {
  143. "name": "删除内容",
  144. "params": {
  145. "content_id": "内容ID",
  146. "permanent": "永久删除"
  147. }
  148. },
  149. "en": {
  150. "name": "Delete Content",
  151. "params": {
  152. "content_id": "Content ID",
  153. "permanent": "Permanent delete"
  154. }
  155. }
  156. }
  157. )
  158. async def delete_content(
  159. content_id: str,
  160. permanent: bool = False,
  161. uid: str = ""
  162. ) -> Dict[str, Any]:
  163. """
  164. 删除内容(需要用户确认)
  165. requires_confirmation=True 表示这是一个危险操作:
  166. - LLM 调用此工具时,不会立即执行
  167. - 会先向用户展示操作详情,等待确认
  168. - 用户确认后才会真正执行
  169. 适用场景:
  170. - 删除操作
  171. - 发送消息
  172. - 修改重要设置
  173. - 任何不可逆操作
  174. Args:
  175. content_id: 要删除的内容ID
  176. permanent: 是否永久删除(False=移到回收站)
  177. uid: 用户ID(自动注入)
  178. Returns:
  179. 删除结果
  180. """
  181. # 实际实现中会执行删除
  182. return {
  183. "success": True,
  184. "content_id": content_id,
  185. "permanent": permanent,
  186. "message": f"内容 {content_id} 已{'永久删除' if permanent else '移到回收站'}"
  187. }
  188. # ============================================================
  189. # 5. 带 context 参数的工具
  190. # ============================================================
  191. @tool(
  192. display={
  193. "zh": {
  194. "name": "获取相关推荐",
  195. "params": {
  196. "top_k": "推荐数量"
  197. }
  198. },
  199. "en": {
  200. "name": "Get Recommendations",
  201. "params": {
  202. "top_k": "Number of recommendations"
  203. }
  204. }
  205. }
  206. )
  207. async def get_recommendations(
  208. top_k: int = 5,
  209. uid: str = "",
  210. context: Optional[Dict[str, Any]] = None
  211. ) -> List[Dict[str, Any]]:
  212. """
  213. 获取相关推荐(使用 context 获取额外信息)
  214. context 参数用于传递执行上下文,由框架自动注入:
  215. - 当前阅读位置 (current_location)
  216. - 当前会话 ID (session_id)
  217. - 排除的内容 ID (exclude_ids)
  218. - 等等...
  219. 框架会检查函数签名,如果有 context 参数就自动传入。
  220. Args:
  221. top_k: 返回推荐数量
  222. uid: 用户ID(自动注入)
  223. context: 执行上下文(自动注入)
  224. Returns:
  225. 推荐列表
  226. """
  227. # 从 context 中提取信息
  228. current_location = None
  229. exclude_ids = []
  230. if context:
  231. current_location = context.get("current_location")
  232. exclude_ids = context.get("exclude_ids", [])
  233. # 实际实现中会根据 context 生成推荐
  234. return [
  235. {
  236. "id": "rec_001",
  237. "title": "推荐内容 1",
  238. "reason": f"基于当前位置 {current_location}" if current_location else "基于您的兴趣"
  239. },
  240. {
  241. "id": "rec_002",
  242. "title": "推荐内容 2",
  243. "reason": "热门内容"
  244. }
  245. ]
  246. # ============================================================
  247. # 6. 同步工具(非 async)
  248. # ============================================================
  249. @tool(
  250. display={
  251. "zh": {
  252. "name": "格式化文本",
  253. "params": {
  254. "text": "原始文本",
  255. "format_type": "格式类型"
  256. }
  257. },
  258. "en": {
  259. "name": "Format Text",
  260. "params": {
  261. "text": "Raw text",
  262. "format_type": "Format type"
  263. }
  264. }
  265. }
  266. )
  267. def format_text(
  268. text: str,
  269. format_type: str = "markdown",
  270. uid: str = ""
  271. ) -> str:
  272. """
  273. 格式化文本(同步工具)
  274. 不需要 async 的工具可以定义为普通函数。
  275. 框架会自动检测并正确调用。
  276. 适用于:
  277. - 纯计算操作
  278. - 文本处理
  279. - 不需要 I/O 的操作
  280. Args:
  281. text: 要格式化的文本
  282. format_type: 格式类型(markdown/plain/html)
  283. uid: 用户ID(自动注入)
  284. Returns:
  285. 格式化后的文本
  286. """
  287. if format_type == "markdown":
  288. return f"**{text}**"
  289. elif format_type == "html":
  290. return f"<p>{text}</p>"
  291. else:
  292. return text
  293. # ============================================================
  294. # 7. 复杂返回类型的工具
  295. # ============================================================
  296. @tool(
  297. display={
  298. "zh": {
  299. "name": "分析内容",
  300. "params": {
  301. "content_id": "内容ID",
  302. "analysis_types": "分析类型"
  303. }
  304. },
  305. "en": {
  306. "name": "Analyze Content",
  307. "params": {
  308. "content_id": "Content ID",
  309. "analysis_types": "Analysis types"
  310. }
  311. }
  312. }
  313. )
  314. async def analyze_content(
  315. content_id: str,
  316. analysis_types: Optional[List[str]] = None,
  317. uid: str = ""
  318. ) -> Dict[str, Any]:
  319. """
  320. 分析内容(复杂返回类型)
  321. 展示如何返回复杂的嵌套结构。
  322. 返回值会自动序列化为 JSON。
  323. Args:
  324. content_id: 要分析的内容ID
  325. analysis_types: 分析类型列表(sentiment/keywords/summary)
  326. uid: 用户ID(自动注入)
  327. Returns:
  328. 分析结果,包含多种分析数据
  329. """
  330. types = analysis_types or ["sentiment", "keywords"]
  331. result = {
  332. "content_id": content_id,
  333. "analyses": {}
  334. }
  335. if "sentiment" in types:
  336. result["analyses"]["sentiment"] = {
  337. "score": 0.8,
  338. "label": "positive",
  339. "confidence": 0.92
  340. }
  341. if "keywords" in types:
  342. result["analyses"]["keywords"] = [
  343. {"word": "AI", "weight": 0.9},
  344. {"word": "学习", "weight": 0.7},
  345. {"word": "创新", "weight": 0.6}
  346. ]
  347. if "summary" in types:
  348. result["analyses"]["summary"] = {
  349. "short": "这是一篇关于AI学习的文章",
  350. "long": "本文详细介绍了AI在学习领域的应用..."
  351. }
  352. return result
  353. # ============================================================
  354. # 使用示例
  355. # ============================================================
  356. if __name__ == "__main__":
  357. import asyncio
  358. from reson_agent import get_tool_registry
  359. async def main():
  360. # 获取全局注册表
  361. registry = get_tool_registry()
  362. # 查看已注册的工具
  363. print("已注册的工具:")
  364. for name in registry.get_tool_names():
  365. print(f" - {name}")
  366. # 获取工具 Schema
  367. schemas = registry.get_schemas(["search_content"])
  368. print("\nsearch_content Schema:")
  369. import json
  370. print(json.dumps(schemas[0], indent=2, ensure_ascii=False))
  371. # 执行工具
  372. result = await registry.execute(
  373. "search_content",
  374. {"query": "人工智能", "limit": 5},
  375. uid="user123"
  376. )
  377. print("\n执行结果:")
  378. print(result)
  379. # 获取 UI 元数据
  380. ui_meta = registry.get_ui_metadata(locale="zh", tool_names=["advanced_search"])
  381. print("\nUI 元数据 (中文):")
  382. print(json.dumps(ui_meta, indent=2, ensure_ascii=False))
  383. asyncio.run(main())