bug fixed for start point sidderent from current point

This commit is contained in:
abnerhexu
2026-01-25 22:04:08 +08:00
parent ab8bb2e220
commit 37933eb22b
2 changed files with 70 additions and 25 deletions

View File

@@ -20,26 +20,56 @@ import json
import os
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):
"""ChatOpenAI subclass that captures reasoning_content if provided by the API"""
class EnhancedChatAnthropic(ChatAnthropic):
"""
针对 Anthropic 的增强类:
1. 提取 'thinking' 块并将其转换为 ReAct 格式的 'Thought: ...'
2. 防止因为只有工具调用而导致的 content 为空
"""
def _create_chat_result(self, response: Any) -> ChatResult:
result = super()._create_chat_result(response)
def generate(self, response: Any) -> ChatResult:
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
@@ -289,7 +319,7 @@ class UAVControlAgent:
"api_key": llm_api_key,
"base_url": final_base_url
}
self.llm = ChatAnthropic(**kwargs)
self.llm = EnhancedChatAnthropic(**kwargs)
else:
kwargs = {
"model": llm_model,
@@ -328,6 +358,17 @@ class UAVControlAgent:
# Create ReAct agent
if self.debug:
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(
llm=self.llm,
tools=self.tools,

View File

@@ -460,6 +460,8 @@ def create_uav_tools(client: UAVAPIClient) -> list:
return "Error: drone_id is required"
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)
except json.JSONDecodeError as e:
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:
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"Finished path. Final coverage: {current_coverage:.2%}"
if math.isclose(current_coverage, 0.0):
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