bug fixed for start point sidderent from current point
This commit is contained in:
77
uav_agent.py
77
uav_agent.py
@@ -20,26 +20,56 @@ import json
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
# from langchain.agents import create_tool_calling_agent
|
||||||
|
# from langchain.agents import create_react_agent as create_react_agent_anthropic
|
||||||
|
# from langchain.agents import AgentExecutor as AgentExecutorAnthropic
|
||||||
|
|
||||||
class EnhancedChatOpenAI(ChatOpenAI):
|
class EnhancedChatAnthropic(ChatAnthropic):
|
||||||
"""ChatOpenAI subclass that captures reasoning_content if provided by the API"""
|
"""
|
||||||
|
针对 Anthropic 的增强类:
|
||||||
|
1. 提取 'thinking' 块并将其转换为 ReAct 格式的 'Thought: ...'
|
||||||
|
2. 防止因为只有工具调用而导致的 content 为空
|
||||||
|
"""
|
||||||
|
|
||||||
def _create_chat_result(self, response: Any) -> ChatResult:
|
def generate(self, response: Any) -> ChatResult:
|
||||||
result = super()._create_chat_result(response)
|
result = super().generate(response)
|
||||||
|
|
||||||
|
for generation in result.generations:
|
||||||
|
message = generation.message
|
||||||
|
raw_content = message.content
|
||||||
|
|
||||||
|
# --- 逻辑 A: 处理思维链 (Thinking Blocks) ---
|
||||||
|
# 如果 content 是列表 (Anthropic 标准格式),提取 thinking
|
||||||
|
if isinstance(raw_content, list):
|
||||||
|
text_parts = []
|
||||||
|
thought_parts = []
|
||||||
|
|
||||||
|
for block in raw_content:
|
||||||
|
if isinstance(block, dict):
|
||||||
|
if block.get("type") == "thinking":
|
||||||
|
# 获取思考内容
|
||||||
|
thinking = block.get("thinking", "")
|
||||||
|
# 存入 additional_kwargs (保持与其他代码一致)
|
||||||
|
message.additional_kwargs["reasoning_content"] = thinking
|
||||||
|
thought_parts.append(f"Thought: {thinking}\n")
|
||||||
|
elif block.get("type") == "text":
|
||||||
|
text_parts.append(block.get("text", ""))
|
||||||
|
|
||||||
|
# 重组 Content,把思考放在最前面,欺骗 ReAct 解析器
|
||||||
|
final_text = "".join(text_parts)
|
||||||
|
if thought_parts and "Thought:" not in final_text:
|
||||||
|
message.content = "".join(thought_parts) + final_text
|
||||||
|
else:
|
||||||
|
message.content = final_text
|
||||||
|
|
||||||
|
# --- 逻辑 B: 处理纯工具调用导致的空字符串 ---
|
||||||
|
# 如果 content 为空,但有工具调用,我们手动补一个 Thought
|
||||||
|
# 这样 ReAct 解析器就不会报错说 "No action found"
|
||||||
|
if not message.content and message.tool_calls:
|
||||||
|
tool_name = message.tool_calls[0]['name']
|
||||||
|
# 伪造一个 Thought,让 Log 好看,也让解析器通过
|
||||||
|
message.content = f"Thought: I should use the {tool_name} tool to proceed.\n"
|
||||||
|
|
||||||
if hasattr(response, "choices") and response.choices:
|
|
||||||
for i, choice in enumerate(response.choices):
|
|
||||||
# Handle MiniMax reasoning_details
|
|
||||||
if hasattr(choice.message, "reasoning_details") and choice.message.reasoning_details:
|
|
||||||
reasoning = choice.message.reasoning_details[0].get('text', '')
|
|
||||||
if reasoning and i < len(result.generations):
|
|
||||||
gen = result.generations[i]
|
|
||||||
if isinstance(gen.message, AIMessage):
|
|
||||||
# Store in additional_kwargs
|
|
||||||
gen.message.additional_kwargs["reasoning_content"] = reasoning
|
|
||||||
# Prepend to content for ReAct agent visibility
|
|
||||||
if "Thought:" not in gen.message.content:
|
|
||||||
gen.message.content = f"Thought: {reasoning}\n" + gen.message.content
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -289,7 +319,7 @@ class UAVControlAgent:
|
|||||||
"api_key": llm_api_key,
|
"api_key": llm_api_key,
|
||||||
"base_url": final_base_url
|
"base_url": final_base_url
|
||||||
}
|
}
|
||||||
self.llm = ChatAnthropic(**kwargs)
|
self.llm = EnhancedChatAnthropic(**kwargs)
|
||||||
else:
|
else:
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"model": llm_model,
|
"model": llm_model,
|
||||||
@@ -328,6 +358,17 @@ class UAVControlAgent:
|
|||||||
# Create ReAct agent
|
# Create ReAct agent
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("🤖 Creating ReAct agent...")
|
print("🤖 Creating ReAct agent...")
|
||||||
|
if llm_provider in ["anthropic", "anthropic-compatible"]:
|
||||||
|
if self.debug:
|
||||||
|
print("🤖 Using Tool Calling Agent (Better for Claude)")
|
||||||
|
self.agent = create_react_agent(
|
||||||
|
llm=self.llm,
|
||||||
|
tools=self.tools,
|
||||||
|
prompt=self.prompt
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if self.debug:
|
||||||
|
print("🤖 Using React Agent (GPT-3 and older)")
|
||||||
self.agent = create_react_agent(
|
self.agent = create_react_agent(
|
||||||
llm=self.llm,
|
llm=self.llm,
|
||||||
tools=self.tools,
|
tools=self.tools,
|
||||||
|
|||||||
@@ -460,6 +460,8 @@ def create_uav_tools(client: UAVAPIClient) -> list:
|
|||||||
return "Error: drone_id is required"
|
return "Error: drone_id is required"
|
||||||
|
|
||||||
result = client.take_off(drone_id, altitude)
|
result = client.take_off(drone_id, altitude)
|
||||||
|
if result["status"] == "success":
|
||||||
|
result["message"] += f" Using `get_drone_status` to check if the drone\'s current position is start point. If not, fly to the start point first."
|
||||||
return json.dumps(result, indent=2)
|
return json.dumps(result, indent=2)
|
||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
return f"Error parsing JSON input: {str(e)}. Expected format: {{\"drone_id\": \"drone-001\", \"altitude\": 15.0}}"
|
return f"Error parsing JSON input: {str(e)}. Expected format: {{\"drone_id\": \"drone-001\", \"altitude\": 15.0}}"
|
||||||
@@ -1248,8 +1250,10 @@ def create_uav_tools(client: UAVAPIClient) -> list:
|
|||||||
if current_coverage >= required_coverage:
|
if current_coverage >= required_coverage:
|
||||||
tool_states.explored_count = 0
|
tool_states.explored_count = 0
|
||||||
return f"Success: Target explored with coverage {current_coverage:.2%} (Visited {tool_states.explored_count}/{total_points} grid points)"
|
return f"Success: Target explored with coverage {current_coverage:.2%} (Visited {tool_states.explored_count}/{total_points} grid points)"
|
||||||
|
if math.isclose(current_coverage, 0.0):
|
||||||
return f"Finished path. Final coverage: {current_coverage:.2%}"
|
return f"Finished path. Final coverage: {current_coverage:.2%}. Please try call this tool again to continue exploring."
|
||||||
|
else:
|
||||||
|
return f"Finished path. Final coverage: {current_coverage:.2%}. Wait for a while and continue calling this function! return [TASK DONE] this time"
|
||||||
|
|
||||||
|
|
||||||
# Return all tools
|
# Return all tools
|
||||||
|
|||||||
Reference in New Issue
Block a user