LightAgent 0.2.0__tar.gz → 0.2.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,13 +10,14 @@ from openai import OpenAI
10
10
  import logging
11
11
  import os
12
12
  import httpx
13
+ import importlib
13
14
 
14
15
  # 全局工具注册表
15
16
  _FUNCTION_MAPPINGS = {} # 工具名称 -> 工具函数
16
17
  _OPENAI_FUNCTION_SCHEMAS = [] # OpenAI 格式的工具描述
17
18
  _PROMPT_FUNCTION_SCHEMAS = [] # prompt 格式的工具描述
18
19
 
19
- import importlib
20
+ __version__ = "0.2.1" # 你可以根据需要设置版本号
20
21
 
21
22
 
22
23
  def register_tool_manually(tools: List[Union[str, Callable]]) -> bool:
@@ -113,6 +114,7 @@ def stream_generator(result):
113
114
  for chunk in result:
114
115
  yield chunk
115
116
 
117
+
116
118
  def dispatch_tool_old(tool_name: str, tool_params: Dict[str, Any]) -> str:
117
119
  """
118
120
  调用工具执行
@@ -146,7 +148,10 @@ def get_tools_str() -> str:
146
148
  tools_str = json.dumps(_OPENAI_FUNCTION_SCHEMAS, indent=4, ensure_ascii=False)
147
149
  return tools_str
148
150
 
151
+
149
152
  class LightAgent:
153
+ __version__ = "0.2.1" # 将版本号放在类中
154
+
150
155
  def __init__(
151
156
  self,
152
157
  *,
@@ -159,6 +164,7 @@ class LightAgent:
159
164
  websocket_base_url: str | httpx.URL | None = None,
160
165
  memory=None, # 支持外部传入记忆模块
161
166
  tree_of_thought: bool = False, # 是否启用链式思考
167
+ self_learning: bool = False, # 是否启用agent自我学习
162
168
  tools: List[Union[str, Callable]] = None, # 支持混合输入
163
169
  debug: bool = False, # 是否启用调试模式
164
170
  log_level: str = "INFO", # 日志级别(INFO, DEBUG, ERROR)
@@ -199,6 +205,7 @@ class LightAgent:
199
205
  self.model = model
200
206
  self.memory = memory
201
207
  self.tree_of_thought = tree_of_thought
208
+ self.self_learning = self_learning
202
209
 
203
210
  self.debug = debug
204
211
  self.log_level = log_level.upper()
@@ -233,8 +240,6 @@ class LightAgent:
233
240
  api_key=self.api_key
234
241
  )
235
242
 
236
-
237
-
238
243
  def get_tool(self, tool_name: str) -> Callable:
239
244
  """
240
245
  用于外部可以获取已加载的工具函数
@@ -355,6 +360,7 @@ class LightAgent:
355
360
  stream: bool = False,
356
361
  max_retry: int = 5,
357
362
  user_id: str = "default_user",
363
+ history: list = None,
358
364
  metadata: Optional[Dict] = None,
359
365
  ) -> Union[Generator[str, None, None], str]:
360
366
  """
@@ -365,10 +371,15 @@ class LightAgent:
365
371
  :param stream: 是否启用流式输出。
366
372
  :param max_retry: 最大重试次数。
367
373
  :param user_id: 用户 ID。
374
+ :param history: 历史对话 。
368
375
  :param metadata: 元数据。
369
376
  :return: 代理的回复。
370
377
  """
371
378
  self.log("INFO", "run", {"query": query, "user_id": user_id, "light_swarm": light_swarm, "stream": stream})
379
+ if history is None:
380
+ history = []
381
+ # 构建消息列表,先添加系统提示信息
382
+ params = {}
372
383
 
373
384
  # 1. 判断是否需要转移任务
374
385
  # if light_swarm:
@@ -393,14 +404,19 @@ class LightAgent:
393
404
  current_time = now.strftime("%H:%M:%S")
394
405
  system_prompt = f"##代理名称:{self.name} ##代理指令 /n{self.instructions} ##身份 /n {self.role} /n 请一步一步思考来完成用户的要求。尽可能完成用户的回答,如果有补充信息,请参考补充信息来调用工具,直到获取所有满足用户的提问所需的答案。 /n 今日的日期: {current_date} 当前时间: {current_time}"
395
406
  params = dict(model=self.model, stream=stream)
396
-
397
- # 3. 从记忆中检索相关内容
407
+ memory = ''
408
+ # 3. 从记忆中检索相关内容&保存记忆
398
409
  if self.memory:
399
410
  related_memories = self.memory.retrieve(query=query, user_id=user_id)
400
- query = self._build_context(query, related_memories)
411
+ memory = memory + self._build_context(related_memories)
401
412
  self.memory.store(data=query, user_id=user_id)
402
- else:
403
- query = query
413
+ if self.self_learning:
414
+ agent_memories = self.memory.retrieve(query=query, user_id=self.name)
415
+ memory = memory + self._build_agent_memory(agent_memories)
416
+ self.memory.store(data=query, user_id=self.name)
417
+
418
+ query = f"{memory}\n##用户提问:\n{query}"
419
+ # print(query)
404
420
 
405
421
  # 4. 拼接tools工具
406
422
  if self.tools:
@@ -415,10 +431,15 @@ class LightAgent:
415
431
  system_prompt = system_prompt + f" /n ##以下是问题的补充说明 /n {tot_response}"
416
432
  self.log("DEBUG", "tree_of_thought", {"response": tot_response})
417
433
 
418
- params["messages"] = [{"role": "system", "content": system_prompt}, {"role": "user", "content": query}]
434
+ # 6. 调用核心运行逻辑
435
+ params["messages"] = [{"role": "system", "content": system_prompt}]
436
+ # 将历史对话添加到消息列表中
437
+ for item in history:
438
+ params["messages"].append({"role": item["role"], "content": item["input"]})
439
+ # 最后添加当前用户的查询信息
440
+ params["messages"].append({"role": "user", "content": query})
419
441
  response = self.client.chat.completions.create(**params)
420
442
 
421
- # 6. 调用核心运行逻辑
422
443
  result = self._core_run_logic(response, params, stream, max_retry)
423
444
 
424
445
  return result
@@ -431,6 +452,9 @@ class LightAgent:
431
452
  if response.choices[0].message.tool_calls:
432
453
  # 初始化一个列表,用于存储所有工具调用的结果
433
454
  tool_responses = []
455
+ # 初始化变量
456
+ output = ""
457
+ function_call_name = ""
434
458
  tool_calls = response.choices[0].message.tool_calls
435
459
  self.log("DEBUG", "tool_calls", {"tool_calls": tool_calls})
436
460
 
@@ -444,6 +468,7 @@ class LightAgent:
444
468
 
445
469
  # 调用工具并获取响应
446
470
  tool_response = dispatch_tool(function_call.name, function_args)
471
+ function_call_name = function_call.name
447
472
  combined_response = ""
448
473
 
449
474
  # 如果工具返回的是生成器(流式输出),则将所有 chunk 叠加
@@ -451,7 +476,11 @@ class LightAgent:
451
476
  # print(f"Streaming response from tool: {function_call.name}")
452
477
  for chunk in tool_response:
453
478
  # print("Received chunk:", chunk) # 打印每个 chunk
454
- combined_response += chunk # 将每个 chunk 叠加
479
+ if function_call_name == 'finish':
480
+ content = chunk.choices[0].delta.content or ""
481
+ combined_response += content # 将每个 chunk 叠加
482
+ else:
483
+ combined_response += chunk # 将每个 chunk 叠加
455
484
  if combined_response == "":
456
485
  combined_response = "".join(tool_response)
457
486
  tool_responses.append(combined_response) # 将叠加后的完整响应添加到列表
@@ -489,6 +518,8 @@ class LightAgent:
489
518
  return reply
490
519
 
491
520
  # 更新响应
521
+ if function_call_name == 'finish':
522
+ return # 如果最后调用了finish工具,则结束生成器
492
523
  response = self.client.chat.completions.create(**params)
493
524
 
494
525
  # 重试次数用尽
@@ -509,8 +540,9 @@ class LightAgent:
509
540
 
510
541
  for chunk in response:
511
542
  content = chunk.choices[0].delta.content or ""
512
- yield chunk # 流式返回内容
513
- output += content
543
+ if content:
544
+ yield chunk # 流式返回内容
545
+ output += content
514
546
 
515
547
  try:
516
548
  # 检查是否有工具调用
@@ -554,6 +586,8 @@ class LightAgent:
554
586
  "arguments": tool_call["arguments"],
555
587
  }
556
588
  self.log("INFO", "tool_call", {"function_call": function_call})
589
+ # 将工具的调用信息推送给开发者
590
+ yield function_call
557
591
 
558
592
  # 解析参数并调用工具
559
593
  try:
@@ -569,14 +603,19 @@ class LightAgent:
569
603
  for json_obj in json_objects:
570
604
  function_args = json.loads(json_obj)
571
605
  tool_response = dispatch_tool(function_call["name"], function_args)
606
+ function_call_name = function_call["name"]
572
607
 
573
608
  # 如果工具返回的是生成器(流式输出),则将所有 chunk 叠加
574
609
  if isinstance(tool_response, Generator):
575
610
  # print(f"Streaming response from tool: {function_call['name']}")
576
611
  combined_response = ""
577
612
  for chunk in tool_response:
578
- # yield chunk
579
- combined_response += chunk # 将每个 chunk 叠加
613
+ yield chunk
614
+ if function_call_name == 'finish':
615
+ content = chunk.choices[0].delta.content or ""
616
+ combined_response += content # 将每个 chunk 叠加
617
+ else:
618
+ combined_response += chunk # 将每个 chunk 叠加
580
619
  tool_responses.append(combined_response) # 将叠加后的完整响应添加到列表
581
620
  else:
582
621
  # print(f"Non-streaming response from tool: {function_call['name']}")
@@ -610,6 +649,8 @@ class LightAgent:
610
649
  break
611
650
 
612
651
  # 更新响应
652
+ if function_call_name == 'finish':
653
+ return # 如果最后调用了finish工具,则结束生成器
613
654
  response = self.client.chat.completions.create(**params)
614
655
 
615
656
  # 重试次数用尽
@@ -710,25 +751,41 @@ class LightAgent:
710
751
  self.log("ERROR", "run_failed", {"error": str(e)})
711
752
  raise # 重新抛出异常以便调试
712
753
 
713
- def _build_context(self, user_input, related_memories):
754
+ def _build_context(self, related_memories):
714
755
  """
715
756
  构建上下文,将用户输入和记忆内容结合。
716
-
717
- :param user_input: 用户输入的问题或内容。
718
757
  :param related_memories: 从记忆中检索到的相关内容。
719
758
  :return: 结合记忆后的上下文。
720
759
  """
721
760
  if not related_memories or not related_memories["memories"]:
722
- return user_input
761
+ return ""
723
762
 
724
763
  memory_context = "\n".join([m["memory"] for m in related_memories["memories"]])
725
764
  if not memory_context:
726
- return user_input
765
+ return ""
727
766
 
728
- prompt = f"\n用户之前提到了\n{memory_context}。\n现在用户问\n{user_input}"
767
+ prompt = f"\n##用户偏好 \n用户之前提到了\n{memory_context}"
729
768
  self.log("DEBUG", "related_memories", {"memory_context": memory_context})
730
769
  return prompt
731
770
 
771
+ def _build_agent_memory(self, agent_memories):
772
+ """
773
+ 构建上下文,将用户输入和记忆内容结合。
774
+
775
+ :param agent_memories: 从记忆中检索到的相关内容。
776
+ :return: 结合记忆后的上下文。
777
+ """
778
+ if not agent_memories or not agent_memories["memories"]:
779
+ return ""
780
+
781
+ memory_context = "\n".join([m["memory"] for m in agent_memories["memories"]])
782
+ if not memory_context:
783
+ return ""
784
+
785
+ prompt = f"\n##以下是解决该问题的相关补充信息:\n{memory_context}。"
786
+ self.log("DEBUG", "agent_memories", {"memory_context": memory_context})
787
+ return prompt
788
+
732
789
  def run_thought(self, query: str, stream=False, tools=None):
733
790
  """使用思维树的方式 让大模型先根据get_tools_str生成一个解答用户query的工具使用计划"""
734
791
  tot_model = "deepseek-chat" # self.model